diff options
261 files changed, 11698 insertions, 6537 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index aaf3a90cf..27aa56780 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -261,7 +261,7 @@ if(ENABLE_SDL2) | |||
| 261 | find_package(SDL2) | 261 | find_package(SDL2) |
| 262 | if (NOT SDL2_FOUND) | 262 | if (NOT SDL2_FOUND) |
| 263 | # otherwise add this to the list of libraries to install | 263 | # otherwise add this to the list of libraries to install |
| 264 | list(APPEND CONAN_REQUIRED_LIBS "sdl2/2.0.12@bincrafters/stable") | 264 | list(APPEND CONAN_REQUIRED_LIBS "sdl2/2.0.14@bincrafters/stable") |
| 265 | endif() | 265 | endif() |
| 266 | endif() | 266 | endif() |
| 267 | 267 | ||
| @@ -33,7 +33,7 @@ If you want to contribute to the user interface translation, please check out th | |||
| 33 | 33 | ||
| 34 | 34 | ||
| 35 | ### Support | 35 | ### Support |
| 36 | We happily accept monetary donations or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like: | 36 | We happily accept monetary donations, or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like: |
| 37 | * Switch consoles to explore and reverse-engineer the hardware | 37 | * Switch consoles to explore and reverse-engineer the hardware |
| 38 | * Switch games for testing, reverse-engineering, and implementing new features | 38 | * Switch games for testing, reverse-engineering, and implementing new features |
| 39 | * Web hosting and infrastructure setup | 39 | * Web hosting and infrastructure setup |
diff --git a/dist/icons/controller/controller.qrc b/dist/icons/controller/controller.qrc index 1c4e960c0..78eae461c 100644 --- a/dist/icons/controller/controller.qrc +++ b/dist/icons/controller/controller.qrc | |||
| @@ -1,26 +1,5 @@ | |||
| 1 | <RCC> | 1 | <RCC> |
| 2 | <qresource prefix="controller"> | 2 | <qresource prefix="controller"> |
| 3 | <file alias="dual_joycon">dual_joycon.png</file> | ||
| 4 | <file alias="dual_joycon_dark">dual_joycon_dark.png</file> | ||
| 5 | <file alias="dual_joycon_midnight">dual_joycon_midnight.png</file> | ||
| 6 | <file alias="handheld">handheld.png</file> | ||
| 7 | <file alias="handheld_dark">handheld_dark.png</file> | ||
| 8 | <file alias="handheld_midnight">handheld_midnight.png</file> | ||
| 9 | <file alias="pro_controller">pro_controller.png</file> | ||
| 10 | <file alias="pro_controller_dark">pro_controller_dark.png</file> | ||
| 11 | <file alias="pro_controller_midnight">pro_controller_midnight.png</file> | ||
| 12 | <file alias="single_joycon_left">single_joycon_left.png</file> | ||
| 13 | <file alias="single_joycon_left_dark">single_joycon_left_dark.png</file> | ||
| 14 | <file alias="single_joycon_left_midnight">single_joycon_left_midnight.png</file> | ||
| 15 | <file alias="single_joycon_right">single_joycon_right.png</file> | ||
| 16 | <file alias="single_joycon_right_dark">single_joycon_right_dark.png</file> | ||
| 17 | <file alias="single_joycon_right_midnight">single_joycon_right_midnight.png</file> | ||
| 18 | <file alias="single_joycon_left_vertical">single_joycon_left_vertical.png</file> | ||
| 19 | <file alias="single_joycon_left_vertical_dark">single_joycon_left_vertical_dark.png</file> | ||
| 20 | <file alias="single_joycon_left_vertical_midnight">single_joycon_left_vertical_midnight.png</file> | ||
| 21 | <file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file> | ||
| 22 | <file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file> | ||
| 23 | <file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file> | ||
| 24 | <file alias="applet_dual_joycon">applet_dual_joycon.png</file> | 3 | <file alias="applet_dual_joycon">applet_dual_joycon.png</file> |
| 25 | <file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file> | 4 | <file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file> |
| 26 | <file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file> | 5 | <file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file> |
diff --git a/dist/icons/controller/dual_joycon.png b/dist/icons/controller/dual_joycon.png deleted file mode 100644 index 4230f5f7b..000000000 --- a/dist/icons/controller/dual_joycon.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/dual_joycon_dark.png b/dist/icons/controller/dual_joycon_dark.png deleted file mode 100644 index 4445db489..000000000 --- a/dist/icons/controller/dual_joycon_dark.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/dual_joycon_midnight.png b/dist/icons/controller/dual_joycon_midnight.png deleted file mode 100644 index aac8e5321..000000000 --- a/dist/icons/controller/dual_joycon_midnight.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/handheld.png b/dist/icons/controller/handheld.png deleted file mode 100644 index d009b4a47..000000000 --- a/dist/icons/controller/handheld.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/handheld_dark.png b/dist/icons/controller/handheld_dark.png deleted file mode 100644 index c80ca9259..000000000 --- a/dist/icons/controller/handheld_dark.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/handheld_midnight.png b/dist/icons/controller/handheld_midnight.png deleted file mode 100644 index 19de4629b..000000000 --- a/dist/icons/controller/handheld_midnight.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/pro_controller.png b/dist/icons/controller/pro_controller.png deleted file mode 100644 index 07d65e94a..000000000 --- a/dist/icons/controller/pro_controller.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/pro_controller_dark.png b/dist/icons/controller/pro_controller_dark.png deleted file mode 100644 index 73efe18f4..000000000 --- a/dist/icons/controller/pro_controller_dark.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/pro_controller_midnight.png b/dist/icons/controller/pro_controller_midnight.png deleted file mode 100644 index 8d7e63f0d..000000000 --- a/dist/icons/controller/pro_controller_midnight.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_left.png b/dist/icons/controller/single_joycon_left.png deleted file mode 100644 index 547153034..000000000 --- a/dist/icons/controller/single_joycon_left.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_left_dark.png b/dist/icons/controller/single_joycon_left_dark.png deleted file mode 100644 index b6ee073cb..000000000 --- a/dist/icons/controller/single_joycon_left_dark.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_left_midnight.png b/dist/icons/controller/single_joycon_left_midnight.png deleted file mode 100644 index 34a485c81..000000000 --- a/dist/icons/controller/single_joycon_left_midnight.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_left_vertical.png b/dist/icons/controller/single_joycon_left_vertical.png deleted file mode 100644 index 1e6282ad8..000000000 --- a/dist/icons/controller/single_joycon_left_vertical.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_left_vertical_dark.png b/dist/icons/controller/single_joycon_left_vertical_dark.png deleted file mode 100644 index a615d995d..000000000 --- a/dist/icons/controller/single_joycon_left_vertical_dark.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_left_vertical_midnight.png b/dist/icons/controller/single_joycon_left_vertical_midnight.png deleted file mode 100644 index 4cc578216..000000000 --- a/dist/icons/controller/single_joycon_left_vertical_midnight.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_right.png b/dist/icons/controller/single_joycon_right.png deleted file mode 100644 index 8d29173f6..000000000 --- a/dist/icons/controller/single_joycon_right.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_right_dark.png b/dist/icons/controller/single_joycon_right_dark.png deleted file mode 100644 index ead2c44e0..000000000 --- a/dist/icons/controller/single_joycon_right_dark.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_right_midnight.png b/dist/icons/controller/single_joycon_right_midnight.png deleted file mode 100644 index 89afe022d..000000000 --- a/dist/icons/controller/single_joycon_right_midnight.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_right_vertical.png b/dist/icons/controller/single_joycon_right_vertical.png deleted file mode 100644 index 4d7d06547..000000000 --- a/dist/icons/controller/single_joycon_right_vertical.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_right_vertical_dark.png b/dist/icons/controller/single_joycon_right_vertical_dark.png deleted file mode 100644 index 9a6eb3013..000000000 --- a/dist/icons/controller/single_joycon_right_vertical_dark.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/dist/icons/controller/single_joycon_right_vertical_midnight.png b/dist/icons/controller/single_joycon_right_vertical_midnight.png deleted file mode 100644 index 685249b68..000000000 --- a/dist/icons/controller/single_joycon_right_vertical_midnight.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject 3806284cbefc4115436dcdc687776a45ec31309 | Subproject 8c09da666aa3f0bb1000b0b6c5d5b0a1876f306 | ||
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 478246b6f..1cfd3bbc9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -64,8 +64,10 @@ if (MSVC) | |||
| 64 | else() | 64 | else() |
| 65 | add_compile_options( | 65 | add_compile_options( |
| 66 | -Wall | 66 | -Wall |
| 67 | -Werror=array-bounds | ||
| 67 | -Werror=implicit-fallthrough | 68 | -Werror=implicit-fallthrough |
| 68 | -Werror=missing-declarations | 69 | -Werror=missing-declarations |
| 70 | -Werror=missing-field-initializers | ||
| 69 | -Werror=reorder | 71 | -Werror=reorder |
| 70 | -Werror=switch | 72 | -Werror=switch |
| 71 | -Werror=uninitialized | 73 | -Werror=uninitialized |
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp index a4a9a757d..5b1065520 100644 --- a/src/audio_core/command_generator.cpp +++ b/src/audio_core/command_generator.cpp | |||
| @@ -383,11 +383,14 @@ void CommandGenerator::GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, E | |||
| 383 | const auto channel_count = params.channel_count; | 383 | const auto channel_count = params.channel_count; |
| 384 | for (s32 i = 0; i < channel_count; i++) { | 384 | for (s32 i = 0; i < channel_count; i++) { |
| 385 | // TODO(ogniK): Actually implement reverb | 385 | // TODO(ogniK): Actually implement reverb |
| 386 | /* | ||
| 386 | if (params.input[i] != params.output[i]) { | 387 | if (params.input[i] != params.output[i]) { |
| 387 | const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]); | 388 | const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]); |
| 388 | auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]); | 389 | auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]); |
| 389 | ApplyMix<1>(output, input, 32768, worker_params.sample_count); | 390 | ApplyMix<1>(output, input, 32768, worker_params.sample_count); |
| 390 | } | 391 | }*/ |
| 392 | auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]); | ||
| 393 | std::memset(output, 0, worker_params.sample_count * sizeof(s32)); | ||
| 391 | } | 394 | } |
| 392 | } | 395 | } |
| 393 | 396 | ||
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index f3373fe04..b0f6f0c34 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp | |||
| @@ -51,6 +51,14 @@ void Stream::Stop() { | |||
| 51 | UNIMPLEMENTED(); | 51 | UNIMPLEMENTED(); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | bool Stream::Flush() { | ||
| 55 | const bool had_buffers = !queued_buffers.empty(); | ||
| 56 | while (!queued_buffers.empty()) { | ||
| 57 | queued_buffers.pop(); | ||
| 58 | } | ||
| 59 | return had_buffers; | ||
| 60 | } | ||
| 61 | |||
| 54 | void Stream::SetVolume(float volume) { | 62 | void Stream::SetVolume(float volume) { |
| 55 | game_volume = volume; | 63 | game_volume = volume; |
| 56 | } | 64 | } |
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 506ac536b..559844b9b 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h | |||
| @@ -56,6 +56,9 @@ public: | |||
| 56 | /// Queues a buffer into the audio stream, returns true on success | 56 | /// Queues a buffer into the audio stream, returns true on success |
| 57 | bool QueueBuffer(BufferPtr&& buffer); | 57 | bool QueueBuffer(BufferPtr&& buffer); |
| 58 | 58 | ||
| 59 | /// Flush audio buffers | ||
| 60 | bool Flush(); | ||
| 61 | |||
| 59 | /// Returns true if the audio stream contains a buffer with the specified tag | 62 | /// Returns true if the audio stream contains a buffer with the specified tag |
| 60 | [[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const; | 63 | [[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const; |
| 61 | 64 | ||
diff --git a/src/audio_core/voice_context.h b/src/audio_core/voice_context.h index 863248761..70359cadb 100644 --- a/src/audio_core/voice_context.h +++ b/src/audio_core/voice_context.h | |||
| @@ -86,28 +86,28 @@ struct BehaviorFlags { | |||
| 86 | static_assert(sizeof(BehaviorFlags) == 0x4, "BehaviorFlags is an invalid size"); | 86 | static_assert(sizeof(BehaviorFlags) == 0x4, "BehaviorFlags is an invalid size"); |
| 87 | 87 | ||
| 88 | struct ADPCMContext { | 88 | struct ADPCMContext { |
| 89 | u16 header{}; | 89 | u16 header; |
| 90 | s16 yn1{}; | 90 | s16 yn1; |
| 91 | s16 yn2{}; | 91 | s16 yn2; |
| 92 | }; | 92 | }; |
| 93 | static_assert(sizeof(ADPCMContext) == 0x6, "ADPCMContext is an invalid size"); | 93 | static_assert(sizeof(ADPCMContext) == 0x6, "ADPCMContext is an invalid size"); |
| 94 | 94 | ||
| 95 | struct VoiceState { | 95 | struct VoiceState { |
| 96 | s64 played_sample_count{}; | 96 | s64 played_sample_count; |
| 97 | s32 offset{}; | 97 | s32 offset; |
| 98 | s32 wave_buffer_index{}; | 98 | s32 wave_buffer_index; |
| 99 | std::array<bool, AudioCommon::MAX_WAVE_BUFFERS> is_wave_buffer_valid{}; | 99 | std::array<bool, AudioCommon::MAX_WAVE_BUFFERS> is_wave_buffer_valid; |
| 100 | s32 wave_buffer_consumed{}; | 100 | s32 wave_buffer_consumed; |
| 101 | std::array<s32, AudioCommon::MAX_SAMPLE_HISTORY> sample_history{}; | 101 | std::array<s32, AudioCommon::MAX_SAMPLE_HISTORY> sample_history; |
| 102 | s32 fraction{}; | 102 | s32 fraction; |
| 103 | VAddr context_address{}; | 103 | VAddr context_address; |
| 104 | Codec::ADPCM_Coeff coeff{}; | 104 | Codec::ADPCM_Coeff coeff; |
| 105 | ADPCMContext context{}; | 105 | ADPCMContext context; |
| 106 | std::array<s64, 2> biquad_filter_state{}; | 106 | std::array<s64, 2> biquad_filter_state; |
| 107 | std::array<s32, AudioCommon::MAX_MIX_BUFFERS> previous_samples{}; | 107 | std::array<s32, AudioCommon::MAX_MIX_BUFFERS> previous_samples; |
| 108 | u32 external_context_size{}; | 108 | u32 external_context_size; |
| 109 | bool is_external_context_used{}; | 109 | bool is_external_context_used; |
| 110 | bool voice_dropped{}; | 110 | bool voice_dropped; |
| 111 | }; | 111 | }; |
| 112 | 112 | ||
| 113 | class VoiceChannelResource { | 113 | class VoiceChannelResource { |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index f77575a00..bfd11e76d 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -138,6 +138,8 @@ add_library(common STATIC | |||
| 138 | microprofile.h | 138 | microprofile.h |
| 139 | microprofileui.h | 139 | microprofileui.h |
| 140 | misc.cpp | 140 | misc.cpp |
| 141 | nvidia_flags.cpp | ||
| 142 | nvidia_flags.h | ||
| 141 | page_table.cpp | 143 | page_table.cpp |
| 142 | page_table.h | 144 | page_table.h |
| 143 | param_package.cpp | 145 | param_package.cpp |
diff --git a/src/common/bit_util.h b/src/common/bit_util.h index 685e7fc9b..64520ca4e 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h | |||
| @@ -4,13 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <bit> | ||
| 7 | #include <climits> | 8 | #include <climits> |
| 8 | #include <cstddef> | 9 | #include <cstddef> |
| 9 | 10 | ||
| 10 | #ifdef _MSC_VER | ||
| 11 | #include <intrin.h> | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 15 | 12 | ||
| 16 | namespace Common { | 13 | namespace Common { |
| @@ -21,48 +18,30 @@ template <typename T> | |||
| 21 | return sizeof(T) * CHAR_BIT; | 18 | return sizeof(T) * CHAR_BIT; |
| 22 | } | 19 | } |
| 23 | 20 | ||
| 24 | #ifdef _MSC_VER | 21 | [[nodiscard]] constexpr u32 MostSignificantBit32(const u32 value) { |
| 25 | 22 | return 31U - static_cast<u32>(std::countl_zero(value)); | |
| 26 | [[nodiscard]] inline u32 MostSignificantBit32(const u32 value) { | ||
| 27 | unsigned long result; | ||
| 28 | _BitScanReverse(&result, value); | ||
| 29 | return static_cast<u32>(result); | ||
| 30 | } | ||
| 31 | |||
| 32 | [[nodiscard]] inline u32 MostSignificantBit64(const u64 value) { | ||
| 33 | unsigned long result; | ||
| 34 | _BitScanReverse64(&result, value); | ||
| 35 | return static_cast<u32>(result); | ||
| 36 | } | ||
| 37 | |||
| 38 | #else | ||
| 39 | |||
| 40 | [[nodiscard]] inline u32 MostSignificantBit32(const u32 value) { | ||
| 41 | return 31U - static_cast<u32>(__builtin_clz(value)); | ||
| 42 | } | 23 | } |
| 43 | 24 | ||
| 44 | [[nodiscard]] inline u32 MostSignificantBit64(const u64 value) { | 25 | [[nodiscard]] constexpr u32 MostSignificantBit64(const u64 value) { |
| 45 | return 63U - static_cast<u32>(__builtin_clzll(value)); | 26 | return 63U - static_cast<u32>(std::countl_zero(value)); |
| 46 | } | 27 | } |
| 47 | 28 | ||
| 48 | #endif | 29 | [[nodiscard]] constexpr u32 Log2Floor32(const u32 value) { |
| 49 | |||
| 50 | [[nodiscard]] inline u32 Log2Floor32(const u32 value) { | ||
| 51 | return MostSignificantBit32(value); | 30 | return MostSignificantBit32(value); |
| 52 | } | 31 | } |
| 53 | 32 | ||
| 54 | [[nodiscard]] inline u32 Log2Ceil32(const u32 value) { | 33 | [[nodiscard]] constexpr u32 Log2Floor64(const u64 value) { |
| 55 | const u32 log2_f = Log2Floor32(value); | 34 | return MostSignificantBit64(value); |
| 56 | return log2_f + ((value ^ (1U << log2_f)) != 0U); | ||
| 57 | } | 35 | } |
| 58 | 36 | ||
| 59 | [[nodiscard]] inline u32 Log2Floor64(const u64 value) { | 37 | [[nodiscard]] constexpr u32 Log2Ceil32(const u32 value) { |
| 60 | return MostSignificantBit64(value); | 38 | const u32 log2_f = Log2Floor32(value); |
| 39 | return log2_f + static_cast<u32>((value ^ (1U << log2_f)) != 0U); | ||
| 61 | } | 40 | } |
| 62 | 41 | ||
| 63 | [[nodiscard]] inline u32 Log2Ceil64(const u64 value) { | 42 | [[nodiscard]] constexpr u32 Log2Ceil64(const u64 value) { |
| 64 | const u64 log2_f = static_cast<u64>(Log2Floor64(value)); | 43 | const u64 log2_f = Log2Floor64(value); |
| 65 | return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL)); | 44 | return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL)); |
| 66 | } | 45 | } |
| 67 | 46 | ||
| 68 | } // namespace Common | 47 | } // namespace Common |
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 75f3027fb..71b64e32a 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -97,10 +97,27 @@ __declspec(dllimport) void __stdcall DebugBreak(void); | |||
| 97 | #define R_UNLESS(expr, res) \ | 97 | #define R_UNLESS(expr, res) \ |
| 98 | { \ | 98 | { \ |
| 99 | if (!(expr)) { \ | 99 | if (!(expr)) { \ |
| 100 | if (res.IsError()) { \ | ||
| 101 | LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \ | ||
| 102 | } \ | ||
| 100 | return res; \ | 103 | return res; \ |
| 101 | } \ | 104 | } \ |
| 102 | } | 105 | } |
| 103 | 106 | ||
| 107 | #define R_SUCCEEDED(res) (res.IsSuccess()) | ||
| 108 | |||
| 109 | /// Evaluates an expression that returns a result, and returns the result if it would fail. | ||
| 110 | #define R_TRY(res_expr) \ | ||
| 111 | { \ | ||
| 112 | const auto _tmp_r_try_rc = (res_expr); \ | ||
| 113 | if (_tmp_r_try_rc.IsError()) { \ | ||
| 114 | return _tmp_r_try_rc; \ | ||
| 115 | } \ | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Evaluates a boolean expression, and succeeds if that expression is true. | ||
| 119 | #define R_SUCCEED_IF(expr) R_UNLESS(!(expr), RESULT_SUCCESS) | ||
| 120 | |||
| 104 | namespace Common { | 121 | namespace Common { |
| 105 | 122 | ||
| 106 | [[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) { | 123 | [[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) { |
diff --git a/src/common/nvidia_flags.cpp b/src/common/nvidia_flags.cpp new file mode 100644 index 000000000..d537517db --- /dev/null +++ b/src/common/nvidia_flags.cpp | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <filesystem> | ||
| 6 | #include <stdlib.h> | ||
| 7 | |||
| 8 | #include <fmt/format.h> | ||
| 9 | |||
| 10 | #include "common/file_util.h" | ||
| 11 | #include "common/nvidia_flags.h" | ||
| 12 | |||
| 13 | namespace Common { | ||
| 14 | |||
| 15 | void ConfigureNvidiaEnvironmentFlags() { | ||
| 16 | #ifdef _WIN32 | ||
| 17 | const std::string shader_path = Common::FS::SanitizePath( | ||
| 18 | fmt::format("{}/nvidia/", Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir))); | ||
| 19 | const std::string windows_path = | ||
| 20 | Common::FS::SanitizePath(shader_path, Common::FS::DirectorySeparator::BackwardSlash); | ||
| 21 | void(Common::FS::CreateFullPath(shader_path + '/')); | ||
| 22 | void(_putenv(fmt::format("__GL_SHADER_DISK_CACHE_PATH={}", windows_path).c_str())); | ||
| 23 | void(_putenv("__GL_SHADER_DISK_CACHE_SKIP_CLEANUP=1")); | ||
| 24 | #endif | ||
| 25 | } | ||
| 26 | |||
| 27 | } // namespace Common | ||
diff --git a/src/common/nvidia_flags.h b/src/common/nvidia_flags.h new file mode 100644 index 000000000..75a0233ac --- /dev/null +++ b/src/common/nvidia_flags.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | namespace Common { | ||
| 6 | |||
| 7 | /// Configure platform specific flags for Nvidia's driver | ||
| 8 | void ConfigureNvidiaEnvironmentFlags(); | ||
| 9 | |||
| 10 | } // namespace Common | ||
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 138fa0131..4a8d09806 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h | |||
| @@ -19,15 +19,14 @@ namespace Common { | |||
| 19 | /// SPSC ring buffer | 19 | /// SPSC ring buffer |
| 20 | /// @tparam T Element type | 20 | /// @tparam T Element type |
| 21 | /// @tparam capacity Number of slots in ring buffer | 21 | /// @tparam capacity Number of slots in ring buffer |
| 22 | /// @tparam granularity Slot size in terms of number of elements | 22 | template <typename T, std::size_t capacity> |
| 23 | template <typename T, std::size_t capacity, std::size_t granularity = 1> | ||
| 24 | class RingBuffer { | 23 | class RingBuffer { |
| 25 | /// A "slot" is made of `granularity` elements of `T`. | 24 | /// A "slot" is made of a single `T`. |
| 26 | static constexpr std::size_t slot_size = granularity * sizeof(T); | 25 | static constexpr std::size_t slot_size = sizeof(T); |
| 27 | // T must be safely memcpy-able and have a trivial default constructor. | 26 | // T must be safely memcpy-able and have a trivial default constructor. |
| 28 | static_assert(std::is_trivial_v<T>); | 27 | static_assert(std::is_trivial_v<T>); |
| 29 | // Ensure capacity is sensible. | 28 | // Ensure capacity is sensible. |
| 30 | static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2 / granularity); | 29 | static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2); |
| 31 | static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two"); | 30 | static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two"); |
| 32 | // Ensure lock-free. | 31 | // Ensure lock-free. |
| 33 | static_assert(std::atomic_size_t::is_always_lock_free); | 32 | static_assert(std::atomic_size_t::is_always_lock_free); |
| @@ -47,7 +46,7 @@ public: | |||
| 47 | const std::size_t second_copy = push_count - first_copy; | 46 | const std::size_t second_copy = push_count - first_copy; |
| 48 | 47 | ||
| 49 | const char* in = static_cast<const char*>(new_slots); | 48 | const char* in = static_cast<const char*>(new_slots); |
| 50 | std::memcpy(m_data.data() + pos * granularity, in, first_copy * slot_size); | 49 | std::memcpy(m_data.data() + pos, in, first_copy * slot_size); |
| 51 | in += first_copy * slot_size; | 50 | in += first_copy * slot_size; |
| 52 | std::memcpy(m_data.data(), in, second_copy * slot_size); | 51 | std::memcpy(m_data.data(), in, second_copy * slot_size); |
| 53 | 52 | ||
| @@ -74,7 +73,7 @@ public: | |||
| 74 | const std::size_t second_copy = pop_count - first_copy; | 73 | const std::size_t second_copy = pop_count - first_copy; |
| 75 | 74 | ||
| 76 | char* out = static_cast<char*>(output); | 75 | char* out = static_cast<char*>(output); |
| 77 | std::memcpy(out, m_data.data() + pos * granularity, first_copy * slot_size); | 76 | std::memcpy(out, m_data.data() + pos, first_copy * slot_size); |
| 78 | out += first_copy * slot_size; | 77 | out += first_copy * slot_size; |
| 79 | std::memcpy(out, m_data.data(), second_copy * slot_size); | 78 | std::memcpy(out, m_data.data(), second_copy * slot_size); |
| 80 | 79 | ||
| @@ -84,9 +83,9 @@ public: | |||
| 84 | } | 83 | } |
| 85 | 84 | ||
| 86 | std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) { | 85 | std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) { |
| 87 | std::vector<T> out(std::min(max_slots, capacity) * granularity); | 86 | std::vector<T> out(std::min(max_slots, capacity)); |
| 88 | const std::size_t count = Pop(out.data(), out.size() / granularity); | 87 | const std::size_t count = Pop(out.data(), out.size()); |
| 89 | out.resize(count * granularity); | 88 | out.resize(count); |
| 90 | return out; | 89 | return out; |
| 91 | } | 90 | } |
| 92 | 91 | ||
| @@ -113,7 +112,7 @@ private: | |||
| 113 | alignas(128) std::atomic_size_t m_write_index{0}; | 112 | alignas(128) std::atomic_size_t m_write_index{0}; |
| 114 | #endif | 113 | #endif |
| 115 | 114 | ||
| 116 | std::array<T, granularity * capacity> m_data; | 115 | std::array<T, capacity> m_data; |
| 117 | }; | 116 | }; |
| 118 | 117 | ||
| 119 | } // namespace Common | 118 | } // namespace Common |
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index fa46cb394..35dac3a8f 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h | |||
| @@ -49,3 +49,9 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) { | |||
| 49 | * \endcode | 49 | * \endcode |
| 50 | */ | 50 | */ |
| 51 | #define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) | 51 | #define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) |
| 52 | |||
| 53 | /** | ||
| 54 | * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be | ||
| 55 | * used when the caller might want to cancel the ScopeExit. | ||
| 56 | */ | ||
| 57 | #define SCOPE_GUARD(body) detail::ScopeExit([&]() body) | ||
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 4cba2aaa4..7b614ad89 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -141,27 +141,13 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st | |||
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | std::string UTF16ToUTF8(const std::u16string& input) { | 143 | std::string UTF16ToUTF8(const std::u16string& input) { |
| 144 | #ifdef _MSC_VER | ||
| 145 | // Workaround for missing char16_t/char32_t instantiations in MSVC2017 | ||
| 146 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; | ||
| 147 | std::basic_string<__int16> tmp_buffer(input.cbegin(), input.cend()); | ||
| 148 | return convert.to_bytes(tmp_buffer); | ||
| 149 | #else | ||
| 150 | std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; | 144 | std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; |
| 151 | return convert.to_bytes(input); | 145 | return convert.to_bytes(input); |
| 152 | #endif | ||
| 153 | } | 146 | } |
| 154 | 147 | ||
| 155 | std::u16string UTF8ToUTF16(const std::string& input) { | 148 | std::u16string UTF8ToUTF16(const std::string& input) { |
| 156 | #ifdef _MSC_VER | ||
| 157 | // Workaround for missing char16_t/char32_t instantiations in MSVC2017 | ||
| 158 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; | ||
| 159 | auto tmp_buffer = convert.from_bytes(input); | ||
| 160 | return std::u16string(tmp_buffer.cbegin(), tmp_buffer.cend()); | ||
| 161 | #else | ||
| 162 | std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; | 149 | std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; |
| 163 | return convert.from_bytes(input); | 150 | return convert.from_bytes(input); |
| 164 | #endif | ||
| 165 | } | 151 | } |
| 166 | 152 | ||
| 167 | #ifdef _WIN32 | 153 | #ifdef _WIN32 |
diff --git a/src/common/uuid.h b/src/common/uuid.h index 4ab9a25f0..2e7a18405 100644 --- a/src/common/uuid.h +++ b/src/common/uuid.h | |||
| @@ -14,8 +14,8 @@ constexpr u128 INVALID_UUID{{0, 0}}; | |||
| 14 | 14 | ||
| 15 | struct UUID { | 15 | struct UUID { |
| 16 | // UUIDs which are 0 are considered invalid! | 16 | // UUIDs which are 0 are considered invalid! |
| 17 | u128 uuid = INVALID_UUID; | 17 | u128 uuid; |
| 18 | constexpr UUID() = default; | 18 | UUID() = default; |
| 19 | constexpr explicit UUID(const u128& id) : uuid{id} {} | 19 | constexpr explicit UUID(const u128& id) : uuid{id} {} |
| 20 | constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {} | 20 | constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {} |
| 21 | 21 | ||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 99310dc50..386d7bddf 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -160,7 +160,16 @@ add_library(core STATIC | |||
| 160 | hle/kernel/k_affinity_mask.h | 160 | hle/kernel/k_affinity_mask.h |
| 161 | hle/kernel/k_condition_variable.cpp | 161 | hle/kernel/k_condition_variable.cpp |
| 162 | hle/kernel/k_condition_variable.h | 162 | hle/kernel/k_condition_variable.h |
| 163 | hle/kernel/k_event.cpp | ||
| 164 | hle/kernel/k_event.h | ||
| 165 | hle/kernel/k_light_condition_variable.h | ||
| 166 | hle/kernel/k_light_lock.cpp | ||
| 167 | hle/kernel/k_light_lock.h | ||
| 163 | hle/kernel/k_priority_queue.h | 168 | hle/kernel/k_priority_queue.h |
| 169 | hle/kernel/k_readable_event.cpp | ||
| 170 | hle/kernel/k_readable_event.h | ||
| 171 | hle/kernel/k_resource_limit.cpp | ||
| 172 | hle/kernel/k_resource_limit.h | ||
| 164 | hle/kernel/k_scheduler.cpp | 173 | hle/kernel/k_scheduler.cpp |
| 165 | hle/kernel/k_scheduler.h | 174 | hle/kernel/k_scheduler.h |
| 166 | hle/kernel/k_scheduler_lock.h | 175 | hle/kernel/k_scheduler_lock.h |
| @@ -168,6 +177,11 @@ add_library(core STATIC | |||
| 168 | hle/kernel/k_scoped_scheduler_lock_and_sleep.h | 177 | hle/kernel/k_scoped_scheduler_lock_and_sleep.h |
| 169 | hle/kernel/k_synchronization_object.cpp | 178 | hle/kernel/k_synchronization_object.cpp |
| 170 | hle/kernel/k_synchronization_object.h | 179 | hle/kernel/k_synchronization_object.h |
| 180 | hle/kernel/k_thread.cpp | ||
| 181 | hle/kernel/k_thread.h | ||
| 182 | hle/kernel/k_thread_queue.h | ||
| 183 | hle/kernel/k_writable_event.cpp | ||
| 184 | hle/kernel/k_writable_event.h | ||
| 171 | hle/kernel/kernel.cpp | 185 | hle/kernel/kernel.cpp |
| 172 | hle/kernel/kernel.h | 186 | hle/kernel/kernel.h |
| 173 | hle/kernel/memory/address_space_info.cpp | 187 | hle/kernel/memory/address_space_info.cpp |
| @@ -196,10 +210,6 @@ add_library(core STATIC | |||
| 196 | hle/kernel/process.h | 210 | hle/kernel/process.h |
| 197 | hle/kernel/process_capability.cpp | 211 | hle/kernel/process_capability.cpp |
| 198 | hle/kernel/process_capability.h | 212 | hle/kernel/process_capability.h |
| 199 | hle/kernel/readable_event.cpp | ||
| 200 | hle/kernel/readable_event.h | ||
| 201 | hle/kernel/resource_limit.cpp | ||
| 202 | hle/kernel/resource_limit.h | ||
| 203 | hle/kernel/server_port.cpp | 213 | hle/kernel/server_port.cpp |
| 204 | hle/kernel/server_port.h | 214 | hle/kernel/server_port.h |
| 205 | hle/kernel/server_session.cpp | 215 | hle/kernel/server_session.cpp |
| @@ -216,14 +226,10 @@ add_library(core STATIC | |||
| 216 | hle/kernel/svc_results.h | 226 | hle/kernel/svc_results.h |
| 217 | hle/kernel/svc_types.h | 227 | hle/kernel/svc_types.h |
| 218 | hle/kernel/svc_wrap.h | 228 | hle/kernel/svc_wrap.h |
| 219 | hle/kernel/thread.cpp | ||
| 220 | hle/kernel/thread.h | ||
| 221 | hle/kernel/time_manager.cpp | 229 | hle/kernel/time_manager.cpp |
| 222 | hle/kernel/time_manager.h | 230 | hle/kernel/time_manager.h |
| 223 | hle/kernel/transfer_memory.cpp | 231 | hle/kernel/transfer_memory.cpp |
| 224 | hle/kernel/transfer_memory.h | 232 | hle/kernel/transfer_memory.h |
| 225 | hle/kernel/writable_event.cpp | ||
| 226 | hle/kernel/writable_event.h | ||
| 227 | hle/lock.cpp | 233 | hle/lock.cpp |
| 228 | hle/lock.h | 234 | hle/lock.h |
| 229 | hle/result.h | 235 | hle/result.h |
| @@ -400,8 +406,6 @@ add_library(core STATIC | |||
| 400 | hle/service/ldr/ldr.h | 406 | hle/service/ldr/ldr.h |
| 401 | hle/service/lm/lm.cpp | 407 | hle/service/lm/lm.cpp |
| 402 | hle/service/lm/lm.h | 408 | hle/service/lm/lm.h |
| 403 | hle/service/lm/manager.cpp | ||
| 404 | hle/service/lm/manager.h | ||
| 405 | hle/service/mig/mig.cpp | 409 | hle/service/mig/mig.cpp |
| 406 | hle/service/mig/mig.h | 410 | hle/service/mig/mig.h |
| 407 | hle/service/mii/manager.cpp | 411 | hle/service/mii/manager.cpp |
| @@ -645,6 +649,7 @@ else() | |||
| 645 | -Werror=implicit-fallthrough | 649 | -Werror=implicit-fallthrough |
| 646 | -Werror=sign-compare | 650 | -Werror=sign-compare |
| 647 | 651 | ||
| 652 | $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> | ||
| 648 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | 653 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> |
| 649 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | 654 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> |
| 650 | 655 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 6c4c8e9e4..ec4407b6e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -71,8 +71,9 @@ public: | |||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { | 73 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { |
| 74 | LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", | 74 | LOG_CRITICAL(Core_ARM, |
| 75 | exception, pc, MemoryReadCode(pc)); | 75 | "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", |
| 76 | exception, pc, MemoryReadCode(pc), parent.IsInThumbMode()); | ||
| 76 | UNIMPLEMENTED(); | 77 | UNIMPLEMENTED(); |
| 77 | } | 78 | } |
| 78 | 79 | ||
| @@ -255,6 +256,9 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) { | |||
| 255 | } | 256 | } |
| 256 | 257 | ||
| 257 | void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { | 258 | void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { |
| 259 | if (!jit) { | ||
| 260 | return; | ||
| 261 | } | ||
| 258 | Dynarmic::A32::Context context; | 262 | Dynarmic::A32::Context context; |
| 259 | jit->SaveContext(context); | 263 | jit->SaveContext(context); |
| 260 | ctx.cpu_registers = context.Regs(); | 264 | ctx.cpu_registers = context.Regs(); |
| @@ -264,6 +268,9 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { | |||
| 264 | } | 268 | } |
| 265 | 269 | ||
| 266 | void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { | 270 | void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { |
| 271 | if (!jit) { | ||
| 272 | return; | ||
| 273 | } | ||
| 267 | Dynarmic::A32::Context context; | 274 | Dynarmic::A32::Context context; |
| 268 | context.Regs() = ctx.cpu_registers; | 275 | context.Regs() = ctx.cpu_registers; |
| 269 | context.ExtRegs() = ctx.extension_registers; | 276 | context.ExtRegs() = ctx.extension_registers; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 35e9ced48..f6c4d4db9 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -50,6 +50,10 @@ public: | |||
| 50 | u64 GetTPIDR_EL0() const override; | 50 | u64 GetTPIDR_EL0() const override; |
| 51 | void ChangeProcessorID(std::size_t new_core_id) override; | 51 | void ChangeProcessorID(std::size_t new_core_id) override; |
| 52 | 52 | ||
| 53 | bool IsInThumbMode() const { | ||
| 54 | return (GetPSTATE() & 0x20) != 0; | ||
| 55 | } | ||
| 56 | |||
| 53 | void SaveContext(ThreadContext32& ctx) override; | 57 | void SaveContext(ThreadContext32& ctx) override; |
| 54 | void SaveContext(ThreadContext64& ctx) override {} | 58 | void SaveContext(ThreadContext64& ctx) override {} |
| 55 | void LoadContext(const ThreadContext32& ctx) override; | 59 | void LoadContext(const ThreadContext32& ctx) override; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 4c5ebca22..ae5566ab8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -294,6 +294,9 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) { | |||
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { | 296 | void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { |
| 297 | if (!jit) { | ||
| 298 | return; | ||
| 299 | } | ||
| 297 | ctx.cpu_registers = jit->GetRegisters(); | 300 | ctx.cpu_registers = jit->GetRegisters(); |
| 298 | ctx.sp = jit->GetSP(); | 301 | ctx.sp = jit->GetSP(); |
| 299 | ctx.pc = jit->GetPC(); | 302 | ctx.pc = jit->GetPC(); |
| @@ -305,6 +308,9 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { | |||
| 305 | } | 308 | } |
| 306 | 309 | ||
| 307 | void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { | 310 | void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { |
| 311 | if (!jit) { | ||
| 312 | return; | ||
| 313 | } | ||
| 308 | jit->SetRegisters(ctx.cpu_registers); | 314 | jit->SetRegisters(ctx.cpu_registers); |
| 309 | jit->SetSP(ctx.sp); | 315 | jit->SetSP(ctx.sp); |
| 310 | jit->SetPC(ctx.pc); | 316 | jit->SetPC(ctx.pc); |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 1a2002dec..30f5e1128 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -28,15 +28,14 @@ | |||
| 28 | #include "core/hardware_interrupt_manager.h" | 28 | #include "core/hardware_interrupt_manager.h" |
| 29 | #include "core/hle/kernel/client_port.h" | 29 | #include "core/hle/kernel/client_port.h" |
| 30 | #include "core/hle/kernel/k_scheduler.h" | 30 | #include "core/hle/kernel/k_scheduler.h" |
| 31 | #include "core/hle/kernel/k_thread.h" | ||
| 31 | #include "core/hle/kernel/kernel.h" | 32 | #include "core/hle/kernel/kernel.h" |
| 32 | #include "core/hle/kernel/physical_core.h" | 33 | #include "core/hle/kernel/physical_core.h" |
| 33 | #include "core/hle/kernel/process.h" | 34 | #include "core/hle/kernel/process.h" |
| 34 | #include "core/hle/kernel/thread.h" | ||
| 35 | #include "core/hle/service/am/applets/applets.h" | 35 | #include "core/hle/service/am/applets/applets.h" |
| 36 | #include "core/hle/service/apm/controller.h" | 36 | #include "core/hle/service/apm/controller.h" |
| 37 | #include "core/hle/service/filesystem/filesystem.h" | 37 | #include "core/hle/service/filesystem/filesystem.h" |
| 38 | #include "core/hle/service/glue/manager.h" | 38 | #include "core/hle/service/glue/manager.h" |
| 39 | #include "core/hle/service/lm/manager.h" | ||
| 40 | #include "core/hle/service/service.h" | 39 | #include "core/hle/service/service.h" |
| 41 | #include "core/hle/service/sm/sm.h" | 40 | #include "core/hle/service/sm/sm.h" |
| 42 | #include "core/hle/service/time/time_manager.h" | 41 | #include "core/hle/service/time/time_manager.h" |
| @@ -293,8 +292,6 @@ struct System::Impl { | |||
| 293 | perf_stats->GetMeanFrametime()); | 292 | perf_stats->GetMeanFrametime()); |
| 294 | } | 293 | } |
| 295 | 294 | ||
| 296 | lm_manager.Flush(); | ||
| 297 | |||
| 298 | is_powered_on = false; | 295 | is_powered_on = false; |
| 299 | exit_lock = false; | 296 | exit_lock = false; |
| 300 | 297 | ||
| @@ -398,7 +395,6 @@ struct System::Impl { | |||
| 398 | 395 | ||
| 399 | /// Service State | 396 | /// Service State |
| 400 | Service::Glue::ARPManager arp_manager; | 397 | Service::Glue::ARPManager arp_manager; |
| 401 | Service::LM::Manager lm_manager{reporter}; | ||
| 402 | Service::Time::TimeManager time_manager; | 398 | Service::Time::TimeManager time_manager; |
| 403 | 399 | ||
| 404 | /// Service manager | 400 | /// Service manager |
| @@ -720,14 +716,6 @@ const Service::APM::Controller& System::GetAPMController() const { | |||
| 720 | return impl->apm_controller; | 716 | return impl->apm_controller; |
| 721 | } | 717 | } |
| 722 | 718 | ||
| 723 | Service::LM::Manager& System::GetLogManager() { | ||
| 724 | return impl->lm_manager; | ||
| 725 | } | ||
| 726 | |||
| 727 | const Service::LM::Manager& System::GetLogManager() const { | ||
| 728 | return impl->lm_manager; | ||
| 729 | } | ||
| 730 | |||
| 731 | Service::Time::TimeManager& System::GetTimeManager() { | 719 | Service::Time::TimeManager& System::GetTimeManager() { |
| 732 | return impl->time_manager; | 720 | return impl->time_manager; |
| 733 | } | 721 | } |
diff --git a/src/core/core.h b/src/core/core.h index 579a774e4..3a8e040c1 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -62,10 +62,6 @@ namespace Glue { | |||
| 62 | class ARPManager; | 62 | class ARPManager; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | namespace LM { | ||
| 66 | class Manager; | ||
| 67 | } // namespace LM | ||
| 68 | |||
| 69 | namespace SM { | 65 | namespace SM { |
| 70 | class ServiceManager; | 66 | class ServiceManager; |
| 71 | } // namespace SM | 67 | } // namespace SM |
| @@ -351,9 +347,6 @@ public: | |||
| 351 | [[nodiscard]] Service::APM::Controller& GetAPMController(); | 347 | [[nodiscard]] Service::APM::Controller& GetAPMController(); |
| 352 | [[nodiscard]] const Service::APM::Controller& GetAPMController() const; | 348 | [[nodiscard]] const Service::APM::Controller& GetAPMController() const; |
| 353 | 349 | ||
| 354 | [[nodiscard]] Service::LM::Manager& GetLogManager(); | ||
| 355 | [[nodiscard]] const Service::LM::Manager& GetLogManager() const; | ||
| 356 | |||
| 357 | [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); | 350 | [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); |
| 358 | [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; | 351 | [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; |
| 359 | 352 | ||
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 373395047..8f04fb8f5 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -11,9 +11,9 @@ | |||
| 11 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 12 | #include "core/cpu_manager.h" | 12 | #include "core/cpu_manager.h" |
| 13 | #include "core/hle/kernel/k_scheduler.h" | 13 | #include "core/hle/kernel/k_scheduler.h" |
| 14 | #include "core/hle/kernel/k_thread.h" | ||
| 14 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 15 | #include "core/hle/kernel/physical_core.h" | 16 | #include "core/hle/kernel/physical_core.h" |
| 16 | #include "core/hle/kernel/thread.h" | ||
| 17 | #include "video_core/gpu.h" | 17 | #include "video_core/gpu.h" |
| 18 | 18 | ||
| 19 | namespace Core { | 19 | namespace Core { |
| @@ -147,7 +147,7 @@ void CpuManager::MultiCoreRunSuspendThread() { | |||
| 147 | while (true) { | 147 | while (true) { |
| 148 | auto core = kernel.GetCurrentHostThreadID(); | 148 | auto core = kernel.GetCurrentHostThreadID(); |
| 149 | auto& scheduler = *kernel.CurrentScheduler(); | 149 | auto& scheduler = *kernel.CurrentScheduler(); |
| 150 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 150 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 151 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); | 151 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); |
| 152 | ASSERT(scheduler.ContextSwitchPending()); | 152 | ASSERT(scheduler.ContextSwitchPending()); |
| 153 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 153 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| @@ -208,7 +208,6 @@ void CpuManager::SingleCoreRunGuestThread() { | |||
| 208 | 208 | ||
| 209 | void CpuManager::SingleCoreRunGuestLoop() { | 209 | void CpuManager::SingleCoreRunGuestLoop() { |
| 210 | auto& kernel = system.Kernel(); | 210 | auto& kernel = system.Kernel(); |
| 211 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); | ||
| 212 | while (true) { | 211 | while (true) { |
| 213 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 212 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 214 | system.EnterDynarmicProfile(); | 213 | system.EnterDynarmicProfile(); |
| @@ -217,9 +216,9 @@ void CpuManager::SingleCoreRunGuestLoop() { | |||
| 217 | physical_core = &kernel.CurrentPhysicalCore(); | 216 | physical_core = &kernel.CurrentPhysicalCore(); |
| 218 | } | 217 | } |
| 219 | system.ExitDynarmicProfile(); | 218 | system.ExitDynarmicProfile(); |
| 220 | thread->SetPhantomMode(true); | 219 | kernel.SetIsPhantomModeForSingleCore(true); |
| 221 | system.CoreTiming().Advance(); | 220 | system.CoreTiming().Advance(); |
| 222 | thread->SetPhantomMode(false); | 221 | kernel.SetIsPhantomModeForSingleCore(false); |
| 223 | physical_core->ArmInterface().ClearExclusiveState(); | 222 | physical_core->ArmInterface().ClearExclusiveState(); |
| 224 | PreemptSingleCore(); | 223 | PreemptSingleCore(); |
| 225 | auto& scheduler = kernel.Scheduler(current_core); | 224 | auto& scheduler = kernel.Scheduler(current_core); |
| @@ -245,7 +244,7 @@ void CpuManager::SingleCoreRunSuspendThread() { | |||
| 245 | while (true) { | 244 | while (true) { |
| 246 | auto core = kernel.GetCurrentHostThreadID(); | 245 | auto core = kernel.GetCurrentHostThreadID(); |
| 247 | auto& scheduler = *kernel.CurrentScheduler(); | 246 | auto& scheduler = *kernel.CurrentScheduler(); |
| 248 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 247 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 249 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); | 248 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); |
| 250 | ASSERT(scheduler.ContextSwitchPending()); | 249 | ASSERT(scheduler.ContextSwitchPending()); |
| 251 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 250 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| @@ -255,22 +254,23 @@ void CpuManager::SingleCoreRunSuspendThread() { | |||
| 255 | 254 | ||
| 256 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | 255 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { |
| 257 | { | 256 | { |
| 258 | auto& scheduler = system.Kernel().Scheduler(current_core); | 257 | auto& kernel = system.Kernel(); |
| 259 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 258 | auto& scheduler = kernel.Scheduler(current_core); |
| 259 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | ||
| 260 | if (idle_count >= 4 || from_running_enviroment) { | 260 | if (idle_count >= 4 || from_running_enviroment) { |
| 261 | if (!from_running_enviroment) { | 261 | if (!from_running_enviroment) { |
| 262 | system.CoreTiming().Idle(); | 262 | system.CoreTiming().Idle(); |
| 263 | idle_count = 0; | 263 | idle_count = 0; |
| 264 | } | 264 | } |
| 265 | current_thread->SetPhantomMode(true); | 265 | kernel.SetIsPhantomModeForSingleCore(true); |
| 266 | system.CoreTiming().Advance(); | 266 | system.CoreTiming().Advance(); |
| 267 | current_thread->SetPhantomMode(false); | 267 | kernel.SetIsPhantomModeForSingleCore(false); |
| 268 | } | 268 | } |
| 269 | current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); | 269 | current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); |
| 270 | system.CoreTiming().ResetTicks(); | 270 | system.CoreTiming().ResetTicks(); |
| 271 | scheduler.Unload(scheduler.GetCurrentThread()); | 271 | scheduler.Unload(scheduler.GetCurrentThread()); |
| 272 | 272 | ||
| 273 | auto& next_scheduler = system.Kernel().Scheduler(current_core); | 273 | auto& next_scheduler = kernel.Scheduler(current_core); |
| 274 | Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); | 274 | Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); |
| 275 | } | 275 | } |
| 276 | 276 | ||
| @@ -278,8 +278,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | |||
| 278 | { | 278 | { |
| 279 | auto& scheduler = system.Kernel().Scheduler(current_core); | 279 | auto& scheduler = system.Kernel().Scheduler(current_core); |
| 280 | scheduler.Reload(scheduler.GetCurrentThread()); | 280 | scheduler.Reload(scheduler.GetCurrentThread()); |
| 281 | auto* currrent_thread2 = scheduler.GetCurrentThread(); | 281 | if (!scheduler.IsIdle()) { |
| 282 | if (!currrent_thread2->IsIdleThread()) { | ||
| 283 | idle_count = 0; | 282 | idle_count = 0; |
| 284 | } | 283 | } |
| 285 | } | 284 | } |
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index cebe2ce37..ad116dcc0 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -568,6 +568,11 @@ KeyManager::KeyManager() { | |||
| 568 | // Initialize keys | 568 | // Initialize keys |
| 569 | const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath(); | 569 | const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath(); |
| 570 | const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir); | 570 | const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir); |
| 571 | |||
| 572 | if (!Common::FS::Exists(yuzu_keys_dir)) { | ||
| 573 | Common::FS::CreateDir(yuzu_keys_dir); | ||
| 574 | } | ||
| 575 | |||
| 571 | if (Settings::values.use_dev_keys) { | 576 | if (Settings::values.use_dev_keys) { |
| 572 | dev_mode = true; | 577 | dev_mode = true; |
| 573 | AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false); | 578 | AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false); |
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index 17f774baa..86c9f5350 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h | |||
| @@ -58,7 +58,7 @@ struct SaveDataAttribute { | |||
| 58 | SaveDataType type; | 58 | SaveDataType type; |
| 59 | SaveDataRank rank; | 59 | SaveDataRank rank; |
| 60 | u16 index; | 60 | u16 index; |
| 61 | INSERT_PADDING_BYTES(4); | 61 | INSERT_PADDING_BYTES_NOINIT(4); |
| 62 | u64 zero_1; | 62 | u64 zero_1; |
| 63 | u64 zero_2; | 63 | u64 zero_2; |
| 64 | u64 zero_3; | 64 | u64 zero_3; |
| @@ -72,7 +72,7 @@ struct SaveDataExtraData { | |||
| 72 | u64 owner_id; | 72 | u64 owner_id; |
| 73 | s64 timestamp; | 73 | s64 timestamp; |
| 74 | SaveDataFlags flags; | 74 | SaveDataFlags flags; |
| 75 | INSERT_PADDING_BYTES(4); | 75 | INSERT_PADDING_BYTES_NOINIT(4); |
| 76 | s64 available_size; | 76 | s64 available_size; |
| 77 | s64 journal_size; | 77 | s64 journal_size; |
| 78 | s64 commit_id; | 78 | s64 commit_id; |
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index a287eebe3..a44ce6288 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -133,8 +133,11 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ | |||
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | cache.erase(old_path); | 135 | cache.erase(old_path); |
| 136 | file->Open(new_path, "r+b"); | 136 | if (file->Open(new_path, "r+b")) { |
| 137 | cache.insert_or_assign(new_path, std::move(file)); | 137 | cache.insert_or_assign(new_path, std::move(file)); |
| 138 | } else { | ||
| 139 | LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", new_path); | ||
| 140 | } | ||
| 138 | } else { | 141 | } else { |
| 139 | UNREACHABLE(); | 142 | UNREACHABLE(); |
| 140 | return nullptr; | 143 | return nullptr; |
| @@ -214,9 +217,12 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, | |||
| 214 | } | 217 | } |
| 215 | 218 | ||
| 216 | auto file = cached.lock(); | 219 | auto file = cached.lock(); |
| 217 | file->Open(file_new_path, "r+b"); | ||
| 218 | cache.erase(file_old_path); | 220 | cache.erase(file_old_path); |
| 219 | cache.insert_or_assign(std::move(file_new_path), std::move(file)); | 221 | if (file->Open(file_new_path, "r+b")) { |
| 222 | cache.insert_or_assign(std::move(file_new_path), std::move(file)); | ||
| 223 | } else { | ||
| 224 | LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", file_new_path); | ||
| 225 | } | ||
| 220 | } | 226 | } |
| 221 | 227 | ||
| 222 | return OpenDirectory(new_path, Mode::ReadWrite); | 228 | return OpenDirectory(new_path, Mode::ReadWrite); |
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 8c1193894..ee7a58b1c 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -21,21 +21,18 @@ public: | |||
| 21 | 21 | ||
| 22 | std::mutex mutex; | 22 | std::mutex mutex; |
| 23 | 23 | ||
| 24 | bool touch_pressed = false; ///< True if touchpad area is currently pressed, otherwise false | 24 | Input::TouchStatus status; |
| 25 | |||
| 26 | float touch_x = 0.0f; ///< Touchpad X-position | ||
| 27 | float touch_y = 0.0f; ///< Touchpad Y-position | ||
| 28 | 25 | ||
| 29 | private: | 26 | private: |
| 30 | class Device : public Input::TouchDevice { | 27 | class Device : public Input::TouchDevice { |
| 31 | public: | 28 | public: |
| 32 | explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} | 29 | explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} |
| 33 | std::tuple<float, float, bool> GetStatus() const override { | 30 | Input::TouchStatus GetStatus() const override { |
| 34 | if (auto state = touch_state.lock()) { | 31 | if (auto state = touch_state.lock()) { |
| 35 | std::lock_guard guard{state->mutex}; | 32 | std::lock_guard guard{state->mutex}; |
| 36 | return std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed); | 33 | return state->status; |
| 37 | } | 34 | } |
| 38 | return std::make_tuple(0.0f, 0.0f, false); | 35 | return {}; |
| 39 | } | 36 | } |
| 40 | 37 | ||
| 41 | private: | 38 | private: |
| @@ -79,36 +76,44 @@ std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsi | |||
| 79 | return std::make_tuple(new_x, new_y); | 76 | return std::make_tuple(new_x, new_y); |
| 80 | } | 77 | } |
| 81 | 78 | ||
| 82 | void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { | 79 | void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) { |
| 83 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | 80 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { |
| 84 | return; | 81 | return; |
| 82 | } | ||
| 83 | if (id >= touch_state->status.size()) { | ||
| 84 | return; | ||
| 85 | } | ||
| 85 | 86 | ||
| 86 | std::lock_guard guard{touch_state->mutex}; | 87 | std::lock_guard guard{touch_state->mutex}; |
| 87 | touch_state->touch_x = | 88 | const float x = |
| 88 | static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / | 89 | static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / |
| 89 | static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left); | 90 | static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left); |
| 90 | touch_state->touch_y = | 91 | const float y = |
| 91 | static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / | 92 | static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / |
| 92 | static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); | 93 | static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); |
| 93 | 94 | ||
| 94 | touch_state->touch_pressed = true; | 95 | touch_state->status[id] = std::make_tuple(x, y, true); |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | void EmuWindow::TouchReleased() { | 98 | void EmuWindow::TouchReleased(std::size_t id) { |
| 99 | if (id >= touch_state->status.size()) { | ||
| 100 | return; | ||
| 101 | } | ||
| 98 | std::lock_guard guard{touch_state->mutex}; | 102 | std::lock_guard guard{touch_state->mutex}; |
| 99 | touch_state->touch_pressed = false; | 103 | touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false); |
| 100 | touch_state->touch_x = 0; | ||
| 101 | touch_state->touch_y = 0; | ||
| 102 | } | 104 | } |
| 103 | 105 | ||
| 104 | void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { | 106 | void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) { |
| 105 | if (!touch_state->touch_pressed) | 107 | if (id >= touch_state->status.size()) { |
| 108 | return; | ||
| 109 | } | ||
| 110 | if (!std::get<2>(touch_state->status[id])) | ||
| 106 | return; | 111 | return; |
| 107 | 112 | ||
| 108 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | 113 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) |
| 109 | std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); | 114 | std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); |
| 110 | 115 | ||
| 111 | TouchPressed(framebuffer_x, framebuffer_y); | 116 | TouchPressed(framebuffer_x, framebuffer_y, id); |
| 112 | } | 117 | } |
| 113 | 118 | ||
| 114 | void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { | 119 | void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 276d2b906..2436c6580 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -117,18 +117,23 @@ public: | |||
| 117 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) | 117 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) |
| 118 | * @param framebuffer_x Framebuffer x-coordinate that was pressed | 118 | * @param framebuffer_x Framebuffer x-coordinate that was pressed |
| 119 | * @param framebuffer_y Framebuffer y-coordinate that was pressed | 119 | * @param framebuffer_y Framebuffer y-coordinate that was pressed |
| 120 | * @param id Touch event ID | ||
| 120 | */ | 121 | */ |
| 121 | void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y); | 122 | void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id); |
| 122 | 123 | ||
| 123 | /// Signal that a touch released event has occurred (e.g. mouse click released) | 124 | /** |
| 124 | void TouchReleased(); | 125 | * Signal that a touch released event has occurred (e.g. mouse click released) |
| 126 | * @param id Touch event ID | ||
| 127 | */ | ||
| 128 | void TouchReleased(std::size_t id); | ||
| 125 | 129 | ||
| 126 | /** | 130 | /** |
| 127 | * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) | 131 | * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) |
| 128 | * @param framebuffer_x Framebuffer x-coordinate | 132 | * @param framebuffer_x Framebuffer x-coordinate |
| 129 | * @param framebuffer_y Framebuffer y-coordinate | 133 | * @param framebuffer_y Framebuffer y-coordinate |
| 134 | * @param id Touch event ID | ||
| 130 | */ | 135 | */ |
| 131 | void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); | 136 | void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id); |
| 132 | 137 | ||
| 133 | /** | 138 | /** |
| 134 | * Returns currently active configuration. | 139 | * Returns currently active configuration. |
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index de51a754e..88ebc6497 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -21,6 +21,11 @@ enum class AnalogDirection : u8 { | |||
| 21 | UP, | 21 | UP, |
| 22 | DOWN, | 22 | DOWN, |
| 23 | }; | 23 | }; |
| 24 | struct AnalogProperties { | ||
| 25 | float deadzone; | ||
| 26 | float range; | ||
| 27 | float threshold; | ||
| 28 | }; | ||
| 24 | 29 | ||
| 25 | /// An abstract class template for an input device (a button, an analog input, etc.). | 30 | /// An abstract class template for an input device (a button, an analog input, etc.). |
| 26 | template <typename StatusType> | 31 | template <typename StatusType> |
| @@ -30,6 +35,12 @@ public: | |||
| 30 | virtual StatusType GetStatus() const { | 35 | virtual StatusType GetStatus() const { |
| 31 | return {}; | 36 | return {}; |
| 32 | } | 37 | } |
| 38 | virtual StatusType GetRawStatus() const { | ||
| 39 | return GetStatus(); | ||
| 40 | } | ||
| 41 | virtual AnalogProperties GetAnalogProperties() const { | ||
| 42 | return {}; | ||
| 43 | } | ||
| 33 | virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { | 44 | virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { |
| 34 | return {}; | 45 | return {}; |
| 35 | } | 46 | } |
| @@ -163,10 +174,11 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common | |||
| 163 | using MotionDevice = InputDevice<MotionStatus>; | 174 | using MotionDevice = InputDevice<MotionStatus>; |
| 164 | 175 | ||
| 165 | /** | 176 | /** |
| 166 | * A touch status is an object that returns a tuple of two floats and a bool. The floats are | 177 | * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool. |
| 167 | * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. | 178 | * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is |
| 179 | * pressed. | ||
| 168 | */ | 180 | */ |
| 169 | using TouchStatus = std::tuple<float, float, bool>; | 181 | using TouchStatus = std::array<std::tuple<float, float, bool>, 16>; |
| 170 | 182 | ||
| 171 | /** | 183 | /** |
| 172 | * A touch device is an input device that returns a touch status object | 184 | * A touch device is an input device that returns a touch status object |
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 456b41e1b..176a72c67 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h | |||
| @@ -4,8 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include <tuple> | 8 | #include <tuple> |
| 8 | 9 | ||
| 10 | #include "common/bit_util.h" | ||
| 9 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 10 | 12 | ||
| 11 | namespace Core { | 13 | namespace Core { |
| @@ -18,34 +20,12 @@ constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz u | |||
| 18 | constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed | 20 | constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed |
| 19 | constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores | 21 | constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores |
| 20 | 22 | ||
| 21 | } // namespace Hardware | 23 | // Virtual to Physical core map. |
| 22 | 24 | constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{ | |
| 23 | constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF; | 25 | 0, 1, 2, 3, 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, |
| 24 | 26 | 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, 3, | |
| 25 | struct EmuThreadHandle { | ||
| 26 | u32 host_handle; | ||
| 27 | u32 guest_handle; | ||
| 28 | |||
| 29 | u64 GetRaw() const { | ||
| 30 | return (static_cast<u64>(host_handle) << 32) | guest_handle; | ||
| 31 | } | ||
| 32 | |||
| 33 | bool operator==(const EmuThreadHandle& rhs) const { | ||
| 34 | return std::tie(host_handle, guest_handle) == std::tie(rhs.host_handle, rhs.guest_handle); | ||
| 35 | } | ||
| 36 | |||
| 37 | bool operator!=(const EmuThreadHandle& rhs) const { | ||
| 38 | return !operator==(rhs); | ||
| 39 | } | ||
| 40 | |||
| 41 | static constexpr EmuThreadHandle InvalidHandle() { | ||
| 42 | constexpr u32 invalid_handle = 0xFFFFFFFF; | ||
| 43 | return {invalid_handle, invalid_handle}; | ||
| 44 | } | ||
| 45 | |||
| 46 | bool IsInvalid() const { | ||
| 47 | return (*this) == InvalidHandle(); | ||
| 48 | } | ||
| 49 | }; | 27 | }; |
| 50 | 28 | ||
| 29 | } // namespace Hardware | ||
| 30 | |||
| 51 | } // namespace Core | 31 | } // namespace Core |
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 79bcf5762..55b1716e4 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h | |||
| @@ -146,7 +146,7 @@ static_assert(sizeof(BufferDescriptorC) == 8, "BufferDescriptorC size is incorre | |||
| 146 | 146 | ||
| 147 | struct DataPayloadHeader { | 147 | struct DataPayloadHeader { |
| 148 | u32_le magic; | 148 | u32_le magic; |
| 149 | INSERT_PADDING_WORDS(1); | 149 | INSERT_PADDING_WORDS_NOINIT(1); |
| 150 | }; | 150 | }; |
| 151 | static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadHeader size is incorrect"); | 151 | static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadHeader size is incorrect"); |
| 152 | 152 | ||
| @@ -174,7 +174,7 @@ struct DomainMessageHeader { | |||
| 174 | INSERT_PADDING_WORDS_NOINIT(2); | 174 | INSERT_PADDING_WORDS_NOINIT(2); |
| 175 | }; | 175 | }; |
| 176 | 176 | ||
| 177 | std::array<u32, 4> raw{}; | 177 | std::array<u32, 4> raw; |
| 178 | }; | 178 | }; |
| 179 | }; | 179 | }; |
| 180 | static_assert(sizeof(DomainMessageHeader) == 16, "DomainMessageHeader size is incorrect"); | 180 | static_assert(sizeof(DomainMessageHeader) == 16, "DomainMessageHeader size is incorrect"); |
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 9762bbf0d..77559ebf9 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h | |||
| @@ -51,6 +51,8 @@ public: | |||
| 51 | */ | 51 | */ |
| 52 | void ConnectionClosed(); | 52 | void ConnectionClosed(); |
| 53 | 53 | ||
| 54 | void Finalize() override {} | ||
| 55 | |||
| 54 | private: | 56 | private: |
| 55 | std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port. | 57 | std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port. |
| 56 | u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have | 58 | u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have |
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index e8e52900d..a2be1a8f6 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp | |||
| @@ -5,9 +5,9 @@ | |||
| 5 | #include "core/hle/kernel/client_session.h" | 5 | #include "core/hle/kernel/client_session.h" |
| 6 | #include "core/hle/kernel/errors.h" | 6 | #include "core/hle/kernel/errors.h" |
| 7 | #include "core/hle/kernel/hle_ipc.h" | 7 | #include "core/hle/kernel/hle_ipc.h" |
| 8 | #include "core/hle/kernel/k_thread.h" | ||
| 8 | #include "core/hle/kernel/server_session.h" | 9 | #include "core/hle/kernel/server_session.h" |
| 9 | #include "core/hle/kernel/session.h" | 10 | #include "core/hle/kernel/session.h" |
| 10 | #include "core/hle/kernel/thread.h" | ||
| 11 | #include "core/hle/result.h" | 11 | #include "core/hle/result.h" |
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| @@ -38,7 +38,7 @@ ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kern | |||
| 38 | return MakeResult(std::move(client_session)); | 38 | return MakeResult(std::move(client_session)); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread, | 41 | ResultCode ClientSession::SendSyncRequest(std::shared_ptr<KThread> thread, |
| 42 | Core::Memory::Memory& memory, | 42 | Core::Memory::Memory& memory, |
| 43 | Core::Timing::CoreTiming& core_timing) { | 43 | Core::Timing::CoreTiming& core_timing) { |
| 44 | // Keep ServerSession alive until we're done working with it. | 44 | // Keep ServerSession alive until we're done working with it. |
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index d5c9ebee8..85aafeaf4 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h | |||
| @@ -24,7 +24,7 @@ namespace Kernel { | |||
| 24 | 24 | ||
| 25 | class KernelCore; | 25 | class KernelCore; |
| 26 | class Session; | 26 | class Session; |
| 27 | class Thread; | 27 | class KThread; |
| 28 | 28 | ||
| 29 | class ClientSession final : public KSynchronizationObject { | 29 | class ClientSession final : public KSynchronizationObject { |
| 30 | public: | 30 | public: |
| @@ -46,11 +46,13 @@ public: | |||
| 46 | return HANDLE_TYPE; | 46 | return HANDLE_TYPE; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory, | 49 | ResultCode SendSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory, |
| 50 | Core::Timing::CoreTiming& core_timing); | 50 | Core::Timing::CoreTiming& core_timing); |
| 51 | 51 | ||
| 52 | bool IsSignaled() const override; | 52 | bool IsSignaled() const override; |
| 53 | 53 | ||
| 54 | void Finalize() override {} | ||
| 55 | |||
| 54 | private: | 56 | private: |
| 55 | static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, | 57 | static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, |
| 56 | std::shared_ptr<Session> parent, | 58 | std::shared_ptr<Session> parent, |
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index a133e8ed0..c6838649f 100644 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp | |||
| @@ -17,12 +17,12 @@ GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel) | |||
| 17 | 17 | ||
| 18 | GlobalSchedulerContext::~GlobalSchedulerContext() = default; | 18 | GlobalSchedulerContext::~GlobalSchedulerContext() = default; |
| 19 | 19 | ||
| 20 | void GlobalSchedulerContext::AddThread(std::shared_ptr<Thread> thread) { | 20 | void GlobalSchedulerContext::AddThread(std::shared_ptr<KThread> thread) { |
| 21 | std::scoped_lock lock{global_list_guard}; | 21 | std::scoped_lock lock{global_list_guard}; |
| 22 | thread_list.push_back(std::move(thread)); | 22 | thread_list.push_back(std::move(thread)); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | void GlobalSchedulerContext::RemoveThread(std::shared_ptr<Thread> thread) { | 25 | void GlobalSchedulerContext::RemoveThread(std::shared_ptr<KThread> thread) { |
| 26 | std::scoped_lock lock{global_list_guard}; | 26 | std::scoped_lock lock{global_list_guard}; |
| 27 | thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), | 27 | thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), |
| 28 | thread_list.end()); | 28 | thread_list.end()); |
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h index 5c7b89290..11592843e 100644 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h | |||
| @@ -12,7 +12,8 @@ | |||
| 12 | #include "core/hardware_properties.h" | 12 | #include "core/hardware_properties.h" |
| 13 | #include "core/hle/kernel/k_priority_queue.h" | 13 | #include "core/hle/kernel/k_priority_queue.h" |
| 14 | #include "core/hle/kernel/k_scheduler_lock.h" | 14 | #include "core/hle/kernel/k_scheduler_lock.h" |
| 15 | #include "core/hle/kernel/thread.h" | 15 | #include "core/hle/kernel/k_thread.h" |
| 16 | #include "core/hle/kernel/svc_types.h" | ||
| 16 | 17 | ||
| 17 | namespace Kernel { | 18 | namespace Kernel { |
| 18 | 19 | ||
| @@ -20,8 +21,12 @@ class KernelCore; | |||
| 20 | class SchedulerLock; | 21 | class SchedulerLock; |
| 21 | 22 | ||
| 22 | using KSchedulerPriorityQueue = | 23 | using KSchedulerPriorityQueue = |
| 23 | KPriorityQueue<Thread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>; | 24 | KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority, |
| 24 | constexpr s32 HighestCoreMigrationAllowedPriority = 2; | 25 | Svc::HighestThreadPriority>; |
| 26 | |||
| 27 | static constexpr s32 HighestCoreMigrationAllowedPriority = 2; | ||
| 28 | static_assert(Svc::LowestThreadPriority >= HighestCoreMigrationAllowedPriority); | ||
| 29 | static_assert(Svc::HighestThreadPriority <= HighestCoreMigrationAllowedPriority); | ||
| 25 | 30 | ||
| 26 | class GlobalSchedulerContext final { | 31 | class GlobalSchedulerContext final { |
| 27 | friend class KScheduler; | 32 | friend class KScheduler; |
| @@ -33,13 +38,13 @@ public: | |||
| 33 | ~GlobalSchedulerContext(); | 38 | ~GlobalSchedulerContext(); |
| 34 | 39 | ||
| 35 | /// Adds a new thread to the scheduler | 40 | /// Adds a new thread to the scheduler |
| 36 | void AddThread(std::shared_ptr<Thread> thread); | 41 | void AddThread(std::shared_ptr<KThread> thread); |
| 37 | 42 | ||
| 38 | /// Removes a thread from the scheduler | 43 | /// Removes a thread from the scheduler |
| 39 | void RemoveThread(std::shared_ptr<Thread> thread); | 44 | void RemoveThread(std::shared_ptr<KThread> thread); |
| 40 | 45 | ||
| 41 | /// Returns a list of all threads managed by the scheduler | 46 | /// Returns a list of all threads managed by the scheduler |
| 42 | [[nodiscard]] const std::vector<std::shared_ptr<Thread>>& GetThreadList() const { | 47 | [[nodiscard]] const std::vector<std::shared_ptr<KThread>>& GetThreadList() const { |
| 43 | return thread_list; | 48 | return thread_list; |
| 44 | } | 49 | } |
| 45 | 50 | ||
| @@ -74,7 +79,7 @@ private: | |||
| 74 | LockType scheduler_lock; | 79 | LockType scheduler_lock; |
| 75 | 80 | ||
| 76 | /// Lists all thread ids that aren't deleted/etc. | 81 | /// Lists all thread ids that aren't deleted/etc. |
| 77 | std::vector<std::shared_ptr<Thread>> thread_list; | 82 | std::vector<std::shared_ptr<KThread>> thread_list; |
| 78 | Common::SpinLock global_list_guard{}; | 83 | Common::SpinLock global_list_guard{}; |
| 79 | }; | 84 | }; |
| 80 | 85 | ||
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 40988b0fd..1a2fa9cd8 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp | |||
| @@ -9,9 +9,9 @@ | |||
| 9 | #include "core/hle/kernel/errors.h" | 9 | #include "core/hle/kernel/errors.h" |
| 10 | #include "core/hle/kernel/handle_table.h" | 10 | #include "core/hle/kernel/handle_table.h" |
| 11 | #include "core/hle/kernel/k_scheduler.h" | 11 | #include "core/hle/kernel/k_scheduler.h" |
| 12 | #include "core/hle/kernel/k_thread.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/kernel/thread.h" | ||
| 15 | 15 | ||
| 16 | namespace Kernel { | 16 | namespace Kernel { |
| 17 | namespace { | 17 | namespace { |
| @@ -89,6 +89,10 @@ ResultCode HandleTable::Close(Handle handle) { | |||
| 89 | 89 | ||
| 90 | const u16 slot = GetSlot(handle); | 90 | const u16 slot = GetSlot(handle); |
| 91 | 91 | ||
| 92 | if (objects[slot].use_count() == 1) { | ||
| 93 | objects[slot]->Finalize(); | ||
| 94 | } | ||
| 95 | |||
| 92 | objects[slot] = nullptr; | 96 | objects[slot] = nullptr; |
| 93 | 97 | ||
| 94 | generations[slot] = next_free_slot; | 98 | generations[slot] = next_free_slot; |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 83decf6cf..7ec62cf18 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -17,16 +17,16 @@ | |||
| 17 | #include "core/hle/kernel/errors.h" | 17 | #include "core/hle/kernel/errors.h" |
| 18 | #include "core/hle/kernel/handle_table.h" | 18 | #include "core/hle/kernel/handle_table.h" |
| 19 | #include "core/hle/kernel/hle_ipc.h" | 19 | #include "core/hle/kernel/hle_ipc.h" |
| 20 | #include "core/hle/kernel/k_readable_event.h" | ||
| 20 | #include "core/hle/kernel/k_scheduler.h" | 21 | #include "core/hle/kernel/k_scheduler.h" |
| 21 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 22 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 23 | #include "core/hle/kernel/k_thread.h" | ||
| 24 | #include "core/hle/kernel/k_writable_event.h" | ||
| 22 | #include "core/hle/kernel/kernel.h" | 25 | #include "core/hle/kernel/kernel.h" |
| 23 | #include "core/hle/kernel/object.h" | 26 | #include "core/hle/kernel/object.h" |
| 24 | #include "core/hle/kernel/process.h" | 27 | #include "core/hle/kernel/process.h" |
| 25 | #include "core/hle/kernel/readable_event.h" | ||
| 26 | #include "core/hle/kernel/server_session.h" | 28 | #include "core/hle/kernel/server_session.h" |
| 27 | #include "core/hle/kernel/thread.h" | ||
| 28 | #include "core/hle/kernel/time_manager.h" | 29 | #include "core/hle/kernel/time_manager.h" |
| 29 | #include "core/hle/kernel/writable_event.h" | ||
| 30 | #include "core/memory.h" | 30 | #include "core/memory.h" |
| 31 | 31 | ||
| 32 | namespace Kernel { | 32 | namespace Kernel { |
| @@ -48,7 +48,7 @@ void SessionRequestHandler::ClientDisconnected( | |||
| 48 | 48 | ||
| 49 | HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, | 49 | HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, |
| 50 | std::shared_ptr<ServerSession> server_session, | 50 | std::shared_ptr<ServerSession> server_session, |
| 51 | std::shared_ptr<Thread> thread) | 51 | std::shared_ptr<KThread> thread) |
| 52 | : server_session(std::move(server_session)), | 52 | : server_session(std::move(server_session)), |
| 53 | thread(std::move(thread)), kernel{kernel}, memory{memory} { | 53 | thread(std::move(thread)), kernel{kernel}, memory{memory} { |
| 54 | cmd_buf[0] = 0; | 54 | cmd_buf[0] = 0; |
| @@ -182,7 +182,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl | |||
| 182 | return RESULT_SUCCESS; | 182 | return RESULT_SUCCESS; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { | 185 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { |
| 186 | auto& owner_process = *thread.GetOwnerProcess(); | 186 | auto& owner_process = *thread.GetOwnerProcess(); |
| 187 | auto& handle_table = owner_process.GetHandleTable(); | 187 | auto& handle_table = owner_process.GetHandleTable(); |
| 188 | 188 | ||
| @@ -338,6 +338,28 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons | |||
| 338 | return 0; | 338 | return 0; |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | bool HLERequestContext::CanReadBuffer(std::size_t buffer_index) const { | ||
| 342 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && | ||
| 343 | BufferDescriptorA()[buffer_index].Size()}; | ||
| 344 | |||
| 345 | if (is_buffer_a) { | ||
| 346 | return BufferDescriptorA().size() > buffer_index; | ||
| 347 | } else { | ||
| 348 | return BufferDescriptorX().size() > buffer_index; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | bool HLERequestContext::CanWriteBuffer(std::size_t buffer_index) const { | ||
| 353 | const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && | ||
| 354 | BufferDescriptorB()[buffer_index].Size()}; | ||
| 355 | |||
| 356 | if (is_buffer_b) { | ||
| 357 | return BufferDescriptorB().size() > buffer_index; | ||
| 358 | } else { | ||
| 359 | return BufferDescriptorC().size() > buffer_index; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 341 | std::string HLERequestContext::Description() const { | 363 | std::string HLERequestContext::Description() const { |
| 342 | if (!command_header) { | 364 | if (!command_header) { |
| 343 | return "No command header available"; | 365 | return "No command header available"; |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index b112e1ebd..9a769781b 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -40,9 +40,9 @@ class HLERequestContext; | |||
| 40 | class KernelCore; | 40 | class KernelCore; |
| 41 | class Process; | 41 | class Process; |
| 42 | class ServerSession; | 42 | class ServerSession; |
| 43 | class Thread; | 43 | class KThread; |
| 44 | class ReadableEvent; | 44 | class KReadableEvent; |
| 45 | class WritableEvent; | 45 | class KWritableEvent; |
| 46 | 46 | ||
| 47 | enum class ThreadWakeupReason; | 47 | enum class ThreadWakeupReason; |
| 48 | 48 | ||
| @@ -110,7 +110,7 @@ class HLERequestContext { | |||
| 110 | public: | 110 | public: |
| 111 | explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, | 111 | explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, |
| 112 | std::shared_ptr<ServerSession> session, | 112 | std::shared_ptr<ServerSession> session, |
| 113 | std::shared_ptr<Thread> thread); | 113 | std::shared_ptr<KThread> thread); |
| 114 | ~HLERequestContext(); | 114 | ~HLERequestContext(); |
| 115 | 115 | ||
| 116 | /// Returns a pointer to the IPC command buffer for this request. | 116 | /// Returns a pointer to the IPC command buffer for this request. |
| @@ -126,15 +126,12 @@ public: | |||
| 126 | return server_session; | 126 | return server_session; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | using WakeupCallback = std::function<void( | ||
| 130 | std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>; | ||
| 131 | |||
| 132 | /// Populates this context with data from the requesting process/thread. | 129 | /// Populates this context with data from the requesting process/thread. |
| 133 | ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, | 130 | ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, |
| 134 | u32_le* src_cmdbuf); | 131 | u32_le* src_cmdbuf); |
| 135 | 132 | ||
| 136 | /// Writes data from this context back to the requesting process/thread. | 133 | /// Writes data from this context back to the requesting process/thread. |
| 137 | ResultCode WriteToOutgoingCommandBuffer(Thread& thread); | 134 | ResultCode WriteToOutgoingCommandBuffer(KThread& thread); |
| 138 | 135 | ||
| 139 | u32_le GetCommand() const { | 136 | u32_le GetCommand() const { |
| 140 | return command; | 137 | return command; |
| @@ -207,6 +204,12 @@ public: | |||
| 207 | /// Helper function to get the size of the output buffer | 204 | /// Helper function to get the size of the output buffer |
| 208 | std::size_t GetWriteBufferSize(std::size_t buffer_index = 0) const; | 205 | std::size_t GetWriteBufferSize(std::size_t buffer_index = 0) const; |
| 209 | 206 | ||
| 207 | /// Helper function to test whether the input buffer at buffer_index can be read | ||
| 208 | bool CanReadBuffer(std::size_t buffer_index = 0) const; | ||
| 209 | |||
| 210 | /// Helper function to test whether the output buffer at buffer_index can be written | ||
| 211 | bool CanWriteBuffer(std::size_t buffer_index = 0) const; | ||
| 212 | |||
| 210 | template <typename T> | 213 | template <typename T> |
| 211 | std::shared_ptr<T> GetCopyObject(std::size_t index) { | 214 | std::shared_ptr<T> GetCopyObject(std::size_t index) { |
| 212 | return DynamicObjectCast<T>(copy_objects.at(index)); | 215 | return DynamicObjectCast<T>(copy_objects.at(index)); |
| @@ -261,11 +264,11 @@ public: | |||
| 261 | 264 | ||
| 262 | std::string Description() const; | 265 | std::string Description() const; |
| 263 | 266 | ||
| 264 | Thread& GetThread() { | 267 | KThread& GetThread() { |
| 265 | return *thread; | 268 | return *thread; |
| 266 | } | 269 | } |
| 267 | 270 | ||
| 268 | const Thread& GetThread() const { | 271 | const KThread& GetThread() const { |
| 269 | return *thread; | 272 | return *thread; |
| 270 | } | 273 | } |
| 271 | 274 | ||
| @@ -280,7 +283,7 @@ private: | |||
| 280 | 283 | ||
| 281 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; | 284 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; |
| 282 | std::shared_ptr<Kernel::ServerSession> server_session; | 285 | std::shared_ptr<Kernel::ServerSession> server_session; |
| 283 | std::shared_ptr<Thread> thread; | 286 | std::shared_ptr<KThread> thread; |
| 284 | // TODO(yuriks): Check common usage of this and optimize size accordingly | 287 | // TODO(yuriks): Check common usage of this and optimize size accordingly |
| 285 | boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; | 288 | boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; |
| 286 | boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; | 289 | boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; |
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index d9e702f13..d0e90fd60 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp | |||
| @@ -7,9 +7,9 @@ | |||
| 7 | #include "core/hle/kernel/k_address_arbiter.h" | 7 | #include "core/hle/kernel/k_address_arbiter.h" |
| 8 | #include "core/hle/kernel/k_scheduler.h" | 8 | #include "core/hle/kernel/k_scheduler.h" |
| 9 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 9 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 10 | #include "core/hle/kernel/k_thread.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/svc_results.h" | 12 | #include "core/hle/kernel/svc_results.h" |
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | #include "core/hle/kernel/time_manager.h" | 13 | #include "core/hle/kernel/time_manager.h" |
| 14 | #include "core/memory.h" | 14 | #include "core/memory.h" |
| 15 | 15 | ||
| @@ -96,7 +96,7 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { | |||
| 96 | auto it = thread_tree.nfind_light({addr, -1}); | 96 | auto it = thread_tree.nfind_light({addr, -1}); |
| 97 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && | 97 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && |
| 98 | (it->GetAddressArbiterKey() == addr)) { | 98 | (it->GetAddressArbiterKey() == addr)) { |
| 99 | Thread* target_thread = std::addressof(*it); | 99 | KThread* target_thread = std::addressof(*it); |
| 100 | target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); | 100 | target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); |
| 101 | 101 | ||
| 102 | ASSERT(target_thread->IsWaitingForAddressArbiter()); | 102 | ASSERT(target_thread->IsWaitingForAddressArbiter()); |
| @@ -118,14 +118,18 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 | |||
| 118 | 118 | ||
| 119 | // Check the userspace value. | 119 | // Check the userspace value. |
| 120 | s32 user_value{}; | 120 | s32 user_value{}; |
| 121 | R_UNLESS(UpdateIfEqual(system, std::addressof(user_value), addr, value, value + 1), | 121 | if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) { |
| 122 | Svc::ResultInvalidCurrentMemory); | 122 | LOG_ERROR(Kernel, "Invalid current memory!"); |
| 123 | R_UNLESS(user_value == value, Svc::ResultInvalidState); | 123 | return Svc::ResultInvalidCurrentMemory; |
| 124 | } | ||
| 125 | if (user_value != value) { | ||
| 126 | return Svc::ResultInvalidState; | ||
| 127 | } | ||
| 124 | 128 | ||
| 125 | auto it = thread_tree.nfind_light({addr, -1}); | 129 | auto it = thread_tree.nfind_light({addr, -1}); |
| 126 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && | 130 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && |
| 127 | (it->GetAddressArbiterKey() == addr)) { | 131 | (it->GetAddressArbiterKey() == addr)) { |
| 128 | Thread* target_thread = std::addressof(*it); | 132 | KThread* target_thread = std::addressof(*it); |
| 129 | target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); | 133 | target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); |
| 130 | 134 | ||
| 131 | ASSERT(target_thread->IsWaitingForAddressArbiter()); | 135 | ASSERT(target_thread->IsWaitingForAddressArbiter()); |
| @@ -143,61 +147,34 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 | |||
| 143 | // Perform signaling. | 147 | // Perform signaling. |
| 144 | s32 num_waiters{}; | 148 | s32 num_waiters{}; |
| 145 | { | 149 | { |
| 146 | KScopedSchedulerLock sl(kernel); | 150 | [[maybe_unused]] const KScopedSchedulerLock sl(kernel); |
| 147 | 151 | ||
| 148 | auto it = thread_tree.nfind_light({addr, -1}); | 152 | auto it = thread_tree.nfind_light({addr, -1}); |
| 149 | // Determine the updated value. | 153 | // Determine the updated value. |
| 150 | s32 new_value{}; | 154 | s32 new_value{}; |
| 151 | if (/*GetTargetFirmware() >= TargetFirmware_7_0_0*/ true) { | 155 | if (count <= 0) { |
| 152 | if (count <= 0) { | 156 | if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) { |
| 153 | if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { | 157 | new_value = value - 2; |
| 154 | new_value = value - 2; | ||
| 155 | } else { | ||
| 156 | new_value = value + 1; | ||
| 157 | } | ||
| 158 | } else { | 158 | } else { |
| 159 | if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { | 159 | new_value = value + 1; |
| 160 | auto tmp_it = it; | ||
| 161 | s32 tmp_num_waiters{}; | ||
| 162 | while ((++tmp_it != thread_tree.end()) && | ||
| 163 | (tmp_it->GetAddressArbiterKey() == addr)) { | ||
| 164 | if ((tmp_num_waiters++) >= count) { | ||
| 165 | break; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | if (tmp_num_waiters < count) { | ||
| 170 | new_value = value - 1; | ||
| 171 | } else { | ||
| 172 | new_value = value; | ||
| 173 | } | ||
| 174 | } else { | ||
| 175 | new_value = value + 1; | ||
| 176 | } | ||
| 177 | } | 160 | } |
| 178 | } else { | 161 | } else { |
| 179 | if (count <= 0) { | 162 | if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) { |
| 180 | if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { | ||
| 181 | new_value = value - 1; | ||
| 182 | } else { | ||
| 183 | new_value = value + 1; | ||
| 184 | } | ||
| 185 | } else { | ||
| 186 | auto tmp_it = it; | 163 | auto tmp_it = it; |
| 187 | s32 tmp_num_waiters{}; | 164 | s32 tmp_num_waiters{}; |
| 188 | while ((tmp_it != thread_tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && | 165 | while (++tmp_it != thread_tree.end() && tmp_it->GetAddressArbiterKey() == addr) { |
| 189 | (tmp_num_waiters < count + 1)) { | 166 | if (tmp_num_waiters++ >= count) { |
| 190 | ++tmp_num_waiters; | 167 | break; |
| 191 | ++tmp_it; | 168 | } |
| 192 | } | 169 | } |
| 193 | 170 | ||
| 194 | if (tmp_num_waiters == 0) { | 171 | if (tmp_num_waiters < count) { |
| 195 | new_value = value + 1; | ||
| 196 | } else if (tmp_num_waiters <= count) { | ||
| 197 | new_value = value - 1; | 172 | new_value = value - 1; |
| 198 | } else { | 173 | } else { |
| 199 | new_value = value; | 174 | new_value = value; |
| 200 | } | 175 | } |
| 176 | } else { | ||
| 177 | new_value = value + 1; | ||
| 201 | } | 178 | } |
| 202 | } | 179 | } |
| 203 | 180 | ||
| @@ -205,17 +182,22 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 | |||
| 205 | s32 user_value{}; | 182 | s32 user_value{}; |
| 206 | bool succeeded{}; | 183 | bool succeeded{}; |
| 207 | if (value != new_value) { | 184 | if (value != new_value) { |
| 208 | succeeded = UpdateIfEqual(system, std::addressof(user_value), addr, value, new_value); | 185 | succeeded = UpdateIfEqual(system, &user_value, addr, value, new_value); |
| 209 | } else { | 186 | } else { |
| 210 | succeeded = ReadFromUser(system, std::addressof(user_value), addr); | 187 | succeeded = ReadFromUser(system, &user_value, addr); |
| 211 | } | 188 | } |
| 212 | 189 | ||
| 213 | R_UNLESS(succeeded, Svc::ResultInvalidCurrentMemory); | 190 | if (!succeeded) { |
| 214 | R_UNLESS(user_value == value, Svc::ResultInvalidState); | 191 | LOG_ERROR(Kernel, "Invalid current memory!"); |
| 192 | return Svc::ResultInvalidCurrentMemory; | ||
| 193 | } | ||
| 194 | if (user_value != value) { | ||
| 195 | return Svc::ResultInvalidState; | ||
| 196 | } | ||
| 215 | 197 | ||
| 216 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && | 198 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && |
| 217 | (it->GetAddressArbiterKey() == addr)) { | 199 | (it->GetAddressArbiterKey() == addr)) { |
| 218 | Thread* target_thread = std::addressof(*it); | 200 | KThread* target_thread = std::addressof(*it); |
| 219 | target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); | 201 | target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); |
| 220 | 202 | ||
| 221 | ASSERT(target_thread->IsWaitingForAddressArbiter()); | 203 | ASSERT(target_thread->IsWaitingForAddressArbiter()); |
| @@ -231,11 +213,10 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 | |||
| 231 | 213 | ||
| 232 | ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { | 214 | ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { |
| 233 | // Prepare to wait. | 215 | // Prepare to wait. |
| 234 | Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 216 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 235 | Handle timer = InvalidHandle; | ||
| 236 | 217 | ||
| 237 | { | 218 | { |
| 238 | KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout); | 219 | KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; |
| 239 | 220 | ||
| 240 | // Check that the thread isn't terminating. | 221 | // Check that the thread isn't terminating. |
| 241 | if (cur_thread->IsTerminationRequested()) { | 222 | if (cur_thread->IsTerminationRequested()) { |
| @@ -250,9 +231,9 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 250 | s32 user_value{}; | 231 | s32 user_value{}; |
| 251 | bool succeeded{}; | 232 | bool succeeded{}; |
| 252 | if (decrement) { | 233 | if (decrement) { |
| 253 | succeeded = DecrementIfLessThan(system, std::addressof(user_value), addr, value); | 234 | succeeded = DecrementIfLessThan(system, &user_value, addr, value); |
| 254 | } else { | 235 | } else { |
| 255 | succeeded = ReadFromUser(system, std::addressof(user_value), addr); | 236 | succeeded = ReadFromUser(system, &user_value, addr); |
| 256 | } | 237 | } |
| 257 | 238 | ||
| 258 | if (!succeeded) { | 239 | if (!succeeded) { |
| @@ -273,17 +254,14 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 273 | } | 254 | } |
| 274 | 255 | ||
| 275 | // Set the arbiter. | 256 | // Set the arbiter. |
| 276 | cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); | 257 | cur_thread->SetAddressArbiter(&thread_tree, addr); |
| 277 | thread_tree.insert(*cur_thread); | 258 | thread_tree.insert(*cur_thread); |
| 278 | cur_thread->SetState(ThreadState::Waiting); | 259 | cur_thread->SetState(ThreadState::Waiting); |
| 279 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); | 260 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); |
| 280 | } | 261 | } |
| 281 | 262 | ||
| 282 | // Cancel the timer wait. | 263 | // Cancel the timer wait. |
| 283 | if (timer != InvalidHandle) { | 264 | kernel.TimeManager().UnscheduleTimeEvent(cur_thread); |
| 284 | auto& time_manager = kernel.TimeManager(); | ||
| 285 | time_manager.UnscheduleTimeEvent(timer); | ||
| 286 | } | ||
| 287 | 265 | ||
| 288 | // Remove from the address arbiter. | 266 | // Remove from the address arbiter. |
| 289 | { | 267 | { |
| @@ -297,16 +275,15 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 297 | 275 | ||
| 298 | // Get the result. | 276 | // Get the result. |
| 299 | KSynchronizationObject* dummy{}; | 277 | KSynchronizationObject* dummy{}; |
| 300 | return cur_thread->GetWaitResult(std::addressof(dummy)); | 278 | return cur_thread->GetWaitResult(&dummy); |
| 301 | } | 279 | } |
| 302 | 280 | ||
| 303 | ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | 281 | ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { |
| 304 | // Prepare to wait. | 282 | // Prepare to wait. |
| 305 | Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 283 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 306 | Handle timer = InvalidHandle; | ||
| 307 | 284 | ||
| 308 | { | 285 | { |
| 309 | KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout); | 286 | KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; |
| 310 | 287 | ||
| 311 | // Check that the thread isn't terminating. | 288 | // Check that the thread isn't terminating. |
| 312 | if (cur_thread->IsTerminationRequested()) { | 289 | if (cur_thread->IsTerminationRequested()) { |
| @@ -319,7 +296,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 319 | 296 | ||
| 320 | // Read the value from userspace. | 297 | // Read the value from userspace. |
| 321 | s32 user_value{}; | 298 | s32 user_value{}; |
| 322 | if (!ReadFromUser(system, std::addressof(user_value), addr)) { | 299 | if (!ReadFromUser(system, &user_value, addr)) { |
| 323 | slp.CancelSleep(); | 300 | slp.CancelSleep(); |
| 324 | return Svc::ResultInvalidCurrentMemory; | 301 | return Svc::ResultInvalidCurrentMemory; |
| 325 | } | 302 | } |
| @@ -337,17 +314,14 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 337 | } | 314 | } |
| 338 | 315 | ||
| 339 | // Set the arbiter. | 316 | // Set the arbiter. |
| 340 | cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); | 317 | cur_thread->SetAddressArbiter(&thread_tree, addr); |
| 341 | thread_tree.insert(*cur_thread); | 318 | thread_tree.insert(*cur_thread); |
| 342 | cur_thread->SetState(ThreadState::Waiting); | 319 | cur_thread->SetState(ThreadState::Waiting); |
| 343 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); | 320 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); |
| 344 | } | 321 | } |
| 345 | 322 | ||
| 346 | // Cancel the timer wait. | 323 | // Cancel the timer wait. |
| 347 | if (timer != InvalidHandle) { | 324 | kernel.TimeManager().UnscheduleTimeEvent(cur_thread); |
| 348 | auto& time_manager = kernel.TimeManager(); | ||
| 349 | time_manager.UnscheduleTimeEvent(timer); | ||
| 350 | } | ||
| 351 | 325 | ||
| 352 | // Remove from the address arbiter. | 326 | // Remove from the address arbiter. |
| 353 | { | 327 | { |
| @@ -361,7 +335,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 361 | 335 | ||
| 362 | // Get the result. | 336 | // Get the result. |
| 363 | KSynchronizationObject* dummy{}; | 337 | KSynchronizationObject* dummy{}; |
| 364 | return cur_thread->GetWaitResult(std::addressof(dummy)); | 338 | return cur_thread->GetWaitResult(&dummy); |
| 365 | } | 339 | } |
| 366 | 340 | ||
| 367 | } // namespace Kernel | 341 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_affinity_mask.h b/src/core/hle/kernel/k_affinity_mask.h index dd73781cd..b906895fc 100644 --- a/src/core/hle/kernel/k_affinity_mask.h +++ b/src/core/hle/kernel/k_affinity_mask.h | |||
| @@ -27,7 +27,7 @@ public: | |||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | [[nodiscard]] constexpr bool GetAffinity(s32 core) const { | 29 | [[nodiscard]] constexpr bool GetAffinity(s32 core) const { |
| 30 | return this->mask & GetCoreBit(core); | 30 | return (this->mask & GetCoreBit(core)) != 0; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | constexpr void SetAffinity(s32 core, bool set) { | 33 | constexpr void SetAffinity(s32 core, bool set) { |
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 49a068310..f0ad8b390 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp | |||
| @@ -10,11 +10,11 @@ | |||
| 10 | #include "core/hle/kernel/k_scheduler.h" | 10 | #include "core/hle/kernel/k_scheduler.h" |
| 11 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 11 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 12 | #include "core/hle/kernel/k_synchronization_object.h" | 12 | #include "core/hle/kernel/k_synchronization_object.h" |
| 13 | #include "core/hle/kernel/k_thread.h" | ||
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/kernel/process.h" | 15 | #include "core/hle/kernel/process.h" |
| 15 | #include "core/hle/kernel/svc_common.h" | 16 | #include "core/hle/kernel/svc_common.h" |
| 16 | #include "core/hle/kernel/svc_results.h" | 17 | #include "core/hle/kernel/svc_results.h" |
| 17 | #include "core/hle/kernel/thread.h" | ||
| 18 | #include "core/memory.h" | 18 | #include "core/memory.h" |
| 19 | 19 | ||
| 20 | namespace Kernel { | 20 | namespace Kernel { |
| @@ -66,7 +66,7 @@ KConditionVariable::KConditionVariable(Core::System& system_) | |||
| 66 | KConditionVariable::~KConditionVariable() = default; | 66 | KConditionVariable::~KConditionVariable() = default; |
| 67 | 67 | ||
| 68 | ResultCode KConditionVariable::SignalToAddress(VAddr addr) { | 68 | ResultCode KConditionVariable::SignalToAddress(VAddr addr) { |
| 69 | Thread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 69 | KThread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 70 | 70 | ||
| 71 | // Signal the address. | 71 | // Signal the address. |
| 72 | { | 72 | { |
| @@ -74,7 +74,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { | |||
| 74 | 74 | ||
| 75 | // Remove waiter thread. | 75 | // Remove waiter thread. |
| 76 | s32 num_waiters{}; | 76 | s32 num_waiters{}; |
| 77 | Thread* next_owner_thread = | 77 | KThread* next_owner_thread = |
| 78 | owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); | 78 | owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); |
| 79 | 79 | ||
| 80 | // Determine the next tag. | 80 | // Determine the next tag. |
| @@ -103,11 +103,11 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { | |||
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { | 105 | ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { |
| 106 | Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 106 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 107 | 107 | ||
| 108 | // Wait for the address. | 108 | // Wait for the address. |
| 109 | { | 109 | { |
| 110 | std::shared_ptr<Thread> owner_thread; | 110 | std::shared_ptr<KThread> owner_thread; |
| 111 | ASSERT(!owner_thread); | 111 | ASSERT(!owner_thread); |
| 112 | { | 112 | { |
| 113 | KScopedSchedulerLock sl(kernel); | 113 | KScopedSchedulerLock sl(kernel); |
| @@ -126,7 +126,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val | |||
| 126 | R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS); | 126 | R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS); |
| 127 | 127 | ||
| 128 | // Get the lock owner thread. | 128 | // Get the lock owner thread. |
| 129 | owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<Thread>(handle); | 129 | owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(handle); |
| 130 | R_UNLESS(owner_thread, Svc::ResultInvalidHandle); | 130 | R_UNLESS(owner_thread, Svc::ResultInvalidHandle); |
| 131 | 131 | ||
| 132 | // Update the lock. | 132 | // Update the lock. |
| @@ -143,7 +143,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val | |||
| 143 | // Remove the thread as a waiter from the lock owner. | 143 | // Remove the thread as a waiter from the lock owner. |
| 144 | { | 144 | { |
| 145 | KScopedSchedulerLock sl(kernel); | 145 | KScopedSchedulerLock sl(kernel); |
| 146 | Thread* owner_thread = cur_thread->GetLockOwner(); | 146 | KThread* owner_thread = cur_thread->GetLockOwner(); |
| 147 | if (owner_thread != nullptr) { | 147 | if (owner_thread != nullptr) { |
| 148 | owner_thread->RemoveWaiter(cur_thread); | 148 | owner_thread->RemoveWaiter(cur_thread); |
| 149 | } | 149 | } |
| @@ -154,7 +154,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val | |||
| 154 | return cur_thread->GetWaitResult(std::addressof(dummy)); | 154 | return cur_thread->GetWaitResult(std::addressof(dummy)); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | Thread* KConditionVariable::SignalImpl(Thread* thread) { | 157 | KThread* KConditionVariable::SignalImpl(KThread* thread) { |
| 158 | // Check pre-conditions. | 158 | // Check pre-conditions. |
| 159 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 159 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 160 | 160 | ||
| @@ -174,7 +174,7 @@ Thread* KConditionVariable::SignalImpl(Thread* thread) { | |||
| 174 | } | 174 | } |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | Thread* thread_to_close = nullptr; | 177 | KThread* thread_to_close = nullptr; |
| 178 | if (can_access) { | 178 | if (can_access) { |
| 179 | if (prev_tag == InvalidHandle) { | 179 | if (prev_tag == InvalidHandle) { |
| 180 | // If nobody held the lock previously, we're all good. | 180 | // If nobody held the lock previously, we're all good. |
| @@ -182,7 +182,7 @@ Thread* KConditionVariable::SignalImpl(Thread* thread) { | |||
| 182 | thread->Wakeup(); | 182 | thread->Wakeup(); |
| 183 | } else { | 183 | } else { |
| 184 | // Get the previous owner. | 184 | // Get the previous owner. |
| 185 | auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<Thread>( | 185 | auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>( |
| 186 | prev_tag & ~Svc::HandleWaitMask); | 186 | prev_tag & ~Svc::HandleWaitMask); |
| 187 | 187 | ||
| 188 | if (owner_thread) { | 188 | if (owner_thread) { |
| @@ -210,8 +210,8 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { | |||
| 210 | 210 | ||
| 211 | // TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using | 211 | // TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using |
| 212 | // std::shared_ptr. | 212 | // std::shared_ptr. |
| 213 | std::vector<std::shared_ptr<Thread>> thread_list; | 213 | std::vector<std::shared_ptr<KThread>> thread_list; |
| 214 | std::array<Thread*, MaxThreads> thread_array; | 214 | std::array<KThread*, MaxThreads> thread_array; |
| 215 | s32 num_to_close{}; | 215 | s32 num_to_close{}; |
| 216 | 216 | ||
| 217 | // Perform signaling. | 217 | // Perform signaling. |
| @@ -222,9 +222,9 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { | |||
| 222 | auto it = thread_tree.nfind_light({cv_key, -1}); | 222 | auto it = thread_tree.nfind_light({cv_key, -1}); |
| 223 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && | 223 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && |
| 224 | (it->GetConditionVariableKey() == cv_key)) { | 224 | (it->GetConditionVariableKey() == cv_key)) { |
| 225 | Thread* target_thread = std::addressof(*it); | 225 | KThread* target_thread = std::addressof(*it); |
| 226 | 226 | ||
| 227 | if (Thread* thread = SignalImpl(target_thread); thread != nullptr) { | 227 | if (KThread* thread = SignalImpl(target_thread); thread != nullptr) { |
| 228 | if (num_to_close < MaxThreads) { | 228 | if (num_to_close < MaxThreads) { |
| 229 | thread_array[num_to_close++] = thread; | 229 | thread_array[num_to_close++] = thread; |
| 230 | } else { | 230 | } else { |
| @@ -257,11 +257,10 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { | |||
| 257 | 257 | ||
| 258 | ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { | 258 | ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { |
| 259 | // Prepare to wait. | 259 | // Prepare to wait. |
| 260 | Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 260 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 261 | Handle timer = InvalidHandle; | ||
| 262 | 261 | ||
| 263 | { | 262 | { |
| 264 | KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout); | 263 | KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; |
| 265 | 264 | ||
| 266 | // Set the synced object. | 265 | // Set the synced object. |
| 267 | cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut); | 266 | cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut); |
| @@ -276,7 +275,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) | |||
| 276 | { | 275 | { |
| 277 | // Remove waiter thread. | 276 | // Remove waiter thread. |
| 278 | s32 num_waiters{}; | 277 | s32 num_waiters{}; |
| 279 | Thread* next_owner_thread = | 278 | KThread* next_owner_thread = |
| 280 | cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); | 279 | cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); |
| 281 | 280 | ||
| 282 | // Update for the next owner thread. | 281 | // Update for the next owner thread. |
| @@ -322,16 +321,13 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) | |||
| 322 | } | 321 | } |
| 323 | 322 | ||
| 324 | // Cancel the timer wait. | 323 | // Cancel the timer wait. |
| 325 | if (timer != InvalidHandle) { | 324 | kernel.TimeManager().UnscheduleTimeEvent(cur_thread); |
| 326 | auto& time_manager = kernel.TimeManager(); | ||
| 327 | time_manager.UnscheduleTimeEvent(timer); | ||
| 328 | } | ||
| 329 | 325 | ||
| 330 | // Remove from the condition variable. | 326 | // Remove from the condition variable. |
| 331 | { | 327 | { |
| 332 | KScopedSchedulerLock sl(kernel); | 328 | KScopedSchedulerLock sl(kernel); |
| 333 | 329 | ||
| 334 | if (Thread* owner = cur_thread->GetLockOwner(); owner != nullptr) { | 330 | if (KThread* owner = cur_thread->GetLockOwner(); owner != nullptr) { |
| 335 | owner->RemoveWaiter(cur_thread); | 331 | owner->RemoveWaiter(cur_thread); |
| 336 | } | 332 | } |
| 337 | 333 | ||
diff --git a/src/core/hle/kernel/k_condition_variable.h b/src/core/hle/kernel/k_condition_variable.h index 98ed5b323..861dbd420 100644 --- a/src/core/hle/kernel/k_condition_variable.h +++ b/src/core/hle/kernel/k_condition_variable.h | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | 9 | ||
| 10 | #include "core/hle/kernel/k_scheduler.h" | 10 | #include "core/hle/kernel/k_scheduler.h" |
| 11 | #include "core/hle/kernel/k_thread.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 14 | 14 | ||
| 15 | namespace Core { | 15 | namespace Core { |
| @@ -20,7 +20,7 @@ namespace Kernel { | |||
| 20 | 20 | ||
| 21 | class KConditionVariable { | 21 | class KConditionVariable { |
| 22 | public: | 22 | public: |
| 23 | using ThreadTree = typename Thread::ConditionVariableThreadTreeType; | 23 | using ThreadTree = typename KThread::ConditionVariableThreadTreeType; |
| 24 | 24 | ||
| 25 | explicit KConditionVariable(Core::System& system_); | 25 | explicit KConditionVariable(Core::System& system_); |
| 26 | ~KConditionVariable(); | 26 | ~KConditionVariable(); |
| @@ -34,7 +34,7 @@ public: | |||
| 34 | [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout); | 34 | [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout); |
| 35 | 35 | ||
| 36 | private: | 36 | private: |
| 37 | [[nodiscard]] Thread* SignalImpl(Thread* thread); | 37 | [[nodiscard]] KThread* SignalImpl(KThread* thread); |
| 38 | 38 | ||
| 39 | ThreadTree thread_tree; | 39 | ThreadTree thread_tree; |
| 40 | 40 | ||
| @@ -43,14 +43,14 @@ private: | |||
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, | 45 | inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, |
| 46 | Thread* thread) { | 46 | KThread* thread) { |
| 47 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 47 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 48 | 48 | ||
| 49 | tree->erase(tree->iterator_to(*thread)); | 49 | tree->erase(tree->iterator_to(*thread)); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, | 52 | inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, |
| 53 | Thread* thread) { | 53 | KThread* thread) { |
| 54 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 54 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 55 | 55 | ||
| 56 | tree->insert(*thread); | 56 | tree->insert(*thread); |
diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp new file mode 100644 index 000000000..bb2fa4ad5 --- /dev/null +++ b/src/core/hle/kernel/k_event.cpp | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Copyright 2021 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/k_event.h" | ||
| 6 | #include "core/hle/kernel/k_readable_event.h" | ||
| 7 | #include "core/hle/kernel/k_writable_event.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {} | ||
| 12 | |||
| 13 | KEvent::~KEvent() = default; | ||
| 14 | |||
| 15 | std::shared_ptr<KEvent> KEvent::Create(KernelCore& kernel, std::string&& name) { | ||
| 16 | return std::make_shared<KEvent>(kernel, std::move(name)); | ||
| 17 | } | ||
| 18 | |||
| 19 | void KEvent::Initialize() { | ||
| 20 | // Create our sub events. | ||
| 21 | readable_event = std::make_shared<KReadableEvent>(kernel, GetName() + ":Readable"); | ||
| 22 | writable_event = std::make_shared<KWritableEvent>(kernel, GetName() + ":Writable"); | ||
| 23 | |||
| 24 | // Initialize our sub sessions. | ||
| 25 | readable_event->Initialize(this); | ||
| 26 | writable_event->Initialize(this); | ||
| 27 | |||
| 28 | // Mark initialized. | ||
| 29 | initialized = true; | ||
| 30 | } | ||
| 31 | |||
| 32 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h new file mode 100644 index 000000000..2fb887129 --- /dev/null +++ b/src/core/hle/kernel/k_event.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // Copyright 2021 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/kernel/object.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | class KernelCore; | ||
| 12 | class KReadableEvent; | ||
| 13 | class KWritableEvent; | ||
| 14 | |||
| 15 | class KEvent final : public Object { | ||
| 16 | public: | ||
| 17 | explicit KEvent(KernelCore& kernel, std::string&& name); | ||
| 18 | ~KEvent() override; | ||
| 19 | |||
| 20 | static std::shared_ptr<KEvent> Create(KernelCore& kernel, std::string&& name); | ||
| 21 | |||
| 22 | void Initialize(); | ||
| 23 | |||
| 24 | void Finalize() override {} | ||
| 25 | |||
| 26 | std::string GetTypeName() const override { | ||
| 27 | return "KEvent"; | ||
| 28 | } | ||
| 29 | |||
| 30 | static constexpr HandleType HANDLE_TYPE = HandleType::Event; | ||
| 31 | HandleType GetHandleType() const override { | ||
| 32 | return HANDLE_TYPE; | ||
| 33 | } | ||
| 34 | |||
| 35 | std::shared_ptr<KReadableEvent>& GetReadableEvent() { | ||
| 36 | return readable_event; | ||
| 37 | } | ||
| 38 | |||
| 39 | std::shared_ptr<KWritableEvent>& GetWritableEvent() { | ||
| 40 | return writable_event; | ||
| 41 | } | ||
| 42 | |||
| 43 | const std::shared_ptr<KReadableEvent>& GetReadableEvent() const { | ||
| 44 | return readable_event; | ||
| 45 | } | ||
| 46 | |||
| 47 | const std::shared_ptr<KWritableEvent>& GetWritableEvent() const { | ||
| 48 | return writable_event; | ||
| 49 | } | ||
| 50 | |||
| 51 | private: | ||
| 52 | std::shared_ptr<KReadableEvent> readable_event; | ||
| 53 | std::shared_ptr<KWritableEvent> writable_event; | ||
| 54 | bool initialized{}; | ||
| 55 | }; | ||
| 56 | |||
| 57 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h new file mode 100644 index 000000000..362d0db28 --- /dev/null +++ b/src/core/hle/kernel/k_light_condition_variable.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/kernel/k_scheduler.h" | ||
| 12 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 13 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 14 | #include "core/hle/kernel/time_manager.h" | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | class KernelCore; | ||
| 18 | |||
| 19 | class KLightConditionVariable { | ||
| 20 | public: | ||
| 21 | explicit KLightConditionVariable(KernelCore& kernel) : thread_queue(kernel), kernel(kernel) {} | ||
| 22 | |||
| 23 | void Wait(KLightLock* lock, s64 timeout = -1) { | ||
| 24 | WaitImpl(lock, timeout); | ||
| 25 | lock->Lock(); | ||
| 26 | } | ||
| 27 | |||
| 28 | void Broadcast() { | ||
| 29 | KScopedSchedulerLock lk{kernel}; | ||
| 30 | while (thread_queue.WakeupFrontThread() != nullptr) { | ||
| 31 | // We want to signal all threads, and so should continue waking up until there's nothing | ||
| 32 | // to wake. | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | private: | ||
| 37 | void WaitImpl(KLightLock* lock, s64 timeout) { | ||
| 38 | KThread* owner = GetCurrentThreadPointer(kernel); | ||
| 39 | |||
| 40 | // Sleep the thread. | ||
| 41 | { | ||
| 42 | KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); | ||
| 43 | lock->Unlock(); | ||
| 44 | |||
| 45 | if (!thread_queue.SleepThread(owner)) { | ||
| 46 | lk.CancelSleep(); | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | // Cancel the task that the sleep setup. | ||
| 52 | kernel.TimeManager().UnscheduleTimeEvent(owner); | ||
| 53 | } | ||
| 54 | KThreadQueue thread_queue; | ||
| 55 | KernelCore& kernel; | ||
| 56 | }; | ||
| 57 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp new file mode 100644 index 000000000..f974022e8 --- /dev/null +++ b/src/core/hle/kernel/k_light_lock.cpp | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/k_light_lock.h" | ||
| 6 | #include "core/hle/kernel/k_scheduler.h" | ||
| 7 | #include "core/hle/kernel/k_thread.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | void KLightLock::Lock() { | ||
| 13 | const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); | ||
| 14 | const uintptr_t cur_thread_tag = (cur_thread | 1); | ||
| 15 | |||
| 16 | while (true) { | ||
| 17 | uintptr_t old_tag = tag.load(std::memory_order_relaxed); | ||
| 18 | |||
| 19 | while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : old_tag | 1, | ||
| 20 | std::memory_order_acquire)) { | ||
| 21 | if ((old_tag | 1) == cur_thread_tag) { | ||
| 22 | return; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | if ((old_tag == 0) || ((old_tag | 1) == cur_thread_tag)) { | ||
| 27 | break; | ||
| 28 | } | ||
| 29 | |||
| 30 | LockSlowPath(old_tag | 1, cur_thread); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | void KLightLock::Unlock() { | ||
| 35 | const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); | ||
| 36 | uintptr_t expected = cur_thread; | ||
| 37 | do { | ||
| 38 | if (expected != cur_thread) { | ||
| 39 | return UnlockSlowPath(cur_thread); | ||
| 40 | } | ||
| 41 | } while (!tag.compare_exchange_weak(expected, 0, std::memory_order_release)); | ||
| 42 | } | ||
| 43 | |||
| 44 | void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { | ||
| 45 | KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread); | ||
| 46 | |||
| 47 | // Pend the current thread waiting on the owner thread. | ||
| 48 | { | ||
| 49 | KScopedSchedulerLock sl{kernel}; | ||
| 50 | |||
| 51 | // Ensure we actually have locking to do. | ||
| 52 | if (tag.load(std::memory_order_relaxed) != _owner) { | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 56 | // Add the current thread as a waiter on the owner. | ||
| 57 | KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL); | ||
| 58 | cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); | ||
| 59 | owner_thread->AddWaiter(cur_thread); | ||
| 60 | |||
| 61 | // Set thread states. | ||
| 62 | if (cur_thread->GetState() == ThreadState::Runnable) { | ||
| 63 | cur_thread->SetState(ThreadState::Waiting); | ||
| 64 | } else { | ||
| 65 | KScheduler::SetSchedulerUpdateNeeded(kernel); | ||
| 66 | } | ||
| 67 | |||
| 68 | if (owner_thread->IsSuspended()) { | ||
| 69 | owner_thread->ContinueIfHasKernelWaiters(); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | // We're no longer waiting on the lock owner. | ||
| 74 | { | ||
| 75 | KScopedSchedulerLock sl{kernel}; | ||
| 76 | KThread* owner_thread = cur_thread->GetLockOwner(); | ||
| 77 | if (owner_thread) { | ||
| 78 | owner_thread->RemoveWaiter(cur_thread); | ||
| 79 | KScheduler::SetSchedulerUpdateNeeded(kernel); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { | ||
| 85 | KThread* owner_thread = reinterpret_cast<KThread*>(_cur_thread); | ||
| 86 | |||
| 87 | // Unlock. | ||
| 88 | { | ||
| 89 | KScopedSchedulerLock sl{kernel}; | ||
| 90 | |||
| 91 | // Get the next owner. | ||
| 92 | s32 num_waiters = 0; | ||
| 93 | KThread* next_owner = owner_thread->RemoveWaiterByKey( | ||
| 94 | std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag))); | ||
| 95 | |||
| 96 | // Pass the lock to the next owner. | ||
| 97 | uintptr_t next_tag = 0; | ||
| 98 | if (next_owner) { | ||
| 99 | next_tag = reinterpret_cast<uintptr_t>(next_owner); | ||
| 100 | if (num_waiters > 1) { | ||
| 101 | next_tag |= 0x1; | ||
| 102 | } | ||
| 103 | |||
| 104 | if (next_owner->GetState() == ThreadState::Waiting) { | ||
| 105 | next_owner->SetState(ThreadState::Runnable); | ||
| 106 | } else { | ||
| 107 | KScheduler::SetSchedulerUpdateNeeded(kernel); | ||
| 108 | } | ||
| 109 | |||
| 110 | if (next_owner->IsSuspended()) { | ||
| 111 | next_owner->ContinueIfHasKernelWaiters(); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | // We may have unsuspended in the process of acquiring the lock, so we'll re-suspend now if | ||
| 116 | // so. | ||
| 117 | if (owner_thread->IsSuspended()) { | ||
| 118 | owner_thread->TrySuspend(); | ||
| 119 | } | ||
| 120 | |||
| 121 | // Write the new tag value. | ||
| 122 | tag.store(next_tag); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | bool KLightLock::IsLockedByCurrentThread() const { | ||
| 127 | return (tag | 1ULL) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)) | 1ULL); | ||
| 128 | } | ||
| 129 | |||
| 130 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_lock.h b/src/core/hle/kernel/k_light_lock.h new file mode 100644 index 000000000..f4c45f76a --- /dev/null +++ b/src/core/hle/kernel/k_light_lock.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/kernel/k_scoped_lock.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | class KernelCore; | ||
| 15 | |||
| 16 | class KLightLock { | ||
| 17 | public: | ||
| 18 | explicit KLightLock(KernelCore& kernel_) : kernel{kernel_} {} | ||
| 19 | |||
| 20 | void Lock(); | ||
| 21 | |||
| 22 | void Unlock(); | ||
| 23 | |||
| 24 | void LockSlowPath(uintptr_t owner, uintptr_t cur_thread); | ||
| 25 | |||
| 26 | void UnlockSlowPath(uintptr_t cur_thread); | ||
| 27 | |||
| 28 | bool IsLocked() const { | ||
| 29 | return tag != 0; | ||
| 30 | } | ||
| 31 | |||
| 32 | bool IsLockedByCurrentThread() const; | ||
| 33 | |||
| 34 | private: | ||
| 35 | std::atomic<uintptr_t> tag{}; | ||
| 36 | KernelCore& kernel; | ||
| 37 | }; | ||
| 38 | |||
| 39 | using KScopedLightLock = KScopedLock<KLightLock>; | ||
| 40 | |||
| 41 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index 0dc929040..4aa669d95 100644 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h | |||
| @@ -18,17 +18,17 @@ | |||
| 18 | 18 | ||
| 19 | namespace Kernel { | 19 | namespace Kernel { |
| 20 | 20 | ||
| 21 | class Thread; | 21 | class KThread; |
| 22 | 22 | ||
| 23 | template <typename T> | 23 | template <typename T> |
| 24 | concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) { | 24 | concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) { |
| 25 | { t.GetAffinityMask() } | 25 | { t.GetAffinityMask() } |
| 26 | ->Common::ConvertibleTo<u64>; | 26 | ->Common::ConvertibleTo<u64>; |
| 27 | {t.SetAffinityMask(std::declval<u64>())}; | 27 | {t.SetAffinityMask(0)}; |
| 28 | 28 | ||
| 29 | { t.GetAffinity(std::declval<int32_t>()) } | 29 | { t.GetAffinity(0) } |
| 30 | ->std::same_as<bool>; | 30 | ->std::same_as<bool>; |
| 31 | {t.SetAffinity(std::declval<int32_t>(), std::declval<bool>())}; | 31 | {t.SetAffinity(0, false)}; |
| 32 | {t.SetAll()}; | 32 | {t.SetAll()}; |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| @@ -42,11 +42,11 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { | |||
| 42 | ->std::same_as<T*>; | 42 | ->std::same_as<T*>; |
| 43 | { (typename T::QueueEntry()).GetPrev() } | 43 | { (typename T::QueueEntry()).GetPrev() } |
| 44 | ->std::same_as<T*>; | 44 | ->std::same_as<T*>; |
| 45 | { t.GetPriorityQueueEntry(std::declval<s32>()) } | 45 | { t.GetPriorityQueueEntry(0) } |
| 46 | ->std::same_as<typename T::QueueEntry&>; | 46 | ->std::same_as<typename T::QueueEntry&>; |
| 47 | 47 | ||
| 48 | {t.GetAffinityMask()}; | 48 | {t.GetAffinityMask()}; |
| 49 | { typename std::remove_cvref<decltype(t.GetAffinityMask())>::type() } | 49 | { std::remove_cvref_t<decltype(t.GetAffinityMask())>() } |
| 50 | ->KPriorityQueueAffinityMask; | 50 | ->KPriorityQueueAffinityMask; |
| 51 | 51 | ||
| 52 | { t.GetActiveCore() } | 52 | { t.GetActiveCore() } |
| @@ -55,17 +55,17 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { | |||
| 55 | ->Common::ConvertibleTo<s32>; | 55 | ->Common::ConvertibleTo<s32>; |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | template <typename Member, size_t _NumCores, int LowestPriority, int HighestPriority> | 58 | template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> |
| 59 | requires KPriorityQueueMember<Member> class KPriorityQueue { | 59 | requires KPriorityQueueMember<Member> class KPriorityQueue { |
| 60 | public: | 60 | public: |
| 61 | using AffinityMaskType = typename std::remove_cv_t< | 61 | using AffinityMaskType = std::remove_cv_t< |
| 62 | typename std::remove_reference<decltype(std::declval<Member>().GetAffinityMask())>::type>; | 62 | std::remove_reference_t<decltype(std::declval<Member>().GetAffinityMask())>>; |
| 63 | 63 | ||
| 64 | static_assert(LowestPriority >= 0); | 64 | static_assert(LowestPriority >= 0); |
| 65 | static_assert(HighestPriority >= 0); | 65 | static_assert(HighestPriority >= 0); |
| 66 | static_assert(LowestPriority >= HighestPriority); | 66 | static_assert(LowestPriority >= HighestPriority); |
| 67 | static constexpr size_t NumPriority = LowestPriority - HighestPriority + 1; | 67 | static constexpr size_t NumPriority = LowestPriority - HighestPriority + 1; |
| 68 | static constexpr size_t NumCores = _NumCores; | 68 | static constexpr size_t NumCores = NumCores_; |
| 69 | 69 | ||
| 70 | static constexpr bool IsValidCore(s32 core) { | 70 | static constexpr bool IsValidCore(s32 core) { |
| 71 | return 0 <= core && core < static_cast<s32>(NumCores); | 71 | return 0 <= core && core < static_cast<s32>(NumCores); |
| @@ -367,7 +367,7 @@ public: | |||
| 367 | this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); | 367 | this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); |
| 368 | } | 368 | } |
| 369 | 369 | ||
| 370 | constexpr Thread* MoveToScheduledBack(Member* member) { | 370 | constexpr KThread* MoveToScheduledBack(Member* member) { |
| 371 | return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), | 371 | return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), |
| 372 | member); | 372 | member); |
| 373 | } | 373 | } |
diff --git a/src/core/hle/kernel/k_readable_event.cpp b/src/core/hle/kernel/k_readable_event.cpp new file mode 100644 index 000000000..d8a42dbaf --- /dev/null +++ b/src/core/hle/kernel/k_readable_event.cpp | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // Copyright 2021 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/hle/kernel/errors.h" | ||
| 10 | #include "core/hle/kernel/k_readable_event.h" | ||
| 11 | #include "core/hle/kernel/k_scheduler.h" | ||
| 12 | #include "core/hle/kernel/k_thread.h" | ||
| 13 | #include "core/hle/kernel/kernel.h" | ||
| 14 | #include "core/hle/kernel/object.h" | ||
| 15 | #include "core/hle/kernel/svc_results.h" | ||
| 16 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | KReadableEvent::KReadableEvent(KernelCore& kernel, std::string&& name) | ||
| 20 | : KSynchronizationObject{kernel, std::move(name)} {} | ||
| 21 | KReadableEvent::~KReadableEvent() = default; | ||
| 22 | |||
| 23 | bool KReadableEvent::IsSignaled() const { | ||
| 24 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 25 | |||
| 26 | return is_signaled; | ||
| 27 | } | ||
| 28 | |||
| 29 | ResultCode KReadableEvent::Signal() { | ||
| 30 | KScopedSchedulerLock lk{kernel}; | ||
| 31 | |||
| 32 | if (!is_signaled) { | ||
| 33 | is_signaled = true; | ||
| 34 | NotifyAvailable(); | ||
| 35 | } | ||
| 36 | |||
| 37 | return RESULT_SUCCESS; | ||
| 38 | } | ||
| 39 | |||
| 40 | ResultCode KReadableEvent::Clear() { | ||
| 41 | Reset(); | ||
| 42 | |||
| 43 | return RESULT_SUCCESS; | ||
| 44 | } | ||
| 45 | |||
| 46 | ResultCode KReadableEvent::Reset() { | ||
| 47 | KScopedSchedulerLock lk{kernel}; | ||
| 48 | |||
| 49 | if (!is_signaled) { | ||
| 50 | return Svc::ResultInvalidState; | ||
| 51 | } | ||
| 52 | |||
| 53 | is_signaled = false; | ||
| 54 | return RESULT_SUCCESS; | ||
| 55 | } | ||
| 56 | |||
| 57 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h new file mode 100644 index 000000000..e6f0fd900 --- /dev/null +++ b/src/core/hle/kernel/k_readable_event.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | // Copyright 2021 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 8 | #include "core/hle/kernel/object.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | class KernelCore; | ||
| 14 | class KEvent; | ||
| 15 | |||
| 16 | class KReadableEvent final : public KSynchronizationObject { | ||
| 17 | public: | ||
| 18 | explicit KReadableEvent(KernelCore& kernel, std::string&& name); | ||
| 19 | ~KReadableEvent() override; | ||
| 20 | |||
| 21 | std::string GetTypeName() const override { | ||
| 22 | return "KReadableEvent"; | ||
| 23 | } | ||
| 24 | |||
| 25 | static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent; | ||
| 26 | HandleType GetHandleType() const override { | ||
| 27 | return HANDLE_TYPE; | ||
| 28 | } | ||
| 29 | |||
| 30 | KEvent* GetParent() const { | ||
| 31 | return parent; | ||
| 32 | } | ||
| 33 | |||
| 34 | void Initialize(KEvent* parent_) { | ||
| 35 | is_signaled = false; | ||
| 36 | parent = parent_; | ||
| 37 | } | ||
| 38 | |||
| 39 | bool IsSignaled() const override; | ||
| 40 | void Finalize() override {} | ||
| 41 | |||
| 42 | ResultCode Signal(); | ||
| 43 | ResultCode Clear(); | ||
| 44 | ResultCode Reset(); | ||
| 45 | |||
| 46 | private: | ||
| 47 | bool is_signaled{}; | ||
| 48 | KEvent* parent{}; | ||
| 49 | }; | ||
| 50 | |||
| 51 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp new file mode 100644 index 000000000..ab2ab683f --- /dev/null +++ b/src/core/hle/kernel/k_resource_limit.cpp | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "core/core_timing.h" | ||
| 11 | #include "core/core_timing_util.h" | ||
| 12 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 13 | #include "core/hle/kernel/svc_results.h" | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | constexpr s64 DefaultTimeout = 10000000000; // 10 seconds | ||
| 17 | |||
| 18 | KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system) | ||
| 19 | : Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {} | ||
| 20 | KResourceLimit::~KResourceLimit() = default; | ||
| 21 | |||
| 22 | s64 KResourceLimit::GetLimitValue(LimitableResource which) const { | ||
| 23 | const auto index = static_cast<std::size_t>(which); | ||
| 24 | s64 value{}; | ||
| 25 | { | ||
| 26 | KScopedLightLock lk{lock}; | ||
| 27 | value = limit_values[index]; | ||
| 28 | ASSERT(value >= 0); | ||
| 29 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 30 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 31 | } | ||
| 32 | return value; | ||
| 33 | } | ||
| 34 | |||
| 35 | s64 KResourceLimit::GetCurrentValue(LimitableResource which) const { | ||
| 36 | const auto index = static_cast<std::size_t>(which); | ||
| 37 | s64 value{}; | ||
| 38 | { | ||
| 39 | KScopedLightLock lk{lock}; | ||
| 40 | value = current_values[index]; | ||
| 41 | ASSERT(value >= 0); | ||
| 42 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 43 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 44 | } | ||
| 45 | return value; | ||
| 46 | } | ||
| 47 | |||
| 48 | s64 KResourceLimit::GetPeakValue(LimitableResource which) const { | ||
| 49 | const auto index = static_cast<std::size_t>(which); | ||
| 50 | s64 value{}; | ||
| 51 | { | ||
| 52 | KScopedLightLock lk{lock}; | ||
| 53 | value = peak_values[index]; | ||
| 54 | ASSERT(value >= 0); | ||
| 55 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 56 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 57 | } | ||
| 58 | return value; | ||
| 59 | } | ||
| 60 | |||
| 61 | s64 KResourceLimit::GetFreeValue(LimitableResource which) const { | ||
| 62 | const auto index = static_cast<std::size_t>(which); | ||
| 63 | s64 value{}; | ||
| 64 | { | ||
| 65 | KScopedLightLock lk(lock); | ||
| 66 | ASSERT(current_values[index] >= 0); | ||
| 67 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 68 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 69 | value = limit_values[index] - current_values[index]; | ||
| 70 | } | ||
| 71 | |||
| 72 | return value; | ||
| 73 | } | ||
| 74 | |||
| 75 | ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) { | ||
| 76 | const auto index = static_cast<std::size_t>(which); | ||
| 77 | KScopedLightLock lk(lock); | ||
| 78 | R_UNLESS(current_values[index] <= value, Svc::ResultInvalidState); | ||
| 79 | |||
| 80 | limit_values[index] = value; | ||
| 81 | |||
| 82 | return RESULT_SUCCESS; | ||
| 83 | } | ||
| 84 | |||
| 85 | bool KResourceLimit::Reserve(LimitableResource which, s64 value) { | ||
| 86 | return Reserve(which, value, system.CoreTiming().GetGlobalTimeNs().count() + DefaultTimeout); | ||
| 87 | } | ||
| 88 | |||
| 89 | bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { | ||
| 90 | ASSERT(value >= 0); | ||
| 91 | const auto index = static_cast<std::size_t>(which); | ||
| 92 | KScopedLightLock lk(lock); | ||
| 93 | |||
| 94 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 95 | if (current_hints[index] >= limit_values[index]) { | ||
| 96 | return false; | ||
| 97 | } | ||
| 98 | |||
| 99 | // Loop until we reserve or run out of time. | ||
| 100 | while (true) { | ||
| 101 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 102 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 103 | |||
| 104 | // If we would overflow, don't allow to succeed. | ||
| 105 | if (current_values[index] + value <= current_values[index]) { | ||
| 106 | break; | ||
| 107 | } | ||
| 108 | |||
| 109 | if (current_values[index] + value <= limit_values[index]) { | ||
| 110 | current_values[index] += value; | ||
| 111 | current_hints[index] += value; | ||
| 112 | peak_values[index] = std::max(peak_values[index], current_values[index]); | ||
| 113 | return true; | ||
| 114 | } | ||
| 115 | |||
| 116 | if (current_hints[index] + value <= limit_values[index] && | ||
| 117 | (timeout < 0 || system.CoreTiming().GetGlobalTimeNs().count() < timeout)) { | ||
| 118 | waiter_count++; | ||
| 119 | cond_var.Wait(&lock, timeout); | ||
| 120 | waiter_count--; | ||
| 121 | } else { | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | return false; | ||
| 127 | } | ||
| 128 | |||
| 129 | void KResourceLimit::Release(LimitableResource which, s64 value) { | ||
| 130 | Release(which, value, value); | ||
| 131 | } | ||
| 132 | |||
| 133 | void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) { | ||
| 134 | ASSERT(value >= 0); | ||
| 135 | ASSERT(hint >= 0); | ||
| 136 | |||
| 137 | const auto index = static_cast<std::size_t>(which); | ||
| 138 | KScopedLightLock lk(lock); | ||
| 139 | ASSERT(current_values[index] <= limit_values[index]); | ||
| 140 | ASSERT(current_hints[index] <= current_values[index]); | ||
| 141 | ASSERT(value <= current_values[index]); | ||
| 142 | ASSERT(hint <= current_hints[index]); | ||
| 143 | |||
| 144 | current_values[index] -= value; | ||
| 145 | current_hints[index] -= hint; | ||
| 146 | |||
| 147 | if (waiter_count != 0) { | ||
| 148 | cond_var.Broadcast(); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h new file mode 100644 index 000000000..58ae456f1 --- /dev/null +++ b/src/core/hle/kernel/k_resource_limit.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include <array> | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "core/hle/kernel/k_light_condition_variable.h" | ||
| 13 | #include "core/hle/kernel/k_light_lock.h" | ||
| 14 | #include "core/hle/kernel/object.h" | ||
| 15 | |||
| 16 | union ResultCode; | ||
| 17 | |||
| 18 | namespace Core { | ||
| 19 | class System; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Kernel { | ||
| 23 | class KernelCore; | ||
| 24 | enum class LimitableResource : u32 { | ||
| 25 | PhysicalMemory = 0, | ||
| 26 | Threads = 1, | ||
| 27 | Events = 2, | ||
| 28 | TransferMemory = 3, | ||
| 29 | Sessions = 4, | ||
| 30 | |||
| 31 | Count, | ||
| 32 | }; | ||
| 33 | |||
| 34 | constexpr bool IsValidResourceType(LimitableResource type) { | ||
| 35 | return type < LimitableResource::Count; | ||
| 36 | } | ||
| 37 | |||
| 38 | class KResourceLimit final : public Object { | ||
| 39 | public: | ||
| 40 | explicit KResourceLimit(KernelCore& kernel, Core::System& system); | ||
| 41 | ~KResourceLimit(); | ||
| 42 | |||
| 43 | s64 GetLimitValue(LimitableResource which) const; | ||
| 44 | s64 GetCurrentValue(LimitableResource which) const; | ||
| 45 | s64 GetPeakValue(LimitableResource which) const; | ||
| 46 | s64 GetFreeValue(LimitableResource which) const; | ||
| 47 | |||
| 48 | ResultCode SetLimitValue(LimitableResource which, s64 value); | ||
| 49 | |||
| 50 | bool Reserve(LimitableResource which, s64 value); | ||
| 51 | bool Reserve(LimitableResource which, s64 value, s64 timeout); | ||
| 52 | void Release(LimitableResource which, s64 value); | ||
| 53 | void Release(LimitableResource which, s64 value, s64 hint); | ||
| 54 | |||
| 55 | std::string GetTypeName() const override { | ||
| 56 | return "KResourceLimit"; | ||
| 57 | } | ||
| 58 | std::string GetName() const override { | ||
| 59 | return GetTypeName(); | ||
| 60 | } | ||
| 61 | |||
| 62 | static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit; | ||
| 63 | HandleType GetHandleType() const override { | ||
| 64 | return HANDLE_TYPE; | ||
| 65 | } | ||
| 66 | |||
| 67 | virtual void Finalize() override {} | ||
| 68 | |||
| 69 | private: | ||
| 70 | using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>; | ||
| 71 | ResourceArray limit_values{}; | ||
| 72 | ResourceArray current_values{}; | ||
| 73 | ResourceArray current_hints{}; | ||
| 74 | ResourceArray peak_values{}; | ||
| 75 | mutable KLightLock lock; | ||
| 76 | s32 waiter_count{}; | ||
| 77 | KLightConditionVariable cond_var; | ||
| 78 | KernelCore& kernel; | ||
| 79 | Core::System& system; | ||
| 80 | }; | ||
| 81 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 12b5619fb..bb5f43b53 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -17,25 +17,30 @@ | |||
| 17 | #include "core/cpu_manager.h" | 17 | #include "core/cpu_manager.h" |
| 18 | #include "core/hle/kernel/k_scheduler.h" | 18 | #include "core/hle/kernel/k_scheduler.h" |
| 19 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 19 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 20 | #include "core/hle/kernel/k_thread.h" | ||
| 20 | #include "core/hle/kernel/kernel.h" | 21 | #include "core/hle/kernel/kernel.h" |
| 21 | #include "core/hle/kernel/physical_core.h" | 22 | #include "core/hle/kernel/physical_core.h" |
| 22 | #include "core/hle/kernel/process.h" | 23 | #include "core/hle/kernel/process.h" |
| 23 | #include "core/hle/kernel/thread.h" | ||
| 24 | #include "core/hle/kernel/time_manager.h" | 24 | #include "core/hle/kernel/time_manager.h" |
| 25 | 25 | ||
| 26 | namespace Kernel { | 26 | namespace Kernel { |
| 27 | 27 | ||
| 28 | static void IncrementScheduledCount(Kernel::Thread* thread) { | 28 | static void IncrementScheduledCount(Kernel::KThread* thread) { |
| 29 | if (auto process = thread->GetOwnerProcess(); process) { | 29 | if (auto process = thread->GetOwnerProcess(); process) { |
| 30 | process->IncrementScheduledCount(); | 30 | process->IncrementScheduledCount(); |
| 31 | } | 31 | } |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, | 34 | void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule) { |
| 35 | Core::EmuThreadHandle global_thread) { | 35 | auto scheduler = kernel.CurrentScheduler(); |
| 36 | const u32 current_core = global_thread.host_handle; | 36 | |
| 37 | bool must_context_switch = global_thread.guest_handle != InvalidHandle && | 37 | u32 current_core{0xF}; |
| 38 | (current_core < Core::Hardware::NUM_CPU_CORES); | 38 | bool must_context_switch{}; |
| 39 | if (scheduler) { | ||
| 40 | current_core = scheduler->core_id; | ||
| 41 | // TODO(bunnei): Should be set to true when we deprecate single core | ||
| 42 | must_context_switch = !kernel.IsPhantomModeForSingleCore(); | ||
| 43 | } | ||
| 39 | 44 | ||
| 40 | while (cores_pending_reschedule != 0) { | 45 | while (cores_pending_reschedule != 0) { |
| 41 | const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule)); | 46 | const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule)); |
| @@ -56,28 +61,27 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul | |||
| 56 | } | 61 | } |
| 57 | } | 62 | } |
| 58 | 63 | ||
| 59 | u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) { | 64 | u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { |
| 60 | std::scoped_lock lock{guard}; | 65 | std::scoped_lock lock{guard}; |
| 61 | if (Thread* prev_highest_thread = this->state.highest_priority_thread; | 66 | if (KThread* prev_highest_thread = state.highest_priority_thread; |
| 62 | prev_highest_thread != highest_thread) { | 67 | prev_highest_thread != highest_thread) { |
| 63 | if (prev_highest_thread != nullptr) { | 68 | if (prev_highest_thread != nullptr) { |
| 64 | IncrementScheduledCount(prev_highest_thread); | 69 | IncrementScheduledCount(prev_highest_thread); |
| 65 | prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks()); | 70 | prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks()); |
| 66 | } | 71 | } |
| 67 | if (this->state.should_count_idle) { | 72 | if (state.should_count_idle) { |
| 68 | if (highest_thread != nullptr) { | 73 | if (highest_thread != nullptr) { |
| 69 | // if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { | 74 | if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { |
| 70 | // process->SetRunningThread(this->core_id, highest_thread, | 75 | process->SetRunningThread(core_id, highest_thread, state.idle_count); |
| 71 | // this->state.idle_count); | 76 | } |
| 72 | //} | ||
| 73 | } else { | 77 | } else { |
| 74 | this->state.idle_count++; | 78 | state.idle_count++; |
| 75 | } | 79 | } |
| 76 | } | 80 | } |
| 77 | 81 | ||
| 78 | this->state.highest_priority_thread = highest_thread; | 82 | state.highest_priority_thread = highest_thread; |
| 79 | this->state.needs_scheduling = true; | 83 | state.needs_scheduling.store(true); |
| 80 | return (1ULL << this->core_id); | 84 | return (1ULL << core_id); |
| 81 | } else { | 85 | } else { |
| 82 | return 0; | 86 | return 0; |
| 83 | } | 87 | } |
| @@ -90,16 +94,29 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { | |||
| 90 | ClearSchedulerUpdateNeeded(kernel); | 94 | ClearSchedulerUpdateNeeded(kernel); |
| 91 | 95 | ||
| 92 | u64 cores_needing_scheduling = 0, idle_cores = 0; | 96 | u64 cores_needing_scheduling = 0, idle_cores = 0; |
| 93 | Thread* top_threads[Core::Hardware::NUM_CPU_CORES]; | 97 | KThread* top_threads[Core::Hardware::NUM_CPU_CORES]; |
| 94 | auto& priority_queue = GetPriorityQueue(kernel); | 98 | auto& priority_queue = GetPriorityQueue(kernel); |
| 95 | 99 | ||
| 96 | /// We want to go over all cores, finding the highest priority thread and determining if | 100 | /// We want to go over all cores, finding the highest priority thread and determining if |
| 97 | /// scheduling is needed for that core. | 101 | /// scheduling is needed for that core. |
| 98 | for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | 102 | for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { |
| 99 | Thread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id)); | 103 | KThread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id)); |
| 100 | if (top_thread != nullptr) { | 104 | if (top_thread != nullptr) { |
| 101 | // If the thread has no waiters, we need to check if the process has a thread pinned. | 105 | // If the thread has no waiters, we need to check if the process has a thread pinned. |
| 102 | // TODO(bunnei): Implement thread pinning | 106 | if (top_thread->GetNumKernelWaiters() == 0) { |
| 107 | if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) { | ||
| 108 | if (KThread* pinned = parent->GetPinnedThread(static_cast<s32>(core_id)); | ||
| 109 | pinned != nullptr && pinned != top_thread) { | ||
| 110 | // We prefer our parent's pinned thread if possible. However, we also don't | ||
| 111 | // want to schedule un-runnable threads. | ||
| 112 | if (pinned->GetRawState() == ThreadState::Runnable) { | ||
| 113 | top_thread = pinned; | ||
| 114 | } else { | ||
| 115 | top_thread = nullptr; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 103 | } else { | 120 | } else { |
| 104 | idle_cores |= (1ULL << core_id); | 121 | idle_cores |= (1ULL << core_id); |
| 105 | } | 122 | } |
| @@ -112,7 +129,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { | |||
| 112 | // Idle cores are bad. We're going to try to migrate threads to each idle core in turn. | 129 | // Idle cores are bad. We're going to try to migrate threads to each idle core in turn. |
| 113 | while (idle_cores != 0) { | 130 | while (idle_cores != 0) { |
| 114 | const auto core_id = static_cast<u32>(std::countr_zero(idle_cores)); | 131 | const auto core_id = static_cast<u32>(std::countr_zero(idle_cores)); |
| 115 | if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { | 132 | if (KThread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { |
| 116 | s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; | 133 | s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; |
| 117 | size_t num_candidates = 0; | 134 | size_t num_candidates = 0; |
| 118 | 135 | ||
| @@ -120,7 +137,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { | |||
| 120 | while (suggested != nullptr) { | 137 | while (suggested != nullptr) { |
| 121 | // Check if the suggested thread is the top thread on its core. | 138 | // Check if the suggested thread is the top thread on its core. |
| 122 | const s32 suggested_core = suggested->GetActiveCore(); | 139 | const s32 suggested_core = suggested->GetActiveCore(); |
| 123 | if (Thread* top_thread = | 140 | if (KThread* top_thread = |
| 124 | (suggested_core >= 0) ? top_threads[suggested_core] : nullptr; | 141 | (suggested_core >= 0) ? top_threads[suggested_core] : nullptr; |
| 125 | top_thread != suggested) { | 142 | top_thread != suggested) { |
| 126 | // Make sure we're not dealing with threads too high priority for migration. | 143 | // Make sure we're not dealing with threads too high priority for migration. |
| @@ -152,7 +169,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { | |||
| 152 | // Check if there's some other thread that can run on the candidate core. | 169 | // Check if there's some other thread that can run on the candidate core. |
| 153 | const s32 candidate_core = migration_candidates[i]; | 170 | const s32 candidate_core = migration_candidates[i]; |
| 154 | suggested = top_threads[candidate_core]; | 171 | suggested = top_threads[candidate_core]; |
| 155 | if (Thread* next_on_candidate_core = | 172 | if (KThread* next_on_candidate_core = |
| 156 | priority_queue.GetScheduledNext(candidate_core, suggested); | 173 | priority_queue.GetScheduledNext(candidate_core, suggested); |
| 157 | next_on_candidate_core != nullptr) { | 174 | next_on_candidate_core != nullptr) { |
| 158 | // The candidate core can run some other thread! We'll migrate its current | 175 | // The candidate core can run some other thread! We'll migrate its current |
| @@ -182,7 +199,20 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { | |||
| 182 | return cores_needing_scheduling; | 199 | return cores_needing_scheduling; |
| 183 | } | 200 | } |
| 184 | 201 | ||
| 185 | void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state) { | 202 | void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) { |
| 203 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 204 | for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; ++i) { | ||
| 205 | // Get an atomic reference to the core scheduler's previous thread. | ||
| 206 | std::atomic_ref<KThread*> prev_thread(kernel.Scheduler(static_cast<s32>(i)).prev_thread); | ||
| 207 | static_assert(std::atomic_ref<KThread*>::is_always_lock_free); | ||
| 208 | |||
| 209 | // Atomically clear the previous thread if it's our target. | ||
| 210 | KThread* compare = thread; | ||
| 211 | prev_thread.compare_exchange_strong(compare, nullptr); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state) { | ||
| 186 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 216 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 187 | 217 | ||
| 188 | // Check if the state has changed, because if it hasn't there's nothing to do. | 218 | // Check if the state has changed, because if it hasn't there's nothing to do. |
| @@ -205,7 +235,7 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, Thread | |||
| 205 | } | 235 | } |
| 206 | } | 236 | } |
| 207 | 237 | ||
| 208 | void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority) { | 238 | void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority) { |
| 209 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 239 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 210 | 240 | ||
| 211 | // If the thread is runnable, we want to change its priority in the queue. | 241 | // If the thread is runnable, we want to change its priority in the queue. |
| @@ -217,7 +247,7 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 | |||
| 217 | } | 247 | } |
| 218 | } | 248 | } |
| 219 | 249 | ||
| 220 | void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, | 250 | void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread, |
| 221 | const KAffinityMask& old_affinity, s32 old_core) { | 251 | const KAffinityMask& old_affinity, s32 old_core) { |
| 222 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 252 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 223 | 253 | ||
| @@ -237,8 +267,8 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { | |||
| 237 | auto& priority_queue = GetPriorityQueue(kernel); | 267 | auto& priority_queue = GetPriorityQueue(kernel); |
| 238 | 268 | ||
| 239 | // Rotate the front of the queue to the end. | 269 | // Rotate the front of the queue to the end. |
| 240 | Thread* top_thread = priority_queue.GetScheduledFront(core_id, priority); | 270 | KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority); |
| 241 | Thread* next_thread = nullptr; | 271 | KThread* next_thread = nullptr; |
| 242 | if (top_thread != nullptr) { | 272 | if (top_thread != nullptr) { |
| 243 | next_thread = priority_queue.MoveToScheduledBack(top_thread); | 273 | next_thread = priority_queue.MoveToScheduledBack(top_thread); |
| 244 | if (next_thread != top_thread) { | 274 | if (next_thread != top_thread) { |
| @@ -249,11 +279,11 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { | |||
| 249 | 279 | ||
| 250 | // While we have a suggested thread, try to migrate it! | 280 | // While we have a suggested thread, try to migrate it! |
| 251 | { | 281 | { |
| 252 | Thread* suggested = priority_queue.GetSuggestedFront(core_id, priority); | 282 | KThread* suggested = priority_queue.GetSuggestedFront(core_id, priority); |
| 253 | while (suggested != nullptr) { | 283 | while (suggested != nullptr) { |
| 254 | // Check if the suggested thread is the top thread on its core. | 284 | // Check if the suggested thread is the top thread on its core. |
| 255 | const s32 suggested_core = suggested->GetActiveCore(); | 285 | const s32 suggested_core = suggested->GetActiveCore(); |
| 256 | if (Thread* top_on_suggested_core = | 286 | if (KThread* top_on_suggested_core = |
| 257 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) | 287 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) |
| 258 | : nullptr; | 288 | : nullptr; |
| 259 | top_on_suggested_core != suggested) { | 289 | top_on_suggested_core != suggested) { |
| @@ -285,7 +315,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { | |||
| 285 | // Now that we might have migrated a thread with the same priority, check if we can do better. | 315 | // Now that we might have migrated a thread with the same priority, check if we can do better. |
| 286 | 316 | ||
| 287 | { | 317 | { |
| 288 | Thread* best_thread = priority_queue.GetScheduledFront(core_id); | 318 | KThread* best_thread = priority_queue.GetScheduledFront(core_id); |
| 289 | if (best_thread == GetCurrentThread()) { | 319 | if (best_thread == GetCurrentThread()) { |
| 290 | best_thread = priority_queue.GetScheduledNext(core_id, best_thread); | 320 | best_thread = priority_queue.GetScheduledNext(core_id, best_thread); |
| 291 | } | 321 | } |
| @@ -293,7 +323,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { | |||
| 293 | // If the best thread we can choose has a priority the same or worse than ours, try to | 323 | // If the best thread we can choose has a priority the same or worse than ours, try to |
| 294 | // migrate a higher priority thread. | 324 | // migrate a higher priority thread. |
| 295 | if (best_thread != nullptr && best_thread->GetPriority() >= priority) { | 325 | if (best_thread != nullptr && best_thread->GetPriority() >= priority) { |
| 296 | Thread* suggested = priority_queue.GetSuggestedFront(core_id); | 326 | KThread* suggested = priority_queue.GetSuggestedFront(core_id); |
| 297 | while (suggested != nullptr) { | 327 | while (suggested != nullptr) { |
| 298 | // If the suggestion's priority is the same as ours, don't bother. | 328 | // If the suggestion's priority is the same as ours, don't bother. |
| 299 | if (suggested->GetPriority() >= best_thread->GetPriority()) { | 329 | if (suggested->GetPriority() >= best_thread->GetPriority()) { |
| @@ -302,7 +332,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { | |||
| 302 | 332 | ||
| 303 | // Check if the suggested thread is the top thread on its core. | 333 | // Check if the suggested thread is the top thread on its core. |
| 304 | const s32 suggested_core = suggested->GetActiveCore(); | 334 | const s32 suggested_core = suggested->GetActiveCore(); |
| 305 | if (Thread* top_on_suggested_core = | 335 | if (KThread* top_on_suggested_core = |
| 306 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) | 336 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) |
| 307 | : nullptr; | 337 | : nullptr; |
| 308 | top_on_suggested_core != suggested) { | 338 | top_on_suggested_core != suggested) { |
| @@ -352,12 +382,14 @@ void KScheduler::DisableScheduling(KernelCore& kernel) { | |||
| 352 | } | 382 | } |
| 353 | } | 383 | } |
| 354 | 384 | ||
| 355 | void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling, | 385 | void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { |
| 356 | Core::EmuThreadHandle global_thread) { | ||
| 357 | if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { | 386 | if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { |
| 358 | scheduler->GetCurrentThread()->EnableDispatch(); | 387 | ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1); |
| 388 | if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) { | ||
| 389 | scheduler->GetCurrentThread()->EnableDispatch(); | ||
| 390 | } | ||
| 359 | } | 391 | } |
| 360 | RescheduleCores(kernel, cores_needing_scheduling, global_thread); | 392 | RescheduleCores(kernel, cores_needing_scheduling); |
| 361 | } | 393 | } |
| 362 | 394 | ||
| 363 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { | 395 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { |
| @@ -372,15 +404,13 @@ KSchedulerPriorityQueue& KScheduler::GetPriorityQueue(KernelCore& kernel) { | |||
| 372 | return kernel.GlobalSchedulerContext().priority_queue; | 404 | return kernel.GlobalSchedulerContext().priority_queue; |
| 373 | } | 405 | } |
| 374 | 406 | ||
| 375 | void KScheduler::YieldWithoutCoreMigration() { | 407 | void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) { |
| 376 | auto& kernel = system.Kernel(); | ||
| 377 | |||
| 378 | // Validate preconditions. | 408 | // Validate preconditions. |
| 379 | ASSERT(CanSchedule(kernel)); | 409 | ASSERT(CanSchedule(kernel)); |
| 380 | ASSERT(kernel.CurrentProcess() != nullptr); | 410 | ASSERT(kernel.CurrentProcess() != nullptr); |
| 381 | 411 | ||
| 382 | // Get the current thread and process. | 412 | // Get the current thread and process. |
| 383 | Thread& cur_thread = *GetCurrentThread(); | 413 | KThread& cur_thread = Kernel::GetCurrentThread(kernel); |
| 384 | Process& cur_process = *kernel.CurrentProcess(); | 414 | Process& cur_process = *kernel.CurrentProcess(); |
| 385 | 415 | ||
| 386 | // If the thread's yield count matches, there's nothing for us to do. | 416 | // If the thread's yield count matches, there's nothing for us to do. |
| @@ -398,7 +428,7 @@ void KScheduler::YieldWithoutCoreMigration() { | |||
| 398 | const auto cur_state = cur_thread.GetRawState(); | 428 | const auto cur_state = cur_thread.GetRawState(); |
| 399 | if (cur_state == ThreadState::Runnable) { | 429 | if (cur_state == ThreadState::Runnable) { |
| 400 | // Put the current thread at the back of the queue. | 430 | // Put the current thread at the back of the queue. |
| 401 | Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); | 431 | KThread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); |
| 402 | IncrementScheduledCount(std::addressof(cur_thread)); | 432 | IncrementScheduledCount(std::addressof(cur_thread)); |
| 403 | 433 | ||
| 404 | // If the next thread is different, we have an update to perform. | 434 | // If the next thread is different, we have an update to perform. |
| @@ -413,15 +443,13 @@ void KScheduler::YieldWithoutCoreMigration() { | |||
| 413 | } | 443 | } |
| 414 | } | 444 | } |
| 415 | 445 | ||
| 416 | void KScheduler::YieldWithCoreMigration() { | 446 | void KScheduler::YieldWithCoreMigration(KernelCore& kernel) { |
| 417 | auto& kernel = system.Kernel(); | ||
| 418 | |||
| 419 | // Validate preconditions. | 447 | // Validate preconditions. |
| 420 | ASSERT(CanSchedule(kernel)); | 448 | ASSERT(CanSchedule(kernel)); |
| 421 | ASSERT(kernel.CurrentProcess() != nullptr); | 449 | ASSERT(kernel.CurrentProcess() != nullptr); |
| 422 | 450 | ||
| 423 | // Get the current thread and process. | 451 | // Get the current thread and process. |
| 424 | Thread& cur_thread = *GetCurrentThread(); | 452 | KThread& cur_thread = Kernel::GetCurrentThread(kernel); |
| 425 | Process& cur_process = *kernel.CurrentProcess(); | 453 | Process& cur_process = *kernel.CurrentProcess(); |
| 426 | 454 | ||
| 427 | // If the thread's yield count matches, there's nothing for us to do. | 455 | // If the thread's yield count matches, there's nothing for us to do. |
| @@ -442,17 +470,17 @@ void KScheduler::YieldWithCoreMigration() { | |||
| 442 | const s32 core_id = cur_thread.GetActiveCore(); | 470 | const s32 core_id = cur_thread.GetActiveCore(); |
| 443 | 471 | ||
| 444 | // Put the current thread at the back of the queue. | 472 | // Put the current thread at the back of the queue. |
| 445 | Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); | 473 | KThread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); |
| 446 | IncrementScheduledCount(std::addressof(cur_thread)); | 474 | IncrementScheduledCount(std::addressof(cur_thread)); |
| 447 | 475 | ||
| 448 | // While we have a suggested thread, try to migrate it! | 476 | // While we have a suggested thread, try to migrate it! |
| 449 | bool recheck = false; | 477 | bool recheck = false; |
| 450 | Thread* suggested = priority_queue.GetSuggestedFront(core_id); | 478 | KThread* suggested = priority_queue.GetSuggestedFront(core_id); |
| 451 | while (suggested != nullptr) { | 479 | while (suggested != nullptr) { |
| 452 | // Check if the suggested thread is the thread running on its core. | 480 | // Check if the suggested thread is the thread running on its core. |
| 453 | const s32 suggested_core = suggested->GetActiveCore(); | 481 | const s32 suggested_core = suggested->GetActiveCore(); |
| 454 | 482 | ||
| 455 | if (Thread* running_on_suggested_core = | 483 | if (KThread* running_on_suggested_core = |
| 456 | (suggested_core >= 0) | 484 | (suggested_core >= 0) |
| 457 | ? kernel.Scheduler(suggested_core).state.highest_priority_thread | 485 | ? kernel.Scheduler(suggested_core).state.highest_priority_thread |
| 458 | : nullptr; | 486 | : nullptr; |
| @@ -503,15 +531,13 @@ void KScheduler::YieldWithCoreMigration() { | |||
| 503 | } | 531 | } |
| 504 | } | 532 | } |
| 505 | 533 | ||
| 506 | void KScheduler::YieldToAnyThread() { | 534 | void KScheduler::YieldToAnyThread(KernelCore& kernel) { |
| 507 | auto& kernel = system.Kernel(); | ||
| 508 | |||
| 509 | // Validate preconditions. | 535 | // Validate preconditions. |
| 510 | ASSERT(CanSchedule(kernel)); | 536 | ASSERT(CanSchedule(kernel)); |
| 511 | ASSERT(kernel.CurrentProcess() != nullptr); | 537 | ASSERT(kernel.CurrentProcess() != nullptr); |
| 512 | 538 | ||
| 513 | // Get the current thread and process. | 539 | // Get the current thread and process. |
| 514 | Thread& cur_thread = *GetCurrentThread(); | 540 | KThread& cur_thread = Kernel::GetCurrentThread(kernel); |
| 515 | Process& cur_process = *kernel.CurrentProcess(); | 541 | Process& cur_process = *kernel.CurrentProcess(); |
| 516 | 542 | ||
| 517 | // If the thread's yield count matches, there's nothing for us to do. | 543 | // If the thread's yield count matches, there's nothing for us to do. |
| @@ -539,11 +565,11 @@ void KScheduler::YieldToAnyThread() { | |||
| 539 | // If there's nothing scheduled, we can try to perform a migration. | 565 | // If there's nothing scheduled, we can try to perform a migration. |
| 540 | if (priority_queue.GetScheduledFront(core_id) == nullptr) { | 566 | if (priority_queue.GetScheduledFront(core_id) == nullptr) { |
| 541 | // While we have a suggested thread, try to migrate it! | 567 | // While we have a suggested thread, try to migrate it! |
| 542 | Thread* suggested = priority_queue.GetSuggestedFront(core_id); | 568 | KThread* suggested = priority_queue.GetSuggestedFront(core_id); |
| 543 | while (suggested != nullptr) { | 569 | while (suggested != nullptr) { |
| 544 | // Check if the suggested thread is the top thread on its core. | 570 | // Check if the suggested thread is the top thread on its core. |
| 545 | const s32 suggested_core = suggested->GetActiveCore(); | 571 | const s32 suggested_core = suggested->GetActiveCore(); |
| 546 | if (Thread* top_on_suggested_core = | 572 | if (KThread* top_on_suggested_core = |
| 547 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) | 573 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) |
| 548 | : nullptr; | 574 | : nullptr; |
| 549 | top_on_suggested_core != suggested) { | 575 | top_on_suggested_core != suggested) { |
| @@ -581,22 +607,21 @@ void KScheduler::YieldToAnyThread() { | |||
| 581 | } | 607 | } |
| 582 | } | 608 | } |
| 583 | 609 | ||
| 584 | KScheduler::KScheduler(Core::System& system, std::size_t core_id) | 610 | KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) { |
| 585 | : system(system), core_id(core_id) { | ||
| 586 | switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this); | 611 | switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this); |
| 587 | this->state.needs_scheduling = true; | 612 | state.needs_scheduling.store(true); |
| 588 | this->state.interrupt_task_thread_runnable = false; | 613 | state.interrupt_task_thread_runnable = false; |
| 589 | this->state.should_count_idle = false; | 614 | state.should_count_idle = false; |
| 590 | this->state.idle_count = 0; | 615 | state.idle_count = 0; |
| 591 | this->state.idle_thread_stack = nullptr; | 616 | state.idle_thread_stack = nullptr; |
| 592 | this->state.highest_priority_thread = nullptr; | 617 | state.highest_priority_thread = nullptr; |
| 593 | } | 618 | } |
| 594 | 619 | ||
| 595 | KScheduler::~KScheduler() = default; | 620 | KScheduler::~KScheduler() = default; |
| 596 | 621 | ||
| 597 | Thread* KScheduler::GetCurrentThread() const { | 622 | KThread* KScheduler::GetCurrentThread() const { |
| 598 | if (current_thread) { | 623 | if (auto result = current_thread.load(); result) { |
| 599 | return current_thread; | 624 | return result; |
| 600 | } | 625 | } |
| 601 | return idle_thread; | 626 | return idle_thread; |
| 602 | } | 627 | } |
| @@ -613,7 +638,7 @@ void KScheduler::RescheduleCurrentCore() { | |||
| 613 | phys_core.ClearInterrupt(); | 638 | phys_core.ClearInterrupt(); |
| 614 | } | 639 | } |
| 615 | guard.lock(); | 640 | guard.lock(); |
| 616 | if (this->state.needs_scheduling) { | 641 | if (state.needs_scheduling.load()) { |
| 617 | Schedule(); | 642 | Schedule(); |
| 618 | } else { | 643 | } else { |
| 619 | guard.unlock(); | 644 | guard.unlock(); |
| @@ -624,66 +649,76 @@ void KScheduler::OnThreadStart() { | |||
| 624 | SwitchContextStep2(); | 649 | SwitchContextStep2(); |
| 625 | } | 650 | } |
| 626 | 651 | ||
| 627 | void KScheduler::Unload(Thread* thread) { | 652 | void KScheduler::Unload(KThread* thread) { |
| 653 | LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); | ||
| 654 | |||
| 628 | if (thread) { | 655 | if (thread) { |
| 629 | thread->SetIsRunning(false); | 656 | if (thread->IsCallingSvc()) { |
| 630 | if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) { | ||
| 631 | system.ArmInterface(core_id).ExceptionalExit(); | 657 | system.ArmInterface(core_id).ExceptionalExit(); |
| 632 | thread->SetContinuousOnSVC(false); | 658 | thread->ClearIsCallingSvc(); |
| 633 | } | 659 | } |
| 634 | if (!thread->IsHLEThread() && !thread->HasExited()) { | 660 | if (!thread->IsTerminationRequested()) { |
| 661 | prev_thread = thread; | ||
| 662 | |||
| 635 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); | 663 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); |
| 636 | cpu_core.SaveContext(thread->GetContext32()); | 664 | cpu_core.SaveContext(thread->GetContext32()); |
| 637 | cpu_core.SaveContext(thread->GetContext64()); | 665 | cpu_core.SaveContext(thread->GetContext64()); |
| 638 | // Save the TPIDR_EL0 system register in case it was modified. | 666 | // Save the TPIDR_EL0 system register in case it was modified. |
| 639 | thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); | 667 | thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); |
| 640 | cpu_core.ClearExclusiveState(); | 668 | cpu_core.ClearExclusiveState(); |
| 669 | } else { | ||
| 670 | prev_thread = nullptr; | ||
| 641 | } | 671 | } |
| 642 | thread->context_guard.unlock(); | 672 | thread->context_guard.unlock(); |
| 643 | } | 673 | } |
| 644 | } | 674 | } |
| 645 | 675 | ||
| 646 | void KScheduler::Reload(Thread* thread) { | 676 | void KScheduler::Reload(KThread* thread) { |
| 677 | LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread ? thread->GetName() : "nullptr"); | ||
| 678 | |||
| 647 | if (thread) { | 679 | if (thread) { |
| 648 | ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); | 680 | ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); |
| 649 | 681 | ||
| 650 | // Cancel any outstanding wakeup events for this thread | ||
| 651 | thread->SetIsRunning(true); | ||
| 652 | thread->SetWasRunning(false); | ||
| 653 | |||
| 654 | auto* const thread_owner_process = thread->GetOwnerProcess(); | 682 | auto* const thread_owner_process = thread->GetOwnerProcess(); |
| 655 | if (thread_owner_process != nullptr) { | 683 | if (thread_owner_process != nullptr) { |
| 656 | system.Kernel().MakeCurrentProcess(thread_owner_process); | 684 | system.Kernel().MakeCurrentProcess(thread_owner_process); |
| 657 | } | 685 | } |
| 658 | if (!thread->IsHLEThread()) { | 686 | |
| 659 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); | 687 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); |
| 660 | cpu_core.LoadContext(thread->GetContext32()); | 688 | cpu_core.LoadContext(thread->GetContext32()); |
| 661 | cpu_core.LoadContext(thread->GetContext64()); | 689 | cpu_core.LoadContext(thread->GetContext64()); |
| 662 | cpu_core.SetTlsAddress(thread->GetTLSAddress()); | 690 | cpu_core.SetTlsAddress(thread->GetTLSAddress()); |
| 663 | cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); | 691 | cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); |
| 664 | cpu_core.ClearExclusiveState(); | 692 | cpu_core.ClearExclusiveState(); |
| 665 | } | ||
| 666 | } | 693 | } |
| 667 | } | 694 | } |
| 668 | 695 | ||
| 669 | void KScheduler::SwitchContextStep2() { | 696 | void KScheduler::SwitchContextStep2() { |
| 670 | // Load context of new thread | 697 | // Load context of new thread |
| 671 | Reload(current_thread); | 698 | Reload(current_thread.load()); |
| 672 | 699 | ||
| 673 | RescheduleCurrentCore(); | 700 | RescheduleCurrentCore(); |
| 674 | } | 701 | } |
| 675 | 702 | ||
| 676 | void KScheduler::ScheduleImpl() { | 703 | void KScheduler::ScheduleImpl() { |
| 677 | Thread* previous_thread = current_thread; | 704 | KThread* previous_thread = current_thread.load(); |
| 678 | current_thread = state.highest_priority_thread; | 705 | KThread* next_thread = state.highest_priority_thread; |
| 679 | 706 | ||
| 680 | this->state.needs_scheduling = false; | 707 | state.needs_scheduling = false; |
| 708 | |||
| 709 | // We never want to schedule a null thread, so use the idle thread if we don't have a next. | ||
| 710 | if (next_thread == nullptr) { | ||
| 711 | next_thread = idle_thread; | ||
| 712 | } | ||
| 681 | 713 | ||
| 682 | if (current_thread == previous_thread) { | 714 | // If we're not actually switching thread, there's nothing to do. |
| 715 | if (next_thread == current_thread.load()) { | ||
| 683 | guard.unlock(); | 716 | guard.unlock(); |
| 684 | return; | 717 | return; |
| 685 | } | 718 | } |
| 686 | 719 | ||
| 720 | current_thread.store(next_thread); | ||
| 721 | |||
| 687 | Process* const previous_process = system.Kernel().CurrentProcess(); | 722 | Process* const previous_process = system.Kernel().CurrentProcess(); |
| 688 | 723 | ||
| 689 | UpdateLastContextSwitchTime(previous_thread, previous_process); | 724 | UpdateLastContextSwitchTime(previous_thread, previous_process); |
| @@ -714,28 +749,29 @@ void KScheduler::SwitchToCurrent() { | |||
| 714 | while (true) { | 749 | while (true) { |
| 715 | { | 750 | { |
| 716 | std::scoped_lock lock{guard}; | 751 | std::scoped_lock lock{guard}; |
| 717 | current_thread = state.highest_priority_thread; | 752 | current_thread.store(state.highest_priority_thread); |
| 718 | this->state.needs_scheduling = false; | 753 | state.needs_scheduling.store(false); |
| 719 | } | 754 | } |
| 720 | const auto is_switch_pending = [this] { | 755 | const auto is_switch_pending = [this] { |
| 721 | std::scoped_lock lock{guard}; | 756 | std::scoped_lock lock{guard}; |
| 722 | return state.needs_scheduling.load(std::memory_order_relaxed); | 757 | return state.needs_scheduling.load(); |
| 723 | }; | 758 | }; |
| 724 | do { | 759 | do { |
| 725 | if (current_thread != nullptr && !current_thread->IsHLEThread()) { | 760 | auto next_thread = current_thread.load(); |
| 726 | current_thread->context_guard.lock(); | 761 | if (next_thread != nullptr) { |
| 727 | if (current_thread->GetRawState() != ThreadState::Runnable) { | 762 | next_thread->context_guard.lock(); |
| 728 | current_thread->context_guard.unlock(); | 763 | if (next_thread->GetRawState() != ThreadState::Runnable) { |
| 764 | next_thread->context_guard.unlock(); | ||
| 729 | break; | 765 | break; |
| 730 | } | 766 | } |
| 731 | if (static_cast<u32>(current_thread->GetProcessorID()) != core_id) { | 767 | if (next_thread->GetActiveCore() != core_id) { |
| 732 | current_thread->context_guard.unlock(); | 768 | next_thread->context_guard.unlock(); |
| 733 | break; | 769 | break; |
| 734 | } | 770 | } |
| 735 | } | 771 | } |
| 736 | std::shared_ptr<Common::Fiber>* next_context; | 772 | std::shared_ptr<Common::Fiber>* next_context; |
| 737 | if (current_thread != nullptr) { | 773 | if (next_thread != nullptr) { |
| 738 | next_context = ¤t_thread->GetHostContext(); | 774 | next_context = &next_thread->GetHostContext(); |
| 739 | } else { | 775 | } else { |
| 740 | next_context = &idle_thread->GetHostContext(); | 776 | next_context = &idle_thread->GetHostContext(); |
| 741 | } | 777 | } |
| @@ -744,13 +780,13 @@ void KScheduler::SwitchToCurrent() { | |||
| 744 | } | 780 | } |
| 745 | } | 781 | } |
| 746 | 782 | ||
| 747 | void KScheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { | 783 | void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) { |
| 748 | const u64 prev_switch_ticks = last_context_switch_time; | 784 | const u64 prev_switch_ticks = last_context_switch_time; |
| 749 | const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); | 785 | const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); |
| 750 | const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; | 786 | const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; |
| 751 | 787 | ||
| 752 | if (thread != nullptr) { | 788 | if (thread != nullptr) { |
| 753 | thread->UpdateCPUTimeTicks(update_ticks); | 789 | thread->AddCpuTime(core_id, update_ticks); |
| 754 | } | 790 | } |
| 755 | 791 | ||
| 756 | if (process != nullptr) { | 792 | if (process != nullptr) { |
| @@ -764,15 +800,10 @@ void KScheduler::Initialize() { | |||
| 764 | std::string name = "Idle Thread Id:" + std::to_string(core_id); | 800 | std::string name = "Idle Thread Id:" + std::to_string(core_id); |
| 765 | std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); | 801 | std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); |
| 766 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | 802 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); |
| 767 | ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); | 803 | auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, |
| 768 | auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0, | 804 | KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0, |
| 769 | nullptr, std::move(init_func), init_func_parameter); | 805 | nullptr, std::move(init_func), init_func_parameter); |
| 770 | idle_thread = thread_res.Unwrap().get(); | 806 | idle_thread = thread_res.Unwrap().get(); |
| 771 | |||
| 772 | { | ||
| 773 | KScopedSchedulerLock lock{system.Kernel()}; | ||
| 774 | idle_thread->SetState(ThreadState::Runnable); | ||
| 775 | } | ||
| 776 | } | 807 | } |
| 777 | 808 | ||
| 778 | KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) | 809 | KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) |
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 783665123..f595b9a5c 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h | |||
| @@ -29,29 +29,33 @@ namespace Kernel { | |||
| 29 | class KernelCore; | 29 | class KernelCore; |
| 30 | class Process; | 30 | class Process; |
| 31 | class SchedulerLock; | 31 | class SchedulerLock; |
| 32 | class Thread; | 32 | class KThread; |
| 33 | 33 | ||
| 34 | class KScheduler final { | 34 | class KScheduler final { |
| 35 | public: | 35 | public: |
| 36 | explicit KScheduler(Core::System& system, std::size_t core_id); | 36 | explicit KScheduler(Core::System& system, s32 core_id); |
| 37 | ~KScheduler(); | 37 | ~KScheduler(); |
| 38 | 38 | ||
| 39 | /// Reschedules to the next available thread (call after current thread is suspended) | 39 | /// Reschedules to the next available thread (call after current thread is suspended) |
| 40 | void RescheduleCurrentCore(); | 40 | void RescheduleCurrentCore(); |
| 41 | 41 | ||
| 42 | /// Reschedules cores pending reschedule, to be called on EnableScheduling. | 42 | /// Reschedules cores pending reschedule, to be called on EnableScheduling. |
| 43 | static void RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, | 43 | static void RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule); |
| 44 | Core::EmuThreadHandle global_thread); | ||
| 45 | 44 | ||
| 46 | /// The next two are for SingleCore Only. | 45 | /// The next two are for SingleCore Only. |
| 47 | /// Unload current thread before preempting core. | 46 | /// Unload current thread before preempting core. |
| 48 | void Unload(Thread* thread); | 47 | void Unload(KThread* thread); |
| 49 | 48 | ||
| 50 | /// Reload current thread after core preemption. | 49 | /// Reload current thread after core preemption. |
| 51 | void Reload(Thread* thread); | 50 | void Reload(KThread* thread); |
| 52 | 51 | ||
| 53 | /// Gets the current running thread | 52 | /// Gets the current running thread |
| 54 | [[nodiscard]] Thread* GetCurrentThread() const; | 53 | [[nodiscard]] KThread* GetCurrentThread() const; |
| 54 | |||
| 55 | /// Returns true if the scheduler is idle | ||
| 56 | [[nodiscard]] bool IsIdle() const { | ||
| 57 | return GetCurrentThread() == idle_thread; | ||
| 58 | } | ||
| 55 | 59 | ||
| 56 | /// Gets the timestamp for the last context switch in ticks. | 60 | /// Gets the timestamp for the last context switch in ticks. |
| 57 | [[nodiscard]] u64 GetLastContextSwitchTicks() const; | 61 | [[nodiscard]] u64 GetLastContextSwitchTicks() const; |
| @@ -72,14 +76,14 @@ public: | |||
| 72 | return switch_fiber; | 76 | return switch_fiber; |
| 73 | } | 77 | } |
| 74 | 78 | ||
| 75 | [[nodiscard]] u64 UpdateHighestPriorityThread(Thread* highest_thread); | 79 | [[nodiscard]] u64 UpdateHighestPriorityThread(KThread* highest_thread); |
| 76 | 80 | ||
| 77 | /** | 81 | /** |
| 78 | * Takes a thread and moves it to the back of the it's priority list. | 82 | * Takes a thread and moves it to the back of the it's priority list. |
| 79 | * | 83 | * |
| 80 | * @note This operation can be redundant and no scheduling is changed if marked as so. | 84 | * @note This operation can be redundant and no scheduling is changed if marked as so. |
| 81 | */ | 85 | */ |
| 82 | void YieldWithoutCoreMigration(); | 86 | static void YieldWithoutCoreMigration(KernelCore& kernel); |
| 83 | 87 | ||
| 84 | /** | 88 | /** |
| 85 | * Takes a thread and moves it to the back of the it's priority list. | 89 | * Takes a thread and moves it to the back of the it's priority list. |
| @@ -88,7 +92,7 @@ public: | |||
| 88 | * | 92 | * |
| 89 | * @note This operation can be redundant and no scheduling is changed if marked as so. | 93 | * @note This operation can be redundant and no scheduling is changed if marked as so. |
| 90 | */ | 94 | */ |
| 91 | void YieldWithCoreMigration(); | 95 | static void YieldWithCoreMigration(KernelCore& kernel); |
| 92 | 96 | ||
| 93 | /** | 97 | /** |
| 94 | * Takes a thread and moves it out of the scheduling queue. | 98 | * Takes a thread and moves it out of the scheduling queue. |
| @@ -97,16 +101,18 @@ public: | |||
| 97 | * | 101 | * |
| 98 | * @note This operation can be redundant and no scheduling is changed if marked as so. | 102 | * @note This operation can be redundant and no scheduling is changed if marked as so. |
| 99 | */ | 103 | */ |
| 100 | void YieldToAnyThread(); | 104 | static void YieldToAnyThread(KernelCore& kernel); |
| 105 | |||
| 106 | static void ClearPreviousThread(KernelCore& kernel, KThread* thread); | ||
| 101 | 107 | ||
| 102 | /// Notify the scheduler a thread's status has changed. | 108 | /// Notify the scheduler a thread's status has changed. |
| 103 | static void OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state); | 109 | static void OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state); |
| 104 | 110 | ||
| 105 | /// Notify the scheduler a thread's priority has changed. | 111 | /// Notify the scheduler a thread's priority has changed. |
| 106 | static void OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority); | 112 | static void OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority); |
| 107 | 113 | ||
| 108 | /// Notify the scheduler a thread's core and/or affinity mask has changed. | 114 | /// Notify the scheduler a thread's core and/or affinity mask has changed. |
| 109 | static void OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, | 115 | static void OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread, |
| 110 | const KAffinityMask& old_affinity, s32 old_core); | 116 | const KAffinityMask& old_affinity, s32 old_core); |
| 111 | 117 | ||
| 112 | static bool CanSchedule(KernelCore& kernel); | 118 | static bool CanSchedule(KernelCore& kernel); |
| @@ -114,8 +120,7 @@ public: | |||
| 114 | static void SetSchedulerUpdateNeeded(KernelCore& kernel); | 120 | static void SetSchedulerUpdateNeeded(KernelCore& kernel); |
| 115 | static void ClearSchedulerUpdateNeeded(KernelCore& kernel); | 121 | static void ClearSchedulerUpdateNeeded(KernelCore& kernel); |
| 116 | static void DisableScheduling(KernelCore& kernel); | 122 | static void DisableScheduling(KernelCore& kernel); |
| 117 | static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling, | 123 | static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling); |
| 118 | Core::EmuThreadHandle global_thread); | ||
| 119 | [[nodiscard]] static u64 UpdateHighestPriorityThreads(KernelCore& kernel); | 124 | [[nodiscard]] static u64 UpdateHighestPriorityThreads(KernelCore& kernel); |
| 120 | 125 | ||
| 121 | private: | 126 | private: |
| @@ -163,13 +168,15 @@ private: | |||
| 163 | * most recent tick count retrieved. No special arithmetic is | 168 | * most recent tick count retrieved. No special arithmetic is |
| 164 | * applied to it. | 169 | * applied to it. |
| 165 | */ | 170 | */ |
| 166 | void UpdateLastContextSwitchTime(Thread* thread, Process* process); | 171 | void UpdateLastContextSwitchTime(KThread* thread, Process* process); |
| 167 | 172 | ||
| 168 | static void OnSwitch(void* this_scheduler); | 173 | static void OnSwitch(void* this_scheduler); |
| 169 | void SwitchToCurrent(); | 174 | void SwitchToCurrent(); |
| 170 | 175 | ||
| 171 | Thread* current_thread{}; | 176 | KThread* prev_thread{}; |
| 172 | Thread* idle_thread{}; | 177 | std::atomic<KThread*> current_thread{}; |
| 178 | |||
| 179 | KThread* idle_thread; | ||
| 173 | 180 | ||
| 174 | std::shared_ptr<Common::Fiber> switch_fiber{}; | 181 | std::shared_ptr<Common::Fiber> switch_fiber{}; |
| 175 | 182 | ||
| @@ -178,7 +185,7 @@ private: | |||
| 178 | bool interrupt_task_thread_runnable{}; | 185 | bool interrupt_task_thread_runnable{}; |
| 179 | bool should_count_idle{}; | 186 | bool should_count_idle{}; |
| 180 | u64 idle_count{}; | 187 | u64 idle_count{}; |
| 181 | Thread* highest_priority_thread{}; | 188 | KThread* highest_priority_thread{}; |
| 182 | void* idle_thread_stack{}; | 189 | void* idle_thread_stack{}; |
| 183 | }; | 190 | }; |
| 184 | 191 | ||
| @@ -186,7 +193,7 @@ private: | |||
| 186 | 193 | ||
| 187 | Core::System& system; | 194 | Core::System& system; |
| 188 | u64 last_context_switch_time{}; | 195 | u64 last_context_switch_time{}; |
| 189 | const std::size_t core_id; | 196 | const s32 core_id; |
| 190 | 197 | ||
| 191 | Common::SpinLock guard{}; | 198 | Common::SpinLock guard{}; |
| 192 | }; | 199 | }; |
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h index 9b40bd22c..169455d18 100644 --- a/src/core/hle/kernel/k_scheduler_lock.h +++ b/src/core/hle/kernel/k_scheduler_lock.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 11 | #include "common/spin_lock.h" | 11 | #include "common/spin_lock.h" |
| 12 | #include "core/hardware_properties.h" | 12 | #include "core/hardware_properties.h" |
| 13 | #include "core/hle/kernel/k_thread.h" | ||
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 14 | 15 | ||
| 15 | namespace Kernel { | 16 | namespace Kernel { |
| @@ -22,46 +23,45 @@ public: | |||
| 22 | explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {} | 23 | explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {} |
| 23 | 24 | ||
| 24 | bool IsLockedByCurrentThread() const { | 25 | bool IsLockedByCurrentThread() const { |
| 25 | return this->owner_thread == kernel.GetCurrentEmuThreadID(); | 26 | return owner_thread == GetCurrentThreadPointer(kernel); |
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | void Lock() { | 29 | void Lock() { |
| 29 | if (this->IsLockedByCurrentThread()) { | 30 | if (IsLockedByCurrentThread()) { |
| 30 | // If we already own the lock, we can just increment the count. | 31 | // If we already own the lock, we can just increment the count. |
| 31 | ASSERT(this->lock_count > 0); | 32 | ASSERT(lock_count > 0); |
| 32 | this->lock_count++; | 33 | lock_count++; |
| 33 | } else { | 34 | } else { |
| 34 | // Otherwise, we want to disable scheduling and acquire the spinlock. | 35 | // Otherwise, we want to disable scheduling and acquire the spinlock. |
| 35 | SchedulerType::DisableScheduling(kernel); | 36 | SchedulerType::DisableScheduling(kernel); |
| 36 | this->spin_lock.lock(); | 37 | spin_lock.lock(); |
| 37 | 38 | ||
| 38 | // For debug, ensure that our state is valid. | 39 | // For debug, ensure that our state is valid. |
| 39 | ASSERT(this->lock_count == 0); | 40 | ASSERT(lock_count == 0); |
| 40 | ASSERT(this->owner_thread == Core::EmuThreadHandle::InvalidHandle()); | 41 | ASSERT(owner_thread == nullptr); |
| 41 | 42 | ||
| 42 | // Increment count, take ownership. | 43 | // Increment count, take ownership. |
| 43 | this->lock_count = 1; | 44 | lock_count = 1; |
| 44 | this->owner_thread = kernel.GetCurrentEmuThreadID(); | 45 | owner_thread = GetCurrentThreadPointer(kernel); |
| 45 | } | 46 | } |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | void Unlock() { | 49 | void Unlock() { |
| 49 | ASSERT(this->IsLockedByCurrentThread()); | 50 | ASSERT(IsLockedByCurrentThread()); |
| 50 | ASSERT(this->lock_count > 0); | 51 | ASSERT(lock_count > 0); |
| 51 | 52 | ||
| 52 | // Release an instance of the lock. | 53 | // Release an instance of the lock. |
| 53 | if ((--this->lock_count) == 0) { | 54 | if ((--lock_count) == 0) { |
| 54 | // We're no longer going to hold the lock. Take note of what cores need scheduling. | 55 | // We're no longer going to hold the lock. Take note of what cores need scheduling. |
| 55 | const u64 cores_needing_scheduling = | 56 | const u64 cores_needing_scheduling = |
| 56 | SchedulerType::UpdateHighestPriorityThreads(kernel); | 57 | SchedulerType::UpdateHighestPriorityThreads(kernel); |
| 57 | Core::EmuThreadHandle leaving_thread = owner_thread; | ||
| 58 | 58 | ||
| 59 | // Note that we no longer hold the lock, and unlock the spinlock. | 59 | // Note that we no longer hold the lock, and unlock the spinlock. |
| 60 | this->owner_thread = Core::EmuThreadHandle::InvalidHandle(); | 60 | owner_thread = nullptr; |
| 61 | this->spin_lock.unlock(); | 61 | spin_lock.unlock(); |
| 62 | 62 | ||
| 63 | // Enable scheduling, and perform a rescheduling operation. | 63 | // Enable scheduling, and perform a rescheduling operation. |
| 64 | SchedulerType::EnableScheduling(kernel, cores_needing_scheduling, leaving_thread); | 64 | SchedulerType::EnableScheduling(kernel, cores_needing_scheduling); |
| 65 | } | 65 | } |
| 66 | } | 66 | } |
| 67 | 67 | ||
| @@ -69,7 +69,7 @@ private: | |||
| 69 | KernelCore& kernel; | 69 | KernelCore& kernel; |
| 70 | Common::SpinLock spin_lock{}; | 70 | Common::SpinLock spin_lock{}; |
| 71 | s32 lock_count{}; | 71 | s32 lock_count{}; |
| 72 | Core::EmuThreadHandle owner_thread{Core::EmuThreadHandle::InvalidHandle()}; | 72 | KThread* owner_thread{}; |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | } // namespace Kernel | 75 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 2bb3817fa..f8189e107 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | |||
| @@ -9,27 +9,24 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/handle_table.h" | 11 | #include "core/hle/kernel/handle_table.h" |
| 12 | #include "core/hle/kernel/k_thread.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/thread.h" | ||
| 14 | #include "core/hle/kernel/time_manager.h" | 14 | #include "core/hle/kernel/time_manager.h" |
| 15 | 15 | ||
| 16 | namespace Kernel { | 16 | namespace Kernel { |
| 17 | 17 | ||
| 18 | class KScopedSchedulerLockAndSleep { | 18 | class KScopedSchedulerLockAndSleep { |
| 19 | public: | 19 | public: |
| 20 | explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* t, | 20 | explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout) |
| 21 | s64 timeout) | 21 | : kernel(kernel), thread(t), timeout_tick(timeout) { |
| 22 | : kernel(kernel), event_handle(event_handle), thread(t), timeout_tick(timeout) { | ||
| 23 | event_handle = InvalidHandle; | ||
| 24 | |||
| 25 | // Lock the scheduler. | 22 | // Lock the scheduler. |
| 26 | kernel.GlobalSchedulerContext().scheduler_lock.Lock(); | 23 | kernel.GlobalSchedulerContext().scheduler_lock.Lock(); |
| 27 | } | 24 | } |
| 28 | 25 | ||
| 29 | ~KScopedSchedulerLockAndSleep() { | 26 | ~KScopedSchedulerLockAndSleep() { |
| 30 | // Register the sleep. | 27 | // Register the sleep. |
| 31 | if (this->timeout_tick > 0) { | 28 | if (timeout_tick > 0) { |
| 32 | kernel.TimeManager().ScheduleTimeEvent(event_handle, this->thread, this->timeout_tick); | 29 | kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick); |
| 33 | } | 30 | } |
| 34 | 31 | ||
| 35 | // Unlock the scheduler. | 32 | // Unlock the scheduler. |
| @@ -37,13 +34,12 @@ public: | |||
| 37 | } | 34 | } |
| 38 | 35 | ||
| 39 | void CancelSleep() { | 36 | void CancelSleep() { |
| 40 | this->timeout_tick = 0; | 37 | timeout_tick = 0; |
| 41 | } | 38 | } |
| 42 | 39 | ||
| 43 | private: | 40 | private: |
| 44 | KernelCore& kernel; | 41 | KernelCore& kernel; |
| 45 | Handle& event_handle; | 42 | KThread* thread{}; |
| 46 | Thread* thread{}; | ||
| 47 | s64 timeout_tick{}; | 43 | s64 timeout_tick{}; |
| 48 | }; | 44 | }; |
| 49 | 45 | ||
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index 1c508cb55..140cc46a7 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp | |||
| @@ -7,9 +7,9 @@ | |||
| 7 | #include "core/hle/kernel/k_scheduler.h" | 7 | #include "core/hle/kernel/k_scheduler.h" |
| 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 9 | #include "core/hle/kernel/k_synchronization_object.h" | 9 | #include "core/hle/kernel/k_synchronization_object.h" |
| 10 | #include "core/hle/kernel/k_thread.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/svc_results.h" | 12 | #include "core/hle/kernel/svc_results.h" |
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| @@ -20,12 +20,11 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, | |||
| 20 | std::vector<ThreadListNode> thread_nodes(num_objects); | 20 | std::vector<ThreadListNode> thread_nodes(num_objects); |
| 21 | 21 | ||
| 22 | // Prepare for wait. | 22 | // Prepare for wait. |
| 23 | Thread* thread = kernel.CurrentScheduler()->GetCurrentThread(); | 23 | KThread* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 24 | Handle timer = InvalidHandle; | ||
| 25 | 24 | ||
| 26 | { | 25 | { |
| 27 | // Setup the scheduling lock and sleep. | 26 | // Setup the scheduling lock and sleep. |
| 28 | KScopedSchedulerLockAndSleep slp(kernel, timer, thread, timeout); | 27 | KScopedSchedulerLockAndSleep slp{kernel, thread, timeout}; |
| 29 | 28 | ||
| 30 | // Check if any of the objects are already signaled. | 29 | // Check if any of the objects are already signaled. |
| 31 | for (auto i = 0; i < num_objects; ++i) { | 30 | for (auto i = 0; i < num_objects; ++i) { |
| @@ -90,10 +89,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, | |||
| 90 | thread->SetWaitObjectsForDebugging({}); | 89 | thread->SetWaitObjectsForDebugging({}); |
| 91 | 90 | ||
| 92 | // Cancel the timer as needed. | 91 | // Cancel the timer as needed. |
| 93 | if (timer != InvalidHandle) { | 92 | kernel.TimeManager().UnscheduleTimeEvent(thread); |
| 94 | auto& time_manager = kernel.TimeManager(); | ||
| 95 | time_manager.UnscheduleTimeEvent(timer); | ||
| 96 | } | ||
| 97 | 93 | ||
| 98 | // Get the wait result. | 94 | // Get the wait result. |
| 99 | ResultCode wait_result{RESULT_SUCCESS}; | 95 | ResultCode wait_result{RESULT_SUCCESS}; |
| @@ -136,7 +132,10 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, | |||
| 136 | 132 | ||
| 137 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} | 133 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} |
| 138 | 134 | ||
| 139 | KSynchronizationObject ::~KSynchronizationObject() = default; | 135 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel, std::string&& name) |
| 136 | : Object{kernel, std::move(name)} {} | ||
| 137 | |||
| 138 | KSynchronizationObject::~KSynchronizationObject() = default; | ||
| 140 | 139 | ||
| 141 | void KSynchronizationObject::NotifyAvailable(ResultCode result) { | 140 | void KSynchronizationObject::NotifyAvailable(ResultCode result) { |
| 142 | KScopedSchedulerLock lock(kernel); | 141 | KScopedSchedulerLock lock(kernel); |
| @@ -148,7 +147,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) { | |||
| 148 | 147 | ||
| 149 | // Iterate over each thread. | 148 | // Iterate over each thread. |
| 150 | for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { | 149 | for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { |
| 151 | Thread* thread = cur_node->thread; | 150 | KThread* thread = cur_node->thread; |
| 152 | if (thread->GetState() == ThreadState::Waiting) { | 151 | if (thread->GetState() == ThreadState::Waiting) { |
| 153 | thread->SetSyncedObject(this, result); | 152 | thread->SetSyncedObject(this, result); |
| 154 | thread->SetState(ThreadState::Runnable); | 153 | thread->SetState(ThreadState::Runnable); |
| @@ -156,8 +155,8 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) { | |||
| 156 | } | 155 | } |
| 157 | } | 156 | } |
| 158 | 157 | ||
| 159 | std::vector<Thread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const { | 158 | std::vector<KThread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const { |
| 160 | std::vector<Thread*> threads; | 159 | std::vector<KThread*> threads; |
| 161 | 160 | ||
| 162 | // If debugging, dump the list of waiters. | 161 | // If debugging, dump the list of waiters. |
| 163 | { | 162 | { |
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 14d80ebf1..5803718fd 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h | |||
| @@ -13,14 +13,14 @@ namespace Kernel { | |||
| 13 | 13 | ||
| 14 | class KernelCore; | 14 | class KernelCore; |
| 15 | class Synchronization; | 15 | class Synchronization; |
| 16 | class Thread; | 16 | class KThread; |
| 17 | 17 | ||
| 18 | /// Class that represents a Kernel object that a thread can be waiting on | 18 | /// Class that represents a Kernel object that a thread can be waiting on |
| 19 | class KSynchronizationObject : public Object { | 19 | class KSynchronizationObject : public Object { |
| 20 | public: | 20 | public: |
| 21 | struct ThreadListNode { | 21 | struct ThreadListNode { |
| 22 | ThreadListNode* next{}; | 22 | ThreadListNode* next{}; |
| 23 | Thread* thread{}; | 23 | KThread* thread{}; |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | [[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index, | 26 | [[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index, |
| @@ -29,10 +29,11 @@ public: | |||
| 29 | 29 | ||
| 30 | [[nodiscard]] virtual bool IsSignaled() const = 0; | 30 | [[nodiscard]] virtual bool IsSignaled() const = 0; |
| 31 | 31 | ||
| 32 | [[nodiscard]] std::vector<Thread*> GetWaitingThreadsForDebugging() const; | 32 | [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; |
| 33 | 33 | ||
| 34 | protected: | 34 | protected: |
| 35 | explicit KSynchronizationObject(KernelCore& kernel); | 35 | explicit KSynchronizationObject(KernelCore& kernel); |
| 36 | explicit KSynchronizationObject(KernelCore& kernel, std::string&& name); | ||
| 36 | virtual ~KSynchronizationObject(); | 37 | virtual ~KSynchronizationObject(); |
| 37 | 38 | ||
| 38 | void NotifyAvailable(ResultCode result); | 39 | void NotifyAvailable(ResultCode result); |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp new file mode 100644 index 000000000..b59259c4f --- /dev/null +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -0,0 +1,1050 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cinttypes> | ||
| 7 | #include <optional> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/bit_util.h" | ||
| 12 | #include "common/common_funcs.h" | ||
| 13 | #include "common/common_types.h" | ||
| 14 | #include "common/fiber.h" | ||
| 15 | #include "common/logging/log.h" | ||
| 16 | #include "common/scope_exit.h" | ||
| 17 | #include "common/thread_queue_list.h" | ||
| 18 | #include "core/core.h" | ||
| 19 | #include "core/cpu_manager.h" | ||
| 20 | #include "core/hardware_properties.h" | ||
| 21 | #include "core/hle/kernel/errors.h" | ||
| 22 | #include "core/hle/kernel/handle_table.h" | ||
| 23 | #include "core/hle/kernel/k_condition_variable.h" | ||
| 24 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 25 | #include "core/hle/kernel/k_scheduler.h" | ||
| 26 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 27 | #include "core/hle/kernel/k_thread.h" | ||
| 28 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 29 | #include "core/hle/kernel/kernel.h" | ||
| 30 | #include "core/hle/kernel/memory/memory_layout.h" | ||
| 31 | #include "core/hle/kernel/object.h" | ||
| 32 | #include "core/hle/kernel/process.h" | ||
| 33 | #include "core/hle/kernel/svc_results.h" | ||
| 34 | #include "core/hle/kernel/time_manager.h" | ||
| 35 | #include "core/hle/result.h" | ||
| 36 | #include "core/memory.h" | ||
| 37 | |||
| 38 | #ifdef ARCHITECTURE_x86_64 | ||
| 39 | #include "core/arm/dynarmic/arm_dynarmic_32.h" | ||
| 40 | #include "core/arm/dynarmic/arm_dynarmic_64.h" | ||
| 41 | #endif | ||
| 42 | |||
| 43 | namespace { | ||
| 44 | static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, | ||
| 45 | u32 entry_point, u32 arg) { | ||
| 46 | context = {}; | ||
| 47 | context.cpu_registers[0] = arg; | ||
| 48 | context.cpu_registers[15] = entry_point; | ||
| 49 | context.cpu_registers[13] = stack_top; | ||
| 50 | } | ||
| 51 | |||
| 52 | static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, VAddr stack_top, | ||
| 53 | VAddr entry_point, u64 arg) { | ||
| 54 | context = {}; | ||
| 55 | context.cpu_registers[0] = arg; | ||
| 56 | context.pc = entry_point; | ||
| 57 | context.sp = stack_top; | ||
| 58 | // TODO(merry): Perform a hardware test to determine the below value. | ||
| 59 | context.fpcr = 0; | ||
| 60 | } | ||
| 61 | } // namespace | ||
| 62 | |||
| 63 | namespace Kernel { | ||
| 64 | |||
| 65 | KThread::KThread(KernelCore& kernel) | ||
| 66 | : KSynchronizationObject{kernel}, activity_pause_lock{kernel} {} | ||
| 67 | KThread::~KThread() = default; | ||
| 68 | |||
| 69 | ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, | ||
| 70 | s32 virt_core, Process* owner, ThreadType type) { | ||
| 71 | // Assert parameters are valid. | ||
| 72 | ASSERT((type == ThreadType::Main) || | ||
| 73 | (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); | ||
| 74 | ASSERT((owner != nullptr) || (type != ThreadType::User)); | ||
| 75 | ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>())); | ||
| 76 | |||
| 77 | // Convert the virtual core to a physical core. | ||
| 78 | const s32 phys_core = Core::Hardware::VirtualToPhysicalCoreMap[virt_core]; | ||
| 79 | ASSERT(0 <= phys_core && phys_core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||
| 80 | |||
| 81 | // First, clear the TLS address. | ||
| 82 | tls_address = {}; | ||
| 83 | |||
| 84 | // Next, assert things based on the type. | ||
| 85 | switch (type) { | ||
| 86 | case ThreadType::Main: | ||
| 87 | ASSERT(arg == 0); | ||
| 88 | [[fallthrough]]; | ||
| 89 | case ThreadType::HighPriority: | ||
| 90 | [[fallthrough]]; | ||
| 91 | case ThreadType::User: | ||
| 92 | ASSERT(((owner == nullptr) || | ||
| 93 | (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask())); | ||
| 94 | ASSERT(((owner == nullptr) || | ||
| 95 | (owner->GetPriorityMask() | (1ULL << prio)) == owner->GetPriorityMask())); | ||
| 96 | break; | ||
| 97 | case ThreadType::Kernel: | ||
| 98 | UNIMPLEMENTED(); | ||
| 99 | break; | ||
| 100 | default: | ||
| 101 | UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | thread_type_for_debugging = type; | ||
| 105 | |||
| 106 | // Set the ideal core ID and affinity mask. | ||
| 107 | virtual_ideal_core_id = virt_core; | ||
| 108 | physical_ideal_core_id = phys_core; | ||
| 109 | virtual_affinity_mask = 1ULL << virt_core; | ||
| 110 | physical_affinity_mask.SetAffinity(phys_core, true); | ||
| 111 | |||
| 112 | // Set the thread state. | ||
| 113 | thread_state = (type == ThreadType::Main) ? ThreadState::Runnable : ThreadState::Initialized; | ||
| 114 | |||
| 115 | // Set TLS address. | ||
| 116 | tls_address = 0; | ||
| 117 | |||
| 118 | // Set parent and condvar tree. | ||
| 119 | parent = nullptr; | ||
| 120 | condvar_tree = nullptr; | ||
| 121 | |||
| 122 | // Set sync booleans. | ||
| 123 | signaled = false; | ||
| 124 | termination_requested = false; | ||
| 125 | wait_cancelled = false; | ||
| 126 | cancellable = false; | ||
| 127 | |||
| 128 | // Set core ID and wait result. | ||
| 129 | core_id = phys_core; | ||
| 130 | wait_result = Svc::ResultNoSynchronizationObject; | ||
| 131 | |||
| 132 | // Set priorities. | ||
| 133 | priority = prio; | ||
| 134 | base_priority = prio; | ||
| 135 | |||
| 136 | // Set sync object and waiting lock to null. | ||
| 137 | synced_object = nullptr; | ||
| 138 | |||
| 139 | // Initialize sleeping queue. | ||
| 140 | sleeping_queue = nullptr; | ||
| 141 | |||
| 142 | // Set suspend flags. | ||
| 143 | suspend_request_flags = 0; | ||
| 144 | suspend_allowed_flags = static_cast<u32>(ThreadState::SuspendFlagMask); | ||
| 145 | |||
| 146 | // We're neither debug attached, nor are we nesting our priority inheritance. | ||
| 147 | debug_attached = false; | ||
| 148 | priority_inheritance_count = 0; | ||
| 149 | |||
| 150 | // We haven't been scheduled, and we have done no light IPC. | ||
| 151 | schedule_count = -1; | ||
| 152 | last_scheduled_tick = 0; | ||
| 153 | light_ipc_data = nullptr; | ||
| 154 | |||
| 155 | // We're not waiting for a lock, and we haven't disabled migration. | ||
| 156 | lock_owner = nullptr; | ||
| 157 | num_core_migration_disables = 0; | ||
| 158 | |||
| 159 | // We have no waiters, but we do have an entrypoint. | ||
| 160 | num_kernel_waiters = 0; | ||
| 161 | |||
| 162 | // Set our current core id. | ||
| 163 | current_core_id = phys_core; | ||
| 164 | |||
| 165 | // We haven't released our resource limit hint, and we've spent no time on the cpu. | ||
| 166 | resource_limit_release_hint = false; | ||
| 167 | cpu_time = 0; | ||
| 168 | |||
| 169 | // Clear our stack parameters. | ||
| 170 | std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0, | ||
| 171 | sizeof(StackParameters)); | ||
| 172 | |||
| 173 | // Setup the TLS, if needed. | ||
| 174 | if (type == ThreadType::User) { | ||
| 175 | tls_address = owner->CreateTLSRegion(); | ||
| 176 | } | ||
| 177 | |||
| 178 | // Set parent, if relevant. | ||
| 179 | if (owner != nullptr) { | ||
| 180 | parent = owner; | ||
| 181 | parent->IncrementThreadCount(); | ||
| 182 | } | ||
| 183 | |||
| 184 | // Initialize thread context. | ||
| 185 | ResetThreadContext64(thread_context_64, user_stack_top, func, arg); | ||
| 186 | ResetThreadContext32(thread_context_32, static_cast<u32>(user_stack_top), | ||
| 187 | static_cast<u32>(func), static_cast<u32>(arg)); | ||
| 188 | |||
| 189 | // Setup the stack parameters. | ||
| 190 | StackParameters& sp = GetStackParameters(); | ||
| 191 | sp.cur_thread = this; | ||
| 192 | sp.disable_count = 1; | ||
| 193 | SetInExceptionHandler(); | ||
| 194 | |||
| 195 | // Set thread ID. | ||
| 196 | thread_id = kernel.CreateNewThreadID(); | ||
| 197 | |||
| 198 | // We initialized! | ||
| 199 | initialized = true; | ||
| 200 | |||
| 201 | // Register ourselves with our parent process. | ||
| 202 | if (parent != nullptr) { | ||
| 203 | parent->RegisterThread(this); | ||
| 204 | if (parent->IsSuspended()) { | ||
| 205 | RequestSuspend(SuspendType::Process); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | return RESULT_SUCCESS; | ||
| 210 | } | ||
| 211 | |||
| 212 | ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, | ||
| 213 | VAddr user_stack_top, s32 prio, s32 core, Process* owner, | ||
| 214 | ThreadType type) { | ||
| 215 | // Initialize the thread. | ||
| 216 | R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); | ||
| 217 | |||
| 218 | return RESULT_SUCCESS; | ||
| 219 | } | ||
| 220 | |||
| 221 | void KThread::Finalize() { | ||
| 222 | // If the thread has an owner process, unregister it. | ||
| 223 | if (parent != nullptr) { | ||
| 224 | parent->UnregisterThread(this); | ||
| 225 | } | ||
| 226 | |||
| 227 | // If the thread has a local region, delete it. | ||
| 228 | if (tls_address != 0) { | ||
| 229 | parent->FreeTLSRegion(tls_address); | ||
| 230 | } | ||
| 231 | |||
| 232 | // Release any waiters. | ||
| 233 | { | ||
| 234 | ASSERT(lock_owner == nullptr); | ||
| 235 | KScopedSchedulerLock sl{kernel}; | ||
| 236 | |||
| 237 | auto it = waiter_list.begin(); | ||
| 238 | while (it != waiter_list.end()) { | ||
| 239 | // The thread shouldn't be a kernel waiter. | ||
| 240 | it->SetLockOwner(nullptr); | ||
| 241 | it->SetSyncedObject(nullptr, Svc::ResultInvalidState); | ||
| 242 | it->Wakeup(); | ||
| 243 | it = waiter_list.erase(it); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | // Decrement the parent process's thread count. | ||
| 248 | if (parent != nullptr) { | ||
| 249 | parent->DecrementThreadCount(); | ||
| 250 | parent->GetResourceLimit()->Release(LimitableResource::Threads, 1); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | bool KThread::IsSignaled() const { | ||
| 255 | return signaled; | ||
| 256 | } | ||
| 257 | |||
| 258 | void KThread::Wakeup() { | ||
| 259 | KScopedSchedulerLock sl{kernel}; | ||
| 260 | |||
| 261 | if (GetState() == ThreadState::Waiting) { | ||
| 262 | if (sleeping_queue != nullptr) { | ||
| 263 | sleeping_queue->WakeupThread(this); | ||
| 264 | } else { | ||
| 265 | SetState(ThreadState::Runnable); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | void KThread::StartTermination() { | ||
| 271 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 272 | |||
| 273 | // Release user exception and unpin, if relevant. | ||
| 274 | if (parent != nullptr) { | ||
| 275 | parent->ReleaseUserException(this); | ||
| 276 | if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) { | ||
| 277 | parent->UnpinCurrentThread(); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | // Set state to terminated. | ||
| 282 | SetState(ThreadState::Terminated); | ||
| 283 | |||
| 284 | // Clear the thread's status as running in parent. | ||
| 285 | if (parent != nullptr) { | ||
| 286 | parent->ClearRunningThread(this); | ||
| 287 | } | ||
| 288 | |||
| 289 | // Signal. | ||
| 290 | signaled = true; | ||
| 291 | NotifyAvailable(); | ||
| 292 | |||
| 293 | // Clear previous thread in KScheduler. | ||
| 294 | KScheduler::ClearPreviousThread(kernel, this); | ||
| 295 | |||
| 296 | // Register terminated dpc flag. | ||
| 297 | RegisterDpc(DpcFlag::Terminated); | ||
| 298 | } | ||
| 299 | |||
| 300 | void KThread::Pin() { | ||
| 301 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 302 | |||
| 303 | // Set ourselves as pinned. | ||
| 304 | GetStackParameters().is_pinned = true; | ||
| 305 | |||
| 306 | // Disable core migration. | ||
| 307 | ASSERT(num_core_migration_disables == 0); | ||
| 308 | { | ||
| 309 | ++num_core_migration_disables; | ||
| 310 | |||
| 311 | // Save our ideal state to restore when we're unpinned. | ||
| 312 | original_physical_ideal_core_id = physical_ideal_core_id; | ||
| 313 | original_physical_affinity_mask = physical_affinity_mask; | ||
| 314 | |||
| 315 | // Bind ourselves to this core. | ||
| 316 | const s32 active_core = GetActiveCore(); | ||
| 317 | const s32 current_core = GetCurrentCoreId(kernel); | ||
| 318 | |||
| 319 | SetActiveCore(current_core); | ||
| 320 | physical_ideal_core_id = current_core; | ||
| 321 | physical_affinity_mask.SetAffinityMask(1ULL << current_core); | ||
| 322 | |||
| 323 | if (active_core != current_core || physical_affinity_mask.GetAffinityMask() != | ||
| 324 | original_physical_affinity_mask.GetAffinityMask()) { | ||
| 325 | KScheduler::OnThreadAffinityMaskChanged(kernel, this, original_physical_affinity_mask, | ||
| 326 | active_core); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | // Disallow performing thread suspension. | ||
| 331 | { | ||
| 332 | // Update our allow flags. | ||
| 333 | suspend_allowed_flags &= ~(1 << (static_cast<u32>(SuspendType::Thread) + | ||
| 334 | static_cast<u32>(ThreadState::SuspendShift))); | ||
| 335 | |||
| 336 | // Update our state. | ||
| 337 | const ThreadState old_state = thread_state; | ||
| 338 | thread_state = static_cast<ThreadState>(GetSuspendFlags() | | ||
| 339 | static_cast<u32>(old_state & ThreadState::Mask)); | ||
| 340 | if (thread_state != old_state) { | ||
| 341 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | // TODO(bunnei): Update our SVC access permissions. | ||
| 346 | ASSERT(parent != nullptr); | ||
| 347 | } | ||
| 348 | |||
| 349 | void KThread::Unpin() { | ||
| 350 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 351 | |||
| 352 | // Set ourselves as unpinned. | ||
| 353 | GetStackParameters().is_pinned = false; | ||
| 354 | |||
| 355 | // Enable core migration. | ||
| 356 | ASSERT(num_core_migration_disables == 1); | ||
| 357 | { | ||
| 358 | num_core_migration_disables--; | ||
| 359 | |||
| 360 | // Restore our original state. | ||
| 361 | const KAffinityMask old_mask = physical_affinity_mask; | ||
| 362 | |||
| 363 | physical_ideal_core_id = original_physical_ideal_core_id; | ||
| 364 | physical_affinity_mask = original_physical_affinity_mask; | ||
| 365 | |||
| 366 | if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { | ||
| 367 | const s32 active_core = GetActiveCore(); | ||
| 368 | |||
| 369 | if (!physical_affinity_mask.GetAffinity(active_core)) { | ||
| 370 | if (physical_ideal_core_id >= 0) { | ||
| 371 | SetActiveCore(physical_ideal_core_id); | ||
| 372 | } else { | ||
| 373 | SetActiveCore(static_cast<s32>( | ||
| 374 | Common::BitSize<u64>() - 1 - | ||
| 375 | std::countl_zero(physical_affinity_mask.GetAffinityMask()))); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_mask, active_core); | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | // Allow performing thread suspension (if termination hasn't been requested). | ||
| 383 | { | ||
| 384 | // Update our allow flags. | ||
| 385 | if (!IsTerminationRequested()) { | ||
| 386 | suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) + | ||
| 387 | static_cast<u32>(ThreadState::SuspendShift))); | ||
| 388 | } | ||
| 389 | |||
| 390 | // Update our state. | ||
| 391 | const ThreadState old_state = thread_state; | ||
| 392 | thread_state = static_cast<ThreadState>(GetSuspendFlags() | | ||
| 393 | static_cast<u32>(old_state & ThreadState::Mask)); | ||
| 394 | if (thread_state != old_state) { | ||
| 395 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | // TODO(bunnei): Update our SVC access permissions. | ||
| 400 | ASSERT(parent != nullptr); | ||
| 401 | |||
| 402 | // Resume any threads that began waiting on us while we were pinned. | ||
| 403 | for (auto it = pinned_waiter_list.begin(); it != pinned_waiter_list.end(); ++it) { | ||
| 404 | if (it->GetState() == ThreadState::Waiting) { | ||
| 405 | it->SetState(ThreadState::Runnable); | ||
| 406 | } | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | ResultCode KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) { | ||
| 411 | KScopedSchedulerLock sl{kernel}; | ||
| 412 | |||
| 413 | // Get the virtual mask. | ||
| 414 | *out_ideal_core = virtual_ideal_core_id; | ||
| 415 | *out_affinity_mask = virtual_affinity_mask; | ||
| 416 | |||
| 417 | return RESULT_SUCCESS; | ||
| 418 | } | ||
| 419 | |||
| 420 | ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask) { | ||
| 421 | KScopedSchedulerLock sl{kernel}; | ||
| 422 | ASSERT(num_core_migration_disables >= 0); | ||
| 423 | |||
| 424 | // Select between core mask and original core mask. | ||
| 425 | if (num_core_migration_disables == 0) { | ||
| 426 | *out_ideal_core = physical_ideal_core_id; | ||
| 427 | *out_affinity_mask = physical_affinity_mask.GetAffinityMask(); | ||
| 428 | } else { | ||
| 429 | *out_ideal_core = original_physical_ideal_core_id; | ||
| 430 | *out_affinity_mask = original_physical_affinity_mask.GetAffinityMask(); | ||
| 431 | } | ||
| 432 | |||
| 433 | return RESULT_SUCCESS; | ||
| 434 | } | ||
| 435 | |||
| 436 | ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) { | ||
| 437 | ASSERT(parent != nullptr); | ||
| 438 | ASSERT(v_affinity_mask != 0); | ||
| 439 | KScopedLightLock lk{activity_pause_lock}; | ||
| 440 | |||
| 441 | // Set the core mask. | ||
| 442 | u64 p_affinity_mask = 0; | ||
| 443 | { | ||
| 444 | KScopedSchedulerLock sl{kernel}; | ||
| 445 | ASSERT(num_core_migration_disables >= 0); | ||
| 446 | |||
| 447 | // If the core id is no-update magic, preserve the ideal core id. | ||
| 448 | if (core_id == Svc::IdealCoreNoUpdate) { | ||
| 449 | core_id = virtual_ideal_core_id; | ||
| 450 | R_UNLESS(((1ULL << core_id) & v_affinity_mask) != 0, Svc::ResultInvalidCombination); | ||
| 451 | } | ||
| 452 | |||
| 453 | // Set the virtual core/affinity mask. | ||
| 454 | virtual_ideal_core_id = core_id; | ||
| 455 | virtual_affinity_mask = v_affinity_mask; | ||
| 456 | |||
| 457 | // Translate the virtual core to a physical core. | ||
| 458 | if (core_id >= 0) { | ||
| 459 | core_id = Core::Hardware::VirtualToPhysicalCoreMap[core_id]; | ||
| 460 | } | ||
| 461 | |||
| 462 | // Translate the virtual affinity mask to a physical one. | ||
| 463 | while (v_affinity_mask != 0) { | ||
| 464 | const u64 next = std::countr_zero(v_affinity_mask); | ||
| 465 | v_affinity_mask &= ~(1ULL << next); | ||
| 466 | p_affinity_mask |= (1ULL << Core::Hardware::VirtualToPhysicalCoreMap[next]); | ||
| 467 | } | ||
| 468 | |||
| 469 | // If we haven't disabled migration, perform an affinity change. | ||
| 470 | if (num_core_migration_disables == 0) { | ||
| 471 | const KAffinityMask old_mask = physical_affinity_mask; | ||
| 472 | |||
| 473 | // Set our new ideals. | ||
| 474 | physical_ideal_core_id = core_id; | ||
| 475 | physical_affinity_mask.SetAffinityMask(p_affinity_mask); | ||
| 476 | |||
| 477 | if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { | ||
| 478 | const s32 active_core = GetActiveCore(); | ||
| 479 | |||
| 480 | if (active_core >= 0 && !physical_affinity_mask.GetAffinity(active_core)) { | ||
| 481 | const s32 new_core = static_cast<s32>( | ||
| 482 | physical_ideal_core_id >= 0 | ||
| 483 | ? physical_ideal_core_id | ||
| 484 | : Common::BitSize<u64>() - 1 - | ||
| 485 | std::countl_zero(physical_affinity_mask.GetAffinityMask())); | ||
| 486 | SetActiveCore(new_core); | ||
| 487 | } | ||
| 488 | KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_mask, active_core); | ||
| 489 | } | ||
| 490 | } else { | ||
| 491 | // Otherwise, we edit the original affinity for restoration later. | ||
| 492 | original_physical_ideal_core_id = core_id; | ||
| 493 | original_physical_affinity_mask.SetAffinityMask(p_affinity_mask); | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | // Update the pinned waiter list. | ||
| 498 | { | ||
| 499 | bool retry_update{}; | ||
| 500 | bool thread_is_pinned{}; | ||
| 501 | do { | ||
| 502 | // Lock the scheduler. | ||
| 503 | KScopedSchedulerLock sl{kernel}; | ||
| 504 | |||
| 505 | // Don't do any further management if our termination has been requested. | ||
| 506 | R_SUCCEED_IF(IsTerminationRequested()); | ||
| 507 | |||
| 508 | // By default, we won't need to retry. | ||
| 509 | retry_update = false; | ||
| 510 | |||
| 511 | // Check if the thread is currently running. | ||
| 512 | bool thread_is_current{}; | ||
| 513 | s32 thread_core; | ||
| 514 | for (thread_core = 0; thread_core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); | ||
| 515 | ++thread_core) { | ||
| 516 | if (kernel.Scheduler(thread_core).GetCurrentThread() == this) { | ||
| 517 | thread_is_current = true; | ||
| 518 | break; | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | // If the thread is currently running, check whether it's no longer allowed under the | ||
| 523 | // new mask. | ||
| 524 | if (thread_is_current && ((1ULL << thread_core) & p_affinity_mask) == 0) { | ||
| 525 | // If the thread is pinned, we want to wait until it's not pinned. | ||
| 526 | if (GetStackParameters().is_pinned) { | ||
| 527 | // Verify that the current thread isn't terminating. | ||
| 528 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), | ||
| 529 | Svc::ResultTerminationRequested); | ||
| 530 | |||
| 531 | // Note that the thread was pinned. | ||
| 532 | thread_is_pinned = true; | ||
| 533 | |||
| 534 | // Wait until the thread isn't pinned any more. | ||
| 535 | pinned_waiter_list.push_back(GetCurrentThread(kernel)); | ||
| 536 | GetCurrentThread(kernel).SetState(ThreadState::Waiting); | ||
| 537 | } else { | ||
| 538 | // If the thread isn't pinned, release the scheduler lock and retry until it's | ||
| 539 | // not current. | ||
| 540 | retry_update = true; | ||
| 541 | } | ||
| 542 | } | ||
| 543 | } while (retry_update); | ||
| 544 | |||
| 545 | // If the thread was pinned, it no longer is, and we should remove the current thread from | ||
| 546 | // our waiter list. | ||
| 547 | if (thread_is_pinned) { | ||
| 548 | // Lock the scheduler. | ||
| 549 | KScopedSchedulerLock sl{kernel}; | ||
| 550 | |||
| 551 | // Remove from the list. | ||
| 552 | pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); | ||
| 553 | } | ||
| 554 | } | ||
| 555 | |||
| 556 | return RESULT_SUCCESS; | ||
| 557 | } | ||
| 558 | |||
| 559 | void KThread::SetBasePriority(s32 value) { | ||
| 560 | ASSERT(Svc::HighestThreadPriority <= value && value <= Svc::LowestThreadPriority); | ||
| 561 | |||
| 562 | KScopedSchedulerLock sl{kernel}; | ||
| 563 | |||
| 564 | // Change our base priority. | ||
| 565 | base_priority = value; | ||
| 566 | |||
| 567 | // Perform a priority restoration. | ||
| 568 | RestorePriority(kernel, this); | ||
| 569 | } | ||
| 570 | |||
| 571 | void KThread::RequestSuspend(SuspendType type) { | ||
| 572 | KScopedSchedulerLock sl{kernel}; | ||
| 573 | |||
| 574 | // Note the request in our flags. | ||
| 575 | suspend_request_flags |= | ||
| 576 | (1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type))); | ||
| 577 | |||
| 578 | // Try to perform the suspend. | ||
| 579 | TrySuspend(); | ||
| 580 | } | ||
| 581 | |||
| 582 | void KThread::Resume(SuspendType type) { | ||
| 583 | KScopedSchedulerLock sl{kernel}; | ||
| 584 | |||
| 585 | // Clear the request in our flags. | ||
| 586 | suspend_request_flags &= | ||
| 587 | ~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type))); | ||
| 588 | |||
| 589 | // Update our state. | ||
| 590 | const ThreadState old_state = thread_state; | ||
| 591 | thread_state = static_cast<ThreadState>(GetSuspendFlags() | | ||
| 592 | static_cast<u32>(old_state & ThreadState::Mask)); | ||
| 593 | if (thread_state != old_state) { | ||
| 594 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 598 | void KThread::WaitCancel() { | ||
| 599 | KScopedSchedulerLock sl{kernel}; | ||
| 600 | |||
| 601 | // Check if we're waiting and cancellable. | ||
| 602 | if (GetState() == ThreadState::Waiting && cancellable) { | ||
| 603 | if (sleeping_queue != nullptr) { | ||
| 604 | sleeping_queue->WakeupThread(this); | ||
| 605 | wait_cancelled = true; | ||
| 606 | } else { | ||
| 607 | SetSyncedObject(nullptr, Svc::ResultCancelled); | ||
| 608 | SetState(ThreadState::Runnable); | ||
| 609 | wait_cancelled = false; | ||
| 610 | } | ||
| 611 | } else { | ||
| 612 | // Otherwise, note that we cancelled a wait. | ||
| 613 | wait_cancelled = true; | ||
| 614 | } | ||
| 615 | } | ||
| 616 | |||
| 617 | void KThread::TrySuspend() { | ||
| 618 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 619 | ASSERT(IsSuspendRequested()); | ||
| 620 | |||
| 621 | // Ensure that we have no waiters. | ||
| 622 | if (GetNumKernelWaiters() > 0) { | ||
| 623 | return; | ||
| 624 | } | ||
| 625 | ASSERT(GetNumKernelWaiters() == 0); | ||
| 626 | |||
| 627 | // Perform the suspend. | ||
| 628 | Suspend(); | ||
| 629 | } | ||
| 630 | |||
| 631 | void KThread::Suspend() { | ||
| 632 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 633 | ASSERT(IsSuspendRequested()); | ||
| 634 | |||
| 635 | // Set our suspend flags in state. | ||
| 636 | const auto old_state = thread_state; | ||
| 637 | thread_state = static_cast<ThreadState>(GetSuspendFlags()) | (old_state & ThreadState::Mask); | ||
| 638 | |||
| 639 | // Note the state change in scheduler. | ||
| 640 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 641 | } | ||
| 642 | |||
| 643 | void KThread::Continue() { | ||
| 644 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 645 | |||
| 646 | // Clear our suspend flags in state. | ||
| 647 | const auto old_state = thread_state; | ||
| 648 | thread_state = old_state & ThreadState::Mask; | ||
| 649 | |||
| 650 | // Note the state change in scheduler. | ||
| 651 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 652 | } | ||
| 653 | |||
| 654 | ResultCode KThread::SetActivity(Svc::ThreadActivity activity) { | ||
| 655 | // Lock ourselves. | ||
| 656 | KScopedLightLock lk(activity_pause_lock); | ||
| 657 | |||
| 658 | // Set the activity. | ||
| 659 | { | ||
| 660 | // Lock the scheduler. | ||
| 661 | KScopedSchedulerLock sl{kernel}; | ||
| 662 | |||
| 663 | // Verify our state. | ||
| 664 | const auto cur_state = GetState(); | ||
| 665 | R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable), | ||
| 666 | Svc::ResultInvalidState); | ||
| 667 | |||
| 668 | // Either pause or resume. | ||
| 669 | if (activity == Svc::ThreadActivity::Paused) { | ||
| 670 | // Verify that we're not suspended. | ||
| 671 | R_UNLESS(!IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState); | ||
| 672 | |||
| 673 | // Suspend. | ||
| 674 | RequestSuspend(SuspendType::Thread); | ||
| 675 | } else { | ||
| 676 | ASSERT(activity == Svc::ThreadActivity::Runnable); | ||
| 677 | |||
| 678 | // Verify that we're suspended. | ||
| 679 | R_UNLESS(IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState); | ||
| 680 | |||
| 681 | // Resume. | ||
| 682 | Resume(SuspendType::Thread); | ||
| 683 | } | ||
| 684 | } | ||
| 685 | |||
| 686 | // If the thread is now paused, update the pinned waiter list. | ||
| 687 | if (activity == Svc::ThreadActivity::Paused) { | ||
| 688 | bool thread_is_pinned{}; | ||
| 689 | bool thread_is_current{}; | ||
| 690 | do { | ||
| 691 | // Lock the scheduler. | ||
| 692 | KScopedSchedulerLock sl{kernel}; | ||
| 693 | |||
| 694 | // Don't do any further management if our termination has been requested. | ||
| 695 | R_SUCCEED_IF(IsTerminationRequested()); | ||
| 696 | |||
| 697 | // Check whether the thread is pinned. | ||
| 698 | if (GetStackParameters().is_pinned) { | ||
| 699 | // Verify that the current thread isn't terminating. | ||
| 700 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), | ||
| 701 | Svc::ResultTerminationRequested); | ||
| 702 | |||
| 703 | // Note that the thread was pinned and not current. | ||
| 704 | thread_is_pinned = true; | ||
| 705 | thread_is_current = false; | ||
| 706 | |||
| 707 | // Wait until the thread isn't pinned any more. | ||
| 708 | pinned_waiter_list.push_back(GetCurrentThread(kernel)); | ||
| 709 | GetCurrentThread(kernel).SetState(ThreadState::Waiting); | ||
| 710 | } else { | ||
| 711 | // Check if the thread is currently running. | ||
| 712 | // If it is, we'll need to retry. | ||
| 713 | thread_is_current = false; | ||
| 714 | |||
| 715 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { | ||
| 716 | if (kernel.Scheduler(i).GetCurrentThread() == this) { | ||
| 717 | thread_is_current = true; | ||
| 718 | break; | ||
| 719 | } | ||
| 720 | } | ||
| 721 | } | ||
| 722 | } while (thread_is_current); | ||
| 723 | |||
| 724 | // If the thread was pinned, it no longer is, and we should remove the current thread from | ||
| 725 | // our waiter list. | ||
| 726 | if (thread_is_pinned) { | ||
| 727 | // Lock the scheduler. | ||
| 728 | KScopedSchedulerLock sl{kernel}; | ||
| 729 | |||
| 730 | // Remove from the list. | ||
| 731 | pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); | ||
| 732 | } | ||
| 733 | } | ||
| 734 | |||
| 735 | return RESULT_SUCCESS; | ||
| 736 | } | ||
| 737 | |||
| 738 | ResultCode KThread::GetThreadContext3(std::vector<u8>& out) { | ||
| 739 | // Lock ourselves. | ||
| 740 | KScopedLightLock lk{activity_pause_lock}; | ||
| 741 | |||
| 742 | // Get the context. | ||
| 743 | { | ||
| 744 | // Lock the scheduler. | ||
| 745 | KScopedSchedulerLock sl{kernel}; | ||
| 746 | |||
| 747 | // Verify that we're suspended. | ||
| 748 | R_UNLESS(IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState); | ||
| 749 | |||
| 750 | // If we're not terminating, get the thread's user context. | ||
| 751 | if (!IsTerminationRequested()) { | ||
| 752 | if (parent->Is64BitProcess()) { | ||
| 753 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | ||
| 754 | auto context = GetContext64(); | ||
| 755 | context.pstate &= 0xFF0FFE20; | ||
| 756 | |||
| 757 | out.resize(sizeof(context)); | ||
| 758 | std::memcpy(out.data(), &context, sizeof(context)); | ||
| 759 | } else { | ||
| 760 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | ||
| 761 | auto context = GetContext32(); | ||
| 762 | context.cpsr &= 0xFF0FFE20; | ||
| 763 | |||
| 764 | out.resize(sizeof(context)); | ||
| 765 | std::memcpy(out.data(), &context, sizeof(context)); | ||
| 766 | } | ||
| 767 | } | ||
| 768 | } | ||
| 769 | |||
| 770 | return RESULT_SUCCESS; | ||
| 771 | } | ||
| 772 | |||
| 773 | void KThread::AddWaiterImpl(KThread* thread) { | ||
| 774 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 775 | |||
| 776 | // Find the right spot to insert the waiter. | ||
| 777 | auto it = waiter_list.begin(); | ||
| 778 | while (it != waiter_list.end()) { | ||
| 779 | if (it->GetPriority() > thread->GetPriority()) { | ||
| 780 | break; | ||
| 781 | } | ||
| 782 | it++; | ||
| 783 | } | ||
| 784 | |||
| 785 | // Keep track of how many kernel waiters we have. | ||
| 786 | if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { | ||
| 787 | ASSERT((num_kernel_waiters++) >= 0); | ||
| 788 | } | ||
| 789 | |||
| 790 | // Insert the waiter. | ||
| 791 | waiter_list.insert(it, *thread); | ||
| 792 | thread->SetLockOwner(this); | ||
| 793 | } | ||
| 794 | |||
| 795 | void KThread::RemoveWaiterImpl(KThread* thread) { | ||
| 796 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 797 | |||
| 798 | // Keep track of how many kernel waiters we have. | ||
| 799 | if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { | ||
| 800 | ASSERT((num_kernel_waiters--) > 0); | ||
| 801 | } | ||
| 802 | |||
| 803 | // Remove the waiter. | ||
| 804 | waiter_list.erase(waiter_list.iterator_to(*thread)); | ||
| 805 | thread->SetLockOwner(nullptr); | ||
| 806 | } | ||
| 807 | |||
| 808 | void KThread::RestorePriority(KernelCore& kernel, KThread* thread) { | ||
| 809 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 810 | |||
| 811 | while (true) { | ||
| 812 | // We want to inherit priority where possible. | ||
| 813 | s32 new_priority = thread->GetBasePriority(); | ||
| 814 | if (thread->HasWaiters()) { | ||
| 815 | new_priority = std::min(new_priority, thread->waiter_list.front().GetPriority()); | ||
| 816 | } | ||
| 817 | |||
| 818 | // If the priority we would inherit is not different from ours, don't do anything. | ||
| 819 | if (new_priority == thread->GetPriority()) { | ||
| 820 | return; | ||
| 821 | } | ||
| 822 | |||
| 823 | // Ensure we don't violate condition variable red black tree invariants. | ||
| 824 | if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { | ||
| 825 | BeforeUpdatePriority(kernel, cv_tree, thread); | ||
| 826 | } | ||
| 827 | |||
| 828 | // Change the priority. | ||
| 829 | const s32 old_priority = thread->GetPriority(); | ||
| 830 | thread->SetPriority(new_priority); | ||
| 831 | |||
| 832 | // Restore the condition variable, if relevant. | ||
| 833 | if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { | ||
| 834 | AfterUpdatePriority(kernel, cv_tree, thread); | ||
| 835 | } | ||
| 836 | |||
| 837 | // Update the scheduler. | ||
| 838 | KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority); | ||
| 839 | |||
| 840 | // Keep the lock owner up to date. | ||
| 841 | KThread* lock_owner = thread->GetLockOwner(); | ||
| 842 | if (lock_owner == nullptr) { | ||
| 843 | return; | ||
| 844 | } | ||
| 845 | |||
| 846 | // Update the thread in the lock owner's sorted list, and continue inheriting. | ||
| 847 | lock_owner->RemoveWaiterImpl(thread); | ||
| 848 | lock_owner->AddWaiterImpl(thread); | ||
| 849 | thread = lock_owner; | ||
| 850 | } | ||
| 851 | } | ||
| 852 | |||
| 853 | void KThread::AddWaiter(KThread* thread) { | ||
| 854 | AddWaiterImpl(thread); | ||
| 855 | RestorePriority(kernel, this); | ||
| 856 | } | ||
| 857 | |||
| 858 | void KThread::RemoveWaiter(KThread* thread) { | ||
| 859 | RemoveWaiterImpl(thread); | ||
| 860 | RestorePriority(kernel, this); | ||
| 861 | } | ||
| 862 | |||
| 863 | KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { | ||
| 864 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 865 | |||
| 866 | s32 num_waiters{}; | ||
| 867 | KThread* next_lock_owner{}; | ||
| 868 | auto it = waiter_list.begin(); | ||
| 869 | while (it != waiter_list.end()) { | ||
| 870 | if (it->GetAddressKey() == key) { | ||
| 871 | KThread* thread = std::addressof(*it); | ||
| 872 | |||
| 873 | // Keep track of how many kernel waiters we have. | ||
| 874 | if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { | ||
| 875 | ASSERT((num_kernel_waiters--) > 0); | ||
| 876 | } | ||
| 877 | it = waiter_list.erase(it); | ||
| 878 | |||
| 879 | // Update the next lock owner. | ||
| 880 | if (next_lock_owner == nullptr) { | ||
| 881 | next_lock_owner = thread; | ||
| 882 | next_lock_owner->SetLockOwner(nullptr); | ||
| 883 | } else { | ||
| 884 | next_lock_owner->AddWaiterImpl(thread); | ||
| 885 | } | ||
| 886 | num_waiters++; | ||
| 887 | } else { | ||
| 888 | it++; | ||
| 889 | } | ||
| 890 | } | ||
| 891 | |||
| 892 | // Do priority updates, if we have a next owner. | ||
| 893 | if (next_lock_owner) { | ||
| 894 | RestorePriority(kernel, this); | ||
| 895 | RestorePriority(kernel, next_lock_owner); | ||
| 896 | } | ||
| 897 | |||
| 898 | // Return output. | ||
| 899 | *out_num_waiters = num_waiters; | ||
| 900 | return next_lock_owner; | ||
| 901 | } | ||
| 902 | |||
| 903 | ResultCode KThread::Run() { | ||
| 904 | while (true) { | ||
| 905 | KScopedSchedulerLock lk{kernel}; | ||
| 906 | |||
| 907 | // If either this thread or the current thread are requesting termination, note it. | ||
| 908 | R_UNLESS(!IsTerminationRequested(), Svc::ResultTerminationRequested); | ||
| 909 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), | ||
| 910 | Svc::ResultTerminationRequested); | ||
| 911 | |||
| 912 | // Ensure our thread state is correct. | ||
| 913 | R_UNLESS(GetState() == ThreadState::Initialized, Svc::ResultInvalidState); | ||
| 914 | |||
| 915 | // If the current thread has been asked to suspend, suspend it and retry. | ||
| 916 | if (GetCurrentThread(kernel).IsSuspended()) { | ||
| 917 | GetCurrentThread(kernel).Suspend(); | ||
| 918 | continue; | ||
| 919 | } | ||
| 920 | |||
| 921 | // If we're not a kernel thread and we've been asked to suspend, suspend ourselves. | ||
| 922 | if (IsUserThread() && IsSuspended()) { | ||
| 923 | Suspend(); | ||
| 924 | } | ||
| 925 | |||
| 926 | // Set our state and finish. | ||
| 927 | SetState(ThreadState::Runnable); | ||
| 928 | return RESULT_SUCCESS; | ||
| 929 | } | ||
| 930 | } | ||
| 931 | |||
| 932 | void KThread::Exit() { | ||
| 933 | ASSERT(this == GetCurrentThreadPointer(kernel)); | ||
| 934 | |||
| 935 | // Release the thread resource hint from parent. | ||
| 936 | if (parent != nullptr) { | ||
| 937 | // TODO(bunnei): Hint that the resource is about to be released. | ||
| 938 | resource_limit_release_hint = true; | ||
| 939 | } | ||
| 940 | |||
| 941 | // Perform termination. | ||
| 942 | { | ||
| 943 | KScopedSchedulerLock sl{kernel}; | ||
| 944 | |||
| 945 | // Disallow all suspension. | ||
| 946 | suspend_allowed_flags = 0; | ||
| 947 | |||
| 948 | // Start termination. | ||
| 949 | StartTermination(); | ||
| 950 | } | ||
| 951 | } | ||
| 952 | |||
| 953 | ResultCode KThread::Sleep(s64 timeout) { | ||
| 954 | ASSERT(!kernel.GlobalSchedulerContext().IsLocked()); | ||
| 955 | ASSERT(this == GetCurrentThreadPointer(kernel)); | ||
| 956 | ASSERT(timeout > 0); | ||
| 957 | |||
| 958 | { | ||
| 959 | // Setup the scheduling lock and sleep. | ||
| 960 | KScopedSchedulerLockAndSleep slp{kernel, this, timeout}; | ||
| 961 | |||
| 962 | // Check if the thread should terminate. | ||
| 963 | if (IsTerminationRequested()) { | ||
| 964 | slp.CancelSleep(); | ||
| 965 | return Svc::ResultTerminationRequested; | ||
| 966 | } | ||
| 967 | |||
| 968 | // Mark the thread as waiting. | ||
| 969 | SetState(ThreadState::Waiting); | ||
| 970 | SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); | ||
| 971 | } | ||
| 972 | |||
| 973 | // The lock/sleep is done. | ||
| 974 | |||
| 975 | // Cancel the timer. | ||
| 976 | kernel.TimeManager().UnscheduleTimeEvent(this); | ||
| 977 | |||
| 978 | return RESULT_SUCCESS; | ||
| 979 | } | ||
| 980 | |||
| 981 | void KThread::SetState(ThreadState state) { | ||
| 982 | KScopedSchedulerLock sl{kernel}; | ||
| 983 | |||
| 984 | // Clear debugging state | ||
| 985 | SetMutexWaitAddressForDebugging({}); | ||
| 986 | SetWaitReasonForDebugging({}); | ||
| 987 | |||
| 988 | const ThreadState old_state = thread_state; | ||
| 989 | thread_state = | ||
| 990 | static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); | ||
| 991 | if (thread_state != old_state) { | ||
| 992 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 993 | } | ||
| 994 | } | ||
| 995 | |||
| 996 | std::shared_ptr<Common::Fiber>& KThread::GetHostContext() { | ||
| 997 | return host_context; | ||
| 998 | } | ||
| 999 | |||
| 1000 | ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags, | ||
| 1001 | std::string name, VAddr entry_point, | ||
| 1002 | u32 priority, u64 arg, s32 processor_id, | ||
| 1003 | VAddr stack_top, Process* owner_process) { | ||
| 1004 | std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); | ||
| 1005 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | ||
| 1006 | return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, | ||
| 1007 | owner_process, std::move(init_func), init_func_parameter); | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags, | ||
| 1011 | std::string name, VAddr entry_point, | ||
| 1012 | u32 priority, u64 arg, s32 processor_id, | ||
| 1013 | VAddr stack_top, Process* owner_process, | ||
| 1014 | std::function<void(void*)>&& thread_start_func, | ||
| 1015 | void* thread_start_parameter) { | ||
| 1016 | auto& kernel = system.Kernel(); | ||
| 1017 | |||
| 1018 | std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel); | ||
| 1019 | |||
| 1020 | if (const auto result = | ||
| 1021 | thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority, | ||
| 1022 | processor_id, owner_process, type_flags); | ||
| 1023 | result.IsError()) { | ||
| 1024 | return result; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | thread->name = name; | ||
| 1028 | |||
| 1029 | auto& scheduler = kernel.GlobalSchedulerContext(); | ||
| 1030 | scheduler.AddThread(thread); | ||
| 1031 | |||
| 1032 | thread->host_context = | ||
| 1033 | std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter); | ||
| 1034 | |||
| 1035 | return MakeResult<std::shared_ptr<KThread>>(std::move(thread)); | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | KThread* GetCurrentThreadPointer(KernelCore& kernel) { | ||
| 1039 | return kernel.GetCurrentEmuThread(); | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | KThread& GetCurrentThread(KernelCore& kernel) { | ||
| 1043 | return *GetCurrentThreadPointer(kernel); | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | s32 GetCurrentCoreId(KernelCore& kernel) { | ||
| 1047 | return GetCurrentThread(kernel).GetCurrentCore(); | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h new file mode 100644 index 000000000..c8ac656a4 --- /dev/null +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -0,0 +1,768 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <span> | ||
| 9 | #include <string> | ||
| 10 | #include <utility> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | #include <boost/intrusive/list.hpp> | ||
| 14 | |||
| 15 | #include "common/common_types.h" | ||
| 16 | #include "common/intrusive_red_black_tree.h" | ||
| 17 | #include "common/spin_lock.h" | ||
| 18 | #include "core/arm/arm_interface.h" | ||
| 19 | #include "core/hle/kernel/k_affinity_mask.h" | ||
| 20 | #include "core/hle/kernel/k_light_lock.h" | ||
| 21 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 22 | #include "core/hle/kernel/object.h" | ||
| 23 | #include "core/hle/kernel/svc_common.h" | ||
| 24 | #include "core/hle/kernel/svc_types.h" | ||
| 25 | #include "core/hle/result.h" | ||
| 26 | |||
| 27 | namespace Common { | ||
| 28 | class Fiber; | ||
| 29 | } | ||
| 30 | |||
| 31 | namespace Core { | ||
| 32 | class ARM_Interface; | ||
| 33 | class System; | ||
| 34 | } // namespace Core | ||
| 35 | |||
| 36 | namespace Kernel { | ||
| 37 | |||
| 38 | class GlobalSchedulerContext; | ||
| 39 | class KernelCore; | ||
| 40 | class Process; | ||
| 41 | class KScheduler; | ||
| 42 | class KThreadQueue; | ||
| 43 | |||
| 44 | using KThreadFunction = VAddr; | ||
| 45 | |||
| 46 | enum class ThreadType : u32 { | ||
| 47 | Main = 0, | ||
| 48 | Kernel = 1, | ||
| 49 | HighPriority = 2, | ||
| 50 | User = 3, | ||
| 51 | }; | ||
| 52 | DECLARE_ENUM_FLAG_OPERATORS(ThreadType); | ||
| 53 | |||
| 54 | enum class SuspendType : u32 { | ||
| 55 | Process = 0, | ||
| 56 | Thread = 1, | ||
| 57 | Debug = 2, | ||
| 58 | Backtrace = 3, | ||
| 59 | Init = 4, | ||
| 60 | |||
| 61 | Count, | ||
| 62 | }; | ||
| 63 | |||
| 64 | enum class ThreadState : u16 { | ||
| 65 | Initialized = 0, | ||
| 66 | Waiting = 1, | ||
| 67 | Runnable = 2, | ||
| 68 | Terminated = 3, | ||
| 69 | |||
| 70 | SuspendShift = 4, | ||
| 71 | Mask = (1 << SuspendShift) - 1, | ||
| 72 | |||
| 73 | ProcessSuspended = (1 << (0 + SuspendShift)), | ||
| 74 | ThreadSuspended = (1 << (1 + SuspendShift)), | ||
| 75 | DebugSuspended = (1 << (2 + SuspendShift)), | ||
| 76 | BacktraceSuspended = (1 << (3 + SuspendShift)), | ||
| 77 | InitSuspended = (1 << (4 + SuspendShift)), | ||
| 78 | |||
| 79 | SuspendFlagMask = ((1 << 5) - 1) << SuspendShift, | ||
| 80 | }; | ||
| 81 | DECLARE_ENUM_FLAG_OPERATORS(ThreadState); | ||
| 82 | |||
| 83 | enum class DpcFlag : u32 { | ||
| 84 | Terminating = (1 << 0), | ||
| 85 | Terminated = (1 << 1), | ||
| 86 | }; | ||
| 87 | |||
| 88 | enum class ThreadWaitReasonForDebugging : u32 { | ||
| 89 | None, ///< Thread is not waiting | ||
| 90 | Sleep, ///< Thread is waiting due to a SleepThread SVC | ||
| 91 | IPC, ///< Thread is waiting for the reply from an IPC request | ||
| 92 | Synchronization, ///< Thread is waiting due to a WaitSynchronization SVC | ||
| 93 | ConditionVar, ///< Thread is waiting due to a WaitProcessWideKey SVC | ||
| 94 | Arbitration, ///< Thread is waiting due to a SignalToAddress/WaitForAddress SVC | ||
| 95 | Suspended, ///< Thread is waiting due to process suspension | ||
| 96 | }; | ||
| 97 | |||
| 98 | [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); | ||
| 99 | [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); | ||
| 100 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); | ||
| 101 | |||
| 102 | class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { | ||
| 103 | friend class KScheduler; | ||
| 104 | friend class Process; | ||
| 105 | |||
| 106 | public: | ||
| 107 | static constexpr s32 DefaultThreadPriority = 44; | ||
| 108 | static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; | ||
| 109 | |||
| 110 | explicit KThread(KernelCore& kernel); | ||
| 111 | ~KThread() override; | ||
| 112 | |||
| 113 | public: | ||
| 114 | using ThreadContext32 = Core::ARM_Interface::ThreadContext32; | ||
| 115 | using ThreadContext64 = Core::ARM_Interface::ThreadContext64; | ||
| 116 | using WaiterList = boost::intrusive::list<KThread>; | ||
| 117 | |||
| 118 | /** | ||
| 119 | * Creates and returns a new thread. The new thread is immediately scheduled | ||
| 120 | * @param system The instance of the whole system | ||
| 121 | * @param name The friendly name desired for the thread | ||
| 122 | * @param entry_point The address at which the thread should start execution | ||
| 123 | * @param priority The thread's priority | ||
| 124 | * @param arg User data to pass to the thread | ||
| 125 | * @param processor_id The ID(s) of the processors on which the thread is desired to be run | ||
| 126 | * @param stack_top The address of the thread's stack top | ||
| 127 | * @param owner_process The parent process for the thread, if null, it's a kernel thread | ||
| 128 | * @return A shared pointer to the newly created thread | ||
| 129 | */ | ||
| 130 | [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create( | ||
| 131 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, | ||
| 132 | u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); | ||
| 133 | |||
| 134 | /** | ||
| 135 | * Creates and returns a new thread. The new thread is immediately scheduled | ||
| 136 | * @param system The instance of the whole system | ||
| 137 | * @param name The friendly name desired for the thread | ||
| 138 | * @param entry_point The address at which the thread should start execution | ||
| 139 | * @param priority The thread's priority | ||
| 140 | * @param arg User data to pass to the thread | ||
| 141 | * @param processor_id The ID(s) of the processors on which the thread is desired to be run | ||
| 142 | * @param stack_top The address of the thread's stack top | ||
| 143 | * @param owner_process The parent process for the thread, if null, it's a kernel thread | ||
| 144 | * @param thread_start_func The function where the host context will start. | ||
| 145 | * @param thread_start_parameter The parameter which will passed to host context on init | ||
| 146 | * @return A shared pointer to the newly created thread | ||
| 147 | */ | ||
| 148 | [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create( | ||
| 149 | Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, | ||
| 150 | u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, | ||
| 151 | std::function<void(void*)>&& thread_start_func, void* thread_start_parameter); | ||
| 152 | |||
| 153 | [[nodiscard]] std::string GetName() const override { | ||
| 154 | return name; | ||
| 155 | } | ||
| 156 | |||
| 157 | void SetName(std::string new_name) { | ||
| 158 | name = std::move(new_name); | ||
| 159 | } | ||
| 160 | |||
| 161 | [[nodiscard]] std::string GetTypeName() const override { | ||
| 162 | return "Thread"; | ||
| 163 | } | ||
| 164 | |||
| 165 | static constexpr HandleType HANDLE_TYPE = HandleType::Thread; | ||
| 166 | [[nodiscard]] HandleType GetHandleType() const override { | ||
| 167 | return HANDLE_TYPE; | ||
| 168 | } | ||
| 169 | |||
| 170 | /** | ||
| 171 | * Gets the thread's current priority | ||
| 172 | * @return The current thread's priority | ||
| 173 | */ | ||
| 174 | [[nodiscard]] s32 GetPriority() const { | ||
| 175 | return priority; | ||
| 176 | } | ||
| 177 | |||
| 178 | /** | ||
| 179 | * Sets the thread's current priority. | ||
| 180 | * @param priority The new priority. | ||
| 181 | */ | ||
| 182 | void SetPriority(s32 value) { | ||
| 183 | priority = value; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * Gets the thread's nominal priority. | ||
| 188 | * @return The current thread's nominal priority. | ||
| 189 | */ | ||
| 190 | [[nodiscard]] s32 GetBasePriority() const { | ||
| 191 | return base_priority; | ||
| 192 | } | ||
| 193 | |||
| 194 | /** | ||
| 195 | * Gets the thread's thread ID | ||
| 196 | * @return The thread's ID | ||
| 197 | */ | ||
| 198 | [[nodiscard]] u64 GetThreadID() const { | ||
| 199 | return thread_id; | ||
| 200 | } | ||
| 201 | |||
| 202 | void ContinueIfHasKernelWaiters() { | ||
| 203 | if (GetNumKernelWaiters() > 0) { | ||
| 204 | Continue(); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | void Wakeup(); | ||
| 209 | |||
| 210 | void SetBasePriority(s32 value); | ||
| 211 | |||
| 212 | [[nodiscard]] ResultCode Run(); | ||
| 213 | |||
| 214 | void Exit(); | ||
| 215 | |||
| 216 | [[nodiscard]] u32 GetSuspendFlags() const { | ||
| 217 | return suspend_allowed_flags & suspend_request_flags; | ||
| 218 | } | ||
| 219 | |||
| 220 | [[nodiscard]] bool IsSuspended() const { | ||
| 221 | return GetSuspendFlags() != 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | [[nodiscard]] bool IsSuspendRequested(SuspendType type) const { | ||
| 225 | return (suspend_request_flags & | ||
| 226 | (1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)))) != | ||
| 227 | 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | [[nodiscard]] bool IsSuspendRequested() const { | ||
| 231 | return suspend_request_flags != 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | void RequestSuspend(SuspendType type); | ||
| 235 | |||
| 236 | void Resume(SuspendType type); | ||
| 237 | |||
| 238 | void TrySuspend(); | ||
| 239 | |||
| 240 | void Continue(); | ||
| 241 | |||
| 242 | void Suspend(); | ||
| 243 | |||
| 244 | void Finalize() override; | ||
| 245 | |||
| 246 | bool IsSignaled() const override; | ||
| 247 | |||
| 248 | void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) { | ||
| 249 | synced_object = obj; | ||
| 250 | wait_result = wait_res; | ||
| 251 | } | ||
| 252 | |||
| 253 | [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const { | ||
| 254 | *out = synced_object; | ||
| 255 | return wait_result; | ||
| 256 | } | ||
| 257 | |||
| 258 | /* | ||
| 259 | * Returns the Thread Local Storage address of the current thread | ||
| 260 | * @returns VAddr of the thread's TLS | ||
| 261 | */ | ||
| 262 | [[nodiscard]] VAddr GetTLSAddress() const { | ||
| 263 | return tls_address; | ||
| 264 | } | ||
| 265 | |||
| 266 | /* | ||
| 267 | * Returns the value of the TPIDR_EL0 Read/Write system register for this thread. | ||
| 268 | * @returns The value of the TPIDR_EL0 register. | ||
| 269 | */ | ||
| 270 | [[nodiscard]] u64 GetTPIDR_EL0() const { | ||
| 271 | return thread_context_64.tpidr; | ||
| 272 | } | ||
| 273 | |||
| 274 | /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread. | ||
| 275 | void SetTPIDR_EL0(u64 value) { | ||
| 276 | thread_context_64.tpidr = value; | ||
| 277 | thread_context_32.tpidr = static_cast<u32>(value); | ||
| 278 | } | ||
| 279 | |||
| 280 | [[nodiscard]] ThreadContext32& GetContext32() { | ||
| 281 | return thread_context_32; | ||
| 282 | } | ||
| 283 | |||
| 284 | [[nodiscard]] const ThreadContext32& GetContext32() const { | ||
| 285 | return thread_context_32; | ||
| 286 | } | ||
| 287 | |||
| 288 | [[nodiscard]] ThreadContext64& GetContext64() { | ||
| 289 | return thread_context_64; | ||
| 290 | } | ||
| 291 | |||
| 292 | [[nodiscard]] const ThreadContext64& GetContext64() const { | ||
| 293 | return thread_context_64; | ||
| 294 | } | ||
| 295 | |||
| 296 | [[nodiscard]] std::shared_ptr<Common::Fiber>& GetHostContext(); | ||
| 297 | |||
| 298 | [[nodiscard]] ThreadState GetState() const { | ||
| 299 | return thread_state & ThreadState::Mask; | ||
| 300 | } | ||
| 301 | |||
| 302 | [[nodiscard]] ThreadState GetRawState() const { | ||
| 303 | return thread_state; | ||
| 304 | } | ||
| 305 | |||
| 306 | void SetState(ThreadState state); | ||
| 307 | |||
| 308 | [[nodiscard]] s64 GetLastScheduledTick() const { | ||
| 309 | return last_scheduled_tick; | ||
| 310 | } | ||
| 311 | |||
| 312 | void SetLastScheduledTick(s64 tick) { | ||
| 313 | last_scheduled_tick = tick; | ||
| 314 | } | ||
| 315 | |||
| 316 | void AddCpuTime([[maybe_unused]] s32 core_id_, s64 amount) { | ||
| 317 | cpu_time += amount; | ||
| 318 | // TODO(bunnei): Debug kernels track per-core tick counts. Should we? | ||
| 319 | } | ||
| 320 | |||
| 321 | [[nodiscard]] s64 GetCpuTime() const { | ||
| 322 | return cpu_time; | ||
| 323 | } | ||
| 324 | |||
| 325 | [[nodiscard]] s32 GetActiveCore() const { | ||
| 326 | return core_id; | ||
| 327 | } | ||
| 328 | |||
| 329 | void SetActiveCore(s32 core) { | ||
| 330 | core_id = core; | ||
| 331 | } | ||
| 332 | |||
| 333 | [[nodiscard]] s32 GetCurrentCore() const { | ||
| 334 | return current_core_id; | ||
| 335 | } | ||
| 336 | |||
| 337 | void SetCurrentCore(s32 core) { | ||
| 338 | current_core_id = core; | ||
| 339 | } | ||
| 340 | |||
| 341 | [[nodiscard]] Process* GetOwnerProcess() { | ||
| 342 | return parent; | ||
| 343 | } | ||
| 344 | |||
| 345 | [[nodiscard]] const Process* GetOwnerProcess() const { | ||
| 346 | return parent; | ||
| 347 | } | ||
| 348 | |||
| 349 | [[nodiscard]] bool IsUserThread() const { | ||
| 350 | return parent != nullptr; | ||
| 351 | } | ||
| 352 | |||
| 353 | [[nodiscard]] KThread* GetLockOwner() const { | ||
| 354 | return lock_owner; | ||
| 355 | } | ||
| 356 | |||
| 357 | void SetLockOwner(KThread* owner) { | ||
| 358 | lock_owner = owner; | ||
| 359 | } | ||
| 360 | |||
| 361 | [[nodiscard]] const KAffinityMask& GetAffinityMask() const { | ||
| 362 | return physical_affinity_mask; | ||
| 363 | } | ||
| 364 | |||
| 365 | [[nodiscard]] ResultCode GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask); | ||
| 366 | |||
| 367 | [[nodiscard]] ResultCode GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask); | ||
| 368 | |||
| 369 | [[nodiscard]] ResultCode SetCoreMask(s32 core_id, u64 v_affinity_mask); | ||
| 370 | |||
| 371 | [[nodiscard]] ResultCode SetActivity(Svc::ThreadActivity activity); | ||
| 372 | |||
| 373 | [[nodiscard]] ResultCode Sleep(s64 timeout); | ||
| 374 | |||
| 375 | [[nodiscard]] s64 GetYieldScheduleCount() const { | ||
| 376 | return schedule_count; | ||
| 377 | } | ||
| 378 | |||
| 379 | void SetYieldScheduleCount(s64 count) { | ||
| 380 | schedule_count = count; | ||
| 381 | } | ||
| 382 | |||
| 383 | void WaitCancel(); | ||
| 384 | |||
| 385 | [[nodiscard]] bool IsWaitCancelled() const { | ||
| 386 | return wait_cancelled; | ||
| 387 | } | ||
| 388 | |||
| 389 | [[nodiscard]] void ClearWaitCancelled() { | ||
| 390 | wait_cancelled = false; | ||
| 391 | } | ||
| 392 | |||
| 393 | [[nodiscard]] bool IsCancellable() const { | ||
| 394 | return cancellable; | ||
| 395 | } | ||
| 396 | |||
| 397 | void SetCancellable() { | ||
| 398 | cancellable = true; | ||
| 399 | } | ||
| 400 | |||
| 401 | void ClearCancellable() { | ||
| 402 | cancellable = false; | ||
| 403 | } | ||
| 404 | |||
| 405 | [[nodiscard]] bool IsTerminationRequested() const { | ||
| 406 | return termination_requested || GetRawState() == ThreadState::Terminated; | ||
| 407 | } | ||
| 408 | |||
| 409 | struct StackParameters { | ||
| 410 | u8 svc_permission[0x10]; | ||
| 411 | std::atomic<u8> dpc_flags; | ||
| 412 | u8 current_svc_id; | ||
| 413 | bool is_calling_svc; | ||
| 414 | bool is_in_exception_handler; | ||
| 415 | bool is_pinned; | ||
| 416 | s32 disable_count; | ||
| 417 | KThread* cur_thread; | ||
| 418 | }; | ||
| 419 | |||
| 420 | [[nodiscard]] StackParameters& GetStackParameters() { | ||
| 421 | return stack_parameters; | ||
| 422 | } | ||
| 423 | |||
| 424 | [[nodiscard]] const StackParameters& GetStackParameters() const { | ||
| 425 | return stack_parameters; | ||
| 426 | } | ||
| 427 | |||
| 428 | class QueueEntry { | ||
| 429 | public: | ||
| 430 | constexpr QueueEntry() = default; | ||
| 431 | |||
| 432 | constexpr void Initialize() { | ||
| 433 | prev = nullptr; | ||
| 434 | next = nullptr; | ||
| 435 | } | ||
| 436 | |||
| 437 | constexpr KThread* GetPrev() const { | ||
| 438 | return prev; | ||
| 439 | } | ||
| 440 | constexpr KThread* GetNext() const { | ||
| 441 | return next; | ||
| 442 | } | ||
| 443 | constexpr void SetPrev(KThread* thread) { | ||
| 444 | prev = thread; | ||
| 445 | } | ||
| 446 | constexpr void SetNext(KThread* thread) { | ||
| 447 | next = thread; | ||
| 448 | } | ||
| 449 | |||
| 450 | private: | ||
| 451 | KThread* prev{}; | ||
| 452 | KThread* next{}; | ||
| 453 | }; | ||
| 454 | |||
| 455 | [[nodiscard]] QueueEntry& GetPriorityQueueEntry(s32 core) { | ||
| 456 | return per_core_priority_queue_entry[core]; | ||
| 457 | } | ||
| 458 | |||
| 459 | [[nodiscard]] const QueueEntry& GetPriorityQueueEntry(s32 core) const { | ||
| 460 | return per_core_priority_queue_entry[core]; | ||
| 461 | } | ||
| 462 | |||
| 463 | void SetSleepingQueue(KThreadQueue* q) { | ||
| 464 | sleeping_queue = q; | ||
| 465 | } | ||
| 466 | |||
| 467 | [[nodiscard]] s32 GetDisableDispatchCount() const { | ||
| 468 | return this->GetStackParameters().disable_count; | ||
| 469 | } | ||
| 470 | |||
| 471 | void DisableDispatch() { | ||
| 472 | ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0); | ||
| 473 | this->GetStackParameters().disable_count++; | ||
| 474 | } | ||
| 475 | |||
| 476 | void EnableDispatch() { | ||
| 477 | ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0); | ||
| 478 | this->GetStackParameters().disable_count--; | ||
| 479 | } | ||
| 480 | |||
| 481 | void Pin(); | ||
| 482 | |||
| 483 | void Unpin(); | ||
| 484 | |||
| 485 | void SetInExceptionHandler() { | ||
| 486 | this->GetStackParameters().is_in_exception_handler = true; | ||
| 487 | } | ||
| 488 | |||
| 489 | void ClearInExceptionHandler() { | ||
| 490 | this->GetStackParameters().is_in_exception_handler = false; | ||
| 491 | } | ||
| 492 | |||
| 493 | [[nodiscard]] bool IsInExceptionHandler() const { | ||
| 494 | return this->GetStackParameters().is_in_exception_handler; | ||
| 495 | } | ||
| 496 | |||
| 497 | void SetIsCallingSvc() { | ||
| 498 | this->GetStackParameters().is_calling_svc = true; | ||
| 499 | } | ||
| 500 | |||
| 501 | void ClearIsCallingSvc() { | ||
| 502 | this->GetStackParameters().is_calling_svc = false; | ||
| 503 | } | ||
| 504 | |||
| 505 | [[nodiscard]] bool IsCallingSvc() const { | ||
| 506 | return this->GetStackParameters().is_calling_svc; | ||
| 507 | } | ||
| 508 | |||
| 509 | [[nodiscard]] u8 GetSvcId() const { | ||
| 510 | return this->GetStackParameters().current_svc_id; | ||
| 511 | } | ||
| 512 | |||
| 513 | void RegisterDpc(DpcFlag flag) { | ||
| 514 | this->GetStackParameters().dpc_flags |= static_cast<u8>(flag); | ||
| 515 | } | ||
| 516 | |||
| 517 | void ClearDpc(DpcFlag flag) { | ||
| 518 | this->GetStackParameters().dpc_flags &= ~static_cast<u8>(flag); | ||
| 519 | } | ||
| 520 | |||
| 521 | [[nodiscard]] u8 GetDpc() const { | ||
| 522 | return this->GetStackParameters().dpc_flags; | ||
| 523 | } | ||
| 524 | |||
| 525 | [[nodiscard]] bool HasDpc() const { | ||
| 526 | return this->GetDpc() != 0; | ||
| 527 | } | ||
| 528 | |||
| 529 | void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) { | ||
| 530 | wait_reason_for_debugging = reason; | ||
| 531 | } | ||
| 532 | |||
| 533 | [[nodiscard]] ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const { | ||
| 534 | return wait_reason_for_debugging; | ||
| 535 | } | ||
| 536 | |||
| 537 | [[nodiscard]] ThreadType GetThreadTypeForDebugging() const { | ||
| 538 | return thread_type_for_debugging; | ||
| 539 | } | ||
| 540 | |||
| 541 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { | ||
| 542 | wait_objects_for_debugging.clear(); | ||
| 543 | wait_objects_for_debugging.reserve(objects.size()); | ||
| 544 | for (const auto& object : objects) { | ||
| 545 | wait_objects_for_debugging.emplace_back(object); | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 549 | [[nodiscard]] const std::vector<KSynchronizationObject*>& GetWaitObjectsForDebugging() const { | ||
| 550 | return wait_objects_for_debugging; | ||
| 551 | } | ||
| 552 | |||
| 553 | void SetMutexWaitAddressForDebugging(VAddr address) { | ||
| 554 | mutex_wait_address_for_debugging = address; | ||
| 555 | } | ||
| 556 | |||
| 557 | [[nodiscard]] VAddr GetMutexWaitAddressForDebugging() const { | ||
| 558 | return mutex_wait_address_for_debugging; | ||
| 559 | } | ||
| 560 | |||
| 561 | [[nodiscard]] s32 GetIdealCoreForDebugging() const { | ||
| 562 | return virtual_ideal_core_id; | ||
| 563 | } | ||
| 564 | |||
| 565 | void AddWaiter(KThread* thread); | ||
| 566 | |||
| 567 | void RemoveWaiter(KThread* thread); | ||
| 568 | |||
| 569 | [[nodiscard]] ResultCode GetThreadContext3(std::vector<u8>& out); | ||
| 570 | |||
| 571 | [[nodiscard]] KThread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key); | ||
| 572 | |||
| 573 | [[nodiscard]] VAddr GetAddressKey() const { | ||
| 574 | return address_key; | ||
| 575 | } | ||
| 576 | |||
| 577 | [[nodiscard]] u32 GetAddressKeyValue() const { | ||
| 578 | return address_key_value; | ||
| 579 | } | ||
| 580 | |||
| 581 | void SetAddressKey(VAddr key) { | ||
| 582 | address_key = key; | ||
| 583 | } | ||
| 584 | |||
| 585 | void SetAddressKey(VAddr key, u32 val) { | ||
| 586 | address_key = key; | ||
| 587 | address_key_value = val; | ||
| 588 | } | ||
| 589 | |||
| 590 | [[nodiscard]] bool HasWaiters() const { | ||
| 591 | return !waiter_list.empty(); | ||
| 592 | } | ||
| 593 | |||
| 594 | [[nodiscard]] s32 GetNumKernelWaiters() const { | ||
| 595 | return num_kernel_waiters; | ||
| 596 | } | ||
| 597 | |||
| 598 | [[nodiscard]] u64 GetConditionVariableKey() const { | ||
| 599 | return condvar_key; | ||
| 600 | } | ||
| 601 | |||
| 602 | [[nodiscard]] u64 GetAddressArbiterKey() const { | ||
| 603 | return condvar_key; | ||
| 604 | } | ||
| 605 | |||
| 606 | private: | ||
| 607 | static constexpr size_t PriorityInheritanceCountMax = 10; | ||
| 608 | union SyncObjectBuffer { | ||
| 609 | std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{}; | ||
| 610 | std::array<Handle, | ||
| 611 | Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))> | ||
| 612 | handles; | ||
| 613 | constexpr SyncObjectBuffer() {} | ||
| 614 | }; | ||
| 615 | static_assert(sizeof(SyncObjectBuffer::sync_objects) == sizeof(SyncObjectBuffer::handles)); | ||
| 616 | |||
| 617 | struct ConditionVariableComparator { | ||
| 618 | struct LightCompareType { | ||
| 619 | u64 cv_key{}; | ||
| 620 | s32 priority{}; | ||
| 621 | |||
| 622 | [[nodiscard]] constexpr u64 GetConditionVariableKey() const { | ||
| 623 | return cv_key; | ||
| 624 | } | ||
| 625 | |||
| 626 | [[nodiscard]] constexpr s32 GetPriority() const { | ||
| 627 | return priority; | ||
| 628 | } | ||
| 629 | }; | ||
| 630 | |||
| 631 | template <typename T> | ||
| 632 | requires( | ||
| 633 | std::same_as<T, KThread> || | ||
| 634 | std::same_as<T, LightCompareType>) static constexpr int Compare(const T& lhs, | ||
| 635 | const KThread& rhs) { | ||
| 636 | const u64 l_key = lhs.GetConditionVariableKey(); | ||
| 637 | const u64 r_key = rhs.GetConditionVariableKey(); | ||
| 638 | |||
| 639 | if (l_key < r_key) { | ||
| 640 | // Sort first by key | ||
| 641 | return -1; | ||
| 642 | } else if (l_key == r_key && lhs.GetPriority() < rhs.GetPriority()) { | ||
| 643 | // And then by priority. | ||
| 644 | return -1; | ||
| 645 | } else { | ||
| 646 | return 1; | ||
| 647 | } | ||
| 648 | } | ||
| 649 | }; | ||
| 650 | |||
| 651 | void AddWaiterImpl(KThread* thread); | ||
| 652 | |||
| 653 | void RemoveWaiterImpl(KThread* thread); | ||
| 654 | |||
| 655 | void StartTermination(); | ||
| 656 | |||
| 657 | [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, | ||
| 658 | s32 prio, s32 virt_core, Process* owner, ThreadType type); | ||
| 659 | |||
| 660 | [[nodiscard]] static ResultCode InitializeThread(KThread* thread, KThreadFunction func, | ||
| 661 | uintptr_t arg, VAddr user_stack_top, s32 prio, | ||
| 662 | s32 core, Process* owner, ThreadType type); | ||
| 663 | |||
| 664 | static void RestorePriority(KernelCore& kernel, KThread* thread); | ||
| 665 | |||
| 666 | // For core KThread implementation | ||
| 667 | ThreadContext32 thread_context_32{}; | ||
| 668 | ThreadContext64 thread_context_64{}; | ||
| 669 | Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{}; | ||
| 670 | s32 priority{}; | ||
| 671 | using ConditionVariableThreadTreeTraits = | ||
| 672 | Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert< | ||
| 673 | &KThread::condvar_arbiter_tree_node>; | ||
| 674 | using ConditionVariableThreadTree = | ||
| 675 | ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>; | ||
| 676 | ConditionVariableThreadTree* condvar_tree{}; | ||
| 677 | u64 condvar_key{}; | ||
| 678 | u64 virtual_affinity_mask{}; | ||
| 679 | KAffinityMask physical_affinity_mask{}; | ||
| 680 | u64 thread_id{}; | ||
| 681 | std::atomic<s64> cpu_time{}; | ||
| 682 | KSynchronizationObject* synced_object{}; | ||
| 683 | VAddr address_key{}; | ||
| 684 | Process* parent{}; | ||
| 685 | VAddr kernel_stack_top{}; | ||
| 686 | u32* light_ipc_data{}; | ||
| 687 | VAddr tls_address{}; | ||
| 688 | KLightLock activity_pause_lock; | ||
| 689 | s64 schedule_count{}; | ||
| 690 | s64 last_scheduled_tick{}; | ||
| 691 | std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; | ||
| 692 | KThreadQueue* sleeping_queue{}; | ||
| 693 | WaiterList waiter_list{}; | ||
| 694 | WaiterList pinned_waiter_list{}; | ||
| 695 | KThread* lock_owner{}; | ||
| 696 | u32 address_key_value{}; | ||
| 697 | u32 suspend_request_flags{}; | ||
| 698 | u32 suspend_allowed_flags{}; | ||
| 699 | ResultCode wait_result{RESULT_SUCCESS}; | ||
| 700 | s32 base_priority{}; | ||
| 701 | s32 physical_ideal_core_id{}; | ||
| 702 | s32 virtual_ideal_core_id{}; | ||
| 703 | s32 num_kernel_waiters{}; | ||
| 704 | s32 current_core_id{}; | ||
| 705 | s32 core_id{}; | ||
| 706 | KAffinityMask original_physical_affinity_mask{}; | ||
| 707 | s32 original_physical_ideal_core_id{}; | ||
| 708 | s32 num_core_migration_disables{}; | ||
| 709 | ThreadState thread_state{}; | ||
| 710 | std::atomic<bool> termination_requested{}; | ||
| 711 | bool wait_cancelled{}; | ||
| 712 | bool cancellable{}; | ||
| 713 | bool signaled{}; | ||
| 714 | bool initialized{}; | ||
| 715 | bool debug_attached{}; | ||
| 716 | s8 priority_inheritance_count{}; | ||
| 717 | bool resource_limit_release_hint{}; | ||
| 718 | StackParameters stack_parameters{}; | ||
| 719 | Common::SpinLock context_guard{}; | ||
| 720 | |||
| 721 | // For emulation | ||
| 722 | std::shared_ptr<Common::Fiber> host_context{}; | ||
| 723 | |||
| 724 | // For debugging | ||
| 725 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; | ||
| 726 | VAddr mutex_wait_address_for_debugging{}; | ||
| 727 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; | ||
| 728 | ThreadType thread_type_for_debugging{}; | ||
| 729 | std::string name; | ||
| 730 | |||
| 731 | public: | ||
| 732 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; | ||
| 733 | |||
| 734 | void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, u64 cv_key, | ||
| 735 | u32 value) { | ||
| 736 | condvar_tree = tree; | ||
| 737 | condvar_key = cv_key; | ||
| 738 | address_key = address; | ||
| 739 | address_key_value = value; | ||
| 740 | } | ||
| 741 | |||
| 742 | void ClearConditionVariable() { | ||
| 743 | condvar_tree = nullptr; | ||
| 744 | } | ||
| 745 | |||
| 746 | [[nodiscard]] bool IsWaitingForConditionVariable() const { | ||
| 747 | return condvar_tree != nullptr; | ||
| 748 | } | ||
| 749 | |||
| 750 | void SetAddressArbiter(ConditionVariableThreadTree* tree, u64 address) { | ||
| 751 | condvar_tree = tree; | ||
| 752 | condvar_key = address; | ||
| 753 | } | ||
| 754 | |||
| 755 | void ClearAddressArbiter() { | ||
| 756 | condvar_tree = nullptr; | ||
| 757 | } | ||
| 758 | |||
| 759 | [[nodiscard]] bool IsWaitingForAddressArbiter() const { | ||
| 760 | return condvar_tree != nullptr; | ||
| 761 | } | ||
| 762 | |||
| 763 | [[nodiscard]] ConditionVariableThreadTree* GetConditionVariableTree() const { | ||
| 764 | return condvar_tree; | ||
| 765 | } | ||
| 766 | }; | ||
| 767 | |||
| 768 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h new file mode 100644 index 000000000..c52eba249 --- /dev/null +++ b/src/core/hle/kernel/k_thread_queue.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/kernel/k_thread.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | class KThreadQueue { | ||
| 12 | public: | ||
| 13 | explicit KThreadQueue(KernelCore& kernel) : kernel{kernel} {} | ||
| 14 | |||
| 15 | bool IsEmpty() const { | ||
| 16 | return wait_list.empty(); | ||
| 17 | } | ||
| 18 | |||
| 19 | KThread::WaiterList::iterator begin() { | ||
| 20 | return wait_list.begin(); | ||
| 21 | } | ||
| 22 | KThread::WaiterList::iterator end() { | ||
| 23 | return wait_list.end(); | ||
| 24 | } | ||
| 25 | |||
| 26 | bool SleepThread(KThread* t) { | ||
| 27 | KScopedSchedulerLock sl{kernel}; | ||
| 28 | |||
| 29 | // If the thread needs terminating, don't enqueue it. | ||
| 30 | if (t->IsTerminationRequested()) { | ||
| 31 | return false; | ||
| 32 | } | ||
| 33 | |||
| 34 | // Set the thread's queue and mark it as waiting. | ||
| 35 | t->SetSleepingQueue(this); | ||
| 36 | t->SetState(ThreadState::Waiting); | ||
| 37 | |||
| 38 | // Add the thread to the queue. | ||
| 39 | wait_list.push_back(*t); | ||
| 40 | |||
| 41 | return true; | ||
| 42 | } | ||
| 43 | |||
| 44 | void WakeupThread(KThread* t) { | ||
| 45 | KScopedSchedulerLock sl{kernel}; | ||
| 46 | |||
| 47 | // Remove the thread from the queue. | ||
| 48 | wait_list.erase(wait_list.iterator_to(*t)); | ||
| 49 | |||
| 50 | // Mark the thread as no longer sleeping. | ||
| 51 | t->SetState(ThreadState::Runnable); | ||
| 52 | t->SetSleepingQueue(nullptr); | ||
| 53 | } | ||
| 54 | |||
| 55 | KThread* WakeupFrontThread() { | ||
| 56 | KScopedSchedulerLock sl{kernel}; | ||
| 57 | |||
| 58 | if (wait_list.empty()) { | ||
| 59 | return nullptr; | ||
| 60 | } else { | ||
| 61 | // Remove the thread from the queue. | ||
| 62 | auto it = wait_list.begin(); | ||
| 63 | KThread* thread = std::addressof(*it); | ||
| 64 | wait_list.erase(it); | ||
| 65 | |||
| 66 | ASSERT(thread->GetState() == ThreadState::Waiting); | ||
| 67 | |||
| 68 | // Mark the thread as no longer sleeping. | ||
| 69 | thread->SetState(ThreadState::Runnable); | ||
| 70 | thread->SetSleepingQueue(nullptr); | ||
| 71 | |||
| 72 | return thread; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | private: | ||
| 77 | KernelCore& kernel; | ||
| 78 | KThread::WaiterList wait_list{}; | ||
| 79 | }; | ||
| 80 | |||
| 81 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_writable_event.cpp b/src/core/hle/kernel/k_writable_event.cpp new file mode 100644 index 000000000..25c52edb2 --- /dev/null +++ b/src/core/hle/kernel/k_writable_event.cpp | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2021 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/k_event.h" | ||
| 6 | #include "core/hle/kernel/k_readable_event.h" | ||
| 7 | #include "core/hle/kernel/k_writable_event.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | KWritableEvent::KWritableEvent(KernelCore& kernel, std::string&& name) | ||
| 12 | : Object{kernel, std::move(name)} {} | ||
| 13 | KWritableEvent::~KWritableEvent() = default; | ||
| 14 | |||
| 15 | void KWritableEvent::Initialize(KEvent* parent_) { | ||
| 16 | parent = parent_; | ||
| 17 | } | ||
| 18 | |||
| 19 | ResultCode KWritableEvent::Signal() { | ||
| 20 | return parent->GetReadableEvent()->Signal(); | ||
| 21 | } | ||
| 22 | |||
| 23 | ResultCode KWritableEvent::Clear() { | ||
| 24 | return parent->GetReadableEvent()->Clear(); | ||
| 25 | } | ||
| 26 | |||
| 27 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h new file mode 100644 index 000000000..518f5448d --- /dev/null +++ b/src/core/hle/kernel/k_writable_event.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/kernel/object.h" | ||
| 8 | #include "core/hle/result.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | class KernelCore; | ||
| 13 | class KEvent; | ||
| 14 | |||
| 15 | class KWritableEvent final : public Object { | ||
| 16 | public: | ||
| 17 | explicit KWritableEvent(KernelCore& kernel, std::string&& name); | ||
| 18 | ~KWritableEvent() override; | ||
| 19 | |||
| 20 | std::string GetTypeName() const override { | ||
| 21 | return "KWritableEvent"; | ||
| 22 | } | ||
| 23 | |||
| 24 | static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent; | ||
| 25 | HandleType GetHandleType() const override { | ||
| 26 | return HANDLE_TYPE; | ||
| 27 | } | ||
| 28 | |||
| 29 | void Initialize(KEvent* parent_); | ||
| 30 | |||
| 31 | void Finalize() override {} | ||
| 32 | |||
| 33 | ResultCode Signal(); | ||
| 34 | ResultCode Clear(); | ||
| 35 | |||
| 36 | KEvent* GetParent() const { | ||
| 37 | return parent; | ||
| 38 | } | ||
| 39 | |||
| 40 | private: | ||
| 41 | KEvent* parent{}; | ||
| 42 | }; | ||
| 43 | |||
| 44 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index c0ff287a6..b20c2d13a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -28,17 +28,17 @@ | |||
| 28 | #include "core/hle/kernel/client_port.h" | 28 | #include "core/hle/kernel/client_port.h" |
| 29 | #include "core/hle/kernel/errors.h" | 29 | #include "core/hle/kernel/errors.h" |
| 30 | #include "core/hle/kernel/handle_table.h" | 30 | #include "core/hle/kernel/handle_table.h" |
| 31 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 31 | #include "core/hle/kernel/k_scheduler.h" | 32 | #include "core/hle/kernel/k_scheduler.h" |
| 33 | #include "core/hle/kernel/k_thread.h" | ||
| 32 | #include "core/hle/kernel/kernel.h" | 34 | #include "core/hle/kernel/kernel.h" |
| 33 | #include "core/hle/kernel/memory/memory_layout.h" | 35 | #include "core/hle/kernel/memory/memory_layout.h" |
| 34 | #include "core/hle/kernel/memory/memory_manager.h" | 36 | #include "core/hle/kernel/memory/memory_manager.h" |
| 35 | #include "core/hle/kernel/memory/slab_heap.h" | 37 | #include "core/hle/kernel/memory/slab_heap.h" |
| 36 | #include "core/hle/kernel/physical_core.h" | 38 | #include "core/hle/kernel/physical_core.h" |
| 37 | #include "core/hle/kernel/process.h" | 39 | #include "core/hle/kernel/process.h" |
| 38 | #include "core/hle/kernel/resource_limit.h" | ||
| 39 | #include "core/hle/kernel/service_thread.h" | 40 | #include "core/hle/kernel/service_thread.h" |
| 40 | #include "core/hle/kernel/shared_memory.h" | 41 | #include "core/hle/kernel/shared_memory.h" |
| 41 | #include "core/hle/kernel/thread.h" | ||
| 42 | #include "core/hle/kernel/time_manager.h" | 42 | #include "core/hle/kernel/time_manager.h" |
| 43 | #include "core/hle/lock.h" | 43 | #include "core/hle/lock.h" |
| 44 | #include "core/hle/result.h" | 44 | #include "core/hle/result.h" |
| @@ -57,14 +57,16 @@ struct KernelCore::Impl { | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | void Initialize(KernelCore& kernel) { | 59 | void Initialize(KernelCore& kernel) { |
| 60 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | ||
| 61 | |||
| 60 | RegisterHostThread(); | 62 | RegisterHostThread(); |
| 61 | 63 | ||
| 62 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | ||
| 63 | service_thread_manager = | 64 | service_thread_manager = |
| 64 | std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager"); | 65 | std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager"); |
| 66 | is_phantom_mode_for_singlecore = false; | ||
| 65 | 67 | ||
| 66 | InitializePhysicalCores(); | 68 | InitializePhysicalCores(); |
| 67 | InitializeSystemResourceLimit(kernel); | 69 | InitializeSystemResourceLimit(kernel, system); |
| 68 | InitializeMemoryLayout(); | 70 | InitializeMemoryLayout(); |
| 69 | InitializePreemption(kernel); | 71 | InitializePreemption(kernel); |
| 70 | InitializeSchedulers(); | 72 | InitializeSchedulers(); |
| @@ -116,32 +118,32 @@ struct KernelCore::Impl { | |||
| 116 | void InitializePhysicalCores() { | 118 | void InitializePhysicalCores() { |
| 117 | exclusive_monitor = | 119 | exclusive_monitor = |
| 118 | Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); | 120 | Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); |
| 119 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 121 | for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 120 | schedulers[i] = std::make_unique<Kernel::KScheduler>(system, i); | 122 | schedulers[i] = std::make_unique<Kernel::KScheduler>(system, i); |
| 121 | cores.emplace_back(i, system, *schedulers[i], interrupts); | 123 | cores.emplace_back(i, system, *schedulers[i], interrupts); |
| 122 | } | 124 | } |
| 123 | } | 125 | } |
| 124 | 126 | ||
| 125 | void InitializeSchedulers() { | 127 | void InitializeSchedulers() { |
| 126 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 128 | for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 127 | cores[i].Scheduler().Initialize(); | 129 | cores[i].Scheduler().Initialize(); |
| 128 | } | 130 | } |
| 129 | } | 131 | } |
| 130 | 132 | ||
| 131 | // Creates the default system resource limit | 133 | // Creates the default system resource limit |
| 132 | void InitializeSystemResourceLimit(KernelCore& kernel) { | 134 | void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) { |
| 133 | system_resource_limit = ResourceLimit::Create(kernel); | 135 | system_resource_limit = std::make_shared<KResourceLimit>(kernel, system); |
| 134 | 136 | ||
| 135 | // If setting the default system values fails, then something seriously wrong has occurred. | 137 | // If setting the default system values fails, then something seriously wrong has occurred. |
| 136 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x100000000) | 138 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000) |
| 137 | .IsSuccess()); | 139 | .IsSuccess()); |
| 138 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess()); | 140 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess()); |
| 139 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess()); | 141 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess()); |
| 140 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess()); | 142 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200) |
| 141 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess()); | 143 | .IsSuccess()); |
| 144 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 900).IsSuccess()); | ||
| 142 | 145 | ||
| 143 | if (!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0) || | 146 | if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, 0x60000)) { |
| 144 | !system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0x60000)) { | ||
| 145 | UNREACHABLE(); | 147 | UNREACHABLE(); |
| 146 | } | 148 | } |
| 147 | } | 149 | } |
| @@ -168,11 +170,9 @@ struct KernelCore::Impl { | |||
| 168 | std::string name = "Suspend Thread Id:" + std::to_string(i); | 170 | std::string name = "Suspend Thread Id:" + std::to_string(i); |
| 169 | std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); | 171 | std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); |
| 170 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | 172 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); |
| 171 | const auto type = | 173 | auto thread_res = KThread::Create(system, ThreadType::HighPriority, std::move(name), 0, |
| 172 | static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND); | 174 | 0, 0, static_cast<u32>(i), 0, nullptr, |
| 173 | auto thread_res = | 175 | std::move(init_func), init_func_parameter); |
| 174 | Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0, | ||
| 175 | nullptr, std::move(init_func), init_func_parameter); | ||
| 176 | 176 | ||
| 177 | suspend_threads[i] = std::move(thread_res).Unwrap(); | 177 | suspend_threads[i] = std::move(thread_res).Unwrap(); |
| 178 | } | 178 | } |
| @@ -207,6 +207,17 @@ struct KernelCore::Impl { | |||
| 207 | return host_thread_id; | 207 | return host_thread_id; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time | ||
| 211 | KThread* GetHostDummyThread() { | ||
| 212 | const thread_local auto thread = | ||
| 213 | KThread::Create( | ||
| 214 | system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0, | ||
| 215 | KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr, | ||
| 216 | []([[maybe_unused]] void* arg) { UNREACHABLE(); }, nullptr) | ||
| 217 | .Unwrap(); | ||
| 218 | return thread.get(); | ||
| 219 | } | ||
| 220 | |||
| 210 | /// Registers a CPU core thread by allocating a host thread ID for it | 221 | /// Registers a CPU core thread by allocating a host thread ID for it |
| 211 | void RegisterCoreThread(std::size_t core_id) { | 222 | void RegisterCoreThread(std::size_t core_id) { |
| 212 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); | 223 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); |
| @@ -219,6 +230,7 @@ struct KernelCore::Impl { | |||
| 219 | /// Registers a new host thread by allocating a host thread ID for it | 230 | /// Registers a new host thread by allocating a host thread ID for it |
| 220 | void RegisterHostThread() { | 231 | void RegisterHostThread() { |
| 221 | [[maybe_unused]] const auto this_id = GetHostThreadId(); | 232 | [[maybe_unused]] const auto this_id = GetHostThreadId(); |
| 233 | [[maybe_unused]] const auto dummy_thread = GetHostDummyThread(); | ||
| 222 | } | 234 | } |
| 223 | 235 | ||
| 224 | [[nodiscard]] u32 GetCurrentHostThreadID() { | 236 | [[nodiscard]] u32 GetCurrentHostThreadID() { |
| @@ -229,20 +241,21 @@ struct KernelCore::Impl { | |||
| 229 | return this_id; | 241 | return this_id; |
| 230 | } | 242 | } |
| 231 | 243 | ||
| 232 | [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() { | 244 | bool IsPhantomModeForSingleCore() const { |
| 233 | Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); | 245 | return is_phantom_mode_for_singlecore; |
| 234 | result.host_handle = GetCurrentHostThreadID(); | 246 | } |
| 235 | if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { | 247 | |
| 236 | return result; | 248 | void SetIsPhantomModeForSingleCore(bool value) { |
| 237 | } | 249 | ASSERT(!is_multicore); |
| 238 | const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler(); | 250 | is_phantom_mode_for_singlecore = value; |
| 239 | const Kernel::Thread* current = sched.GetCurrentThread(); | 251 | } |
| 240 | if (current != nullptr && !current->IsPhantomMode()) { | 252 | |
| 241 | result.guest_handle = current->GetGlobalHandle(); | 253 | KThread* GetCurrentEmuThread() { |
| 242 | } else { | 254 | const auto thread_id = GetCurrentHostThreadID(); |
| 243 | result.guest_handle = InvalidHandle; | 255 | if (thread_id >= Core::Hardware::NUM_CPU_CORES) { |
| 256 | return GetHostDummyThread(); | ||
| 244 | } | 257 | } |
| 245 | return result; | 258 | return schedulers[thread_id]->GetCurrentThread(); |
| 246 | } | 259 | } |
| 247 | 260 | ||
| 248 | void InitializeMemoryLayout() { | 261 | void InitializeMemoryLayout() { |
| @@ -307,7 +320,7 @@ struct KernelCore::Impl { | |||
| 307 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | 320 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |
| 308 | Kernel::TimeManager time_manager; | 321 | Kernel::TimeManager time_manager; |
| 309 | 322 | ||
| 310 | std::shared_ptr<ResourceLimit> system_resource_limit; | 323 | std::shared_ptr<KResourceLimit> system_resource_limit; |
| 311 | 324 | ||
| 312 | std::shared_ptr<Core::Timing::EventType> preemption_event; | 325 | std::shared_ptr<Core::Timing::EventType> preemption_event; |
| 313 | 326 | ||
| @@ -342,11 +355,12 @@ struct KernelCore::Impl { | |||
| 342 | // the release of itself | 355 | // the release of itself |
| 343 | std::unique_ptr<Common::ThreadWorker> service_thread_manager; | 356 | std::unique_ptr<Common::ThreadWorker> service_thread_manager; |
| 344 | 357 | ||
| 345 | std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; | 358 | std::array<std::shared_ptr<KThread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; |
| 346 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; | 359 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; |
| 347 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 360 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
| 348 | 361 | ||
| 349 | bool is_multicore{}; | 362 | bool is_multicore{}; |
| 363 | bool is_phantom_mode_for_singlecore{}; | ||
| 350 | u32 single_core_thread_id{}; | 364 | u32 single_core_thread_id{}; |
| 351 | 365 | ||
| 352 | std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; | 366 | std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; |
| @@ -376,12 +390,12 @@ void KernelCore::Shutdown() { | |||
| 376 | impl->Shutdown(); | 390 | impl->Shutdown(); |
| 377 | } | 391 | } |
| 378 | 392 | ||
| 379 | std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { | 393 | std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const { |
| 380 | return impl->system_resource_limit; | 394 | return impl->system_resource_limit; |
| 381 | } | 395 | } |
| 382 | 396 | ||
| 383 | std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { | 397 | std::shared_ptr<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { |
| 384 | return impl->global_handle_table.Get<Thread>(handle); | 398 | return impl->global_handle_table.Get<KThread>(handle); |
| 385 | } | 399 | } |
| 386 | 400 | ||
| 387 | void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { | 401 | void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { |
| @@ -546,8 +560,8 @@ u32 KernelCore::GetCurrentHostThreadID() const { | |||
| 546 | return impl->GetCurrentHostThreadID(); | 560 | return impl->GetCurrentHostThreadID(); |
| 547 | } | 561 | } |
| 548 | 562 | ||
| 549 | Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { | 563 | KThread* KernelCore::GetCurrentEmuThread() const { |
| 550 | return impl->GetCurrentEmuThreadID(); | 564 | return impl->GetCurrentEmuThread(); |
| 551 | } | 565 | } |
| 552 | 566 | ||
| 553 | Memory::MemoryManager& KernelCore::MemoryManager() { | 567 | Memory::MemoryManager& KernelCore::MemoryManager() { |
| @@ -645,4 +659,12 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> servi | |||
| 645 | }); | 659 | }); |
| 646 | } | 660 | } |
| 647 | 661 | ||
| 662 | bool KernelCore::IsPhantomModeForSingleCore() const { | ||
| 663 | return impl->IsPhantomModeForSingleCore(); | ||
| 664 | } | ||
| 665 | |||
| 666 | void KernelCore::SetIsPhantomModeForSingleCore(bool value) { | ||
| 667 | impl->SetIsPhantomModeForSingleCore(value); | ||
| 668 | } | ||
| 669 | |||
| 648 | } // namespace Kernel | 670 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 933d9a7d6..806a0d986 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -38,14 +38,18 @@ class GlobalSchedulerContext; | |||
| 38 | class HandleTable; | 38 | class HandleTable; |
| 39 | class PhysicalCore; | 39 | class PhysicalCore; |
| 40 | class Process; | 40 | class Process; |
| 41 | class ResourceLimit; | 41 | class KResourceLimit; |
| 42 | class KScheduler; | 42 | class KScheduler; |
| 43 | class SharedMemory; | 43 | class SharedMemory; |
| 44 | class ServiceThread; | 44 | class ServiceThread; |
| 45 | class Synchronization; | 45 | class Synchronization; |
| 46 | class Thread; | 46 | class KThread; |
| 47 | class TimeManager; | 47 | class TimeManager; |
| 48 | 48 | ||
| 49 | using EmuThreadHandle = uintptr_t; | ||
| 50 | constexpr EmuThreadHandle EmuThreadHandleInvalid{}; | ||
| 51 | constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63}; | ||
| 52 | |||
| 49 | /// Represents a single instance of the kernel. | 53 | /// Represents a single instance of the kernel. |
| 50 | class KernelCore { | 54 | class KernelCore { |
| 51 | private: | 55 | private: |
| @@ -81,10 +85,10 @@ public: | |||
| 81 | void Shutdown(); | 85 | void Shutdown(); |
| 82 | 86 | ||
| 83 | /// Retrieves a shared pointer to the system resource limit instance. | 87 | /// Retrieves a shared pointer to the system resource limit instance. |
| 84 | std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const; | 88 | std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const; |
| 85 | 89 | ||
| 86 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. | 90 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. |
| 87 | std::shared_ptr<Thread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; | 91 | std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; |
| 88 | 92 | ||
| 89 | /// Adds the given shared pointer to an internal list of active processes. | 93 | /// Adds the given shared pointer to an internal list of active processes. |
| 90 | void AppendNewProcess(std::shared_ptr<Process> process); | 94 | void AppendNewProcess(std::shared_ptr<Process> process); |
| @@ -161,8 +165,8 @@ public: | |||
| 161 | /// Determines whether or not the given port is a valid named port. | 165 | /// Determines whether or not the given port is a valid named port. |
| 162 | bool IsValidNamedPort(NamedPortTable::const_iterator port) const; | 166 | bool IsValidNamedPort(NamedPortTable::const_iterator port) const; |
| 163 | 167 | ||
| 164 | /// Gets the current host_thread/guest_thread handle. | 168 | /// Gets the current host_thread/guest_thread pointer. |
| 165 | Core::EmuThreadHandle GetCurrentEmuThreadID() const; | 169 | KThread* GetCurrentEmuThread() const; |
| 166 | 170 | ||
| 167 | /// Gets the current host_thread handle. | 171 | /// Gets the current host_thread handle. |
| 168 | u32 GetCurrentHostThreadID() const; | 172 | u32 GetCurrentHostThreadID() const; |
| @@ -237,10 +241,14 @@ public: | |||
| 237 | */ | 241 | */ |
| 238 | void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread); | 242 | void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread); |
| 239 | 243 | ||
| 244 | /// Workaround for single-core mode when preempting threads while idle. | ||
| 245 | bool IsPhantomModeForSingleCore() const; | ||
| 246 | void SetIsPhantomModeForSingleCore(bool value); | ||
| 247 | |||
| 240 | private: | 248 | private: |
| 241 | friend class Object; | 249 | friend class Object; |
| 242 | friend class Process; | 250 | friend class Process; |
| 243 | friend class Thread; | 251 | friend class KThread; |
| 244 | 252 | ||
| 245 | /// Creates a new object ID, incrementing the internal object ID counter. | 253 | /// Creates a new object ID, incrementing the internal object ID counter. |
| 246 | u32 CreateNewObjectID(); | 254 | u32 CreateNewObjectID(); |
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index 080886554..7de91c768 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "common/scope_exit.h" | 7 | #include "common/scope_exit.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/kernel/errors.h" | 9 | #include "core/hle/kernel/errors.h" |
| 10 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/memory/address_space_info.h" | 12 | #include "core/hle/kernel/memory/address_space_info.h" |
| 12 | #include "core/hle/kernel/memory/memory_block.h" | 13 | #include "core/hle/kernel/memory/memory_block.h" |
| @@ -15,7 +16,6 @@ | |||
| 15 | #include "core/hle/kernel/memory/page_table.h" | 16 | #include "core/hle/kernel/memory/page_table.h" |
| 16 | #include "core/hle/kernel/memory/system_control.h" | 17 | #include "core/hle/kernel/memory/system_control.h" |
| 17 | #include "core/hle/kernel/process.h" | 18 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/resource_limit.h" | ||
| 19 | #include "core/memory.h" | 19 | #include "core/memory.h" |
| 20 | 20 | ||
| 21 | namespace Kernel::Memory { | 21 | namespace Kernel::Memory { |
| @@ -414,7 +414,7 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 414 | const std::size_t remaining_pages{remaining_size / PageSize}; | 414 | const std::size_t remaining_pages{remaining_size / PageSize}; |
| 415 | 415 | ||
| 416 | if (process->GetResourceLimit() && | 416 | if (process->GetResourceLimit() && |
| 417 | !process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, remaining_size)) { | 417 | !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, remaining_size)) { |
| 418 | return ERR_RESOURCE_LIMIT_EXCEEDED; | 418 | return ERR_RESOURCE_LIMIT_EXCEEDED; |
| 419 | } | 419 | } |
| 420 | 420 | ||
| @@ -422,7 +422,7 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 422 | { | 422 | { |
| 423 | auto block_guard = detail::ScopeExit([&] { | 423 | auto block_guard = detail::ScopeExit([&] { |
| 424 | system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool); | 424 | system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool); |
| 425 | process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, remaining_size); | 425 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, remaining_size); |
| 426 | }); | 426 | }); |
| 427 | 427 | ||
| 428 | CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, | 428 | CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, |
| @@ -474,7 +474,7 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 474 | CASCADE_CODE(UnmapMemory(addr, size)); | 474 | CASCADE_CODE(UnmapMemory(addr, size)); |
| 475 | 475 | ||
| 476 | auto process{system.Kernel().CurrentProcess()}; | 476 | auto process{system.Kernel().CurrentProcess()}; |
| 477 | process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, mapped_size); | 477 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); |
| 478 | physical_memory_usage -= mapped_size; | 478 | physical_memory_usage -= mapped_size; |
| 479 | 479 | ||
| 480 | return RESULT_SUCCESS; | 480 | return RESULT_SUCCESS; |
| @@ -783,7 +783,7 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) { | |||
| 783 | 783 | ||
| 784 | auto process{system.Kernel().CurrentProcess()}; | 784 | auto process{system.Kernel().CurrentProcess()}; |
| 785 | if (process->GetResourceLimit() && delta != 0 && | 785 | if (process->GetResourceLimit() && delta != 0 && |
| 786 | !process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, delta)) { | 786 | !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, delta)) { |
| 787 | return ERR_RESOURCE_LIMIT_EXCEEDED; | 787 | return ERR_RESOURCE_LIMIT_EXCEEDED; |
| 788 | } | 788 | } |
| 789 | 789 | ||
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index 2c571792b..d7f40c403 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp | |||
| @@ -8,7 +8,10 @@ | |||
| 8 | 8 | ||
| 9 | namespace Kernel { | 9 | namespace Kernel { |
| 10 | 10 | ||
| 11 | Object::Object(KernelCore& kernel) : kernel{kernel}, object_id{kernel.CreateNewObjectID()} {} | 11 | Object::Object(KernelCore& kernel_) |
| 12 | : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{"[UNKNOWN KERNEL OBJECT]"} {} | ||
| 13 | Object::Object(KernelCore& kernel_, std::string&& name_) | ||
| 14 | : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{std::move(name_)} {} | ||
| 12 | Object::~Object() = default; | 15 | Object::~Object() = default; |
| 13 | 16 | ||
| 14 | bool Object::IsWaitable() const { | 17 | bool Object::IsWaitable() const { |
| @@ -21,6 +24,7 @@ bool Object::IsWaitable() const { | |||
| 21 | return true; | 24 | return true; |
| 22 | 25 | ||
| 23 | case HandleType::Unknown: | 26 | case HandleType::Unknown: |
| 27 | case HandleType::Event: | ||
| 24 | case HandleType::WritableEvent: | 28 | case HandleType::WritableEvent: |
| 25 | case HandleType::SharedMemory: | 29 | case HandleType::SharedMemory: |
| 26 | case HandleType::TransferMemory: | 30 | case HandleType::TransferMemory: |
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 27124ef67..501e58b33 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h | |||
| @@ -18,6 +18,7 @@ using Handle = u32; | |||
| 18 | 18 | ||
| 19 | enum class HandleType : u32 { | 19 | enum class HandleType : u32 { |
| 20 | Unknown, | 20 | Unknown, |
| 21 | Event, | ||
| 21 | WritableEvent, | 22 | WritableEvent, |
| 22 | ReadableEvent, | 23 | ReadableEvent, |
| 23 | SharedMemory, | 24 | SharedMemory, |
| @@ -34,7 +35,8 @@ enum class HandleType : u32 { | |||
| 34 | 35 | ||
| 35 | class Object : NonCopyable, public std::enable_shared_from_this<Object> { | 36 | class Object : NonCopyable, public std::enable_shared_from_this<Object> { |
| 36 | public: | 37 | public: |
| 37 | explicit Object(KernelCore& kernel); | 38 | explicit Object(KernelCore& kernel_); |
| 39 | explicit Object(KernelCore& kernel_, std::string&& name_); | ||
| 38 | virtual ~Object(); | 40 | virtual ~Object(); |
| 39 | 41 | ||
| 40 | /// Returns a unique identifier for the object. For debugging purposes only. | 42 | /// Returns a unique identifier for the object. For debugging purposes only. |
| @@ -46,7 +48,7 @@ public: | |||
| 46 | return "[BAD KERNEL OBJECT TYPE]"; | 48 | return "[BAD KERNEL OBJECT TYPE]"; |
| 47 | } | 49 | } |
| 48 | virtual std::string GetName() const { | 50 | virtual std::string GetName() const { |
| 49 | return "[UNKNOWN KERNEL OBJECT]"; | 51 | return name; |
| 50 | } | 52 | } |
| 51 | virtual HandleType GetHandleType() const = 0; | 53 | virtual HandleType GetHandleType() const = 0; |
| 52 | 54 | ||
| @@ -61,12 +63,15 @@ public: | |||
| 61 | */ | 63 | */ |
| 62 | bool IsWaitable() const; | 64 | bool IsWaitable() const; |
| 63 | 65 | ||
| 66 | virtual void Finalize() = 0; | ||
| 67 | |||
| 64 | protected: | 68 | protected: |
| 65 | /// The kernel instance this object was created under. | 69 | /// The kernel instance this object was created under. |
| 66 | KernelCore& kernel; | 70 | KernelCore& kernel; |
| 67 | 71 | ||
| 68 | private: | 72 | private: |
| 69 | std::atomic<u32> object_id{0}; | 73 | std::atomic<u32> object_id{0}; |
| 74 | std::string name; | ||
| 70 | }; | 75 | }; |
| 71 | 76 | ||
| 72 | template <typename T> | 77 | template <typename T> |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 37b77fa6e..2286b292d 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -15,14 +15,15 @@ | |||
| 15 | #include "core/file_sys/program_metadata.h" | 15 | #include "core/file_sys/program_metadata.h" |
| 16 | #include "core/hle/kernel/code_set.h" | 16 | #include "core/hle/kernel/code_set.h" |
| 17 | #include "core/hle/kernel/errors.h" | 17 | #include "core/hle/kernel/errors.h" |
| 18 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 18 | #include "core/hle/kernel/k_scheduler.h" | 19 | #include "core/hle/kernel/k_scheduler.h" |
| 20 | #include "core/hle/kernel/k_thread.h" | ||
| 19 | #include "core/hle/kernel/kernel.h" | 21 | #include "core/hle/kernel/kernel.h" |
| 20 | #include "core/hle/kernel/memory/memory_block_manager.h" | 22 | #include "core/hle/kernel/memory/memory_block_manager.h" |
| 21 | #include "core/hle/kernel/memory/page_table.h" | 23 | #include "core/hle/kernel/memory/page_table.h" |
| 22 | #include "core/hle/kernel/memory/slab_heap.h" | 24 | #include "core/hle/kernel/memory/slab_heap.h" |
| 23 | #include "core/hle/kernel/process.h" | 25 | #include "core/hle/kernel/process.h" |
| 24 | #include "core/hle/kernel/resource_limit.h" | 26 | #include "core/hle/kernel/svc_results.h" |
| 25 | #include "core/hle/kernel/thread.h" | ||
| 26 | #include "core/hle/lock.h" | 27 | #include "core/hle/lock.h" |
| 27 | #include "core/memory.h" | 28 | #include "core/memory.h" |
| 28 | #include "core/settings.h" | 29 | #include "core/settings.h" |
| @@ -38,11 +39,10 @@ namespace { | |||
| 38 | */ | 39 | */ |
| 39 | void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { | 40 | void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { |
| 40 | const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); | 41 | const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); |
| 41 | ThreadType type = THREADTYPE_USER; | 42 | auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0, |
| 42 | auto thread_res = Thread::Create(system, type, "main", entry_point, priority, 0, | 43 | owner_process.GetIdealCoreId(), stack_top, &owner_process); |
| 43 | owner_process.GetIdealCore(), stack_top, &owner_process); | ||
| 44 | 44 | ||
| 45 | std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap(); | 45 | std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap(); |
| 46 | 46 | ||
| 47 | // Register 1 must be a handle to the main thread | 47 | // Register 1 must be a handle to the main thread |
| 48 | const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); | 48 | const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); |
| @@ -117,7 +117,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, | |||
| 117 | 117 | ||
| 118 | std::shared_ptr<Process> process = std::make_shared<Process>(system); | 118 | std::shared_ptr<Process> process = std::make_shared<Process>(system); |
| 119 | process->name = std::move(name); | 119 | process->name = std::move(name); |
| 120 | process->resource_limit = ResourceLimit::Create(kernel); | 120 | process->resource_limit = std::make_shared<KResourceLimit>(kernel, system); |
| 121 | process->status = ProcessStatus::Created; | 121 | process->status = ProcessStatus::Created; |
| 122 | process->program_id = 0; | 122 | process->program_id = 0; |
| 123 | process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() | 123 | process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() |
| @@ -133,12 +133,29 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, | |||
| 133 | return process; | 133 | return process; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const { | 136 | std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const { |
| 137 | return resource_limit; | 137 | return resource_limit; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | void Process::IncrementThreadCount() { | ||
| 141 | ASSERT(num_threads >= 0); | ||
| 142 | num_created_threads++; | ||
| 143 | |||
| 144 | if (const auto count = ++num_threads; count > peak_num_threads) { | ||
| 145 | peak_num_threads = count; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | void Process::DecrementThreadCount() { | ||
| 150 | ASSERT(num_threads > 0); | ||
| 151 | |||
| 152 | if (const auto count = --num_threads; count == 0) { | ||
| 153 | UNIMPLEMENTED_MSG("Process termination is not implemented!"); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 140 | u64 Process::GetTotalPhysicalMemoryAvailable() const { | 157 | u64 Process::GetTotalPhysicalMemoryAvailable() const { |
| 141 | const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) + | 158 | const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + |
| 142 | page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + | 159 | page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + |
| 143 | main_thread_stack_size}; | 160 | main_thread_stack_size}; |
| 144 | 161 | ||
| @@ -162,26 +179,79 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { | |||
| 162 | return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); | 179 | return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); |
| 163 | } | 180 | } |
| 164 | 181 | ||
| 165 | void Process::RegisterThread(const Thread* thread) { | 182 | bool Process::ReleaseUserException(KThread* thread) { |
| 183 | KScopedSchedulerLock sl{kernel}; | ||
| 184 | |||
| 185 | if (exception_thread == thread) { | ||
| 186 | exception_thread = nullptr; | ||
| 187 | |||
| 188 | // Remove waiter thread. | ||
| 189 | s32 num_waiters{}; | ||
| 190 | KThread* next = thread->RemoveWaiterByKey( | ||
| 191 | std::addressof(num_waiters), | ||
| 192 | reinterpret_cast<uintptr_t>(std::addressof(exception_thread))); | ||
| 193 | if (next != nullptr) { | ||
| 194 | if (next->GetState() == ThreadState::Waiting) { | ||
| 195 | next->SetState(ThreadState::Runnable); | ||
| 196 | } else { | ||
| 197 | KScheduler::SetSchedulerUpdateNeeded(kernel); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | return true; | ||
| 202 | } else { | ||
| 203 | return false; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | void Process::PinCurrentThread() { | ||
| 208 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 209 | |||
| 210 | // Get the current thread. | ||
| 211 | const s32 core_id = GetCurrentCoreId(kernel); | ||
| 212 | KThread* cur_thread = GetCurrentThreadPointer(kernel); | ||
| 213 | |||
| 214 | // Pin it. | ||
| 215 | PinThread(core_id, cur_thread); | ||
| 216 | cur_thread->Pin(); | ||
| 217 | |||
| 218 | // An update is needed. | ||
| 219 | KScheduler::SetSchedulerUpdateNeeded(kernel); | ||
| 220 | } | ||
| 221 | |||
| 222 | void Process::UnpinCurrentThread() { | ||
| 223 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 224 | |||
| 225 | // Get the current thread. | ||
| 226 | const s32 core_id = GetCurrentCoreId(kernel); | ||
| 227 | KThread* cur_thread = GetCurrentThreadPointer(kernel); | ||
| 228 | |||
| 229 | // Unpin it. | ||
| 230 | cur_thread->Unpin(); | ||
| 231 | UnpinThread(core_id, cur_thread); | ||
| 232 | |||
| 233 | // An update is needed. | ||
| 234 | KScheduler::SetSchedulerUpdateNeeded(kernel); | ||
| 235 | } | ||
| 236 | |||
| 237 | void Process::RegisterThread(const KThread* thread) { | ||
| 166 | thread_list.push_back(thread); | 238 | thread_list.push_back(thread); |
| 167 | } | 239 | } |
| 168 | 240 | ||
| 169 | void Process::UnregisterThread(const Thread* thread) { | 241 | void Process::UnregisterThread(const KThread* thread) { |
| 170 | thread_list.remove(thread); | 242 | thread_list.remove(thread); |
| 171 | } | 243 | } |
| 172 | 244 | ||
| 173 | ResultCode Process::ClearSignalState() { | 245 | ResultCode Process::Reset() { |
| 174 | KScopedSchedulerLock lock(system.Kernel()); | 246 | // Lock the process and the scheduler. |
| 175 | if (status == ProcessStatus::Exited) { | 247 | KScopedLightLock lk(state_lock); |
| 176 | LOG_ERROR(Kernel, "called on a terminated process instance."); | 248 | KScopedSchedulerLock sl{kernel}; |
| 177 | return ERR_INVALID_STATE; | ||
| 178 | } | ||
| 179 | 249 | ||
| 180 | if (!is_signaled) { | 250 | // Validate that we're in a state that we can reset. |
| 181 | LOG_ERROR(Kernel, "called on a process instance that isn't signaled."); | 251 | R_UNLESS(status != ProcessStatus::Exited, Svc::ResultInvalidState); |
| 182 | return ERR_INVALID_STATE; | 252 | R_UNLESS(is_signaled, Svc::ResultInvalidState); |
| 183 | } | ||
| 184 | 253 | ||
| 254 | // Clear signaled. | ||
| 185 | is_signaled = false; | 255 | is_signaled = false; |
| 186 | return RESULT_SUCCESS; | 256 | return RESULT_SUCCESS; |
| 187 | } | 257 | } |
| @@ -237,13 +307,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, | |||
| 237 | 307 | ||
| 238 | // Set initial resource limits | 308 | // Set initial resource limits |
| 239 | resource_limit->SetLimitValue( | 309 | resource_limit->SetLimitValue( |
| 240 | ResourceType::PhysicalMemory, | 310 | LimitableResource::PhysicalMemory, |
| 241 | kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application)); | 311 | kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application)); |
| 242 | resource_limit->SetLimitValue(ResourceType::Threads, 608); | 312 | resource_limit->SetLimitValue(LimitableResource::Threads, 608); |
| 243 | resource_limit->SetLimitValue(ResourceType::Events, 700); | 313 | resource_limit->SetLimitValue(LimitableResource::Events, 700); |
| 244 | resource_limit->SetLimitValue(ResourceType::TransferMemory, 128); | 314 | resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128); |
| 245 | resource_limit->SetLimitValue(ResourceType::Sessions, 894); | 315 | resource_limit->SetLimitValue(LimitableResource::Sessions, 894); |
| 246 | ASSERT(resource_limit->Reserve(ResourceType::PhysicalMemory, code_size)); | 316 | ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemory, code_size)); |
| 247 | 317 | ||
| 248 | // Create TLS region | 318 | // Create TLS region |
| 249 | tls_region_address = CreateTLSRegion(); | 319 | tls_region_address = CreateTLSRegion(); |
| @@ -260,14 +330,14 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { | |||
| 260 | ChangeStatus(ProcessStatus::Running); | 330 | ChangeStatus(ProcessStatus::Running); |
| 261 | 331 | ||
| 262 | SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); | 332 | SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); |
| 263 | resource_limit->Reserve(ResourceType::Threads, 1); | 333 | resource_limit->Reserve(LimitableResource::Threads, 1); |
| 264 | resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size); | 334 | resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); |
| 265 | } | 335 | } |
| 266 | 336 | ||
| 267 | void Process::PrepareForTermination() { | 337 | void Process::PrepareForTermination() { |
| 268 | ChangeStatus(ProcessStatus::Exiting); | 338 | ChangeStatus(ProcessStatus::Exiting); |
| 269 | 339 | ||
| 270 | const auto stop_threads = [this](const std::vector<std::shared_ptr<Thread>>& thread_list) { | 340 | const auto stop_threads = [this](const std::vector<std::shared_ptr<KThread>>& thread_list) { |
| 271 | for (auto& thread : thread_list) { | 341 | for (auto& thread : thread_list) { |
| 272 | if (thread->GetOwnerProcess() != this) | 342 | if (thread->GetOwnerProcess() != this) |
| 273 | continue; | 343 | continue; |
| @@ -279,7 +349,7 @@ void Process::PrepareForTermination() { | |||
| 279 | ASSERT_MSG(thread->GetState() == ThreadState::Waiting, | 349 | ASSERT_MSG(thread->GetState() == ThreadState::Waiting, |
| 280 | "Exiting processes with non-waiting threads is currently unimplemented"); | 350 | "Exiting processes with non-waiting threads is currently unimplemented"); |
| 281 | 351 | ||
| 282 | thread->Stop(); | 352 | thread->Exit(); |
| 283 | } | 353 | } |
| 284 | }; | 354 | }; |
| 285 | 355 | ||
| @@ -372,7 +442,7 @@ bool Process::IsSignaled() const { | |||
| 372 | Process::Process(Core::System& system) | 442 | Process::Process(Core::System& system) |
| 373 | : KSynchronizationObject{system.Kernel()}, | 443 | : KSynchronizationObject{system.Kernel()}, |
| 374 | page_table{std::make_unique<Memory::PageTable>(system)}, handle_table{system.Kernel()}, | 444 | page_table{std::make_unique<Memory::PageTable>(system)}, handle_table{system.Kernel()}, |
| 375 | address_arbiter{system}, condition_var{system}, system{system} {} | 445 | address_arbiter{system}, condition_var{system}, state_lock{system.Kernel()}, system{system} {} |
| 376 | 446 | ||
| 377 | Process::~Process() = default; | 447 | Process::~Process() = default; |
| 378 | 448 | ||
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 564e1f27d..320b0f347 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -29,8 +29,8 @@ class ProgramMetadata; | |||
| 29 | namespace Kernel { | 29 | namespace Kernel { |
| 30 | 30 | ||
| 31 | class KernelCore; | 31 | class KernelCore; |
| 32 | class ResourceLimit; | 32 | class KResourceLimit; |
| 33 | class Thread; | 33 | class KThread; |
| 34 | class TLSPage; | 34 | class TLSPage; |
| 35 | 35 | ||
| 36 | struct CodeSet; | 36 | struct CodeSet; |
| @@ -170,13 +170,18 @@ public: | |||
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | /// Gets the resource limit descriptor for this process | 172 | /// Gets the resource limit descriptor for this process |
| 173 | std::shared_ptr<ResourceLimit> GetResourceLimit() const; | 173 | std::shared_ptr<KResourceLimit> GetResourceLimit() const; |
| 174 | 174 | ||
| 175 | /// Gets the ideal CPU core ID for this process | 175 | /// Gets the ideal CPU core ID for this process |
| 176 | u8 GetIdealCore() const { | 176 | u8 GetIdealCoreId() const { |
| 177 | return ideal_core; | 177 | return ideal_core; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | /// Checks if the specified thread priority is valid. | ||
| 181 | bool CheckThreadPriority(s32 prio) const { | ||
| 182 | return ((1ULL << prio) & GetPriorityMask()) != 0; | ||
| 183 | } | ||
| 184 | |||
| 180 | /// Gets the bitmask of allowed cores that this process' threads can run on. | 185 | /// Gets the bitmask of allowed cores that this process' threads can run on. |
| 181 | u64 GetCoreMask() const { | 186 | u64 GetCoreMask() const { |
| 182 | return capabilities.GetCoreMask(); | 187 | return capabilities.GetCoreMask(); |
| @@ -212,6 +217,14 @@ public: | |||
| 212 | return is_64bit_process; | 217 | return is_64bit_process; |
| 213 | } | 218 | } |
| 214 | 219 | ||
| 220 | [[nodiscard]] bool IsSuspended() const { | ||
| 221 | return is_suspended; | ||
| 222 | } | ||
| 223 | |||
| 224 | void SetSuspended(bool suspended) { | ||
| 225 | is_suspended = suspended; | ||
| 226 | } | ||
| 227 | |||
| 215 | /// Gets the total running time of the process instance in ticks. | 228 | /// Gets the total running time of the process instance in ticks. |
| 216 | u64 GetCPUTimeTicks() const { | 229 | u64 GetCPUTimeTicks() const { |
| 217 | return total_process_running_time_ticks; | 230 | return total_process_running_time_ticks; |
| @@ -232,6 +245,33 @@ public: | |||
| 232 | ++schedule_count; | 245 | ++schedule_count; |
| 233 | } | 246 | } |
| 234 | 247 | ||
| 248 | void IncrementThreadCount(); | ||
| 249 | void DecrementThreadCount(); | ||
| 250 | |||
| 251 | void SetRunningThread(s32 core, KThread* thread, u64 idle_count) { | ||
| 252 | running_threads[core] = thread; | ||
| 253 | running_thread_idle_counts[core] = idle_count; | ||
| 254 | } | ||
| 255 | |||
| 256 | void ClearRunningThread(KThread* thread) { | ||
| 257 | for (size_t i = 0; i < running_threads.size(); ++i) { | ||
| 258 | if (running_threads[i] == thread) { | ||
| 259 | running_threads[i] = nullptr; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | [[nodiscard]] KThread* GetRunningThread(s32 core) const { | ||
| 265 | return running_threads[core]; | ||
| 266 | } | ||
| 267 | |||
| 268 | bool ReleaseUserException(KThread* thread); | ||
| 269 | |||
| 270 | [[nodiscard]] KThread* GetPinnedThread(s32 core_id) const { | ||
| 271 | ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||
| 272 | return pinned_threads[core_id]; | ||
| 273 | } | ||
| 274 | |||
| 235 | /// Gets 8 bytes of random data for svcGetInfo RandomEntropy | 275 | /// Gets 8 bytes of random data for svcGetInfo RandomEntropy |
| 236 | u64 GetRandomEntropy(std::size_t index) const { | 276 | u64 GetRandomEntropy(std::size_t index) const { |
| 237 | return random_entropy.at(index); | 277 | return random_entropy.at(index); |
| @@ -252,17 +292,17 @@ public: | |||
| 252 | u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const; | 292 | u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const; |
| 253 | 293 | ||
| 254 | /// Gets the list of all threads created with this process as their owner. | 294 | /// Gets the list of all threads created with this process as their owner. |
| 255 | const std::list<const Thread*>& GetThreadList() const { | 295 | const std::list<const KThread*>& GetThreadList() const { |
| 256 | return thread_list; | 296 | return thread_list; |
| 257 | } | 297 | } |
| 258 | 298 | ||
| 259 | /// Registers a thread as being created under this process, | 299 | /// Registers a thread as being created under this process, |
| 260 | /// adding it to this process' thread list. | 300 | /// adding it to this process' thread list. |
| 261 | void RegisterThread(const Thread* thread); | 301 | void RegisterThread(const KThread* thread); |
| 262 | 302 | ||
| 263 | /// Unregisters a thread from this process, removing it | 303 | /// Unregisters a thread from this process, removing it |
| 264 | /// from this process' thread list. | 304 | /// from this process' thread list. |
| 265 | void UnregisterThread(const Thread* thread); | 305 | void UnregisterThread(const KThread* thread); |
| 266 | 306 | ||
| 267 | /// Clears the signaled state of the process if and only if it's signaled. | 307 | /// Clears the signaled state of the process if and only if it's signaled. |
| 268 | /// | 308 | /// |
| @@ -272,7 +312,7 @@ public: | |||
| 272 | /// @pre The process must be in a signaled state. If this is called on a | 312 | /// @pre The process must be in a signaled state. If this is called on a |
| 273 | /// process instance that is not signaled, ERR_INVALID_STATE will be | 313 | /// process instance that is not signaled, ERR_INVALID_STATE will be |
| 274 | /// returned. | 314 | /// returned. |
| 275 | ResultCode ClearSignalState(); | 315 | ResultCode Reset(); |
| 276 | 316 | ||
| 277 | /** | 317 | /** |
| 278 | * Loads process-specifics configuration info with metadata provided | 318 | * Loads process-specifics configuration info with metadata provided |
| @@ -303,6 +343,15 @@ public: | |||
| 303 | 343 | ||
| 304 | bool IsSignaled() const override; | 344 | bool IsSignaled() const override; |
| 305 | 345 | ||
| 346 | void Finalize() override {} | ||
| 347 | |||
| 348 | void PinCurrentThread(); | ||
| 349 | void UnpinCurrentThread(); | ||
| 350 | |||
| 351 | KLightLock& GetStateLock() { | ||
| 352 | return state_lock; | ||
| 353 | } | ||
| 354 | |||
| 306 | /////////////////////////////////////////////////////////////////////////////////////////////// | 355 | /////////////////////////////////////////////////////////////////////////////////////////////// |
| 307 | // Thread-local storage management | 356 | // Thread-local storage management |
| 308 | 357 | ||
| @@ -313,6 +362,20 @@ public: | |||
| 313 | void FreeTLSRegion(VAddr tls_address); | 362 | void FreeTLSRegion(VAddr tls_address); |
| 314 | 363 | ||
| 315 | private: | 364 | private: |
| 365 | void PinThread(s32 core_id, KThread* thread) { | ||
| 366 | ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||
| 367 | ASSERT(thread != nullptr); | ||
| 368 | ASSERT(pinned_threads[core_id] == nullptr); | ||
| 369 | pinned_threads[core_id] = thread; | ||
| 370 | } | ||
| 371 | |||
| 372 | void UnpinThread(s32 core_id, KThread* thread) { | ||
| 373 | ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||
| 374 | ASSERT(thread != nullptr); | ||
| 375 | ASSERT(pinned_threads[core_id] == thread); | ||
| 376 | pinned_threads[core_id] = nullptr; | ||
| 377 | } | ||
| 378 | |||
| 316 | /// Changes the process status. If the status is different | 379 | /// Changes the process status. If the status is different |
| 317 | /// from the current process status, then this will trigger | 380 | /// from the current process status, then this will trigger |
| 318 | /// a process signal. | 381 | /// a process signal. |
| @@ -339,7 +402,7 @@ private: | |||
| 339 | u32 system_resource_size = 0; | 402 | u32 system_resource_size = 0; |
| 340 | 403 | ||
| 341 | /// Resource limit descriptor for this process | 404 | /// Resource limit descriptor for this process |
| 342 | std::shared_ptr<ResourceLimit> resource_limit; | 405 | std::shared_ptr<KResourceLimit> resource_limit; |
| 343 | 406 | ||
| 344 | /// The ideal CPU core for this process, threads are scheduled on this core by default. | 407 | /// The ideal CPU core for this process, threads are scheduled on this core by default. |
| 345 | u8 ideal_core = 0; | 408 | u8 ideal_core = 0; |
| @@ -380,7 +443,7 @@ private: | |||
| 380 | std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{}; | 443 | std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{}; |
| 381 | 444 | ||
| 382 | /// List of threads that are running with this process as their owner. | 445 | /// List of threads that are running with this process as their owner. |
| 383 | std::list<const Thread*> thread_list; | 446 | std::list<const KThread*> thread_list; |
| 384 | 447 | ||
| 385 | /// Address of the top of the main thread's stack | 448 | /// Address of the top of the main thread's stack |
| 386 | VAddr main_thread_stack_top{}; | 449 | VAddr main_thread_stack_top{}; |
| @@ -401,6 +464,19 @@ private: | |||
| 401 | s64 schedule_count{}; | 464 | s64 schedule_count{}; |
| 402 | 465 | ||
| 403 | bool is_signaled{}; | 466 | bool is_signaled{}; |
| 467 | bool is_suspended{}; | ||
| 468 | |||
| 469 | std::atomic<s32> num_created_threads{}; | ||
| 470 | std::atomic<u16> num_threads{}; | ||
| 471 | u16 peak_num_threads{}; | ||
| 472 | |||
| 473 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{}; | ||
| 474 | std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{}; | ||
| 475 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> pinned_threads{}; | ||
| 476 | |||
| 477 | KThread* exception_thread{}; | ||
| 478 | |||
| 479 | KLightLock state_lock; | ||
| 404 | 480 | ||
| 405 | /// System context | 481 | /// System context |
| 406 | Core::System& system; | 482 | Core::System& system; |
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp deleted file mode 100644 index 99ed0857e..000000000 --- a/src/core/hle/kernel/readable_event.cpp +++ /dev/null | |||
| @@ -1,52 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "core/hle/kernel/errors.h" | ||
| 9 | #include "core/hle/kernel/k_scheduler.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/object.h" | ||
| 12 | #include "core/hle/kernel/readable_event.h" | ||
| 13 | #include "core/hle/kernel/thread.h" | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | |||
| 17 | ReadableEvent::ReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {} | ||
| 18 | ReadableEvent::~ReadableEvent() = default; | ||
| 19 | |||
| 20 | void ReadableEvent::Signal() { | ||
| 21 | if (is_signaled) { | ||
| 22 | return; | ||
| 23 | } | ||
| 24 | |||
| 25 | is_signaled = true; | ||
| 26 | NotifyAvailable(); | ||
| 27 | } | ||
| 28 | |||
| 29 | bool ReadableEvent::IsSignaled() const { | ||
| 30 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 31 | |||
| 32 | return is_signaled; | ||
| 33 | } | ||
| 34 | |||
| 35 | void ReadableEvent::Clear() { | ||
| 36 | is_signaled = false; | ||
| 37 | } | ||
| 38 | |||
| 39 | ResultCode ReadableEvent::Reset() { | ||
| 40 | KScopedSchedulerLock lock(kernel); | ||
| 41 | if (!is_signaled) { | ||
| 42 | LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}", | ||
| 43 | GetObjectId(), GetTypeName(), GetName()); | ||
| 44 | return ERR_INVALID_STATE; | ||
| 45 | } | ||
| 46 | |||
| 47 | Clear(); | ||
| 48 | |||
| 49 | return RESULT_SUCCESS; | ||
| 50 | } | ||
| 51 | |||
| 52 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h deleted file mode 100644 index 34e477274..000000000 --- a/src/core/hle/kernel/readable_event.h +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 8 | #include "core/hle/kernel/object.h" | ||
| 9 | |||
| 10 | union ResultCode; | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | class KernelCore; | ||
| 15 | class WritableEvent; | ||
| 16 | |||
| 17 | class ReadableEvent final : public KSynchronizationObject { | ||
| 18 | friend class WritableEvent; | ||
| 19 | |||
| 20 | public: | ||
| 21 | ~ReadableEvent() override; | ||
| 22 | |||
| 23 | std::string GetTypeName() const override { | ||
| 24 | return "ReadableEvent"; | ||
| 25 | } | ||
| 26 | std::string GetName() const override { | ||
| 27 | return name; | ||
| 28 | } | ||
| 29 | |||
| 30 | static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent; | ||
| 31 | HandleType GetHandleType() const override { | ||
| 32 | return HANDLE_TYPE; | ||
| 33 | } | ||
| 34 | |||
| 35 | /// Unconditionally clears the readable event's state. | ||
| 36 | void Clear(); | ||
| 37 | |||
| 38 | /// Clears the readable event's state if and only if it | ||
| 39 | /// has already been signaled. | ||
| 40 | /// | ||
| 41 | /// @pre The event must be in a signaled state. If this event | ||
| 42 | /// is in an unsignaled state and this function is called, | ||
| 43 | /// then ERR_INVALID_STATE will be returned. | ||
| 44 | ResultCode Reset(); | ||
| 45 | |||
| 46 | void Signal(); | ||
| 47 | |||
| 48 | bool IsSignaled() const override; | ||
| 49 | |||
| 50 | private: | ||
| 51 | explicit ReadableEvent(KernelCore& kernel); | ||
| 52 | |||
| 53 | bool is_signaled{}; | ||
| 54 | std::string name; ///< Name of event (optional) | ||
| 55 | }; | ||
| 56 | |||
| 57 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp deleted file mode 100644 index 7bf50339d..000000000 --- a/src/core/hle/kernel/resource_limit.cpp +++ /dev/null | |||
| @@ -1,73 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/errors.h" | ||
| 6 | #include "core/hle/kernel/resource_limit.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | namespace { | ||
| 11 | constexpr std::size_t ResourceTypeToIndex(ResourceType type) { | ||
| 12 | return static_cast<std::size_t>(type); | ||
| 13 | } | ||
| 14 | } // Anonymous namespace | ||
| 15 | |||
| 16 | ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} | ||
| 17 | ResourceLimit::~ResourceLimit() = default; | ||
| 18 | |||
| 19 | bool ResourceLimit::Reserve(ResourceType resource, s64 amount) { | ||
| 20 | return Reserve(resource, amount, 10000000000); | ||
| 21 | } | ||
| 22 | |||
| 23 | bool ResourceLimit::Reserve(ResourceType resource, s64 amount, u64 timeout) { | ||
| 24 | const std::size_t index{ResourceTypeToIndex(resource)}; | ||
| 25 | |||
| 26 | s64 new_value = current[index] + amount; | ||
| 27 | if (new_value > limit[index] && available[index] + amount <= limit[index]) { | ||
| 28 | // TODO(bunnei): This is wrong for multicore, we should wait the calling thread for timeout | ||
| 29 | new_value = current[index] + amount; | ||
| 30 | } | ||
| 31 | |||
| 32 | if (new_value <= limit[index]) { | ||
| 33 | current[index] = new_value; | ||
| 34 | return true; | ||
| 35 | } | ||
| 36 | return false; | ||
| 37 | } | ||
| 38 | |||
| 39 | void ResourceLimit::Release(ResourceType resource, u64 amount) { | ||
| 40 | Release(resource, amount, amount); | ||
| 41 | } | ||
| 42 | |||
| 43 | void ResourceLimit::Release(ResourceType resource, u64 used_amount, u64 available_amount) { | ||
| 44 | const std::size_t index{ResourceTypeToIndex(resource)}; | ||
| 45 | |||
| 46 | current[index] -= used_amount; | ||
| 47 | available[index] -= available_amount; | ||
| 48 | } | ||
| 49 | |||
| 50 | std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) { | ||
| 51 | return std::make_shared<ResourceLimit>(kernel); | ||
| 52 | } | ||
| 53 | |||
| 54 | s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { | ||
| 55 | return limit.at(ResourceTypeToIndex(resource)) - current.at(ResourceTypeToIndex(resource)); | ||
| 56 | } | ||
| 57 | |||
| 58 | s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { | ||
| 59 | return limit.at(ResourceTypeToIndex(resource)); | ||
| 60 | } | ||
| 61 | |||
| 62 | ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) { | ||
| 63 | const std::size_t index{ResourceTypeToIndex(resource)}; | ||
| 64 | if (current[index] <= value) { | ||
| 65 | limit[index] = value; | ||
| 66 | return RESULT_SUCCESS; | ||
| 67 | } else { | ||
| 68 | LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", resource, | ||
| 69 | value, index); | ||
| 70 | return ERR_INVALID_STATE; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h deleted file mode 100644 index 936cc4d0f..000000000 --- a/src/core/hle/kernel/resource_limit.h +++ /dev/null | |||
| @@ -1,104 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <memory> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/kernel/object.h" | ||
| 12 | |||
| 13 | union ResultCode; | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | |||
| 17 | class KernelCore; | ||
| 18 | |||
| 19 | enum class ResourceType : u32 { | ||
| 20 | PhysicalMemory, | ||
| 21 | Threads, | ||
| 22 | Events, | ||
| 23 | TransferMemory, | ||
| 24 | Sessions, | ||
| 25 | |||
| 26 | // Used as a count, not an actual type. | ||
| 27 | ResourceTypeCount | ||
| 28 | }; | ||
| 29 | |||
| 30 | constexpr bool IsValidResourceType(ResourceType type) { | ||
| 31 | return type < ResourceType::ResourceTypeCount; | ||
| 32 | } | ||
| 33 | |||
| 34 | class ResourceLimit final : public Object { | ||
| 35 | public: | ||
| 36 | explicit ResourceLimit(KernelCore& kernel); | ||
| 37 | ~ResourceLimit() override; | ||
| 38 | |||
| 39 | /// Creates a resource limit object. | ||
| 40 | static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel); | ||
| 41 | |||
| 42 | std::string GetTypeName() const override { | ||
| 43 | return "ResourceLimit"; | ||
| 44 | } | ||
| 45 | std::string GetName() const override { | ||
| 46 | return GetTypeName(); | ||
| 47 | } | ||
| 48 | |||
| 49 | static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit; | ||
| 50 | HandleType GetHandleType() const override { | ||
| 51 | return HANDLE_TYPE; | ||
| 52 | } | ||
| 53 | |||
| 54 | bool Reserve(ResourceType resource, s64 amount); | ||
| 55 | bool Reserve(ResourceType resource, s64 amount, u64 timeout); | ||
| 56 | void Release(ResourceType resource, u64 amount); | ||
| 57 | void Release(ResourceType resource, u64 used_amount, u64 available_amount); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Gets the current value for the specified resource. | ||
| 61 | * @param resource Requested resource type | ||
| 62 | * @returns The current value of the resource type | ||
| 63 | */ | ||
| 64 | s64 GetCurrentResourceValue(ResourceType resource) const; | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Gets the max value for the specified resource. | ||
| 68 | * @param resource Requested resource type | ||
| 69 | * @returns The max value of the resource type | ||
| 70 | */ | ||
| 71 | s64 GetMaxResourceValue(ResourceType resource) const; | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Sets the limit value for a given resource type. | ||
| 75 | * | ||
| 76 | * @param resource The resource type to apply the limit to. | ||
| 77 | * @param value The limit to apply to the given resource type. | ||
| 78 | * | ||
| 79 | * @return A result code indicating if setting the limit value | ||
| 80 | * was successful or not. | ||
| 81 | * | ||
| 82 | * @note The supplied limit value *must* be greater than or equal to | ||
| 83 | * the current resource value for the given resource type, | ||
| 84 | * otherwise ERR_INVALID_STATE will be returned. | ||
| 85 | */ | ||
| 86 | ResultCode SetLimitValue(ResourceType resource, s64 value); | ||
| 87 | |||
| 88 | private: | ||
| 89 | // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create | ||
| 90 | // functions | ||
| 91 | // | ||
| 92 | // Currently we have no way of distinguishing if a Create was called by the running application, | ||
| 93 | // or by a service module. Approach this once we have separated the service modules into their | ||
| 94 | // own processes | ||
| 95 | |||
| 96 | using ResourceArray = | ||
| 97 | std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>; | ||
| 98 | |||
| 99 | ResourceArray limit{}; | ||
| 100 | ResourceArray current{}; | ||
| 101 | ResourceArray available{}; | ||
| 102 | }; | ||
| 103 | |||
| 104 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 82857f93b..fe7a483c4 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp | |||
| @@ -6,10 +6,10 @@ | |||
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/hle/kernel/client_port.h" | 7 | #include "core/hle/kernel/client_port.h" |
| 8 | #include "core/hle/kernel/errors.h" | 8 | #include "core/hle/kernel/errors.h" |
| 9 | #include "core/hle/kernel/k_thread.h" | ||
| 9 | #include "core/hle/kernel/object.h" | 10 | #include "core/hle/kernel/object.h" |
| 10 | #include "core/hle/kernel/server_port.h" | 11 | #include "core/hle/kernel/server_port.h" |
| 11 | #include "core/hle/kernel/server_session.h" | 12 | #include "core/hle/kernel/server_session.h" |
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 6470df993..29b4f2509 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h | |||
| @@ -81,6 +81,8 @@ public: | |||
| 81 | 81 | ||
| 82 | bool IsSignaled() const override; | 82 | bool IsSignaled() const override; |
| 83 | 83 | ||
| 84 | void Finalize() override {} | ||
| 85 | |||
| 84 | private: | 86 | private: |
| 85 | /// ServerSessions waiting to be accepted by the port | 87 | /// ServerSessions waiting to be accepted by the port |
| 86 | std::vector<std::shared_ptr<ServerSession>> pending_sessions; | 88 | std::vector<std::shared_ptr<ServerSession>> pending_sessions; |
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 4f2bb7822..790dbb998 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -15,11 +15,11 @@ | |||
| 15 | #include "core/hle/kernel/handle_table.h" | 15 | #include "core/hle/kernel/handle_table.h" |
| 16 | #include "core/hle/kernel/hle_ipc.h" | 16 | #include "core/hle/kernel/hle_ipc.h" |
| 17 | #include "core/hle/kernel/k_scheduler.h" | 17 | #include "core/hle/kernel/k_scheduler.h" |
| 18 | #include "core/hle/kernel/k_thread.h" | ||
| 18 | #include "core/hle/kernel/kernel.h" | 19 | #include "core/hle/kernel/kernel.h" |
| 19 | #include "core/hle/kernel/process.h" | 20 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/server_session.h" | 21 | #include "core/hle/kernel/server_session.h" |
| 21 | #include "core/hle/kernel/session.h" | 22 | #include "core/hle/kernel/session.h" |
| 22 | #include "core/hle/kernel/thread.h" | ||
| 23 | #include "core/memory.h" | 23 | #include "core/memory.h" |
| 24 | 24 | ||
| 25 | namespace Kernel { | 25 | namespace Kernel { |
| @@ -116,7 +116,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con | |||
| 116 | return RESULT_SUCCESS; | 116 | return RESULT_SUCCESS; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, | 119 | ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<KThread> thread, |
| 120 | Core::Memory::Memory& memory) { | 120 | Core::Memory::Memory& memory) { |
| 121 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; | 121 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; |
| 122 | auto context = | 122 | auto context = |
| @@ -154,14 +154,14 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 154 | KScopedSchedulerLock lock(kernel); | 154 | KScopedSchedulerLock lock(kernel); |
| 155 | if (!context.IsThreadWaiting()) { | 155 | if (!context.IsThreadWaiting()) { |
| 156 | context.GetThread().Wakeup(); | 156 | context.GetThread().Wakeup(); |
| 157 | context.GetThread().SetSynchronizationResults(nullptr, result); | 157 | context.GetThread().SetSyncedObject(nullptr, result); |
| 158 | } | 158 | } |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | return result; | 161 | return result; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, | 164 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<KThread> thread, |
| 165 | Core::Memory::Memory& memory, | 165 | Core::Memory::Memory& memory, |
| 166 | Core::Timing::CoreTiming& core_timing) { | 166 | Core::Timing::CoreTiming& core_timing) { |
| 167 | return QueueSyncRequest(std::move(thread), memory); | 167 | return QueueSyncRequest(std::move(thread), memory); |
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 9155cf7f5..c42d5ee59 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -29,7 +29,7 @@ class HLERequestContext; | |||
| 29 | class KernelCore; | 29 | class KernelCore; |
| 30 | class Session; | 30 | class Session; |
| 31 | class SessionRequestHandler; | 31 | class SessionRequestHandler; |
| 32 | class Thread; | 32 | class KThread; |
| 33 | 33 | ||
| 34 | /** | 34 | /** |
| 35 | * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS | 35 | * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS |
| @@ -95,7 +95,7 @@ public: | |||
| 95 | * | 95 | * |
| 96 | * @returns ResultCode from the operation. | 96 | * @returns ResultCode from the operation. |
| 97 | */ | 97 | */ |
| 98 | ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory, | 98 | ResultCode HandleSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory, |
| 99 | Core::Timing::CoreTiming& core_timing); | 99 | Core::Timing::CoreTiming& core_timing); |
| 100 | 100 | ||
| 101 | /// Called when a client disconnection occurs. | 101 | /// Called when a client disconnection occurs. |
| @@ -126,9 +126,11 @@ public: | |||
| 126 | 126 | ||
| 127 | bool IsSignaled() const override; | 127 | bool IsSignaled() const override; |
| 128 | 128 | ||
| 129 | void Finalize() override {} | ||
| 130 | |||
| 129 | private: | 131 | private: |
| 130 | /// Queues a sync request from the emulated application. | 132 | /// Queues a sync request from the emulated application. |
| 131 | ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); | 133 | ResultCode QueueSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory); |
| 132 | 134 | ||
| 133 | /// Completes a sync request from the emulated application. | 135 | /// Completes a sync request from the emulated application. |
| 134 | ResultCode CompleteSyncRequest(HLERequestContext& context); | 136 | ResultCode CompleteSyncRequest(HLERequestContext& context); |
| @@ -149,12 +151,12 @@ private: | |||
| 149 | /// List of threads that are pending a response after a sync request. This list is processed in | 151 | /// List of threads that are pending a response after a sync request. This list is processed in |
| 150 | /// a LIFO manner, thus, the last request will be dispatched first. | 152 | /// a LIFO manner, thus, the last request will be dispatched first. |
| 151 | /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. | 153 | /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. |
| 152 | std::vector<std::shared_ptr<Thread>> pending_requesting_threads; | 154 | std::vector<std::shared_ptr<KThread>> pending_requesting_threads; |
| 153 | 155 | ||
| 154 | /// Thread whose request is currently being handled. A request is considered "handled" when a | 156 | /// Thread whose request is currently being handled. A request is considered "handled" when a |
| 155 | /// response is sent via svcReplyAndReceive. | 157 | /// response is sent via svcReplyAndReceive. |
| 156 | /// TODO(Subv): Find a better name for this. | 158 | /// TODO(Subv): Find a better name for this. |
| 157 | std::shared_ptr<Thread> currently_handling; | 159 | std::shared_ptr<KThread> currently_handling; |
| 158 | 160 | ||
| 159 | /// When set to True, converts the session to a domain at the end of the command | 161 | /// When set to True, converts the session to a domain at the end of the command |
| 160 | bool convert_to_domain{}; | 162 | bool convert_to_domain{}; |
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index f6dd2c1d2..fa3c5651a 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h | |||
| @@ -39,6 +39,8 @@ public: | |||
| 39 | 39 | ||
| 40 | bool IsSignaled() const override; | 40 | bool IsSignaled() const override; |
| 41 | 41 | ||
| 42 | void Finalize() override {} | ||
| 43 | |||
| 42 | std::shared_ptr<ClientSession> Client() { | 44 | std::shared_ptr<ClientSession> Client() { |
| 43 | if (auto result{client.lock()}) { | 45 | if (auto result{client.lock()}) { |
| 44 | return result; | 46 | return result; |
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 0ef87235c..623bd8b11 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -71,6 +71,8 @@ public: | |||
| 71 | return device_memory.GetPointer(physical_address + offset); | 71 | return device_memory.GetPointer(physical_address + offset); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | void Finalize() override {} | ||
| 75 | |||
| 74 | private: | 76 | private: |
| 75 | Core::DeviceMemory& device_memory; | 77 | Core::DeviceMemory& device_memory; |
| 76 | Process* owner_process{}; | 78 | Process* owner_process{}; |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index cc8b661af..26650a513 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "common/fiber.h" | 14 | #include "common/fiber.h" |
| 15 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 16 | #include "common/microprofile.h" | 16 | #include "common/microprofile.h" |
| 17 | #include "common/scope_exit.h" | ||
| 17 | #include "common/string_util.h" | 18 | #include "common/string_util.h" |
| 18 | #include "core/arm/exclusive_monitor.h" | 19 | #include "core/arm/exclusive_monitor.h" |
| 19 | #include "core/core.h" | 20 | #include "core/core.h" |
| @@ -26,26 +27,27 @@ | |||
| 26 | #include "core/hle/kernel/handle_table.h" | 27 | #include "core/hle/kernel/handle_table.h" |
| 27 | #include "core/hle/kernel/k_address_arbiter.h" | 28 | #include "core/hle/kernel/k_address_arbiter.h" |
| 28 | #include "core/hle/kernel/k_condition_variable.h" | 29 | #include "core/hle/kernel/k_condition_variable.h" |
| 30 | #include "core/hle/kernel/k_event.h" | ||
| 31 | #include "core/hle/kernel/k_readable_event.h" | ||
| 32 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 29 | #include "core/hle/kernel/k_scheduler.h" | 33 | #include "core/hle/kernel/k_scheduler.h" |
| 30 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 34 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 31 | #include "core/hle/kernel/k_synchronization_object.h" | 35 | #include "core/hle/kernel/k_synchronization_object.h" |
| 36 | #include "core/hle/kernel/k_thread.h" | ||
| 37 | #include "core/hle/kernel/k_writable_event.h" | ||
| 32 | #include "core/hle/kernel/kernel.h" | 38 | #include "core/hle/kernel/kernel.h" |
| 33 | #include "core/hle/kernel/memory/memory_block.h" | 39 | #include "core/hle/kernel/memory/memory_block.h" |
| 34 | #include "core/hle/kernel/memory/memory_layout.h" | 40 | #include "core/hle/kernel/memory/memory_layout.h" |
| 35 | #include "core/hle/kernel/memory/page_table.h" | 41 | #include "core/hle/kernel/memory/page_table.h" |
| 36 | #include "core/hle/kernel/physical_core.h" | 42 | #include "core/hle/kernel/physical_core.h" |
| 37 | #include "core/hle/kernel/process.h" | 43 | #include "core/hle/kernel/process.h" |
| 38 | #include "core/hle/kernel/readable_event.h" | ||
| 39 | #include "core/hle/kernel/resource_limit.h" | ||
| 40 | #include "core/hle/kernel/shared_memory.h" | 44 | #include "core/hle/kernel/shared_memory.h" |
| 41 | #include "core/hle/kernel/svc.h" | 45 | #include "core/hle/kernel/svc.h" |
| 42 | #include "core/hle/kernel/svc_results.h" | 46 | #include "core/hle/kernel/svc_results.h" |
| 43 | #include "core/hle/kernel/svc_types.h" | 47 | #include "core/hle/kernel/svc_types.h" |
| 44 | #include "core/hle/kernel/svc_wrap.h" | 48 | #include "core/hle/kernel/svc_wrap.h" |
| 45 | #include "core/hle/kernel/thread.h" | ||
| 46 | #include "core/hle/kernel/time_manager.h" | 49 | #include "core/hle/kernel/time_manager.h" |
| 47 | #include "core/hle/kernel/transfer_memory.h" | 50 | #include "core/hle/kernel/transfer_memory.h" |
| 48 | #include "core/hle/kernel/writable_event.h" | ||
| 49 | #include "core/hle/lock.h" | 51 | #include "core/hle/lock.h" |
| 50 | #include "core/hle/result.h" | 52 | #include "core/hle/result.h" |
| 51 | #include "core/hle/service/service.h" | 53 | #include "core/hle/service/service.h" |
| @@ -141,7 +143,7 @@ enum class ResourceLimitValueType { | |||
| 141 | ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, | 143 | ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, |
| 142 | u32 resource_type, ResourceLimitValueType value_type) { | 144 | u32 resource_type, ResourceLimitValueType value_type) { |
| 143 | std::lock_guard lock{HLE::g_hle_lock}; | 145 | std::lock_guard lock{HLE::g_hle_lock}; |
| 144 | const auto type = static_cast<ResourceType>(resource_type); | 146 | const auto type = static_cast<LimitableResource>(resource_type); |
| 145 | if (!IsValidResourceType(type)) { | 147 | if (!IsValidResourceType(type)) { |
| 146 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | 148 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); |
| 147 | return ERR_INVALID_ENUM_VALUE; | 149 | return ERR_INVALID_ENUM_VALUE; |
| @@ -151,7 +153,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_ | |||
| 151 | ASSERT(current_process != nullptr); | 153 | ASSERT(current_process != nullptr); |
| 152 | 154 | ||
| 153 | const auto resource_limit_object = | 155 | const auto resource_limit_object = |
| 154 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | 156 | current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); |
| 155 | if (!resource_limit_object) { | 157 | if (!resource_limit_object) { |
| 156 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | 158 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", |
| 157 | resource_limit); | 159 | resource_limit); |
| @@ -159,10 +161,10 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_ | |||
| 159 | } | 161 | } |
| 160 | 162 | ||
| 161 | if (value_type == ResourceLimitValueType::CurrentValue) { | 163 | if (value_type == ResourceLimitValueType::CurrentValue) { |
| 162 | return MakeResult(resource_limit_object->GetCurrentResourceValue(type)); | 164 | return MakeResult(resource_limit_object->GetCurrentValue(type)); |
| 163 | } | 165 | } |
| 164 | 166 | ||
| 165 | return MakeResult(resource_limit_object->GetMaxResourceValue(type)); | 167 | return MakeResult(resource_limit_object->GetLimitValue(type)); |
| 166 | } | 168 | } |
| 167 | } // Anonymous namespace | 169 | } // Anonymous namespace |
| 168 | 170 | ||
| @@ -312,7 +314,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, | |||
| 312 | return ERR_NOT_FOUND; | 314 | return ERR_NOT_FOUND; |
| 313 | } | 315 | } |
| 314 | 316 | ||
| 315 | ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Sessions, 1)); | 317 | ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::Sessions, 1)); |
| 316 | 318 | ||
| 317 | auto client_port = it->second; | 319 | auto client_port = it->second; |
| 318 | 320 | ||
| @@ -351,7 +353,8 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | |||
| 351 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); | 353 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); |
| 352 | } | 354 | } |
| 353 | 355 | ||
| 354 | return thread->GetSignalingResult(); | 356 | KSynchronizationObject* dummy{}; |
| 357 | return thread->GetWaitResult(std::addressof(dummy)); | ||
| 355 | } | 358 | } |
| 356 | 359 | ||
| 357 | static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { | 360 | static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { |
| @@ -359,27 +362,29 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { | |||
| 359 | } | 362 | } |
| 360 | 363 | ||
| 361 | /// Get the ID for the specified thread. | 364 | /// Get the ID for the specified thread. |
| 362 | static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) { | 365 | static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { |
| 363 | LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | 366 | LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); |
| 364 | 367 | ||
| 368 | // Get the thread from its handle. | ||
| 365 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 369 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 366 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 370 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 367 | if (!thread) { | 371 | if (!thread) { |
| 368 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle); | 372 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); |
| 369 | return ERR_INVALID_HANDLE; | 373 | return ResultInvalidHandle; |
| 370 | } | 374 | } |
| 371 | 375 | ||
| 372 | *thread_id = thread->GetThreadID(); | 376 | // Get the thread's id. |
| 377 | *out_thread_id = thread->GetThreadID(); | ||
| 373 | return RESULT_SUCCESS; | 378 | return RESULT_SUCCESS; |
| 374 | } | 379 | } |
| 375 | 380 | ||
| 376 | static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high, | 381 | static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low, |
| 377 | Handle thread_handle) { | 382 | u32* out_thread_id_high, Handle thread_handle) { |
| 378 | u64 thread_id{}; | 383 | u64 out_thread_id{}; |
| 379 | const ResultCode result{GetThreadId(system, &thread_id, thread_handle)}; | 384 | const ResultCode result{GetThreadId(system, &out_thread_id, thread_handle)}; |
| 380 | 385 | ||
| 381 | *thread_id_low = static_cast<u32>(thread_id >> 32); | 386 | *out_thread_id_low = static_cast<u32>(out_thread_id >> 32); |
| 382 | *thread_id_high = static_cast<u32>(thread_id & std::numeric_limits<u32>::max()); | 387 | *out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max()); |
| 383 | 388 | ||
| 384 | return result; | 389 | return result; |
| 385 | } | 390 | } |
| @@ -395,7 +400,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han | |||
| 395 | return RESULT_SUCCESS; | 400 | return RESULT_SUCCESS; |
| 396 | } | 401 | } |
| 397 | 402 | ||
| 398 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); | 403 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 399 | if (thread) { | 404 | if (thread) { |
| 400 | const Process* const owner_process = thread->GetOwnerProcess(); | 405 | const Process* const owner_process = thread->GetOwnerProcess(); |
| 401 | if (!owner_process) { | 406 | if (!owner_process) { |
| @@ -473,15 +478,16 @@ static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u | |||
| 473 | static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { | 478 | static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { |
| 474 | LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); | 479 | LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); |
| 475 | 480 | ||
| 481 | // Get the thread from its handle. | ||
| 476 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 482 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 477 | std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 483 | std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 478 | if (!thread) { | 484 | if (!thread) { |
| 479 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | 485 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); |
| 480 | thread_handle); | 486 | return ResultInvalidHandle; |
| 481 | return ERR_INVALID_HANDLE; | ||
| 482 | } | 487 | } |
| 483 | 488 | ||
| 484 | thread->CancelWait(); | 489 | // Cancel the thread's wait. |
| 490 | thread->WaitCancel(); | ||
| 485 | return RESULT_SUCCESS; | 491 | return RESULT_SUCCESS; |
| 486 | } | 492 | } |
| 487 | 493 | ||
| @@ -496,8 +502,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd | |||
| 496 | thread_handle, address, tag); | 502 | thread_handle, address, tag); |
| 497 | 503 | ||
| 498 | // Validate the input address. | 504 | // Validate the input address. |
| 499 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 505 | if (Memory::IsKernelAddress(address)) { |
| 500 | R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); | 506 | LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})", |
| 507 | address); | ||
| 508 | return ResultInvalidCurrentMemory; | ||
| 509 | } | ||
| 510 | if (!Common::IsAligned(address, sizeof(u32))) { | ||
| 511 | LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address); | ||
| 512 | return ResultInvalidAddress; | ||
| 513 | } | ||
| 501 | 514 | ||
| 502 | return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); | 515 | return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); |
| 503 | } | 516 | } |
| @@ -512,8 +525,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) { | |||
| 512 | LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); | 525 | LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); |
| 513 | 526 | ||
| 514 | // Validate the input address. | 527 | // Validate the input address. |
| 515 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 528 | if (Memory::IsKernelAddress(address)) { |
| 516 | R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); | 529 | LOG_ERROR(Kernel_SVC, |
| 530 | "Attempting to arbitrate an unlock on a kernel address (address={:08X})", | ||
| 531 | address); | ||
| 532 | return ResultInvalidCurrentMemory; | ||
| 533 | } | ||
| 534 | if (!Common::IsAligned(address, sizeof(u32))) { | ||
| 535 | LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address); | ||
| 536 | return ResultInvalidAddress; | ||
| 537 | } | ||
| 517 | 538 | ||
| 518 | return system.Kernel().CurrentProcess()->SignalToAddress(address); | 539 | return system.Kernel().CurrentProcess()->SignalToAddress(address); |
| 519 | } | 540 | } |
| @@ -630,7 +651,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { | |||
| 630 | handle_debug_buffer(info1, info2); | 651 | handle_debug_buffer(info1, info2); |
| 631 | 652 | ||
| 632 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 653 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 633 | const auto thread_processor_id = current_thread->GetProcessorID(); | 654 | const auto thread_processor_id = current_thread->GetActiveCore(); |
| 634 | system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); | 655 | system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); |
| 635 | } | 656 | } |
| 636 | } | 657 | } |
| @@ -872,7 +893,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 872 | return ERR_INVALID_COMBINATION; | 893 | return ERR_INVALID_COMBINATION; |
| 873 | } | 894 | } |
| 874 | 895 | ||
| 875 | const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<Thread>( | 896 | const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>( |
| 876 | static_cast<Handle>(handle)); | 897 | static_cast<Handle>(handle)); |
| 877 | if (!thread) { | 898 | if (!thread) { |
| 878 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", | 899 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", |
| @@ -888,7 +909,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 888 | const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); | 909 | const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); |
| 889 | u64 out_ticks = 0; | 910 | u64 out_ticks = 0; |
| 890 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { | 911 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { |
| 891 | const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); | 912 | const u64 thread_ticks = current_thread->GetCpuTime(); |
| 892 | 913 | ||
| 893 | out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); | 914 | out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); |
| 894 | } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { | 915 | } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { |
| @@ -1026,128 +1047,139 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size | |||
| 1026 | } | 1047 | } |
| 1027 | 1048 | ||
| 1028 | /// Sets the thread activity | 1049 | /// Sets the thread activity |
| 1029 | static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { | 1050 | static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, |
| 1030 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); | 1051 | ThreadActivity thread_activity) { |
| 1031 | if (activity > static_cast<u32>(ThreadActivity::Paused)) { | 1052 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, |
| 1032 | return ERR_INVALID_ENUM_VALUE; | 1053 | thread_activity); |
| 1054 | |||
| 1055 | // Validate the activity. | ||
| 1056 | constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { | ||
| 1057 | return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; | ||
| 1058 | }; | ||
| 1059 | if (!IsValidThreadActivity(thread_activity)) { | ||
| 1060 | LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})", | ||
| 1061 | thread_activity); | ||
| 1062 | return ResultInvalidEnumValue; | ||
| 1033 | } | 1063 | } |
| 1034 | 1064 | ||
| 1035 | const auto* current_process = system.Kernel().CurrentProcess(); | 1065 | // Get the thread from its handle. |
| 1036 | const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 1066 | auto& kernel = system.Kernel(); |
| 1067 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||
| 1068 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | ||
| 1037 | if (!thread) { | 1069 | if (!thread) { |
| 1038 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | 1070 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); |
| 1039 | return ERR_INVALID_HANDLE; | 1071 | return ResultInvalidHandle; |
| 1040 | } | 1072 | } |
| 1041 | 1073 | ||
| 1042 | if (thread->GetOwnerProcess() != current_process) { | 1074 | // Check that the activity is being set on a non-current thread for the current process. |
| 1043 | LOG_ERROR(Kernel_SVC, | 1075 | if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { |
| 1044 | "The current process does not own the current thread, thread_handle={:08X} " | 1076 | LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread."); |
| 1045 | "thread_pid={}, " | 1077 | return ResultInvalidHandle; |
| 1046 | "current_process_pid={}", | 1078 | } |
| 1047 | handle, thread->GetOwnerProcess()->GetProcessID(), | 1079 | if (thread.get() == GetCurrentThreadPointer(kernel)) { |
| 1048 | current_process->GetProcessID()); | 1080 | LOG_ERROR(Kernel_SVC, "Thread is busy"); |
| 1049 | return ERR_INVALID_HANDLE; | 1081 | return ResultBusy; |
| 1050 | } | 1082 | } |
| 1051 | 1083 | ||
| 1052 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { | 1084 | // Set the activity. |
| 1053 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); | 1085 | const auto set_result = thread->SetActivity(thread_activity); |
| 1054 | return ERR_BUSY; | 1086 | if (set_result.IsError()) { |
| 1087 | LOG_ERROR(Kernel_SVC, "Failed to set thread activity."); | ||
| 1088 | return set_result; | ||
| 1055 | } | 1089 | } |
| 1056 | 1090 | ||
| 1057 | return thread->SetActivity(static_cast<ThreadActivity>(activity)); | 1091 | return RESULT_SUCCESS; |
| 1058 | } | 1092 | } |
| 1059 | 1093 | ||
| 1060 | static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) { | 1094 | static ResultCode SetThreadActivity32(Core::System& system, Handle thread_handle, |
| 1061 | return SetThreadActivity(system, handle, activity); | 1095 | Svc::ThreadActivity thread_activity) { |
| 1096 | return SetThreadActivity(system, thread_handle, thread_activity); | ||
| 1062 | } | 1097 | } |
| 1063 | 1098 | ||
| 1064 | /// Gets the thread context | 1099 | /// Gets the thread context |
| 1065 | static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { | 1100 | static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) { |
| 1066 | LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); | 1101 | LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, |
| 1102 | thread_handle); | ||
| 1067 | 1103 | ||
| 1104 | // Get the thread from its handle. | ||
| 1068 | const auto* current_process = system.Kernel().CurrentProcess(); | 1105 | const auto* current_process = system.Kernel().CurrentProcess(); |
| 1069 | const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 1106 | const std::shared_ptr<KThread> thread = |
| 1107 | current_process->GetHandleTable().Get<KThread>(thread_handle); | ||
| 1070 | if (!thread) { | 1108 | if (!thread) { |
| 1071 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | 1109 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle); |
| 1072 | return ERR_INVALID_HANDLE; | 1110 | return ResultInvalidHandle; |
| 1073 | } | 1111 | } |
| 1074 | 1112 | ||
| 1113 | // Require the handle be to a non-current thread in the current process. | ||
| 1075 | if (thread->GetOwnerProcess() != current_process) { | 1114 | if (thread->GetOwnerProcess() != current_process) { |
| 1076 | LOG_ERROR(Kernel_SVC, | 1115 | LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); |
| 1077 | "The current process does not own the current thread, thread_handle={:08X} " | 1116 | return ResultInvalidHandle; |
| 1078 | "thread_pid={}, " | ||
| 1079 | "current_process_pid={}", | ||
| 1080 | handle, thread->GetOwnerProcess()->GetProcessID(), | ||
| 1081 | current_process->GetProcessID()); | ||
| 1082 | return ERR_INVALID_HANDLE; | ||
| 1083 | } | 1117 | } |
| 1084 | |||
| 1085 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { | 1118 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { |
| 1086 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); | 1119 | LOG_ERROR(Kernel_SVC, "Current thread is busy."); |
| 1087 | return ERR_BUSY; | 1120 | return ResultBusy; |
| 1088 | } | 1121 | } |
| 1089 | 1122 | ||
| 1090 | Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64(); | 1123 | // Get the thread context. |
| 1091 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | 1124 | std::vector<u8> context; |
| 1092 | ctx.pstate &= 0xFF0FFE20; | 1125 | const auto context_result = thread->GetThreadContext3(context); |
| 1093 | 1126 | if (context_result.IsError()) { | |
| 1094 | // If 64-bit, we can just write the context registers directly and we're good. | 1127 | LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})", |
| 1095 | // However, if 32-bit, we have to ensure some registers are zeroed out. | 1128 | context_result.raw); |
| 1096 | if (!current_process->Is64BitProcess()) { | 1129 | return context_result; |
| 1097 | std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0); | ||
| 1098 | std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); | ||
| 1099 | } | 1130 | } |
| 1100 | 1131 | ||
| 1101 | system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx)); | 1132 | // Copy the thread context to user space. |
| 1133 | system.Memory().WriteBlock(out_context, context.data(), context.size()); | ||
| 1134 | |||
| 1102 | return RESULT_SUCCESS; | 1135 | return RESULT_SUCCESS; |
| 1103 | } | 1136 | } |
| 1104 | 1137 | ||
| 1105 | static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { | 1138 | static ResultCode GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) { |
| 1106 | return GetThreadContext(system, thread_context, handle); | 1139 | return GetThreadContext(system, out_context, thread_handle); |
| 1107 | } | 1140 | } |
| 1108 | 1141 | ||
| 1109 | /// Gets the priority for the specified thread | 1142 | /// Gets the priority for the specified thread |
| 1110 | static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) { | 1143 | static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) { |
| 1111 | LOG_TRACE(Kernel_SVC, "called"); | 1144 | LOG_TRACE(Kernel_SVC, "called"); |
| 1112 | 1145 | ||
| 1146 | // Get the thread from its handle. | ||
| 1113 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1147 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1114 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); | 1148 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 1115 | if (!thread) { | 1149 | if (!thread) { |
| 1116 | *priority = 0; | 1150 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle); |
| 1117 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | 1151 | return ResultInvalidHandle; |
| 1118 | return ERR_INVALID_HANDLE; | ||
| 1119 | } | 1152 | } |
| 1120 | 1153 | ||
| 1121 | *priority = thread->GetPriority(); | 1154 | // Get the thread's priority. |
| 1155 | *out_priority = thread->GetPriority(); | ||
| 1122 | return RESULT_SUCCESS; | 1156 | return RESULT_SUCCESS; |
| 1123 | } | 1157 | } |
| 1124 | 1158 | ||
| 1125 | static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) { | 1159 | static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) { |
| 1126 | return GetThreadPriority(system, priority, handle); | 1160 | return GetThreadPriority(system, out_priority, handle); |
| 1127 | } | 1161 | } |
| 1128 | 1162 | ||
| 1129 | /// Sets the priority for the specified thread | 1163 | /// Sets the priority for the specified thread |
| 1130 | static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { | 1164 | static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { |
| 1131 | LOG_TRACE(Kernel_SVC, "called"); | 1165 | LOG_TRACE(Kernel_SVC, "called"); |
| 1132 | 1166 | ||
| 1133 | if (priority > THREADPRIO_LOWEST) { | 1167 | // Validate the priority. |
| 1134 | LOG_ERROR( | 1168 | if (HighestThreadPriority > priority || priority > LowestThreadPriority) { |
| 1135 | Kernel_SVC, | 1169 | LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); |
| 1136 | "An invalid priority was specified, expected {} but got {} for thread_handle={:08X}", | 1170 | return ResultInvalidPriority; |
| 1137 | THREADPRIO_LOWEST, priority, handle); | ||
| 1138 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 1139 | } | 1171 | } |
| 1140 | 1172 | ||
| 1141 | const auto* const current_process = system.Kernel().CurrentProcess(); | 1173 | // Get the thread from its handle. |
| 1142 | 1174 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | |
| 1143 | std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 1175 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 1144 | if (!thread) { | 1176 | if (!thread) { |
| 1145 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | 1177 | LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle); |
| 1146 | return ERR_INVALID_HANDLE; | 1178 | return ResultInvalidHandle; |
| 1147 | } | 1179 | } |
| 1148 | 1180 | ||
| 1181 | // Set the thread priority. | ||
| 1149 | thread->SetBasePriority(priority); | 1182 | thread->SetBasePriority(priority); |
| 1150 | |||
| 1151 | return RESULT_SUCCESS; | 1183 | return RESULT_SUCCESS; |
| 1152 | } | 1184 | } |
| 1153 | 1185 | ||
| @@ -1438,62 +1470,62 @@ static void ExitProcess(Core::System& system) { | |||
| 1438 | current_process->PrepareForTermination(); | 1470 | current_process->PrepareForTermination(); |
| 1439 | 1471 | ||
| 1440 | // Kill the current thread | 1472 | // Kill the current thread |
| 1441 | system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop(); | 1473 | system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit(); |
| 1442 | } | 1474 | } |
| 1443 | 1475 | ||
| 1444 | static void ExitProcess32(Core::System& system) { | 1476 | static void ExitProcess32(Core::System& system) { |
| 1445 | ExitProcess(system); | 1477 | ExitProcess(system); |
| 1446 | } | 1478 | } |
| 1447 | 1479 | ||
| 1480 | static constexpr bool IsValidCoreId(int32_t core_id) { | ||
| 1481 | return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); | ||
| 1482 | } | ||
| 1483 | |||
| 1448 | /// Creates a new thread | 1484 | /// Creates a new thread |
| 1449 | static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, | 1485 | static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, |
| 1450 | VAddr stack_top, u32 priority, s32 processor_id) { | 1486 | VAddr stack_bottom, u32 priority, s32 core_id) { |
| 1451 | LOG_DEBUG(Kernel_SVC, | 1487 | LOG_DEBUG(Kernel_SVC, |
| 1452 | "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, " | 1488 | "called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, " |
| 1453 | "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", | 1489 | "priority=0x{:08X}, core_id=0x{:08X}", |
| 1454 | entry_point, arg, stack_top, priority, processor_id, *out_handle); | 1490 | entry_point, arg, stack_bottom, priority, core_id); |
| 1455 | 1491 | ||
| 1456 | auto* const current_process = system.Kernel().CurrentProcess(); | 1492 | // Adjust core id, if it's the default magic. |
| 1457 | 1493 | auto& kernel = system.Kernel(); | |
| 1458 | if (processor_id == THREADPROCESSORID_IDEAL) { | 1494 | auto& process = *kernel.CurrentProcess(); |
| 1459 | // Set the target CPU to the one specified by the process. | 1495 | if (core_id == IdealCoreUseProcessValue) { |
| 1460 | processor_id = current_process->GetIdealCore(); | 1496 | core_id = process.GetIdealCoreId(); |
| 1461 | ASSERT(processor_id != THREADPROCESSORID_IDEAL); | ||
| 1462 | } | 1497 | } |
| 1463 | 1498 | ||
| 1464 | if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) { | 1499 | // Validate arguments. |
| 1465 | LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id); | 1500 | if (!IsValidCoreId(core_id)) { |
| 1466 | return ERR_INVALID_PROCESSOR_ID; | 1501 | LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); |
| 1502 | return ResultInvalidCoreId; | ||
| 1467 | } | 1503 | } |
| 1468 | 1504 | if (((1ULL << core_id) & process.GetCoreMask()) == 0) { | |
| 1469 | const u64 core_mask = current_process->GetCoreMask(); | 1505 | LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id); |
| 1470 | if ((core_mask | (1ULL << processor_id)) != core_mask) { | 1506 | return ResultInvalidCoreId; |
| 1471 | LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id); | ||
| 1472 | return ERR_INVALID_PROCESSOR_ID; | ||
| 1473 | } | 1507 | } |
| 1474 | 1508 | ||
| 1475 | if (priority > THREADPRIO_LOWEST) { | 1509 | if (HighestThreadPriority > priority || priority > LowestThreadPriority) { |
| 1476 | LOG_ERROR(Kernel_SVC, | 1510 | LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority); |
| 1477 | "Invalid thread priority specified ({}). Must be within the range 0-64", | 1511 | return ResultInvalidPriority; |
| 1478 | priority); | ||
| 1479 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 1480 | } | 1512 | } |
| 1481 | 1513 | if (!process.CheckThreadPriority(priority)) { | |
| 1482 | if (((1ULL << priority) & current_process->GetPriorityMask()) == 0) { | 1514 | LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority); |
| 1483 | LOG_ERROR(Kernel_SVC, "Invalid thread priority specified ({})", priority); | 1515 | return ResultInvalidPriority; |
| 1484 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 1485 | } | 1516 | } |
| 1486 | 1517 | ||
| 1487 | auto& kernel = system.Kernel(); | 1518 | ASSERT(process.GetResourceLimit()->Reserve( |
| 1488 | 1519 | LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); | |
| 1489 | ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1)); | ||
| 1490 | 1520 | ||
| 1491 | ThreadType type = THREADTYPE_USER; | 1521 | std::shared_ptr<KThread> thread; |
| 1492 | CASCADE_RESULT(std::shared_ptr<Thread> thread, | 1522 | { |
| 1493 | Thread::Create(system, type, "", entry_point, priority, arg, processor_id, | 1523 | KScopedLightLock lk{process.GetStateLock()}; |
| 1494 | stack_top, current_process)); | 1524 | CASCADE_RESULT(thread, KThread::Create(system, ThreadType::User, "", entry_point, priority, |
| 1525 | arg, core_id, stack_bottom, &process)); | ||
| 1526 | } | ||
| 1495 | 1527 | ||
| 1496 | const auto new_thread_handle = current_process->GetHandleTable().Create(thread); | 1528 | const auto new_thread_handle = process.GetHandleTable().Create(thread); |
| 1497 | if (new_thread_handle.Failed()) { | 1529 | if (new_thread_handle.Failed()) { |
| 1498 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", | 1530 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", |
| 1499 | new_thread_handle.Code().raw); | 1531 | new_thread_handle.Code().raw); |
| @@ -1517,17 +1549,24 @@ static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 p | |||
| 1517 | static ResultCode StartThread(Core::System& system, Handle thread_handle) { | 1549 | static ResultCode StartThread(Core::System& system, Handle thread_handle) { |
| 1518 | LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | 1550 | LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); |
| 1519 | 1551 | ||
| 1552 | // Get the thread from its handle. | ||
| 1520 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1553 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1521 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1554 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1522 | if (!thread) { | 1555 | if (!thread) { |
| 1523 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | 1556 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); |
| 1524 | thread_handle); | 1557 | return ResultInvalidHandle; |
| 1525 | return ERR_INVALID_HANDLE; | ||
| 1526 | } | 1558 | } |
| 1527 | 1559 | ||
| 1528 | ASSERT(thread->GetState() == ThreadState::Initialized); | 1560 | // Try to start the thread. |
| 1561 | const auto run_result = thread->Run(); | ||
| 1562 | if (run_result.IsError()) { | ||
| 1563 | LOG_ERROR(Kernel_SVC, | ||
| 1564 | "Unable to successfuly start thread (thread handle={:08X}, result={})", | ||
| 1565 | thread_handle, run_result.raw); | ||
| 1566 | return run_result; | ||
| 1567 | } | ||
| 1529 | 1568 | ||
| 1530 | return thread->Start(); | 1569 | return RESULT_SUCCESS; |
| 1531 | } | 1570 | } |
| 1532 | 1571 | ||
| 1533 | static ResultCode StartThread32(Core::System& system, Handle thread_handle) { | 1572 | static ResultCode StartThread32(Core::System& system, Handle thread_handle) { |
| @@ -1540,7 +1579,7 @@ static void ExitThread(Core::System& system) { | |||
| 1540 | 1579 | ||
| 1541 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 1580 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 1542 | system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); | 1581 | system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); |
| 1543 | current_thread->Stop(); | 1582 | current_thread->Exit(); |
| 1544 | } | 1583 | } |
| 1545 | 1584 | ||
| 1546 | static void ExitThread32(Core::System& system) { | 1585 | static void ExitThread32(Core::System& system) { |
| @@ -1549,34 +1588,28 @@ static void ExitThread32(Core::System& system) { | |||
| 1549 | 1588 | ||
| 1550 | /// Sleep the current thread | 1589 | /// Sleep the current thread |
| 1551 | static void SleepThread(Core::System& system, s64 nanoseconds) { | 1590 | static void SleepThread(Core::System& system, s64 nanoseconds) { |
| 1552 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); | 1591 | auto& kernel = system.Kernel(); |
| 1592 | const auto yield_type = static_cast<Svc::YieldType>(nanoseconds); | ||
| 1553 | 1593 | ||
| 1554 | enum class SleepType : s64 { | 1594 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); |
| 1555 | YieldWithoutCoreMigration = 0, | ||
| 1556 | YieldWithCoreMigration = -1, | ||
| 1557 | YieldAndWaitForLoadBalancing = -2, | ||
| 1558 | }; | ||
| 1559 | 1595 | ||
| 1560 | auto& scheduler = *system.Kernel().CurrentScheduler(); | 1596 | // When the input tick is positive, sleep. |
| 1561 | if (nanoseconds <= 0) { | 1597 | if (nanoseconds > 0) { |
| 1562 | switch (static_cast<SleepType>(nanoseconds)) { | 1598 | // Convert the timeout from nanoseconds to ticks. |
| 1563 | case SleepType::YieldWithoutCoreMigration: { | 1599 | // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... |
| 1564 | scheduler.YieldWithoutCoreMigration(); | 1600 | |
| 1565 | break; | 1601 | // Sleep. |
| 1566 | } | 1602 | // NOTE: Nintendo does not check the result of this sleep. |
| 1567 | case SleepType::YieldWithCoreMigration: { | 1603 | static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds)); |
| 1568 | scheduler.YieldWithCoreMigration(); | 1604 | } else if (yield_type == Svc::YieldType::WithoutCoreMigration) { |
| 1569 | break; | 1605 | KScheduler::YieldWithoutCoreMigration(kernel); |
| 1570 | } | 1606 | } else if (yield_type == Svc::YieldType::WithCoreMigration) { |
| 1571 | case SleepType::YieldAndWaitForLoadBalancing: { | 1607 | KScheduler::YieldWithCoreMigration(kernel); |
| 1572 | scheduler.YieldToAnyThread(); | 1608 | } else if (yield_type == Svc::YieldType::ToAnyThread) { |
| 1573 | break; | 1609 | KScheduler::YieldToAnyThread(kernel); |
| 1574 | } | ||
| 1575 | default: | ||
| 1576 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | ||
| 1577 | } | ||
| 1578 | } else { | 1610 | } else { |
| 1579 | scheduler.GetCurrentThread()->Sleep(nanoseconds); | 1611 | // Nintendo does nothing at all if an otherwise invalid value is passed. |
| 1612 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | ||
| 1580 | } | 1613 | } |
| 1581 | } | 1614 | } |
| 1582 | 1615 | ||
| @@ -1592,8 +1625,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address, | |||
| 1592 | cv_key, tag, timeout_ns); | 1625 | cv_key, tag, timeout_ns); |
| 1593 | 1626 | ||
| 1594 | // Validate input. | 1627 | // Validate input. |
| 1595 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 1628 | if (Memory::IsKernelAddress(address)) { |
| 1596 | R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); | 1629 | LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address); |
| 1630 | return ResultInvalidCurrentMemory; | ||
| 1631 | } | ||
| 1632 | if (!Common::IsAligned(address, sizeof(s32))) { | ||
| 1633 | LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address); | ||
| 1634 | return ResultInvalidAddress; | ||
| 1635 | } | ||
| 1597 | 1636 | ||
| 1598 | // Convert timeout from nanoseconds to ticks. | 1637 | // Convert timeout from nanoseconds to ticks. |
| 1599 | s64 timeout{}; | 1638 | s64 timeout{}; |
| @@ -1668,9 +1707,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit | |||
| 1668 | address, arb_type, value, timeout_ns); | 1707 | address, arb_type, value, timeout_ns); |
| 1669 | 1708 | ||
| 1670 | // Validate input. | 1709 | // Validate input. |
| 1671 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 1710 | if (Memory::IsKernelAddress(address)) { |
| 1672 | R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); | 1711 | LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address); |
| 1673 | R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue); | 1712 | return ResultInvalidCurrentMemory; |
| 1713 | } | ||
| 1714 | if (!Common::IsAligned(address, sizeof(s32))) { | ||
| 1715 | LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address); | ||
| 1716 | return ResultInvalidAddress; | ||
| 1717 | } | ||
| 1718 | if (!IsValidArbitrationType(arb_type)) { | ||
| 1719 | LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type); | ||
| 1720 | return ResultInvalidEnumValue; | ||
| 1721 | } | ||
| 1674 | 1722 | ||
| 1675 | // Convert timeout from nanoseconds to ticks. | 1723 | // Convert timeout from nanoseconds to ticks. |
| 1676 | s64 timeout{}; | 1724 | s64 timeout{}; |
| @@ -1704,9 +1752,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign | |||
| 1704 | address, signal_type, value, count); | 1752 | address, signal_type, value, count); |
| 1705 | 1753 | ||
| 1706 | // Validate input. | 1754 | // Validate input. |
| 1707 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 1755 | if (Memory::IsKernelAddress(address)) { |
| 1708 | R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress); | 1756 | LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address); |
| 1709 | R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue); | 1757 | return ResultInvalidCurrentMemory; |
| 1758 | } | ||
| 1759 | if (!Common::IsAligned(address, sizeof(s32))) { | ||
| 1760 | LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address); | ||
| 1761 | return ResultInvalidAddress; | ||
| 1762 | } | ||
| 1763 | if (!IsValidSignalType(signal_type)) { | ||
| 1764 | LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type); | ||
| 1765 | return ResultInvalidEnumValue; | ||
| 1766 | } | ||
| 1710 | 1767 | ||
| 1711 | return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, | 1768 | return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, |
| 1712 | count); | 1769 | count); |
| @@ -1766,20 +1823,28 @@ static ResultCode CloseHandle32(Core::System& system, Handle handle) { | |||
| 1766 | static ResultCode ResetSignal(Core::System& system, Handle handle) { | 1823 | static ResultCode ResetSignal(Core::System& system, Handle handle) { |
| 1767 | LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); | 1824 | LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); |
| 1768 | 1825 | ||
| 1826 | // Get the current handle table. | ||
| 1769 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1827 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1770 | 1828 | ||
| 1771 | auto event = handle_table.Get<ReadableEvent>(handle); | 1829 | // Try to reset as readable event. |
| 1772 | if (event) { | 1830 | { |
| 1773 | return event->Reset(); | 1831 | auto readable_event = handle_table.Get<KReadableEvent>(handle); |
| 1832 | if (readable_event) { | ||
| 1833 | return readable_event->Reset(); | ||
| 1834 | } | ||
| 1774 | } | 1835 | } |
| 1775 | 1836 | ||
| 1776 | auto process = handle_table.Get<Process>(handle); | 1837 | // Try to reset as process. |
| 1777 | if (process) { | 1838 | { |
| 1778 | return process->ClearSignalState(); | 1839 | auto process = handle_table.Get<Process>(handle); |
| 1840 | if (process) { | ||
| 1841 | return process->Reset(); | ||
| 1842 | } | ||
| 1779 | } | 1843 | } |
| 1780 | 1844 | ||
| 1781 | LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle); | 1845 | LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle); |
| 1782 | return ERR_INVALID_HANDLE; | 1846 | |
| 1847 | return Svc::ResultInvalidHandle; | ||
| 1783 | } | 1848 | } |
| 1784 | 1849 | ||
| 1785 | static ResultCode ResetSignal32(Core::System& system, Handle handle) { | 1850 | static ResultCode ResetSignal32(Core::System& system, Handle handle) { |
| @@ -1839,171 +1904,193 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u | |||
| 1839 | return CreateTransferMemory(system, handle, addr, size, permissions); | 1904 | return CreateTransferMemory(system, handle, addr, size, permissions); |
| 1840 | } | 1905 | } |
| 1841 | 1906 | ||
| 1842 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, | 1907 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, |
| 1843 | u64* mask) { | 1908 | u64* out_affinity_mask) { |
| 1844 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); | 1909 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); |
| 1845 | 1910 | ||
| 1911 | // Get the thread from its handle. | ||
| 1846 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1912 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1847 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1913 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1848 | if (!thread) { | 1914 | if (!thread) { |
| 1849 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | 1915 | LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle); |
| 1850 | thread_handle); | 1916 | return ResultInvalidHandle; |
| 1851 | *core = 0; | ||
| 1852 | *mask = 0; | ||
| 1853 | return ERR_INVALID_HANDLE; | ||
| 1854 | } | 1917 | } |
| 1855 | 1918 | ||
| 1856 | *core = thread->GetIdealCore(); | 1919 | // Get the core mask. |
| 1857 | *mask = thread->GetAffinityMask().GetAffinityMask(); | 1920 | const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask); |
| 1921 | if (result.IsError()) { | ||
| 1922 | LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw); | ||
| 1923 | return result; | ||
| 1924 | } | ||
| 1858 | 1925 | ||
| 1859 | return RESULT_SUCCESS; | 1926 | return RESULT_SUCCESS; |
| 1860 | } | 1927 | } |
| 1861 | 1928 | ||
| 1862 | static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, | 1929 | static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id, |
| 1863 | u32* mask_low, u32* mask_high) { | 1930 | u32* out_affinity_mask_low, u32* out_affinity_mask_high) { |
| 1864 | u64 mask{}; | 1931 | u64 out_affinity_mask{}; |
| 1865 | const auto result = GetThreadCoreMask(system, thread_handle, core, &mask); | 1932 | const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask); |
| 1866 | *mask_high = static_cast<u32>(mask >> 32); | 1933 | *out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32); |
| 1867 | *mask_low = static_cast<u32>(mask); | 1934 | *out_affinity_mask_low = static_cast<u32>(out_affinity_mask); |
| 1868 | return result; | 1935 | return result; |
| 1869 | } | 1936 | } |
| 1870 | 1937 | ||
| 1871 | static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, | 1938 | static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, |
| 1872 | u64 affinity_mask) { | 1939 | u64 affinity_mask) { |
| 1873 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", | 1940 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}", |
| 1874 | thread_handle, core, affinity_mask); | 1941 | thread_handle, core_id, affinity_mask); |
| 1875 | |||
| 1876 | const auto* const current_process = system.Kernel().CurrentProcess(); | ||
| 1877 | 1942 | ||
| 1878 | if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) { | 1943 | const auto& current_process = *system.Kernel().CurrentProcess(); |
| 1879 | const u8 ideal_cpu_core = current_process->GetIdealCore(); | ||
| 1880 | 1944 | ||
| 1881 | ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL)); | 1945 | // Determine the core id/affinity mask. |
| 1882 | 1946 | if (core_id == Svc::IdealCoreUseProcessValue) { | |
| 1883 | // Set the target CPU to the ideal core specified by the process. | 1947 | core_id = current_process.GetIdealCoreId(); |
| 1884 | core = ideal_cpu_core; | 1948 | affinity_mask = (1ULL << core_id); |
| 1885 | affinity_mask = 1ULL << core; | ||
| 1886 | } else { | 1949 | } else { |
| 1887 | const u64 core_mask = current_process->GetCoreMask(); | 1950 | // Validate the affinity mask. |
| 1888 | 1951 | const u64 process_core_mask = current_process.GetCoreMask(); | |
| 1889 | if ((core_mask | affinity_mask) != core_mask) { | 1952 | if ((affinity_mask | process_core_mask) != process_core_mask) { |
| 1890 | LOG_ERROR( | 1953 | LOG_ERROR(Kernel_SVC, |
| 1891 | Kernel_SVC, | 1954 | "Affinity mask does match the process core mask (affinity mask={:016X}, core " |
| 1892 | "Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})", | 1955 | "mask={:016X})", |
| 1893 | core_mask, affinity_mask); | 1956 | affinity_mask, process_core_mask); |
| 1894 | return ERR_INVALID_PROCESSOR_ID; | 1957 | return ResultInvalidCoreId; |
| 1895 | } | 1958 | } |
| 1896 | |||
| 1897 | if (affinity_mask == 0) { | 1959 | if (affinity_mask == 0) { |
| 1898 | LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero."); | 1960 | LOG_ERROR(Kernel_SVC, "Affinity mask is zero."); |
| 1899 | return ERR_INVALID_COMBINATION; | 1961 | return ResultInvalidCombination; |
| 1900 | } | 1962 | } |
| 1901 | 1963 | ||
| 1902 | if (core < Core::Hardware::NUM_CPU_CORES) { | 1964 | // Validate the core id. |
| 1903 | if ((affinity_mask & (1ULL << core)) == 0) { | 1965 | if (IsValidCoreId(core_id)) { |
| 1904 | LOG_ERROR(Kernel_SVC, | 1966 | if (((1ULL << core_id) & affinity_mask) == 0) { |
| 1905 | "Core is not enabled for the current mask, core={}, mask={:016X}", core, | 1967 | LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); |
| 1906 | affinity_mask); | 1968 | return ResultInvalidCombination; |
| 1907 | return ERR_INVALID_COMBINATION; | 1969 | } |
| 1970 | } else { | ||
| 1971 | if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { | ||
| 1972 | LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); | ||
| 1973 | return ResultInvalidCoreId; | ||
| 1908 | } | 1974 | } |
| 1909 | } else if (core != static_cast<u32>(THREADPROCESSORID_DONT_CARE) && | ||
| 1910 | core != static_cast<u32>(THREADPROCESSORID_DONT_UPDATE)) { | ||
| 1911 | LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core); | ||
| 1912 | return ERR_INVALID_PROCESSOR_ID; | ||
| 1913 | } | 1975 | } |
| 1914 | } | 1976 | } |
| 1915 | 1977 | ||
| 1916 | const auto& handle_table = current_process->GetHandleTable(); | 1978 | // Get the thread from its handle. |
| 1917 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1979 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1980 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | ||
| 1918 | if (!thread) { | 1981 | if (!thread) { |
| 1919 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | 1982 | LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle); |
| 1920 | thread_handle); | 1983 | return ResultInvalidHandle; |
| 1921 | return ERR_INVALID_HANDLE; | 1984 | } |
| 1985 | |||
| 1986 | // Set the core mask. | ||
| 1987 | const auto set_result = thread->SetCoreMask(core_id, affinity_mask); | ||
| 1988 | if (set_result.IsError()) { | ||
| 1989 | LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw); | ||
| 1990 | return set_result; | ||
| 1922 | } | 1991 | } |
| 1923 | 1992 | ||
| 1924 | return thread->SetCoreAndAffinityMask(core, affinity_mask); | 1993 | return RESULT_SUCCESS; |
| 1925 | } | 1994 | } |
| 1926 | 1995 | ||
| 1927 | static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, | 1996 | static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id, |
| 1928 | u32 affinity_mask_low, u32 affinity_mask_high) { | 1997 | u32 affinity_mask_low, u32 affinity_mask_high) { |
| 1929 | const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); | 1998 | const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); |
| 1930 | return SetThreadCoreMask(system, thread_handle, core, affinity_mask); | 1999 | return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask); |
| 1931 | } | 2000 | } |
| 1932 | 2001 | ||
| 1933 | static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { | 2002 | static ResultCode SignalEvent(Core::System& system, Handle event_handle) { |
| 1934 | LOG_DEBUG(Kernel_SVC, "called"); | 2003 | LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); |
| 1935 | |||
| 1936 | auto& kernel = system.Kernel(); | ||
| 1937 | const auto [readable_event, writable_event] = | ||
| 1938 | WritableEvent::CreateEventPair(kernel, "CreateEvent"); | ||
| 1939 | 2004 | ||
| 1940 | HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 2005 | // Get the current handle table. |
| 2006 | const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||
| 1941 | 2007 | ||
| 1942 | const auto write_create_result = handle_table.Create(writable_event); | 2008 | // Get the writable event. |
| 1943 | if (write_create_result.Failed()) { | 2009 | auto writable_event = handle_table.Get<KWritableEvent>(event_handle); |
| 1944 | return write_create_result.Code(); | 2010 | if (!writable_event) { |
| 1945 | } | 2011 | LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle); |
| 1946 | *write_handle = *write_create_result; | 2012 | return ResultInvalidHandle; |
| 1947 | |||
| 1948 | const auto read_create_result = handle_table.Create(readable_event); | ||
| 1949 | if (read_create_result.Failed()) { | ||
| 1950 | handle_table.Close(*write_create_result); | ||
| 1951 | return read_create_result.Code(); | ||
| 1952 | } | 2013 | } |
| 1953 | *read_handle = *read_create_result; | ||
| 1954 | 2014 | ||
| 1955 | LOG_DEBUG(Kernel_SVC, | 2015 | return writable_event->Signal(); |
| 1956 | "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}", | ||
| 1957 | *write_create_result, *read_create_result); | ||
| 1958 | return RESULT_SUCCESS; | ||
| 1959 | } | 2016 | } |
| 1960 | 2017 | ||
| 1961 | static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) { | 2018 | static ResultCode SignalEvent32(Core::System& system, Handle event_handle) { |
| 1962 | return CreateEvent(system, write_handle, read_handle); | 2019 | return SignalEvent(system, event_handle); |
| 1963 | } | 2020 | } |
| 1964 | 2021 | ||
| 1965 | static ResultCode ClearEvent(Core::System& system, Handle handle) { | 2022 | static ResultCode ClearEvent(Core::System& system, Handle event_handle) { |
| 1966 | LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); | 2023 | LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); |
| 1967 | 2024 | ||
| 2025 | // Get the current handle table. | ||
| 1968 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 2026 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1969 | 2027 | ||
| 1970 | auto writable_event = handle_table.Get<WritableEvent>(handle); | 2028 | // Try to clear the writable event. |
| 1971 | if (writable_event) { | 2029 | { |
| 1972 | writable_event->Clear(); | 2030 | auto writable_event = handle_table.Get<KWritableEvent>(event_handle); |
| 1973 | return RESULT_SUCCESS; | 2031 | if (writable_event) { |
| 2032 | return writable_event->Clear(); | ||
| 2033 | } | ||
| 1974 | } | 2034 | } |
| 1975 | 2035 | ||
| 1976 | auto readable_event = handle_table.Get<ReadableEvent>(handle); | 2036 | // Try to clear the readable event. |
| 1977 | if (readable_event) { | 2037 | { |
| 1978 | readable_event->Clear(); | 2038 | auto readable_event = handle_table.Get<KReadableEvent>(event_handle); |
| 1979 | return RESULT_SUCCESS; | 2039 | if (readable_event) { |
| 2040 | return readable_event->Clear(); | ||
| 2041 | } | ||
| 1980 | } | 2042 | } |
| 1981 | 2043 | ||
| 1982 | LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle); | 2044 | LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle); |
| 1983 | return ERR_INVALID_HANDLE; | 2045 | |
| 2046 | return Svc::ResultInvalidHandle; | ||
| 1984 | } | 2047 | } |
| 1985 | 2048 | ||
| 1986 | static ResultCode ClearEvent32(Core::System& system, Handle handle) { | 2049 | static ResultCode ClearEvent32(Core::System& system, Handle event_handle) { |
| 1987 | return ClearEvent(system, handle); | 2050 | return ClearEvent(system, event_handle); |
| 1988 | } | 2051 | } |
| 1989 | 2052 | ||
| 1990 | static ResultCode SignalEvent(Core::System& system, Handle handle) { | 2053 | static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) { |
| 1991 | LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle); | 2054 | LOG_DEBUG(Kernel_SVC, "called"); |
| 2055 | |||
| 2056 | // Get the kernel reference and handle table. | ||
| 2057 | auto& kernel = system.Kernel(); | ||
| 2058 | HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||
| 1992 | 2059 | ||
| 1993 | HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 2060 | // Create a new event. |
| 1994 | auto writable_event = handle_table.Get<WritableEvent>(handle); | 2061 | const auto event = KEvent::Create(kernel, "CreateEvent"); |
| 2062 | if (!event) { | ||
| 2063 | LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached."); | ||
| 2064 | return ResultOutOfResource; | ||
| 2065 | } | ||
| 1995 | 2066 | ||
| 1996 | if (!writable_event) { | 2067 | // Initialize the event. |
| 1997 | LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle); | 2068 | event->Initialize(); |
| 1998 | return ERR_INVALID_HANDLE; | 2069 | |
| 2070 | // Add the writable event to the handle table. | ||
| 2071 | const auto write_create_result = handle_table.Create(event->GetWritableEvent()); | ||
| 2072 | if (write_create_result.Failed()) { | ||
| 2073 | return write_create_result.Code(); | ||
| 2074 | } | ||
| 2075 | *out_write = *write_create_result; | ||
| 2076 | |||
| 2077 | // Add the writable event to the handle table. | ||
| 2078 | auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); }); | ||
| 2079 | |||
| 2080 | // Add the readable event to the handle table. | ||
| 2081 | const auto read_create_result = handle_table.Create(event->GetReadableEvent()); | ||
| 2082 | if (read_create_result.Failed()) { | ||
| 2083 | return read_create_result.Code(); | ||
| 1999 | } | 2084 | } |
| 2085 | *out_read = *read_create_result; | ||
| 2000 | 2086 | ||
| 2001 | writable_event->Signal(); | 2087 | // We succeeded. |
| 2088 | handle_guard.Cancel(); | ||
| 2002 | return RESULT_SUCCESS; | 2089 | return RESULT_SUCCESS; |
| 2003 | } | 2090 | } |
| 2004 | 2091 | ||
| 2005 | static ResultCode SignalEvent32(Core::System& system, Handle handle) { | 2092 | static ResultCode CreateEvent32(Core::System& system, Handle* out_write, Handle* out_read) { |
| 2006 | return SignalEvent(system, handle); | 2093 | return CreateEvent(system, out_write, out_read); |
| 2007 | } | 2094 | } |
| 2008 | 2095 | ||
| 2009 | static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { | 2096 | static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { |
| @@ -2037,7 +2124,7 @@ static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) | |||
| 2037 | LOG_DEBUG(Kernel_SVC, "called"); | 2124 | LOG_DEBUG(Kernel_SVC, "called"); |
| 2038 | 2125 | ||
| 2039 | auto& kernel = system.Kernel(); | 2126 | auto& kernel = system.Kernel(); |
| 2040 | auto resource_limit = ResourceLimit::Create(kernel); | 2127 | auto resource_limit = std::make_shared<KResourceLimit>(kernel, system); |
| 2041 | 2128 | ||
| 2042 | auto* const current_process = kernel.CurrentProcess(); | 2129 | auto* const current_process = kernel.CurrentProcess(); |
| 2043 | ASSERT(current_process != nullptr); | 2130 | ASSERT(current_process != nullptr); |
| @@ -2084,7 +2171,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour | |||
| 2084 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, | 2171 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, |
| 2085 | resource_type, value); | 2172 | resource_type, value); |
| 2086 | 2173 | ||
| 2087 | const auto type = static_cast<ResourceType>(resource_type); | 2174 | const auto type = static_cast<LimitableResource>(resource_type); |
| 2088 | if (!IsValidResourceType(type)) { | 2175 | if (!IsValidResourceType(type)) { |
| 2089 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | 2176 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); |
| 2090 | return ERR_INVALID_ENUM_VALUE; | 2177 | return ERR_INVALID_ENUM_VALUE; |
| @@ -2094,7 +2181,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour | |||
| 2094 | ASSERT(current_process != nullptr); | 2181 | ASSERT(current_process != nullptr); |
| 2095 | 2182 | ||
| 2096 | auto resource_limit_object = | 2183 | auto resource_limit_object = |
| 2097 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | 2184 | current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); |
| 2098 | if (!resource_limit_object) { | 2185 | if (!resource_limit_object) { |
| 2099 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | 2186 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", |
| 2100 | resource_limit); | 2187 | resource_limit); |
| @@ -2106,8 +2193,8 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour | |||
| 2106 | LOG_ERROR( | 2193 | LOG_ERROR( |
| 2107 | Kernel_SVC, | 2194 | Kernel_SVC, |
| 2108 | "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", | 2195 | "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", |
| 2109 | resource_limit_object->GetMaxResourceValue(type), resource_type, | 2196 | resource_limit_object->GetLimitValue(type), resource_type, |
| 2110 | resource_limit_object->GetCurrentResourceValue(type)); | 2197 | resource_limit_object->GetCurrentValue(type)); |
| 2111 | return set_result; | 2198 | return set_result; |
| 2112 | } | 2199 | } |
| 2113 | 2200 | ||
| @@ -2491,7 +2578,7 @@ void Call(Core::System& system, u32 immediate) { | |||
| 2491 | kernel.EnterSVCProfile(); | 2578 | kernel.EnterSVCProfile(); |
| 2492 | 2579 | ||
| 2493 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); | 2580 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 2494 | thread->SetContinuousOnSVC(true); | 2581 | thread->SetIsCallingSvc(); |
| 2495 | 2582 | ||
| 2496 | const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) | 2583 | const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) |
| 2497 | : GetSVCInfo32(immediate); | 2584 | : GetSVCInfo32(immediate); |
| @@ -2507,7 +2594,7 @@ void Call(Core::System& system, u32 immediate) { | |||
| 2507 | 2594 | ||
| 2508 | kernel.ExitSVCProfile(); | 2595 | kernel.ExitSVCProfile(); |
| 2509 | 2596 | ||
| 2510 | if (!thread->IsContinuousOnSVC()) { | 2597 | if (!thread->IsCallingSvc()) { |
| 2511 | auto* host_context = thread->GetHostContext().get(); | 2598 | auto* host_context = thread->GetHostContext().get(); |
| 2512 | host_context->Rewind(); | 2599 | host_context->Rewind(); |
| 2513 | } | 2600 | } |
diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index 78282f021..204cd989d 100644 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h | |||
| @@ -8,13 +8,19 @@ | |||
| 8 | 8 | ||
| 9 | namespace Kernel::Svc { | 9 | namespace Kernel::Svc { |
| 10 | 10 | ||
| 11 | constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57}; | ||
| 11 | constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59}; | 12 | constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59}; |
| 12 | constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102}; | 13 | constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102}; |
| 14 | constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103}; | ||
| 13 | constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106}; | 15 | constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106}; |
| 16 | constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112}; | ||
| 17 | constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113}; | ||
| 14 | constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114}; | 18 | constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114}; |
| 19 | constexpr ResultCode ResultInvalidCombination{ErrorModule::Kernel, 116}; | ||
| 15 | constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117}; | 20 | constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117}; |
| 16 | constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118}; | 21 | constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118}; |
| 17 | constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120}; | 22 | constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120}; |
| 23 | constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122}; | ||
| 18 | constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; | 24 | constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; |
| 19 | 25 | ||
| 20 | } // namespace Kernel::Svc | 26 | } // namespace Kernel::Svc |
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index d623f7a50..ec463b97c 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h | |||
| @@ -77,4 +77,22 @@ enum class ArbitrationType : u32 { | |||
| 77 | WaitIfEqual = 2, | 77 | WaitIfEqual = 2, |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | enum class YieldType : s64 { | ||
| 81 | WithoutCoreMigration = 0, | ||
| 82 | WithCoreMigration = -1, | ||
| 83 | ToAnyThread = -2, | ||
| 84 | }; | ||
| 85 | |||
| 86 | enum class ThreadActivity : u32 { | ||
| 87 | Runnable = 0, | ||
| 88 | Paused = 1, | ||
| 89 | }; | ||
| 90 | |||
| 91 | constexpr inline s32 IdealCoreDontCare = -1; | ||
| 92 | constexpr inline s32 IdealCoreUseProcessValue = -2; | ||
| 93 | constexpr inline s32 IdealCoreNoUpdate = -3; | ||
| 94 | |||
| 95 | constexpr inline s32 LowestThreadPriority = 63; | ||
| 96 | constexpr inline s32 HighestThreadPriority = 0; | ||
| 97 | |||
| 80 | } // namespace Kernel::Svc | 98 | } // namespace Kernel::Svc |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index a32750ed7..96afd544b 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -58,6 +58,14 @@ void SvcWrap64(Core::System& system) { | |||
| 58 | func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw); | 58 | func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | // Used by SetThreadActivity | ||
| 62 | template <ResultCode func(Core::System&, Handle, Svc::ThreadActivity)> | ||
| 63 | void SvcWrap64(Core::System& system) { | ||
| 64 | FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), | ||
| 65 | static_cast<Svc::ThreadActivity>(Param(system, 1))) | ||
| 66 | .raw); | ||
| 67 | } | ||
| 68 | |||
| 61 | template <ResultCode func(Core::System&, u32, u64, u64, u64)> | 69 | template <ResultCode func(Core::System&, u32, u64, u64, u64)> |
| 62 | void SvcWrap64(Core::System& system) { | 70 | void SvcWrap64(Core::System& system) { |
| 63 | FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), | 71 | FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), |
| @@ -158,9 +166,18 @@ void SvcWrap64(Core::System& system) { | |||
| 158 | .raw); | 166 | .raw); |
| 159 | } | 167 | } |
| 160 | 168 | ||
| 161 | template <ResultCode func(Core::System&, u32, u32*, u64*)> | 169 | // Used by SetThreadCoreMask |
| 170 | template <ResultCode func(Core::System&, Handle, s32, u64)> | ||
| 162 | void SvcWrap64(Core::System& system) { | 171 | void SvcWrap64(Core::System& system) { |
| 163 | u32 param_1 = 0; | 172 | FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), |
| 173 | static_cast<s32>(Param(system, 1)), Param(system, 2)) | ||
| 174 | .raw); | ||
| 175 | } | ||
| 176 | |||
| 177 | // Used by GetThreadCoreMask | ||
| 178 | template <ResultCode func(Core::System&, Handle, s32*, u64*)> | ||
| 179 | void SvcWrap64(Core::System& system) { | ||
| 180 | s32 param_1 = 0; | ||
| 164 | u64 param_2 = 0; | 181 | u64 param_2 = 0; |
| 165 | const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), ¶m_1, ¶m_2); | 182 | const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), ¶m_1, ¶m_2); |
| 166 | 183 | ||
| @@ -473,12 +490,35 @@ void SvcWrap32(Core::System& system) { | |||
| 473 | FuncReturn(system, retval); | 490 | FuncReturn(system, retval); |
| 474 | } | 491 | } |
| 475 | 492 | ||
| 493 | // Used by GetThreadCoreMask32 | ||
| 494 | template <ResultCode func(Core::System&, Handle, s32*, u32*, u32*)> | ||
| 495 | void SvcWrap32(Core::System& system) { | ||
| 496 | s32 param_1 = 0; | ||
| 497 | u32 param_2 = 0; | ||
| 498 | u32 param_3 = 0; | ||
| 499 | |||
| 500 | const u32 retval = func(system, Param32(system, 2), ¶m_1, ¶m_2, ¶m_3).raw; | ||
| 501 | system.CurrentArmInterface().SetReg(1, param_1); | ||
| 502 | system.CurrentArmInterface().SetReg(2, param_2); | ||
| 503 | system.CurrentArmInterface().SetReg(3, param_3); | ||
| 504 | FuncReturn(system, retval); | ||
| 505 | } | ||
| 506 | |||
| 476 | // Used by SignalProcessWideKey32 | 507 | // Used by SignalProcessWideKey32 |
| 477 | template <void func(Core::System&, u32, s32)> | 508 | template <void func(Core::System&, u32, s32)> |
| 478 | void SvcWrap32(Core::System& system) { | 509 | void SvcWrap32(Core::System& system) { |
| 479 | func(system, static_cast<u32>(Param(system, 0)), static_cast<s32>(Param(system, 1))); | 510 | func(system, static_cast<u32>(Param(system, 0)), static_cast<s32>(Param(system, 1))); |
| 480 | } | 511 | } |
| 481 | 512 | ||
| 513 | // Used by SetThreadActivity32 | ||
| 514 | template <ResultCode func(Core::System&, Handle, Svc::ThreadActivity)> | ||
| 515 | void SvcWrap32(Core::System& system) { | ||
| 516 | const u32 retval = func(system, static_cast<Handle>(Param(system, 0)), | ||
| 517 | static_cast<Svc::ThreadActivity>(Param(system, 1))) | ||
| 518 | .raw; | ||
| 519 | FuncReturn(system, retval); | ||
| 520 | } | ||
| 521 | |||
| 482 | // Used by SetThreadPriority32 | 522 | // Used by SetThreadPriority32 |
| 483 | template <ResultCode func(Core::System&, Handle, u32)> | 523 | template <ResultCode func(Core::System&, Handle, u32)> |
| 484 | void SvcWrap32(Core::System& system) { | 524 | void SvcWrap32(Core::System& system) { |
| @@ -487,7 +527,7 @@ void SvcWrap32(Core::System& system) { | |||
| 487 | FuncReturn(system, retval); | 527 | FuncReturn(system, retval); |
| 488 | } | 528 | } |
| 489 | 529 | ||
| 490 | // Used by SetThreadCoreMask32 | 530 | // Used by SetMemoryAttribute32 |
| 491 | template <ResultCode func(Core::System&, Handle, u32, u32, u32)> | 531 | template <ResultCode func(Core::System&, Handle, u32, u32, u32)> |
| 492 | void SvcWrap32(Core::System& system) { | 532 | void SvcWrap32(Core::System& system) { |
| 493 | const u32 retval = | 533 | const u32 retval = |
| @@ -497,6 +537,16 @@ void SvcWrap32(Core::System& system) { | |||
| 497 | FuncReturn(system, retval); | 537 | FuncReturn(system, retval); |
| 498 | } | 538 | } |
| 499 | 539 | ||
| 540 | // Used by SetThreadCoreMask32 | ||
| 541 | template <ResultCode func(Core::System&, Handle, s32, u32, u32)> | ||
| 542 | void SvcWrap32(Core::System& system) { | ||
| 543 | const u32 retval = | ||
| 544 | func(system, static_cast<Handle>(Param(system, 0)), static_cast<s32>(Param(system, 1)), | ||
| 545 | static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3))) | ||
| 546 | .raw; | ||
| 547 | FuncReturn(system, retval); | ||
| 548 | } | ||
| 549 | |||
| 500 | // Used by WaitProcessWideKeyAtomic32 | 550 | // Used by WaitProcessWideKeyAtomic32 |
| 501 | template <ResultCode func(Core::System&, u32, u32, Handle, u32, u32)> | 551 | template <ResultCode func(Core::System&, u32, u32, Handle, u32, u32)> |
| 502 | void SvcWrap32(Core::System& system) { | 552 | void SvcWrap32(Core::System& system) { |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp deleted file mode 100644 index d97323255..000000000 --- a/src/core/hle/kernel/thread.cpp +++ /dev/null | |||
| @@ -1,460 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cinttypes> | ||
| 7 | #include <optional> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/fiber.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "common/thread_queue_list.h" | ||
| 15 | #include "core/core.h" | ||
| 16 | #include "core/cpu_manager.h" | ||
| 17 | #include "core/hardware_properties.h" | ||
| 18 | #include "core/hle/kernel/errors.h" | ||
| 19 | #include "core/hle/kernel/handle_table.h" | ||
| 20 | #include "core/hle/kernel/k_condition_variable.h" | ||
| 21 | #include "core/hle/kernel/k_scheduler.h" | ||
| 22 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 23 | #include "core/hle/kernel/kernel.h" | ||
| 24 | #include "core/hle/kernel/memory/memory_layout.h" | ||
| 25 | #include "core/hle/kernel/object.h" | ||
| 26 | #include "core/hle/kernel/process.h" | ||
| 27 | #include "core/hle/kernel/thread.h" | ||
| 28 | #include "core/hle/kernel/time_manager.h" | ||
| 29 | #include "core/hle/result.h" | ||
| 30 | #include "core/memory.h" | ||
| 31 | |||
| 32 | #ifdef ARCHITECTURE_x86_64 | ||
| 33 | #include "core/arm/dynarmic/arm_dynarmic_32.h" | ||
| 34 | #include "core/arm/dynarmic/arm_dynarmic_64.h" | ||
| 35 | #endif | ||
| 36 | |||
| 37 | namespace Kernel { | ||
| 38 | |||
| 39 | bool Thread::IsSignaled() const { | ||
| 40 | return signaled; | ||
| 41 | } | ||
| 42 | |||
| 43 | Thread::Thread(KernelCore& kernel) : KSynchronizationObject{kernel} {} | ||
| 44 | Thread::~Thread() = default; | ||
| 45 | |||
| 46 | void Thread::Stop() { | ||
| 47 | { | ||
| 48 | KScopedSchedulerLock lock(kernel); | ||
| 49 | SetState(ThreadState::Terminated); | ||
| 50 | signaled = true; | ||
| 51 | NotifyAvailable(); | ||
| 52 | kernel.GlobalHandleTable().Close(global_handle); | ||
| 53 | |||
| 54 | if (owner_process) { | ||
| 55 | owner_process->UnregisterThread(this); | ||
| 56 | |||
| 57 | // Mark the TLS slot in the thread's page as free. | ||
| 58 | owner_process->FreeTLSRegion(tls_address); | ||
| 59 | } | ||
| 60 | has_exited = true; | ||
| 61 | } | ||
| 62 | global_handle = 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | void Thread::Wakeup() { | ||
| 66 | KScopedSchedulerLock lock(kernel); | ||
| 67 | SetState(ThreadState::Runnable); | ||
| 68 | } | ||
| 69 | |||
| 70 | ResultCode Thread::Start() { | ||
| 71 | KScopedSchedulerLock lock(kernel); | ||
| 72 | SetState(ThreadState::Runnable); | ||
| 73 | return RESULT_SUCCESS; | ||
| 74 | } | ||
| 75 | |||
| 76 | void Thread::CancelWait() { | ||
| 77 | KScopedSchedulerLock lock(kernel); | ||
| 78 | if (GetState() != ThreadState::Waiting || !is_cancellable) { | ||
| 79 | is_sync_cancelled = true; | ||
| 80 | return; | ||
| 81 | } | ||
| 82 | // TODO(Blinkhawk): Implement cancel of server session | ||
| 83 | is_sync_cancelled = false; | ||
| 84 | SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); | ||
| 85 | SetState(ThreadState::Runnable); | ||
| 86 | } | ||
| 87 | |||
| 88 | static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, | ||
| 89 | u32 entry_point, u32 arg) { | ||
| 90 | context = {}; | ||
| 91 | context.cpu_registers[0] = arg; | ||
| 92 | context.cpu_registers[15] = entry_point; | ||
| 93 | context.cpu_registers[13] = stack_top; | ||
| 94 | } | ||
| 95 | |||
| 96 | static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, VAddr stack_top, | ||
| 97 | VAddr entry_point, u64 arg) { | ||
| 98 | context = {}; | ||
| 99 | context.cpu_registers[0] = arg; | ||
| 100 | context.pc = entry_point; | ||
| 101 | context.sp = stack_top; | ||
| 102 | // TODO(merry): Perform a hardware test to determine the below value. | ||
| 103 | context.fpcr = 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | std::shared_ptr<Common::Fiber>& Thread::GetHostContext() { | ||
| 107 | return host_context; | ||
| 108 | } | ||
| 109 | |||
| 110 | ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadType type_flags, | ||
| 111 | std::string name, VAddr entry_point, u32 priority, | ||
| 112 | u64 arg, s32 processor_id, VAddr stack_top, | ||
| 113 | Process* owner_process) { | ||
| 114 | std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); | ||
| 115 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | ||
| 116 | return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, | ||
| 117 | owner_process, std::move(init_func), init_func_parameter); | ||
| 118 | } | ||
| 119 | |||
| 120 | ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadType type_flags, | ||
| 121 | std::string name, VAddr entry_point, u32 priority, | ||
| 122 | u64 arg, s32 processor_id, VAddr stack_top, | ||
| 123 | Process* owner_process, | ||
| 124 | std::function<void(void*)>&& thread_start_func, | ||
| 125 | void* thread_start_parameter) { | ||
| 126 | auto& kernel = system.Kernel(); | ||
| 127 | // Check if priority is in ranged. Lowest priority -> highest priority id. | ||
| 128 | if (priority > THREADPRIO_LOWEST && ((type_flags & THREADTYPE_IDLE) == 0)) { | ||
| 129 | LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); | ||
| 130 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (processor_id > THREADPROCESSORID_MAX) { | ||
| 134 | LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); | ||
| 135 | return ERR_INVALID_PROCESSOR_ID; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (owner_process) { | ||
| 139 | if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) { | ||
| 140 | LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); | ||
| 141 | // TODO (bunnei): Find the correct error code to use here | ||
| 142 | return RESULT_UNKNOWN; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel); | ||
| 147 | |||
| 148 | thread->thread_id = kernel.CreateNewThreadID(); | ||
| 149 | thread->thread_state = ThreadState::Initialized; | ||
| 150 | thread->entry_point = entry_point; | ||
| 151 | thread->stack_top = stack_top; | ||
| 152 | thread->disable_count = 1; | ||
| 153 | thread->tpidr_el0 = 0; | ||
| 154 | thread->current_priority = priority; | ||
| 155 | thread->base_priority = priority; | ||
| 156 | thread->lock_owner = nullptr; | ||
| 157 | thread->schedule_count = -1; | ||
| 158 | thread->last_scheduled_tick = 0; | ||
| 159 | thread->processor_id = processor_id; | ||
| 160 | thread->ideal_core = processor_id; | ||
| 161 | thread->affinity_mask.SetAffinity(processor_id, true); | ||
| 162 | thread->name = std::move(name); | ||
| 163 | thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); | ||
| 164 | thread->owner_process = owner_process; | ||
| 165 | thread->type = type_flags; | ||
| 166 | thread->signaled = false; | ||
| 167 | if ((type_flags & THREADTYPE_IDLE) == 0) { | ||
| 168 | auto& scheduler = kernel.GlobalSchedulerContext(); | ||
| 169 | scheduler.AddThread(thread); | ||
| 170 | } | ||
| 171 | if (owner_process) { | ||
| 172 | thread->tls_address = thread->owner_process->CreateTLSRegion(); | ||
| 173 | thread->owner_process->RegisterThread(thread.get()); | ||
| 174 | } else { | ||
| 175 | thread->tls_address = 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used | ||
| 179 | // to initialize the context | ||
| 180 | if ((type_flags & THREADTYPE_HLE) == 0) { | ||
| 181 | ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top), | ||
| 182 | static_cast<u32>(entry_point), static_cast<u32>(arg)); | ||
| 183 | ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); | ||
| 184 | } | ||
| 185 | thread->host_context = | ||
| 186 | std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter); | ||
| 187 | |||
| 188 | return MakeResult<std::shared_ptr<Thread>>(std::move(thread)); | ||
| 189 | } | ||
| 190 | |||
| 191 | void Thread::SetBasePriority(u32 priority) { | ||
| 192 | ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, | ||
| 193 | "Invalid priority value."); | ||
| 194 | |||
| 195 | KScopedSchedulerLock lock(kernel); | ||
| 196 | |||
| 197 | // Change our base priority. | ||
| 198 | base_priority = priority; | ||
| 199 | |||
| 200 | // Perform a priority restoration. | ||
| 201 | RestorePriority(kernel, this); | ||
| 202 | } | ||
| 203 | |||
| 204 | void Thread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) { | ||
| 205 | signaling_object = object; | ||
| 206 | signaling_result = result; | ||
| 207 | } | ||
| 208 | |||
| 209 | VAddr Thread::GetCommandBufferAddress() const { | ||
| 210 | // Offset from the start of TLS at which the IPC command buffer begins. | ||
| 211 | constexpr u64 command_header_offset = 0x80; | ||
| 212 | return GetTLSAddress() + command_header_offset; | ||
| 213 | } | ||
| 214 | |||
| 215 | void Thread::SetState(ThreadState state) { | ||
| 216 | KScopedSchedulerLock sl(kernel); | ||
| 217 | |||
| 218 | // Clear debugging state | ||
| 219 | SetMutexWaitAddressForDebugging({}); | ||
| 220 | SetWaitReasonForDebugging({}); | ||
| 221 | |||
| 222 | const ThreadState old_state = thread_state; | ||
| 223 | thread_state = | ||
| 224 | static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); | ||
| 225 | if (thread_state != old_state) { | ||
| 226 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | void Thread::AddWaiterImpl(Thread* thread) { | ||
| 231 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 232 | |||
| 233 | // Find the right spot to insert the waiter. | ||
| 234 | auto it = waiter_list.begin(); | ||
| 235 | while (it != waiter_list.end()) { | ||
| 236 | if (it->GetPriority() > thread->GetPriority()) { | ||
| 237 | break; | ||
| 238 | } | ||
| 239 | it++; | ||
| 240 | } | ||
| 241 | |||
| 242 | // Keep track of how many kernel waiters we have. | ||
| 243 | if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { | ||
| 244 | ASSERT((num_kernel_waiters++) >= 0); | ||
| 245 | } | ||
| 246 | |||
| 247 | // Insert the waiter. | ||
| 248 | waiter_list.insert(it, *thread); | ||
| 249 | thread->SetLockOwner(this); | ||
| 250 | } | ||
| 251 | |||
| 252 | void Thread::RemoveWaiterImpl(Thread* thread) { | ||
| 253 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 254 | |||
| 255 | // Keep track of how many kernel waiters we have. | ||
| 256 | if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { | ||
| 257 | ASSERT((num_kernel_waiters--) > 0); | ||
| 258 | } | ||
| 259 | |||
| 260 | // Remove the waiter. | ||
| 261 | waiter_list.erase(waiter_list.iterator_to(*thread)); | ||
| 262 | thread->SetLockOwner(nullptr); | ||
| 263 | } | ||
| 264 | |||
| 265 | void Thread::RestorePriority(KernelCore& kernel, Thread* thread) { | ||
| 266 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 267 | |||
| 268 | while (true) { | ||
| 269 | // We want to inherit priority where possible. | ||
| 270 | s32 new_priority = thread->GetBasePriority(); | ||
| 271 | if (thread->HasWaiters()) { | ||
| 272 | new_priority = std::min(new_priority, thread->waiter_list.front().GetPriority()); | ||
| 273 | } | ||
| 274 | |||
| 275 | // If the priority we would inherit is not different from ours, don't do anything. | ||
| 276 | if (new_priority == thread->GetPriority()) { | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | |||
| 280 | // Ensure we don't violate condition variable red black tree invariants. | ||
| 281 | if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { | ||
| 282 | BeforeUpdatePriority(kernel, cv_tree, thread); | ||
| 283 | } | ||
| 284 | |||
| 285 | // Change the priority. | ||
| 286 | const s32 old_priority = thread->GetPriority(); | ||
| 287 | thread->SetPriority(new_priority); | ||
| 288 | |||
| 289 | // Restore the condition variable, if relevant. | ||
| 290 | if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { | ||
| 291 | AfterUpdatePriority(kernel, cv_tree, thread); | ||
| 292 | } | ||
| 293 | |||
| 294 | // Update the scheduler. | ||
| 295 | KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority); | ||
| 296 | |||
| 297 | // Keep the lock owner up to date. | ||
| 298 | Thread* lock_owner = thread->GetLockOwner(); | ||
| 299 | if (lock_owner == nullptr) { | ||
| 300 | return; | ||
| 301 | } | ||
| 302 | |||
| 303 | // Update the thread in the lock owner's sorted list, and continue inheriting. | ||
| 304 | lock_owner->RemoveWaiterImpl(thread); | ||
| 305 | lock_owner->AddWaiterImpl(thread); | ||
| 306 | thread = lock_owner; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | void Thread::AddWaiter(Thread* thread) { | ||
| 311 | AddWaiterImpl(thread); | ||
| 312 | RestorePriority(kernel, this); | ||
| 313 | } | ||
| 314 | |||
| 315 | void Thread::RemoveWaiter(Thread* thread) { | ||
| 316 | RemoveWaiterImpl(thread); | ||
| 317 | RestorePriority(kernel, this); | ||
| 318 | } | ||
| 319 | |||
| 320 | Thread* Thread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { | ||
| 321 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 322 | |||
| 323 | s32 num_waiters{}; | ||
| 324 | Thread* next_lock_owner{}; | ||
| 325 | auto it = waiter_list.begin(); | ||
| 326 | while (it != waiter_list.end()) { | ||
| 327 | if (it->GetAddressKey() == key) { | ||
| 328 | Thread* thread = std::addressof(*it); | ||
| 329 | |||
| 330 | // Keep track of how many kernel waiters we have. | ||
| 331 | if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { | ||
| 332 | ASSERT((num_kernel_waiters--) > 0); | ||
| 333 | } | ||
| 334 | it = waiter_list.erase(it); | ||
| 335 | |||
| 336 | // Update the next lock owner. | ||
| 337 | if (next_lock_owner == nullptr) { | ||
| 338 | next_lock_owner = thread; | ||
| 339 | next_lock_owner->SetLockOwner(nullptr); | ||
| 340 | } else { | ||
| 341 | next_lock_owner->AddWaiterImpl(thread); | ||
| 342 | } | ||
| 343 | num_waiters++; | ||
| 344 | } else { | ||
| 345 | it++; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | // Do priority updates, if we have a next owner. | ||
| 350 | if (next_lock_owner) { | ||
| 351 | RestorePriority(kernel, this); | ||
| 352 | RestorePriority(kernel, next_lock_owner); | ||
| 353 | } | ||
| 354 | |||
| 355 | // Return output. | ||
| 356 | *out_num_waiters = num_waiters; | ||
| 357 | return next_lock_owner; | ||
| 358 | } | ||
| 359 | |||
| 360 | ResultCode Thread::SetActivity(ThreadActivity value) { | ||
| 361 | KScopedSchedulerLock lock(kernel); | ||
| 362 | |||
| 363 | auto sched_status = GetState(); | ||
| 364 | |||
| 365 | if (sched_status != ThreadState::Runnable && sched_status != ThreadState::Waiting) { | ||
| 366 | return ERR_INVALID_STATE; | ||
| 367 | } | ||
| 368 | |||
| 369 | if (IsTerminationRequested()) { | ||
| 370 | return RESULT_SUCCESS; | ||
| 371 | } | ||
| 372 | |||
| 373 | if (value == ThreadActivity::Paused) { | ||
| 374 | if ((pausing_state & static_cast<u32>(ThreadSchedFlags::ThreadPauseFlag)) != 0) { | ||
| 375 | return ERR_INVALID_STATE; | ||
| 376 | } | ||
| 377 | AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); | ||
| 378 | } else { | ||
| 379 | if ((pausing_state & static_cast<u32>(ThreadSchedFlags::ThreadPauseFlag)) == 0) { | ||
| 380 | return ERR_INVALID_STATE; | ||
| 381 | } | ||
| 382 | RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); | ||
| 383 | } | ||
| 384 | return RESULT_SUCCESS; | ||
| 385 | } | ||
| 386 | |||
| 387 | ResultCode Thread::Sleep(s64 nanoseconds) { | ||
| 388 | Handle event_handle{}; | ||
| 389 | { | ||
| 390 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); | ||
| 391 | SetState(ThreadState::Waiting); | ||
| 392 | SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); | ||
| 393 | } | ||
| 394 | |||
| 395 | if (event_handle != InvalidHandle) { | ||
| 396 | auto& time_manager = kernel.TimeManager(); | ||
| 397 | time_manager.UnscheduleTimeEvent(event_handle); | ||
| 398 | } | ||
| 399 | return RESULT_SUCCESS; | ||
| 400 | } | ||
| 401 | |||
| 402 | void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { | ||
| 403 | const auto old_state = GetRawState(); | ||
| 404 | pausing_state |= static_cast<u32>(flag); | ||
| 405 | const auto base_scheduling = GetState(); | ||
| 406 | thread_state = base_scheduling | static_cast<ThreadState>(pausing_state); | ||
| 407 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 408 | } | ||
| 409 | |||
| 410 | void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { | ||
| 411 | const auto old_state = GetRawState(); | ||
| 412 | pausing_state &= ~static_cast<u32>(flag); | ||
| 413 | const auto base_scheduling = GetState(); | ||
| 414 | thread_state = base_scheduling | static_cast<ThreadState>(pausing_state); | ||
| 415 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||
| 416 | } | ||
| 417 | |||
| 418 | ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { | ||
| 419 | KScopedSchedulerLock lock(kernel); | ||
| 420 | const auto HighestSetCore = [](u64 mask, u32 max_cores) { | ||
| 421 | for (s32 core = static_cast<s32>(max_cores - 1); core >= 0; core--) { | ||
| 422 | if (((mask >> core) & 1) != 0) { | ||
| 423 | return core; | ||
| 424 | } | ||
| 425 | } | ||
| 426 | return -1; | ||
| 427 | }; | ||
| 428 | |||
| 429 | const bool use_override = affinity_override_count != 0; | ||
| 430 | if (new_core == THREADPROCESSORID_DONT_UPDATE) { | ||
| 431 | new_core = use_override ? ideal_core_override : ideal_core; | ||
| 432 | if ((new_affinity_mask & (1ULL << new_core)) == 0) { | ||
| 433 | LOG_ERROR(Kernel, "New affinity mask is incorrect! new_core={}, new_affinity_mask={}", | ||
| 434 | new_core, new_affinity_mask); | ||
| 435 | return ERR_INVALID_COMBINATION; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | if (use_override) { | ||
| 439 | ideal_core_override = new_core; | ||
| 440 | } else { | ||
| 441 | const auto old_affinity_mask = affinity_mask; | ||
| 442 | affinity_mask.SetAffinityMask(new_affinity_mask); | ||
| 443 | ideal_core = new_core; | ||
| 444 | if (old_affinity_mask.GetAffinityMask() != new_affinity_mask) { | ||
| 445 | const s32 old_core = processor_id; | ||
| 446 | if (processor_id >= 0 && !affinity_mask.GetAffinity(processor_id)) { | ||
| 447 | if (static_cast<s32>(ideal_core) < 0) { | ||
| 448 | processor_id = HighestSetCore(affinity_mask.GetAffinityMask(), | ||
| 449 | Core::Hardware::NUM_CPU_CORES); | ||
| 450 | } else { | ||
| 451 | processor_id = ideal_core; | ||
| 452 | } | ||
| 453 | } | ||
| 454 | KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_affinity_mask, old_core); | ||
| 455 | } | ||
| 456 | } | ||
| 457 | return RESULT_SUCCESS; | ||
| 458 | } | ||
| 459 | |||
| 460 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h deleted file mode 100644 index 6b66c9a0e..000000000 --- a/src/core/hle/kernel/thread.h +++ /dev/null | |||
| @@ -1,782 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <functional> | ||
| 9 | #include <span> | ||
| 10 | #include <string> | ||
| 11 | #include <utility> | ||
| 12 | #include <vector> | ||
| 13 | |||
| 14 | #include <boost/intrusive/list.hpp> | ||
| 15 | |||
| 16 | #include "common/common_types.h" | ||
| 17 | #include "common/intrusive_red_black_tree.h" | ||
| 18 | #include "common/spin_lock.h" | ||
| 19 | #include "core/arm/arm_interface.h" | ||
| 20 | #include "core/hle/kernel/k_affinity_mask.h" | ||
| 21 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 22 | #include "core/hle/kernel/object.h" | ||
| 23 | #include "core/hle/kernel/svc_common.h" | ||
| 24 | #include "core/hle/result.h" | ||
| 25 | |||
| 26 | namespace Common { | ||
| 27 | class Fiber; | ||
| 28 | } | ||
| 29 | |||
| 30 | namespace Core { | ||
| 31 | class ARM_Interface; | ||
| 32 | class System; | ||
| 33 | } // namespace Core | ||
| 34 | |||
| 35 | namespace Kernel { | ||
| 36 | |||
| 37 | class GlobalSchedulerContext; | ||
| 38 | class KernelCore; | ||
| 39 | class Process; | ||
| 40 | class KScheduler; | ||
| 41 | |||
| 42 | enum ThreadPriority : u32 { | ||
| 43 | THREADPRIO_HIGHEST = 0, ///< Highest thread priority | ||
| 44 | THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration | ||
| 45 | THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps | ||
| 46 | THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps | ||
| 47 | THREADPRIO_LOWEST = 63, ///< Lowest thread priority | ||
| 48 | THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. | ||
| 49 | }; | ||
| 50 | |||
| 51 | enum ThreadType : u32 { | ||
| 52 | THREADTYPE_USER = 0x1, | ||
| 53 | THREADTYPE_KERNEL = 0x2, | ||
| 54 | THREADTYPE_HLE = 0x4, | ||
| 55 | THREADTYPE_IDLE = 0x8, | ||
| 56 | THREADTYPE_SUSPEND = 0x10, | ||
| 57 | }; | ||
| 58 | |||
| 59 | enum ThreadProcessorId : s32 { | ||
| 60 | /// Indicates that no particular processor core is preferred. | ||
| 61 | THREADPROCESSORID_DONT_CARE = -1, | ||
| 62 | |||
| 63 | /// Run thread on the ideal core specified by the process. | ||
| 64 | THREADPROCESSORID_IDEAL = -2, | ||
| 65 | |||
| 66 | /// Indicates that the preferred processor ID shouldn't be updated in | ||
| 67 | /// a core mask setting operation. | ||
| 68 | THREADPROCESSORID_DONT_UPDATE = -3, | ||
| 69 | |||
| 70 | THREADPROCESSORID_0 = 0, ///< Run thread on core 0 | ||
| 71 | THREADPROCESSORID_1 = 1, ///< Run thread on core 1 | ||
| 72 | THREADPROCESSORID_2 = 2, ///< Run thread on core 2 | ||
| 73 | THREADPROCESSORID_3 = 3, ///< Run thread on core 3 | ||
| 74 | THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this | ||
| 75 | |||
| 76 | /// Allowed CPU mask | ||
| 77 | THREADPROCESSORID_DEFAULT_MASK = (1 << THREADPROCESSORID_0) | (1 << THREADPROCESSORID_1) | | ||
| 78 | (1 << THREADPROCESSORID_2) | (1 << THREADPROCESSORID_3) | ||
| 79 | }; | ||
| 80 | |||
| 81 | enum class ThreadState : u16 { | ||
| 82 | Initialized = 0, | ||
| 83 | Waiting = 1, | ||
| 84 | Runnable = 2, | ||
| 85 | Terminated = 3, | ||
| 86 | |||
| 87 | SuspendShift = 4, | ||
| 88 | Mask = (1 << SuspendShift) - 1, | ||
| 89 | |||
| 90 | ProcessSuspended = (1 << (0 + SuspendShift)), | ||
| 91 | ThreadSuspended = (1 << (1 + SuspendShift)), | ||
| 92 | DebugSuspended = (1 << (2 + SuspendShift)), | ||
| 93 | BacktraceSuspended = (1 << (3 + SuspendShift)), | ||
| 94 | InitSuspended = (1 << (4 + SuspendShift)), | ||
| 95 | |||
| 96 | SuspendFlagMask = ((1 << 5) - 1) << SuspendShift, | ||
| 97 | }; | ||
| 98 | DECLARE_ENUM_FLAG_OPERATORS(ThreadState); | ||
| 99 | |||
| 100 | enum class ThreadWakeupReason { | ||
| 101 | Signal, // The thread was woken up by WakeupAllWaitingThreads due to an object signal. | ||
| 102 | Timeout // The thread was woken up due to a wait timeout. | ||
| 103 | }; | ||
| 104 | |||
| 105 | enum class ThreadActivity : u32 { | ||
| 106 | Normal = 0, | ||
| 107 | Paused = 1, | ||
| 108 | }; | ||
| 109 | |||
| 110 | enum class ThreadSchedFlags : u32 { | ||
| 111 | ProcessPauseFlag = 1 << 4, | ||
| 112 | ThreadPauseFlag = 1 << 5, | ||
| 113 | ProcessDebugPauseFlag = 1 << 6, | ||
| 114 | KernelInitPauseFlag = 1 << 8, | ||
| 115 | }; | ||
| 116 | |||
| 117 | enum class ThreadWaitReasonForDebugging : u32 { | ||
| 118 | None, ///< Thread is not waiting | ||
| 119 | Sleep, ///< Thread is waiting due to a SleepThread SVC | ||
| 120 | IPC, ///< Thread is waiting for the reply from an IPC request | ||
| 121 | Synchronization, ///< Thread is waiting due to a WaitSynchronization SVC | ||
| 122 | ConditionVar, ///< Thread is waiting due to a WaitProcessWideKey SVC | ||
| 123 | Arbitration, ///< Thread is waiting due to a SignalToAddress/WaitForAddress SVC | ||
| 124 | Suspended, ///< Thread is waiting due to process suspension | ||
| 125 | }; | ||
| 126 | |||
| 127 | class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { | ||
| 128 | friend class KScheduler; | ||
| 129 | friend class Process; | ||
| 130 | |||
| 131 | public: | ||
| 132 | explicit Thread(KernelCore& kernel); | ||
| 133 | ~Thread() override; | ||
| 134 | |||
| 135 | using MutexWaitingThreads = std::vector<std::shared_ptr<Thread>>; | ||
| 136 | |||
| 137 | using ThreadContext32 = Core::ARM_Interface::ThreadContext32; | ||
| 138 | using ThreadContext64 = Core::ARM_Interface::ThreadContext64; | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Creates and returns a new thread. The new thread is immediately scheduled | ||
| 142 | * @param system The instance of the whole system | ||
| 143 | * @param name The friendly name desired for the thread | ||
| 144 | * @param entry_point The address at which the thread should start execution | ||
| 145 | * @param priority The thread's priority | ||
| 146 | * @param arg User data to pass to the thread | ||
| 147 | * @param processor_id The ID(s) of the processors on which the thread is desired to be run | ||
| 148 | * @param stack_top The address of the thread's stack top | ||
| 149 | * @param owner_process The parent process for the thread, if null, it's a kernel thread | ||
| 150 | * @return A shared pointer to the newly created thread | ||
| 151 | */ | ||
| 152 | static ResultVal<std::shared_ptr<Thread>> Create(Core::System& system, ThreadType type_flags, | ||
| 153 | std::string name, VAddr entry_point, | ||
| 154 | u32 priority, u64 arg, s32 processor_id, | ||
| 155 | VAddr stack_top, Process* owner_process); | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Creates and returns a new thread. The new thread is immediately scheduled | ||
| 159 | * @param system The instance of the whole system | ||
| 160 | * @param name The friendly name desired for the thread | ||
| 161 | * @param entry_point The address at which the thread should start execution | ||
| 162 | * @param priority The thread's priority | ||
| 163 | * @param arg User data to pass to the thread | ||
| 164 | * @param processor_id The ID(s) of the processors on which the thread is desired to be run | ||
| 165 | * @param stack_top The address of the thread's stack top | ||
| 166 | * @param owner_process The parent process for the thread, if null, it's a kernel thread | ||
| 167 | * @param thread_start_func The function where the host context will start. | ||
| 168 | * @param thread_start_parameter The parameter which will passed to host context on init | ||
| 169 | * @return A shared pointer to the newly created thread | ||
| 170 | */ | ||
| 171 | static ResultVal<std::shared_ptr<Thread>> Create(Core::System& system, ThreadType type_flags, | ||
| 172 | std::string name, VAddr entry_point, | ||
| 173 | u32 priority, u64 arg, s32 processor_id, | ||
| 174 | VAddr stack_top, Process* owner_process, | ||
| 175 | std::function<void(void*)>&& thread_start_func, | ||
| 176 | void* thread_start_parameter); | ||
| 177 | |||
| 178 | std::string GetName() const override { | ||
| 179 | return name; | ||
| 180 | } | ||
| 181 | |||
| 182 | void SetName(std::string new_name) { | ||
| 183 | name = std::move(new_name); | ||
| 184 | } | ||
| 185 | |||
| 186 | std::string GetTypeName() const override { | ||
| 187 | return "Thread"; | ||
| 188 | } | ||
| 189 | |||
| 190 | static constexpr HandleType HANDLE_TYPE = HandleType::Thread; | ||
| 191 | HandleType GetHandleType() const override { | ||
| 192 | return HANDLE_TYPE; | ||
| 193 | } | ||
| 194 | |||
| 195 | /** | ||
| 196 | * Gets the thread's current priority | ||
| 197 | * @return The current thread's priority | ||
| 198 | */ | ||
| 199 | [[nodiscard]] s32 GetPriority() const { | ||
| 200 | return current_priority; | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * Sets the thread's current priority. | ||
| 205 | * @param priority The new priority. | ||
| 206 | */ | ||
| 207 | void SetPriority(s32 priority) { | ||
| 208 | current_priority = priority; | ||
| 209 | } | ||
| 210 | |||
| 211 | /** | ||
| 212 | * Gets the thread's nominal priority. | ||
| 213 | * @return The current thread's nominal priority. | ||
| 214 | */ | ||
| 215 | [[nodiscard]] s32 GetBasePriority() const { | ||
| 216 | return base_priority; | ||
| 217 | } | ||
| 218 | |||
| 219 | /** | ||
| 220 | * Sets the thread's nominal priority. | ||
| 221 | * @param priority The new priority. | ||
| 222 | */ | ||
| 223 | void SetBasePriority(u32 priority); | ||
| 224 | |||
| 225 | /// Changes the core that the thread is running or scheduled to run on. | ||
| 226 | [[nodiscard]] ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); | ||
| 227 | |||
| 228 | /** | ||
| 229 | * Gets the thread's thread ID | ||
| 230 | * @return The thread's ID | ||
| 231 | */ | ||
| 232 | [[nodiscard]] u64 GetThreadID() const { | ||
| 233 | return thread_id; | ||
| 234 | } | ||
| 235 | |||
| 236 | /// Resumes a thread from waiting | ||
| 237 | void Wakeup(); | ||
| 238 | |||
| 239 | ResultCode Start(); | ||
| 240 | |||
| 241 | virtual bool IsSignaled() const override; | ||
| 242 | |||
| 243 | /// Cancels a waiting operation that this thread may or may not be within. | ||
| 244 | /// | ||
| 245 | /// When the thread is within a waiting state, this will set the thread's | ||
| 246 | /// waiting result to signal a canceled wait. The function will then resume | ||
| 247 | /// this thread. | ||
| 248 | /// | ||
| 249 | void CancelWait(); | ||
| 250 | |||
| 251 | void SetSynchronizationResults(KSynchronizationObject* object, ResultCode result); | ||
| 252 | |||
| 253 | void SetSyncedObject(KSynchronizationObject* object, ResultCode result) { | ||
| 254 | SetSynchronizationResults(object, result); | ||
| 255 | } | ||
| 256 | |||
| 257 | ResultCode GetWaitResult(KSynchronizationObject** out) const { | ||
| 258 | *out = signaling_object; | ||
| 259 | return signaling_result; | ||
| 260 | } | ||
| 261 | |||
| 262 | ResultCode GetSignalingResult() const { | ||
| 263 | return signaling_result; | ||
| 264 | } | ||
| 265 | |||
| 266 | /** | ||
| 267 | * Stops a thread, invalidating it from further use | ||
| 268 | */ | ||
| 269 | void Stop(); | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Returns the Thread Local Storage address of the current thread | ||
| 273 | * @returns VAddr of the thread's TLS | ||
| 274 | */ | ||
| 275 | VAddr GetTLSAddress() const { | ||
| 276 | return tls_address; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* | ||
| 280 | * Returns the value of the TPIDR_EL0 Read/Write system register for this thread. | ||
| 281 | * @returns The value of the TPIDR_EL0 register. | ||
| 282 | */ | ||
| 283 | u64 GetTPIDR_EL0() const { | ||
| 284 | return tpidr_el0; | ||
| 285 | } | ||
| 286 | |||
| 287 | /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread. | ||
| 288 | void SetTPIDR_EL0(u64 value) { | ||
| 289 | tpidr_el0 = value; | ||
| 290 | } | ||
| 291 | |||
| 292 | /* | ||
| 293 | * Returns the address of the current thread's command buffer, located in the TLS. | ||
| 294 | * @returns VAddr of the thread's command buffer. | ||
| 295 | */ | ||
| 296 | VAddr GetCommandBufferAddress() const; | ||
| 297 | |||
| 298 | ThreadContext32& GetContext32() { | ||
| 299 | return context_32; | ||
| 300 | } | ||
| 301 | |||
| 302 | const ThreadContext32& GetContext32() const { | ||
| 303 | return context_32; | ||
| 304 | } | ||
| 305 | |||
| 306 | ThreadContext64& GetContext64() { | ||
| 307 | return context_64; | ||
| 308 | } | ||
| 309 | |||
| 310 | const ThreadContext64& GetContext64() const { | ||
| 311 | return context_64; | ||
| 312 | } | ||
| 313 | |||
| 314 | bool IsHLEThread() const { | ||
| 315 | return (type & THREADTYPE_HLE) != 0; | ||
| 316 | } | ||
| 317 | |||
| 318 | bool IsSuspendThread() const { | ||
| 319 | return (type & THREADTYPE_SUSPEND) != 0; | ||
| 320 | } | ||
| 321 | |||
| 322 | bool IsIdleThread() const { | ||
| 323 | return (type & THREADTYPE_IDLE) != 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | bool WasRunning() const { | ||
| 327 | return was_running; | ||
| 328 | } | ||
| 329 | |||
| 330 | void SetWasRunning(bool value) { | ||
| 331 | was_running = value; | ||
| 332 | } | ||
| 333 | |||
| 334 | std::shared_ptr<Common::Fiber>& GetHostContext(); | ||
| 335 | |||
| 336 | ThreadState GetState() const { | ||
| 337 | return thread_state & ThreadState::Mask; | ||
| 338 | } | ||
| 339 | |||
| 340 | ThreadState GetRawState() const { | ||
| 341 | return thread_state; | ||
| 342 | } | ||
| 343 | |||
| 344 | void SetState(ThreadState state); | ||
| 345 | |||
| 346 | s64 GetLastScheduledTick() const { | ||
| 347 | return last_scheduled_tick; | ||
| 348 | } | ||
| 349 | |||
| 350 | void SetLastScheduledTick(s64 tick) { | ||
| 351 | last_scheduled_tick = tick; | ||
| 352 | } | ||
| 353 | |||
| 354 | u64 GetTotalCPUTimeTicks() const { | ||
| 355 | return total_cpu_time_ticks; | ||
| 356 | } | ||
| 357 | |||
| 358 | void UpdateCPUTimeTicks(u64 ticks) { | ||
| 359 | total_cpu_time_ticks += ticks; | ||
| 360 | } | ||
| 361 | |||
| 362 | s32 GetProcessorID() const { | ||
| 363 | return processor_id; | ||
| 364 | } | ||
| 365 | |||
| 366 | s32 GetActiveCore() const { | ||
| 367 | return GetProcessorID(); | ||
| 368 | } | ||
| 369 | |||
| 370 | void SetProcessorID(s32 new_core) { | ||
| 371 | processor_id = new_core; | ||
| 372 | } | ||
| 373 | |||
| 374 | void SetActiveCore(s32 new_core) { | ||
| 375 | processor_id = new_core; | ||
| 376 | } | ||
| 377 | |||
| 378 | Process* GetOwnerProcess() { | ||
| 379 | return owner_process; | ||
| 380 | } | ||
| 381 | |||
| 382 | const Process* GetOwnerProcess() const { | ||
| 383 | return owner_process; | ||
| 384 | } | ||
| 385 | |||
| 386 | const MutexWaitingThreads& GetMutexWaitingThreads() const { | ||
| 387 | return wait_mutex_threads; | ||
| 388 | } | ||
| 389 | |||
| 390 | Thread* GetLockOwner() const { | ||
| 391 | return lock_owner; | ||
| 392 | } | ||
| 393 | |||
| 394 | void SetLockOwner(Thread* owner) { | ||
| 395 | lock_owner = owner; | ||
| 396 | } | ||
| 397 | |||
| 398 | u32 GetIdealCore() const { | ||
| 399 | return ideal_core; | ||
| 400 | } | ||
| 401 | |||
| 402 | const KAffinityMask& GetAffinityMask() const { | ||
| 403 | return affinity_mask; | ||
| 404 | } | ||
| 405 | |||
| 406 | ResultCode SetActivity(ThreadActivity value); | ||
| 407 | |||
| 408 | /// Sleeps this thread for the given amount of nanoseconds. | ||
| 409 | ResultCode Sleep(s64 nanoseconds); | ||
| 410 | |||
| 411 | s64 GetYieldScheduleCount() const { | ||
| 412 | return schedule_count; | ||
| 413 | } | ||
| 414 | |||
| 415 | void SetYieldScheduleCount(s64 count) { | ||
| 416 | schedule_count = count; | ||
| 417 | } | ||
| 418 | |||
| 419 | bool IsRunning() const { | ||
| 420 | return is_running; | ||
| 421 | } | ||
| 422 | |||
| 423 | void SetIsRunning(bool value) { | ||
| 424 | is_running = value; | ||
| 425 | } | ||
| 426 | |||
| 427 | bool IsWaitCancelled() const { | ||
| 428 | return is_sync_cancelled; | ||
| 429 | } | ||
| 430 | |||
| 431 | void ClearWaitCancelled() { | ||
| 432 | is_sync_cancelled = false; | ||
| 433 | } | ||
| 434 | |||
| 435 | Handle GetGlobalHandle() const { | ||
| 436 | return global_handle; | ||
| 437 | } | ||
| 438 | |||
| 439 | bool IsCancellable() const { | ||
| 440 | return is_cancellable; | ||
| 441 | } | ||
| 442 | |||
| 443 | void SetCancellable() { | ||
| 444 | is_cancellable = true; | ||
| 445 | } | ||
| 446 | |||
| 447 | void ClearCancellable() { | ||
| 448 | is_cancellable = false; | ||
| 449 | } | ||
| 450 | |||
| 451 | bool IsTerminationRequested() const { | ||
| 452 | return will_be_terminated || GetRawState() == ThreadState::Terminated; | ||
| 453 | } | ||
| 454 | |||
| 455 | bool IsPaused() const { | ||
| 456 | return pausing_state != 0; | ||
| 457 | } | ||
| 458 | |||
| 459 | bool IsContinuousOnSVC() const { | ||
| 460 | return is_continuous_on_svc; | ||
| 461 | } | ||
| 462 | |||
| 463 | void SetContinuousOnSVC(bool is_continuous) { | ||
| 464 | is_continuous_on_svc = is_continuous; | ||
| 465 | } | ||
| 466 | |||
| 467 | bool IsPhantomMode() const { | ||
| 468 | return is_phantom_mode; | ||
| 469 | } | ||
| 470 | |||
| 471 | void SetPhantomMode(bool phantom) { | ||
| 472 | is_phantom_mode = phantom; | ||
| 473 | } | ||
| 474 | |||
| 475 | bool HasExited() const { | ||
| 476 | return has_exited; | ||
| 477 | } | ||
| 478 | |||
| 479 | class QueueEntry { | ||
| 480 | public: | ||
| 481 | constexpr QueueEntry() = default; | ||
| 482 | |||
| 483 | constexpr void Initialize() { | ||
| 484 | prev = nullptr; | ||
| 485 | next = nullptr; | ||
| 486 | } | ||
| 487 | |||
| 488 | constexpr Thread* GetPrev() const { | ||
| 489 | return prev; | ||
| 490 | } | ||
| 491 | constexpr Thread* GetNext() const { | ||
| 492 | return next; | ||
| 493 | } | ||
| 494 | constexpr void SetPrev(Thread* thread) { | ||
| 495 | prev = thread; | ||
| 496 | } | ||
| 497 | constexpr void SetNext(Thread* thread) { | ||
| 498 | next = thread; | ||
| 499 | } | ||
| 500 | |||
| 501 | private: | ||
| 502 | Thread* prev{}; | ||
| 503 | Thread* next{}; | ||
| 504 | }; | ||
| 505 | |||
| 506 | QueueEntry& GetPriorityQueueEntry(s32 core) { | ||
| 507 | return per_core_priority_queue_entry[core]; | ||
| 508 | } | ||
| 509 | |||
| 510 | const QueueEntry& GetPriorityQueueEntry(s32 core) const { | ||
| 511 | return per_core_priority_queue_entry[core]; | ||
| 512 | } | ||
| 513 | |||
| 514 | s32 GetDisableDispatchCount() const { | ||
| 515 | return disable_count; | ||
| 516 | } | ||
| 517 | |||
| 518 | void DisableDispatch() { | ||
| 519 | ASSERT(GetDisableDispatchCount() >= 0); | ||
| 520 | disable_count++; | ||
| 521 | } | ||
| 522 | |||
| 523 | void EnableDispatch() { | ||
| 524 | ASSERT(GetDisableDispatchCount() > 0); | ||
| 525 | disable_count--; | ||
| 526 | } | ||
| 527 | |||
| 528 | void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) { | ||
| 529 | wait_reason_for_debugging = reason; | ||
| 530 | } | ||
| 531 | |||
| 532 | [[nodiscard]] ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const { | ||
| 533 | return wait_reason_for_debugging; | ||
| 534 | } | ||
| 535 | |||
| 536 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { | ||
| 537 | wait_objects_for_debugging.clear(); | ||
| 538 | wait_objects_for_debugging.reserve(objects.size()); | ||
| 539 | for (const auto& object : objects) { | ||
| 540 | wait_objects_for_debugging.emplace_back(object); | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | [[nodiscard]] const std::vector<KSynchronizationObject*>& GetWaitObjectsForDebugging() const { | ||
| 545 | return wait_objects_for_debugging; | ||
| 546 | } | ||
| 547 | |||
| 548 | void SetMutexWaitAddressForDebugging(VAddr address) { | ||
| 549 | mutex_wait_address_for_debugging = address; | ||
| 550 | } | ||
| 551 | |||
| 552 | [[nodiscard]] VAddr GetMutexWaitAddressForDebugging() const { | ||
| 553 | return mutex_wait_address_for_debugging; | ||
| 554 | } | ||
| 555 | |||
| 556 | void AddWaiter(Thread* thread); | ||
| 557 | |||
| 558 | void RemoveWaiter(Thread* thread); | ||
| 559 | |||
| 560 | [[nodiscard]] Thread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key); | ||
| 561 | |||
| 562 | [[nodiscard]] VAddr GetAddressKey() const { | ||
| 563 | return address_key; | ||
| 564 | } | ||
| 565 | |||
| 566 | [[nodiscard]] u32 GetAddressKeyValue() const { | ||
| 567 | return address_key_value; | ||
| 568 | } | ||
| 569 | |||
| 570 | void SetAddressKey(VAddr key) { | ||
| 571 | address_key = key; | ||
| 572 | } | ||
| 573 | |||
| 574 | void SetAddressKey(VAddr key, u32 val) { | ||
| 575 | address_key = key; | ||
| 576 | address_key_value = val; | ||
| 577 | } | ||
| 578 | |||
| 579 | private: | ||
| 580 | static constexpr size_t PriorityInheritanceCountMax = 10; | ||
| 581 | union SyncObjectBuffer { | ||
| 582 | std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{}; | ||
| 583 | std::array<Handle, | ||
| 584 | Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))> | ||
| 585 | handles; | ||
| 586 | constexpr SyncObjectBuffer() {} | ||
| 587 | }; | ||
| 588 | static_assert(sizeof(SyncObjectBuffer::sync_objects) == sizeof(SyncObjectBuffer::handles)); | ||
| 589 | |||
| 590 | struct ConditionVariableComparator { | ||
| 591 | struct LightCompareType { | ||
| 592 | u64 cv_key{}; | ||
| 593 | s32 priority{}; | ||
| 594 | |||
| 595 | [[nodiscard]] constexpr u64 GetConditionVariableKey() const { | ||
| 596 | return cv_key; | ||
| 597 | } | ||
| 598 | |||
| 599 | [[nodiscard]] constexpr s32 GetPriority() const { | ||
| 600 | return priority; | ||
| 601 | } | ||
| 602 | }; | ||
| 603 | |||
| 604 | template <typename T> | ||
| 605 | requires( | ||
| 606 | std::same_as<T, Thread> || | ||
| 607 | std::same_as<T, LightCompareType>) static constexpr int Compare(const T& lhs, | ||
| 608 | const Thread& rhs) { | ||
| 609 | const uintptr_t l_key = lhs.GetConditionVariableKey(); | ||
| 610 | const uintptr_t r_key = rhs.GetConditionVariableKey(); | ||
| 611 | |||
| 612 | if (l_key < r_key) { | ||
| 613 | // Sort first by key | ||
| 614 | return -1; | ||
| 615 | } else if (l_key == r_key && lhs.GetPriority() < rhs.GetPriority()) { | ||
| 616 | // And then by priority. | ||
| 617 | return -1; | ||
| 618 | } else { | ||
| 619 | return 1; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | }; | ||
| 623 | |||
| 624 | Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{}; | ||
| 625 | |||
| 626 | using ConditionVariableThreadTreeTraits = | ||
| 627 | Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&Thread::condvar_arbiter_tree_node>; | ||
| 628 | using ConditionVariableThreadTree = | ||
| 629 | ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>; | ||
| 630 | |||
| 631 | public: | ||
| 632 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; | ||
| 633 | |||
| 634 | [[nodiscard]] uintptr_t GetConditionVariableKey() const { | ||
| 635 | return condvar_key; | ||
| 636 | } | ||
| 637 | |||
| 638 | [[nodiscard]] uintptr_t GetAddressArbiterKey() const { | ||
| 639 | return condvar_key; | ||
| 640 | } | ||
| 641 | |||
| 642 | void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, uintptr_t cv_key, | ||
| 643 | u32 value) { | ||
| 644 | condvar_tree = tree; | ||
| 645 | condvar_key = cv_key; | ||
| 646 | address_key = address; | ||
| 647 | address_key_value = value; | ||
| 648 | } | ||
| 649 | |||
| 650 | void ClearConditionVariable() { | ||
| 651 | condvar_tree = nullptr; | ||
| 652 | } | ||
| 653 | |||
| 654 | [[nodiscard]] bool IsWaitingForConditionVariable() const { | ||
| 655 | return condvar_tree != nullptr; | ||
| 656 | } | ||
| 657 | |||
| 658 | void SetAddressArbiter(ConditionVariableThreadTree* tree, uintptr_t address) { | ||
| 659 | condvar_tree = tree; | ||
| 660 | condvar_key = address; | ||
| 661 | } | ||
| 662 | |||
| 663 | void ClearAddressArbiter() { | ||
| 664 | condvar_tree = nullptr; | ||
| 665 | } | ||
| 666 | |||
| 667 | [[nodiscard]] bool IsWaitingForAddressArbiter() const { | ||
| 668 | return condvar_tree != nullptr; | ||
| 669 | } | ||
| 670 | |||
| 671 | [[nodiscard]] ConditionVariableThreadTree* GetConditionVariableTree() const { | ||
| 672 | return condvar_tree; | ||
| 673 | } | ||
| 674 | |||
| 675 | [[nodiscard]] bool HasWaiters() const { | ||
| 676 | return !waiter_list.empty(); | ||
| 677 | } | ||
| 678 | |||
| 679 | private: | ||
| 680 | void AddSchedulingFlag(ThreadSchedFlags flag); | ||
| 681 | void RemoveSchedulingFlag(ThreadSchedFlags flag); | ||
| 682 | void AddWaiterImpl(Thread* thread); | ||
| 683 | void RemoveWaiterImpl(Thread* thread); | ||
| 684 | static void RestorePriority(KernelCore& kernel, Thread* thread); | ||
| 685 | |||
| 686 | Common::SpinLock context_guard{}; | ||
| 687 | ThreadContext32 context_32{}; | ||
| 688 | ThreadContext64 context_64{}; | ||
| 689 | std::shared_ptr<Common::Fiber> host_context{}; | ||
| 690 | |||
| 691 | ThreadState thread_state = ThreadState::Initialized; | ||
| 692 | |||
| 693 | u64 thread_id = 0; | ||
| 694 | |||
| 695 | VAddr entry_point = 0; | ||
| 696 | VAddr stack_top = 0; | ||
| 697 | std::atomic_int disable_count = 0; | ||
| 698 | |||
| 699 | ThreadType type; | ||
| 700 | |||
| 701 | /// Nominal thread priority, as set by the emulated application. | ||
| 702 | /// The nominal priority is the thread priority without priority | ||
| 703 | /// inheritance taken into account. | ||
| 704 | s32 base_priority{}; | ||
| 705 | |||
| 706 | /// Current thread priority. This may change over the course of the | ||
| 707 | /// thread's lifetime in order to facilitate priority inheritance. | ||
| 708 | s32 current_priority{}; | ||
| 709 | |||
| 710 | u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. | ||
| 711 | s64 schedule_count{}; | ||
| 712 | s64 last_scheduled_tick{}; | ||
| 713 | |||
| 714 | s32 processor_id = 0; | ||
| 715 | |||
| 716 | VAddr tls_address = 0; ///< Virtual address of the Thread Local Storage of the thread | ||
| 717 | u64 tpidr_el0 = 0; ///< TPIDR_EL0 read/write system register. | ||
| 718 | |||
| 719 | /// Process that owns this thread | ||
| 720 | Process* owner_process; | ||
| 721 | |||
| 722 | /// Objects that the thread is waiting on, in the same order as they were | ||
| 723 | /// passed to WaitSynchronization. This is used for debugging only. | ||
| 724 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; | ||
| 725 | |||
| 726 | /// The current mutex wait address. This is used for debugging only. | ||
| 727 | VAddr mutex_wait_address_for_debugging{}; | ||
| 728 | |||
| 729 | /// The reason the thread is waiting. This is used for debugging only. | ||
| 730 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; | ||
| 731 | |||
| 732 | KSynchronizationObject* signaling_object; | ||
| 733 | ResultCode signaling_result{RESULT_SUCCESS}; | ||
| 734 | |||
| 735 | /// List of threads that are waiting for a mutex that is held by this thread. | ||
| 736 | MutexWaitingThreads wait_mutex_threads; | ||
| 737 | |||
| 738 | /// Thread that owns the lock that this thread is waiting for. | ||
| 739 | Thread* lock_owner{}; | ||
| 740 | |||
| 741 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. | ||
| 742 | Handle global_handle = 0; | ||
| 743 | |||
| 744 | KScheduler* scheduler = nullptr; | ||
| 745 | |||
| 746 | std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; | ||
| 747 | |||
| 748 | u32 ideal_core{0xFFFFFFFF}; | ||
| 749 | KAffinityMask affinity_mask{}; | ||
| 750 | |||
| 751 | s32 ideal_core_override = -1; | ||
| 752 | u32 affinity_override_count = 0; | ||
| 753 | |||
| 754 | u32 pausing_state = 0; | ||
| 755 | bool is_running = false; | ||
| 756 | bool is_cancellable = false; | ||
| 757 | bool is_sync_cancelled = false; | ||
| 758 | |||
| 759 | bool is_continuous_on_svc = false; | ||
| 760 | |||
| 761 | bool will_be_terminated = false; | ||
| 762 | bool is_phantom_mode = false; | ||
| 763 | bool has_exited = false; | ||
| 764 | |||
| 765 | bool was_running = false; | ||
| 766 | |||
| 767 | bool signaled{}; | ||
| 768 | |||
| 769 | ConditionVariableThreadTree* condvar_tree{}; | ||
| 770 | uintptr_t condvar_key{}; | ||
| 771 | VAddr address_key{}; | ||
| 772 | u32 address_key_value{}; | ||
| 773 | s32 num_kernel_waiters{}; | ||
| 774 | |||
| 775 | using WaiterList = boost::intrusive::list<Thread>; | ||
| 776 | WaiterList waiter_list{}; | ||
| 777 | WaiterList pinned_waiter_list{}; | ||
| 778 | |||
| 779 | std::string name; | ||
| 780 | }; | ||
| 781 | |||
| 782 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 832edd629..fd0630019 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | #include "core/core_timing_util.h" | 8 | #include "core/core_timing_util.h" |
| 9 | #include "core/hle/kernel/handle_table.h" | 9 | #include "core/hle/kernel/handle_table.h" |
| 10 | #include "core/hle/kernel/k_scheduler.h" | 10 | #include "core/hle/kernel/k_scheduler.h" |
| 11 | #include "core/hle/kernel/k_thread.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | #include "core/hle/kernel/time_manager.h" | 13 | #include "core/hle/kernel/time_manager.h" |
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| @@ -18,50 +18,30 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { | |||
| 18 | time_manager_event_type = Core::Timing::CreateEvent( | 18 | time_manager_event_type = Core::Timing::CreateEvent( |
| 19 | "Kernel::TimeManagerCallback", | 19 | "Kernel::TimeManagerCallback", |
| 20 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { | 20 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { |
| 21 | std::shared_ptr<Thread> thread; | 21 | std::shared_ptr<KThread> thread; |
| 22 | { | 22 | { |
| 23 | std::lock_guard lock{mutex}; | 23 | std::lock_guard lock{mutex}; |
| 24 | const auto proper_handle = static_cast<Handle>(thread_handle); | 24 | thread = SharedFrom<KThread>(reinterpret_cast<KThread*>(thread_handle)); |
| 25 | if (cancelled_events[proper_handle]) { | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | thread = system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); | ||
| 29 | } | ||
| 30 | |||
| 31 | if (thread) { | ||
| 32 | // Thread can be null if process has exited | ||
| 33 | thread->Wakeup(); | ||
| 34 | } | 25 | } |
| 26 | thread->Wakeup(); | ||
| 35 | }); | 27 | }); |
| 36 | } | 28 | } |
| 37 | 29 | ||
| 38 | void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { | 30 | void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { |
| 39 | std::lock_guard lock{mutex}; | 31 | std::lock_guard lock{mutex}; |
| 40 | event_handle = timetask->GetGlobalHandle(); | ||
| 41 | if (nanoseconds > 0) { | 32 | if (nanoseconds > 0) { |
| 42 | ASSERT(timetask); | 33 | ASSERT(thread); |
| 43 | ASSERT(timetask->GetState() != ThreadState::Runnable); | 34 | ASSERT(thread->GetState() != ThreadState::Runnable); |
| 44 | system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds}, | 35 | system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds}, |
| 45 | time_manager_event_type, event_handle); | 36 | time_manager_event_type, |
| 46 | } else { | 37 | reinterpret_cast<uintptr_t>(thread)); |
| 47 | event_handle = InvalidHandle; | ||
| 48 | } | ||
| 49 | cancelled_events[event_handle] = false; | ||
| 50 | } | ||
| 51 | |||
| 52 | void TimeManager::UnscheduleTimeEvent(Handle event_handle) { | ||
| 53 | std::lock_guard lock{mutex}; | ||
| 54 | if (event_handle == InvalidHandle) { | ||
| 55 | return; | ||
| 56 | } | 38 | } |
| 57 | system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle); | ||
| 58 | cancelled_events[event_handle] = true; | ||
| 59 | } | 39 | } |
| 60 | 40 | ||
| 61 | void TimeManager::CancelTimeEvent(Thread* time_task) { | 41 | void TimeManager::UnscheduleTimeEvent(KThread* thread) { |
| 62 | std::lock_guard lock{mutex}; | 42 | std::lock_guard lock{mutex}; |
| 63 | const Handle event_handle = time_task->GetGlobalHandle(); | 43 | system.CoreTiming().UnscheduleEvent(time_manager_event_type, |
| 64 | UnscheduleTimeEvent(event_handle); | 44 | reinterpret_cast<uintptr_t>(thread)); |
| 65 | } | 45 | } |
| 66 | 46 | ||
| 67 | } // namespace Kernel | 47 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index f39df39a0..0d7f05f30 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h | |||
| @@ -20,7 +20,7 @@ struct EventType; | |||
| 20 | 20 | ||
| 21 | namespace Kernel { | 21 | namespace Kernel { |
| 22 | 22 | ||
| 23 | class Thread; | 23 | class KThread; |
| 24 | 24 | ||
| 25 | /** | 25 | /** |
| 26 | * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp | 26 | * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp |
| @@ -31,18 +31,14 @@ public: | |||
| 31 | explicit TimeManager(Core::System& system); | 31 | explicit TimeManager(Core::System& system); |
| 32 | 32 | ||
| 33 | /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' | 33 | /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' |
| 34 | /// returns a non-invalid handle in `event_handle` if correctly scheduled | 34 | void ScheduleTimeEvent(KThread* time_task, s64 nanoseconds); |
| 35 | void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds); | ||
| 36 | 35 | ||
| 37 | /// Unschedule an existing time event | 36 | /// Unschedule an existing time event |
| 38 | void UnscheduleTimeEvent(Handle event_handle); | 37 | void UnscheduleTimeEvent(KThread* thread); |
| 39 | |||
| 40 | void CancelTimeEvent(Thread* time_task); | ||
| 41 | 38 | ||
| 42 | private: | 39 | private: |
| 43 | Core::System& system; | 40 | Core::System& system; |
| 44 | std::shared_ptr<Core::Timing::EventType> time_manager_event_type; | 41 | std::shared_ptr<Core::Timing::EventType> time_manager_event_type; |
| 45 | std::unordered_map<Handle, bool> cancelled_events; | ||
| 46 | std::mutex mutex; | 42 | std::mutex mutex; |
| 47 | }; | 43 | }; |
| 48 | 44 | ||
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index 05e9f7464..777799d12 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h | |||
| @@ -72,6 +72,8 @@ public: | |||
| 72 | /// is closed. | 72 | /// is closed. |
| 73 | ResultCode Reset(); | 73 | ResultCode Reset(); |
| 74 | 74 | ||
| 75 | void Finalize() override {} | ||
| 76 | |||
| 75 | private: | 77 | private: |
| 76 | /// The base address for the memory managed by this instance. | 78 | /// The base address for the memory managed by this instance. |
| 77 | VAddr base_address{}; | 79 | VAddr base_address{}; |
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp deleted file mode 100644 index fc2f7c424..000000000 --- a/src/core/hle/kernel/writable_event.cpp +++ /dev/null | |||
| @@ -1,45 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "core/hle/kernel/kernel.h" | ||
| 8 | #include "core/hle/kernel/object.h" | ||
| 9 | #include "core/hle/kernel/readable_event.h" | ||
| 10 | #include "core/hle/kernel/thread.h" | ||
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {} | ||
| 16 | WritableEvent::~WritableEvent() = default; | ||
| 17 | |||
| 18 | EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { | ||
| 19 | std::shared_ptr<WritableEvent> writable_event(new WritableEvent(kernel)); | ||
| 20 | std::shared_ptr<ReadableEvent> readable_event(new ReadableEvent(kernel)); | ||
| 21 | |||
| 22 | writable_event->name = name + ":Writable"; | ||
| 23 | writable_event->readable = readable_event; | ||
| 24 | readable_event->name = name + ":Readable"; | ||
| 25 | |||
| 26 | return {std::move(readable_event), std::move(writable_event)}; | ||
| 27 | } | ||
| 28 | |||
| 29 | std::shared_ptr<ReadableEvent> WritableEvent::GetReadableEvent() const { | ||
| 30 | return readable; | ||
| 31 | } | ||
| 32 | |||
| 33 | void WritableEvent::Signal() { | ||
| 34 | readable->Signal(); | ||
| 35 | } | ||
| 36 | |||
| 37 | void WritableEvent::Clear() { | ||
| 38 | readable->Clear(); | ||
| 39 | } | ||
| 40 | |||
| 41 | bool WritableEvent::IsSignaled() const { | ||
| 42 | return readable->IsSignaled(); | ||
| 43 | } | ||
| 44 | |||
| 45 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h deleted file mode 100644 index 6189cf65c..000000000 --- a/src/core/hle/kernel/writable_event.h +++ /dev/null | |||
| @@ -1,59 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | |||
| 9 | #include "core/hle/kernel/object.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | class KernelCore; | ||
| 14 | class ReadableEvent; | ||
| 15 | class WritableEvent; | ||
| 16 | |||
| 17 | struct EventPair { | ||
| 18 | std::shared_ptr<ReadableEvent> readable; | ||
| 19 | std::shared_ptr<WritableEvent> writable; | ||
| 20 | }; | ||
| 21 | |||
| 22 | class WritableEvent final : public Object { | ||
| 23 | public: | ||
| 24 | ~WritableEvent() override; | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Creates an event | ||
| 28 | * @param kernel The kernel instance to create this event under. | ||
| 29 | * @param name Optional name of event | ||
| 30 | */ | ||
| 31 | static EventPair CreateEventPair(KernelCore& kernel, std::string name = "Unknown"); | ||
| 32 | |||
| 33 | std::string GetTypeName() const override { | ||
| 34 | return "WritableEvent"; | ||
| 35 | } | ||
| 36 | std::string GetName() const override { | ||
| 37 | return name; | ||
| 38 | } | ||
| 39 | |||
| 40 | static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent; | ||
| 41 | HandleType GetHandleType() const override { | ||
| 42 | return HANDLE_TYPE; | ||
| 43 | } | ||
| 44 | |||
| 45 | std::shared_ptr<ReadableEvent> GetReadableEvent() const; | ||
| 46 | |||
| 47 | void Signal(); | ||
| 48 | void Clear(); | ||
| 49 | bool IsSignaled() const; | ||
| 50 | |||
| 51 | private: | ||
| 52 | explicit WritableEvent(KernelCore& kernel); | ||
| 53 | |||
| 54 | std::shared_ptr<ReadableEvent> readable; | ||
| 55 | |||
| 56 | std::string name; ///< Name of event (optional) | ||
| 57 | }; | ||
| 58 | |||
| 59 | } // namespace Kernel | ||
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 6981f8ee7..3ec0e1eca 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -32,9 +32,15 @@ | |||
| 32 | 32 | ||
| 33 | namespace Service::Account { | 33 | namespace Service::Account { |
| 34 | 34 | ||
| 35 | constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30}; | 35 | constexpr ResultCode ERR_INVALID_USER_ID{ErrorModule::Account, 20}; |
| 36 | constexpr ResultCode ERR_INVALID_APPLICATION_ID{ErrorModule::Account, 22}; | ||
| 37 | constexpr ResultCode ERR_INVALID_BUFFER{ErrorModule::Account, 30}; | ||
| 38 | constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 31}; | ||
| 36 | constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100}; | 39 | constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100}; |
| 37 | 40 | ||
| 41 | // Thumbnails are hard coded to be at least this size | ||
| 42 | constexpr std::size_t THUMBNAIL_SIZE = 0x24000; | ||
| 43 | |||
| 38 | static std::string GetImagePath(Common::UUID uuid) { | 44 | static std::string GetImagePath(Common::UUID uuid) { |
| 39 | return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + | 45 | return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + |
| 40 | "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; | 46 | "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; |
| @@ -369,7 +375,7 @@ protected: | |||
| 369 | if (user_data.size() < sizeof(ProfileData)) { | 375 | if (user_data.size() < sizeof(ProfileData)) { |
| 370 | LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); | 376 | LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); |
| 371 | IPC::ResponseBuilder rb{ctx, 2}; | 377 | IPC::ResponseBuilder rb{ctx, 2}; |
| 372 | rb.Push(ERR_INVALID_BUFFER_SIZE); | 378 | rb.Push(ERR_INVALID_BUFFER); |
| 373 | return; | 379 | return; |
| 374 | } | 380 | } |
| 375 | 381 | ||
| @@ -402,7 +408,7 @@ protected: | |||
| 402 | if (user_data.size() < sizeof(ProfileData)) { | 408 | if (user_data.size() < sizeof(ProfileData)) { |
| 403 | LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); | 409 | LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); |
| 404 | IPC::ResponseBuilder rb{ctx, 2}; | 410 | IPC::ResponseBuilder rb{ctx, 2}; |
| 405 | rb.Push(ERR_INVALID_BUFFER_SIZE); | 411 | rb.Push(ERR_INVALID_BUFFER); |
| 406 | return; | 412 | return; |
| 407 | } | 413 | } |
| 408 | 414 | ||
| @@ -534,7 +540,7 @@ private: | |||
| 534 | rb.Push(RESULT_SUCCESS); | 540 | rb.Push(RESULT_SUCCESS); |
| 535 | } | 541 | } |
| 536 | 542 | ||
| 537 | Common::UUID user_id; | 543 | Common::UUID user_id{Common::INVALID_UUID}; |
| 538 | }; | 544 | }; |
| 539 | 545 | ||
| 540 | // 6.0.0+ | 546 | // 6.0.0+ |
| @@ -811,6 +817,55 @@ void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ct | |||
| 811 | rb.Push(RESULT_SUCCESS); | 817 | rb.Push(RESULT_SUCCESS); |
| 812 | } | 818 | } |
| 813 | 819 | ||
| 820 | void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx) { | ||
| 821 | IPC::RequestParser rp{ctx}; | ||
| 822 | const auto uuid = rp.PopRaw<Common::UUID>(); | ||
| 823 | |||
| 824 | LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}", uuid.Format()); | ||
| 825 | |||
| 826 | // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable | ||
| 827 | // way of confirming things like the TID, we're going to assume a non zero value for the time | ||
| 828 | // being. | ||
| 829 | constexpr u64 tid{1}; | ||
| 830 | StoreSaveDataThumbnail(ctx, uuid, tid); | ||
| 831 | } | ||
| 832 | |||
| 833 | void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx) { | ||
| 834 | IPC::RequestParser rp{ctx}; | ||
| 835 | const auto uuid = rp.PopRaw<Common::UUID>(); | ||
| 836 | const auto tid = rp.Pop<u64_le>(); | ||
| 837 | |||
| 838 | LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}, tid={:016X}", uuid.Format(), tid); | ||
| 839 | StoreSaveDataThumbnail(ctx, uuid, tid); | ||
| 840 | } | ||
| 841 | |||
| 842 | void Module::Interface::StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx, | ||
| 843 | const Common::UUID& uuid, const u64 tid) { | ||
| 844 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 845 | |||
| 846 | if (tid == 0) { | ||
| 847 | LOG_ERROR(Service_ACC, "TitleID is not valid!"); | ||
| 848 | rb.Push(ERR_INVALID_APPLICATION_ID); | ||
| 849 | return; | ||
| 850 | } | ||
| 851 | |||
| 852 | if (!uuid) { | ||
| 853 | LOG_ERROR(Service_ACC, "User ID is not valid!"); | ||
| 854 | rb.Push(ERR_INVALID_USER_ID); | ||
| 855 | return; | ||
| 856 | } | ||
| 857 | const auto thumbnail_size = ctx.GetReadBufferSize(); | ||
| 858 | if (thumbnail_size != THUMBNAIL_SIZE) { | ||
| 859 | LOG_ERROR(Service_ACC, "Buffer size is empty! size={:X} expecting {:X}", thumbnail_size, | ||
| 860 | THUMBNAIL_SIZE); | ||
| 861 | rb.Push(ERR_INVALID_BUFFER_SIZE); | ||
| 862 | return; | ||
| 863 | } | ||
| 864 | |||
| 865 | // TODO(ogniK): Construct save data thumbnail | ||
| 866 | rb.Push(RESULT_SUCCESS); | ||
| 867 | } | ||
| 868 | |||
| 814 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { | 869 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { |
| 815 | LOG_DEBUG(Service_ACC, "called"); | 870 | LOG_DEBUG(Service_ACC, "called"); |
| 816 | // A u8 is passed into this function which we can safely ignore. It's to determine if we have | 871 | // A u8 is passed into this function which we can safely ignore. It's to determine if we have |
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index ab8edc049..0e3ad8ec6 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/uuid.h" | ||
| 7 | #include "core/hle/service/glue/manager.h" | 8 | #include "core/hle/service/glue/manager.h" |
| 8 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 9 | 10 | ||
| @@ -36,9 +37,13 @@ public: | |||
| 36 | void ListQualifiedUsers(Kernel::HLERequestContext& ctx); | 37 | void ListQualifiedUsers(Kernel::HLERequestContext& ctx); |
| 37 | void LoadOpenContext(Kernel::HLERequestContext& ctx); | 38 | void LoadOpenContext(Kernel::HLERequestContext& ctx); |
| 38 | void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); | 39 | void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); |
| 40 | void StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx); | ||
| 41 | void StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx); | ||
| 39 | 42 | ||
| 40 | private: | 43 | private: |
| 41 | ResultCode InitializeApplicationInfoBase(); | 44 | ResultCode InitializeApplicationInfoBase(); |
| 45 | void StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx, const Common::UUID& uuid, | ||
| 46 | const u64 tid); | ||
| 42 | 47 | ||
| 43 | enum class ApplicationType : u32_le { | 48 | enum class ApplicationType : u32_le { |
| 44 | GameCard = 0, | 49 | GameCard = 0, |
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index d2bb8c2c8..49b22583e 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp | |||
| @@ -29,7 +29,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 29 | {104, nullptr, "GetProfileUpdateNotifier"}, | 29 | {104, nullptr, "GetProfileUpdateNotifier"}, |
| 30 | {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ | 30 | {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ |
| 31 | {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ | 31 | {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ |
| 32 | {110, nullptr, "StoreSaveDataThumbnail"}, | 32 | {110, &ACC_SU::StoreSaveDataThumbnailSystem, "StoreSaveDataThumbnail"}, |
| 33 | {111, nullptr, "ClearSaveDataThumbnail"}, | 33 | {111, nullptr, "ClearSaveDataThumbnail"}, |
| 34 | {112, nullptr, "LoadSaveDataThumbnail"}, | 34 | {112, nullptr, "LoadSaveDataThumbnail"}, |
| 35 | {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ | 35 | {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ |
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 75a24f8f5..8d66d180d 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp | |||
| @@ -26,7 +26,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 26 | {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, | 26 | {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, |
| 27 | {102, nullptr, "AuthenticateApplicationAsync"}, | 27 | {102, nullptr, "AuthenticateApplicationAsync"}, |
| 28 | {103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ | 28 | {103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ |
| 29 | {110, nullptr, "StoreSaveDataThumbnail"}, | 29 | {110, &ACC_U0::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"}, |
| 30 | {111, nullptr, "ClearSaveDataThumbnail"}, | 30 | {111, nullptr, "ClearSaveDataThumbnail"}, |
| 31 | {120, nullptr, "CreateGuestLoginRequest"}, | 31 | {120, nullptr, "CreateGuestLoginRequest"}, |
| 32 | {130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+ | 32 | {130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+ |
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index a4aa5316a..951081cd0 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp | |||
| @@ -29,7 +29,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 29 | {104, nullptr, "GetProfileUpdateNotifier"}, | 29 | {104, nullptr, "GetProfileUpdateNotifier"}, |
| 30 | {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ | 30 | {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ |
| 31 | {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ | 31 | {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ |
| 32 | {110, nullptr, "StoreSaveDataThumbnail"}, | 32 | {110, &ACC_U1::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"}, |
| 33 | {111, nullptr, "ClearSaveDataThumbnail"}, | 33 | {111, nullptr, "ClearSaveDataThumbnail"}, |
| 34 | {112, nullptr, "LoadSaveDataThumbnail"}, | 34 | {112, nullptr, "LoadSaveDataThumbnail"}, |
| 35 | {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ | 35 | {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 9b829e957..50b2c58e2 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -41,12 +41,18 @@ constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/ | |||
| 41 | ProfileManager::ProfileManager() { | 41 | ProfileManager::ProfileManager() { |
| 42 | ParseUserSaveFile(); | 42 | ParseUserSaveFile(); |
| 43 | 43 | ||
| 44 | if (user_count == 0) | 44 | // Create an user if none are present |
| 45 | if (user_count == 0) { | ||
| 45 | CreateNewUser(UUID::Generate(), "yuzu"); | 46 | CreateNewUser(UUID::Generate(), "yuzu"); |
| 47 | } | ||
| 46 | 48 | ||
| 47 | auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1); | 49 | auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1); |
| 48 | if (UserExistsIndex(current)) | 50 | |
| 51 | // If user index don't exist. Load the first user and change the active user | ||
| 52 | if (!UserExistsIndex(current)) { | ||
| 49 | current = 0; | 53 | current = 0; |
| 54 | Settings::values.current_user = 0; | ||
| 55 | } | ||
| 50 | 56 | ||
| 51 | OpenUser(*GetUser(current)); | 57 | OpenUser(*GetUser(current)); |
| 52 | } | 58 | } |
| @@ -227,17 +233,17 @@ void ProfileManager::CloseUser(UUID uuid) { | |||
| 227 | 233 | ||
| 228 | /// Gets all valid user ids on the system | 234 | /// Gets all valid user ids on the system |
| 229 | UserIDArray ProfileManager::GetAllUsers() const { | 235 | UserIDArray ProfileManager::GetAllUsers() const { |
| 230 | UserIDArray output; | 236 | UserIDArray output{}; |
| 231 | std::transform(profiles.begin(), profiles.end(), output.begin(), | 237 | std::ranges::transform(profiles, output.begin(), |
| 232 | [](const ProfileInfo& p) { return p.user_uuid; }); | 238 | [](const ProfileInfo& p) { return p.user_uuid; }); |
| 233 | return output; | 239 | return output; |
| 234 | } | 240 | } |
| 235 | 241 | ||
| 236 | /// Get all the open users on the system and zero out the rest of the data. This is specifically | 242 | /// Get all the open users on the system and zero out the rest of the data. This is specifically |
| 237 | /// needed for GetOpenUsers and we need to ensure the rest of the output buffer is zero'd out | 243 | /// needed for GetOpenUsers and we need to ensure the rest of the output buffer is zero'd out |
| 238 | UserIDArray ProfileManager::GetOpenUsers() const { | 244 | UserIDArray ProfileManager::GetOpenUsers() const { |
| 239 | UserIDArray output; | 245 | UserIDArray output{}; |
| 240 | std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) { | 246 | std::ranges::transform(profiles, output.begin(), [](const ProfileInfo& p) { |
| 241 | if (p.is_open) | 247 | if (p.is_open) |
| 242 | return p.user_uuid; | 248 | return p.user_uuid; |
| 243 | return UUID{Common::INVALID_UUID}; | 249 | return UUID{Common::INVALID_UUID}; |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 5310637a6..71b9d5518 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -23,12 +23,12 @@ using UserIDArray = std::array<Common::UUID, MAX_USERS>; | |||
| 23 | /// Contains extra data related to a user. | 23 | /// Contains extra data related to a user. |
| 24 | /// TODO: RE this structure | 24 | /// TODO: RE this structure |
| 25 | struct ProfileData { | 25 | struct ProfileData { |
| 26 | INSERT_PADDING_WORDS(1); | 26 | INSERT_PADDING_WORDS_NOINIT(1); |
| 27 | u32 icon_id{}; | 27 | u32 icon_id; |
| 28 | u8 bg_color_id{}; | 28 | u8 bg_color_id; |
| 29 | INSERT_PADDING_BYTES(0x7); | 29 | INSERT_PADDING_BYTES_NOINIT(0x7); |
| 30 | INSERT_PADDING_BYTES(0x10); | 30 | INSERT_PADDING_BYTES_NOINIT(0x10); |
| 31 | INSERT_PADDING_BYTES(0x60); | 31 | INSERT_PADDING_BYTES_NOINIT(0x60); |
| 32 | }; | 32 | }; |
| 33 | static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size"); | 33 | static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size"); |
| 34 | 34 | ||
| @@ -43,9 +43,9 @@ struct ProfileInfo { | |||
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | struct ProfileBase { | 45 | struct ProfileBase { |
| 46 | Common::UUID user_uuid{Common::INVALID_UUID}; | 46 | Common::UUID user_uuid; |
| 47 | u64_le timestamp{}; | 47 | u64_le timestamp; |
| 48 | ProfileUsername username{}; | 48 | ProfileUsername username; |
| 49 | 49 | ||
| 50 | // Zero out all the fields to make the profile slot considered "Empty" | 50 | // Zero out all the fields to make the profile slot considered "Empty" |
| 51 | void Invalidate() { | 51 | void Invalidate() { |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index c9808060a..bb77c2569 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -13,11 +13,12 @@ | |||
| 13 | #include "core/file_sys/registered_cache.h" | 13 | #include "core/file_sys/registered_cache.h" |
| 14 | #include "core/file_sys/savedata_factory.h" | 14 | #include "core/file_sys/savedata_factory.h" |
| 15 | #include "core/hle/ipc_helpers.h" | 15 | #include "core/hle/ipc_helpers.h" |
| 16 | #include "core/hle/kernel/k_event.h" | ||
| 17 | #include "core/hle/kernel/k_readable_event.h" | ||
| 18 | #include "core/hle/kernel/k_writable_event.h" | ||
| 16 | #include "core/hle/kernel/kernel.h" | 19 | #include "core/hle/kernel/kernel.h" |
| 17 | #include "core/hle/kernel/process.h" | 20 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/readable_event.h" | ||
| 19 | #include "core/hle/kernel/transfer_memory.h" | 21 | #include "core/hle/kernel/transfer_memory.h" |
| 20 | #include "core/hle/kernel/writable_event.h" | ||
| 21 | #include "core/hle/service/acc/profile_manager.h" | 22 | #include "core/hle/service/acc/profile_manager.h" |
| 22 | #include "core/hle/service/am/am.h" | 23 | #include "core/hle/service/am/am.h" |
| 23 | #include "core/hle/service/am/applet_ae.h" | 24 | #include "core/hle/service/am/applet_ae.h" |
| @@ -303,17 +304,18 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv | |||
| 303 | RegisterHandlers(functions); | 304 | RegisterHandlers(functions); |
| 304 | 305 | ||
| 305 | auto& kernel = system.Kernel(); | 306 | auto& kernel = system.Kernel(); |
| 306 | launchable_event = | 307 | launchable_event = Kernel::KEvent::Create(kernel, "ISelfController:LaunchableEvent"); |
| 307 | Kernel::WritableEvent::CreateEventPair(kernel, "ISelfController:LaunchableEvent"); | 308 | launchable_event->Initialize(); |
| 308 | 309 | ||
| 309 | // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is | 310 | // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is |
| 310 | // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple | 311 | // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple |
| 311 | // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not | 312 | // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not |
| 312 | // suspended if the event has previously been created by a call to | 313 | // suspended if the event has previously been created by a call to |
| 313 | // GetAccumulatedSuspendedTickChangedEvent. | 314 | // GetAccumulatedSuspendedTickChangedEvent. |
| 314 | accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair( | 315 | accumulated_suspended_tick_changed_event = |
| 315 | kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent"); | 316 | Kernel::KEvent::Create(kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent"); |
| 316 | accumulated_suspended_tick_changed_event.writable->Signal(); | 317 | accumulated_suspended_tick_changed_event->Initialize(); |
| 318 | accumulated_suspended_tick_changed_event->GetWritableEvent()->Signal(); | ||
| 317 | } | 319 | } |
| 318 | 320 | ||
| 319 | ISelfController::~ISelfController() = default; | 321 | ISelfController::~ISelfController() = default; |
| @@ -372,11 +374,11 @@ void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) { | |||
| 372 | void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { | 374 | void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { |
| 373 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 375 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 374 | 376 | ||
| 375 | launchable_event.writable->Signal(); | 377 | launchable_event->GetWritableEvent()->Signal(); |
| 376 | 378 | ||
| 377 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 379 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 378 | rb.Push(RESULT_SUCCESS); | 380 | rb.Push(RESULT_SUCCESS); |
| 379 | rb.PushCopyObjects(launchable_event.readable); | 381 | rb.PushCopyObjects(launchable_event->GetReadableEvent()); |
| 380 | } | 382 | } |
| 381 | 383 | ||
| 382 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { | 384 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { |
| @@ -555,41 +557,42 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest | |||
| 555 | 557 | ||
| 556 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 558 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 557 | rb.Push(RESULT_SUCCESS); | 559 | rb.Push(RESULT_SUCCESS); |
| 558 | rb.PushCopyObjects(accumulated_suspended_tick_changed_event.readable); | 560 | rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); |
| 559 | } | 561 | } |
| 560 | 562 | ||
| 561 | AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { | 563 | AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { |
| 562 | on_new_message = | 564 | on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived"); |
| 563 | Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OnMessageReceived"); | 565 | on_new_message->Initialize(); |
| 564 | on_operation_mode_changed = | 566 | on_operation_mode_changed = |
| 565 | Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OperationModeChanged"); | 567 | Kernel::KEvent::Create(kernel, "AMMessageQueue:OperationModeChanged"); |
| 568 | on_operation_mode_changed->Initialize(); | ||
| 566 | } | 569 | } |
| 567 | 570 | ||
| 568 | AppletMessageQueue::~AppletMessageQueue() = default; | 571 | AppletMessageQueue::~AppletMessageQueue() = default; |
| 569 | 572 | ||
| 570 | const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const { | 573 | const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const { |
| 571 | return on_new_message.readable; | 574 | return on_new_message->GetReadableEvent(); |
| 572 | } | 575 | } |
| 573 | 576 | ||
| 574 | const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() | 577 | const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() |
| 575 | const { | 578 | const { |
| 576 | return on_operation_mode_changed.readable; | 579 | return on_operation_mode_changed->GetReadableEvent(); |
| 577 | } | 580 | } |
| 578 | 581 | ||
| 579 | void AppletMessageQueue::PushMessage(AppletMessage msg) { | 582 | void AppletMessageQueue::PushMessage(AppletMessage msg) { |
| 580 | messages.push(msg); | 583 | messages.push(msg); |
| 581 | on_new_message.writable->Signal(); | 584 | on_new_message->GetWritableEvent()->Signal(); |
| 582 | } | 585 | } |
| 583 | 586 | ||
| 584 | AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { | 587 | AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { |
| 585 | if (messages.empty()) { | 588 | if (messages.empty()) { |
| 586 | on_new_message.writable->Clear(); | 589 | on_new_message->GetWritableEvent()->Clear(); |
| 587 | return AppletMessage::NoMessage; | 590 | return AppletMessage::NoMessage; |
| 588 | } | 591 | } |
| 589 | auto msg = messages.front(); | 592 | auto msg = messages.front(); |
| 590 | messages.pop(); | 593 | messages.pop(); |
| 591 | if (messages.empty()) { | 594 | if (messages.empty()) { |
| 592 | on_new_message.writable->Clear(); | 595 | on_new_message->GetWritableEvent()->Clear(); |
| 593 | } | 596 | } |
| 594 | return msg; | 597 | return msg; |
| 595 | } | 598 | } |
| @@ -601,7 +604,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const { | |||
| 601 | void AppletMessageQueue::OperationModeChanged() { | 604 | void AppletMessageQueue::OperationModeChanged() { |
| 602 | PushMessage(AppletMessage::OperationModeChanged); | 605 | PushMessage(AppletMessage::OperationModeChanged); |
| 603 | PushMessage(AppletMessage::PerformanceModeChanged); | 606 | PushMessage(AppletMessage::PerformanceModeChanged); |
| 604 | on_operation_mode_changed.writable->Signal(); | 607 | on_operation_mode_changed->GetWritableEvent()->Signal(); |
| 605 | } | 608 | } |
| 606 | 609 | ||
| 607 | void AppletMessageQueue::RequestExit() { | 610 | void AppletMessageQueue::RequestExit() { |
| @@ -635,7 +638,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, | |||
| 635 | {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, | 638 | {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, |
| 636 | {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, | 639 | {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, |
| 637 | {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, | 640 | {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, |
| 638 | {53, nullptr, "BeginVrModeEx"}, | 641 | {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"}, |
| 639 | {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, | 642 | {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, |
| 640 | {55, nullptr, "IsInControllerFirmwareUpdateSection"}, | 643 | {55, nullptr, "IsInControllerFirmwareUpdateSection"}, |
| 641 | {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, | 644 | {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, |
| @@ -732,6 +735,13 @@ void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx | |||
| 732 | rb.Push(RESULT_SUCCESS); | 735 | rb.Push(RESULT_SUCCESS); |
| 733 | } | 736 | } |
| 734 | 737 | ||
| 738 | void ICommonStateGetter::BeginVrModeEx(Kernel::HLERequestContext& ctx) { | ||
| 739 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 740 | |||
| 741 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 742 | rb.Push(RESULT_SUCCESS); | ||
| 743 | } | ||
| 744 | |||
| 735 | void ICommonStateGetter::EndVrModeEx(Kernel::HLERequestContext& ctx) { | 745 | void ICommonStateGetter::EndVrModeEx(Kernel::HLERequestContext& ctx) { |
| 736 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 746 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 737 | 747 | ||
| @@ -856,7 +866,7 @@ public: | |||
| 856 | {25, nullptr, "Terminate"}, | 866 | {25, nullptr, "Terminate"}, |
| 857 | {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, | 867 | {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, |
| 858 | {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, | 868 | {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, |
| 859 | {60, nullptr, "PresetLibraryAppletGpuTimeSliceZero"}, | 869 | {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"}, |
| 860 | {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, | 870 | {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, |
| 861 | {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, | 871 | {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, |
| 862 | {102, nullptr, "PushExtraStorage"}, | 872 | {102, nullptr, "PushExtraStorage"}, |
| @@ -900,6 +910,13 @@ private: | |||
| 900 | rb.Push(applet->GetStatus()); | 910 | rb.Push(applet->GetStatus()); |
| 901 | } | 911 | } |
| 902 | 912 | ||
| 913 | void PresetLibraryAppletGpuTimeSliceZero(Kernel::HLERequestContext& ctx) { | ||
| 914 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 915 | |||
| 916 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 917 | rb.Push(RESULT_SUCCESS); | ||
| 918 | } | ||
| 919 | |||
| 903 | void Start(Kernel::HLERequestContext& ctx) { | 920 | void Start(Kernel::HLERequestContext& ctx) { |
| 904 | LOG_DEBUG(Service_AM, "called"); | 921 | LOG_DEBUG(Service_AM, "called"); |
| 905 | 922 | ||
| @@ -1178,7 +1195,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | |||
| 1178 | {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, | 1195 | {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, |
| 1179 | {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, | 1196 | {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, |
| 1180 | {60, nullptr, "SetMediaPlaybackStateForApplication"}, | 1197 | {60, nullptr, "SetMediaPlaybackStateForApplication"}, |
| 1181 | {65, nullptr, "IsGamePlayRecordingSupported"}, | 1198 | {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"}, |
| 1182 | {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, | 1199 | {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, |
| 1183 | {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, | 1200 | {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, |
| 1184 | {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, | 1201 | {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, |
| @@ -1199,10 +1216,10 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | |||
| 1199 | {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, | 1216 | {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, |
| 1200 | {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, | 1217 | {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, |
| 1201 | {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, | 1218 | {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, |
| 1202 | {141, nullptr, "TryPopFromFriendInvitationStorageChannel"}, | 1219 | {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"}, |
| 1203 | {150, nullptr, "GetNotificationStorageChannelEvent"}, | 1220 | {150, nullptr, "GetNotificationStorageChannelEvent"}, |
| 1204 | {151, nullptr, "TryPopFromNotificationStorageChannel"}, | 1221 | {151, nullptr, "TryPopFromNotificationStorageChannel"}, |
| 1205 | {160, nullptr, "GetHealthWarningDisappearedSystemEvent"}, | 1222 | {160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"}, |
| 1206 | {170, nullptr, "SetHdcpAuthenticationActivated"}, | 1223 | {170, nullptr, "SetHdcpAuthenticationActivated"}, |
| 1207 | {180, nullptr, "GetLaunchRequiredVersion"}, | 1224 | {180, nullptr, "GetLaunchRequiredVersion"}, |
| 1208 | {181, nullptr, "UpgradeLaunchRequiredVersion"}, | 1225 | {181, nullptr, "UpgradeLaunchRequiredVersion"}, |
| @@ -1215,11 +1232,15 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | |||
| 1215 | RegisterHandlers(functions); | 1232 | RegisterHandlers(functions); |
| 1216 | 1233 | ||
| 1217 | auto& kernel = system.Kernel(); | 1234 | auto& kernel = system.Kernel(); |
| 1218 | gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair( | 1235 | gpu_error_detected_event = |
| 1219 | kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); | 1236 | Kernel::KEvent::Create(kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); |
| 1220 | 1237 | gpu_error_detected_event->Initialize(); | |
| 1221 | friend_invitation_storage_channel_event = Kernel::WritableEvent::CreateEventPair( | 1238 | friend_invitation_storage_channel_event = |
| 1222 | kernel, "IApplicationFunctions:FriendInvitationStorageChannelEvent"); | 1239 | Kernel::KEvent::Create(kernel, "IApplicationFunctions:FriendInvitationStorageChannelEvent"); |
| 1240 | friend_invitation_storage_channel_event->Initialize(); | ||
| 1241 | health_warning_disappeared_system_event = | ||
| 1242 | Kernel::KEvent::Create(kernel, "IApplicationFunctions:HealthWarningDisappearedSystemEvent"); | ||
| 1243 | health_warning_disappeared_system_event->Initialize(); | ||
| 1223 | } | 1244 | } |
| 1224 | 1245 | ||
| 1225 | IApplicationFunctions::~IApplicationFunctions() = default; | 1246 | IApplicationFunctions::~IApplicationFunctions() = default; |
| @@ -1466,6 +1487,16 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { | |||
| 1466 | rb.Push(*res_code); | 1487 | rb.Push(*res_code); |
| 1467 | } | 1488 | } |
| 1468 | 1489 | ||
| 1490 | void IApplicationFunctions::IsGamePlayRecordingSupported(Kernel::HLERequestContext& ctx) { | ||
| 1491 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1492 | |||
| 1493 | constexpr bool gameplay_recording_supported = false; | ||
| 1494 | |||
| 1495 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 1496 | rb.Push(RESULT_SUCCESS); | ||
| 1497 | rb.Push(gameplay_recording_supported); | ||
| 1498 | } | ||
| 1499 | |||
| 1469 | void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { | 1500 | void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { |
| 1470 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 1501 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 1471 | 1502 | ||
| @@ -1606,7 +1637,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon | |||
| 1606 | 1637 | ||
| 1607 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 1638 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 1608 | rb.Push(RESULT_SUCCESS); | 1639 | rb.Push(RESULT_SUCCESS); |
| 1609 | rb.PushCopyObjects(gpu_error_detected_event.readable); | 1640 | rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); |
| 1610 | } | 1641 | } |
| 1611 | 1642 | ||
| 1612 | void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) { | 1643 | void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) { |
| @@ -1614,7 +1645,23 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe | |||
| 1614 | 1645 | ||
| 1615 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 1646 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 1616 | rb.Push(RESULT_SUCCESS); | 1647 | rb.Push(RESULT_SUCCESS); |
| 1617 | rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); | 1648 | rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); |
| 1649 | } | ||
| 1650 | |||
| 1651 | void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel( | ||
| 1652 | Kernel::HLERequestContext& ctx) { | ||
| 1653 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1654 | |||
| 1655 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1656 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx) { | ||
| 1660 | LOG_DEBUG(Service_AM, "called"); | ||
| 1661 | |||
| 1662 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 1663 | rb.Push(RESULT_SUCCESS); | ||
| 1664 | rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); | ||
| 1618 | } | 1665 | } |
| 1619 | 1666 | ||
| 1620 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, | 1667 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| @@ -1650,8 +1697,9 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) | |||
| 1650 | 1697 | ||
| 1651 | RegisterHandlers(functions); | 1698 | RegisterHandlers(functions); |
| 1652 | 1699 | ||
| 1653 | pop_from_general_channel_event = Kernel::WritableEvent::CreateEventPair( | 1700 | pop_from_general_channel_event = |
| 1654 | system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent"); | 1701 | Kernel::KEvent::Create(system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent"); |
| 1702 | pop_from_general_channel_event->Initialize(); | ||
| 1655 | } | 1703 | } |
| 1656 | 1704 | ||
| 1657 | IHomeMenuFunctions::~IHomeMenuFunctions() = default; | 1705 | IHomeMenuFunctions::~IHomeMenuFunctions() = default; |
| @@ -1668,7 +1716,7 @@ void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext | |||
| 1668 | 1716 | ||
| 1669 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 1717 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 1670 | rb.Push(RESULT_SUCCESS); | 1718 | rb.Push(RESULT_SUCCESS); |
| 1671 | rb.PushCopyObjects(pop_from_general_channel_event.readable); | 1719 | rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent()); |
| 1672 | } | 1720 | } |
| 1673 | 1721 | ||
| 1674 | IGlobalStateController::IGlobalStateController(Core::System& system_) | 1722 | IGlobalStateController::IGlobalStateController(Core::System& system_) |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index f51aca1af..6911f0d6e 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -7,11 +7,12 @@ | |||
| 7 | #include <chrono> | 7 | #include <chrono> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <queue> | 9 | #include <queue> |
| 10 | #include "core/hle/kernel/writable_event.h" | 10 | |
| 11 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | class KernelCore; | 14 | class KernelCore; |
| 15 | class KEvent; | ||
| 15 | class TransferMemory; | 16 | class TransferMemory; |
| 16 | } // namespace Kernel | 17 | } // namespace Kernel |
| 17 | 18 | ||
| @@ -55,8 +56,8 @@ public: | |||
| 55 | explicit AppletMessageQueue(Kernel::KernelCore& kernel); | 56 | explicit AppletMessageQueue(Kernel::KernelCore& kernel); |
| 56 | ~AppletMessageQueue(); | 57 | ~AppletMessageQueue(); |
| 57 | 58 | ||
| 58 | const std::shared_ptr<Kernel::ReadableEvent>& GetMessageReceiveEvent() const; | 59 | const std::shared_ptr<Kernel::KReadableEvent>& GetMessageReceiveEvent() const; |
| 59 | const std::shared_ptr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const; | 60 | const std::shared_ptr<Kernel::KReadableEvent>& GetOperationModeChangedEvent() const; |
| 60 | void PushMessage(AppletMessage msg); | 61 | void PushMessage(AppletMessage msg); |
| 61 | AppletMessage PopMessage(); | 62 | AppletMessage PopMessage(); |
| 62 | std::size_t GetMessageCount() const; | 63 | std::size_t GetMessageCount() const; |
| @@ -65,8 +66,8 @@ public: | |||
| 65 | 66 | ||
| 66 | private: | 67 | private: |
| 67 | std::queue<AppletMessage> messages; | 68 | std::queue<AppletMessage> messages; |
| 68 | Kernel::EventPair on_new_message; | 69 | std::shared_ptr<Kernel::KEvent> on_new_message; |
| 69 | Kernel::EventPair on_operation_mode_changed; | 70 | std::shared_ptr<Kernel::KEvent> on_operation_mode_changed; |
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 72 | class IWindowController final : public ServiceFramework<IWindowController> { | 73 | class IWindowController final : public ServiceFramework<IWindowController> { |
| @@ -153,8 +154,8 @@ private: | |||
| 153 | }; | 154 | }; |
| 154 | 155 | ||
| 155 | NVFlinger::NVFlinger& nvflinger; | 156 | NVFlinger::NVFlinger& nvflinger; |
| 156 | Kernel::EventPair launchable_event; | 157 | std::shared_ptr<Kernel::KEvent> launchable_event; |
| 157 | Kernel::EventPair accumulated_suspended_tick_changed_event; | 158 | std::shared_ptr<Kernel::KEvent> accumulated_suspended_tick_changed_event; |
| 158 | 159 | ||
| 159 | u32 idle_time_detection_extension = 0; | 160 | u32 idle_time_detection_extension = 0; |
| 160 | u64 num_fatal_sections_entered = 0; | 161 | u64 num_fatal_sections_entered = 0; |
| @@ -189,6 +190,7 @@ private: | |||
| 189 | void IsVrModeEnabled(Kernel::HLERequestContext& ctx); | 190 | void IsVrModeEnabled(Kernel::HLERequestContext& ctx); |
| 190 | void SetVrModeEnabled(Kernel::HLERequestContext& ctx); | 191 | void SetVrModeEnabled(Kernel::HLERequestContext& ctx); |
| 191 | void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx); | 192 | void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx); |
| 193 | void BeginVrModeEx(Kernel::HLERequestContext& ctx); | ||
| 192 | void EndVrModeEx(Kernel::HLERequestContext& ctx); | 194 | void EndVrModeEx(Kernel::HLERequestContext& ctx); |
| 193 | void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); | 195 | void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); |
| 194 | void SetCpuBoostMode(Kernel::HLERequestContext& ctx); | 196 | void SetCpuBoostMode(Kernel::HLERequestContext& ctx); |
| @@ -265,6 +267,7 @@ private: | |||
| 265 | void SetTerminateResult(Kernel::HLERequestContext& ctx); | 267 | void SetTerminateResult(Kernel::HLERequestContext& ctx); |
| 266 | void GetDisplayVersion(Kernel::HLERequestContext& ctx); | 268 | void GetDisplayVersion(Kernel::HLERequestContext& ctx); |
| 267 | void GetDesiredLanguage(Kernel::HLERequestContext& ctx); | 269 | void GetDesiredLanguage(Kernel::HLERequestContext& ctx); |
| 270 | void IsGamePlayRecordingSupported(Kernel::HLERequestContext& ctx); | ||
| 268 | void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx); | 271 | void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx); |
| 269 | void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx); | 272 | void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx); |
| 270 | void NotifyRunning(Kernel::HLERequestContext& ctx); | 273 | void NotifyRunning(Kernel::HLERequestContext& ctx); |
| @@ -287,12 +290,15 @@ private: | |||
| 287 | void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); | 290 | void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); |
| 288 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); | 291 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); |
| 289 | void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); | 292 | void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); |
| 293 | void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx); | ||
| 294 | void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx); | ||
| 290 | 295 | ||
| 291 | bool launch_popped_application_specific = false; | 296 | bool launch_popped_application_specific = false; |
| 292 | bool launch_popped_account_preselect = false; | 297 | bool launch_popped_account_preselect = false; |
| 293 | s32 previous_program_index{-1}; | 298 | s32 previous_program_index{-1}; |
| 294 | Kernel::EventPair gpu_error_detected_event; | 299 | std::shared_ptr<Kernel::KEvent> gpu_error_detected_event; |
| 295 | Kernel::EventPair friend_invitation_storage_channel_event; | 300 | std::shared_ptr<Kernel::KEvent> friend_invitation_storage_channel_event; |
| 301 | std::shared_ptr<Kernel::KEvent> health_warning_disappeared_system_event; | ||
| 296 | }; | 302 | }; |
| 297 | 303 | ||
| 298 | class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { | 304 | class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { |
| @@ -304,7 +310,7 @@ private: | |||
| 304 | void RequestToGetForeground(Kernel::HLERequestContext& ctx); | 310 | void RequestToGetForeground(Kernel::HLERequestContext& ctx); |
| 305 | void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); | 311 | void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); |
| 306 | 312 | ||
| 307 | Kernel::EventPair pop_from_general_channel_event; | 313 | std::shared_ptr<Kernel::KEvent> pop_from_general_channel_event; |
| 308 | }; | 314 | }; |
| 309 | 315 | ||
| 310 | class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { | 316 | class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { |
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 08676c3fc..e2f3b7563 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | |||
| 6 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 7 | #include "core/core.h" | 8 | #include "core/core.h" |
| 8 | #include "core/frontend/applets/controller.h" | 9 | #include "core/frontend/applets/controller.h" |
| @@ -11,9 +12,10 @@ | |||
| 11 | #include "core/frontend/applets/profile_select.h" | 12 | #include "core/frontend/applets/profile_select.h" |
| 12 | #include "core/frontend/applets/software_keyboard.h" | 13 | #include "core/frontend/applets/software_keyboard.h" |
| 13 | #include "core/frontend/applets/web_browser.h" | 14 | #include "core/frontend/applets/web_browser.h" |
| 14 | #include "core/hle/kernel/readable_event.h" | 15 | #include "core/hle/kernel/k_event.h" |
| 16 | #include "core/hle/kernel/k_readable_event.h" | ||
| 17 | #include "core/hle/kernel/k_writable_event.h" | ||
| 15 | #include "core/hle/kernel/server_session.h" | 18 | #include "core/hle/kernel/server_session.h" |
| 16 | #include "core/hle/kernel/writable_event.h" | ||
| 17 | #include "core/hle/service/am/am.h" | 19 | #include "core/hle/service/am/am.h" |
| 18 | #include "core/hle/service/am/applets/applets.h" | 20 | #include "core/hle/service/am/applets/applets.h" |
| 19 | #include "core/hle/service/am/applets/controller.h" | 21 | #include "core/hle/service/am/applets/controller.h" |
| @@ -27,11 +29,13 @@ namespace Service::AM::Applets { | |||
| 27 | 29 | ||
| 28 | AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) { | 30 | AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) { |
| 29 | state_changed_event = | 31 | state_changed_event = |
| 30 | Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:StateChangedEvent"); | 32 | Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:StateChangedEvent"); |
| 31 | pop_out_data_event = | 33 | state_changed_event->Initialize(); |
| 32 | Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:PopDataOutEvent"); | 34 | pop_out_data_event = Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:PopDataOutEvent"); |
| 33 | pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair( | 35 | pop_out_data_event->Initialize(); |
| 34 | kernel, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); | 36 | pop_interactive_out_data_event = |
| 37 | Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); | ||
| 38 | pop_interactive_out_data_event->Initialize(); | ||
| 35 | } | 39 | } |
| 36 | 40 | ||
| 37 | AppletDataBroker::~AppletDataBroker() = default; | 41 | AppletDataBroker::~AppletDataBroker() = default; |
| @@ -58,7 +62,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { | |||
| 58 | 62 | ||
| 59 | auto out = std::move(out_channel.front()); | 63 | auto out = std::move(out_channel.front()); |
| 60 | out_channel.pop_front(); | 64 | out_channel.pop_front(); |
| 61 | pop_out_data_event.writable->Clear(); | 65 | pop_out_data_event->GetWritableEvent()->Clear(); |
| 62 | return out; | 66 | return out; |
| 63 | } | 67 | } |
| 64 | 68 | ||
| @@ -77,7 +81,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { | |||
| 77 | 81 | ||
| 78 | auto out = std::move(out_interactive_channel.front()); | 82 | auto out = std::move(out_interactive_channel.front()); |
| 79 | out_interactive_channel.pop_front(); | 83 | out_interactive_channel.pop_front(); |
| 80 | pop_interactive_out_data_event.writable->Clear(); | 84 | pop_interactive_out_data_event->GetWritableEvent()->Clear(); |
| 81 | return out; | 85 | return out; |
| 82 | } | 86 | } |
| 83 | 87 | ||
| @@ -96,7 +100,7 @@ void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storag | |||
| 96 | 100 | ||
| 97 | void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { | 101 | void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { |
| 98 | out_channel.emplace_back(std::move(storage)); | 102 | out_channel.emplace_back(std::move(storage)); |
| 99 | pop_out_data_event.writable->Signal(); | 103 | pop_out_data_event->GetWritableEvent()->Signal(); |
| 100 | } | 104 | } |
| 101 | 105 | ||
| 102 | void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { | 106 | void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { |
| @@ -105,23 +109,23 @@ void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& s | |||
| 105 | 109 | ||
| 106 | void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) { | 110 | void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) { |
| 107 | out_interactive_channel.emplace_back(std::move(storage)); | 111 | out_interactive_channel.emplace_back(std::move(storage)); |
| 108 | pop_interactive_out_data_event.writable->Signal(); | 112 | pop_interactive_out_data_event->GetWritableEvent()->Signal(); |
| 109 | } | 113 | } |
| 110 | 114 | ||
| 111 | void AppletDataBroker::SignalStateChanged() const { | 115 | void AppletDataBroker::SignalStateChanged() const { |
| 112 | state_changed_event.writable->Signal(); | 116 | state_changed_event->GetWritableEvent()->Signal(); |
| 113 | } | 117 | } |
| 114 | 118 | ||
| 115 | std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const { | 119 | std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetNormalDataEvent() const { |
| 116 | return pop_out_data_event.readable; | 120 | return pop_out_data_event->GetReadableEvent(); |
| 117 | } | 121 | } |
| 118 | 122 | ||
| 119 | std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { | 123 | std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { |
| 120 | return pop_interactive_out_data_event.readable; | 124 | return pop_interactive_out_data_event->GetReadableEvent(); |
| 121 | } | 125 | } |
| 122 | 126 | ||
| 123 | std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const { | 127 | std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetStateChangedEvent() const { |
| 124 | return state_changed_event.readable; | 128 | return state_changed_event->GetReadableEvent(); |
| 125 | } | 129 | } |
| 126 | 130 | ||
| 127 | Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {} | 131 | Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {} |
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 4fd792c05..b9a006317 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -6,9 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <queue> | 8 | #include <queue> |
| 9 | |||
| 9 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 10 | #include "core/hle/kernel/object.h" | 11 | #include "core/hle/kernel/object.h" |
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 12 | 12 | ||
| 13 | union ResultCode; | 13 | union ResultCode; |
| 14 | 14 | ||
| @@ -29,7 +29,9 @@ class WebBrowserApplet; | |||
| 29 | 29 | ||
| 30 | namespace Kernel { | 30 | namespace Kernel { |
| 31 | class KernelCore; | 31 | class KernelCore; |
| 32 | } | 32 | class KEvent; |
| 33 | class KReadableEvent; | ||
| 34 | } // namespace Kernel | ||
| 33 | 35 | ||
| 34 | namespace Service::AM { | 36 | namespace Service::AM { |
| 35 | 37 | ||
| @@ -87,9 +89,9 @@ public: | |||
| 87 | 89 | ||
| 88 | void SignalStateChanged() const; | 90 | void SignalStateChanged() const; |
| 89 | 91 | ||
| 90 | std::shared_ptr<Kernel::ReadableEvent> GetNormalDataEvent() const; | 92 | std::shared_ptr<Kernel::KReadableEvent> GetNormalDataEvent() const; |
| 91 | std::shared_ptr<Kernel::ReadableEvent> GetInteractiveDataEvent() const; | 93 | std::shared_ptr<Kernel::KReadableEvent> GetInteractiveDataEvent() const; |
| 92 | std::shared_ptr<Kernel::ReadableEvent> GetStateChangedEvent() const; | 94 | std::shared_ptr<Kernel::KReadableEvent> GetStateChangedEvent() const; |
| 93 | 95 | ||
| 94 | private: | 96 | private: |
| 95 | // Queues are named from applet's perspective | 97 | // Queues are named from applet's perspective |
| @@ -106,13 +108,13 @@ private: | |||
| 106 | // PopInteractiveDataToGame and PushInteractiveDataFromApplet | 108 | // PopInteractiveDataToGame and PushInteractiveDataFromApplet |
| 107 | std::deque<std::shared_ptr<IStorage>> out_interactive_channel; | 109 | std::deque<std::shared_ptr<IStorage>> out_interactive_channel; |
| 108 | 110 | ||
| 109 | Kernel::EventPair state_changed_event; | 111 | std::shared_ptr<Kernel::KEvent> state_changed_event; |
| 110 | 112 | ||
| 111 | // Signaled on PushNormalDataFromApplet | 113 | // Signaled on PushNormalDataFromApplet |
| 112 | Kernel::EventPair pop_out_data_event; | 114 | std::shared_ptr<Kernel::KEvent> pop_out_data_event; |
| 113 | 115 | ||
| 114 | // Signaled on PushInteractiveDataFromApplet | 116 | // Signaled on PushInteractiveDataFromApplet |
| 115 | Kernel::EventPair pop_interactive_out_data_event; | 117 | std::shared_ptr<Kernel::KEvent> pop_interactive_out_data_event; |
| 116 | }; | 118 | }; |
| 117 | 119 | ||
| 118 | class Applet { | 120 | class Applet { |
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp index 7edfca64e..d7d3ee99a 100644 --- a/src/core/hle/service/am/applets/controller.cpp +++ b/src/core/hle/service/am/applets/controller.cpp | |||
| @@ -37,7 +37,7 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters( | |||
| 37 | .border_colors = std::move(identification_colors), | 37 | .border_colors = std::move(identification_colors), |
| 38 | .enable_explain_text = enable_text, | 38 | .enable_explain_text = enable_text, |
| 39 | .explain_text = std::move(text), | 39 | .explain_text = std::move(text), |
| 40 | .allow_pro_controller = npad_style_set.pro_controller == 1, | 40 | .allow_pro_controller = npad_style_set.fullkey == 1, |
| 41 | .allow_handheld = npad_style_set.handheld == 1, | 41 | .allow_handheld = npad_style_set.handheld == 1, |
| 42 | .allow_dual_joycons = npad_style_set.joycon_dual == 1, | 42 | .allow_dual_joycons = npad_style_set.joycon_dual == 1, |
| 43 | .allow_left_joycon = npad_style_set.joycon_left == 1, | 43 | .allow_left_joycon = npad_style_set.joycon_left == 1, |
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 23e28565b..8d657c0bf 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <numeric> | 6 | #include <numeric> |
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | |||
| 8 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| 10 | #include "core/file_sys/common_funcs.h" | 11 | #include "core/file_sys/common_funcs.h" |
| @@ -14,10 +15,10 @@ | |||
| 14 | #include "core/file_sys/patch_manager.h" | 15 | #include "core/file_sys/patch_manager.h" |
| 15 | #include "core/file_sys/registered_cache.h" | 16 | #include "core/file_sys/registered_cache.h" |
| 16 | #include "core/hle/ipc_helpers.h" | 17 | #include "core/hle/ipc_helpers.h" |
| 18 | #include "core/hle/kernel/k_event.h" | ||
| 19 | #include "core/hle/kernel/k_readable_event.h" | ||
| 17 | #include "core/hle/kernel/kernel.h" | 20 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/kernel/process.h" | 21 | #include "core/hle/kernel/process.h" |
| 19 | #include "core/hle/kernel/readable_event.h" | ||
| 20 | #include "core/hle/kernel/writable_event.h" | ||
| 21 | #include "core/hle/service/aoc/aoc_u.h" | 22 | #include "core/hle/service/aoc/aoc_u.h" |
| 22 | #include "core/loader/loader.h" | 23 | #include "core/loader/loader.h" |
| 23 | #include "core/settings.h" | 24 | #include "core/settings.h" |
| @@ -62,8 +63,9 @@ public: | |||
| 62 | 63 | ||
| 63 | RegisterHandlers(functions); | 64 | RegisterHandlers(functions); |
| 64 | 65 | ||
| 65 | purchased_event = Kernel::WritableEvent::CreateEventPair( | 66 | purchased_event = |
| 66 | system.Kernel(), "IPurchaseEventManager:PurchasedEvent"); | 67 | Kernel::KEvent::Create(system.Kernel(), "IPurchaseEventManager:PurchasedEvent"); |
| 68 | purchased_event->Initialize(); | ||
| 67 | } | 69 | } |
| 68 | 70 | ||
| 69 | private: | 71 | private: |
| @@ -96,10 +98,10 @@ private: | |||
| 96 | 98 | ||
| 97 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 99 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 98 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 99 | rb.PushCopyObjects(purchased_event.readable); | 101 | rb.PushCopyObjects(purchased_event->GetReadableEvent()); |
| 100 | } | 102 | } |
| 101 | 103 | ||
| 102 | Kernel::EventPair purchased_event; | 104 | std::shared_ptr<Kernel::KEvent> purchased_event; |
| 103 | }; | 105 | }; |
| 104 | 106 | ||
| 105 | AOC_U::AOC_U(Core::System& system_) | 107 | AOC_U::AOC_U(Core::System& system_) |
| @@ -124,8 +126,8 @@ AOC_U::AOC_U(Core::System& system_) | |||
| 124 | RegisterHandlers(functions); | 126 | RegisterHandlers(functions); |
| 125 | 127 | ||
| 126 | auto& kernel = system.Kernel(); | 128 | auto& kernel = system.Kernel(); |
| 127 | aoc_change_event = | 129 | aoc_change_event = Kernel::KEvent::Create(kernel, "GetAddOnContentListChanged:Event"); |
| 128 | Kernel::WritableEvent::CreateEventPair(kernel, "GetAddOnContentListChanged:Event"); | 130 | aoc_change_event->Initialize(); |
| 129 | } | 131 | } |
| 130 | 132 | ||
| 131 | AOC_U::~AOC_U() = default; | 133 | AOC_U::~AOC_U() = default; |
| @@ -252,7 +254,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) { | |||
| 252 | 254 | ||
| 253 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 255 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 254 | rb.Push(RESULT_SUCCESS); | 256 | rb.Push(RESULT_SUCCESS); |
| 255 | rb.PushCopyObjects(aoc_change_event.readable); | 257 | rb.PushCopyObjects(aoc_change_event->GetReadableEvent()); |
| 256 | } | 258 | } |
| 257 | 259 | ||
| 258 | void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) { | 260 | void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 26ee51be0..1aa23529e 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h | |||
| @@ -11,7 +11,7 @@ class System; | |||
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | class WritableEvent; | 14 | class KEvent; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | namespace Service::AOC { | 17 | namespace Service::AOC { |
| @@ -31,7 +31,7 @@ private: | |||
| 31 | void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx); | 31 | void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx); |
| 32 | 32 | ||
| 33 | std::vector<u64> add_on_content; | 33 | std::vector<u64> add_on_content; |
| 34 | Kernel::EventPair aoc_change_event; | 34 | std::shared_ptr<Kernel::KEvent> aoc_change_event; |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | /// Registers all AOC services with the specified service manager. | 37 | /// Registers all AOC services with the specified service manager. |
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 0cd797109..5ed9cb20e 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -14,9 +14,10 @@ | |||
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/hle/ipc_helpers.h" | 15 | #include "core/hle/ipc_helpers.h" |
| 16 | #include "core/hle/kernel/hle_ipc.h" | 16 | #include "core/hle/kernel/hle_ipc.h" |
| 17 | #include "core/hle/kernel/k_event.h" | ||
| 18 | #include "core/hle/kernel/k_readable_event.h" | ||
| 19 | #include "core/hle/kernel/k_writable_event.h" | ||
| 17 | #include "core/hle/kernel/kernel.h" | 20 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/kernel/readable_event.h" | ||
| 19 | #include "core/hle/kernel/writable_event.h" | ||
| 20 | #include "core/hle/service/audio/audout_u.h" | 21 | #include "core/hle/service/audio/audout_u.h" |
| 21 | #include "core/hle/service/audio/errors.h" | 22 | #include "core/hle/service/audio/errors.h" |
| 22 | #include "core/memory.h" | 23 | #include "core/memory.h" |
| @@ -29,7 +30,7 @@ constexpr int DefaultSampleRate{48000}; | |||
| 29 | struct AudoutParams { | 30 | struct AudoutParams { |
| 30 | s32_le sample_rate; | 31 | s32_le sample_rate; |
| 31 | u16_le channel_count; | 32 | u16_le channel_count; |
| 32 | INSERT_PADDING_BYTES(2); | 33 | INSERT_PADDING_BYTES_NOINIT(2); |
| 33 | }; | 34 | }; |
| 34 | static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size"); | 35 | static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size"); |
| 35 | 36 | ||
| @@ -58,7 +59,7 @@ public: | |||
| 58 | {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"}, | 59 | {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"}, |
| 59 | {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"}, | 60 | {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"}, |
| 60 | {10, nullptr, "GetAudioOutPlayedSampleCount"}, | 61 | {10, nullptr, "GetAudioOutPlayedSampleCount"}, |
| 61 | {11, nullptr, "FlushAudioOutBuffers"}, | 62 | {11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"}, |
| 62 | {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"}, | 63 | {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"}, |
| 63 | {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"}, | 64 | {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"}, |
| 64 | }; | 65 | }; |
| @@ -66,13 +67,13 @@ public: | |||
| 66 | RegisterHandlers(functions); | 67 | RegisterHandlers(functions); |
| 67 | 68 | ||
| 68 | // This is the event handle used to check if the audio buffer was released | 69 | // This is the event handle used to check if the audio buffer was released |
| 69 | buffer_event = | 70 | buffer_event = Kernel::KEvent::Create(system.Kernel(), "IAudioOutBufferReleased"); |
| 70 | Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased"); | 71 | buffer_event->Initialize(); |
| 71 | 72 | ||
| 72 | stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, | 73 | stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, |
| 73 | audio_params.channel_count, std::move(unique_name), [this] { | 74 | audio_params.channel_count, std::move(unique_name), [this] { |
| 74 | const auto guard = LockService(); | 75 | const auto guard = LockService(); |
| 75 | buffer_event.writable->Signal(); | 76 | buffer_event->GetWritableEvent()->Signal(); |
| 76 | }); | 77 | }); |
| 77 | } | 78 | } |
| 78 | 79 | ||
| @@ -125,7 +126,7 @@ private: | |||
| 125 | 126 | ||
| 126 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 127 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 127 | rb.Push(RESULT_SUCCESS); | 128 | rb.Push(RESULT_SUCCESS); |
| 128 | rb.PushCopyObjects(buffer_event.readable); | 129 | rb.PushCopyObjects(buffer_event->GetReadableEvent()); |
| 129 | } | 130 | } |
| 130 | 131 | ||
| 131 | void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { | 132 | void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { |
| @@ -185,6 +186,14 @@ private: | |||
| 185 | rb.Push(static_cast<u32>(stream->GetQueueSize())); | 186 | rb.Push(static_cast<u32>(stream->GetQueueSize())); |
| 186 | } | 187 | } |
| 187 | 188 | ||
| 189 | void FlushAudioOutBuffers(Kernel::HLERequestContext& ctx) { | ||
| 190 | LOG_DEBUG(Service_Audio, "called"); | ||
| 191 | |||
| 192 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 193 | rb.Push(RESULT_SUCCESS); | ||
| 194 | rb.Push(stream->Flush()); | ||
| 195 | } | ||
| 196 | |||
| 188 | void SetAudioOutVolume(Kernel::HLERequestContext& ctx) { | 197 | void SetAudioOutVolume(Kernel::HLERequestContext& ctx) { |
| 189 | IPC::RequestParser rp{ctx}; | 198 | IPC::RequestParser rp{ctx}; |
| 190 | const float volume = rp.Pop<float>(); | 199 | const float volume = rp.Pop<float>(); |
| @@ -211,7 +220,7 @@ private: | |||
| 211 | [[maybe_unused]] AudoutParams audio_params{}; | 220 | [[maybe_unused]] AudoutParams audio_params{}; |
| 212 | 221 | ||
| 213 | /// This is the event handle used to check if the audio buffer was released | 222 | /// This is the event handle used to check if the audio buffer was released |
| 214 | Kernel::EventPair buffer_event; | 223 | std::shared_ptr<Kernel::KEvent> buffer_event; |
| 215 | Core::Memory::Memory& main_memory; | 224 | Core::Memory::Memory& main_memory; |
| 216 | }; | 225 | }; |
| 217 | 226 | ||
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index c5c22d053..b2b2ffc5a 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -16,9 +16,10 @@ | |||
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/hle/ipc_helpers.h" | 17 | #include "core/hle/ipc_helpers.h" |
| 18 | #include "core/hle/kernel/hle_ipc.h" | 18 | #include "core/hle/kernel/hle_ipc.h" |
| 19 | #include "core/hle/kernel/k_event.h" | ||
| 20 | #include "core/hle/kernel/k_readable_event.h" | ||
| 21 | #include "core/hle/kernel/k_writable_event.h" | ||
| 19 | #include "core/hle/kernel/kernel.h" | 22 | #include "core/hle/kernel/kernel.h" |
| 20 | #include "core/hle/kernel/readable_event.h" | ||
| 21 | #include "core/hle/kernel/writable_event.h" | ||
| 22 | #include "core/hle/service/audio/audren_u.h" | 23 | #include "core/hle/service/audio/audren_u.h" |
| 23 | #include "core/hle/service/audio/errors.h" | 24 | #include "core/hle/service/audio/errors.h" |
| 24 | 25 | ||
| @@ -47,13 +48,13 @@ public: | |||
| 47 | // clang-format on | 48 | // clang-format on |
| 48 | RegisterHandlers(functions); | 49 | RegisterHandlers(functions); |
| 49 | 50 | ||
| 50 | system_event = | 51 | system_event = Kernel::KEvent::Create(system.Kernel(), "IAudioRenderer:SystemEvent"); |
| 51 | Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent"); | 52 | system_event->Initialize(); |
| 52 | renderer = std::make_unique<AudioCore::AudioRenderer>( | 53 | renderer = std::make_unique<AudioCore::AudioRenderer>( |
| 53 | system.CoreTiming(), system.Memory(), audren_params, | 54 | system.CoreTiming(), system.Memory(), audren_params, |
| 54 | [this]() { | 55 | [this]() { |
| 55 | const auto guard = LockService(); | 56 | const auto guard = LockService(); |
| 56 | system_event.writable->Signal(); | 57 | system_event->GetWritableEvent()->Signal(); |
| 57 | }, | 58 | }, |
| 58 | instance_number); | 59 | instance_number); |
| 59 | } | 60 | } |
| @@ -126,7 +127,7 @@ private: | |||
| 126 | 127 | ||
| 127 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 128 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 128 | rb.Push(RESULT_SUCCESS); | 129 | rb.Push(RESULT_SUCCESS); |
| 129 | rb.PushCopyObjects(system_event.readable); | 130 | rb.PushCopyObjects(system_event->GetReadableEvent()); |
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { | 133 | void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { |
| @@ -160,7 +161,7 @@ private: | |||
| 160 | rb.Push(ERR_NOT_SUPPORTED); | 161 | rb.Push(ERR_NOT_SUPPORTED); |
| 161 | } | 162 | } |
| 162 | 163 | ||
| 163 | Kernel::EventPair system_event; | 164 | std::shared_ptr<Kernel::KEvent> system_event; |
| 164 | std::unique_ptr<AudioCore::AudioRenderer> renderer; | 165 | std::unique_ptr<AudioCore::AudioRenderer> renderer; |
| 165 | u32 rendering_time_limit_percent = 100; | 166 | u32 rendering_time_limit_percent = 100; |
| 166 | }; | 167 | }; |
| @@ -187,17 +188,19 @@ public: | |||
| 187 | RegisterHandlers(functions); | 188 | RegisterHandlers(functions); |
| 188 | 189 | ||
| 189 | auto& kernel = system.Kernel(); | 190 | auto& kernel = system.Kernel(); |
| 190 | buffer_event = | 191 | buffer_event = Kernel::KEvent::Create(kernel, "IAudioOutBufferReleasedEvent"); |
| 191 | Kernel::WritableEvent::CreateEventPair(kernel, "IAudioOutBufferReleasedEvent"); | 192 | buffer_event->Initialize(); |
| 192 | 193 | ||
| 193 | // Should be similar to audio_output_device_switch_event | 194 | // Should be similar to audio_output_device_switch_event |
| 194 | audio_input_device_switch_event = Kernel::WritableEvent::CreateEventPair( | 195 | audio_input_device_switch_event = |
| 195 | kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent"); | 196 | Kernel::KEvent::Create(kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent"); |
| 197 | audio_input_device_switch_event->Initialize(); | ||
| 196 | 198 | ||
| 197 | // Should only be signalled when an audio output device has been changed, example: speaker | 199 | // Should only be signalled when an audio output device has been changed, example: speaker |
| 198 | // to headset | 200 | // to headset |
| 199 | audio_output_device_switch_event = Kernel::WritableEvent::CreateEventPair( | 201 | audio_output_device_switch_event = |
| 200 | kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent"); | 202 | Kernel::KEvent::Create(kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent"); |
| 203 | audio_output_device_switch_event->Initialize(); | ||
| 201 | } | 204 | } |
| 202 | 205 | ||
| 203 | private: | 206 | private: |
| @@ -286,11 +289,11 @@ private: | |||
| 286 | void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { | 289 | void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { |
| 287 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 290 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 288 | 291 | ||
| 289 | buffer_event.writable->Signal(); | 292 | buffer_event->GetWritableEvent()->Signal(); |
| 290 | 293 | ||
| 291 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 294 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 292 | rb.Push(RESULT_SUCCESS); | 295 | rb.Push(RESULT_SUCCESS); |
| 293 | rb.PushCopyObjects(buffer_event.readable); | 296 | rb.PushCopyObjects(buffer_event->GetReadableEvent()); |
| 294 | } | 297 | } |
| 295 | 298 | ||
| 296 | void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { | 299 | void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { |
| @@ -307,7 +310,7 @@ private: | |||
| 307 | 310 | ||
| 308 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 311 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 309 | rb.Push(RESULT_SUCCESS); | 312 | rb.Push(RESULT_SUCCESS); |
| 310 | rb.PushCopyObjects(audio_input_device_switch_event.readable); | 313 | rb.PushCopyObjects(audio_input_device_switch_event->GetReadableEvent()); |
| 311 | } | 314 | } |
| 312 | 315 | ||
| 313 | void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { | 316 | void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { |
| @@ -315,13 +318,13 @@ private: | |||
| 315 | 318 | ||
| 316 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 319 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 317 | rb.Push(RESULT_SUCCESS); | 320 | rb.Push(RESULT_SUCCESS); |
| 318 | rb.PushCopyObjects(audio_output_device_switch_event.readable); | 321 | rb.PushCopyObjects(audio_output_device_switch_event->GetReadableEvent()); |
| 319 | } | 322 | } |
| 320 | 323 | ||
| 321 | u32_le revision = 0; | 324 | u32_le revision = 0; |
| 322 | Kernel::EventPair buffer_event; | 325 | std::shared_ptr<Kernel::KEvent> buffer_event; |
| 323 | Kernel::EventPair audio_input_device_switch_event; | 326 | std::shared_ptr<Kernel::KEvent> audio_input_device_switch_event; |
| 324 | Kernel::EventPair audio_output_device_switch_event; | 327 | std::shared_ptr<Kernel::KEvent> audio_output_device_switch_event; |
| 325 | 328 | ||
| 326 | }; // namespace Audio | 329 | }; // namespace Audio |
| 327 | 330 | ||
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp index 174388445..92d25dbe4 100644 --- a/src/core/hle/service/bcat/backend/backend.cpp +++ b/src/core/hle/service/bcat/backend/backend.cpp | |||
| @@ -5,6 +5,9 @@ | |||
| 5 | #include "common/hex_util.h" | 5 | #include "common/hex_util.h" |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/hle/kernel/k_event.h" | ||
| 9 | #include "core/hle/kernel/k_readable_event.h" | ||
| 10 | #include "core/hle/kernel/k_writable_event.h" | ||
| 8 | #include "core/hle/lock.h" | 11 | #include "core/hle/lock.h" |
| 9 | #include "core/hle/service/bcat/backend/backend.h" | 12 | #include "core/hle/service/bcat/backend/backend.h" |
| 10 | 13 | ||
| @@ -12,12 +15,13 @@ namespace Service::BCAT { | |||
| 12 | 15 | ||
| 13 | ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel, | 16 | ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel, |
| 14 | std::string_view event_name) { | 17 | std::string_view event_name) { |
| 15 | event = Kernel::WritableEvent::CreateEventPair( | 18 | event = Kernel::KEvent::Create(kernel, |
| 16 | kernel, std::string("ProgressServiceBackend:UpdateEvent:").append(event_name)); | 19 | "ProgressServiceBackend:UpdateEvent:" + std::string(event_name)); |
| 20 | event->Initialize(); | ||
| 17 | } | 21 | } |
| 18 | 22 | ||
| 19 | std::shared_ptr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const { | 23 | std::shared_ptr<Kernel::KReadableEvent> ProgressServiceBackend::GetEvent() const { |
| 20 | return event.readable; | 24 | return event->GetReadableEvent(); |
| 21 | } | 25 | } |
| 22 | 26 | ||
| 23 | DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { | 27 | DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { |
| @@ -85,9 +89,9 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) { | |||
| 85 | void ProgressServiceBackend::SignalUpdate() const { | 89 | void ProgressServiceBackend::SignalUpdate() const { |
| 86 | if (need_hle_lock) { | 90 | if (need_hle_lock) { |
| 87 | std::lock_guard lock(HLE::g_hle_lock); | 91 | std::lock_guard lock(HLE::g_hle_lock); |
| 88 | event.writable->Signal(); | 92 | event->GetWritableEvent()->Signal(); |
| 89 | } else { | 93 | } else { |
| 90 | event.writable->Signal(); | 94 | event->GetWritableEvent()->Signal(); |
| 91 | } | 95 | } |
| 92 | } | 96 | } |
| 93 | 97 | ||
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h index 48bbbe66f..db585b069 100644 --- a/src/core/hle/service/bcat/backend/backend.h +++ b/src/core/hle/service/bcat/backend/backend.h | |||
| @@ -11,8 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "core/file_sys/vfs_types.h" | 13 | #include "core/file_sys/vfs_types.h" |
| 14 | #include "core/hle/kernel/readable_event.h" | ||
| 15 | #include "core/hle/kernel/writable_event.h" | ||
| 16 | #include "core/hle/result.h" | 14 | #include "core/hle/result.h" |
| 17 | 15 | ||
| 18 | namespace Core { | 16 | namespace Core { |
| @@ -21,7 +19,9 @@ class System; | |||
| 21 | 19 | ||
| 22 | namespace Kernel { | 20 | namespace Kernel { |
| 23 | class KernelCore; | 21 | class KernelCore; |
| 24 | } | 22 | class KEvent; |
| 23 | class KReadableEvent; | ||
| 24 | } // namespace Kernel | ||
| 25 | 25 | ||
| 26 | namespace Service::BCAT { | 26 | namespace Service::BCAT { |
| 27 | 27 | ||
| @@ -98,13 +98,13 @@ public: | |||
| 98 | private: | 98 | private: |
| 99 | explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name); | 99 | explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name); |
| 100 | 100 | ||
| 101 | std::shared_ptr<Kernel::ReadableEvent> GetEvent() const; | 101 | std::shared_ptr<Kernel::KReadableEvent> GetEvent() const; |
| 102 | DeliveryCacheProgressImpl& GetImpl(); | 102 | DeliveryCacheProgressImpl& GetImpl(); |
| 103 | 103 | ||
| 104 | void SignalUpdate() const; | 104 | void SignalUpdate() const; |
| 105 | 105 | ||
| 106 | DeliveryCacheProgressImpl impl{}; | 106 | DeliveryCacheProgressImpl impl{}; |
| 107 | Kernel::EventPair event; | 107 | std::shared_ptr<Kernel::KEvent> event; |
| 108 | bool need_hle_lock = false; | 108 | bool need_hle_lock = false; |
| 109 | }; | 109 | }; |
| 110 | 110 | ||
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index b8696a395..503109fdd 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp | |||
| @@ -11,9 +11,9 @@ | |||
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/file_sys/vfs.h" | 12 | #include "core/file_sys/vfs.h" |
| 13 | #include "core/hle/ipc_helpers.h" | 13 | #include "core/hle/ipc_helpers.h" |
| 14 | #include "core/hle/kernel/k_readable_event.h" | ||
| 15 | #include "core/hle/kernel/k_writable_event.h" | ||
| 14 | #include "core/hle/kernel/process.h" | 16 | #include "core/hle/kernel/process.h" |
| 15 | #include "core/hle/kernel/readable_event.h" | ||
| 16 | #include "core/hle/kernel/writable_event.h" | ||
| 17 | #include "core/hle/service/bcat/backend/backend.h" | 17 | #include "core/hle/service/bcat/backend/backend.h" |
| 18 | #include "core/hle/service/bcat/bcat.h" | 18 | #include "core/hle/service/bcat/bcat.h" |
| 19 | #include "core/hle/service/bcat/module.h" | 19 | #include "core/hle/service/bcat/module.h" |
| @@ -89,7 +89,7 @@ struct DeliveryCacheDirectoryEntry { | |||
| 89 | class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { | 89 | class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { |
| 90 | public: | 90 | public: |
| 91 | explicit IDeliveryCacheProgressService(Core::System& system_, | 91 | explicit IDeliveryCacheProgressService(Core::System& system_, |
| 92 | std::shared_ptr<Kernel::ReadableEvent> event_, | 92 | std::shared_ptr<Kernel::KReadableEvent> event_, |
| 93 | const DeliveryCacheProgressImpl& impl_) | 93 | const DeliveryCacheProgressImpl& impl_) |
| 94 | : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{std::move(event_)}, | 94 | : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{std::move(event_)}, |
| 95 | impl{impl_} { | 95 | impl{impl_} { |
| @@ -121,7 +121,7 @@ private: | |||
| 121 | rb.Push(RESULT_SUCCESS); | 121 | rb.Push(RESULT_SUCCESS); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | std::shared_ptr<Kernel::ReadableEvent> event; | 124 | std::shared_ptr<Kernel::KReadableEvent> event; |
| 125 | const DeliveryCacheProgressImpl& impl; | 125 | const DeliveryCacheProgressImpl& impl; |
| 126 | }; | 126 | }; |
| 127 | 127 | ||
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index 2de86f1f1..17a2ac899 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp | |||
| @@ -6,9 +6,9 @@ | |||
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/ipc_helpers.h" | 7 | #include "core/hle/ipc_helpers.h" |
| 8 | #include "core/hle/kernel/hle_ipc.h" | 8 | #include "core/hle/kernel/hle_ipc.h" |
| 9 | #include "core/hle/kernel/k_event.h" | ||
| 10 | #include "core/hle/kernel/k_readable_event.h" | ||
| 9 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/readable_event.h" | ||
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 12 | #include "core/hle/service/btdrv/btdrv.h" | 12 | #include "core/hle/service/btdrv/btdrv.h" |
| 13 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 14 | #include "core/hle/service/sm/sm.h" | 14 | #include "core/hle/service/sm/sm.h" |
| @@ -35,7 +35,8 @@ public: | |||
| 35 | RegisterHandlers(functions); | 35 | RegisterHandlers(functions); |
| 36 | 36 | ||
| 37 | auto& kernel = system.Kernel(); | 37 | auto& kernel = system.Kernel(); |
| 38 | register_event = Kernel::WritableEvent::CreateEventPair(kernel, "BT:RegisterEvent"); | 38 | register_event = Kernel::KEvent::Create(kernel, "BT:RegisterEvent"); |
| 39 | register_event->Initialize(); | ||
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | private: | 42 | private: |
| @@ -44,10 +45,10 @@ private: | |||
| 44 | 45 | ||
| 45 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 46 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 46 | rb.Push(RESULT_SUCCESS); | 47 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.PushCopyObjects(register_event.readable); | 48 | rb.PushCopyObjects(register_event->GetReadableEvent()); |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | Kernel::EventPair register_event; | 51 | std::shared_ptr<Kernel::KEvent> register_event; |
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | class BtDrv final : public ServiceFramework<BtDrv> { | 54 | class BtDrv final : public ServiceFramework<BtDrv> { |
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index 38b55300e..9cf2ee92a 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/kernel/hle_ipc.h" | 10 | #include "core/hle/kernel/hle_ipc.h" |
| 11 | #include "core/hle/kernel/k_event.h" | ||
| 12 | #include "core/hle/kernel/k_readable_event.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/readable_event.h" | ||
| 13 | #include "core/hle/kernel/writable_event.h" | ||
| 14 | #include "core/hle/service/btm/btm.h" | 14 | #include "core/hle/service/btm/btm.h" |
| 15 | #include "core/hle/service/service.h" | 15 | #include "core/hle/service/service.h" |
| 16 | 16 | ||
| @@ -58,12 +58,14 @@ public: | |||
| 58 | RegisterHandlers(functions); | 58 | RegisterHandlers(functions); |
| 59 | 59 | ||
| 60 | auto& kernel = system.Kernel(); | 60 | auto& kernel = system.Kernel(); |
| 61 | scan_event = Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ScanEvent"); | 61 | scan_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ScanEvent"); |
| 62 | connection_event = | 62 | scan_event->Initialize(); |
| 63 | Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ConnectionEvent"); | 63 | connection_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConnectionEvent"); |
| 64 | service_discovery = | 64 | connection_event->Initialize(); |
| 65 | Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:Discovery"); | 65 | service_discovery = Kernel::KEvent::Create(kernel, "IBtmUserCore:Discovery"); |
| 66 | config_event = Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ConfigEvent"); | 66 | service_discovery->Initialize(); |
| 67 | config_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConfigEvent"); | ||
| 68 | config_event->Initialize(); | ||
| 67 | } | 69 | } |
| 68 | 70 | ||
| 69 | private: | 71 | private: |
| @@ -72,7 +74,7 @@ private: | |||
| 72 | 74 | ||
| 73 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 75 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 74 | rb.Push(RESULT_SUCCESS); | 76 | rb.Push(RESULT_SUCCESS); |
| 75 | rb.PushCopyObjects(scan_event.readable); | 77 | rb.PushCopyObjects(scan_event->GetReadableEvent()); |
| 76 | } | 78 | } |
| 77 | 79 | ||
| 78 | void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) { | 80 | void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) { |
| @@ -80,7 +82,7 @@ private: | |||
| 80 | 82 | ||
| 81 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 83 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 82 | rb.Push(RESULT_SUCCESS); | 84 | rb.Push(RESULT_SUCCESS); |
| 83 | rb.PushCopyObjects(connection_event.readable); | 85 | rb.PushCopyObjects(connection_event->GetReadableEvent()); |
| 84 | } | 86 | } |
| 85 | 87 | ||
| 86 | void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) { | 88 | void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) { |
| @@ -88,7 +90,7 @@ private: | |||
| 88 | 90 | ||
| 89 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 91 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 90 | rb.Push(RESULT_SUCCESS); | 92 | rb.Push(RESULT_SUCCESS); |
| 91 | rb.PushCopyObjects(service_discovery.readable); | 93 | rb.PushCopyObjects(service_discovery->GetReadableEvent()); |
| 92 | } | 94 | } |
| 93 | 95 | ||
| 94 | void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) { | 96 | void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) { |
| @@ -96,13 +98,13 @@ private: | |||
| 96 | 98 | ||
| 97 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 99 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 98 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 99 | rb.PushCopyObjects(config_event.readable); | 101 | rb.PushCopyObjects(config_event->GetReadableEvent()); |
| 100 | } | 102 | } |
| 101 | 103 | ||
| 102 | Kernel::EventPair scan_event; | 104 | std::shared_ptr<Kernel::KEvent> scan_event; |
| 103 | Kernel::EventPair connection_event; | 105 | std::shared_ptr<Kernel::KEvent> connection_event; |
| 104 | Kernel::EventPair service_discovery; | 106 | std::shared_ptr<Kernel::KEvent> service_discovery; |
| 105 | Kernel::EventPair config_event; | 107 | std::shared_ptr<Kernel::KEvent> config_event; |
| 106 | }; | 108 | }; |
| 107 | 109 | ||
| 108 | class BTM_USR final : public ServiceFramework<BTM_USR> { | 110 | class BTM_USR final : public ServiceFramework<BTM_USR> { |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index c5b053c31..72a877d68 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -7,8 +7,9 @@ | |||
| 7 | #include "common/uuid.h" | 7 | #include "common/uuid.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/kernel/readable_event.h" | 10 | #include "core/hle/kernel/k_event.h" |
| 11 | #include "core/hle/kernel/writable_event.h" | 11 | #include "core/hle/kernel/k_readable_event.h" |
| 12 | #include "core/hle/kernel/k_writable_event.h" | ||
| 12 | #include "core/hle/service/friend/errors.h" | 13 | #include "core/hle/service/friend/errors.h" |
| 13 | #include "core/hle/service/friend/friend.h" | 14 | #include "core/hle/service/friend/friend.h" |
| 14 | #include "core/hle/service/friend/interface.h" | 15 | #include "core/hle/service/friend/interface.h" |
| @@ -183,8 +184,9 @@ public: | |||
| 183 | 184 | ||
| 184 | RegisterHandlers(functions); | 185 | RegisterHandlers(functions); |
| 185 | 186 | ||
| 186 | notification_event = Kernel::WritableEvent::CreateEventPair( | 187 | notification_event = |
| 187 | system.Kernel(), "INotificationService:NotifyEvent"); | 188 | Kernel::KEvent::Create(system.Kernel(), "INotificationService:NotifyEvent"); |
| 189 | notification_event->Initialize(); | ||
| 188 | } | 190 | } |
| 189 | 191 | ||
| 190 | private: | 192 | private: |
| @@ -193,7 +195,7 @@ private: | |||
| 193 | 195 | ||
| 194 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 196 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 195 | rb.Push(RESULT_SUCCESS); | 197 | rb.Push(RESULT_SUCCESS); |
| 196 | rb.PushCopyObjects(notification_event.readable); | 198 | rb.PushCopyObjects(notification_event->GetReadableEvent()); |
| 197 | } | 199 | } |
| 198 | 200 | ||
| 199 | void Clear(Kernel::HLERequestContext& ctx) { | 201 | void Clear(Kernel::HLERequestContext& ctx) { |
| @@ -258,7 +260,7 @@ private: | |||
| 258 | }; | 260 | }; |
| 259 | 261 | ||
| 260 | Common::UUID uuid{Common::INVALID_UUID}; | 262 | Common::UUID uuid{Common::INVALID_UUID}; |
| 261 | Kernel::EventPair notification_event; | 263 | std::shared_ptr<Kernel::KEvent> notification_event; |
| 262 | std::queue<SizedNotificationInfo> notifications; | 264 | std::queue<SizedNotificationInfo> notifications; |
| 263 | States states{}; | 265 | States states{}; |
| 264 | }; | 266 | }; |
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 59b694cd4..c4a59147d 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp | |||
| @@ -39,16 +39,25 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, | |||
| 39 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 39 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 40 | 40 | ||
| 41 | cur_entry.key.fill(0); | 41 | cur_entry.key.fill(0); |
| 42 | cur_entry.modifier = 0; | ||
| 43 | if (Settings::values.keyboard_enabled) { | 42 | if (Settings::values.keyboard_enabled) { |
| 44 | for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { | 43 | for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { |
| 45 | auto& entry = cur_entry.key[i / KEYS_PER_BYTE]; | 44 | auto& entry = cur_entry.key[i / KEYS_PER_BYTE]; |
| 46 | entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE))); | 45 | entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE))); |
| 47 | } | 46 | } |
| 48 | 47 | ||
| 49 | for (std::size_t i = 0; i < keyboard_mods.size(); ++i) { | 48 | using namespace Settings::NativeKeyboard; |
| 50 | cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i); | 49 | |
| 51 | } | 50 | // TODO: Assign the correct key to all modifiers |
| 51 | cur_entry.modifier.control.Assign(keyboard_mods[LeftControl]->GetStatus()); | ||
| 52 | cur_entry.modifier.shift.Assign(keyboard_mods[LeftShift]->GetStatus()); | ||
| 53 | cur_entry.modifier.left_alt.Assign(keyboard_mods[LeftAlt]->GetStatus()); | ||
| 54 | cur_entry.modifier.right_alt.Assign(keyboard_mods[RightAlt]->GetStatus()); | ||
| 55 | cur_entry.modifier.gui.Assign(0); | ||
| 56 | cur_entry.modifier.caps_lock.Assign(keyboard_mods[CapsLock]->GetStatus()); | ||
| 57 | cur_entry.modifier.scroll_lock.Assign(keyboard_mods[ScrollLock]->GetStatus()); | ||
| 58 | cur_entry.modifier.num_lock.Assign(keyboard_mods[NumLock]->GetStatus()); | ||
| 59 | cur_entry.modifier.katakana.Assign(0); | ||
| 60 | cur_entry.modifier.hiragana.Assign(0); | ||
| 52 | } | 61 | } |
| 53 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 62 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); |
| 54 | } | 63 | } |
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index f3eef5936..b5b281752 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/bit_field.h" | ||
| 8 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| @@ -31,12 +32,28 @@ public: | |||
| 31 | void OnLoadInputDevices() override; | 32 | void OnLoadInputDevices() override; |
| 32 | 33 | ||
| 33 | private: | 34 | private: |
| 35 | struct Modifiers { | ||
| 36 | union { | ||
| 37 | u32_le raw{}; | ||
| 38 | BitField<0, 1, u32> control; | ||
| 39 | BitField<1, 1, u32> shift; | ||
| 40 | BitField<2, 1, u32> left_alt; | ||
| 41 | BitField<3, 1, u32> right_alt; | ||
| 42 | BitField<4, 1, u32> gui; | ||
| 43 | BitField<8, 1, u32> caps_lock; | ||
| 44 | BitField<9, 1, u32> scroll_lock; | ||
| 45 | BitField<10, 1, u32> num_lock; | ||
| 46 | BitField<11, 1, u32> katakana; | ||
| 47 | BitField<12, 1, u32> hiragana; | ||
| 48 | }; | ||
| 49 | }; | ||
| 50 | static_assert(sizeof(Modifiers) == 0x4, "Modifiers is an invalid size"); | ||
| 51 | |||
| 34 | struct KeyboardState { | 52 | struct KeyboardState { |
| 35 | s64_le sampling_number; | 53 | s64_le sampling_number; |
| 36 | s64_le sampling_number2; | 54 | s64_le sampling_number2; |
| 37 | 55 | ||
| 38 | s32_le modifier; | 56 | Modifiers modifier; |
| 39 | s32_le attribute; | ||
| 40 | std::array<u8, 32> key; | 57 | std::array<u8, 32> key; |
| 41 | }; | 58 | }; |
| 42 | static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); | 59 | static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); |
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index ac40989c5..2e7457604 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp | |||
| @@ -36,6 +36,7 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 36 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 36 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 37 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 37 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 38 | 38 | ||
| 39 | cur_entry.attribute.raw = 0; | ||
| 39 | if (Settings::values.mouse_enabled) { | 40 | if (Settings::values.mouse_enabled) { |
| 40 | const auto [px, py, sx, sy] = mouse_device->GetStatus(); | 41 | const auto [px, py, sx, sy] = mouse_device->GetStatus(); |
| 41 | const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width); | 42 | const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width); |
| @@ -46,10 +47,14 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 46 | cur_entry.delta_y = y - last_entry.y; | 47 | cur_entry.delta_y = y - last_entry.y; |
| 47 | cur_entry.mouse_wheel_x = sx; | 48 | cur_entry.mouse_wheel_x = sx; |
| 48 | cur_entry.mouse_wheel_y = sy; | 49 | cur_entry.mouse_wheel_y = sy; |
| 50 | cur_entry.attribute.is_connected.Assign(1); | ||
| 49 | 51 | ||
| 50 | for (std::size_t i = 0; i < mouse_button_devices.size(); ++i) { | 52 | using namespace Settings::NativeMouseButton; |
| 51 | cur_entry.button |= (mouse_button_devices[i]->GetStatus() << i); | 53 | cur_entry.button.left.Assign(mouse_button_devices[Left]->GetStatus()); |
| 52 | } | 54 | cur_entry.button.right.Assign(mouse_button_devices[Right]->GetStatus()); |
| 55 | cur_entry.button.middle.Assign(mouse_button_devices[Middle]->GetStatus()); | ||
| 56 | cur_entry.button.forward.Assign(mouse_button_devices[Forward]->GetStatus()); | ||
| 57 | cur_entry.button.back.Assign(mouse_button_devices[Back]->GetStatus()); | ||
| 53 | } | 58 | } |
| 54 | 59 | ||
| 55 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 60 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); |
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 357ab7107..3b432a36e 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/bit_field.h" | ||
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 10 | #include "core/frontend/input.h" | 11 | #include "core/frontend/input.h" |
| @@ -30,6 +31,27 @@ public: | |||
| 30 | void OnLoadInputDevices() override; | 31 | void OnLoadInputDevices() override; |
| 31 | 32 | ||
| 32 | private: | 33 | private: |
| 34 | struct Buttons { | ||
| 35 | union { | ||
| 36 | u32_le raw{}; | ||
| 37 | BitField<0, 1, u32> left; | ||
| 38 | BitField<1, 1, u32> right; | ||
| 39 | BitField<2, 1, u32> middle; | ||
| 40 | BitField<3, 1, u32> forward; | ||
| 41 | BitField<4, 1, u32> back; | ||
| 42 | }; | ||
| 43 | }; | ||
| 44 | static_assert(sizeof(Buttons) == 0x4, "Buttons is an invalid size"); | ||
| 45 | |||
| 46 | struct Attributes { | ||
| 47 | union { | ||
| 48 | u32_le raw{}; | ||
| 49 | BitField<0, 1, u32> transferable; | ||
| 50 | BitField<1, 1, u32> is_connected; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | ||
| 54 | |||
| 33 | struct MouseState { | 55 | struct MouseState { |
| 34 | s64_le sampling_number; | 56 | s64_le sampling_number; |
| 35 | s64_le sampling_number2; | 57 | s64_le sampling_number2; |
| @@ -39,8 +61,8 @@ private: | |||
| 39 | s32_le delta_y; | 61 | s32_le delta_y; |
| 40 | s32_le mouse_wheel_x; | 62 | s32_le mouse_wheel_x; |
| 41 | s32_le mouse_wheel_y; | 63 | s32_le mouse_wheel_y; |
| 42 | s32_le button; | 64 | Buttons button; |
| 43 | s32_le attribute; | 65 | Attributes attribute; |
| 44 | }; | 66 | }; |
| 45 | static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size"); | 67 | static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size"); |
| 46 | 68 | ||
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index d280e7caf..dbf198345 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -12,9 +12,10 @@ | |||
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/core_timing.h" | 13 | #include "core/core_timing.h" |
| 14 | #include "core/frontend/input.h" | 14 | #include "core/frontend/input.h" |
| 15 | #include "core/hle/kernel/k_event.h" | ||
| 16 | #include "core/hle/kernel/k_readable_event.h" | ||
| 17 | #include "core/hle/kernel/k_writable_event.h" | ||
| 15 | #include "core/hle/kernel/kernel.h" | 18 | #include "core/hle/kernel/kernel.h" |
| 16 | #include "core/hle/kernel/readable_event.h" | ||
| 17 | #include "core/hle/kernel/writable_event.h" | ||
| 18 | #include "core/hle/service/hid/controllers/npad.h" | 19 | #include "core/hle/service/hid/controllers/npad.h" |
| 19 | #include "core/settings.h" | 20 | #include "core/settings.h" |
| 20 | 21 | ||
| @@ -141,7 +142,9 @@ bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { | |||
| 141 | device_handle.device_index < DeviceIndex::MaxDeviceIndex; | 142 | device_handle.device_index < DeviceIndex::MaxDeviceIndex; |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} | 145 | Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) { |
| 146 | latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE}); | ||
| 147 | } | ||
| 145 | 148 | ||
| 146 | Controller_NPad::~Controller_NPad() { | 149 | Controller_NPad::~Controller_NPad() { |
| 147 | OnRelease(); | 150 | OnRelease(); |
| @@ -151,79 +154,86 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | |||
| 151 | const auto controller_type = connected_controllers[controller_idx].type; | 154 | const auto controller_type = connected_controllers[controller_idx].type; |
| 152 | auto& controller = shared_memory_entries[controller_idx]; | 155 | auto& controller = shared_memory_entries[controller_idx]; |
| 153 | if (controller_type == NPadControllerType::None) { | 156 | if (controller_type == NPadControllerType::None) { |
| 154 | styleset_changed_events[controller_idx].writable->Signal(); | 157 | styleset_changed_events[controller_idx]->GetWritableEvent()->Signal(); |
| 155 | return; | 158 | return; |
| 156 | } | 159 | } |
| 157 | controller.joy_styles.raw = 0; // Zero out | 160 | controller.style_set.raw = 0; // Zero out |
| 158 | controller.device_type.raw = 0; | 161 | controller.device_type.raw = 0; |
| 159 | controller.properties.raw = 0; | 162 | controller.system_properties.raw = 0; |
| 160 | switch (controller_type) { | 163 | switch (controller_type) { |
| 161 | case NPadControllerType::None: | 164 | case NPadControllerType::None: |
| 162 | UNREACHABLE(); | 165 | UNREACHABLE(); |
| 163 | break; | 166 | break; |
| 164 | case NPadControllerType::ProController: | 167 | case NPadControllerType::ProController: |
| 165 | controller.joy_styles.pro_controller.Assign(1); | 168 | controller.style_set.fullkey.Assign(1); |
| 166 | controller.device_type.pro_controller.Assign(1); | 169 | controller.device_type.fullkey.Assign(1); |
| 167 | controller.properties.is_vertical.Assign(1); | 170 | controller.system_properties.is_vertical.Assign(1); |
| 168 | controller.properties.use_plus.Assign(1); | 171 | controller.system_properties.use_plus.Assign(1); |
| 169 | controller.properties.use_minus.Assign(1); | 172 | controller.system_properties.use_minus.Assign(1); |
| 170 | controller.pad_assignment = NpadAssignments::Single; | 173 | controller.assignment_mode = NpadAssignments::Single; |
| 174 | controller.footer_type = AppletFooterUiType::SwitchProController; | ||
| 171 | break; | 175 | break; |
| 172 | case NPadControllerType::Handheld: | 176 | case NPadControllerType::Handheld: |
| 173 | controller.joy_styles.handheld.Assign(1); | 177 | controller.style_set.handheld.Assign(1); |
| 174 | controller.device_type.handheld.Assign(1); | 178 | controller.device_type.handheld_left.Assign(1); |
| 175 | controller.properties.is_vertical.Assign(1); | 179 | controller.device_type.handheld_right.Assign(1); |
| 176 | controller.properties.use_plus.Assign(1); | 180 | controller.system_properties.is_vertical.Assign(1); |
| 177 | controller.properties.use_minus.Assign(1); | 181 | controller.system_properties.use_plus.Assign(1); |
| 178 | controller.pad_assignment = NpadAssignments::Dual; | 182 | controller.system_properties.use_minus.Assign(1); |
| 183 | controller.assignment_mode = NpadAssignments::Dual; | ||
| 184 | controller.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; | ||
| 179 | break; | 185 | break; |
| 180 | case NPadControllerType::JoyDual: | 186 | case NPadControllerType::JoyDual: |
| 181 | controller.joy_styles.joycon_dual.Assign(1); | 187 | controller.style_set.joycon_dual.Assign(1); |
| 182 | controller.device_type.joycon_left.Assign(1); | 188 | controller.device_type.joycon_left.Assign(1); |
| 183 | controller.device_type.joycon_right.Assign(1); | 189 | controller.device_type.joycon_right.Assign(1); |
| 184 | controller.properties.is_vertical.Assign(1); | 190 | controller.system_properties.is_vertical.Assign(1); |
| 185 | controller.properties.use_plus.Assign(1); | 191 | controller.system_properties.use_plus.Assign(1); |
| 186 | controller.properties.use_minus.Assign(1); | 192 | controller.system_properties.use_minus.Assign(1); |
| 187 | controller.pad_assignment = NpadAssignments::Dual; | 193 | controller.assignment_mode = NpadAssignments::Dual; |
| 194 | controller.footer_type = AppletFooterUiType::JoyDual; | ||
| 188 | break; | 195 | break; |
| 189 | case NPadControllerType::JoyLeft: | 196 | case NPadControllerType::JoyLeft: |
| 190 | controller.joy_styles.joycon_left.Assign(1); | 197 | controller.style_set.joycon_left.Assign(1); |
| 191 | controller.device_type.joycon_left.Assign(1); | 198 | controller.device_type.joycon_left.Assign(1); |
| 192 | controller.properties.is_horizontal.Assign(1); | 199 | controller.system_properties.is_horizontal.Assign(1); |
| 193 | controller.properties.use_minus.Assign(1); | 200 | controller.system_properties.use_minus.Assign(1); |
| 194 | controller.pad_assignment = NpadAssignments::Single; | 201 | controller.assignment_mode = NpadAssignments::Single; |
| 202 | controller.footer_type = AppletFooterUiType::JoyLeftHorizontal; | ||
| 195 | break; | 203 | break; |
| 196 | case NPadControllerType::JoyRight: | 204 | case NPadControllerType::JoyRight: |
| 197 | controller.joy_styles.joycon_right.Assign(1); | 205 | controller.style_set.joycon_right.Assign(1); |
| 198 | controller.device_type.joycon_right.Assign(1); | 206 | controller.device_type.joycon_right.Assign(1); |
| 199 | controller.properties.is_horizontal.Assign(1); | 207 | controller.system_properties.is_horizontal.Assign(1); |
| 200 | controller.properties.use_plus.Assign(1); | 208 | controller.system_properties.use_plus.Assign(1); |
| 201 | controller.pad_assignment = NpadAssignments::Single; | 209 | controller.assignment_mode = NpadAssignments::Single; |
| 210 | controller.footer_type = AppletFooterUiType::JoyRightHorizontal; | ||
| 202 | break; | 211 | break; |
| 203 | case NPadControllerType::Pokeball: | 212 | case NPadControllerType::Pokeball: |
| 204 | controller.joy_styles.pokeball.Assign(1); | 213 | controller.style_set.palma.Assign(1); |
| 205 | controller.device_type.pokeball.Assign(1); | 214 | controller.device_type.palma.Assign(1); |
| 206 | controller.pad_assignment = NpadAssignments::Single; | 215 | controller.assignment_mode = NpadAssignments::Single; |
| 207 | break; | 216 | break; |
| 208 | } | 217 | } |
| 209 | 218 | ||
| 210 | controller.single_color_error = ColorReadError::ReadOk; | 219 | controller.fullkey_color.attribute = ColorAttributes::Ok; |
| 211 | controller.single_color.body_color = 0; | 220 | controller.fullkey_color.fullkey.body = 0; |
| 212 | controller.single_color.button_color = 0; | 221 | controller.fullkey_color.fullkey.button = 0; |
| 213 | 222 | ||
| 214 | controller.dual_color_error = ColorReadError::ReadOk; | 223 | controller.joycon_color.attribute = ColorAttributes::Ok; |
| 215 | controller.left_color.body_color = | 224 | controller.joycon_color.left.body = |
| 216 | Settings::values.players.GetValue()[controller_idx].body_color_left; | 225 | Settings::values.players.GetValue()[controller_idx].body_color_left; |
| 217 | controller.left_color.button_color = | 226 | controller.joycon_color.left.button = |
| 218 | Settings::values.players.GetValue()[controller_idx].button_color_left; | 227 | Settings::values.players.GetValue()[controller_idx].button_color_left; |
| 219 | controller.right_color.body_color = | 228 | controller.joycon_color.right.body = |
| 220 | Settings::values.players.GetValue()[controller_idx].body_color_right; | 229 | Settings::values.players.GetValue()[controller_idx].body_color_right; |
| 221 | controller.right_color.button_color = | 230 | controller.joycon_color.right.button = |
| 222 | Settings::values.players.GetValue()[controller_idx].button_color_right; | 231 | Settings::values.players.GetValue()[controller_idx].button_color_right; |
| 223 | 232 | ||
| 224 | controller.battery_level[0] = BATTERY_FULL; | 233 | // TODO: Investigate when we should report all batery types |
| 225 | controller.battery_level[1] = BATTERY_FULL; | 234 | controller.battery_level_dual = BATTERY_FULL; |
| 226 | controller.battery_level[2] = BATTERY_FULL; | 235 | controller.battery_level_left = BATTERY_FULL; |
| 236 | controller.battery_level_right = BATTERY_FULL; | ||
| 227 | 237 | ||
| 228 | SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); | 238 | SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); |
| 229 | } | 239 | } |
| @@ -231,8 +241,9 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | |||
| 231 | void Controller_NPad::OnInit() { | 241 | void Controller_NPad::OnInit() { |
| 232 | auto& kernel = system.Kernel(); | 242 | auto& kernel = system.Kernel(); |
| 233 | for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { | 243 | for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { |
| 234 | styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( | 244 | styleset_changed_events[i] = |
| 235 | kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); | 245 | Kernel::KEvent::Create(kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); |
| 246 | styleset_changed_events[i]->Initialize(); | ||
| 236 | } | 247 | } |
| 237 | 248 | ||
| 238 | if (!IsControllerActivated()) { | 249 | if (!IsControllerActivated()) { |
| @@ -247,8 +258,8 @@ void Controller_NPad::OnInit() { | |||
| 247 | style.joycon_left.Assign(1); | 258 | style.joycon_left.Assign(1); |
| 248 | style.joycon_right.Assign(1); | 259 | style.joycon_right.Assign(1); |
| 249 | style.joycon_dual.Assign(1); | 260 | style.joycon_dual.Assign(1); |
| 250 | style.pro_controller.Assign(1); | 261 | style.fullkey.Assign(1); |
| 251 | style.pokeball.Assign(1); | 262 | style.palma.Assign(1); |
| 252 | } | 263 | } |
| 253 | 264 | ||
| 254 | std::transform(Settings::values.players.GetValue().begin(), | 265 | std::transform(Settings::values.players.GetValue().begin(), |
| @@ -402,13 +413,10 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 402 | } | 413 | } |
| 403 | for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { | 414 | for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { |
| 404 | auto& npad = shared_memory_entries[i]; | 415 | auto& npad = shared_memory_entries[i]; |
| 405 | const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, | 416 | const std::array<NPadGeneric*, 7> controller_npads{ |
| 406 | &npad.handheld_states, | 417 | &npad.fullkey_states, &npad.handheld_states, &npad.joy_dual_states, |
| 407 | &npad.dual_states, | 418 | &npad.joy_left_states, &npad.joy_right_states, &npad.palma_states, |
| 408 | &npad.left_joy_states, | 419 | &npad.system_ext_states}; |
| 409 | &npad.right_joy_states, | ||
| 410 | &npad.pokeball_states, | ||
| 411 | &npad.libnx}; | ||
| 412 | 420 | ||
| 413 | for (auto* main_controller : controller_npads) { | 421 | for (auto* main_controller : controller_npads) { |
| 414 | main_controller->common.entry_count = 16; | 422 | main_controller->common.entry_count = 16; |
| @@ -438,19 +446,19 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 438 | auto& pad_state = npad_pad_states[npad_index]; | 446 | auto& pad_state = npad_pad_states[npad_index]; |
| 439 | 447 | ||
| 440 | auto& main_controller = | 448 | auto& main_controller = |
| 441 | npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; | 449 | npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index]; |
| 442 | auto& handheld_entry = | 450 | auto& handheld_entry = |
| 443 | npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; | 451 | npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; |
| 444 | auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index]; | 452 | auto& dual_entry = npad.joy_dual_states.npad[npad.joy_dual_states.common.last_entry_index]; |
| 445 | auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index]; | 453 | auto& left_entry = npad.joy_left_states.npad[npad.joy_left_states.common.last_entry_index]; |
| 446 | auto& right_entry = | 454 | auto& right_entry = |
| 447 | npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index]; | 455 | npad.joy_right_states.npad[npad.joy_right_states.common.last_entry_index]; |
| 448 | auto& pokeball_entry = | 456 | auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index]; |
| 449 | npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; | 457 | auto& libnx_entry = |
| 450 | auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; | 458 | npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index]; |
| 451 | 459 | ||
| 452 | libnx_entry.connection_status.raw = 0; | 460 | libnx_entry.connection_status.raw = 0; |
| 453 | libnx_entry.connection_status.IsConnected.Assign(1); | 461 | libnx_entry.connection_status.is_connected.Assign(1); |
| 454 | 462 | ||
| 455 | switch (controller_type) { | 463 | switch (controller_type) { |
| 456 | case NPadControllerType::None: | 464 | case NPadControllerType::None: |
| @@ -458,67 +466,67 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 458 | break; | 466 | break; |
| 459 | case NPadControllerType::ProController: | 467 | case NPadControllerType::ProController: |
| 460 | main_controller.connection_status.raw = 0; | 468 | main_controller.connection_status.raw = 0; |
| 461 | main_controller.connection_status.IsConnected.Assign(1); | 469 | main_controller.connection_status.is_connected.Assign(1); |
| 462 | main_controller.connection_status.IsWired.Assign(1); | 470 | main_controller.connection_status.is_wired.Assign(1); |
| 463 | main_controller.pad.pad_states.raw = pad_state.pad_states.raw; | 471 | main_controller.pad.pad_states.raw = pad_state.pad_states.raw; |
| 464 | main_controller.pad.l_stick = pad_state.l_stick; | 472 | main_controller.pad.l_stick = pad_state.l_stick; |
| 465 | main_controller.pad.r_stick = pad_state.r_stick; | 473 | main_controller.pad.r_stick = pad_state.r_stick; |
| 466 | 474 | ||
| 467 | libnx_entry.connection_status.IsWired.Assign(1); | 475 | libnx_entry.connection_status.is_wired.Assign(1); |
| 468 | break; | 476 | break; |
| 469 | case NPadControllerType::Handheld: | 477 | case NPadControllerType::Handheld: |
| 470 | handheld_entry.connection_status.raw = 0; | 478 | handheld_entry.connection_status.raw = 0; |
| 471 | handheld_entry.connection_status.IsConnected.Assign(1); | 479 | handheld_entry.connection_status.is_connected.Assign(1); |
| 472 | handheld_entry.connection_status.IsWired.Assign(1); | 480 | handheld_entry.connection_status.is_wired.Assign(1); |
| 473 | handheld_entry.connection_status.IsLeftJoyConnected.Assign(1); | 481 | handheld_entry.connection_status.is_left_connected.Assign(1); |
| 474 | handheld_entry.connection_status.IsRightJoyConnected.Assign(1); | 482 | handheld_entry.connection_status.is_right_connected.Assign(1); |
| 475 | handheld_entry.connection_status.IsLeftJoyWired.Assign(1); | 483 | handheld_entry.connection_status.is_left_wired.Assign(1); |
| 476 | handheld_entry.connection_status.IsRightJoyWired.Assign(1); | 484 | handheld_entry.connection_status.is_right_wired.Assign(1); |
| 477 | handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 485 | handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 478 | handheld_entry.pad.l_stick = pad_state.l_stick; | 486 | handheld_entry.pad.l_stick = pad_state.l_stick; |
| 479 | handheld_entry.pad.r_stick = pad_state.r_stick; | 487 | handheld_entry.pad.r_stick = pad_state.r_stick; |
| 480 | 488 | ||
| 481 | libnx_entry.connection_status.IsWired.Assign(1); | 489 | libnx_entry.connection_status.is_wired.Assign(1); |
| 482 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | 490 | libnx_entry.connection_status.is_left_connected.Assign(1); |
| 483 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | 491 | libnx_entry.connection_status.is_right_connected.Assign(1); |
| 484 | libnx_entry.connection_status.IsLeftJoyWired.Assign(1); | 492 | libnx_entry.connection_status.is_left_wired.Assign(1); |
| 485 | libnx_entry.connection_status.IsRightJoyWired.Assign(1); | 493 | libnx_entry.connection_status.is_right_wired.Assign(1); |
| 486 | break; | 494 | break; |
| 487 | case NPadControllerType::JoyDual: | 495 | case NPadControllerType::JoyDual: |
| 488 | dual_entry.connection_status.raw = 0; | 496 | dual_entry.connection_status.raw = 0; |
| 489 | dual_entry.connection_status.IsConnected.Assign(1); | 497 | dual_entry.connection_status.is_connected.Assign(1); |
| 490 | dual_entry.connection_status.IsLeftJoyConnected.Assign(1); | 498 | dual_entry.connection_status.is_left_connected.Assign(1); |
| 491 | dual_entry.connection_status.IsRightJoyConnected.Assign(1); | 499 | dual_entry.connection_status.is_right_connected.Assign(1); |
| 492 | dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 500 | dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 493 | dual_entry.pad.l_stick = pad_state.l_stick; | 501 | dual_entry.pad.l_stick = pad_state.l_stick; |
| 494 | dual_entry.pad.r_stick = pad_state.r_stick; | 502 | dual_entry.pad.r_stick = pad_state.r_stick; |
| 495 | 503 | ||
| 496 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | 504 | libnx_entry.connection_status.is_left_connected.Assign(1); |
| 497 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | 505 | libnx_entry.connection_status.is_right_connected.Assign(1); |
| 498 | break; | 506 | break; |
| 499 | case NPadControllerType::JoyLeft: | 507 | case NPadControllerType::JoyLeft: |
| 500 | left_entry.connection_status.raw = 0; | 508 | left_entry.connection_status.raw = 0; |
| 501 | left_entry.connection_status.IsConnected.Assign(1); | 509 | left_entry.connection_status.is_connected.Assign(1); |
| 502 | left_entry.connection_status.IsLeftJoyConnected.Assign(1); | 510 | left_entry.connection_status.is_left_connected.Assign(1); |
| 503 | left_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 511 | left_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 504 | left_entry.pad.l_stick = pad_state.l_stick; | 512 | left_entry.pad.l_stick = pad_state.l_stick; |
| 505 | left_entry.pad.r_stick = pad_state.r_stick; | 513 | left_entry.pad.r_stick = pad_state.r_stick; |
| 506 | 514 | ||
| 507 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | 515 | libnx_entry.connection_status.is_left_connected.Assign(1); |
| 508 | break; | 516 | break; |
| 509 | case NPadControllerType::JoyRight: | 517 | case NPadControllerType::JoyRight: |
| 510 | right_entry.connection_status.raw = 0; | 518 | right_entry.connection_status.raw = 0; |
| 511 | right_entry.connection_status.IsConnected.Assign(1); | 519 | right_entry.connection_status.is_connected.Assign(1); |
| 512 | right_entry.connection_status.IsRightJoyConnected.Assign(1); | 520 | right_entry.connection_status.is_right_connected.Assign(1); |
| 513 | right_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 521 | right_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 514 | right_entry.pad.l_stick = pad_state.l_stick; | 522 | right_entry.pad.l_stick = pad_state.l_stick; |
| 515 | right_entry.pad.r_stick = pad_state.r_stick; | 523 | right_entry.pad.r_stick = pad_state.r_stick; |
| 516 | 524 | ||
| 517 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | 525 | libnx_entry.connection_status.is_right_connected.Assign(1); |
| 518 | break; | 526 | break; |
| 519 | case NPadControllerType::Pokeball: | 527 | case NPadControllerType::Pokeball: |
| 520 | pokeball_entry.connection_status.raw = 0; | 528 | pokeball_entry.connection_status.raw = 0; |
| 521 | pokeball_entry.connection_status.IsConnected.Assign(1); | 529 | pokeball_entry.connection_status.is_connected.Assign(1); |
| 522 | pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 530 | pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 523 | pokeball_entry.pad.l_stick = pad_state.l_stick; | 531 | pokeball_entry.pad.l_stick = pad_state.l_stick; |
| 524 | pokeball_entry.pad.r_stick = pad_state.r_stick; | 532 | pokeball_entry.pad.r_stick = pad_state.r_stick; |
| @@ -552,7 +560,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 552 | } | 560 | } |
| 553 | 561 | ||
| 554 | const std::array<SixAxisGeneric*, 6> controller_sixaxes{ | 562 | const std::array<SixAxisGeneric*, 6> controller_sixaxes{ |
| 555 | &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, | 563 | &npad.sixaxis_fullkey, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, |
| 556 | &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, | 564 | &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, |
| 557 | }; | 565 | }; |
| 558 | 566 | ||
| @@ -590,7 +598,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 590 | } | 598 | } |
| 591 | 599 | ||
| 592 | auto& full_sixaxis_entry = | 600 | auto& full_sixaxis_entry = |
| 593 | npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index]; | 601 | npad.sixaxis_fullkey.sixaxis[npad.sixaxis_fullkey.common.last_entry_index]; |
| 594 | auto& handheld_sixaxis_entry = | 602 | auto& handheld_sixaxis_entry = |
| 595 | npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; | 603 | npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; |
| 596 | auto& dual_left_sixaxis_entry = | 604 | auto& dual_left_sixaxis_entry = |
| @@ -607,7 +615,9 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 607 | UNREACHABLE(); | 615 | UNREACHABLE(); |
| 608 | break; | 616 | break; |
| 609 | case NPadControllerType::ProController: | 617 | case NPadControllerType::ProController: |
| 618 | full_sixaxis_entry.attribute.raw = 0; | ||
| 610 | if (sixaxis_sensors_enabled && motions[i][0]) { | 619 | if (sixaxis_sensors_enabled && motions[i][0]) { |
| 620 | full_sixaxis_entry.attribute.is_connected.Assign(1); | ||
| 611 | full_sixaxis_entry.accel = motion_devices[0].accel; | 621 | full_sixaxis_entry.accel = motion_devices[0].accel; |
| 612 | full_sixaxis_entry.gyro = motion_devices[0].gyro; | 622 | full_sixaxis_entry.gyro = motion_devices[0].gyro; |
| 613 | full_sixaxis_entry.rotation = motion_devices[0].rotation; | 623 | full_sixaxis_entry.rotation = motion_devices[0].rotation; |
| @@ -615,7 +625,9 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 615 | } | 625 | } |
| 616 | break; | 626 | break; |
| 617 | case NPadControllerType::Handheld: | 627 | case NPadControllerType::Handheld: |
| 628 | handheld_sixaxis_entry.attribute.raw = 0; | ||
| 618 | if (sixaxis_sensors_enabled && motions[i][0]) { | 629 | if (sixaxis_sensors_enabled && motions[i][0]) { |
| 630 | handheld_sixaxis_entry.attribute.is_connected.Assign(1); | ||
| 619 | handheld_sixaxis_entry.accel = motion_devices[0].accel; | 631 | handheld_sixaxis_entry.accel = motion_devices[0].accel; |
| 620 | handheld_sixaxis_entry.gyro = motion_devices[0].gyro; | 632 | handheld_sixaxis_entry.gyro = motion_devices[0].gyro; |
| 621 | handheld_sixaxis_entry.rotation = motion_devices[0].rotation; | 633 | handheld_sixaxis_entry.rotation = motion_devices[0].rotation; |
| @@ -623,8 +635,11 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 623 | } | 635 | } |
| 624 | break; | 636 | break; |
| 625 | case NPadControllerType::JoyDual: | 637 | case NPadControllerType::JoyDual: |
| 638 | dual_left_sixaxis_entry.attribute.raw = 0; | ||
| 639 | dual_right_sixaxis_entry.attribute.raw = 0; | ||
| 626 | if (sixaxis_sensors_enabled && motions[i][0]) { | 640 | if (sixaxis_sensors_enabled && motions[i][0]) { |
| 627 | // Set motion for the left joycon | 641 | // Set motion for the left joycon |
| 642 | dual_left_sixaxis_entry.attribute.is_connected.Assign(1); | ||
| 628 | dual_left_sixaxis_entry.accel = motion_devices[0].accel; | 643 | dual_left_sixaxis_entry.accel = motion_devices[0].accel; |
| 629 | dual_left_sixaxis_entry.gyro = motion_devices[0].gyro; | 644 | dual_left_sixaxis_entry.gyro = motion_devices[0].gyro; |
| 630 | dual_left_sixaxis_entry.rotation = motion_devices[0].rotation; | 645 | dual_left_sixaxis_entry.rotation = motion_devices[0].rotation; |
| @@ -632,6 +647,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 632 | } | 647 | } |
| 633 | if (sixaxis_sensors_enabled && motions[i][1]) { | 648 | if (sixaxis_sensors_enabled && motions[i][1]) { |
| 634 | // Set motion for the right joycon | 649 | // Set motion for the right joycon |
| 650 | dual_right_sixaxis_entry.attribute.is_connected.Assign(1); | ||
| 635 | dual_right_sixaxis_entry.accel = motion_devices[1].accel; | 651 | dual_right_sixaxis_entry.accel = motion_devices[1].accel; |
| 636 | dual_right_sixaxis_entry.gyro = motion_devices[1].gyro; | 652 | dual_right_sixaxis_entry.gyro = motion_devices[1].gyro; |
| 637 | dual_right_sixaxis_entry.rotation = motion_devices[1].rotation; | 653 | dual_right_sixaxis_entry.rotation = motion_devices[1].rotation; |
| @@ -639,7 +655,9 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 639 | } | 655 | } |
| 640 | break; | 656 | break; |
| 641 | case NPadControllerType::JoyLeft: | 657 | case NPadControllerType::JoyLeft: |
| 658 | left_sixaxis_entry.attribute.raw = 0; | ||
| 642 | if (sixaxis_sensors_enabled && motions[i][0]) { | 659 | if (sixaxis_sensors_enabled && motions[i][0]) { |
| 660 | left_sixaxis_entry.attribute.is_connected.Assign(1); | ||
| 643 | left_sixaxis_entry.accel = motion_devices[0].accel; | 661 | left_sixaxis_entry.accel = motion_devices[0].accel; |
| 644 | left_sixaxis_entry.gyro = motion_devices[0].gyro; | 662 | left_sixaxis_entry.gyro = motion_devices[0].gyro; |
| 645 | left_sixaxis_entry.rotation = motion_devices[0].rotation; | 663 | left_sixaxis_entry.rotation = motion_devices[0].rotation; |
| @@ -647,7 +665,9 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 647 | } | 665 | } |
| 648 | break; | 666 | break; |
| 649 | case NPadControllerType::JoyRight: | 667 | case NPadControllerType::JoyRight: |
| 668 | right_sixaxis_entry.attribute.raw = 0; | ||
| 650 | if (sixaxis_sensors_enabled && motions[i][1]) { | 669 | if (sixaxis_sensors_enabled && motions[i][1]) { |
| 670 | right_sixaxis_entry.attribute.is_connected.Assign(1); | ||
| 651 | right_sixaxis_entry.accel = motion_devices[1].accel; | 671 | right_sixaxis_entry.accel = motion_devices[1].accel; |
| 652 | right_sixaxis_entry.gyro = motion_devices[1].gyro; | 672 | right_sixaxis_entry.gyro = motion_devices[1].gyro; |
| 653 | right_sixaxis_entry.rotation = motion_devices[1].rotation; | 673 | right_sixaxis_entry.rotation = motion_devices[1].rotation; |
| @@ -713,8 +733,8 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode | |||
| 713 | void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) { | 733 | void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) { |
| 714 | const std::size_t npad_index = NPadIdToIndex(npad_id); | 734 | const std::size_t npad_index = NPadIdToIndex(npad_id); |
| 715 | ASSERT(npad_index < shared_memory_entries.size()); | 735 | ASSERT(npad_index < shared_memory_entries.size()); |
| 716 | if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { | 736 | if (shared_memory_entries[npad_index].assignment_mode != assignment_mode) { |
| 717 | shared_memory_entries[npad_index].pad_assignment = assignment_mode; | 737 | shared_memory_entries[npad_index].assignment_mode = assignment_mode; |
| 718 | } | 738 | } |
| 719 | } | 739 | } |
| 720 | 740 | ||
| @@ -732,7 +752,7 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size | |||
| 732 | // Send an empty vibration to stop any vibrations. | 752 | // Send an empty vibration to stop any vibrations. |
| 733 | vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f); | 753 | vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f); |
| 734 | // Then reset the vibration value to its default value. | 754 | // Then reset the vibration value to its default value. |
| 735 | latest_vibration_values[npad_index][device_index] = {}; | 755 | latest_vibration_values[npad_index][device_index] = DEFAULT_VIBRATION_VALUE; |
| 736 | } | 756 | } |
| 737 | 757 | ||
| 738 | return false; | 758 | return false; |
| @@ -870,13 +890,14 @@ bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_dev | |||
| 870 | return vibration_devices_mounted[npad_index][device_index]; | 890 | return vibration_devices_mounted[npad_index][device_index]; |
| 871 | } | 891 | } |
| 872 | 892 | ||
| 873 | std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { | 893 | std::shared_ptr<Kernel::KReadableEvent> Controller_NPad::GetStyleSetChangedEvent( |
| 894 | u32 npad_id) const { | ||
| 874 | const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; | 895 | const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; |
| 875 | return styleset_event.readable; | 896 | return styleset_event->GetReadableEvent(); |
| 876 | } | 897 | } |
| 877 | 898 | ||
| 878 | void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { | 899 | void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { |
| 879 | styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal(); | 900 | styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent()->Signal(); |
| 880 | } | 901 | } |
| 881 | 902 | ||
| 882 | void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { | 903 | void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { |
| @@ -890,7 +911,7 @@ void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::siz | |||
| 890 | return; | 911 | return; |
| 891 | } | 912 | } |
| 892 | 913 | ||
| 893 | if (controller == NPadControllerType::Handheld) { | 914 | if (controller == NPadControllerType::Handheld && npad_index == HANDHELD_INDEX) { |
| 894 | Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type = | 915 | Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type = |
| 895 | MapNPadToSettingsType(controller); | 916 | MapNPadToSettingsType(controller); |
| 896 | Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; | 917 | Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; |
| @@ -921,9 +942,17 @@ void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { | |||
| 921 | connected_controllers[npad_index].is_connected = false; | 942 | connected_controllers[npad_index].is_connected = false; |
| 922 | 943 | ||
| 923 | auto& controller = shared_memory_entries[npad_index]; | 944 | auto& controller = shared_memory_entries[npad_index]; |
| 924 | controller.joy_styles.raw = 0; // Zero out | 945 | controller.style_set.raw = 0; // Zero out |
| 925 | controller.device_type.raw = 0; | 946 | controller.device_type.raw = 0; |
| 926 | controller.properties.raw = 0; | 947 | controller.system_properties.raw = 0; |
| 948 | controller.button_properties.raw = 0; | ||
| 949 | controller.battery_level_dual = 0; | ||
| 950 | controller.battery_level_left = 0; | ||
| 951 | controller.battery_level_right = 0; | ||
| 952 | controller.fullkey_color = {}; | ||
| 953 | controller.joycon_color = {}; | ||
| 954 | controller.assignment_mode = NpadAssignments::Dual; | ||
| 955 | controller.footer_type = AppletFooterUiType::None; | ||
| 927 | 956 | ||
| 928 | SignalStyleSetChangedEvent(IndexToNPad(npad_index)); | 957 | SignalStyleSetChangedEvent(IndexToNPad(npad_index)); |
| 929 | } | 958 | } |
| @@ -944,6 +973,23 @@ void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) { | |||
| 944 | sixaxis_sensors_enabled = six_axis_status; | 973 | sixaxis_sensors_enabled = six_axis_status; |
| 945 | } | 974 | } |
| 946 | 975 | ||
| 976 | void Controller_NPad::SetSixAxisFusionParameters(f32 parameter1, f32 parameter2) { | ||
| 977 | sixaxis_fusion_parameter1 = parameter1; | ||
| 978 | sixaxis_fusion_parameter2 = parameter2; | ||
| 979 | } | ||
| 980 | |||
| 981 | std::pair<f32, f32> Controller_NPad::GetSixAxisFusionParameters() { | ||
| 982 | return { | ||
| 983 | sixaxis_fusion_parameter1, | ||
| 984 | sixaxis_fusion_parameter2, | ||
| 985 | }; | ||
| 986 | } | ||
| 987 | |||
| 988 | void Controller_NPad::ResetSixAxisFusionParameters() { | ||
| 989 | sixaxis_fusion_parameter1 = 0.0f; | ||
| 990 | sixaxis_fusion_parameter2 = 0.0f; | ||
| 991 | } | ||
| 992 | |||
| 947 | void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { | 993 | void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { |
| 948 | const auto npad_index_1 = NPadIdToIndex(npad_id_1); | 994 | const auto npad_index_1 = NPadIdToIndex(npad_id_1); |
| 949 | const auto npad_index_2 = NPadIdToIndex(npad_id_2); | 995 | const auto npad_index_2 = NPadIdToIndex(npad_id_2); |
| @@ -1082,7 +1128,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const | |||
| 1082 | [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) { | 1128 | [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) { |
| 1083 | switch (controller) { | 1129 | switch (controller) { |
| 1084 | case NPadControllerType::ProController: | 1130 | case NPadControllerType::ProController: |
| 1085 | return style.pro_controller; | 1131 | return style.fullkey; |
| 1086 | case NPadControllerType::JoyDual: | 1132 | case NPadControllerType::JoyDual: |
| 1087 | return style.joycon_dual; | 1133 | return style.joycon_dual; |
| 1088 | case NPadControllerType::JoyLeft: | 1134 | case NPadControllerType::JoyLeft: |
| @@ -1090,7 +1136,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const | |||
| 1090 | case NPadControllerType::JoyRight: | 1136 | case NPadControllerType::JoyRight: |
| 1091 | return style.joycon_right; | 1137 | return style.joycon_right; |
| 1092 | case NPadControllerType::Pokeball: | 1138 | case NPadControllerType::Pokeball: |
| 1093 | return style.pokeball; | 1139 | return style.palma; |
| 1094 | default: | 1140 | default: |
| 1095 | return false; | 1141 | return false; |
| 1096 | } | 1142 | } |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index e2e826623..48bab988c 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -10,10 +10,14 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/frontend/input.h" | 11 | #include "core/frontend/input.h" |
| 12 | #include "core/hle/kernel/object.h" | 12 | #include "core/hle/kernel/object.h" |
| 13 | #include "core/hle/kernel/writable_event.h" | ||
| 14 | #include "core/hle/service/hid/controllers/controller_base.h" | 13 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 15 | #include "core/settings.h" | 14 | #include "core/settings.h" |
| 16 | 15 | ||
| 16 | namespace Kernel { | ||
| 17 | class KEvent; | ||
| 18 | class KReadableEvent; | ||
| 19 | } // namespace Kernel | ||
| 20 | |||
| 17 | namespace Service::HID { | 21 | namespace Service::HID { |
| 18 | 22 | ||
| 19 | constexpr u32 NPAD_HANDHELD = 32; | 23 | constexpr u32 NPAD_HANDHELD = 32; |
| @@ -90,17 +94,17 @@ public: | |||
| 90 | }; | 94 | }; |
| 91 | 95 | ||
| 92 | enum class NpadCommunicationMode : u64 { | 96 | enum class NpadCommunicationMode : u64 { |
| 93 | Unknown0 = 0, | 97 | Mode_5ms = 0, |
| 94 | Unknown1 = 1, | 98 | Mode_10ms = 1, |
| 95 | Unknown2 = 2, | 99 | Mode_15ms = 2, |
| 96 | Unknown3 = 3, | 100 | Default = 3, |
| 97 | }; | 101 | }; |
| 98 | 102 | ||
| 99 | struct DeviceHandle { | 103 | struct DeviceHandle { |
| 100 | NpadType npad_type{}; | 104 | NpadType npad_type; |
| 101 | u8 npad_id{}; | 105 | u8 npad_id; |
| 102 | DeviceIndex device_index{}; | 106 | DeviceIndex device_index; |
| 103 | INSERT_PADDING_BYTES(1); | 107 | INSERT_PADDING_BYTES_NOINIT(1); |
| 104 | }; | 108 | }; |
| 105 | static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size"); | 109 | static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size"); |
| 106 | 110 | ||
| @@ -108,25 +112,37 @@ public: | |||
| 108 | union { | 112 | union { |
| 109 | u32_le raw{}; | 113 | u32_le raw{}; |
| 110 | 114 | ||
| 111 | BitField<0, 1, u32> pro_controller; | 115 | BitField<0, 1, u32> fullkey; |
| 112 | BitField<1, 1, u32> handheld; | 116 | BitField<1, 1, u32> handheld; |
| 113 | BitField<2, 1, u32> joycon_dual; | 117 | BitField<2, 1, u32> joycon_dual; |
| 114 | BitField<3, 1, u32> joycon_left; | 118 | BitField<3, 1, u32> joycon_left; |
| 115 | BitField<4, 1, u32> joycon_right; | 119 | BitField<4, 1, u32> joycon_right; |
| 116 | 120 | BitField<5, 1, u32> gamecube; | |
| 117 | BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible | 121 | BitField<6, 1, u32> palma; |
| 122 | BitField<7, 1, u32> lark; | ||
| 123 | BitField<8, 1, u32> handheld_lark; | ||
| 124 | BitField<9, 1, u32> lucia; | ||
| 125 | BitField<29, 1, u32> system_ext; | ||
| 126 | BitField<30, 1, u32> system; | ||
| 118 | }; | 127 | }; |
| 119 | }; | 128 | }; |
| 120 | static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); | 129 | static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); |
| 121 | 130 | ||
| 122 | struct VibrationValue { | 131 | struct VibrationValue { |
| 123 | f32 amp_low{0.0f}; | 132 | f32 amp_low; |
| 124 | f32 freq_low{160.0f}; | 133 | f32 freq_low; |
| 125 | f32 amp_high{0.0f}; | 134 | f32 amp_high; |
| 126 | f32 freq_high{320.0f}; | 135 | f32 freq_high; |
| 127 | }; | 136 | }; |
| 128 | static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size"); | 137 | static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size"); |
| 129 | 138 | ||
| 139 | static constexpr VibrationValue DEFAULT_VIBRATION_VALUE{ | ||
| 140 | .amp_low = 0.0f, | ||
| 141 | .freq_low = 160.0f, | ||
| 142 | .amp_high = 0.0f, | ||
| 143 | .freq_high = 320.0f, | ||
| 144 | }; | ||
| 145 | |||
| 130 | struct LedPattern { | 146 | struct LedPattern { |
| 131 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { | 147 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { |
| 132 | position1.Assign(light1); | 148 | position1.Assign(light1); |
| @@ -180,7 +196,7 @@ public: | |||
| 180 | 196 | ||
| 181 | bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; | 197 | bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; |
| 182 | 198 | ||
| 183 | std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; | 199 | std::shared_ptr<Kernel::KReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; |
| 184 | void SignalStyleSetChangedEvent(u32 npad_id) const; | 200 | void SignalStyleSetChangedEvent(u32 npad_id) const; |
| 185 | 201 | ||
| 186 | // Adds a new controller at an index. | 202 | // Adds a new controller at an index. |
| @@ -195,6 +211,9 @@ public: | |||
| 195 | GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; | 211 | GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; |
| 196 | bool IsSixAxisSensorAtRest() const; | 212 | bool IsSixAxisSensorAtRest() const; |
| 197 | void SetSixAxisEnabled(bool six_axis_status); | 213 | void SetSixAxisEnabled(bool six_axis_status); |
| 214 | void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); | ||
| 215 | std::pair<f32, f32> GetSixAxisFusionParameters(); | ||
| 216 | void ResetSixAxisFusionParameters(); | ||
| 198 | LedPattern GetLedPattern(u32 npad_id); | 217 | LedPattern GetLedPattern(u32 npad_id); |
| 199 | bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; | 218 | bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; |
| 200 | void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); | 219 | void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); |
| @@ -228,12 +247,32 @@ private: | |||
| 228 | }; | 247 | }; |
| 229 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); | 248 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); |
| 230 | 249 | ||
| 250 | enum class ColorAttributes : u32_le { | ||
| 251 | Ok = 0, | ||
| 252 | ReadError = 1, | ||
| 253 | NoController = 2, | ||
| 254 | }; | ||
| 255 | static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size"); | ||
| 256 | |||
| 231 | struct ControllerColor { | 257 | struct ControllerColor { |
| 232 | u32_le body_color; | 258 | u32_le body; |
| 233 | u32_le button_color; | 259 | u32_le button; |
| 234 | }; | 260 | }; |
| 235 | static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); | 261 | static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); |
| 236 | 262 | ||
| 263 | struct FullKeyColor { | ||
| 264 | ColorAttributes attribute; | ||
| 265 | ControllerColor fullkey; | ||
| 266 | }; | ||
| 267 | static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size"); | ||
| 268 | |||
| 269 | struct JoyconColor { | ||
| 270 | ColorAttributes attribute; | ||
| 271 | ControllerColor left; | ||
| 272 | ControllerColor right; | ||
| 273 | }; | ||
| 274 | static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor is an invalid size"); | ||
| 275 | |||
| 237 | struct ControllerPadState { | 276 | struct ControllerPadState { |
| 238 | union { | 277 | union { |
| 239 | u64_le raw{}; | 278 | u64_le raw{}; |
| @@ -275,6 +314,9 @@ private: | |||
| 275 | 314 | ||
| 276 | BitField<26, 1, u64> right_sl; | 315 | BitField<26, 1, u64> right_sl; |
| 277 | BitField<27, 1, u64> right_sr; | 316 | BitField<27, 1, u64> right_sr; |
| 317 | |||
| 318 | BitField<28, 1, u64> palma; | ||
| 319 | BitField<30, 1, u64> handheld_left_b; | ||
| 278 | }; | 320 | }; |
| 279 | }; | 321 | }; |
| 280 | static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); | 322 | static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); |
| @@ -288,12 +330,12 @@ private: | |||
| 288 | struct ConnectionState { | 330 | struct ConnectionState { |
| 289 | union { | 331 | union { |
| 290 | u32_le raw{}; | 332 | u32_le raw{}; |
| 291 | BitField<0, 1, u32> IsConnected; | 333 | BitField<0, 1, u32> is_connected; |
| 292 | BitField<1, 1, u32> IsWired; | 334 | BitField<1, 1, u32> is_wired; |
| 293 | BitField<2, 1, u32> IsLeftJoyConnected; | 335 | BitField<2, 1, u32> is_left_connected; |
| 294 | BitField<3, 1, u32> IsLeftJoyWired; | 336 | BitField<3, 1, u32> is_left_wired; |
| 295 | BitField<4, 1, u32> IsRightJoyConnected; | 337 | BitField<4, 1, u32> is_right_connected; |
| 296 | BitField<5, 1, u32> IsRightJoyWired; | 338 | BitField<5, 1, u32> is_right_wired; |
| 297 | }; | 339 | }; |
| 298 | }; | 340 | }; |
| 299 | static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); | 341 | static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); |
| @@ -319,6 +361,15 @@ private: | |||
| 319 | }; | 361 | }; |
| 320 | static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); | 362 | static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); |
| 321 | 363 | ||
| 364 | struct SixAxisAttributes { | ||
| 365 | union { | ||
| 366 | u32_le raw{}; | ||
| 367 | BitField<0, 1, u32> is_connected; | ||
| 368 | BitField<1, 1, u32> is_interpolated; | ||
| 369 | }; | ||
| 370 | }; | ||
| 371 | static_assert(sizeof(SixAxisAttributes) == 4, "SixAxisAttributes is an invalid size"); | ||
| 372 | |||
| 322 | struct SixAxisStates { | 373 | struct SixAxisStates { |
| 323 | s64_le timestamp{}; | 374 | s64_le timestamp{}; |
| 324 | INSERT_PADDING_WORDS(2); | 375 | INSERT_PADDING_WORDS(2); |
| @@ -327,7 +378,8 @@ private: | |||
| 327 | Common::Vec3f gyro{}; | 378 | Common::Vec3f gyro{}; |
| 328 | Common::Vec3f rotation{}; | 379 | Common::Vec3f rotation{}; |
| 329 | std::array<Common::Vec3f, 3> orientation{}; | 380 | std::array<Common::Vec3f, 3> orientation{}; |
| 330 | s64_le always_one{1}; | 381 | SixAxisAttributes attribute; |
| 382 | INSERT_PADDING_BYTES(4); // Reserved | ||
| 331 | }; | 383 | }; |
| 332 | static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); | 384 | static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); |
| 333 | 385 | ||
| @@ -337,32 +389,54 @@ private: | |||
| 337 | }; | 389 | }; |
| 338 | static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); | 390 | static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); |
| 339 | 391 | ||
| 340 | enum class ColorReadError : u32_le { | 392 | struct NPadSystemProperties { |
| 341 | ReadOk = 0, | ||
| 342 | ColorDoesntExist = 1, | ||
| 343 | NoController = 2, | ||
| 344 | }; | ||
| 345 | |||
| 346 | struct NPadProperties { | ||
| 347 | union { | 393 | union { |
| 348 | s64_le raw{}; | 394 | s64_le raw{}; |
| 395 | BitField<0, 1, s64> is_charging_joy_dual; | ||
| 396 | BitField<1, 1, s64> is_charging_joy_left; | ||
| 397 | BitField<2, 1, s64> is_charging_joy_right; | ||
| 398 | BitField<3, 1, s64> is_powered_joy_dual; | ||
| 399 | BitField<4, 1, s64> is_powered_joy_left; | ||
| 400 | BitField<5, 1, s64> is_powered_joy_right; | ||
| 401 | BitField<9, 1, s64> is_system_unsupported_button; | ||
| 402 | BitField<10, 1, s64> is_system_ext_unsupported_button; | ||
| 349 | BitField<11, 1, s64> is_vertical; | 403 | BitField<11, 1, s64> is_vertical; |
| 350 | BitField<12, 1, s64> is_horizontal; | 404 | BitField<12, 1, s64> is_horizontal; |
| 351 | BitField<13, 1, s64> use_plus; | 405 | BitField<13, 1, s64> use_plus; |
| 352 | BitField<14, 1, s64> use_minus; | 406 | BitField<14, 1, s64> use_minus; |
| 407 | BitField<15, 1, s64> use_directional_buttons; | ||
| 353 | }; | 408 | }; |
| 354 | }; | 409 | }; |
| 410 | static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); | ||
| 411 | |||
| 412 | struct NPadButtonProperties { | ||
| 413 | union { | ||
| 414 | s32_le raw{}; | ||
| 415 | BitField<0, 1, s32> is_home_button_protection_enabled; | ||
| 416 | }; | ||
| 417 | }; | ||
| 418 | static_assert(sizeof(NPadButtonProperties) == 0x4, "NPadButtonProperties is an invalid size"); | ||
| 355 | 419 | ||
| 356 | struct NPadDevice { | 420 | struct NPadDevice { |
| 357 | union { | 421 | union { |
| 358 | u32_le raw{}; | 422 | u32_le raw{}; |
| 359 | BitField<0, 1, s32> pro_controller; | 423 | BitField<0, 1, s32> fullkey; |
| 360 | BitField<1, 1, s32> handheld; | 424 | BitField<1, 1, s32> debug_pad; |
| 361 | BitField<2, 1, s32> handheld_left; | 425 | BitField<2, 1, s32> handheld_left; |
| 362 | BitField<3, 1, s32> handheld_right; | 426 | BitField<3, 1, s32> handheld_right; |
| 363 | BitField<4, 1, s32> joycon_left; | 427 | BitField<4, 1, s32> joycon_left; |
| 364 | BitField<5, 1, s32> joycon_right; | 428 | BitField<5, 1, s32> joycon_right; |
| 365 | BitField<6, 1, s32> pokeball; | 429 | BitField<6, 1, s32> palma; |
| 430 | BitField<7, 1, s32> lark_hvc_left; | ||
| 431 | BitField<8, 1, s32> lark_hvc_right; | ||
| 432 | BitField<9, 1, s32> lark_nes_left; | ||
| 433 | BitField<10, 1, s32> lark_nes_right; | ||
| 434 | BitField<11, 1, s32> handheld_lark_hvc_left; | ||
| 435 | BitField<12, 1, s32> handheld_lark_hvc_right; | ||
| 436 | BitField<13, 1, s32> handheld_lark_nes_left; | ||
| 437 | BitField<14, 1, s32> handheld_lark_nes_right; | ||
| 438 | BitField<15, 1, s32> lucia; | ||
| 439 | BitField<31, 1, s32> system; | ||
| 366 | }; | 440 | }; |
| 367 | }; | 441 | }; |
| 368 | 442 | ||
| @@ -373,37 +447,69 @@ private: | |||
| 373 | std::array<Common::Vec3f, 3> orientation; | 447 | std::array<Common::Vec3f, 3> orientation; |
| 374 | }; | 448 | }; |
| 375 | 449 | ||
| 376 | struct NPadEntry { | 450 | struct NfcXcdHandle { |
| 377 | NpadStyleSet joy_styles; | 451 | INSERT_PADDING_BYTES(0x60); |
| 378 | NpadAssignments pad_assignment; | 452 | }; |
| 379 | 453 | ||
| 380 | ColorReadError single_color_error; | 454 | struct AppletFooterUiAttributes { |
| 381 | ControllerColor single_color; | 455 | INSERT_PADDING_BYTES(0x4); |
| 456 | }; | ||
| 382 | 457 | ||
| 383 | ColorReadError dual_color_error; | 458 | enum class AppletFooterUiType : u8 { |
| 384 | ControllerColor left_color; | 459 | None = 0, |
| 385 | ControllerColor right_color; | 460 | HandheldNone = 1, |
| 461 | HandheldJoyConLeftOnly = 1, | ||
| 462 | HandheldJoyConRightOnly = 3, | ||
| 463 | HandheldJoyConLeftJoyConRight = 4, | ||
| 464 | JoyDual = 5, | ||
| 465 | JoyDualLeftOnly = 6, | ||
| 466 | JoyDualRightOnly = 7, | ||
| 467 | JoyLeftHorizontal = 8, | ||
| 468 | JoyLeftVertical = 9, | ||
| 469 | JoyRightHorizontal = 10, | ||
| 470 | JoyRightVertical = 11, | ||
| 471 | SwitchProController = 12, | ||
| 472 | CompatibleProController = 13, | ||
| 473 | CompatibleJoyCon = 14, | ||
| 474 | LarkHvc1 = 15, | ||
| 475 | LarkHvc2 = 16, | ||
| 476 | LarkNesLeft = 17, | ||
| 477 | LarkNesRight = 18, | ||
| 478 | Lucia = 19, | ||
| 479 | Verification = 20, | ||
| 480 | }; | ||
| 481 | |||
| 482 | struct NPadEntry { | ||
| 483 | NpadStyleSet style_set; | ||
| 484 | NpadAssignments assignment_mode; | ||
| 485 | FullKeyColor fullkey_color; | ||
| 486 | JoyconColor joycon_color; | ||
| 386 | 487 | ||
| 387 | NPadGeneric main_controller_states; | 488 | NPadGeneric fullkey_states; |
| 388 | NPadGeneric handheld_states; | 489 | NPadGeneric handheld_states; |
| 389 | NPadGeneric dual_states; | 490 | NPadGeneric joy_dual_states; |
| 390 | NPadGeneric left_joy_states; | 491 | NPadGeneric joy_left_states; |
| 391 | NPadGeneric right_joy_states; | 492 | NPadGeneric joy_right_states; |
| 392 | NPadGeneric pokeball_states; | 493 | NPadGeneric palma_states; |
| 393 | NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be | 494 | NPadGeneric system_ext_states; |
| 394 | // relying on this for the time being | 495 | SixAxisGeneric sixaxis_fullkey; |
| 395 | SixAxisGeneric sixaxis_full; | ||
| 396 | SixAxisGeneric sixaxis_handheld; | 496 | SixAxisGeneric sixaxis_handheld; |
| 397 | SixAxisGeneric sixaxis_dual_left; | 497 | SixAxisGeneric sixaxis_dual_left; |
| 398 | SixAxisGeneric sixaxis_dual_right; | 498 | SixAxisGeneric sixaxis_dual_right; |
| 399 | SixAxisGeneric sixaxis_left; | 499 | SixAxisGeneric sixaxis_left; |
| 400 | SixAxisGeneric sixaxis_right; | 500 | SixAxisGeneric sixaxis_right; |
| 401 | NPadDevice device_type; | 501 | NPadDevice device_type; |
| 402 | NPadProperties properties; | 502 | INSERT_PADDING_BYTES(0x4); // reserved |
| 403 | INSERT_PADDING_WORDS(1); | 503 | NPadSystemProperties system_properties; |
| 404 | std::array<u32, 3> battery_level; | 504 | NPadButtonProperties button_properties; |
| 405 | INSERT_PADDING_BYTES(0x5c); | 505 | u32 battery_level_dual; |
| 406 | INSERT_PADDING_BYTES(0xdf8); | 506 | u32 battery_level_left; |
| 507 | u32 battery_level_right; | ||
| 508 | AppletFooterUiAttributes footer_attributes; | ||
| 509 | AppletFooterUiType footer_type; | ||
| 510 | // nfc_states needs to be checked switchbrew does not match with HW | ||
| 511 | NfcXcdHandle nfc_states; | ||
| 512 | INSERT_PADDING_BYTES(0xdef); | ||
| 407 | }; | 513 | }; |
| 408 | static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); | 514 | static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); |
| 409 | 515 | ||
| @@ -439,10 +545,9 @@ private: | |||
| 439 | std::vector<u32> supported_npad_id_types{}; | 545 | std::vector<u32> supported_npad_id_types{}; |
| 440 | NpadHoldType hold_type{NpadHoldType::Vertical}; | 546 | NpadHoldType hold_type{NpadHoldType::Vertical}; |
| 441 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; | 547 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; |
| 442 | // NpadCommunicationMode is unknown, default value is 1 | 548 | NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; |
| 443 | NpadCommunicationMode communication_mode{NpadCommunicationMode::Unknown1}; | ||
| 444 | // Each controller should have their own styleset changed event | 549 | // Each controller should have their own styleset changed event |
| 445 | std::array<Kernel::EventPair, 10> styleset_changed_events; | 550 | std::array<std::shared_ptr<Kernel::KEvent>, 10> styleset_changed_events; |
| 446 | std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints; | 551 | std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints; |
| 447 | std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; | 552 | std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; |
| 448 | bool permit_vibration_session_enabled{false}; | 553 | bool permit_vibration_session_enabled{false}; |
| @@ -451,6 +556,8 @@ private: | |||
| 451 | std::array<bool, 10> unintended_home_button_input_protection{}; | 556 | std::array<bool, 10> unintended_home_button_input_protection{}; |
| 452 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; | 557 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; |
| 453 | bool sixaxis_sensors_enabled{true}; | 558 | bool sixaxis_sensors_enabled{true}; |
| 559 | f32 sixaxis_fusion_parameter1{}; | ||
| 560 | f32 sixaxis_fusion_parameter2{}; | ||
| 454 | bool sixaxis_at_rest{true}; | 561 | bool sixaxis_at_rest{true}; |
| 455 | std::array<ControllerPad, 10> npad_pad_states{}; | 562 | std::array<ControllerPad, 10> npad_pad_states{}; |
| 456 | bool is_in_lr_assignment_mode{false}; | 563 | bool is_in_lr_assignment_mode{false}; |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 0df395e85..5219f2dad 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 5 | #include <cstring> | 6 | #include <cstring> |
| 6 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| @@ -16,7 +17,13 @@ constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | |||
| 16 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} | 17 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} |
| 17 | Controller_Touchscreen::~Controller_Touchscreen() = default; | 18 | Controller_Touchscreen::~Controller_Touchscreen() = default; |
| 18 | 19 | ||
| 19 | void Controller_Touchscreen::OnInit() {} | 20 | void Controller_Touchscreen::OnInit() { |
| 21 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | ||
| 22 | mouse_finger_id[id] = MAX_FINGERS; | ||
| 23 | keyboard_finger_id[id] = MAX_FINGERS; | ||
| 24 | udp_finger_id[id] = MAX_FINGERS; | ||
| 25 | } | ||
| 26 | } | ||
| 20 | 27 | ||
| 21 | void Controller_Touchscreen::OnRelease() {} | 28 | void Controller_Touchscreen::OnRelease() {} |
| 22 | 29 | ||
| @@ -40,38 +47,106 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | |||
| 40 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 47 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 41 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 48 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 42 | 49 | ||
| 43 | bool pressed = false; | 50 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); |
| 44 | float x, y; | 51 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); |
| 45 | std::tie(x, y, pressed) = touch_device->GetStatus(); | 52 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { |
| 46 | auto& touch_entry = cur_entry.states[0]; | 53 | mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); |
| 47 | touch_entry.attribute.raw = 0; | 54 | udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); |
| 48 | if (!pressed && touch_btn_device) { | ||
| 49 | std::tie(x, y, pressed) = touch_btn_device->GetStatus(); | ||
| 50 | } | 55 | } |
| 51 | if (pressed && Settings::values.touchscreen.enabled) { | 56 | |
| 52 | touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); | 57 | if (Settings::values.use_touch_from_button) { |
| 53 | touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); | 58 | const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); |
| 54 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; | 59 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { |
| 55 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; | 60 | keyboard_finger_id[id] = |
| 56 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; | 61 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); |
| 57 | const u64 tick = core_timing.GetCPUTicks(); | 62 | } |
| 58 | touch_entry.delta_time = tick - last_touch; | ||
| 59 | last_touch = tick; | ||
| 60 | touch_entry.finger = Settings::values.touchscreen.finger; | ||
| 61 | cur_entry.entry_count = 1; | ||
| 62 | } else { | ||
| 63 | cur_entry.entry_count = 0; | ||
| 64 | } | 63 | } |
| 65 | 64 | ||
| 65 | std::array<Finger, 16> active_fingers; | ||
| 66 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), | ||
| 67 | [](const auto& finger) { return finger.pressed; }); | ||
| 68 | const auto active_fingers_count = | ||
| 69 | static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); | ||
| 70 | |||
| 71 | const u64 tick = core_timing.GetCPUTicks(); | ||
| 72 | cur_entry.entry_count = static_cast<s32_le>(active_fingers_count); | ||
| 73 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | ||
| 74 | auto& touch_entry = cur_entry.states[id]; | ||
| 75 | if (id < active_fingers_count) { | ||
| 76 | touch_entry.x = static_cast<u16>(active_fingers[id].x * Layout::ScreenUndocked::Width); | ||
| 77 | touch_entry.y = static_cast<u16>(active_fingers[id].y * Layout::ScreenUndocked::Height); | ||
| 78 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; | ||
| 79 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; | ||
| 80 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; | ||
| 81 | touch_entry.delta_time = tick - active_fingers[id].last_touch; | ||
| 82 | fingers[active_fingers[id].id].last_touch = tick; | ||
| 83 | touch_entry.finger = active_fingers[id].id; | ||
| 84 | touch_entry.attribute.raw = active_fingers[id].attribute.raw; | ||
| 85 | } else { | ||
| 86 | // Clear touch entry | ||
| 87 | touch_entry.attribute.raw = 0; | ||
| 88 | touch_entry.x = 0; | ||
| 89 | touch_entry.y = 0; | ||
| 90 | touch_entry.diameter_x = 0; | ||
| 91 | touch_entry.diameter_y = 0; | ||
| 92 | touch_entry.rotation_angle = 0; | ||
| 93 | touch_entry.delta_time = 0; | ||
| 94 | touch_entry.finger = 0; | ||
| 95 | } | ||
| 96 | } | ||
| 66 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); | 97 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); |
| 67 | } | 98 | } |
| 68 | 99 | ||
| 69 | void Controller_Touchscreen::OnLoadInputDevices() { | 100 | void Controller_Touchscreen::OnLoadInputDevices() { |
| 70 | touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device); | 101 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); |
| 71 | if (Settings::values.use_touch_from_button) { | 102 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); |
| 72 | touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); | 103 | touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); |
| 73 | } else { | 104 | } |
| 74 | touch_btn_device.reset(); | 105 | |
| 106 | std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const { | ||
| 107 | std::size_t first_free_id = 0; | ||
| 108 | while (first_free_id < MAX_FINGERS) { | ||
| 109 | if (!fingers[first_free_id].pressed) { | ||
| 110 | return first_free_id; | ||
| 111 | } else { | ||
| 112 | first_free_id++; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | return std::nullopt; | ||
| 116 | } | ||
| 117 | |||
| 118 | std::size_t Controller_Touchscreen::UpdateTouchInputEvent( | ||
| 119 | const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { | ||
| 120 | const auto& [x, y, pressed] = touch_input; | ||
| 121 | if (pressed) { | ||
| 122 | Attributes attribute{}; | ||
| 123 | if (finger_id == MAX_FINGERS) { | ||
| 124 | const auto first_free_id = GetUnusedFingerID(); | ||
| 125 | if (!first_free_id) { | ||
| 126 | // Invalid finger id do nothing | ||
| 127 | return MAX_FINGERS; | ||
| 128 | } | ||
| 129 | finger_id = first_free_id.value(); | ||
| 130 | fingers[finger_id].pressed = true; | ||
| 131 | fingers[finger_id].id = static_cast<u32_le>(finger_id); | ||
| 132 | attribute.start_touch.Assign(1); | ||
| 133 | } | ||
| 134 | fingers[finger_id].x = x; | ||
| 135 | fingers[finger_id].y = y; | ||
| 136 | fingers[finger_id].attribute = attribute; | ||
| 137 | return finger_id; | ||
| 75 | } | 138 | } |
| 139 | |||
| 140 | if (finger_id != MAX_FINGERS) { | ||
| 141 | if (!fingers[finger_id].attribute.end_touch) { | ||
| 142 | fingers[finger_id].attribute.end_touch.Assign(1); | ||
| 143 | fingers[finger_id].attribute.start_touch.Assign(0); | ||
| 144 | return finger_id; | ||
| 145 | } | ||
| 146 | fingers[finger_id].pressed = false; | ||
| 147 | } | ||
| 148 | |||
| 149 | return MAX_FINGERS; | ||
| 76 | } | 150 | } |
| 151 | |||
| 77 | } // namespace Service::HID | 152 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 4d9042adc..784124e25 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -30,6 +30,18 @@ public: | |||
| 30 | void OnLoadInputDevices() override; | 30 | void OnLoadInputDevices() override; |
| 31 | 31 | ||
| 32 | private: | 32 | private: |
| 33 | static constexpr std::size_t MAX_FINGERS = 16; | ||
| 34 | |||
| 35 | // Returns an unused finger id, if there is no fingers available std::nullopt will be returned | ||
| 36 | std::optional<std::size_t> GetUnusedFingerID() const; | ||
| 37 | |||
| 38 | // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no | ||
| 39 | // changes will be made. Updates the coordinates if the finger id it's already set. If the touch | ||
| 40 | // ends delays the output by one frame to set the end_touch flag before finally freeing the | ||
| 41 | // finger id | ||
| 42 | std::size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, | ||
| 43 | std::size_t finger_id); | ||
| 44 | |||
| 33 | struct Attributes { | 45 | struct Attributes { |
| 34 | union { | 46 | union { |
| 35 | u32 raw{}; | 47 | u32 raw{}; |
| @@ -55,7 +67,7 @@ private: | |||
| 55 | s64_le sampling_number; | 67 | s64_le sampling_number; |
| 56 | s64_le sampling_number2; | 68 | s64_le sampling_number2; |
| 57 | s32_le entry_count; | 69 | s32_le entry_count; |
| 58 | std::array<TouchState, 16> states; | 70 | std::array<TouchState, MAX_FINGERS> states; |
| 59 | }; | 71 | }; |
| 60 | static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); | 72 | static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); |
| 61 | 73 | ||
| @@ -66,9 +78,23 @@ private: | |||
| 66 | }; | 78 | }; |
| 67 | static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, | 79 | static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, |
| 68 | "TouchScreenSharedMemory is an invalid size"); | 80 | "TouchScreenSharedMemory is an invalid size"); |
| 81 | |||
| 82 | struct Finger { | ||
| 83 | u64_le last_touch{}; | ||
| 84 | float x{}; | ||
| 85 | float y{}; | ||
| 86 | u32_le id{}; | ||
| 87 | bool pressed{}; | ||
| 88 | Attributes attribute; | ||
| 89 | }; | ||
| 90 | |||
| 69 | TouchScreenSharedMemory shared_memory{}; | 91 | TouchScreenSharedMemory shared_memory{}; |
| 70 | std::unique_ptr<Input::TouchDevice> touch_device; | 92 | std::unique_ptr<Input::TouchDevice> touch_mouse_device; |
| 93 | std::unique_ptr<Input::TouchDevice> touch_udp_device; | ||
| 71 | std::unique_ptr<Input::TouchDevice> touch_btn_device; | 94 | std::unique_ptr<Input::TouchDevice> touch_btn_device; |
| 72 | s64_le last_touch{}; | 95 | std::array<std::size_t, MAX_FINGERS> mouse_finger_id; |
| 96 | std::array<std::size_t, MAX_FINGERS> keyboard_finger_id; | ||
| 97 | std::array<std::size_t, MAX_FINGERS> udp_finger_id; | ||
| 98 | std::array<Finger, MAX_FINGERS> fingers; | ||
| 73 | }; | 99 | }; |
| 74 | } // namespace Service::HID | 100 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index ad229787c..5b59961bd 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/bit_field.h" | ||
| 7 | #include "common/common_funcs.h" | 8 | #include "common/common_funcs.h" |
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| @@ -28,6 +29,67 @@ public: | |||
| 28 | void OnLoadInputDevices() override; | 29 | void OnLoadInputDevices() override; |
| 29 | 30 | ||
| 30 | private: | 31 | private: |
| 32 | struct Attributes { | ||
| 33 | union { | ||
| 34 | u32_le raw{}; | ||
| 35 | BitField<0, 1, u32> is_connected; | ||
| 36 | BitField<1, 1, u32> is_wired; | ||
| 37 | BitField<2, 1, u32> is_left_connected; | ||
| 38 | BitField<3, 1, u32> is_left_wired; | ||
| 39 | BitField<4, 1, u32> is_right_connected; | ||
| 40 | BitField<5, 1, u32> is_right_wired; | ||
| 41 | }; | ||
| 42 | }; | ||
| 43 | static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size"); | ||
| 44 | |||
| 45 | struct Buttons { | ||
| 46 | union { | ||
| 47 | u32_le raw{}; | ||
| 48 | // Button states | ||
| 49 | BitField<0, 1, u32> a; | ||
| 50 | BitField<1, 1, u32> b; | ||
| 51 | BitField<2, 1, u32> x; | ||
| 52 | BitField<3, 1, u32> y; | ||
| 53 | BitField<4, 1, u32> l_stick; | ||
| 54 | BitField<5, 1, u32> r_stick; | ||
| 55 | BitField<6, 1, u32> l; | ||
| 56 | BitField<7, 1, u32> r; | ||
| 57 | BitField<8, 1, u32> zl; | ||
| 58 | BitField<9, 1, u32> zr; | ||
| 59 | BitField<10, 1, u32> plus; | ||
| 60 | BitField<11, 1, u32> minus; | ||
| 61 | |||
| 62 | // D-Pad | ||
| 63 | BitField<12, 1, u32> d_left; | ||
| 64 | BitField<13, 1, u32> d_up; | ||
| 65 | BitField<14, 1, u32> d_right; | ||
| 66 | BitField<15, 1, u32> d_down; | ||
| 67 | |||
| 68 | // Left JoyStick | ||
| 69 | BitField<16, 1, u32> l_stick_left; | ||
| 70 | BitField<17, 1, u32> l_stick_up; | ||
| 71 | BitField<18, 1, u32> l_stick_right; | ||
| 72 | BitField<19, 1, u32> l_stick_down; | ||
| 73 | |||
| 74 | // Right JoyStick | ||
| 75 | BitField<20, 1, u32> r_stick_left; | ||
| 76 | BitField<21, 1, u32> r_stick_up; | ||
| 77 | BitField<22, 1, u32> r_stick_right; | ||
| 78 | BitField<23, 1, u32> r_stick_down; | ||
| 79 | |||
| 80 | // Not always active? | ||
| 81 | BitField<24, 1, u32> left_sl; | ||
| 82 | BitField<25, 1, u32> left_sr; | ||
| 83 | |||
| 84 | BitField<26, 1, u32> right_sl; | ||
| 85 | BitField<27, 1, u32> right_sr; | ||
| 86 | |||
| 87 | BitField<28, 1, u32> palma; | ||
| 88 | BitField<30, 1, u32> handheld_left_b; | ||
| 89 | }; | ||
| 90 | }; | ||
| 91 | static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size"); | ||
| 92 | |||
| 31 | struct AnalogStick { | 93 | struct AnalogStick { |
| 32 | s32_le x; | 94 | s32_le x; |
| 33 | s32_le y; | 95 | s32_le y; |
| @@ -37,10 +99,10 @@ private: | |||
| 37 | struct XPadState { | 99 | struct XPadState { |
| 38 | s64_le sampling_number; | 100 | s64_le sampling_number; |
| 39 | s64_le sampling_number2; | 101 | s64_le sampling_number2; |
| 40 | s32_le attributes; | 102 | Attributes attributes; |
| 41 | u32_le pad_states; | 103 | Buttons pad_states; |
| 42 | AnalogStick x_stick; | 104 | AnalogStick l_stick; |
| 43 | AnalogStick y_stick; | 105 | AnalogStick r_stick; |
| 44 | }; | 106 | }; |
| 45 | static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size"); | 107 | static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size"); |
| 46 | 108 | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index d86711fea..1e2677320 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -14,10 +14,10 @@ | |||
| 14 | #include "core/hle/ipc_helpers.h" | 14 | #include "core/hle/ipc_helpers.h" |
| 15 | #include "core/hle/kernel/client_port.h" | 15 | #include "core/hle/kernel/client_port.h" |
| 16 | #include "core/hle/kernel/client_session.h" | 16 | #include "core/hle/kernel/client_session.h" |
| 17 | #include "core/hle/kernel/k_readable_event.h" | ||
| 18 | #include "core/hle/kernel/k_writable_event.h" | ||
| 17 | #include "core/hle/kernel/kernel.h" | 19 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/kernel/readable_event.h" | ||
| 19 | #include "core/hle/kernel/shared_memory.h" | 20 | #include "core/hle/kernel/shared_memory.h" |
| 20 | #include "core/hle/kernel/writable_event.h" | ||
| 21 | #include "core/hle/service/hid/errors.h" | 21 | #include "core/hle/service/hid/errors.h" |
| 22 | #include "core/hle/service/hid/hid.h" | 22 | #include "core/hle/service/hid/hid.h" |
| 23 | #include "core/hle/service/hid/irs.h" | 23 | #include "core/hle/service/hid/irs.h" |
| @@ -59,20 +59,26 @@ IAppletResource::IAppletResource(Core::System& system_) | |||
| 59 | MakeController<Controller_Mouse>(HidController::Mouse); | 59 | MakeController<Controller_Mouse>(HidController::Mouse); |
| 60 | MakeController<Controller_Keyboard>(HidController::Keyboard); | 60 | MakeController<Controller_Keyboard>(HidController::Keyboard); |
| 61 | MakeController<Controller_XPad>(HidController::XPad); | 61 | MakeController<Controller_XPad>(HidController::XPad); |
| 62 | MakeController<Controller_Stubbed>(HidController::Unknown1); | 62 | MakeController<Controller_Stubbed>(HidController::HomeButton); |
| 63 | MakeController<Controller_Stubbed>(HidController::Unknown2); | 63 | MakeController<Controller_Stubbed>(HidController::SleepButton); |
| 64 | MakeController<Controller_Stubbed>(HidController::Unknown3); | 64 | MakeController<Controller_Stubbed>(HidController::CaptureButton); |
| 65 | MakeController<Controller_Stubbed>(HidController::SixAxisSensor); | 65 | MakeController<Controller_Stubbed>(HidController::InputDetector); |
| 66 | MakeController<Controller_Stubbed>(HidController::UniquePad); | ||
| 66 | MakeController<Controller_NPad>(HidController::NPad); | 67 | MakeController<Controller_NPad>(HidController::NPad); |
| 67 | MakeController<Controller_Gesture>(HidController::Gesture); | 68 | MakeController<Controller_Gesture>(HidController::Gesture); |
| 69 | MakeController<Controller_Stubbed>(HidController::ConsoleSixAxisSensor); | ||
| 68 | 70 | ||
| 69 | // Homebrew doesn't try to activate some controllers, so we activate them by default | 71 | // Homebrew doesn't try to activate some controllers, so we activate them by default |
| 70 | GetController<Controller_NPad>(HidController::NPad).ActivateController(); | 72 | GetController<Controller_NPad>(HidController::NPad).ActivateController(); |
| 71 | GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); | 73 | GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); |
| 72 | 74 | ||
| 73 | GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00); | 75 | GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00); |
| 74 | GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00); | 76 | GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00); |
| 75 | GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); | 77 | GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000); |
| 78 | GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200); | ||
| 79 | GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); | ||
| 80 | GetController<Controller_Stubbed>(HidController::ConsoleSixAxisSensor) | ||
| 81 | .SetCommonHeaderOffset(0x3C200); | ||
| 76 | 82 | ||
| 77 | // Register update callbacks | 83 | // Register update callbacks |
| 78 | pad_update_event = Core::Timing::CreateEvent( | 84 | pad_update_event = Core::Timing::CreateEvent( |
| @@ -219,9 +225,9 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} { | |||
| 219 | {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, | 225 | {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, |
| 220 | {68, nullptr, "IsSixAxisSensorFusionEnabled"}, | 226 | {68, nullptr, "IsSixAxisSensorFusionEnabled"}, |
| 221 | {69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"}, | 227 | {69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"}, |
| 222 | {70, nullptr, "SetSixAxisSensorFusionParameters"}, | 228 | {70, &Hid::SetSixAxisSensorFusionParameters, "SetSixAxisSensorFusionParameters"}, |
| 223 | {71, nullptr, "GetSixAxisSensorFusionParameters"}, | 229 | {71, &Hid::GetSixAxisSensorFusionParameters, "GetSixAxisSensorFusionParameters"}, |
| 224 | {72, nullptr, "ResetSixAxisSensorFusionParameters"}, | 230 | {72, &Hid::ResetSixAxisSensorFusionParameters, "ResetSixAxisSensorFusionParameters"}, |
| 225 | {73, nullptr, "SetAccelerometerParameters"}, | 231 | {73, nullptr, "SetAccelerometerParameters"}, |
| 226 | {74, nullptr, "GetAccelerometerParameters"}, | 232 | {74, nullptr, "GetAccelerometerParameters"}, |
| 227 | {75, nullptr, "ResetAccelerometerParameters"}, | 233 | {75, nullptr, "ResetAccelerometerParameters"}, |
| @@ -411,9 +417,9 @@ void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { | |||
| 411 | void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { | 417 | void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { |
| 412 | IPC::RequestParser rp{ctx}; | 418 | IPC::RequestParser rp{ctx}; |
| 413 | struct Parameters { | 419 | struct Parameters { |
| 414 | u32 basic_xpad_id{}; | 420 | u32 basic_xpad_id; |
| 415 | INSERT_PADDING_WORDS(1); | 421 | INSERT_PADDING_WORDS_NOINIT(1); |
| 416 | u64 applet_resource_user_id{}; | 422 | u64 applet_resource_user_id; |
| 417 | }; | 423 | }; |
| 418 | 424 | ||
| 419 | const auto parameters{rp.PopRaw<Parameters>()}; | 425 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -441,9 +447,9 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { | |||
| 441 | void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | 447 | void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 442 | IPC::RequestParser rp{ctx}; | 448 | IPC::RequestParser rp{ctx}; |
| 443 | struct Parameters { | 449 | struct Parameters { |
| 444 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 450 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 445 | INSERT_PADDING_WORDS(1); | 451 | INSERT_PADDING_WORDS_NOINIT(1); |
| 446 | u64 applet_resource_user_id{}; | 452 | u64 applet_resource_user_id; |
| 447 | }; | 453 | }; |
| 448 | 454 | ||
| 449 | const auto parameters{rp.PopRaw<Parameters>()}; | 455 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -462,9 +468,9 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 462 | void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | 468 | void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 463 | IPC::RequestParser rp{ctx}; | 469 | IPC::RequestParser rp{ctx}; |
| 464 | struct Parameters { | 470 | struct Parameters { |
| 465 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 471 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 466 | INSERT_PADDING_WORDS(1); | 472 | INSERT_PADDING_WORDS_NOINIT(1); |
| 467 | u64 applet_resource_user_id{}; | 473 | u64 applet_resource_user_id; |
| 468 | }; | 474 | }; |
| 469 | 475 | ||
| 470 | const auto parameters{rp.PopRaw<Parameters>()}; | 476 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -483,9 +489,9 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 483 | void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | 489 | void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 484 | IPC::RequestParser rp{ctx}; | 490 | IPC::RequestParser rp{ctx}; |
| 485 | struct Parameters { | 491 | struct Parameters { |
| 486 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 492 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 487 | INSERT_PADDING_WORDS(1); | 493 | INSERT_PADDING_WORDS_NOINIT(1); |
| 488 | u64 applet_resource_user_id{}; | 494 | u64 applet_resource_user_id; |
| 489 | }; | 495 | }; |
| 490 | 496 | ||
| 491 | const auto parameters{rp.PopRaw<Parameters>()}; | 497 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -504,9 +510,9 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 504 | void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { | 510 | void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 505 | IPC::RequestParser rp{ctx}; | 511 | IPC::RequestParser rp{ctx}; |
| 506 | struct Parameters { | 512 | struct Parameters { |
| 507 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 513 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 508 | INSERT_PADDING_WORDS(1); | 514 | INSERT_PADDING_WORDS_NOINIT(1); |
| 509 | u64 applet_resource_user_id{}; | 515 | u64 applet_resource_user_id; |
| 510 | }; | 516 | }; |
| 511 | 517 | ||
| 512 | const auto parameters{rp.PopRaw<Parameters>()}; | 518 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -525,11 +531,12 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 525 | void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { | 531 | void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { |
| 526 | IPC::RequestParser rp{ctx}; | 532 | IPC::RequestParser rp{ctx}; |
| 527 | struct Parameters { | 533 | struct Parameters { |
| 528 | bool enable_sixaxis_sensor_fusion{}; | 534 | bool enable_sixaxis_sensor_fusion; |
| 529 | INSERT_PADDING_BYTES(3); | 535 | INSERT_PADDING_BYTES_NOINIT(3); |
| 530 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 536 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 531 | u64 applet_resource_user_id{}; | 537 | u64 applet_resource_user_id; |
| 532 | }; | 538 | }; |
| 539 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 533 | 540 | ||
| 534 | const auto parameters{rp.PopRaw<Parameters>()}; | 541 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 535 | 542 | ||
| @@ -544,6 +551,83 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { | |||
| 544 | rb.Push(RESULT_SUCCESS); | 551 | rb.Push(RESULT_SUCCESS); |
| 545 | } | 552 | } |
| 546 | 553 | ||
| 554 | void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | ||
| 555 | IPC::RequestParser rp{ctx}; | ||
| 556 | struct Parameters { | ||
| 557 | Controller_NPad::DeviceHandle sixaxis_handle; | ||
| 558 | f32 parameter1; | ||
| 559 | f32 parameter2; | ||
| 560 | u64 applet_resource_user_id; | ||
| 561 | }; | ||
| 562 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | ||
| 563 | |||
| 564 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 565 | |||
| 566 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 567 | .SetSixAxisFusionParameters(parameters.parameter1, parameters.parameter2); | ||
| 568 | |||
| 569 | LOG_WARNING(Service_HID, | ||
| 570 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " | ||
| 571 | "parameter2={}, applet_resource_user_id={}", | ||
| 572 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 573 | parameters.sixaxis_handle.device_index, parameters.parameter1, | ||
| 574 | parameters.parameter2, parameters.applet_resource_user_id); | ||
| 575 | |||
| 576 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 577 | rb.Push(RESULT_SUCCESS); | ||
| 578 | } | ||
| 579 | |||
| 580 | void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | ||
| 581 | IPC::RequestParser rp{ctx}; | ||
| 582 | struct Parameters { | ||
| 583 | Controller_NPad::DeviceHandle sixaxis_handle; | ||
| 584 | u64 applet_resource_user_id; | ||
| 585 | }; | ||
| 586 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 587 | |||
| 588 | f32 parameter1 = 0; | ||
| 589 | f32 parameter2 = 0; | ||
| 590 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 591 | |||
| 592 | std::tie(parameter1, parameter2) = | ||
| 593 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 594 | .GetSixAxisFusionParameters(); | ||
| 595 | |||
| 596 | LOG_WARNING( | ||
| 597 | Service_HID, | ||
| 598 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 599 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 600 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 601 | |||
| 602 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 603 | rb.Push(RESULT_SUCCESS); | ||
| 604 | rb.Push(parameter1); | ||
| 605 | rb.Push(parameter2); | ||
| 606 | } | ||
| 607 | |||
| 608 | void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | ||
| 609 | IPC::RequestParser rp{ctx}; | ||
| 610 | struct Parameters { | ||
| 611 | Controller_NPad::DeviceHandle sixaxis_handle; | ||
| 612 | u64 applet_resource_user_id; | ||
| 613 | }; | ||
| 614 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 615 | |||
| 616 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 617 | |||
| 618 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 619 | .ResetSixAxisFusionParameters(); | ||
| 620 | |||
| 621 | LOG_WARNING( | ||
| 622 | Service_HID, | ||
| 623 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 624 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 625 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 626 | |||
| 627 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 628 | rb.Push(RESULT_SUCCESS); | ||
| 629 | } | ||
| 630 | |||
| 547 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 631 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 548 | IPC::RequestParser rp{ctx}; | 632 | IPC::RequestParser rp{ctx}; |
| 549 | const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; | 633 | const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; |
| @@ -566,9 +650,9 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 566 | void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 650 | void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 567 | IPC::RequestParser rp{ctx}; | 651 | IPC::RequestParser rp{ctx}; |
| 568 | struct Parameters { | 652 | struct Parameters { |
| 569 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 653 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 570 | INSERT_PADDING_WORDS(1); | 654 | INSERT_PADDING_WORDS_NOINIT(1); |
| 571 | u64 applet_resource_user_id{}; | 655 | u64 applet_resource_user_id; |
| 572 | }; | 656 | }; |
| 573 | 657 | ||
| 574 | const auto parameters{rp.PopRaw<Parameters>()}; | 658 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -587,9 +671,9 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 587 | void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 671 | void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 588 | IPC::RequestParser rp{ctx}; | 672 | IPC::RequestParser rp{ctx}; |
| 589 | struct Parameters { | 673 | struct Parameters { |
| 590 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 674 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 591 | INSERT_PADDING_WORDS(1); | 675 | INSERT_PADDING_WORDS_NOINIT(1); |
| 592 | u64 applet_resource_user_id{}; | 676 | u64 applet_resource_user_id; |
| 593 | }; | 677 | }; |
| 594 | 678 | ||
| 595 | const auto parameters{rp.PopRaw<Parameters>()}; | 679 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -609,9 +693,9 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 609 | void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { | 693 | void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { |
| 610 | IPC::RequestParser rp{ctx}; | 694 | IPC::RequestParser rp{ctx}; |
| 611 | struct Parameters { | 695 | struct Parameters { |
| 612 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 696 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 613 | INSERT_PADDING_WORDS(1); | 697 | INSERT_PADDING_WORDS_NOINIT(1); |
| 614 | u64 applet_resource_user_id{}; | 698 | u64 applet_resource_user_id; |
| 615 | }; | 699 | }; |
| 616 | 700 | ||
| 617 | const auto parameters{rp.PopRaw<Parameters>()}; | 701 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -630,9 +714,9 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { | |||
| 630 | void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { | 714 | void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { |
| 631 | IPC::RequestParser rp{ctx}; | 715 | IPC::RequestParser rp{ctx}; |
| 632 | struct Parameters { | 716 | struct Parameters { |
| 633 | u32 unknown{}; | 717 | u32 unknown; |
| 634 | INSERT_PADDING_WORDS(1); | 718 | INSERT_PADDING_WORDS_NOINIT(1); |
| 635 | u64 applet_resource_user_id{}; | 719 | u64 applet_resource_user_id; |
| 636 | }; | 720 | }; |
| 637 | 721 | ||
| 638 | const auto parameters{rp.PopRaw<Parameters>()}; | 722 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -712,10 +796,10 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { | |||
| 712 | void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | 796 | void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { |
| 713 | IPC::RequestParser rp{ctx}; | 797 | IPC::RequestParser rp{ctx}; |
| 714 | struct Parameters { | 798 | struct Parameters { |
| 715 | u32 npad_id{}; | 799 | u32 npad_id; |
| 716 | INSERT_PADDING_WORDS(1); | 800 | INSERT_PADDING_WORDS_NOINIT(1); |
| 717 | u64 applet_resource_user_id{}; | 801 | u64 applet_resource_user_id; |
| 718 | u64 unknown{}; | 802 | u64 unknown; |
| 719 | }; | 803 | }; |
| 720 | 804 | ||
| 721 | const auto parameters{rp.PopRaw<Parameters>()}; | 805 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -732,9 +816,9 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | |||
| 732 | void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { | 816 | void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { |
| 733 | IPC::RequestParser rp{ctx}; | 817 | IPC::RequestParser rp{ctx}; |
| 734 | struct Parameters { | 818 | struct Parameters { |
| 735 | u32 npad_id{}; | 819 | u32 npad_id; |
| 736 | INSERT_PADDING_WORDS(1); | 820 | INSERT_PADDING_WORDS_NOINIT(1); |
| 737 | u64 applet_resource_user_id{}; | 821 | u64 applet_resource_user_id; |
| 738 | }; | 822 | }; |
| 739 | 823 | ||
| 740 | const auto parameters{rp.PopRaw<Parameters>()}; | 824 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -766,9 +850,9 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | |||
| 766 | // Should have no effect with how our npad sets up the data | 850 | // Should have no effect with how our npad sets up the data |
| 767 | IPC::RequestParser rp{ctx}; | 851 | IPC::RequestParser rp{ctx}; |
| 768 | struct Parameters { | 852 | struct Parameters { |
| 769 | u32 unknown{}; | 853 | u32 unknown; |
| 770 | INSERT_PADDING_WORDS(1); | 854 | INSERT_PADDING_WORDS_NOINIT(1); |
| 771 | u64 applet_resource_user_id{}; | 855 | u64 applet_resource_user_id; |
| 772 | }; | 856 | }; |
| 773 | 857 | ||
| 774 | const auto parameters{rp.PopRaw<Parameters>()}; | 858 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -810,9 +894,9 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | |||
| 810 | void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { | 894 | void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { |
| 811 | IPC::RequestParser rp{ctx}; | 895 | IPC::RequestParser rp{ctx}; |
| 812 | struct Parameters { | 896 | struct Parameters { |
| 813 | u32 npad_id{}; | 897 | u32 npad_id; |
| 814 | INSERT_PADDING_WORDS(1); | 898 | INSERT_PADDING_WORDS_NOINIT(1); |
| 815 | u64 applet_resource_user_id{}; | 899 | u64 applet_resource_user_id; |
| 816 | }; | 900 | }; |
| 817 | 901 | ||
| 818 | const auto parameters{rp.PopRaw<Parameters>()}; | 902 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -831,10 +915,10 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | |||
| 831 | // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault | 915 | // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault |
| 832 | IPC::RequestParser rp{ctx}; | 916 | IPC::RequestParser rp{ctx}; |
| 833 | struct Parameters { | 917 | struct Parameters { |
| 834 | u32 npad_id{}; | 918 | u32 npad_id; |
| 835 | INSERT_PADDING_WORDS(1); | 919 | INSERT_PADDING_WORDS_NOINIT(1); |
| 836 | u64 applet_resource_user_id{}; | 920 | u64 applet_resource_user_id; |
| 837 | u64 npad_joy_device_type{}; | 921 | u64 npad_joy_device_type; |
| 838 | }; | 922 | }; |
| 839 | 923 | ||
| 840 | const auto parameters{rp.PopRaw<Parameters>()}; | 924 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -854,9 +938,9 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | |||
| 854 | void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | 938 | void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { |
| 855 | IPC::RequestParser rp{ctx}; | 939 | IPC::RequestParser rp{ctx}; |
| 856 | struct Parameters { | 940 | struct Parameters { |
| 857 | u32 npad_id{}; | 941 | u32 npad_id; |
| 858 | INSERT_PADDING_WORDS(1); | 942 | INSERT_PADDING_WORDS_NOINIT(1); |
| 859 | u64 applet_resource_user_id{}; | 943 | u64 applet_resource_user_id; |
| 860 | }; | 944 | }; |
| 861 | 945 | ||
| 862 | const auto parameters{rp.PopRaw<Parameters>()}; | 946 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -962,9 +1046,9 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { | |||
| 962 | void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { | 1046 | void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { |
| 963 | IPC::RequestParser rp{ctx}; | 1047 | IPC::RequestParser rp{ctx}; |
| 964 | struct Parameters { | 1048 | struct Parameters { |
| 965 | u32 npad_id{}; | 1049 | u32 npad_id; |
| 966 | INSERT_PADDING_WORDS(1); | 1050 | INSERT_PADDING_WORDS_NOINIT(1); |
| 967 | u64 applet_resource_user_id{}; | 1051 | u64 applet_resource_user_id; |
| 968 | }; | 1052 | }; |
| 969 | 1053 | ||
| 970 | const auto parameters{rp.PopRaw<Parameters>()}; | 1054 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -981,10 +1065,10 @@ void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext | |||
| 981 | void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) { | 1065 | void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) { |
| 982 | IPC::RequestParser rp{ctx}; | 1066 | IPC::RequestParser rp{ctx}; |
| 983 | struct Parameters { | 1067 | struct Parameters { |
| 984 | bool unintended_home_button_input_protection{}; | 1068 | bool unintended_home_button_input_protection; |
| 985 | INSERT_PADDING_BYTES(3); | 1069 | INSERT_PADDING_BYTES_NOINIT(3); |
| 986 | u32 npad_id{}; | 1070 | u32 npad_id; |
| 987 | u64 applet_resource_user_id{}; | 1071 | u64 applet_resource_user_id; |
| 988 | }; | 1072 | }; |
| 989 | 1073 | ||
| 990 | const auto parameters{rp.PopRaw<Parameters>()}; | 1074 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -1036,10 +1120,10 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | |||
| 1036 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { | 1120 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 1037 | IPC::RequestParser rp{ctx}; | 1121 | IPC::RequestParser rp{ctx}; |
| 1038 | struct Parameters { | 1122 | struct Parameters { |
| 1039 | Controller_NPad::DeviceHandle vibration_device_handle{}; | 1123 | Controller_NPad::DeviceHandle vibration_device_handle; |
| 1040 | Controller_NPad::VibrationValue vibration_value{}; | 1124 | Controller_NPad::VibrationValue vibration_value; |
| 1041 | INSERT_PADDING_WORDS(1); | 1125 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1042 | u64 applet_resource_user_id{}; | 1126 | u64 applet_resource_user_id; |
| 1043 | }; | 1127 | }; |
| 1044 | 1128 | ||
| 1045 | const auto parameters{rp.PopRaw<Parameters>()}; | 1129 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -1060,9 +1144,9 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { | |||
| 1060 | void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | 1144 | void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { |
| 1061 | IPC::RequestParser rp{ctx}; | 1145 | IPC::RequestParser rp{ctx}; |
| 1062 | struct Parameters { | 1146 | struct Parameters { |
| 1063 | Controller_NPad::DeviceHandle vibration_device_handle{}; | 1147 | Controller_NPad::DeviceHandle vibration_device_handle; |
| 1064 | INSERT_PADDING_WORDS(1); | 1148 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1065 | u64 applet_resource_user_id{}; | 1149 | u64 applet_resource_user_id; |
| 1066 | }; | 1150 | }; |
| 1067 | 1151 | ||
| 1068 | const auto parameters{rp.PopRaw<Parameters>()}; | 1152 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -1157,9 +1241,9 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | |||
| 1157 | void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { | 1241 | void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { |
| 1158 | IPC::RequestParser rp{ctx}; | 1242 | IPC::RequestParser rp{ctx}; |
| 1159 | struct Parameters { | 1243 | struct Parameters { |
| 1160 | Controller_NPad::DeviceHandle vibration_device_handle{}; | 1244 | Controller_NPad::DeviceHandle vibration_device_handle; |
| 1161 | INSERT_PADDING_WORDS(1); | 1245 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1162 | u64 applet_resource_user_id{}; | 1246 | u64 applet_resource_user_id; |
| 1163 | }; | 1247 | }; |
| 1164 | 1248 | ||
| 1165 | const auto parameters{rp.PopRaw<Parameters>()}; | 1249 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -1190,9 +1274,9 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 1190 | void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 1274 | void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 1191 | IPC::RequestParser rp{ctx}; | 1275 | IPC::RequestParser rp{ctx}; |
| 1192 | struct Parameters { | 1276 | struct Parameters { |
| 1193 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 1277 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 1194 | INSERT_PADDING_WORDS(1); | 1278 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1195 | u64 applet_resource_user_id{}; | 1279 | u64 applet_resource_user_id; |
| 1196 | }; | 1280 | }; |
| 1197 | 1281 | ||
| 1198 | const auto parameters{rp.PopRaw<Parameters>()}; | 1282 | const auto parameters{rp.PopRaw<Parameters>()}; |
| @@ -1210,9 +1294,9 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 1210 | void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 1294 | void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 1211 | IPC::RequestParser rp{ctx}; | 1295 | IPC::RequestParser rp{ctx}; |
| 1212 | struct Parameters { | 1296 | struct Parameters { |
| 1213 | Controller_NPad::DeviceHandle sixaxis_handle{}; | 1297 | Controller_NPad::DeviceHandle sixaxis_handle; |
| 1214 | INSERT_PADDING_WORDS(1); | 1298 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1215 | u64 applet_resource_user_id{}; | 1299 | u64 applet_resource_user_id; |
| 1216 | }; | 1300 | }; |
| 1217 | 1301 | ||
| 1218 | const auto parameters{rp.PopRaw<Parameters>()}; | 1302 | const auto parameters{rp.PopRaw<Parameters>()}; |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index b87bfdde1..7cc0433e2 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -29,12 +29,14 @@ enum class HidController : std::size_t { | |||
| 29 | Mouse, | 29 | Mouse, |
| 30 | Keyboard, | 30 | Keyboard, |
| 31 | XPad, | 31 | XPad, |
| 32 | Unknown1, | 32 | HomeButton, |
| 33 | Unknown2, | 33 | SleepButton, |
| 34 | Unknown3, | 34 | CaptureButton, |
| 35 | SixAxisSensor, | 35 | InputDetector, |
| 36 | UniquePad, | ||
| 36 | NPad, | 37 | NPad, |
| 37 | Gesture, | 38 | Gesture, |
| 39 | ConsoleSixAxisSensor, | ||
| 38 | 40 | ||
| 39 | MaxControllers, | 41 | MaxControllers, |
| 40 | }; | 42 | }; |
| @@ -97,6 +99,9 @@ private: | |||
| 97 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx); | 99 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 98 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx); | 100 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 99 | void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx); | 101 | void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx); |
| 102 | void SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx); | ||
| 103 | void GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx); | ||
| 104 | void ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx); | ||
| 100 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); | 105 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); |
| 101 | void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); | 106 | void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); |
| 102 | void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); | 107 | void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp index 6ad3a2877..f4490f3d9 100644 --- a/src/core/hle/service/lbl/lbl.cpp +++ b/src/core/hle/service/lbl/lbl.cpp | |||
| @@ -20,30 +20,30 @@ public: | |||
| 20 | static const FunctionInfo functions[] = { | 20 | static const FunctionInfo functions[] = { |
| 21 | {0, nullptr, "SaveCurrentSetting"}, | 21 | {0, nullptr, "SaveCurrentSetting"}, |
| 22 | {1, nullptr, "LoadCurrentSetting"}, | 22 | {1, nullptr, "LoadCurrentSetting"}, |
| 23 | {2, nullptr, "SetCurrentBrightnessSetting"}, | 23 | {2, &LBL::SetCurrentBrightnessSetting, "SetCurrentBrightnessSetting"}, |
| 24 | {3, nullptr, "GetCurrentBrightnessSetting"}, | 24 | {3, &LBL::GetCurrentBrightnessSetting, "GetCurrentBrightnessSetting"}, |
| 25 | {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"}, | 25 | {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"}, |
| 26 | {5, nullptr, "GetBrightnessSettingAppliedToBacklight"}, | 26 | {5, nullptr, "GetBrightnessSettingAppliedToBacklight"}, |
| 27 | {6, nullptr, "SwitchBacklightOn"}, | 27 | {6, &LBL::SwitchBacklightOn, "SwitchBacklightOn"}, |
| 28 | {7, nullptr, "SwitchBacklightOff"}, | 28 | {7, &LBL::SwitchBacklightOff, "SwitchBacklightOff"}, |
| 29 | {8, nullptr, "GetBacklightSwitchStatus"}, | 29 | {8, &LBL::GetBacklightSwitchStatus, "GetBacklightSwitchStatus"}, |
| 30 | {9, nullptr, "EnableDimming"}, | 30 | {9, &LBL::EnableDimming, "EnableDimming"}, |
| 31 | {10, nullptr, "DisableDimming"}, | 31 | {10, &LBL::DisableDimming, "DisableDimming"}, |
| 32 | {11, nullptr, "IsDimmingEnabled"}, | 32 | {11, &LBL::IsDimmingEnabled, "IsDimmingEnabled"}, |
| 33 | {12, nullptr, "EnableAutoBrightnessControl"}, | 33 | {12, &LBL::EnableAutoBrightnessControl, "EnableAutoBrightnessControl"}, |
| 34 | {13, nullptr, "DisableAutoBrightnessControl"}, | 34 | {13, &LBL::DisableAutoBrightnessControl, "DisableAutoBrightnessControl"}, |
| 35 | {14, nullptr, "IsAutoBrightnessControlEnabled"}, | 35 | {14, &LBL::IsAutoBrightnessControlEnabled, "IsAutoBrightnessControlEnabled"}, |
| 36 | {15, nullptr, "SetAmbientLightSensorValue"}, | 36 | {15, &LBL::SetAmbientLightSensorValue, "SetAmbientLightSensorValue"}, |
| 37 | {16, nullptr, "GetAmbientLightSensorValue"}, | 37 | {16, &LBL::GetAmbientLightSensorValue, "GetAmbientLightSensorValue"}, |
| 38 | {17, nullptr, "SetBrightnessReflectionDelayLevel"}, | 38 | {17, &LBL::SetBrightnessReflectionDelayLevel, "SetBrightnessReflectionDelayLevel"}, |
| 39 | {18, nullptr, "GetBrightnessReflectionDelayLevel"}, | 39 | {18, &LBL::GetBrightnessReflectionDelayLevel, "GetBrightnessReflectionDelayLevel"}, |
| 40 | {19, nullptr, "SetCurrentBrightnessMapping"}, | 40 | {19, &LBL::SetCurrentBrightnessMapping, "SetCurrentBrightnessMapping"}, |
| 41 | {20, nullptr, "GetCurrentBrightnessMapping"}, | 41 | {20, &LBL::GetCurrentBrightnessMapping, "GetCurrentBrightnessMapping"}, |
| 42 | {21, nullptr, "SetCurrentAmbientLightSensorMapping"}, | 42 | {21, &LBL::SetCurrentAmbientLightSensorMapping, "SetCurrentAmbientLightSensorMapping"}, |
| 43 | {22, nullptr, "GetCurrentAmbientLightSensorMapping"}, | 43 | {22, &LBL::GetCurrentAmbientLightSensorMapping, "GetCurrentAmbientLightSensorMapping"}, |
| 44 | {23, nullptr, "IsAmbientLightSensorAvailable"}, | 44 | {23, &LBL::IsAmbientLightSensorAvailable, "IsAmbientLightSensorAvailable"}, |
| 45 | {24, nullptr, "SetCurrentBrightnessSettingForVrMode"}, | 45 | {24, &LBL::SetCurrentBrightnessSettingForVrMode, "SetCurrentBrightnessSettingForVrMode"}, |
| 46 | {25, nullptr, "GetCurrentBrightnessSettingForVrMode"}, | 46 | {25, &LBL::GetCurrentBrightnessSettingForVrMode, "GetCurrentBrightnessSettingForVrMode"}, |
| 47 | {26, &LBL::EnableVrMode, "EnableVrMode"}, | 47 | {26, &LBL::EnableVrMode, "EnableVrMode"}, |
| 48 | {27, &LBL::DisableVrMode, "DisableVrMode"}, | 48 | {27, &LBL::DisableVrMode, "DisableVrMode"}, |
| 49 | {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"}, | 49 | {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"}, |
| @@ -55,6 +55,237 @@ public: | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | private: | 57 | private: |
| 58 | enum class BacklightSwitchStatus : u32 { | ||
| 59 | Off = 0, | ||
| 60 | On = 1, | ||
| 61 | }; | ||
| 62 | |||
| 63 | void SetCurrentBrightnessSetting(Kernel::HLERequestContext& ctx) { | ||
| 64 | IPC::RequestParser rp{ctx}; | ||
| 65 | auto brightness = rp.Pop<float>(); | ||
| 66 | |||
| 67 | if (!std::isfinite(brightness)) { | ||
| 68 | LOG_ERROR(Service_LBL, "Brightness is infinite!"); | ||
| 69 | brightness = 0.0f; | ||
| 70 | } | ||
| 71 | |||
| 72 | LOG_DEBUG(Service_LBL, "called brightness={}", brightness); | ||
| 73 | |||
| 74 | current_brightness = brightness; | ||
| 75 | update_instantly = true; | ||
| 76 | |||
| 77 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 78 | rb.Push(RESULT_SUCCESS); | ||
| 79 | } | ||
| 80 | |||
| 81 | void GetCurrentBrightnessSetting(Kernel::HLERequestContext& ctx) { | ||
| 82 | IPC::RequestParser rp{ctx}; | ||
| 83 | auto brightness = current_brightness; | ||
| 84 | if (!std::isfinite(brightness)) { | ||
| 85 | LOG_ERROR(Service_LBL, "Brightness is infinite!"); | ||
| 86 | brightness = 0.0f; | ||
| 87 | } | ||
| 88 | |||
| 89 | LOG_DEBUG(Service_LBL, "called brightness={}", brightness); | ||
| 90 | |||
| 91 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 92 | rb.Push(RESULT_SUCCESS); | ||
| 93 | rb.Push(brightness); | ||
| 94 | } | ||
| 95 | |||
| 96 | void SwitchBacklightOn(Kernel::HLERequestContext& ctx) { | ||
| 97 | IPC::RequestParser rp{ctx}; | ||
| 98 | const auto fade_time = rp.Pop<u64_le>(); | ||
| 99 | LOG_WARNING(Service_LBL, "(STUBBED) called, fade_time={}", fade_time); | ||
| 100 | |||
| 101 | backlight_enabled = true; | ||
| 102 | |||
| 103 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 104 | rb.Push(RESULT_SUCCESS); | ||
| 105 | } | ||
| 106 | |||
| 107 | void SwitchBacklightOff(Kernel::HLERequestContext& ctx) { | ||
| 108 | IPC::RequestParser rp{ctx}; | ||
| 109 | const auto fade_time = rp.Pop<u64_le>(); | ||
| 110 | LOG_WARNING(Service_LBL, "(STUBBED) called, fade_time={}", fade_time); | ||
| 111 | |||
| 112 | backlight_enabled = false; | ||
| 113 | |||
| 114 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 115 | rb.Push(RESULT_SUCCESS); | ||
| 116 | } | ||
| 117 | |||
| 118 | void GetBacklightSwitchStatus(Kernel::HLERequestContext& ctx) { | ||
| 119 | LOG_DEBUG(Service_LBL, "called"); | ||
| 120 | |||
| 121 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 122 | rb.Push(RESULT_SUCCESS); | ||
| 123 | rb.PushEnum<BacklightSwitchStatus>(backlight_enabled ? BacklightSwitchStatus::On | ||
| 124 | : BacklightSwitchStatus::Off); | ||
| 125 | } | ||
| 126 | |||
| 127 | void EnableDimming(Kernel::HLERequestContext& ctx) { | ||
| 128 | LOG_DEBUG(Service_LBL, "called"); | ||
| 129 | |||
| 130 | dimming = true; | ||
| 131 | |||
| 132 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 133 | rb.Push(RESULT_SUCCESS); | ||
| 134 | } | ||
| 135 | |||
| 136 | void DisableDimming(Kernel::HLERequestContext& ctx) { | ||
| 137 | LOG_DEBUG(Service_LBL, "called"); | ||
| 138 | |||
| 139 | dimming = false; | ||
| 140 | |||
| 141 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 142 | rb.Push(RESULT_SUCCESS); | ||
| 143 | } | ||
| 144 | |||
| 145 | void IsDimmingEnabled(Kernel::HLERequestContext& ctx) { | ||
| 146 | LOG_DEBUG(Service_LBL, "called"); | ||
| 147 | |||
| 148 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 149 | rb.Push(RESULT_SUCCESS); | ||
| 150 | rb.Push(dimming); | ||
| 151 | } | ||
| 152 | |||
| 153 | void EnableAutoBrightnessControl(Kernel::HLERequestContext& ctx) { | ||
| 154 | LOG_DEBUG(Service_LBL, "called"); | ||
| 155 | auto_brightness = true; | ||
| 156 | update_instantly = true; | ||
| 157 | |||
| 158 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 159 | rb.Push(RESULT_SUCCESS); | ||
| 160 | } | ||
| 161 | |||
| 162 | void DisableAutoBrightnessControl(Kernel::HLERequestContext& ctx) { | ||
| 163 | LOG_DEBUG(Service_LBL, "called"); | ||
| 164 | auto_brightness = false; | ||
| 165 | |||
| 166 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 167 | rb.Push(RESULT_SUCCESS); | ||
| 168 | } | ||
| 169 | |||
| 170 | void IsAutoBrightnessControlEnabled(Kernel::HLERequestContext& ctx) { | ||
| 171 | LOG_DEBUG(Service_LBL, "called"); | ||
| 172 | |||
| 173 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 174 | rb.Push(RESULT_SUCCESS); | ||
| 175 | rb.Push(auto_brightness); | ||
| 176 | } | ||
| 177 | |||
| 178 | void SetAmbientLightSensorValue(Kernel::HLERequestContext& ctx) { | ||
| 179 | IPC::RequestParser rp{ctx}; | ||
| 180 | const auto light_value = rp.Pop<float>(); | ||
| 181 | |||
| 182 | LOG_DEBUG(Service_LBL, "called light_value={}", light_value); | ||
| 183 | |||
| 184 | ambient_light_value = light_value; | ||
| 185 | |||
| 186 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 187 | rb.Push(RESULT_SUCCESS); | ||
| 188 | } | ||
| 189 | |||
| 190 | void GetAmbientLightSensorValue(Kernel::HLERequestContext& ctx) { | ||
| 191 | LOG_DEBUG(Service_LBL, "called"); | ||
| 192 | |||
| 193 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 194 | rb.Push(RESULT_SUCCESS); | ||
| 195 | rb.Push(ambient_light_value); | ||
| 196 | } | ||
| 197 | |||
| 198 | void SetBrightnessReflectionDelayLevel(Kernel::HLERequestContext& ctx) { | ||
| 199 | // This is Intentional, this function does absolutely nothing | ||
| 200 | LOG_DEBUG(Service_LBL, "called"); | ||
| 201 | |||
| 202 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 203 | rb.Push(RESULT_SUCCESS); | ||
| 204 | } | ||
| 205 | |||
| 206 | void GetBrightnessReflectionDelayLevel(Kernel::HLERequestContext& ctx) { | ||
| 207 | // This is intentional, the function is hard coded to return 0.0f on hardware | ||
| 208 | LOG_DEBUG(Service_LBL, "called"); | ||
| 209 | |||
| 210 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 211 | rb.Push(RESULT_SUCCESS); | ||
| 212 | rb.Push(0.0f); | ||
| 213 | } | ||
| 214 | |||
| 215 | void SetCurrentBrightnessMapping(Kernel::HLERequestContext& ctx) { | ||
| 216 | // This is Intentional, this function does absolutely nothing | ||
| 217 | LOG_DEBUG(Service_LBL, "called"); | ||
| 218 | |||
| 219 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 220 | rb.Push(RESULT_SUCCESS); | ||
| 221 | } | ||
| 222 | |||
| 223 | void GetCurrentBrightnessMapping(Kernel::HLERequestContext& ctx) { | ||
| 224 | // This is Intentional, this function does absolutely nothing | ||
| 225 | LOG_DEBUG(Service_LBL, "called"); | ||
| 226 | |||
| 227 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 228 | rb.Push(RESULT_SUCCESS); | ||
| 229 | // This function is suppose to return something but it seems like it doesn't | ||
| 230 | } | ||
| 231 | |||
| 232 | void SetCurrentAmbientLightSensorMapping(Kernel::HLERequestContext& ctx) { | ||
| 233 | // This is Intentional, this function does absolutely nothing | ||
| 234 | LOG_DEBUG(Service_LBL, "called"); | ||
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 237 | rb.Push(RESULT_SUCCESS); | ||
| 238 | } | ||
| 239 | |||
| 240 | void GetCurrentAmbientLightSensorMapping(Kernel::HLERequestContext& ctx) { | ||
| 241 | // This is Intentional, this function does absolutely nothing | ||
| 242 | LOG_DEBUG(Service_LBL, "called"); | ||
| 243 | |||
| 244 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 245 | rb.Push(RESULT_SUCCESS); | ||
| 246 | // This function is suppose to return something but it seems like it doesn't | ||
| 247 | } | ||
| 248 | |||
| 249 | void IsAmbientLightSensorAvailable(Kernel::HLERequestContext& ctx) { | ||
| 250 | LOG_WARNING(Service_LBL, "(STUBBED) called"); | ||
| 251 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 252 | rb.Push(RESULT_SUCCESS); | ||
| 253 | // TODO(ogniK): Only return true if there's no device error | ||
| 254 | rb.Push(true); | ||
| 255 | } | ||
| 256 | |||
| 257 | void SetCurrentBrightnessSettingForVrMode(Kernel::HLERequestContext& ctx) { | ||
| 258 | IPC::RequestParser rp{ctx}; | ||
| 259 | auto brightness = rp.Pop<float>(); | ||
| 260 | |||
| 261 | if (!std::isfinite(brightness)) { | ||
| 262 | LOG_ERROR(Service_LBL, "Brightness is infinite!"); | ||
| 263 | brightness = 0.0f; | ||
| 264 | } | ||
| 265 | |||
| 266 | LOG_DEBUG(Service_LBL, "called brightness={}", brightness); | ||
| 267 | |||
| 268 | current_vr_brightness = brightness; | ||
| 269 | |||
| 270 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 271 | rb.Push(RESULT_SUCCESS); | ||
| 272 | } | ||
| 273 | |||
| 274 | void GetCurrentBrightnessSettingForVrMode(Kernel::HLERequestContext& ctx) { | ||
| 275 | IPC::RequestParser rp{ctx}; | ||
| 276 | auto brightness = current_vr_brightness; | ||
| 277 | if (!std::isfinite(brightness)) { | ||
| 278 | LOG_ERROR(Service_LBL, "Brightness is infinite!"); | ||
| 279 | brightness = 0.0f; | ||
| 280 | } | ||
| 281 | |||
| 282 | LOG_DEBUG(Service_LBL, "called brightness={}", brightness); | ||
| 283 | |||
| 284 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 285 | rb.Push(RESULT_SUCCESS); | ||
| 286 | rb.Push(brightness); | ||
| 287 | } | ||
| 288 | |||
| 58 | void EnableVrMode(Kernel::HLERequestContext& ctx) { | 289 | void EnableVrMode(Kernel::HLERequestContext& ctx) { |
| 59 | LOG_DEBUG(Service_LBL, "called"); | 290 | LOG_DEBUG(Service_LBL, "called"); |
| 60 | 291 | ||
| @@ -82,6 +313,14 @@ private: | |||
| 82 | } | 313 | } |
| 83 | 314 | ||
| 84 | bool vr_mode_enabled = false; | 315 | bool vr_mode_enabled = false; |
| 316 | float current_brightness = 1.0f; | ||
| 317 | float backlight_brightness = 1.0f; | ||
| 318 | float ambient_light_value = 0.0f; | ||
| 319 | float current_vr_brightness = 1.0f; | ||
| 320 | bool dimming = true; | ||
| 321 | bool backlight_enabled = true; | ||
| 322 | bool update_instantly = false; | ||
| 323 | bool auto_brightness = false; // TODO(ogniK): Move to system settings | ||
| 85 | }; | 324 | }; |
| 86 | 325 | ||
| 87 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { | 326 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 8e49b068c..7d7542fc2 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp | |||
| @@ -5,22 +5,71 @@ | |||
| 5 | #include <sstream> | 5 | #include <sstream> |
| 6 | #include <string> | 6 | #include <string> |
| 7 | 7 | ||
| 8 | #include <optional> | ||
| 9 | #include <unordered_map> | ||
| 10 | #include <boost/container_hash/hash.hpp> | ||
| 8 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 9 | #include "common/scope_exit.h" | 12 | #include "common/scope_exit.h" |
| 10 | #include "core/core.h" | 13 | #include "core/core.h" |
| 11 | #include "core/hle/ipc_helpers.h" | 14 | #include "core/hle/ipc_helpers.h" |
| 12 | #include "core/hle/service/lm/lm.h" | 15 | #include "core/hle/service/lm/lm.h" |
| 13 | #include "core/hle/service/lm/manager.h" | ||
| 14 | #include "core/hle/service/service.h" | 16 | #include "core/hle/service/service.h" |
| 15 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 16 | 18 | ||
| 17 | namespace Service::LM { | 19 | namespace Service::LM { |
| 20 | enum class LogSeverity : u8 { | ||
| 21 | Trace = 0, | ||
| 22 | Info = 1, | ||
| 23 | Warning = 2, | ||
| 24 | Error = 3, | ||
| 25 | Fatal = 4, | ||
| 26 | }; | ||
| 27 | |||
| 28 | // To keep flags out of hashing as well as the payload size | ||
| 29 | struct LogPacketHeaderEntry { | ||
| 30 | u64_le pid{}; | ||
| 31 | u64_le tid{}; | ||
| 32 | LogSeverity severity{}; | ||
| 33 | u8 verbosity{}; | ||
| 34 | |||
| 35 | auto operator<=>(const LogPacketHeaderEntry&) const = default; | ||
| 36 | }; | ||
| 37 | } // namespace Service::LM | ||
| 38 | |||
| 39 | namespace std { | ||
| 40 | template <> | ||
| 41 | struct hash<Service::LM::LogPacketHeaderEntry> { | ||
| 42 | std::size_t operator()(const Service::LM::LogPacketHeaderEntry& k) const noexcept { | ||
| 43 | std::size_t seed{}; | ||
| 44 | boost::hash_combine(seed, k.pid); | ||
| 45 | boost::hash_combine(seed, k.tid); | ||
| 46 | boost::hash_combine(seed, k.severity); | ||
| 47 | boost::hash_combine(seed, k.verbosity); | ||
| 48 | return seed; | ||
| 49 | }; | ||
| 50 | }; | ||
| 51 | } // namespace std | ||
| 52 | |||
| 53 | namespace Service::LM { | ||
| 54 | |||
| 55 | enum class LogDestination : u32 { | ||
| 56 | TargetManager = 1 << 0, | ||
| 57 | Uart = 1 << 1, | ||
| 58 | UartSleep = 1 << 2, | ||
| 59 | All = 0xffff, | ||
| 60 | }; | ||
| 61 | DECLARE_ENUM_FLAG_OPERATORS(LogDestination); | ||
| 62 | |||
| 63 | enum class LogPacketFlags : u8 { | ||
| 64 | Head = 1 << 0, | ||
| 65 | Tail = 1 << 1, | ||
| 66 | LittleEndian = 1 << 2, | ||
| 67 | }; | ||
| 68 | DECLARE_ENUM_FLAG_OPERATORS(LogPacketFlags); | ||
| 18 | 69 | ||
| 19 | class ILogger final : public ServiceFramework<ILogger> { | 70 | class ILogger final : public ServiceFramework<ILogger> { |
| 20 | public: | 71 | public: |
| 21 | explicit ILogger(Core::System& system_) | 72 | explicit ILogger(Core::System& system_) : ServiceFramework{system_, "ILogger"} { |
| 22 | : ServiceFramework{system_, "ILogger"}, manager{system_.GetLogManager()}, | ||
| 23 | memory{system_.Memory()} { | ||
| 24 | static const FunctionInfo functions[] = { | 73 | static const FunctionInfo functions[] = { |
| 25 | {0, &ILogger::Log, "Log"}, | 74 | {0, &ILogger::Log, "Log"}, |
| 26 | {1, &ILogger::SetDestination, "SetDestination"}, | 75 | {1, &ILogger::SetDestination, "SetDestination"}, |
| @@ -30,54 +79,264 @@ public: | |||
| 30 | 79 | ||
| 31 | private: | 80 | private: |
| 32 | void Log(Kernel::HLERequestContext& ctx) { | 81 | void Log(Kernel::HLERequestContext& ctx) { |
| 82 | std::size_t offset{}; | ||
| 83 | const auto data = ctx.ReadBuffer(); | ||
| 84 | |||
| 33 | // This function only succeeds - Get that out of the way | 85 | // This function only succeeds - Get that out of the way |
| 34 | IPC::ResponseBuilder rb{ctx, 2}; | 86 | IPC::ResponseBuilder rb{ctx, 2}; |
| 35 | rb.Push(RESULT_SUCCESS); | 87 | rb.Push(RESULT_SUCCESS); |
| 36 | 88 | ||
| 37 | // Read MessageHeader, despite not doing anything with it right now | 89 | if (data.size() < sizeof(LogPacketHeader)) { |
| 38 | MessageHeader header{}; | 90 | LOG_ERROR(Service_LM, "Data size is too small for header! size={}", data.size()); |
| 39 | VAddr addr{ctx.BufferDescriptorX()[0].Address()}; | 91 | return; |
| 40 | const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size}; | 92 | } |
| 41 | memory.ReadBlock(addr, &header, sizeof(MessageHeader)); | ||
| 42 | addr += sizeof(MessageHeader); | ||
| 43 | |||
| 44 | FieldMap fields; | ||
| 45 | while (addr < end_addr) { | ||
| 46 | const auto field = static_cast<Field>(memory.Read8(addr++)); | ||
| 47 | const auto length = memory.Read8(addr++); | ||
| 48 | 93 | ||
| 49 | if (static_cast<Field>(memory.Read8(addr)) == Field::Skip) { | 94 | LogPacketHeader header{}; |
| 50 | ++addr; | 95 | std::memcpy(&header, data.data(), sizeof(LogPacketHeader)); |
| 51 | } | 96 | offset += sizeof(LogPacketHeader); |
| 52 | 97 | ||
| 53 | SCOPE_EXIT({ addr += length; }); | 98 | LogPacketHeaderEntry entry{ |
| 99 | .pid = header.pid, | ||
| 100 | .tid = header.tid, | ||
| 101 | .severity = header.severity, | ||
| 102 | .verbosity = header.verbosity, | ||
| 103 | }; | ||
| 54 | 104 | ||
| 55 | if (field == Field::Skip) { | 105 | if (True(header.flags & LogPacketFlags::Head)) { |
| 56 | continue; | 106 | std::vector<u8> tmp(data.size() - sizeof(LogPacketHeader)); |
| 107 | std::memcpy(tmp.data(), data.data() + offset, tmp.size()); | ||
| 108 | entries[entry] = std::move(tmp); | ||
| 109 | } else { | ||
| 110 | // Append to existing entry | ||
| 111 | if (!entries.contains(entry)) { | ||
| 112 | LOG_ERROR(Service_LM, "Log entry does not exist!"); | ||
| 113 | return; | ||
| 57 | } | 114 | } |
| 115 | std::vector<u8> tmp(data.size() - sizeof(LogPacketHeader)); | ||
| 58 | 116 | ||
| 59 | std::vector<u8> data(length); | 117 | auto& existing_entry = entries[entry]; |
| 60 | memory.ReadBlock(addr, data.data(), length); | 118 | const auto base = existing_entry.size(); |
| 61 | fields.emplace(field, std::move(data)); | 119 | existing_entry.resize(base + (data.size() - sizeof(LogPacketHeader))); |
| 120 | std::memcpy(existing_entry.data() + base, data.data() + offset, | ||
| 121 | (data.size() - sizeof(LogPacketHeader))); | ||
| 62 | } | 122 | } |
| 63 | 123 | ||
| 64 | manager.Log({header, std::move(fields)}); | 124 | if (True(header.flags & LogPacketFlags::Tail)) { |
| 125 | auto it = entries.find(entry); | ||
| 126 | if (it == entries.end()) { | ||
| 127 | LOG_ERROR(Service_LM, "Log entry does not exist!"); | ||
| 128 | return; | ||
| 129 | } | ||
| 130 | ParseLog(it->first, it->second); | ||
| 131 | entries.erase(it); | ||
| 132 | } | ||
| 65 | } | 133 | } |
| 66 | 134 | ||
| 67 | void SetDestination(Kernel::HLERequestContext& ctx) { | 135 | void SetDestination(Kernel::HLERequestContext& ctx) { |
| 68 | IPC::RequestParser rp{ctx}; | 136 | IPC::RequestParser rp{ctx}; |
| 69 | const auto destination = rp.PopEnum<DestinationFlag>(); | 137 | const auto log_destination = rp.PopEnum<LogDestination>(); |
| 70 | |||
| 71 | LOG_DEBUG(Service_LM, "called, destination={:08X}", destination); | ||
| 72 | 138 | ||
| 73 | manager.SetDestination(destination); | 139 | LOG_DEBUG(Service_LM, "called, destination={}", DestinationToString(log_destination)); |
| 140 | destination = log_destination; | ||
| 74 | 141 | ||
| 75 | IPC::ResponseBuilder rb{ctx, 2}; | 142 | IPC::ResponseBuilder rb{ctx, 2}; |
| 76 | rb.Push(RESULT_SUCCESS); | 143 | rb.Push(RESULT_SUCCESS); |
| 77 | } | 144 | } |
| 78 | 145 | ||
| 79 | Manager& manager; | 146 | u64 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) { |
| 80 | Core::Memory::Memory& memory; | 147 | u64 result{}; |
| 148 | u32 shift{}; | ||
| 149 | |||
| 150 | for (std::size_t i = 0; i < sizeof(u64); i++) { | ||
| 151 | const auto v = data[offset]; | ||
| 152 | result |= (static_cast<u64>(v & 0x7f) << shift); | ||
| 153 | shift += 7; | ||
| 154 | offset++; | ||
| 155 | if (offset >= data.size() || ((v & 0x80) == 0)) { | ||
| 156 | break; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | return result; | ||
| 160 | } | ||
| 161 | |||
| 162 | std::optional<std::string> ReadString(const std::vector<u8>& data, std::size_t& offset, | ||
| 163 | std::size_t length) { | ||
| 164 | if (length == 0) { | ||
| 165 | return std::nullopt; | ||
| 166 | } | ||
| 167 | const auto length_to_read = std::min(length, data.size() - offset); | ||
| 168 | |||
| 169 | std::string output(length_to_read, '\0'); | ||
| 170 | std::memcpy(output.data(), data.data() + offset, length_to_read); | ||
| 171 | offset += length_to_read; | ||
| 172 | return output; | ||
| 173 | } | ||
| 174 | |||
| 175 | u32_le ReadAsU32(const std::vector<u8>& data, std::size_t& offset, std::size_t length) { | ||
| 176 | ASSERT(length == sizeof(u32)); | ||
| 177 | u32_le output{}; | ||
| 178 | std::memcpy(&output, data.data() + offset, sizeof(u32)); | ||
| 179 | offset += length; | ||
| 180 | return output; | ||
| 181 | } | ||
| 182 | |||
| 183 | u64_le ReadAsU64(const std::vector<u8>& data, std::size_t& offset, std::size_t length) { | ||
| 184 | ASSERT(length == sizeof(u64)); | ||
| 185 | u64_le output{}; | ||
| 186 | std::memcpy(&output, data.data() + offset, sizeof(u64)); | ||
| 187 | offset += length; | ||
| 188 | return output; | ||
| 189 | } | ||
| 190 | |||
| 191 | void ParseLog(const LogPacketHeaderEntry entry, const std::vector<u8>& log_data) { | ||
| 192 | // Possible entries | ||
| 193 | std::optional<std::string> text_log; | ||
| 194 | std::optional<u32> line_number; | ||
| 195 | std::optional<std::string> file_name; | ||
| 196 | std::optional<std::string> function_name; | ||
| 197 | std::optional<std::string> module_name; | ||
| 198 | std::optional<std::string> thread_name; | ||
| 199 | std::optional<u64> log_pack_drop_count; | ||
| 200 | std::optional<s64> user_system_clock; | ||
| 201 | std::optional<std::string> process_name; | ||
| 202 | |||
| 203 | std::size_t offset{}; | ||
| 204 | while (offset < log_data.size()) { | ||
| 205 | const auto key = static_cast<LogDataChunkKey>(ReadLeb128(log_data, offset)); | ||
| 206 | const auto chunk_size = ReadLeb128(log_data, offset); | ||
| 207 | |||
| 208 | switch (key) { | ||
| 209 | case LogDataChunkKey::LogSessionBegin: | ||
| 210 | case LogDataChunkKey::LogSessionEnd: | ||
| 211 | break; | ||
| 212 | case LogDataChunkKey::TextLog: | ||
| 213 | text_log = ReadString(log_data, offset, chunk_size); | ||
| 214 | break; | ||
| 215 | case LogDataChunkKey::LineNumber: | ||
| 216 | line_number = ReadAsU32(log_data, offset, chunk_size); | ||
| 217 | break; | ||
| 218 | case LogDataChunkKey::FileName: | ||
| 219 | file_name = ReadString(log_data, offset, chunk_size); | ||
| 220 | break; | ||
| 221 | case LogDataChunkKey::FunctionName: | ||
| 222 | function_name = ReadString(log_data, offset, chunk_size); | ||
| 223 | break; | ||
| 224 | case LogDataChunkKey::ModuleName: | ||
| 225 | module_name = ReadString(log_data, offset, chunk_size); | ||
| 226 | break; | ||
| 227 | case LogDataChunkKey::ThreadName: | ||
| 228 | thread_name = ReadString(log_data, offset, chunk_size); | ||
| 229 | break; | ||
| 230 | case LogDataChunkKey::LogPacketDropCount: | ||
| 231 | log_pack_drop_count = ReadAsU64(log_data, offset, chunk_size); | ||
| 232 | break; | ||
| 233 | case LogDataChunkKey::UserSystemClock: | ||
| 234 | user_system_clock = ReadAsU64(log_data, offset, chunk_size); | ||
| 235 | break; | ||
| 236 | case LogDataChunkKey::ProcessName: | ||
| 237 | process_name = ReadString(log_data, offset, chunk_size); | ||
| 238 | break; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | std::string output_log{}; | ||
| 243 | if (process_name) { | ||
| 244 | output_log += fmt::format("Process: {}\n", *process_name); | ||
| 245 | } | ||
| 246 | if (module_name) { | ||
| 247 | output_log += fmt::format("Module: {}\n", *module_name); | ||
| 248 | } | ||
| 249 | if (file_name) { | ||
| 250 | output_log += fmt::format("File: {}\n", *file_name); | ||
| 251 | } | ||
| 252 | if (function_name) { | ||
| 253 | output_log += fmt::format("Function: {}\n", *function_name); | ||
| 254 | } | ||
| 255 | if (line_number && *line_number != 0) { | ||
| 256 | output_log += fmt::format("Line: {}\n", *line_number); | ||
| 257 | } | ||
| 258 | output_log += fmt::format("ProcessID: {:X}\n", entry.pid); | ||
| 259 | output_log += fmt::format("ThreadID: {:X}\n", entry.tid); | ||
| 260 | |||
| 261 | if (text_log) { | ||
| 262 | output_log += fmt::format("Log Text: {}\n", *text_log); | ||
| 263 | } | ||
| 264 | |||
| 265 | switch (entry.severity) { | ||
| 266 | case LogSeverity::Trace: | ||
| 267 | LOG_DEBUG(Service_LM, "LogManager TRACE ({}):\n{}", DestinationToString(destination), | ||
| 268 | output_log); | ||
| 269 | break; | ||
| 270 | case LogSeverity::Info: | ||
| 271 | LOG_INFO(Service_LM, "LogManager INFO ({}):\n{}", DestinationToString(destination), | ||
| 272 | output_log); | ||
| 273 | break; | ||
| 274 | case LogSeverity::Warning: | ||
| 275 | LOG_WARNING(Service_LM, "LogManager WARNING ({}):\n{}", | ||
| 276 | DestinationToString(destination), output_log); | ||
| 277 | break; | ||
| 278 | case LogSeverity::Error: | ||
| 279 | LOG_ERROR(Service_LM, "LogManager ERROR ({}):\n{}", DestinationToString(destination), | ||
| 280 | output_log); | ||
| 281 | break; | ||
| 282 | case LogSeverity::Fatal: | ||
| 283 | LOG_CRITICAL(Service_LM, "LogManager FATAL ({}):\n{}", DestinationToString(destination), | ||
| 284 | output_log); | ||
| 285 | break; | ||
| 286 | default: | ||
| 287 | LOG_CRITICAL(Service_LM, "LogManager UNKNOWN ({}):\n{}", | ||
| 288 | DestinationToString(destination), output_log); | ||
| 289 | break; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | static std::string DestinationToString(LogDestination destination) { | ||
| 294 | if (True(destination & LogDestination::All)) { | ||
| 295 | return "TargetManager | Uart | UartSleep"; | ||
| 296 | } | ||
| 297 | std::string output{}; | ||
| 298 | if (True(destination & LogDestination::TargetManager)) { | ||
| 299 | output += "| TargetManager"; | ||
| 300 | } | ||
| 301 | if (True(destination & LogDestination::Uart)) { | ||
| 302 | output += "| Uart"; | ||
| 303 | } | ||
| 304 | if (True(destination & LogDestination::UartSleep)) { | ||
| 305 | output += "| UartSleep"; | ||
| 306 | } | ||
| 307 | if (output.length() > 0) { | ||
| 308 | return output.substr(2); | ||
| 309 | } | ||
| 310 | return "No Destination"; | ||
| 311 | } | ||
| 312 | |||
| 313 | enum class LogDataChunkKey : u32 { | ||
| 314 | LogSessionBegin = 0, | ||
| 315 | LogSessionEnd = 1, | ||
| 316 | TextLog = 2, | ||
| 317 | LineNumber = 3, | ||
| 318 | FileName = 4, | ||
| 319 | FunctionName = 5, | ||
| 320 | ModuleName = 6, | ||
| 321 | ThreadName = 7, | ||
| 322 | LogPacketDropCount = 8, | ||
| 323 | UserSystemClock = 9, | ||
| 324 | ProcessName = 10, | ||
| 325 | }; | ||
| 326 | |||
| 327 | struct LogPacketHeader { | ||
| 328 | u64_le pid{}; | ||
| 329 | u64_le tid{}; | ||
| 330 | LogPacketFlags flags{}; | ||
| 331 | INSERT_PADDING_BYTES(1); | ||
| 332 | LogSeverity severity{}; | ||
| 333 | u8 verbosity{}; | ||
| 334 | u32_le payload_size{}; | ||
| 335 | }; | ||
| 336 | static_assert(sizeof(LogPacketHeader) == 0x18, "LogPacketHeader is an invalid size"); | ||
| 337 | |||
| 338 | std::unordered_map<LogPacketHeaderEntry, std::vector<u8>> entries{}; | ||
| 339 | LogDestination destination{LogDestination::All}; | ||
| 81 | }; | 340 | }; |
| 82 | 341 | ||
| 83 | class LM final : public ServiceFramework<LM> { | 342 | class LM final : public ServiceFramework<LM> { |
diff --git a/src/core/hle/service/lm/manager.cpp b/src/core/hle/service/lm/manager.cpp deleted file mode 100644 index 3ee2374e7..000000000 --- a/src/core/hle/service/lm/manager.cpp +++ /dev/null | |||
| @@ -1,134 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/string_util.h" | ||
| 8 | #include "core/hle/service/lm/manager.h" | ||
| 9 | #include "core/reporter.h" | ||
| 10 | |||
| 11 | namespace Service::LM { | ||
| 12 | |||
| 13 | std::ostream& operator<<(std::ostream& os, DestinationFlag dest) { | ||
| 14 | std::vector<std::string> array; | ||
| 15 | const auto check_single_flag = [dest, &array](DestinationFlag check, std::string name) { | ||
| 16 | if ((static_cast<u32>(check) & static_cast<u32>(dest)) != 0) { | ||
| 17 | array.emplace_back(std::move(name)); | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | check_single_flag(DestinationFlag::Default, "Default"); | ||
| 22 | check_single_flag(DestinationFlag::UART, "UART"); | ||
| 23 | check_single_flag(DestinationFlag::UARTSleeping, "UART (Sleeping)"); | ||
| 24 | |||
| 25 | os << "["; | ||
| 26 | for (const auto& entry : array) { | ||
| 27 | os << entry << ", "; | ||
| 28 | } | ||
| 29 | return os << "]"; | ||
| 30 | } | ||
| 31 | |||
| 32 | std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity) { | ||
| 33 | switch (severity) { | ||
| 34 | case MessageHeader::Severity::Trace: | ||
| 35 | return os << "Trace"; | ||
| 36 | case MessageHeader::Severity::Info: | ||
| 37 | return os << "Info"; | ||
| 38 | case MessageHeader::Severity::Warning: | ||
| 39 | return os << "Warning"; | ||
| 40 | case MessageHeader::Severity::Error: | ||
| 41 | return os << "Error"; | ||
| 42 | case MessageHeader::Severity::Critical: | ||
| 43 | return os << "Critical"; | ||
| 44 | default: | ||
| 45 | return os << fmt::format("{:08X}", static_cast<u32>(severity)); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | std::ostream& operator<<(std::ostream& os, Field field) { | ||
| 50 | switch (field) { | ||
| 51 | case Field::Skip: | ||
| 52 | return os << "Skip"; | ||
| 53 | case Field::Message: | ||
| 54 | return os << "Message"; | ||
| 55 | case Field::Line: | ||
| 56 | return os << "Line"; | ||
| 57 | case Field::Filename: | ||
| 58 | return os << "Filename"; | ||
| 59 | case Field::Function: | ||
| 60 | return os << "Function"; | ||
| 61 | case Field::Module: | ||
| 62 | return os << "Module"; | ||
| 63 | case Field::Thread: | ||
| 64 | return os << "Thread"; | ||
| 65 | default: | ||
| 66 | return os << fmt::format("{:08X}", static_cast<u32>(field)); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | std::string FormatField(Field type, const std::vector<u8>& data) { | ||
| 71 | switch (type) { | ||
| 72 | case Field::Skip: | ||
| 73 | return ""; | ||
| 74 | case Field::Line: | ||
| 75 | if (data.size() >= sizeof(u32)) { | ||
| 76 | u32 line; | ||
| 77 | std::memcpy(&line, data.data(), sizeof(u32)); | ||
| 78 | return fmt::format("{}", line); | ||
| 79 | } | ||
| 80 | return "[ERROR DECODING LINE NUMBER]"; | ||
| 81 | case Field::Message: | ||
| 82 | case Field::Filename: | ||
| 83 | case Field::Function: | ||
| 84 | case Field::Module: | ||
| 85 | case Field::Thread: | ||
| 86 | return Common::StringFromFixedZeroTerminatedBuffer( | ||
| 87 | reinterpret_cast<const char*>(data.data()), data.size()); | ||
| 88 | default: | ||
| 89 | UNIMPLEMENTED_MSG("Unimplemented field type={}", type); | ||
| 90 | return ""; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | Manager::Manager(Core::Reporter& reporter) : reporter(reporter) {} | ||
| 95 | |||
| 96 | Manager::~Manager() = default; | ||
| 97 | |||
| 98 | void Manager::SetEnabled(bool enabled) { | ||
| 99 | this->enabled = enabled; | ||
| 100 | } | ||
| 101 | |||
| 102 | void Manager::SetDestination(DestinationFlag destination) { | ||
| 103 | this->destination = destination; | ||
| 104 | } | ||
| 105 | |||
| 106 | void Manager::Log(LogMessage message) { | ||
| 107 | if (message.header.IsHeadLog()) { | ||
| 108 | InitializeLog(); | ||
| 109 | } | ||
| 110 | |||
| 111 | current_log.emplace_back(std::move(message)); | ||
| 112 | |||
| 113 | if (current_log.back().header.IsTailLog()) { | ||
| 114 | FinalizeLog(); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | void Manager::Flush() { | ||
| 119 | FinalizeLog(); | ||
| 120 | } | ||
| 121 | |||
| 122 | void Manager::InitializeLog() { | ||
| 123 | current_log.clear(); | ||
| 124 | |||
| 125 | LOG_INFO(Service_LM, "Initialized new log session"); | ||
| 126 | } | ||
| 127 | |||
| 128 | void Manager::FinalizeLog() { | ||
| 129 | reporter.SaveLogReport(static_cast<u32>(destination), std::move(current_log)); | ||
| 130 | |||
| 131 | LOG_INFO(Service_LM, "Finalized current log session"); | ||
| 132 | } | ||
| 133 | |||
| 134 | } // namespace Service::LM | ||
diff --git a/src/core/hle/service/lm/manager.h b/src/core/hle/service/lm/manager.h deleted file mode 100644 index 544e636ba..000000000 --- a/src/core/hle/service/lm/manager.h +++ /dev/null | |||
| @@ -1,106 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <map> | ||
| 8 | #include <ostream> | ||
| 9 | #include <vector> | ||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/swap.h" | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | class Reporter; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::LM { | ||
| 19 | |||
| 20 | enum class DestinationFlag : u32 { | ||
| 21 | Default = 1, | ||
| 22 | UART = 2, | ||
| 23 | UARTSleeping = 4, | ||
| 24 | |||
| 25 | All = 0xFFFF, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct MessageHeader { | ||
| 29 | enum Flags : u32_le { | ||
| 30 | IsHead = 1, | ||
| 31 | IsTail = 2, | ||
| 32 | }; | ||
| 33 | enum Severity : u32_le { | ||
| 34 | Trace, | ||
| 35 | Info, | ||
| 36 | Warning, | ||
| 37 | Error, | ||
| 38 | Critical, | ||
| 39 | }; | ||
| 40 | |||
| 41 | u64_le pid; | ||
| 42 | u64_le thread_context; | ||
| 43 | union { | ||
| 44 | BitField<0, 16, Flags> flags; | ||
| 45 | BitField<16, 8, Severity> severity; | ||
| 46 | BitField<24, 8, u32> verbosity; | ||
| 47 | }; | ||
| 48 | u32_le payload_size; | ||
| 49 | |||
| 50 | bool IsHeadLog() const { | ||
| 51 | return flags & IsHead; | ||
| 52 | } | ||
| 53 | bool IsTailLog() const { | ||
| 54 | return flags & IsTail; | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size"); | ||
| 58 | |||
| 59 | enum class Field : u8 { | ||
| 60 | Skip = 1, | ||
| 61 | Message = 2, | ||
| 62 | Line = 3, | ||
| 63 | Filename = 4, | ||
| 64 | Function = 5, | ||
| 65 | Module = 6, | ||
| 66 | Thread = 7, | ||
| 67 | }; | ||
| 68 | |||
| 69 | std::ostream& operator<<(std::ostream& os, DestinationFlag dest); | ||
| 70 | std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity); | ||
| 71 | std::ostream& operator<<(std::ostream& os, Field field); | ||
| 72 | |||
| 73 | using FieldMap = std::map<Field, std::vector<u8>>; | ||
| 74 | |||
| 75 | struct LogMessage { | ||
| 76 | MessageHeader header; | ||
| 77 | FieldMap fields; | ||
| 78 | }; | ||
| 79 | |||
| 80 | std::string FormatField(Field type, const std::vector<u8>& data); | ||
| 81 | |||
| 82 | class Manager { | ||
| 83 | public: | ||
| 84 | explicit Manager(Core::Reporter& reporter); | ||
| 85 | ~Manager(); | ||
| 86 | |||
| 87 | void SetEnabled(bool enabled); | ||
| 88 | void SetDestination(DestinationFlag destination); | ||
| 89 | |||
| 90 | void Log(LogMessage message); | ||
| 91 | |||
| 92 | void Flush(); | ||
| 93 | |||
| 94 | private: | ||
| 95 | void InitializeLog(); | ||
| 96 | void FinalizeLog(); | ||
| 97 | |||
| 98 | bool enabled = true; | ||
| 99 | DestinationFlag destination = DestinationFlag::All; | ||
| 100 | |||
| 101 | std::vector<LogMessage> current_log; | ||
| 102 | |||
| 103 | Core::Reporter& reporter; | ||
| 104 | }; | ||
| 105 | |||
| 106 | } // namespace Service::LM | ||
diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp index d73b90015..70350a2a3 100644 --- a/src/core/hle/service/mii/manager.cpp +++ b/src/core/hle/service/mii/manager.cpp | |||
| @@ -21,7 +21,7 @@ namespace { | |||
| 21 | 21 | ||
| 22 | constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; | 22 | constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; |
| 23 | 23 | ||
| 24 | constexpr std::size_t DefaultMiiCount{sizeof(RawData::DefaultMii) / sizeof(DefaultMii)}; | 24 | constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()}; |
| 25 | 25 | ||
| 26 | constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'}; | 26 | constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'}; |
| 27 | constexpr std::array<u8, 8> HairColorLookup{8, 1, 2, 3, 4, 5, 6, 7}; | 27 | constexpr std::array<u8, 8> HairColorLookup{8, 1, 2, 3, 4, 5, 6, 7}; |
| @@ -100,6 +100,7 @@ MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { | |||
| 100 | .mole_scale = static_cast<u8>(bf.mole_scale.Value()), | 100 | .mole_scale = static_cast<u8>(bf.mole_scale.Value()), |
| 101 | .mole_x = static_cast<u8>(bf.mole_x.Value()), | 101 | .mole_x = static_cast<u8>(bf.mole_x.Value()), |
| 102 | .mole_y = static_cast<u8>(bf.mole_y.Value()), | 102 | .mole_y = static_cast<u8>(bf.mole_y.Value()), |
| 103 | .padding = 0, | ||
| 103 | }; | 104 | }; |
| 104 | } | 105 | } |
| 105 | 106 | ||
| @@ -140,13 +141,6 @@ T GetRandomValue(T max) { | |||
| 140 | return GetRandomValue<T>({}, max); | 141 | return GetRandomValue<T>({}, max); |
| 141 | } | 142 | } |
| 142 | 143 | ||
| 143 | template <typename T> | ||
| 144 | T GetArrayValue(const u8* data, std::size_t index) { | ||
| 145 | T result{}; | ||
| 146 | std::memcpy(&result, &data[index * sizeof(T)], sizeof(T)); | ||
| 147 | return result; | ||
| 148 | } | ||
| 149 | |||
| 150 | MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { | 144 | MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { |
| 151 | MiiStoreBitFields bf{}; | 145 | MiiStoreBitFields bf{}; |
| 152 | 146 | ||
| @@ -192,32 +186,20 @@ MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Commo | |||
| 192 | const std::size_t index{3 * static_cast<std::size_t>(age) + | 186 | const std::size_t index{3 * static_cast<std::size_t>(age) + |
| 193 | 9 * static_cast<std::size_t>(gender) + static_cast<std::size_t>(race)}; | 187 | 9 * static_cast<std::size_t>(gender) + static_cast<std::size_t>(race)}; |
| 194 | 188 | ||
| 195 | const auto faceline_type_info{ | 189 | const auto faceline_type_info{RawData::RandomMiiFaceline.at(index)}; |
| 196 | GetArrayValue<RandomMiiData4>(&RawData::RandomMiiFaceline[0], index)}; | 190 | const auto faceline_color_info{RawData::RandomMiiFacelineColor.at( |
| 197 | const auto faceline_color_info{GetArrayValue<RandomMiiData3>( | ||
| 198 | RawData::RandomMiiFacelineColor.data(), | ||
| 199 | 3 * static_cast<std::size_t>(gender) + static_cast<std::size_t>(race))}; | 191 | 3 * static_cast<std::size_t>(gender) + static_cast<std::size_t>(race))}; |
| 200 | const auto faceline_wrinkle_info{ | 192 | const auto faceline_wrinkle_info{RawData::RandomMiiFacelineWrinkle.at(index)}; |
| 201 | GetArrayValue<RandomMiiData4>(RawData::RandomMiiFacelineWrinkle.data(), index)}; | 193 | const auto faceline_makeup_info{RawData::RandomMiiFacelineMakeup.at(index)}; |
| 202 | const auto faceline_makeup_info{ | 194 | const auto hair_type_info{RawData::RandomMiiHairType.at(index)}; |
| 203 | GetArrayValue<RandomMiiData4>(RawData::RandomMiiFacelineMakeup.data(), index)}; | 195 | const auto hair_color_info{RawData::RandomMiiHairColor.at(3 * static_cast<std::size_t>(race) + |
| 204 | const auto hair_type_info{ | 196 | static_cast<std::size_t>(age))}; |
| 205 | GetArrayValue<RandomMiiData4>(RawData::RandomMiiHairType.data(), index)}; | 197 | const auto eye_type_info{RawData::RandomMiiEyeType.at(index)}; |
| 206 | const auto hair_color_info{GetArrayValue<RandomMiiData3>(RawData::RandomMiiHairColor.data(), | 198 | const auto eye_color_info{RawData::RandomMiiEyeColor.at(static_cast<std::size_t>(race))}; |
| 207 | 3 * static_cast<std::size_t>(race) + | 199 | const auto eyebrow_type_info{RawData::RandomMiiEyebrowType.at(index)}; |
| 208 | static_cast<std::size_t>(age))}; | 200 | const auto nose_type_info{RawData::RandomMiiNoseType.at(index)}; |
| 209 | const auto eye_type_info{ | 201 | const auto mouth_type_info{RawData::RandomMiiMouthType.at(index)}; |
| 210 | GetArrayValue<RandomMiiData4>(RawData::RandomMiiEyeType.data(), index)}; | 202 | const auto glasses_type_info{RawData::RandomMiiGlassType.at(static_cast<std::size_t>(age))}; |
| 211 | const auto eye_color_info{GetArrayValue<RandomMiiData2>(RawData::RandomMiiEyeColor.data(), | ||
| 212 | static_cast<std::size_t>(race))}; | ||
| 213 | const auto eyebrow_type_info{ | ||
| 214 | GetArrayValue<RandomMiiData4>(RawData::RandomMiiEyebrowType.data(), index)}; | ||
| 215 | const auto nose_type_info{ | ||
| 216 | GetArrayValue<RandomMiiData4>(RawData::RandomMiiNoseType.data(), index)}; | ||
| 217 | const auto mouth_type_info{ | ||
| 218 | GetArrayValue<RandomMiiData4>(RawData::RandomMiiMouthType.data(), index)}; | ||
| 219 | const auto glasses_type_info{GetArrayValue<RandomMiiData2>(RawData::RandomMiiGlassType.data(), | ||
| 220 | static_cast<std::size_t>(age))}; | ||
| 221 | 203 | ||
| 222 | bf.faceline_type.Assign( | 204 | bf.faceline_type.Assign( |
| 223 | faceline_type_info.values[GetRandomValue<std::size_t>(faceline_type_info.values_count)]); | 205 | faceline_type_info.values[GetRandomValue<std::size_t>(faceline_type_info.values_count)]); |
| @@ -454,8 +436,7 @@ MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { | |||
| 454 | } | 436 | } |
| 455 | 437 | ||
| 456 | MiiInfo MiiManager::BuildDefault(std::size_t index) { | 438 | MiiInfo MiiManager::BuildDefault(std::size_t index) { |
| 457 | return ConvertStoreDataToInfo(BuildDefaultStoreData( | 439 | return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); |
| 458 | GetArrayValue<DefaultMii>(RawData::DefaultMii.data(), index), user_id)); | ||
| 459 | } | 440 | } |
| 460 | 441 | ||
| 461 | ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { | 442 | ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { |
diff --git a/src/core/hle/service/mii/manager.h b/src/core/hle/service/mii/manager.h index 927451dea..2106a528a 100644 --- a/src/core/hle/service/mii/manager.h +++ b/src/core/hle/service/mii/manager.h | |||
| @@ -27,58 +27,58 @@ enum class SourceFlag : u32 { | |||
| 27 | DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); | 27 | DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); |
| 28 | 28 | ||
| 29 | struct MiiInfo { | 29 | struct MiiInfo { |
| 30 | Common::UUID uuid{Common::INVALID_UUID}; | 30 | Common::UUID uuid; |
| 31 | std::array<char16_t, 11> name{}; | 31 | std::array<char16_t, 11> name; |
| 32 | u8 font_region{}; | 32 | u8 font_region; |
| 33 | u8 favorite_color{}; | 33 | u8 favorite_color; |
| 34 | u8 gender{}; | 34 | u8 gender; |
| 35 | u8 height{}; | 35 | u8 height; |
| 36 | u8 build{}; | 36 | u8 build; |
| 37 | u8 type{}; | 37 | u8 type; |
| 38 | u8 region_move{}; | 38 | u8 region_move; |
| 39 | u8 faceline_type{}; | 39 | u8 faceline_type; |
| 40 | u8 faceline_color{}; | 40 | u8 faceline_color; |
| 41 | u8 faceline_wrinkle{}; | 41 | u8 faceline_wrinkle; |
| 42 | u8 faceline_make{}; | 42 | u8 faceline_make; |
| 43 | u8 hair_type{}; | 43 | u8 hair_type; |
| 44 | u8 hair_color{}; | 44 | u8 hair_color; |
| 45 | u8 hair_flip{}; | 45 | u8 hair_flip; |
| 46 | u8 eye_type{}; | 46 | u8 eye_type; |
| 47 | u8 eye_color{}; | 47 | u8 eye_color; |
| 48 | u8 eye_scale{}; | 48 | u8 eye_scale; |
| 49 | u8 eye_aspect{}; | 49 | u8 eye_aspect; |
| 50 | u8 eye_rotate{}; | 50 | u8 eye_rotate; |
| 51 | u8 eye_x{}; | 51 | u8 eye_x; |
| 52 | u8 eye_y{}; | 52 | u8 eye_y; |
| 53 | u8 eyebrow_type{}; | 53 | u8 eyebrow_type; |
| 54 | u8 eyebrow_color{}; | 54 | u8 eyebrow_color; |
| 55 | u8 eyebrow_scale{}; | 55 | u8 eyebrow_scale; |
| 56 | u8 eyebrow_aspect{}; | 56 | u8 eyebrow_aspect; |
| 57 | u8 eyebrow_rotate{}; | 57 | u8 eyebrow_rotate; |
| 58 | u8 eyebrow_x{}; | 58 | u8 eyebrow_x; |
| 59 | u8 eyebrow_y{}; | 59 | u8 eyebrow_y; |
| 60 | u8 nose_type{}; | 60 | u8 nose_type; |
| 61 | u8 nose_scale{}; | 61 | u8 nose_scale; |
| 62 | u8 nose_y{}; | 62 | u8 nose_y; |
| 63 | u8 mouth_type{}; | 63 | u8 mouth_type; |
| 64 | u8 mouth_color{}; | 64 | u8 mouth_color; |
| 65 | u8 mouth_scale{}; | 65 | u8 mouth_scale; |
| 66 | u8 mouth_aspect{}; | 66 | u8 mouth_aspect; |
| 67 | u8 mouth_y{}; | 67 | u8 mouth_y; |
| 68 | u8 beard_color{}; | 68 | u8 beard_color; |
| 69 | u8 beard_type{}; | 69 | u8 beard_type; |
| 70 | u8 mustache_type{}; | 70 | u8 mustache_type; |
| 71 | u8 mustache_scale{}; | 71 | u8 mustache_scale; |
| 72 | u8 mustache_y{}; | 72 | u8 mustache_y; |
| 73 | u8 glasses_type{}; | 73 | u8 glasses_type; |
| 74 | u8 glasses_color{}; | 74 | u8 glasses_color; |
| 75 | u8 glasses_scale{}; | 75 | u8 glasses_scale; |
| 76 | u8 glasses_y{}; | 76 | u8 glasses_y; |
| 77 | u8 mole_type{}; | 77 | u8 mole_type; |
| 78 | u8 mole_scale{}; | 78 | u8 mole_scale; |
| 79 | u8 mole_x{}; | 79 | u8 mole_x; |
| 80 | u8 mole_y{}; | 80 | u8 mole_y; |
| 81 | INSERT_PADDING_BYTES(1); | 81 | u8 padding; |
| 82 | 82 | ||
| 83 | std::u16string Name() const; | 83 | std::u16string Name() const; |
| 84 | }; | 84 | }; |
| @@ -233,7 +233,7 @@ struct RandomMiiData4 { | |||
| 233 | Age age{}; | 233 | Age age{}; |
| 234 | Race race{}; | 234 | Race race{}; |
| 235 | u32 values_count{}; | 235 | u32 values_count{}; |
| 236 | std::array<u8, 0xbc> values{}; | 236 | std::array<u32, 47> values{}; |
| 237 | }; | 237 | }; |
| 238 | static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size."); | 238 | static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size."); |
| 239 | 239 | ||
| @@ -241,14 +241,14 @@ struct RandomMiiData3 { | |||
| 241 | u32 arg_1; | 241 | u32 arg_1; |
| 242 | u32 arg_2; | 242 | u32 arg_2; |
| 243 | u32 values_count; | 243 | u32 values_count; |
| 244 | std::array<u8, 0xbc> values{}; | 244 | std::array<u32, 47> values{}; |
| 245 | }; | 245 | }; |
| 246 | static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size."); | 246 | static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size."); |
| 247 | 247 | ||
| 248 | struct RandomMiiData2 { | 248 | struct RandomMiiData2 { |
| 249 | u32 arg_1; | 249 | u32 arg_1; |
| 250 | u32 values_count; | 250 | u32 values_count; |
| 251 | std::array<u8, 0xbc> values{}; | 251 | std::array<u32, 47> values{}; |
| 252 | }; | 252 | }; |
| 253 | static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size."); | 253 | static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size."); |
| 254 | 254 | ||
| @@ -324,7 +324,7 @@ public: | |||
| 324 | ResultCode GetIndex(const MiiInfo& info, u32& index); | 324 | ResultCode GetIndex(const MiiInfo& info, u32& index); |
| 325 | 325 | ||
| 326 | private: | 326 | private: |
| 327 | const Common::UUID user_id; | 327 | const Common::UUID user_id{Common::INVALID_UUID}; |
| 328 | u64 update_counter{}; | 328 | u64 update_counter{}; |
| 329 | }; | 329 | }; |
| 330 | 330 | ||
diff --git a/src/core/hle/service/mii/raw_data.cpp b/src/core/hle/service/mii/raw_data.cpp index 25d7bae0c..9d3c8017a 100644 --- a/src/core/hle/service/mii/raw_data.cpp +++ b/src/core/hle/service/mii/raw_data.cpp | |||
| @@ -22,2240 +22,1642 @@ | |||
| 22 | 22 | ||
| 23 | namespace Service::Mii::RawData { | 23 | namespace Service::Mii::RawData { |
| 24 | 24 | ||
| 25 | const std::array<u8, 1728> DefaultMii{ | 25 | const std::array<Service::Mii::DefaultMii, 8> DefaultMii{ |
| 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 26 | Service::Mii::DefaultMii{ |
| 27 | 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 27 | .face_type = 0, |
| 28 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 28 | .face_color = 0, |
| 29 | 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 29 | .face_wrinkle = 0, |
| 30 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 30 | .face_makeup = 0, |
| 31 | 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 31 | .hair_type = 33, |
| 32 | 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 32 | .hair_color = 1, |
| 33 | 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 33 | .hair_flip = 0, |
| 34 | 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 34 | .eye_type = 2, |
| 35 | 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 35 | .eye_color = 0, |
| 36 | 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | 36 | .eye_scale = 4, |
| 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 37 | .eye_aspect = 3, |
| 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 38 | .eye_rotate = 4, |
| 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 39 | .eye_x = 2, |
| 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 40 | .eye_y = 12, |
| 41 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 41 | .eyebrow_type = 6, |
| 42 | 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | 42 | .eyebrow_color = 1, |
| 43 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 43 | .eyebrow_scale = 4, |
| 44 | 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 44 | .eyebrow_aspect = 3, |
| 45 | 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 45 | .eyebrow_rotate = 6, |
| 46 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 46 | .eyebrow_x = 2, |
| 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 47 | .eyebrow_y = 10, |
| 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 48 | .nose_type = 1, |
| 49 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | 49 | .nose_scale = 4, |
| 50 | 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 50 | .nose_y = 9, |
| 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 51 | .mouth_type = 23, |
| 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 52 | .mouth_color = 0, |
| 53 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 53 | .mouth_scale = 4, |
| 54 | 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 54 | .mouth_aspect = 3, |
| 55 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 55 | .mouth_y = 13, |
| 56 | 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 56 | .mustache_type = 0, |
| 57 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 57 | .beard_type = 0, |
| 58 | 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 58 | .beard_color = 0, |
| 59 | 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 59 | .mustache_scale = 4, |
| 60 | 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 60 | .mustache_y = 10, |
| 61 | 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 61 | .glasses_type = 0, |
| 62 | 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 62 | .glasses_color = 0, |
| 63 | 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | 63 | .glasses_scale = 4, |
| 64 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 64 | .glasses_y = 10, |
| 65 | 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, | 65 | .mole_type = 0, |
| 66 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 66 | .mole_scale = 4, |
| 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 67 | .mole_x = 2, |
| 68 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 68 | .mole_y = 20, |
| 69 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | 69 | .height = 64, |
| 70 | 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 70 | .weight = 64, |
| 71 | 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 71 | .gender = Gender::Male, |
| 72 | 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 72 | .favorite_color = 0, |
| 73 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 73 | .region = 0, |
| 74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 74 | .font_region = FontRegion::Standard, |
| 75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 75 | .type = 0, |
| 76 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | 76 | }, |
| 77 | 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | 77 | Service::Mii::DefaultMii{ |
| 78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, | 78 | .face_type = 0, |
| 79 | 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 79 | .face_color = 0, |
| 80 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 80 | .face_wrinkle = 0, |
| 81 | 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 81 | .face_makeup = 0, |
| 82 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 82 | .hair_type = 12, |
| 83 | 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 83 | .hair_color = 1, |
| 84 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 84 | .hair_flip = 0, |
| 85 | 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 85 | .eye_type = 4, |
| 86 | 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 86 | .eye_color = 0, |
| 87 | 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 87 | .eye_scale = 4, |
| 88 | 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 88 | .eye_aspect = 3, |
| 89 | 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 89 | .eye_rotate = 3, |
| 90 | 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | 90 | .eye_x = 2, |
| 91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 91 | .eye_y = 12, |
| 92 | 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, | 92 | .eyebrow_type = 0, |
| 93 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 93 | .eyebrow_color = 1, |
| 94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 94 | .eyebrow_scale = 4, |
| 95 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 95 | .eyebrow_aspect = 3, |
| 96 | 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | 96 | .eyebrow_rotate = 6, |
| 97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 97 | .eyebrow_x = 2, |
| 98 | 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 98 | .eyebrow_y = 10, |
| 99 | 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 99 | .nose_type = 1, |
| 100 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 100 | .nose_scale = 4, |
| 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 101 | .nose_y = 9, |
| 102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 102 | .mouth_type = 23, |
| 103 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | 103 | .mouth_color = 0, |
| 104 | 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 104 | .mouth_scale = 4, |
| 105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, | 105 | .mouth_aspect = 3, |
| 106 | 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 106 | .mouth_y = 13, |
| 107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 107 | .mustache_type = 0, |
| 108 | 0x0e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 108 | .beard_type = 0, |
| 109 | 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 109 | .beard_color = 0, |
| 110 | 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 110 | .mustache_scale = 4, |
| 111 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 111 | .mustache_y = 10, |
| 112 | 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 112 | .glasses_type = 0, |
| 113 | 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 113 | .glasses_color = 0, |
| 114 | 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 114 | .glasses_scale = 4, |
| 115 | 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 115 | .glasses_y = 10, |
| 116 | 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 116 | .mole_type = 0, |
| 117 | 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | 117 | .mole_scale = 4, |
| 118 | 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 118 | .mole_x = 2, |
| 119 | 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, | 119 | .mole_y = 20, |
| 120 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 120 | .height = 64, |
| 121 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 121 | .weight = 64, |
| 122 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 122 | .gender = Gender::Female, |
| 123 | 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | 123 | .favorite_color = 0, |
| 124 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 124 | .region = 0, |
| 125 | 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 125 | .font_region = FontRegion::Standard, |
| 126 | 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 126 | .type = 0, |
| 127 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 127 | }, |
| 128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 128 | Service::Mii::DefaultMii{ |
| 129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 129 | .face_type = 0, |
| 130 | 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | 130 | .face_color = 4, |
| 131 | 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 131 | .face_wrinkle = 0, |
| 132 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, | 132 | .face_makeup = 0, |
| 133 | 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | 133 | .hair_type = 68, |
| 134 | .hair_color = 0, | ||
| 135 | .hair_flip = 0, | ||
| 136 | .eye_type = 2, | ||
| 137 | .eye_color = 0, | ||
| 138 | .eye_scale = 4, | ||
| 139 | .eye_aspect = 3, | ||
| 140 | .eye_rotate = 4, | ||
| 141 | .eye_x = 2, | ||
| 142 | .eye_y = 12, | ||
| 143 | .eyebrow_type = 6, | ||
| 144 | .eyebrow_color = 0, | ||
| 145 | .eyebrow_scale = 4, | ||
| 146 | .eyebrow_aspect = 3, | ||
| 147 | .eyebrow_rotate = 6, | ||
| 148 | .eyebrow_x = 2, | ||
| 149 | .eyebrow_y = 10, | ||
| 150 | .nose_type = 1, | ||
| 151 | .nose_scale = 4, | ||
| 152 | .nose_y = 9, | ||
| 153 | .mouth_type = 23, | ||
| 154 | .mouth_color = 0, | ||
| 155 | .mouth_scale = 4, | ||
| 156 | .mouth_aspect = 3, | ||
| 157 | .mouth_y = 13, | ||
| 158 | .mustache_type = 0, | ||
| 159 | .beard_type = 0, | ||
| 160 | .beard_color = 0, | ||
| 161 | .mustache_scale = 4, | ||
| 162 | .mustache_y = 10, | ||
| 163 | .glasses_type = 0, | ||
| 164 | .glasses_color = 0, | ||
| 165 | .glasses_scale = 4, | ||
| 166 | .glasses_y = 10, | ||
| 167 | .mole_type = 0, | ||
| 168 | .mole_scale = 4, | ||
| 169 | .mole_x = 2, | ||
| 170 | .mole_y = 20, | ||
| 171 | .height = 64, | ||
| 172 | .weight = 64, | ||
| 173 | .gender = Gender::Male, | ||
| 174 | .favorite_color = 4, | ||
| 175 | .region = 0, | ||
| 176 | .font_region = FontRegion::Standard, | ||
| 177 | .type = 0, | ||
| 178 | }, | ||
| 179 | Service::Mii::DefaultMii{ | ||
| 180 | .face_type = 0, | ||
| 181 | .face_color = 0, | ||
| 182 | .face_wrinkle = 0, | ||
| 183 | .face_makeup = 0, | ||
| 184 | .hair_type = 55, | ||
| 185 | .hair_color = 6, | ||
| 186 | .hair_flip = 0, | ||
| 187 | .eye_type = 2, | ||
| 188 | .eye_color = 4, | ||
| 189 | .eye_scale = 4, | ||
| 190 | .eye_aspect = 3, | ||
| 191 | .eye_rotate = 4, | ||
| 192 | .eye_x = 2, | ||
| 193 | .eye_y = 12, | ||
| 194 | .eyebrow_type = 6, | ||
| 195 | .eyebrow_color = 6, | ||
| 196 | .eyebrow_scale = 4, | ||
| 197 | .eyebrow_aspect = 3, | ||
| 198 | .eyebrow_rotate = 6, | ||
| 199 | .eyebrow_x = 2, | ||
| 200 | .eyebrow_y = 10, | ||
| 201 | .nose_type = 1, | ||
| 202 | .nose_scale = 4, | ||
| 203 | .nose_y = 9, | ||
| 204 | .mouth_type = 23, | ||
| 205 | .mouth_color = 0, | ||
| 206 | .mouth_scale = 4, | ||
| 207 | .mouth_aspect = 3, | ||
| 208 | .mouth_y = 13, | ||
| 209 | .mustache_type = 0, | ||
| 210 | .beard_type = 0, | ||
| 211 | .beard_color = 0, | ||
| 212 | .mustache_scale = 4, | ||
| 213 | .mustache_y = 10, | ||
| 214 | .glasses_type = 0, | ||
| 215 | .glasses_color = 0, | ||
| 216 | .glasses_scale = 4, | ||
| 217 | .glasses_y = 10, | ||
| 218 | .mole_type = 0, | ||
| 219 | .mole_scale = 4, | ||
| 220 | .mole_x = 2, | ||
| 221 | .mole_y = 20, | ||
| 222 | .height = 64, | ||
| 223 | .weight = 64, | ||
| 224 | .gender = Gender::Male, | ||
| 225 | .favorite_color = 5, | ||
| 226 | .region = 0, | ||
| 227 | .font_region = FontRegion::Standard, | ||
| 228 | .type = 0, | ||
| 229 | }, | ||
| 230 | Service::Mii::DefaultMii{ | ||
| 231 | .face_type = 0, | ||
| 232 | .face_color = 1, | ||
| 233 | .face_wrinkle = 0, | ||
| 234 | .face_makeup = 0, | ||
| 235 | .hair_type = 33, | ||
| 236 | .hair_color = 1, | ||
| 237 | .hair_flip = 0, | ||
| 238 | .eye_type = 2, | ||
| 239 | .eye_color = 0, | ||
| 240 | .eye_scale = 4, | ||
| 241 | .eye_aspect = 3, | ||
| 242 | .eye_rotate = 4, | ||
| 243 | .eye_x = 2, | ||
| 244 | .eye_y = 12, | ||
| 245 | .eyebrow_type = 6, | ||
| 246 | .eyebrow_color = 1, | ||
| 247 | .eyebrow_scale = 4, | ||
| 248 | .eyebrow_aspect = 3, | ||
| 249 | .eyebrow_rotate = 6, | ||
| 250 | .eyebrow_x = 2, | ||
| 251 | .eyebrow_y = 10, | ||
| 252 | .nose_type = 1, | ||
| 253 | .nose_scale = 4, | ||
| 254 | .nose_y = 9, | ||
| 255 | .mouth_type = 23, | ||
| 256 | .mouth_color = 0, | ||
| 257 | .mouth_scale = 4, | ||
| 258 | .mouth_aspect = 3, | ||
| 259 | .mouth_y = 13, | ||
| 260 | .mustache_type = 0, | ||
| 261 | .beard_type = 0, | ||
| 262 | .beard_color = 0, | ||
| 263 | .mustache_scale = 4, | ||
| 264 | .mustache_y = 10, | ||
| 265 | .glasses_type = 0, | ||
| 266 | .glasses_color = 0, | ||
| 267 | .glasses_scale = 4, | ||
| 268 | .glasses_y = 10, | ||
| 269 | .mole_type = 0, | ||
| 270 | .mole_scale = 4, | ||
| 271 | .mole_x = 2, | ||
| 272 | .mole_y = 20, | ||
| 273 | .height = 64, | ||
| 274 | .weight = 64, | ||
| 275 | .gender = Gender::Male, | ||
| 276 | .favorite_color = 0, | ||
| 277 | .region = 0, | ||
| 278 | .font_region = FontRegion::Standard, | ||
| 279 | .type = 0, | ||
| 280 | }, | ||
| 281 | Service::Mii::DefaultMii{ | ||
| 282 | .face_type = 0, | ||
| 283 | .face_color = 2, | ||
| 284 | .face_wrinkle = 0, | ||
| 285 | .face_makeup = 0, | ||
| 286 | .hair_type = 24, | ||
| 287 | .hair_color = 0, | ||
| 288 | .hair_flip = 0, | ||
| 289 | .eye_type = 4, | ||
| 290 | .eye_color = 0, | ||
| 291 | .eye_scale = 4, | ||
| 292 | .eye_aspect = 3, | ||
| 293 | .eye_rotate = 3, | ||
| 294 | .eye_x = 2, | ||
| 295 | .eye_y = 12, | ||
| 296 | .eyebrow_type = 0, | ||
| 297 | .eyebrow_color = 0, | ||
| 298 | .eyebrow_scale = 4, | ||
| 299 | .eyebrow_aspect = 3, | ||
| 300 | .eyebrow_rotate = 6, | ||
| 301 | .eyebrow_x = 2, | ||
| 302 | .eyebrow_y = 10, | ||
| 303 | .nose_type = 1, | ||
| 304 | .nose_scale = 4, | ||
| 305 | .nose_y = 9, | ||
| 306 | .mouth_type = 23, | ||
| 307 | .mouth_color = 0, | ||
| 308 | .mouth_scale = 4, | ||
| 309 | .mouth_aspect = 3, | ||
| 310 | .mouth_y = 13, | ||
| 311 | .mustache_type = 0, | ||
| 312 | .beard_type = 0, | ||
| 313 | .beard_color = 0, | ||
| 314 | .mustache_scale = 4, | ||
| 315 | .mustache_y = 10, | ||
| 316 | .glasses_type = 0, | ||
| 317 | .glasses_color = 0, | ||
| 318 | .glasses_scale = 4, | ||
| 319 | .glasses_y = 10, | ||
| 320 | .mole_type = 0, | ||
| 321 | .mole_scale = 4, | ||
| 322 | .mole_x = 2, | ||
| 323 | .mole_y = 20, | ||
| 324 | .height = 64, | ||
| 325 | .weight = 64, | ||
| 326 | .gender = Gender::Female, | ||
| 327 | .favorite_color = 2, | ||
| 328 | .region = 0, | ||
| 329 | .font_region = FontRegion::Standard, | ||
| 330 | .type = 0, | ||
| 331 | }, | ||
| 332 | Service::Mii::DefaultMii{ | ||
| 333 | .face_type = 0, | ||
| 334 | .face_color = 0, | ||
| 335 | .face_wrinkle = 0, | ||
| 336 | .face_makeup = 0, | ||
| 337 | .hair_type = 14, | ||
| 338 | .hair_color = 7, | ||
| 339 | .hair_flip = 0, | ||
| 340 | .eye_type = 4, | ||
| 341 | .eye_color = 5, | ||
| 342 | .eye_scale = 4, | ||
| 343 | .eye_aspect = 3, | ||
| 344 | .eye_rotate = 3, | ||
| 345 | .eye_x = 2, | ||
| 346 | .eye_y = 12, | ||
| 347 | .eyebrow_type = 0, | ||
| 348 | .eyebrow_color = 7, | ||
| 349 | .eyebrow_scale = 4, | ||
| 350 | .eyebrow_aspect = 3, | ||
| 351 | .eyebrow_rotate = 6, | ||
| 352 | .eyebrow_x = 2, | ||
| 353 | .eyebrow_y = 10, | ||
| 354 | .nose_type = 1, | ||
| 355 | .nose_scale = 4, | ||
| 356 | .nose_y = 9, | ||
| 357 | .mouth_type = 23, | ||
| 358 | .mouth_color = 0, | ||
| 359 | .mouth_scale = 4, | ||
| 360 | .mouth_aspect = 3, | ||
| 361 | .mouth_y = 13, | ||
| 362 | .mustache_type = 0, | ||
| 363 | .beard_type = 0, | ||
| 364 | .beard_color = 0, | ||
| 365 | .mustache_scale = 4, | ||
| 366 | .mustache_y = 10, | ||
| 367 | .glasses_type = 0, | ||
| 368 | .glasses_color = 0, | ||
| 369 | .glasses_scale = 4, | ||
| 370 | .glasses_y = 10, | ||
| 371 | .mole_type = 0, | ||
| 372 | .mole_scale = 4, | ||
| 373 | .mole_x = 2, | ||
| 374 | .mole_y = 20, | ||
| 375 | .height = 64, | ||
| 376 | .weight = 64, | ||
| 377 | .gender = Gender::Female, | ||
| 378 | .favorite_color = 6, | ||
| 379 | .region = 0, | ||
| 380 | .font_region = FontRegion::Standard, | ||
| 381 | .type = 0, | ||
| 382 | }, | ||
| 383 | Service::Mii::DefaultMii{ | ||
| 384 | .face_type = 0, | ||
| 385 | .face_color = 0, | ||
| 386 | .face_wrinkle = 0, | ||
| 387 | .face_makeup = 0, | ||
| 388 | .hair_type = 12, | ||
| 389 | .hair_color = 1, | ||
| 390 | .hair_flip = 0, | ||
| 391 | .eye_type = 4, | ||
| 392 | .eye_color = 0, | ||
| 393 | .eye_scale = 4, | ||
| 394 | .eye_aspect = 3, | ||
| 395 | .eye_rotate = 3, | ||
| 396 | .eye_x = 2, | ||
| 397 | .eye_y = 12, | ||
| 398 | .eyebrow_type = 0, | ||
| 399 | .eyebrow_color = 1, | ||
| 400 | .eyebrow_scale = 4, | ||
| 401 | .eyebrow_aspect = 3, | ||
| 402 | .eyebrow_rotate = 6, | ||
| 403 | .eyebrow_x = 2, | ||
| 404 | .eyebrow_y = 10, | ||
| 405 | .nose_type = 1, | ||
| 406 | .nose_scale = 4, | ||
| 407 | .nose_y = 9, | ||
| 408 | .mouth_type = 23, | ||
| 409 | .mouth_color = 0, | ||
| 410 | .mouth_scale = 4, | ||
| 411 | .mouth_aspect = 3, | ||
| 412 | .mouth_y = 13, | ||
| 413 | .mustache_type = 0, | ||
| 414 | .beard_type = 0, | ||
| 415 | .beard_color = 0, | ||
| 416 | .mustache_scale = 4, | ||
| 417 | .mustache_y = 10, | ||
| 418 | .glasses_type = 0, | ||
| 419 | .glasses_color = 0, | ||
| 420 | .glasses_scale = 4, | ||
| 421 | .glasses_y = 10, | ||
| 422 | .mole_type = 0, | ||
| 423 | .mole_scale = 4, | ||
| 424 | .mole_x = 2, | ||
| 425 | .mole_y = 20, | ||
| 426 | .height = 64, | ||
| 427 | .weight = 64, | ||
| 428 | .gender = Gender::Female, | ||
| 429 | .favorite_color = 7, | ||
| 430 | .region = 0, | ||
| 431 | .font_region = FontRegion::Standard, | ||
| 432 | .type = 0, | ||
| 433 | }, | ||
| 134 | 434 | ||
| 135 | const std::array<u8, 3672> RandomMiiFaceline{ | 435 | }; |
| 136 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 137 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 138 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 139 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 143 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 144 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 149 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 150 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 151 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 152 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 159 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 162 | 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 163 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 164 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 171 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 172 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 174 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 175 | 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 176 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 177 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 178 | 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 182 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 187 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 188 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 189 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 190 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 191 | 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 195 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 196 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 197 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 200 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 201 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 202 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 203 | 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 206 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 207 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 208 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 209 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 213 | 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 214 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 215 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 216 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 220 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 221 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 222 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 226 | 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 227 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 228 | 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 229 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 231 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 234 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 238 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 240 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 241 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 242 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 243 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 245 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 246 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 247 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 248 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 249 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 251 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 252 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 253 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 254 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 255 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 256 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 257 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 258 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 259 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 260 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 261 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 262 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 263 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 264 | 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 265 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 266 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 267 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 268 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 269 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 270 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 271 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 272 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 273 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 274 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 275 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 276 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 277 | 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 278 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 279 | 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 280 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 281 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 282 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 283 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 284 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 285 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 286 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 287 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 288 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 289 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 290 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 291 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 292 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 293 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 294 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 295 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 296 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 297 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 298 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 299 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 300 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 302 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 303 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 304 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 305 | 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 306 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 307 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 308 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 309 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 310 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 311 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 312 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 313 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 314 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 315 | 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 316 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 317 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 318 | 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 319 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 320 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 321 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 322 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 323 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 324 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 325 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 326 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 327 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 328 | 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 329 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 330 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 331 | 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 332 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 333 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 334 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 335 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 336 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 337 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 338 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 339 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 340 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 341 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 342 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 343 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 344 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 345 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 346 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 347 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 348 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 349 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 350 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 351 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 352 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 353 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 354 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 355 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 356 | 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 357 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 358 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 359 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 360 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 361 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 362 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 363 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 364 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 365 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 366 | 436 | ||
| 367 | const std::array<u8, 1200> RandomMiiFacelineColor{ | 437 | const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFaceline{ |
| 368 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 438 | Service::Mii::RandomMiiData4{ |
| 369 | 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 439 | .gender = Gender::Male, |
| 370 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | 440 | .age = Age::Young, |
| 371 | 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 441 | .race = Race::Black, |
| 372 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 442 | .values_count = 10, |
| 373 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 443 | .values = {0, 0, 1, 1, 2, 3, 4, 5, 9, 9}, |
| 374 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 444 | }, |
| 375 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 445 | Service::Mii::RandomMiiData4{ |
| 376 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 446 | .gender = Gender::Male, |
| 377 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 447 | .age = Age::Normal, |
| 378 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 448 | .race = Race::Black, |
| 379 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 449 | .values_count = 10, |
| 380 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 450 | .values = {0, 0, 1, 1, 2, 3, 4, 5, 9, 9}, |
| 381 | 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 451 | }, |
| 382 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 452 | Service::Mii::RandomMiiData4{ |
| 383 | 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 453 | .gender = Gender::Male, |
| 384 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 454 | .age = Age::Old, |
| 385 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 455 | .race = Race::Black, |
| 386 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 456 | .values_count = 10, |
| 387 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 457 | .values = {0, 0, 1, 1, 2, 3, 4, 5, 9, 9}, |
| 388 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 458 | }, |
| 389 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 459 | Service::Mii::RandomMiiData4{ |
| 390 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 460 | .gender = Gender::Male, |
| 391 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 461 | .age = Age::Young, |
| 392 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 462 | .race = Race::White, |
| 393 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 463 | .values_count = 12, |
| 394 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 464 | .values = {0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 10, 11}, |
| 395 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 465 | }, |
| 396 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 466 | Service::Mii::RandomMiiData4{ |
| 397 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 467 | .gender = Gender::Male, |
| 398 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 468 | .age = Age::Normal, |
| 399 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 469 | .race = Race::White, |
| 400 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 470 | .values_count = 13, |
| 401 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 471 | .values = {0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 10, 11}, |
| 402 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 472 | }, |
| 403 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 473 | Service::Mii::RandomMiiData4{ |
| 404 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 474 | .gender = Gender::Male, |
| 405 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 475 | .age = Age::Old, |
| 406 | 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 476 | .race = Race::White, |
| 407 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | 477 | .values_count = 12, |
| 408 | 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 478 | .values = {0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 10, 11}, |
| 409 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 479 | }, |
| 410 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 480 | Service::Mii::RandomMiiData4{ |
| 411 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 481 | .gender = Gender::Male, |
| 412 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 482 | .age = Age::Young, |
| 413 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 483 | .race = Race::Asian, |
| 414 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 484 | .values_count = 12, |
| 415 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 485 | .values = {0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 10, 11}, |
| 416 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 486 | }, |
| 417 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 487 | Service::Mii::RandomMiiData4{ |
| 418 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 488 | .gender = Gender::Male, |
| 419 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 489 | .age = Age::Normal, |
| 420 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 490 | .race = Race::Asian, |
| 421 | 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 491 | .values_count = 13, |
| 422 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 492 | .values = {0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 10, 11}, |
| 423 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 493 | }, |
| 424 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 494 | Service::Mii::RandomMiiData4{ |
| 425 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 495 | .gender = Gender::Male, |
| 426 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 496 | .age = Age::Old, |
| 427 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 497 | .race = Race::Asian, |
| 428 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 498 | .values_count = 12, |
| 429 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 499 | .values = {0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 10, 11}, |
| 430 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 500 | }, |
| 431 | 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 501 | Service::Mii::RandomMiiData4{ |
| 432 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 502 | .gender = Gender::Female, |
| 433 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 503 | .age = Age::Young, |
| 434 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 504 | .race = Race::Black, |
| 435 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 505 | .values_count = 10, |
| 436 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 506 | .values = {0, 0, 1, 1, 2, 3, 4, 5, 9, 9}, |
| 437 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 507 | }, |
| 438 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 508 | Service::Mii::RandomMiiData4{ |
| 439 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 509 | .gender = Gender::Female, |
| 440 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 510 | .age = Age::Normal, |
| 441 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 511 | .race = Race::Black, |
| 442 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | 512 | .values_count = 10, |
| 513 | .values = {0, 0, 1, 1, 2, 3, 4, 5, 9, 9}, | ||
| 514 | }, | ||
| 515 | Service::Mii::RandomMiiData4{ | ||
| 516 | .gender = Gender::Female, | ||
| 517 | .age = Age::Old, | ||
| 518 | .race = Race::Black, | ||
| 519 | .values_count = 10, | ||
| 520 | .values = {0, 0, 1, 1, 2, 3, 4, 5, 9, 9}, | ||
| 521 | }, | ||
| 522 | Service::Mii::RandomMiiData4{ | ||
| 523 | .gender = Gender::Female, | ||
| 524 | .age = Age::Young, | ||
| 525 | .race = Race::White, | ||
| 526 | .values_count = 12, | ||
| 527 | .values = {0, 0, 0, 1, 1, 1, 2, 3, 4, 5, 8, 10}, | ||
| 528 | }, | ||
| 529 | Service::Mii::RandomMiiData4{ | ||
| 530 | .gender = Gender::Female, | ||
| 531 | .age = Age::Normal, | ||
| 532 | .race = Race::White, | ||
| 533 | .values_count = 12, | ||
| 534 | .values = {0, 0, 0, 1, 1, 1, 2, 3, 4, 5, 8, 10}, | ||
| 535 | }, | ||
| 536 | Service::Mii::RandomMiiData4{ | ||
| 537 | .gender = Gender::Female, | ||
| 538 | .age = Age::Old, | ||
| 539 | .race = Race::White, | ||
| 540 | .values_count = 12, | ||
| 541 | .values = {0, 0, 0, 1, 1, 1, 2, 3, 4, 5, 8, 10}, | ||
| 542 | }, | ||
| 543 | Service::Mii::RandomMiiData4{ | ||
| 544 | .gender = Gender::Female, | ||
| 545 | .age = Age::Young, | ||
| 546 | .race = Race::Asian, | ||
| 547 | .values_count = 12, | ||
| 548 | .values = {0, 0, 0, 1, 1, 1, 2, 3, 4, 5, 8, 10}, | ||
| 549 | }, | ||
| 550 | Service::Mii::RandomMiiData4{ | ||
| 551 | .gender = Gender::Female, | ||
| 552 | .age = Age::Normal, | ||
| 553 | .race = Race::Asian, | ||
| 554 | .values_count = 12, | ||
| 555 | .values = {0, 0, 0, 1, 1, 1, 2, 3, 4, 5, 8, 10}, | ||
| 556 | }, | ||
| 557 | Service::Mii::RandomMiiData4{ | ||
| 558 | .gender = Gender::Female, | ||
| 559 | .age = Age::Old, | ||
| 560 | .race = Race::Asian, | ||
| 561 | .values_count = 12, | ||
| 562 | .values = {0, 0, 0, 1, 1, 1, 2, 3, 4, 5, 8, 10}, | ||
| 563 | }, | ||
| 564 | }; | ||
| 443 | 565 | ||
| 444 | const std::array<u8, 3672> RandomMiiFacelineWrinkle{ | 566 | const std::array<Service::Mii::RandomMiiData3, 6> RandomMiiFacelineColor{ |
| 445 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | 567 | Service::Mii::RandomMiiData3{ |
| 446 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 568 | .arg_1 = 0, |
| 447 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 569 | .arg_2 = 0, |
| 448 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 570 | .values_count = 10, |
| 449 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 571 | .values = {2, 2, 4, 4, 4, 4, 5, 5, 5, 5}, |
| 450 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 572 | }, |
| 451 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 573 | Service::Mii::RandomMiiData3{ |
| 452 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 574 | .arg_1 = 0, |
| 453 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 575 | .arg_2 = 1, |
| 454 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 576 | .values_count = 10, |
| 455 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 577 | .values = {0, 0, 0, 0, 1, 1, 2, 3, 3, 3}, |
| 456 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 578 | }, |
| 457 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 579 | Service::Mii::RandomMiiData3{ |
| 458 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 580 | .arg_1 = 0, |
| 459 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 581 | .arg_2 = 2, |
| 460 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 582 | .values_count = 10, |
| 461 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 583 | .values = {0, 0, 1, 1, 1, 1, 1, 1, 1, 2}, |
| 462 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 584 | }, |
| 463 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 585 | Service::Mii::RandomMiiData3{ |
| 464 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 586 | .arg_1 = 1, |
| 465 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 587 | .arg_2 = 0, |
| 466 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 588 | .values_count = 10, |
| 467 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 589 | .values = {2, 2, 4, 4, 4, 4, 5, 5, 5, 5}, |
| 468 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 590 | }, |
| 469 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 591 | Service::Mii::RandomMiiData3{ |
| 470 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 592 | .arg_1 = 1, |
| 471 | 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 593 | .arg_2 = 1, |
| 472 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 594 | .values_count = 10, |
| 473 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 595 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 1, 3}, |
| 474 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 596 | }, |
| 475 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 597 | Service::Mii::RandomMiiData3{ |
| 476 | 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 598 | .arg_1 = 1, |
| 477 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 599 | .arg_2 = 2, |
| 478 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 600 | .values_count = 10, |
| 479 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 601 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, |
| 480 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 602 | }, |
| 481 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 603 | }; |
| 482 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 483 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 484 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 485 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 486 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 487 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 488 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 489 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 490 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 491 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 492 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 493 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 494 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 495 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 496 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 497 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 498 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 499 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 500 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 501 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 502 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 503 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 504 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 505 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 506 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 507 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 508 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 509 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 510 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 511 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 512 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 513 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 514 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 515 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 516 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 517 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 518 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 519 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 520 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 521 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 522 | 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 523 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 524 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 525 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 526 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 527 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 528 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 529 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 530 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 531 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 532 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 533 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 534 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 535 | 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 536 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 537 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 538 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 539 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 540 | 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 541 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 542 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 543 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 544 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 545 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 546 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 547 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 548 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 549 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 550 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 551 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 552 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 553 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 554 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 555 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 556 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 557 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 558 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 559 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 560 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 561 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 562 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 563 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 564 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 565 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 566 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 567 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 568 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 569 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 570 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 571 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 572 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 573 | 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 574 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 575 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 576 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 577 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 578 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 579 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 580 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 581 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 582 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 583 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 584 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 585 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 586 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 587 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 588 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 589 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 590 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 591 | 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 592 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 593 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 594 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 595 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 596 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 597 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 598 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 599 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 600 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 601 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 602 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 603 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 604 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 605 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 606 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 607 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 608 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 609 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 610 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 611 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 612 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 613 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 614 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 615 | 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 616 | 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 617 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 618 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 619 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 620 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 621 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 622 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 623 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 624 | 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 625 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 626 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 627 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 628 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 629 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 630 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 631 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 632 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 633 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 634 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 635 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 636 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 637 | 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 638 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 639 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 640 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 641 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 642 | 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 643 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 644 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 645 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 646 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 647 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 648 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 649 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 650 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 651 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 652 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 653 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 654 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 655 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 656 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 657 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 658 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 659 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 660 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 661 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 662 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 663 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 664 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 665 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 666 | 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 667 | 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 668 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 669 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 670 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 671 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 672 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 673 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 674 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 675 | 604 | ||
| 676 | const std::array<u8, 3672> RandomMiiFacelineMakeup{ | 605 | const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFacelineWrinkle{ |
| 677 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | 606 | Service::Mii::RandomMiiData4{ |
| 678 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 607 | .gender = Gender::Male, |
| 679 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 608 | .age = Age::Young, |
| 680 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 609 | .race = Race::Black, |
| 681 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 610 | .values_count = 20, |
| 682 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 611 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8}, |
| 683 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 612 | }, |
| 684 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 613 | Service::Mii::RandomMiiData4{ |
| 685 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 614 | .gender = Gender::Male, |
| 686 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 615 | .age = Age::Normal, |
| 687 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 616 | .race = Race::Black, |
| 688 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 617 | .values_count = 20, |
| 689 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 618 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8}, |
| 690 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 619 | }, |
| 691 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 620 | Service::Mii::RandomMiiData4{ |
| 692 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 621 | .gender = Gender::Male, |
| 693 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 622 | .age = Age::Old, |
| 694 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 623 | .race = Race::Black, |
| 695 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 624 | .values_count = 20, |
| 696 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 625 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8}, |
| 697 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 626 | }, |
| 698 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 627 | Service::Mii::RandomMiiData4{ |
| 699 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 628 | .gender = Gender::Male, |
| 700 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 629 | .age = Age::Young, |
| 701 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 630 | .race = Race::White, |
| 702 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 631 | .values_count = 20, |
| 703 | 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 632 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9}, |
| 704 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 633 | }, |
| 705 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 634 | Service::Mii::RandomMiiData4{ |
| 706 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 635 | .gender = Gender::Male, |
| 707 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 636 | .age = Age::Normal, |
| 708 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 637 | .race = Race::White, |
| 709 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 638 | .values_count = 20, |
| 710 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 639 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9}, |
| 711 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 640 | }, |
| 712 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 641 | Service::Mii::RandomMiiData4{ |
| 713 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 642 | .gender = Gender::Male, |
| 714 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 643 | .age = Age::Old, |
| 715 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 644 | .race = Race::White, |
| 716 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 645 | .values_count = 20, |
| 717 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 646 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, |
| 718 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 647 | }, |
| 719 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 648 | Service::Mii::RandomMiiData4{ |
| 720 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 649 | .gender = Gender::Male, |
| 721 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 650 | .age = Age::Young, |
| 722 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 651 | .race = Race::Asian, |
| 723 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 652 | .values_count = 20, |
| 724 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 653 | .values = {9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11}, |
| 725 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 654 | }, |
| 726 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 655 | Service::Mii::RandomMiiData4{ |
| 727 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 656 | .gender = Gender::Male, |
| 728 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | 657 | .age = Age::Normal, |
| 729 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 658 | .race = Race::Asian, |
| 730 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 659 | .values_count = 20, |
| 731 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 660 | .values = {9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11}, |
| 732 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 661 | }, |
| 733 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 662 | Service::Mii::RandomMiiData4{ |
| 734 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 663 | .gender = Gender::Male, |
| 735 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 664 | .age = Age::Old, |
| 736 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 665 | .race = Race::Asian, |
| 737 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 666 | .values_count = 20, |
| 738 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 667 | .values = {9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11}, |
| 739 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 668 | }, |
| 740 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 669 | Service::Mii::RandomMiiData4{ |
| 741 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 670 | .gender = Gender::Female, |
| 742 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 671 | .age = Age::Young, |
| 743 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 672 | .race = Race::Black, |
| 744 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 673 | .values_count = 20, |
| 745 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 674 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8}, |
| 746 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 675 | }, |
| 747 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 676 | Service::Mii::RandomMiiData4{ |
| 748 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 677 | .gender = Gender::Female, |
| 749 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 678 | .age = Age::Normal, |
| 750 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 679 | .race = Race::Black, |
| 751 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 680 | .values_count = 20, |
| 752 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 681 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8}, |
| 753 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 682 | }, |
| 754 | 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 683 | Service::Mii::RandomMiiData4{ |
| 755 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 684 | .gender = Gender::Female, |
| 756 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 685 | .age = Age::Old, |
| 757 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 686 | .race = Race::Black, |
| 758 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 687 | .values_count = 20, |
| 759 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 688 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8}, |
| 760 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 689 | }, |
| 761 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 690 | Service::Mii::RandomMiiData4{ |
| 762 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 691 | .gender = Gender::Female, |
| 763 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 692 | .age = Age::Young, |
| 764 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 693 | .race = Race::White, |
| 765 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 694 | .values_count = 20, |
| 766 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 695 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 4, 4, 8, 8}, |
| 767 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 696 | }, |
| 768 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 697 | Service::Mii::RandomMiiData4{ |
| 769 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 698 | .gender = Gender::Female, |
| 770 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 699 | .age = Age::Normal, |
| 771 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 700 | .race = Race::White, |
| 772 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 701 | .values_count = 20, |
| 773 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 702 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 4, 4, 8, 8}, |
| 774 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 703 | }, |
| 775 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 704 | Service::Mii::RandomMiiData4{ |
| 776 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 705 | .gender = Gender::Female, |
| 777 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 706 | .age = Age::Old, |
| 778 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 707 | .race = Race::White, |
| 779 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | 708 | .values_count = 20, |
| 780 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 709 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 4, 4}, |
| 781 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 710 | }, |
| 782 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 711 | Service::Mii::RandomMiiData4{ |
| 783 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 712 | .gender = Gender::Female, |
| 784 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 713 | .age = Age::Young, |
| 785 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 714 | .race = Race::Asian, |
| 786 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 715 | .values_count = 20, |
| 787 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 716 | .values = {9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11}, |
| 788 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 717 | }, |
| 789 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 718 | Service::Mii::RandomMiiData4{ |
| 790 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 719 | .gender = Gender::Female, |
| 791 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 720 | .age = Age::Normal, |
| 792 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 721 | .race = Race::Asian, |
| 793 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 722 | .values_count = 20, |
| 794 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 723 | .values = {9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11}, |
| 795 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 724 | }, |
| 796 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 725 | Service::Mii::RandomMiiData4{ |
| 797 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 726 | .gender = Gender::Female, |
| 798 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 727 | .age = Age::Old, |
| 799 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 728 | .race = Race::Asian, |
| 800 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 729 | .values_count = 20, |
| 801 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 730 | .values = {9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11}, |
| 802 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 731 | }, |
| 803 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 732 | }; |
| 804 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 805 | 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 806 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 807 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 808 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 809 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 810 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 811 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 812 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 813 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 814 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 815 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 816 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 817 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 818 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 819 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 820 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 821 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 822 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 823 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 824 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 825 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 826 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 827 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 828 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 829 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 830 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 831 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 832 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 833 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 834 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 835 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 836 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 837 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 838 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 839 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 840 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 841 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 842 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 843 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 844 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 845 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 846 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 847 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 848 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 849 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 850 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 851 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 852 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 853 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 854 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 855 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 856 | 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 857 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 858 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 859 | 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 860 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 861 | 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 862 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 863 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 864 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 865 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 866 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 867 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 868 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 869 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 870 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 871 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 872 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 873 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 874 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 875 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 876 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 877 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 878 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 879 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 880 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 881 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 882 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 883 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 884 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 885 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 886 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 887 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 888 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 889 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 890 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 891 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 892 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 893 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 894 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 895 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 896 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 897 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 898 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 899 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 900 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 901 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 902 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 903 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 904 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 905 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 906 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 907 | 733 | ||
| 908 | const std::array<u8, 3672> RandomMiiHairType{ | 734 | const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFacelineMakeup{ |
| 909 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | 735 | Service::Mii::RandomMiiData4{ |
| 910 | 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, | 736 | .gender = Gender::Male, |
| 911 | 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | 737 | .age = Age::Young, |
| 912 | 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, | 738 | .race = Race::Black, |
| 913 | 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, | 739 | .values_count = 20, |
| 914 | 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, | 740 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, |
| 915 | 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, | 741 | }, |
| 916 | 0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, | 742 | Service::Mii::RandomMiiData4{ |
| 917 | 0x56, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 743 | .gender = Gender::Male, |
| 918 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 744 | .age = Age::Normal, |
| 919 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 745 | .race = Race::Black, |
| 920 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 746 | .values_count = 20, |
| 921 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 747 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9}, |
| 922 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | 748 | }, |
| 923 | 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | 749 | Service::Mii::RandomMiiData4{ |
| 924 | 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | 750 | .gender = Gender::Male, |
| 925 | 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, | 751 | .age = Age::Old, |
| 926 | 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, | 752 | .race = Race::Black, |
| 927 | 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, | 753 | .values_count = 20, |
| 928 | 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | 754 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9}, |
| 929 | 0x42, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, | 755 | }, |
| 930 | 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 756 | Service::Mii::RandomMiiData4{ |
| 931 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 757 | .gender = Gender::Male, |
| 932 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 758 | .age = Age::Young, |
| 933 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 759 | .race = Race::White, |
| 934 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 760 | .values_count = 20, |
| 935 | 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | 761 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, |
| 936 | 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | 762 | }, |
| 937 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | 763 | Service::Mii::RandomMiiData4{ |
| 938 | 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, | 764 | .gender = Gender::Male, |
| 939 | 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, | 765 | .age = Age::Normal, |
| 940 | 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, | 766 | .race = Race::White, |
| 941 | 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, | 767 | .values_count = 20, |
| 942 | 0x49, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, | 768 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, |
| 943 | 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 769 | }, |
| 944 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 770 | Service::Mii::RandomMiiData4{ |
| 945 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 771 | .gender = Gender::Male, |
| 946 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 772 | .age = Age::Old, |
| 947 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 773 | .race = Race::White, |
| 948 | 0x26, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | 774 | .values_count = 20, |
| 949 | 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | 775 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, |
| 950 | 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, | 776 | }, |
| 951 | 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, | 777 | Service::Mii::RandomMiiData4{ |
| 952 | 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, | 778 | .gender = Gender::Male, |
| 953 | 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, | 779 | .age = Age::Young, |
| 954 | 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, | 780 | .race = Race::Asian, |
| 955 | 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, | 781 | .values_count = 20, |
| 956 | 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, | 782 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, |
| 957 | 0x4c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 783 | }, |
| 958 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 784 | Service::Mii::RandomMiiData4{ |
| 959 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 785 | .gender = Gender::Male, |
| 960 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | 786 | .age = Age::Normal, |
| 961 | 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, | 787 | .race = Race::Asian, |
| 962 | 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | 788 | .values_count = 20, |
| 963 | 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, | 789 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, |
| 964 | 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, | 790 | }, |
| 965 | 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, | 791 | Service::Mii::RandomMiiData4{ |
| 966 | 0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, | 792 | .gender = Gender::Male, |
| 967 | 0x38, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, | 793 | .age = Age::Old, |
| 968 | 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, | 794 | .race = Race::Asian, |
| 969 | 0x44, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, | 795 | .values_count = 20, |
| 970 | 0x51, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 796 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, |
| 971 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 797 | }, |
| 972 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 798 | Service::Mii::RandomMiiData4{ |
| 973 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | 799 | .gender = Gender::Female, |
| 974 | 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | 800 | .age = Age::Young, |
| 975 | 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | 801 | .race = Race::Black, |
| 976 | 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, | 802 | .values_count = 20, |
| 977 | 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, | 803 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2}, |
| 978 | 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, | 804 | }, |
| 979 | 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, | 805 | Service::Mii::RandomMiiData4{ |
| 980 | 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | 806 | .gender = Gender::Female, |
| 981 | 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, | 807 | .age = Age::Normal, |
| 982 | 0x46, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, | 808 | .race = Race::Black, |
| 983 | 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 809 | .values_count = 20, |
| 984 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 810 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 9, 9}, |
| 985 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 811 | }, |
| 986 | 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | 812 | Service::Mii::RandomMiiData4{ |
| 987 | 0x1e, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | 813 | .gender = Gender::Female, |
| 988 | 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, | 814 | .age = Age::Old, |
| 989 | 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, | 815 | .race = Race::Black, |
| 990 | 0x41, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, | 816 | .values_count = 20, |
| 991 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 817 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 9, 9}, |
| 992 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 818 | }, |
| 993 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 819 | Service::Mii::RandomMiiData4{ |
| 994 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 820 | .gender = Gender::Female, |
| 995 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 821 | .age = Age::Young, |
| 996 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 822 | .race = Race::White, |
| 997 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 823 | .values_count = 20, |
| 998 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 824 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9}, |
| 999 | 0x13, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | 825 | }, |
| 1000 | 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | 826 | Service::Mii::RandomMiiData4{ |
| 1001 | 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, | 827 | .gender = Gender::Female, |
| 1002 | 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, | 828 | .age = Age::Normal, |
| 1003 | 0x41, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, | 829 | .race = Race::White, |
| 1004 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 830 | .values_count = 20, |
| 1005 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 831 | .values = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9}, |
| 1006 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 832 | }, |
| 1007 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 833 | Service::Mii::RandomMiiData4{ |
| 1008 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 834 | .gender = Gender::Female, |
| 1009 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 835 | .age = Age::Old, |
| 1010 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 836 | .race = Race::White, |
| 1011 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | 837 | .values_count = 20, |
| 1012 | 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | 838 | .values = {0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 9}, |
| 1013 | 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, | 839 | }, |
| 1014 | 0x2f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, | 840 | Service::Mii::RandomMiiData4{ |
| 1015 | 0x37, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, | 841 | .gender = Gender::Female, |
| 1016 | 0x43, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 842 | .age = Age::Young, |
| 1017 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 843 | .race = Race::Asian, |
| 1018 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 844 | .values_count = 20, |
| 1019 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 845 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, |
| 1020 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 846 | }, |
| 1021 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 847 | Service::Mii::RandomMiiData4{ |
| 1022 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 848 | .gender = Gender::Female, |
| 1023 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 849 | .age = Age::Normal, |
| 1024 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 850 | .race = Race::Asian, |
| 1025 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 851 | .values_count = 20, |
| 1026 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 852 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, |
| 1027 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | 853 | }, |
| 1028 | 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | 854 | Service::Mii::RandomMiiData4{ |
| 1029 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | 855 | .gender = Gender::Female, |
| 1030 | 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | 856 | .age = Age::Old, |
| 1031 | 0x1c, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, | 857 | .race = Race::Asian, |
| 1032 | 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, | 858 | .values_count = 20, |
| 1033 | 0x4c, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, | 859 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, |
| 1034 | 0x53, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 860 | }, |
| 1035 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 861 | }; |
| 1036 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1037 | 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1038 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 1039 | 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1040 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 1041 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1042 | 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | ||
| 1043 | 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | ||
| 1044 | 0x2e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, | ||
| 1045 | 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, | ||
| 1046 | 0x4a, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, | ||
| 1047 | 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, | ||
| 1048 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1049 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1050 | 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1051 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 1052 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1053 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1054 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 1055 | 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 1056 | 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, | ||
| 1057 | 0x32, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, | ||
| 1058 | 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, | ||
| 1059 | 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, | ||
| 1060 | 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1061 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1062 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, | ||
| 1063 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 1064 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 1065 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1066 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1067 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 1068 | 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 1069 | 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 1070 | 0x2a, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, | ||
| 1071 | 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, | ||
| 1072 | 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, | ||
| 1073 | 0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, | ||
| 1074 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1075 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1076 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 1077 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1078 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1079 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 1080 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 1081 | 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 1082 | 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, | ||
| 1083 | 0x3a, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, | ||
| 1084 | 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, | ||
| 1085 | 0x4a, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, | ||
| 1086 | 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1087 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1088 | 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1089 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 1090 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1091 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1092 | 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 1093 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 1094 | 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | ||
| 1095 | 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, | ||
| 1096 | 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | ||
| 1097 | 0x45, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, | ||
| 1098 | 0x4f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, | ||
| 1099 | 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1100 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1101 | 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1102 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 1103 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1104 | 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1105 | 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 1106 | 0x3a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, | ||
| 1107 | 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1109 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1113 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, | ||
| 1114 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 1115 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1116 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 1117 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 1118 | 0x15, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, | ||
| 1119 | 0x3e, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, | ||
| 1120 | 0x51, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1121 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1122 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1123 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1126 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1127 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 1128 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1129 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 1130 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 1131 | 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, | ||
| 1132 | 0x45, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, | ||
| 1133 | 0x53, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1134 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1135 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1136 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1137 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1138 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 1139 | 862 | ||
| 1140 | const std::array<u8, 1800> RandomMiiHairColor{ | 863 | const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiHairType{ |
| 1141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 864 | Service::Mii::RandomMiiData4{ |
| 1142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 865 | .gender = Gender::Male, |
| 1143 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 866 | .age = Age::Young, |
| 1144 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 867 | .race = Race::Black, |
| 1145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 868 | .values_count = 30, |
| 1146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 869 | .values = {13, 23, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 43, 44, 45, |
| 1147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 870 | 47, 48, 49, 50, 51, 52, 54, 56, 57, 64, 66, 75, 76, 86, 89}, |
| 1148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 871 | }, |
| 1149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 872 | Service::Mii::RandomMiiData4{ |
| 1150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 873 | .gender = Gender::Male, |
| 1151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 874 | .age = Age::Normal, |
| 1152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 875 | .race = Race::Black, |
| 1153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 876 | .values_count = 31, |
| 1154 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 877 | .values = {13, 23, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 43, 44, 45, 47, |
| 1155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 878 | 48, 49, 50, 51, 52, 54, 56, 57, 64, 66, 73, 75, 81, 86, 87}, |
| 1156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 879 | }, |
| 1157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 880 | Service::Mii::RandomMiiData4{ |
| 1158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 881 | .gender = Gender::Male, |
| 1159 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 882 | .age = Age::Old, |
| 1160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 883 | .race = Race::Black, |
| 1161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 884 | .values_count = 31, |
| 1162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 885 | .values = {13, 23, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 43, 44, 45, 47, |
| 1163 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 886 | 48, 49, 50, 51, 52, 54, 56, 57, 64, 66, 73, 75, 81, 86, 87}, |
| 1164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 887 | }, |
| 1165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 888 | Service::Mii::RandomMiiData4{ |
| 1166 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 889 | .gender = Gender::Male, |
| 1167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 890 | .age = Age::Young, |
| 1168 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 891 | .race = Race::White, |
| 1169 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 892 | .values_count = 38, |
| 1170 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 893 | .values = {13, 23, 30, 31, 32, 33, 34, 36, 37, 38, 40, 42, 43, 44, 45, 47, 48, 49, 50, |
| 1171 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 894 | 51, 52, 53, 54, 55, 56, 58, 59, 60, 64, 65, 66, 67, 68, 70, 75, 76, 86, 89}, |
| 1172 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 895 | }, |
| 1173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 896 | Service::Mii::RandomMiiData4{ |
| 1174 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 897 | .gender = Gender::Male, |
| 1175 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 898 | .age = Age::Normal, |
| 1176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 899 | .race = Race::White, |
| 1177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 900 | .values_count = 39, |
| 1178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 901 | .values = {13, 23, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 43, 44, 45, 47, 48, 49, 50, 51, |
| 1179 | 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 902 | 52, 53, 54, 55, 56, 58, 59, 60, 64, 65, 66, 67, 68, 70, 73, 75, 81, 86, 87}, |
| 1180 | 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | 903 | }, |
| 1181 | 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 904 | Service::Mii::RandomMiiData4{ |
| 1182 | 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 905 | .gender = Gender::Male, |
| 1183 | 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 906 | .age = Age::Old, |
| 1184 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 907 | .race = Race::White, |
| 1185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 908 | .values_count = 39, |
| 1186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 909 | .values = {13, 23, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 43, 44, 45, 47, 48, 49, 50, 51, |
| 1187 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 910 | 52, 53, 54, 55, 56, 58, 59, 60, 64, 65, 66, 67, 68, 70, 73, 75, 81, 86, 87}, |
| 1188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 911 | }, |
| 1189 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 912 | Service::Mii::RandomMiiData4{ |
| 1190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 913 | .gender = Gender::Male, |
| 1191 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 914 | .age = Age::Young, |
| 1192 | 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | 915 | .race = Race::Asian, |
| 1193 | 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 916 | .values_count = 18, |
| 1194 | 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 917 | .values = {13, 23, 30, 36, 37, 41, 45, 47, 51, 53, 54, 55, 58, 59, 65, 67, 86, 88}, |
| 1195 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 918 | }, |
| 1196 | 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 919 | Service::Mii::RandomMiiData4{ |
| 1197 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 920 | .gender = Gender::Male, |
| 1198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 921 | .age = Age::Normal, |
| 1199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 922 | .race = Race::Asian, |
| 1200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 923 | .values_count = 19, |
| 1201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 924 | .values = {13, 23, 30, 36, 37, 39, 41, 45, 47, 51, 53, 54, 55, 58, 59, 65, 67, 86, 88}, |
| 1202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 925 | }, |
| 1203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 926 | Service::Mii::RandomMiiData4{ |
| 1204 | 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 927 | .gender = Gender::Male, |
| 1205 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 928 | .age = Age::Old, |
| 1206 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 929 | .race = Race::Asian, |
| 1207 | 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 930 | .values_count = 19, |
| 1208 | 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 931 | .values = {13, 23, 30, 36, 37, 39, 41, 45, 47, 51, 53, 54, 55, 58, 59, 65, 67, 86, 88}, |
| 1209 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 932 | }, |
| 1210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 933 | Service::Mii::RandomMiiData4{ |
| 1211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 934 | .gender = Gender::Female, |
| 1212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 935 | .age = Age::Young, |
| 1213 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 936 | .race = Race::Black, |
| 1214 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 937 | .values_count = 39, |
| 1215 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 938 | .values = {0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, |
| 1216 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 939 | 21, 22, 24, 25, 26, 28, 46, 50, 61, 62, 63, 64, 69, 76, 77, 79, 80, 83, 85}, |
| 1217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 940 | }, |
| 1218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 941 | Service::Mii::RandomMiiData4{ |
| 1219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 942 | .gender = Gender::Female, |
| 1220 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 943 | .age = Age::Normal, |
| 1221 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 944 | .race = Race::Black, |
| 1222 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 945 | .values_count = 42, |
| 1223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 946 | .values = {0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, |
| 1224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 947 | 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 28, 46, 50, |
| 1225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 948 | 61, 62, 63, 64, 69, 72, 74, 77, 78, 82, 83, 84, 85, 87}, |
| 1226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 949 | }, |
| 1227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 950 | Service::Mii::RandomMiiData4{ |
| 1228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 951 | .gender = Gender::Female, |
| 1229 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 952 | .age = Age::Old, |
| 1230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 953 | .race = Race::Black, |
| 1231 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 954 | .values_count = 42, |
| 1232 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 955 | .values = {0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, |
| 1233 | 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 956 | 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 28, 46, 50, |
| 1234 | 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 957 | 61, 62, 63, 64, 69, 72, 74, 77, 78, 82, 83, 84, 85, 87}, |
| 1235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 958 | }, |
| 1236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 959 | Service::Mii::RandomMiiData4{ |
| 1237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 960 | .gender = Gender::Female, |
| 1238 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 961 | .age = Age::Young, |
| 1239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 962 | .race = Race::White, |
| 1240 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 963 | .values_count = 44, |
| 1241 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 964 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 1242 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 965 | 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 29, 42, 50, |
| 1243 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 966 | 58, 60, 62, 63, 64, 69, 71, 76, 79, 80, 81, 82, 83, 86}, |
| 1244 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 967 | }, |
| 1245 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 968 | Service::Mii::RandomMiiData4{ |
| 1246 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 969 | .gender = Gender::Female, |
| 1247 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 970 | .age = Age::Normal, |
| 1248 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 971 | .race = Race::White, |
| 1249 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 972 | .values_count = 44, |
| 1250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 973 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 1251 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 974 | 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 29, 50, 58, |
| 1252 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 975 | 60, 62, 63, 64, 69, 71, 72, 74, 79, 81, 82, 83, 84, 85}, |
| 1253 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | 976 | }, |
| 977 | Service::Mii::RandomMiiData4{ | ||
| 978 | .gender = Gender::Female, | ||
| 979 | .age = Age::Old, | ||
| 980 | .race = Race::White, | ||
| 981 | .values_count = 44, | ||
| 982 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | ||
| 983 | 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 29, 50, 58, | ||
| 984 | 60, 62, 63, 64, 69, 71, 72, 74, 79, 81, 82, 83, 84, 85}, | ||
| 985 | }, | ||
| 986 | Service::Mii::RandomMiiData4{ | ||
| 987 | .gender = Gender::Female, | ||
| 988 | .age = Age::Young, | ||
| 989 | .race = Race::Asian, | ||
| 990 | .values_count = 24, | ||
| 991 | .values = {0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, | ||
| 992 | 16, 17, 18, 20, 21, 24, 25, 58, 62, 69, 76, 83}, | ||
| 993 | }, | ||
| 994 | Service::Mii::RandomMiiData4{ | ||
| 995 | .gender = Gender::Female, | ||
| 996 | .age = Age::Normal, | ||
| 997 | .race = Race::Asian, | ||
| 998 | .values_count = 27, | ||
| 999 | .values = {0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 16, 17, | ||
| 1000 | 18, 20, 21, 24, 25, 58, 62, 69, 74, 76, 81, 83, 85}, | ||
| 1001 | }, | ||
| 1002 | Service::Mii::RandomMiiData4{ | ||
| 1003 | .gender = Gender::Female, | ||
| 1004 | .age = Age::Old, | ||
| 1005 | .race = Race::Asian, | ||
| 1006 | .values_count = 27, | ||
| 1007 | .values = {0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 16, 17, | ||
| 1008 | 18, 20, 21, 24, 25, 58, 62, 69, 74, 76, 81, 83, 85}, | ||
| 1009 | }, | ||
| 1010 | }; | ||
| 1254 | 1011 | ||
| 1255 | const std::array<u8, 3672> RandomMiiEyeType{ | 1012 | const std::array<RandomMiiData3, 9> RandomMiiHairColor{ |
| 1256 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | 1013 | Service::Mii::RandomMiiData3{ |
| 1257 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 1014 | .arg_1 = 0, |
| 1258 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | 1015 | .arg_2 = 0, |
| 1259 | 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | 1016 | .values_count = 20, |
| 1260 | 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | 1017 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, |
| 1261 | 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | 1018 | }, |
| 1262 | 0x2b, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, | 1019 | Service::Mii::RandomMiiData3{ |
| 1263 | 0x35, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1020 | .arg_1 = 0, |
| 1264 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1021 | .arg_2 = 1, |
| 1265 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1022 | .values_count = 20, |
| 1266 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1023 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, |
| 1267 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1024 | }, |
| 1268 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1025 | Service::Mii::RandomMiiData3{ |
| 1269 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1026 | .arg_1 = 0, |
| 1270 | 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 1027 | .arg_2 = 2, |
| 1271 | 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | 1028 | .values_count = 20, |
| 1272 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, | 1029 | .values = {0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, |
| 1273 | 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | 1030 | }, |
| 1274 | 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, | 1031 | Service::Mii::RandomMiiData3{ |
| 1275 | 0x2f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, | 1032 | .arg_1 = 1, |
| 1276 | 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1033 | .arg_2 = 0, |
| 1277 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1034 | .values_count = 20, |
| 1278 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1035 | .values = {2, 3, 3, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7}, |
| 1279 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1036 | }, |
| 1280 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1037 | Service::Mii::RandomMiiData3{ |
| 1281 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1038 | .arg_1 = 1, |
| 1282 | 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 1039 | .arg_2 = 1, |
| 1283 | 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 1040 | .values_count = 20, |
| 1284 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | 1041 | .values = {2, 3, 3, 3, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7}, |
| 1285 | 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, | 1042 | }, |
| 1286 | 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | 1043 | Service::Mii::RandomMiiData3{ |
| 1287 | 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, | 1044 | .arg_1 = 1, |
| 1288 | 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, | 1045 | .arg_2 = 2, |
| 1289 | 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1046 | .values_count = 20, |
| 1290 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1047 | .values = {2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7}, |
| 1291 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1048 | }, |
| 1292 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1049 | Service::Mii::RandomMiiData3{ |
| 1293 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1050 | .arg_1 = 2, |
| 1294 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1051 | .arg_2 = 0, |
| 1295 | 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | 1052 | .values_count = 20, |
| 1296 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 1053 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, |
| 1297 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | 1054 | }, |
| 1298 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | 1055 | Service::Mii::RandomMiiData3{ |
| 1299 | 0x16, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, | 1056 | .arg_1 = 2, |
| 1300 | 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | 1057 | .arg_2 = 1, |
| 1301 | 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, | 1058 | .values_count = 20, |
| 1302 | 0x2c, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, | 1059 | .values = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 3}, |
| 1303 | 0x35, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, | 1060 | }, |
| 1304 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1061 | Service::Mii::RandomMiiData3{ |
| 1305 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1062 | .arg_1 = 2, |
| 1306 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1063 | .arg_2 = 2, |
| 1307 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | 1064 | .values_count = 20, |
| 1308 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 1065 | .values = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, |
| 1309 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | 1066 | }, |
| 1310 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | 1067 | }; |
| 1311 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | ||
| 1312 | 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 1313 | 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, | ||
| 1314 | 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, | ||
| 1315 | 0x2f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, | ||
| 1316 | 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1317 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1318 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1319 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1320 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1321 | 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 1322 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1323 | 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1324 | 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, | ||
| 1325 | 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 1326 | 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | ||
| 1327 | 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, | ||
| 1328 | 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, | ||
| 1329 | 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1330 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1331 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1332 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1333 | 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 1334 | 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1335 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 1336 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1337 | 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 1338 | 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | ||
| 1339 | 0x29, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, | ||
| 1340 | 0x35, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, | ||
| 1341 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1342 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1343 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1344 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1345 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1346 | 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 1347 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1348 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1349 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 1350 | 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 1351 | 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | ||
| 1352 | 0x2c, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, | ||
| 1353 | 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1354 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1355 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1356 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1357 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1358 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | ||
| 1359 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 1360 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1361 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 1362 | 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | ||
| 1363 | 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, | ||
| 1364 | 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, | ||
| 1365 | 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, | ||
| 1366 | 0x35, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1367 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1368 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1369 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1370 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1371 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1372 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 1373 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1374 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1375 | 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | ||
| 1376 | 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | ||
| 1377 | 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 1378 | 0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, | ||
| 1379 | 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, | ||
| 1380 | 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, | ||
| 1381 | 0x39, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1382 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1383 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1384 | 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1385 | 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 1386 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1387 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 1388 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 1389 | 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 1390 | 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 1391 | 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | ||
| 1392 | 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, | ||
| 1393 | 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, | ||
| 1394 | 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1395 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1396 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1397 | 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1398 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1399 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1400 | 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1401 | 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 1402 | 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 1403 | 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 1404 | 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | ||
| 1405 | 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, | ||
| 1406 | 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, | ||
| 1407 | 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1408 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1409 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, | ||
| 1410 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 1411 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1412 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1413 | 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 1414 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 1415 | 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, | ||
| 1416 | 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 1417 | 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, | ||
| 1418 | 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, | ||
| 1419 | 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, | ||
| 1420 | 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, | ||
| 1421 | 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1422 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1423 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 1424 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1425 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1426 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1427 | 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | ||
| 1428 | 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | ||
| 1429 | 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 1430 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, | ||
| 1431 | 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, | ||
| 1432 | 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, | ||
| 1433 | 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, | ||
| 1434 | 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1435 | 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1436 | 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 1437 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1438 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1439 | 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 1440 | 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 1441 | 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 1442 | 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 1443 | 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | ||
| 1444 | 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, | ||
| 1445 | 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, | ||
| 1446 | 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, | ||
| 1447 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1448 | 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1449 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1450 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1451 | 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1452 | 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 1453 | 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | ||
| 1454 | 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, | ||
| 1455 | 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, | ||
| 1456 | 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1457 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1458 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1459 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1460 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | ||
| 1461 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 1462 | 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1463 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1464 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 1465 | 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, | ||
| 1466 | 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 1467 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | ||
| 1468 | 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, | ||
| 1469 | 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1470 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1471 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1472 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1473 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1474 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 1475 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1476 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1477 | 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | ||
| 1478 | 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, | ||
| 1479 | 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 1480 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, | ||
| 1481 | 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, | ||
| 1482 | 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1483 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1484 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1485 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 1486 | 1068 | ||
| 1487 | const std::array<u8, 588> RandomMiiEyeColor{ | 1069 | const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiEyeType{ |
| 1488 | 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1070 | Service::Mii::RandomMiiData4{ |
| 1489 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1071 | .gender = Gender::Male, |
| 1490 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1072 | .age = Age::Young, |
| 1491 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1073 | .race = Race::Black, |
| 1492 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1074 | .values_count = 26, |
| 1493 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1075 | .values = {2, 3, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 27, |
| 1494 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1076 | 29, 32, 34, 36, 38, 39, 41, 43, 47, 49, 51, 53, 57}, |
| 1495 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1077 | }, |
| 1496 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1078 | Service::Mii::RandomMiiData4{ |
| 1497 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1079 | .gender = Gender::Male, |
| 1498 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1080 | .age = Age::Normal, |
| 1499 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1081 | .race = Race::Black, |
| 1500 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1082 | .values_count = 26, |
| 1501 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 1083 | .values = {2, 3, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 27, |
| 1502 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 1084 | 29, 32, 34, 36, 38, 39, 41, 43, 47, 49, 51, 53, 57}, |
| 1503 | 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1085 | }, |
| 1504 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1086 | Service::Mii::RandomMiiData4{ |
| 1505 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1087 | .gender = Gender::Male, |
| 1506 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1088 | .age = Age::Old, |
| 1507 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1089 | .race = Race::Black, |
| 1508 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1090 | .values_count = 27, |
| 1509 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1091 | .values = {2, 3, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 26, 27, |
| 1510 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1092 | 29, 32, 34, 36, 38, 39, 41, 43, 47, 48, 49, 53, 57}, |
| 1511 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1093 | }, |
| 1512 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 1094 | Service::Mii::RandomMiiData4{ |
| 1513 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1095 | .gender = Gender::Male, |
| 1514 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1096 | .age = Age::Young, |
| 1515 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1097 | .race = Race::White, |
| 1516 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1098 | .values_count = 35, |
| 1517 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1099 | .values = {2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 21, 22, 27, 29, |
| 1518 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1100 | 31, 32, 34, 36, 37, 38, 39, 41, 43, 44, 47, 49, 51, 53, 55, 56, 57}, |
| 1519 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1101 | }, |
| 1520 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1102 | Service::Mii::RandomMiiData4{ |
| 1521 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1103 | .gender = Gender::Male, |
| 1522 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1104 | .age = Age::Normal, |
| 1523 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1105 | .race = Race::White, |
| 1524 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | 1106 | .values_count = 35, |
| 1107 | .values = {2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 21, 22, 27, 29, | ||
| 1108 | 31, 32, 34, 36, 37, 38, 39, 41, 43, 44, 47, 49, 51, 53, 55, 56, 57}, | ||
| 1109 | }, | ||
| 1110 | Service::Mii::RandomMiiData4{ | ||
| 1111 | .gender = Gender::Male, | ||
| 1112 | .age = Age::Old, | ||
| 1113 | .race = Race::White, | ||
| 1114 | .values_count = 35, | ||
| 1115 | .values = {2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 21, 22, 26, 27, 29, | ||
| 1116 | 31, 32, 34, 36, 37, 38, 39, 41, 43, 44, 47, 48, 49, 50, 53, 56, 57}, | ||
| 1117 | }, | ||
| 1118 | Service::Mii::RandomMiiData4{ | ||
| 1119 | .gender = Gender::Male, | ||
| 1120 | .age = Age::Young, | ||
| 1121 | .race = Race::Asian, | ||
| 1122 | .values_count = 30, | ||
| 1123 | .values = {2, 3, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 21, | ||
| 1124 | 22, 31, 32, 34, 36, 37, 39, 41, 44, 49, 51, 53, 55, 56, 57}, | ||
| 1125 | }, | ||
| 1126 | Service::Mii::RandomMiiData4{ | ||
| 1127 | .gender = Gender::Male, | ||
| 1128 | .age = Age::Normal, | ||
| 1129 | .race = Race::Asian, | ||
| 1130 | .values_count = 30, | ||
| 1131 | .values = {2, 3, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 21, | ||
| 1132 | 22, 31, 32, 34, 36, 37, 39, 41, 44, 49, 51, 53, 55, 56, 57}, | ||
| 1133 | }, | ||
| 1134 | Service::Mii::RandomMiiData4{ | ||
| 1135 | .gender = Gender::Male, | ||
| 1136 | .age = Age::Old, | ||
| 1137 | .race = Race::Asian, | ||
| 1138 | .values_count = 30, | ||
| 1139 | .values = {2, 3, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 21, 22, | ||
| 1140 | 26, 31, 32, 34, 36, 37, 39, 41, 44, 48, 49, 50, 51, 53, 57}, | ||
| 1141 | }, | ||
| 1142 | Service::Mii::RandomMiiData4{ | ||
| 1143 | .gender = Gender::Female, | ||
| 1144 | .age = Age::Young, | ||
| 1145 | .race = Race::Black, | ||
| 1146 | .values_count = 39, | ||
| 1147 | .values = {0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 18, 19, 23, 24, 25, 27, | ||
| 1148 | 28, 29, 32, 33, 34, 35, 38, 39, 40, 41, 42, 45, 46, 47, 48, 53, 54, 57, 59}, | ||
| 1149 | }, | ||
| 1150 | Service::Mii::RandomMiiData4{ | ||
| 1151 | .gender = Gender::Female, | ||
| 1152 | .age = Age::Normal, | ||
| 1153 | .race = Race::Black, | ||
| 1154 | .values_count = 39, | ||
| 1155 | .values = {0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 18, 19, 23, 24, 25, 27, | ||
| 1156 | 28, 29, 32, 33, 34, 35, 38, 39, 40, 41, 42, 45, 46, 47, 48, 53, 54, 57, 59}, | ||
| 1157 | }, | ||
| 1158 | Service::Mii::RandomMiiData4{ | ||
| 1159 | .gender = Gender::Female, | ||
| 1160 | .age = Age::Old, | ||
| 1161 | .race = Race::Black, | ||
| 1162 | .values_count = 40, | ||
| 1163 | .values = {0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 18, 19, 23, 24, 25, 26, | ||
| 1164 | 27, 28, 29, 32, 33, 34, 35, 38, 39, 40, 41, 42, 45, 46, 47, 48, 53, 54, 57, 59}, | ||
| 1165 | }, | ||
| 1166 | Service::Mii::RandomMiiData4{ | ||
| 1167 | .gender = Gender::Female, | ||
| 1168 | .age = Age::Young, | ||
| 1169 | .race = Race::White, | ||
| 1170 | .values_count = 46, | ||
| 1171 | .values = {0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, | ||
| 1172 | 18, 19, 20, 21, 23, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35, 37, | ||
| 1173 | 38, 39, 40, 41, 42, 45, 46, 47, 48, 53, 54, 57, 58, 59}, | ||
| 1174 | }, | ||
| 1175 | Service::Mii::RandomMiiData4{ | ||
| 1176 | .gender = Gender::Female, | ||
| 1177 | .age = Age::Normal, | ||
| 1178 | .race = Race::White, | ||
| 1179 | .values_count = 46, | ||
| 1180 | .values = {0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, | ||
| 1181 | 18, 19, 20, 21, 23, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35, 37, | ||
| 1182 | 38, 39, 40, 41, 42, 45, 46, 47, 48, 53, 54, 57, 58, 59}, | ||
| 1183 | }, | ||
| 1184 | Service::Mii::RandomMiiData4{ | ||
| 1185 | .gender = Gender::Female, | ||
| 1186 | .age = Age::Old, | ||
| 1187 | .race = Race::White, | ||
| 1188 | .values_count = 46, | ||
| 1189 | .values = {0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 18, | ||
| 1190 | 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 37, | ||
| 1191 | 38, 39, 40, 41, 42, 45, 46, 47, 48, 53, 54, 57, 58, 59}, | ||
| 1192 | }, | ||
| 1193 | Service::Mii::RandomMiiData4{ | ||
| 1194 | .gender = Gender::Female, | ||
| 1195 | .age = Age::Young, | ||
| 1196 | .race = Race::Asian, | ||
| 1197 | .values_count = 34, | ||
| 1198 | .values = {0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 18, 19, 23, | ||
| 1199 | 24, 25, 27, 28, 29, 32, 33, 34, 35, 38, 39, 40, 41, 42, 45, 46, 47}, | ||
| 1200 | }, | ||
| 1201 | Service::Mii::RandomMiiData4{ | ||
| 1202 | .gender = Gender::Female, | ||
| 1203 | .age = Age::Normal, | ||
| 1204 | .race = Race::Asian, | ||
| 1205 | .values_count = 34, | ||
| 1206 | .values = {0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 18, 19, 23, | ||
| 1207 | 24, 25, 27, 28, 29, 32, 33, 34, 35, 38, 39, 40, 41, 42, 45, 46, 47}, | ||
| 1208 | }, | ||
| 1209 | Service::Mii::RandomMiiData4{ | ||
| 1210 | .gender = Gender::Female, | ||
| 1211 | .age = Age::Old, | ||
| 1212 | .race = Race::Asian, | ||
| 1213 | .values_count = 35, | ||
| 1214 | .values = {0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 15, 16, 18, 19, 23, 24, | ||
| 1215 | 25, 26, 27, 28, 29, 32, 33, 34, 35, 38, 39, 40, 41, 42, 45, 46, 47}, | ||
| 1216 | }, | ||
| 1217 | }; | ||
| 1525 | 1218 | ||
| 1526 | const std::array<u8, 3672> RandomMiiEyebrowType{ | 1219 | const std::array<Service::Mii::RandomMiiData2, 3> RandomMiiEyeColor{ |
| 1527 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | 1220 | Service::Mii::RandomMiiData2{ |
| 1528 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 1221 | .arg_1 = 0, |
| 1529 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 1222 | .values_count = 10, |
| 1530 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | 1223 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, |
| 1531 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | 1224 | }, |
| 1532 | 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1225 | Service::Mii::RandomMiiData2{ |
| 1533 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1226 | .arg_1 = 1, |
| 1534 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1227 | .values_count = 10, |
| 1535 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1228 | .values = {0, 1, 1, 2, 3, 3, 4, 4, 4, 5}, |
| 1536 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1229 | }, |
| 1537 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1230 | Service::Mii::RandomMiiData2{ |
| 1538 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1231 | .arg_1 = 2, |
| 1539 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1232 | .values_count = 10, |
| 1540 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1233 | .values = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, |
| 1541 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 1234 | }, |
| 1542 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 1235 | }; |
| 1543 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1544 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1545 | 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1546 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1547 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1548 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1549 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1550 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1551 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1552 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1553 | 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1554 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 1555 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1556 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1557 | 0x0e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 1558 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1559 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1560 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1561 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1562 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1563 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1564 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1565 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1566 | 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1567 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 1568 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1569 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 1570 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1571 | 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | ||
| 1572 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1573 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1574 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1575 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1576 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1577 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1578 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | ||
| 1579 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 1580 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 1581 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1582 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1583 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 1584 | 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1585 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1586 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1587 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1588 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1589 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1590 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1591 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1592 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 1593 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1594 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1595 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 1596 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 1597 | 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1598 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1599 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1600 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1601 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1602 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1603 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1604 | 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1605 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 1606 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1607 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 1608 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 1609 | 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1610 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1611 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1612 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1613 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1614 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1615 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1616 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1617 | 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 1618 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 1619 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1620 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1621 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | ||
| 1622 | 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1623 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1624 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1625 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1626 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1627 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1628 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1629 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 1630 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 1631 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1632 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1633 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 1634 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 1635 | 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1636 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1637 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1638 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1639 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1640 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1641 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1642 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1643 | 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1644 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1645 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1646 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1647 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1648 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1649 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1650 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1651 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1652 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1653 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1654 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1655 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1656 | 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1657 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1658 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1659 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1660 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1661 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1662 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1663 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1664 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1665 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1666 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1667 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1668 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 1669 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1670 | 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1671 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1672 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1673 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1674 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1675 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1676 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1677 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1678 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1679 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1680 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1681 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 1682 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1683 | 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1684 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1685 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1686 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1687 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1688 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1689 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1690 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1691 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1692 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1693 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1694 | 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1695 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1696 | 0x0f, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1697 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1698 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1699 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1700 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1701 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1702 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1703 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1704 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1705 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1706 | 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1707 | 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1708 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1709 | 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1710 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1711 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1712 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1713 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1714 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1715 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1716 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1717 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1718 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1719 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 1720 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1721 | 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1722 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1723 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1724 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1725 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1726 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1727 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1728 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1729 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1730 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1731 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1732 | 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1733 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1734 | 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1735 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1736 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1737 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1738 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1739 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1740 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1741 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1742 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1743 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1744 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1745 | 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1746 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1747 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1748 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1749 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1750 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1751 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1752 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1753 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1754 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1755 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1756 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 1757 | 1236 | ||
| 1758 | const std::array<u8, 3672> RandomMiiNoseType{ | 1237 | const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiEyebrowType{ |
| 1759 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | 1238 | Service::Mii::RandomMiiData4{ |
| 1760 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 1239 | .gender = Gender::Male, |
| 1761 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 1240 | .age = Age::Young, |
| 1762 | 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1241 | .race = Race::Black, |
| 1763 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1242 | .values_count = 18, |
| 1764 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1243 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 20}, |
| 1765 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1244 | }, |
| 1766 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1245 | Service::Mii::RandomMiiData4{ |
| 1767 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1246 | .gender = Gender::Male, |
| 1768 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1247 | .age = Age::Normal, |
| 1769 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1248 | .race = Race::Black, |
| 1770 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1249 | .values_count = 18, |
| 1771 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1250 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 20}, |
| 1772 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1251 | }, |
| 1773 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 1252 | Service::Mii::RandomMiiData4{ |
| 1774 | 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 1253 | .gender = Gender::Male, |
| 1775 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1254 | .age = Age::Old, |
| 1776 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1255 | .race = Race::Black, |
| 1777 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1256 | .values_count = 18, |
| 1778 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1257 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 20}, |
| 1779 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1258 | }, |
| 1780 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1259 | Service::Mii::RandomMiiData4{ |
| 1781 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1260 | .gender = Gender::Male, |
| 1782 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1261 | .age = Age::Young, |
| 1783 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1262 | .race = Race::White, |
| 1784 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1263 | .values_count = 23, |
| 1785 | 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1264 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, |
| 1786 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | 1265 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, |
| 1787 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | 1266 | }, |
| 1788 | 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1267 | Service::Mii::RandomMiiData4{ |
| 1789 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1268 | .gender = Gender::Male, |
| 1790 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1269 | .age = Age::Normal, |
| 1791 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1270 | .race = Race::White, |
| 1792 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1271 | .values_count = 23, |
| 1793 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1272 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, |
| 1794 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1273 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, |
| 1795 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1274 | }, |
| 1796 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1275 | Service::Mii::RandomMiiData4{ |
| 1797 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1276 | .gender = Gender::Male, |
| 1798 | 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1277 | .age = Age::Old, |
| 1799 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 1278 | .race = Race::White, |
| 1800 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 1279 | .values_count = 23, |
| 1801 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | 1280 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, |
| 1802 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1281 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, |
| 1803 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1282 | }, |
| 1804 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1283 | Service::Mii::RandomMiiData4{ |
| 1805 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1284 | .gender = Gender::Male, |
| 1806 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1285 | .age = Age::Young, |
| 1807 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1286 | .race = Race::Asian, |
| 1808 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1287 | .values_count = 21, |
| 1809 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1288 | .values = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22}, |
| 1810 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | 1289 | }, |
| 1811 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 1290 | Service::Mii::RandomMiiData4{ |
| 1812 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 1291 | .gender = Gender::Male, |
| 1813 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | 1292 | .age = Age::Normal, |
| 1814 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | 1293 | .race = Race::Asian, |
| 1815 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1294 | .values_count = 21, |
| 1816 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1295 | .values = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22}, |
| 1817 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1296 | }, |
| 1818 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1297 | Service::Mii::RandomMiiData4{ |
| 1819 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1298 | .gender = Gender::Male, |
| 1820 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1299 | .age = Age::Old, |
| 1821 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1300 | .race = Race::Asian, |
| 1822 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1301 | .values_count = 21, |
| 1823 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1302 | .values = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22}, |
| 1824 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 1303 | }, |
| 1825 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 1304 | Service::Mii::RandomMiiData4{ |
| 1826 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | 1305 | .gender = Gender::Female, |
| 1827 | 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1306 | .age = Age::Young, |
| 1828 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1307 | .race = Race::Black, |
| 1829 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1308 | .values_count = 9, |
| 1830 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1309 | .values = {0, 1, 3, 7, 8, 9, 10, 11, 13}, |
| 1831 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1310 | }, |
| 1832 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1311 | Service::Mii::RandomMiiData4{ |
| 1833 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1312 | .gender = Gender::Female, |
| 1834 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1313 | .age = Age::Normal, |
| 1835 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1314 | .race = Race::Black, |
| 1836 | 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1315 | .values_count = 9, |
| 1837 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | 1316 | .values = {0, 1, 3, 7, 8, 9, 10, 11, 13}, |
| 1838 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 1317 | }, |
| 1839 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | 1318 | Service::Mii::RandomMiiData4{ |
| 1840 | 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | 1319 | .gender = Gender::Female, |
| 1841 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1320 | .age = Age::Old, |
| 1842 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1321 | .race = Race::Black, |
| 1843 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1322 | .values_count = 9, |
| 1844 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1323 | .values = {0, 1, 3, 7, 8, 9, 10, 11, 13}, |
| 1845 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1324 | }, |
| 1846 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1325 | Service::Mii::RandomMiiData4{ |
| 1847 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1326 | .gender = Gender::Female, |
| 1848 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1327 | .age = Age::Young, |
| 1849 | 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1328 | .race = Race::White, |
| 1850 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 1329 | .values_count = 11, |
| 1851 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 1330 | .values = {0, 1, 3, 7, 8, 9, 10, 11, 13, 15, 19}, |
| 1852 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | 1331 | }, |
| 1853 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1332 | Service::Mii::RandomMiiData4{ |
| 1854 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1333 | .gender = Gender::Female, |
| 1855 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1334 | .age = Age::Normal, |
| 1856 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1335 | .race = Race::White, |
| 1857 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1336 | .values_count = 11, |
| 1858 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1337 | .values = {0, 1, 3, 7, 8, 9, 10, 11, 13, 15, 19}, |
| 1859 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1338 | }, |
| 1860 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1339 | Service::Mii::RandomMiiData4{ |
| 1861 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | 1340 | .gender = Gender::Female, |
| 1862 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 1341 | .age = Age::Old, |
| 1863 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 1342 | .race = Race::White, |
| 1864 | 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | 1343 | .values_count = 11, |
| 1865 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1344 | .values = {0, 1, 3, 7, 8, 9, 10, 11, 13, 15, 19}, |
| 1866 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1345 | }, |
| 1867 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1346 | Service::Mii::RandomMiiData4{ |
| 1868 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1347 | .gender = Gender::Female, |
| 1869 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1348 | .age = Age::Young, |
| 1870 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1349 | .race = Race::Asian, |
| 1871 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1350 | .values_count = 9, |
| 1872 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1351 | .values = {0, 3, 7, 8, 9, 10, 11, 13, 15}, |
| 1873 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1352 | }, |
| 1874 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1353 | Service::Mii::RandomMiiData4{ |
| 1875 | 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 1354 | .gender = Gender::Female, |
| 1876 | 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1355 | .age = Age::Normal, |
| 1877 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1356 | .race = Race::Asian, |
| 1878 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1357 | .values_count = 9, |
| 1879 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1358 | .values = {0, 3, 7, 8, 9, 10, 11, 13, 15}, |
| 1880 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1359 | }, |
| 1881 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1360 | Service::Mii::RandomMiiData4{ |
| 1882 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1361 | .gender = Gender::Female, |
| 1883 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1362 | .age = Age::Old, |
| 1884 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1363 | .race = Race::Asian, |
| 1885 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1364 | .values_count = 9, |
| 1886 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1365 | .values = {0, 3, 7, 8, 9, 10, 11, 13, 15}, |
| 1887 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1366 | }, |
| 1888 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 1367 | }; |
| 1889 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1890 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1891 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1892 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1893 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1894 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1895 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1896 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1897 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1898 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1899 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1900 | 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 1901 | 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1902 | 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1903 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1904 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1905 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1906 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1907 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1908 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1909 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1910 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1911 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1912 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 1913 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 1914 | 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1915 | 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 1916 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1917 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1918 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1919 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1920 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1921 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1922 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1923 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1924 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1925 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1926 | 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 1927 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1928 | 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1929 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1930 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1931 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1932 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1933 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1934 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1935 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1936 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1937 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1938 | 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1939 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 1940 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 1941 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1942 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1943 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1944 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1945 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1946 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1947 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1948 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1949 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1950 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 1951 | 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 1952 | 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 1953 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 1954 | 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1955 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1956 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1957 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1958 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1959 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1960 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1961 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1962 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1963 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | ||
| 1964 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 1965 | 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | ||
| 1966 | 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1967 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1968 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1969 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1970 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1971 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1972 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1973 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1974 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1975 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 1976 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1977 | 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 1978 | 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 1979 | 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1980 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1981 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1982 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1983 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1984 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1985 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1986 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1987 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 1988 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 1989 | 1368 | ||
| 1990 | const std::array<u8, 3672> RandomMiiMouthType{ | 1369 | const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiNoseType{ |
| 1991 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | 1370 | Service::Mii::RandomMiiData4{ |
| 1992 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 1371 | .gender = Gender::Male, |
| 1993 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 1372 | .age = Age::Young, |
| 1994 | 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | 1373 | .race = Race::Black, |
| 1995 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | 1374 | .values_count = 11, |
| 1996 | 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | 1375 | .values = {0, 1, 2, 3, 4, 5, 7, 8, 10, 13, 14}, |
| 1997 | 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | 1376 | }, |
| 1998 | 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1377 | Service::Mii::RandomMiiData4{ |
| 1999 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1378 | .gender = Gender::Male, |
| 2000 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1379 | .age = Age::Normal, |
| 2001 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1380 | .race = Race::Black, |
| 2002 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1381 | .values_count = 11, |
| 2003 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1382 | .values = {0, 1, 2, 3, 4, 5, 7, 8, 10, 13, 14}, |
| 2004 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1383 | }, |
| 2005 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 1384 | Service::Mii::RandomMiiData4{ |
| 2006 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | 1385 | .gender = Gender::Male, |
| 2007 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | 1386 | .age = Age::Old, |
| 2008 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | 1387 | .race = Race::Black, |
| 2009 | 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | 1388 | .values_count = 11, |
| 2010 | 0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | 1389 | .values = {0, 1, 2, 3, 4, 5, 7, 8, 10, 13, 14}, |
| 2011 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1390 | }, |
| 2012 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1391 | Service::Mii::RandomMiiData4{ |
| 2013 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1392 | .gender = Gender::Male, |
| 2014 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1393 | .age = Age::Young, |
| 2015 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1394 | .race = Race::White, |
| 2016 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1395 | .values_count = 18, |
| 2017 | 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1396 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, |
| 2018 | 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 1397 | }, |
| 2019 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | 1398 | Service::Mii::RandomMiiData4{ |
| 2020 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | 1399 | .gender = Gender::Male, |
| 2021 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | 1400 | .age = Age::Normal, |
| 2022 | 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, | 1401 | .race = Race::White, |
| 2023 | 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | 1402 | .values_count = 18, |
| 2024 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1403 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, |
| 2025 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1404 | }, |
| 2026 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1405 | Service::Mii::RandomMiiData4{ |
| 2027 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1406 | .gender = Gender::Male, |
| 2028 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1407 | .age = Age::Old, |
| 2029 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1408 | .race = Race::White, |
| 2030 | 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 1409 | .values_count = 15, |
| 2031 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 1410 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 16}, |
| 2032 | 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | 1411 | }, |
| 2033 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | 1412 | Service::Mii::RandomMiiData4{ |
| 2034 | 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | 1413 | .gender = Gender::Male, |
| 2035 | 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | 1414 | .age = Age::Young, |
| 2036 | 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1415 | .race = Race::Asian, |
| 2037 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1416 | .values_count = 18, |
| 2038 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1417 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, |
| 2039 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1418 | }, |
| 2040 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1419 | Service::Mii::RandomMiiData4{ |
| 2041 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1420 | .gender = Gender::Male, |
| 2042 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | 1421 | .age = Age::Normal, |
| 2043 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 1422 | .race = Race::Asian, |
| 2044 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 1423 | .values_count = 18, |
| 2045 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | 1424 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, |
| 2046 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | 1425 | }, |
| 2047 | 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | 1426 | Service::Mii::RandomMiiData4{ |
| 2048 | 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | 1427 | .gender = Gender::Male, |
| 2049 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1428 | .age = Age::Old, |
| 2050 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1429 | .race = Race::Asian, |
| 2051 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1430 | .values_count = 15, |
| 2052 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1431 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 16}, |
| 2053 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1432 | }, |
| 2054 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1433 | Service::Mii::RandomMiiData4{ |
| 2055 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1434 | .gender = Gender::Female, |
| 2056 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | 1435 | .age = Age::Young, |
| 2057 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, | 1436 | .race = Race::Black, |
| 2058 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | 1437 | .values_count = 8, |
| 2059 | 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | 1438 | .values = {0, 1, 3, 4, 8, 10, 13, 14}, |
| 2060 | 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | 1439 | }, |
| 2061 | 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, | 1440 | Service::Mii::RandomMiiData4{ |
| 2062 | 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1441 | .gender = Gender::Female, |
| 2063 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1442 | .age = Age::Normal, |
| 2064 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1443 | .race = Race::Black, |
| 2065 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1444 | .values_count = 8, |
| 2066 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1445 | .values = {0, 1, 3, 4, 8, 10, 13, 14}, |
| 2067 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1446 | }, |
| 2068 | 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1447 | Service::Mii::RandomMiiData4{ |
| 2069 | 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 1448 | .gender = Gender::Female, |
| 2070 | 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | 1449 | .age = Age::Old, |
| 2071 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | 1450 | .race = Race::Black, |
| 2072 | 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | 1451 | .values_count = 8, |
| 2073 | 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | 1452 | .values = {0, 1, 3, 4, 8, 10, 13, 14}, |
| 2074 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1453 | }, |
| 2075 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1454 | Service::Mii::RandomMiiData4{ |
| 2076 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1455 | .gender = Gender::Female, |
| 2077 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1456 | .age = Age::Young, |
| 2078 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1457 | .race = Race::White, |
| 2079 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1458 | .values_count = 12, |
| 2080 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | 1459 | .values = {0, 1, 3, 4, 6, 8, 9, 10, 11, 13, 14, 15}, |
| 2081 | 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | 1460 | }, |
| 2082 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 1461 | Service::Mii::RandomMiiData4{ |
| 2083 | 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | 1462 | .gender = Gender::Female, |
| 2084 | 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | 1463 | .age = Age::Normal, |
| 2085 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | 1464 | .race = Race::White, |
| 2086 | 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, | 1465 | .values_count = 11, |
| 2087 | 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1466 | .values = {0, 1, 3, 4, 6, 8, 9, 10, 11, 13, 15}, |
| 2088 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1467 | }, |
| 2089 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1468 | Service::Mii::RandomMiiData4{ |
| 2090 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1469 | .gender = Gender::Female, |
| 2091 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1470 | .age = Age::Old, |
| 2092 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1471 | .race = Race::White, |
| 2093 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | 1472 | .values_count = 10, |
| 2094 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | 1473 | .values = {0, 1, 3, 4, 6, 8, 10, 11, 13, 14}, |
| 2095 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, | 1474 | }, |
| 2096 | 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | 1475 | Service::Mii::RandomMiiData4{ |
| 2097 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | 1476 | .gender = Gender::Female, |
| 2098 | 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | 1477 | .age = Age::Young, |
| 2099 | 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | 1478 | .race = Race::Asian, |
| 2100 | 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1479 | .values_count = 12, |
| 2101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1480 | .values = {0, 1, 3, 4, 6, 8, 9, 10, 11, 13, 14, 15}, |
| 2102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1481 | }, |
| 2103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1482 | Service::Mii::RandomMiiData4{ |
| 2104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1483 | .gender = Gender::Female, |
| 2105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | 1484 | .age = Age::Normal, |
| 2106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1485 | .race = Race::Asian, |
| 2107 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | 1486 | .values_count = 11, |
| 2108 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | 1487 | .values = {0, 1, 3, 4, 6, 8, 9, 10, 11, 13, 15}, |
| 2109 | 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | 1488 | }, |
| 2110 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | 1489 | Service::Mii::RandomMiiData4{ |
| 2111 | 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | 1490 | .gender = Gender::Female, |
| 2112 | 0x1e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | 1491 | .age = Age::Old, |
| 2113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1492 | .race = Race::Asian, |
| 2114 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1493 | .values_count = 10, |
| 2115 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1494 | .values = {0, 1, 3, 4, 6, 8, 10, 11, 13, 14}, |
| 2116 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1495 | }, |
| 2117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1496 | }; |
| 2118 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 2119 | 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 2120 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 2121 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 2122 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 2123 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 2124 | 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | ||
| 2125 | 0x1e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, | ||
| 2126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2131 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2132 | 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 2133 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 2134 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 2135 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 2136 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | ||
| 2137 | 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, | ||
| 2138 | 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2139 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2143 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2144 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 2145 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 2146 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 2147 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 2148 | 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 2149 | 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 2150 | 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 2151 | 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 2157 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2158 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 2159 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 2160 | 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 2161 | 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, | ||
| 2162 | 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, | ||
| 2163 | 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 2164 | 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 2170 | 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 2171 | 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 2172 | 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | ||
| 2173 | 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, | ||
| 2174 | 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, | ||
| 2175 | 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 2176 | 0x1d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2182 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 2183 | 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 2184 | 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 2185 | 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, | ||
| 2186 | 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 2187 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | ||
| 2188 | 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 2189 | 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2195 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, | ||
| 2196 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, | ||
| 2197 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | ||
| 2198 | 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, | ||
| 2199 | 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, | ||
| 2200 | 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, | ||
| 2201 | 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, | ||
| 2202 | 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2206 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2207 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 2208 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2209 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 2210 | 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 2211 | 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, | ||
| 2212 | 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, | ||
| 2213 | 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, | ||
| 2214 | 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 2215 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 2220 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 2221 | 1497 | ||
| 2222 | const std::array<u8, 588> RandomMiiGlassType{ | 1498 | const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiMouthType{ |
| 2223 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, | 1499 | Service::Mii::RandomMiiData4{ |
| 2224 | 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1500 | .gender = Gender::Male, |
| 2225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1501 | .age = Age::Young, |
| 2226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1502 | .race = Race::Black, |
| 2227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1503 | .values_count = 25, |
| 2228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1504 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 12, 14, 15, 17, 18, |
| 2229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1505 | 19, 21, 22, 23, 25, 26, 28, 30, 32, 33, 34, 35}, |
| 2230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1506 | }, |
| 2231 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1507 | Service::Mii::RandomMiiData4{ |
| 2232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1508 | .gender = Gender::Male, |
| 2233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1509 | .age = Age::Normal, |
| 2234 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1510 | .race = Race::Black, |
| 2235 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, | 1511 | .values_count = 27, |
| 2236 | 0x56, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, | 1512 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, |
| 2237 | 0x60, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1513 | 18, 19, 21, 22, 23, 25, 26, 28, 30, 32, 33, 34, 35}, |
| 2238 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1514 | }, |
| 2239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1515 | Service::Mii::RandomMiiData4{ |
| 2240 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1516 | .gender = Gender::Male, |
| 2241 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1517 | .age = Age::Old, |
| 2242 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1518 | .race = Race::Black, |
| 2243 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1519 | .values_count = 28, |
| 2244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1520 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, |
| 2245 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1521 | 18, 19, 21, 22, 23, 25, 26, 28, 30, 31, 32, 33, 34, 35}, |
| 2246 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1522 | }, |
| 2247 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, | 1523 | Service::Mii::RandomMiiData4{ |
| 2248 | 0x4e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, | 1524 | .gender = Gender::Male, |
| 2249 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, | 1525 | .age = Age::Young, |
| 2250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1526 | .race = Race::White, |
| 2251 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1527 | .values_count = 24, |
| 2252 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1528 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 12, 14, 15, 16, |
| 2253 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1529 | 17, 18, 19, 20, 21, 22, 23, 30, 31, 33, 34, 35}, |
| 2254 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1530 | }, |
| 2255 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1531 | Service::Mii::RandomMiiData4{ |
| 2256 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1532 | .gender = Gender::Male, |
| 2257 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1533 | .age = Age::Normal, |
| 2258 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1534 | .race = Race::White, |
| 2259 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | 1535 | .values_count = 26, |
| 1536 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
| 1537 | 16, 17, 18, 19, 20, 21, 22, 23, 30, 31, 33, 34, 35}, | ||
| 1538 | }, | ||
| 1539 | Service::Mii::RandomMiiData4{ | ||
| 1540 | .gender = Gender::Male, | ||
| 1541 | .age = Age::Old, | ||
| 1542 | .race = Race::White, | ||
| 1543 | .values_count = 26, | ||
| 1544 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
| 1545 | 16, 17, 18, 19, 20, 21, 22, 23, 30, 31, 33, 34, 35}, | ||
| 1546 | }, | ||
| 1547 | Service::Mii::RandomMiiData4{ | ||
| 1548 | .gender = Gender::Male, | ||
| 1549 | .age = Age::Young, | ||
| 1550 | .race = Race::Asian, | ||
| 1551 | .values_count = 24, | ||
| 1552 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 12, 14, 15, 16, | ||
| 1553 | 17, 18, 19, 20, 21, 22, 23, 30, 31, 33, 34, 35}, | ||
| 1554 | }, | ||
| 1555 | Service::Mii::RandomMiiData4{ | ||
| 1556 | .gender = Gender::Male, | ||
| 1557 | .age = Age::Normal, | ||
| 1558 | .race = Race::Asian, | ||
| 1559 | .values_count = 26, | ||
| 1560 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
| 1561 | 16, 17, 18, 19, 20, 21, 22, 23, 30, 31, 33, 34, 35}, | ||
| 1562 | }, | ||
| 1563 | Service::Mii::RandomMiiData4{ | ||
| 1564 | .gender = Gender::Male, | ||
| 1565 | .age = Age::Old, | ||
| 1566 | .race = Race::Asian, | ||
| 1567 | .values_count = 26, | ||
| 1568 | .values = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
| 1569 | 16, 17, 18, 19, 20, 21, 22, 23, 30, 31, 33, 34, 35}, | ||
| 1570 | }, | ||
| 1571 | Service::Mii::RandomMiiData4{ | ||
| 1572 | .gender = Gender::Female, | ||
| 1573 | .age = Age::Young, | ||
| 1574 | .race = Race::Black, | ||
| 1575 | .values_count = 25, | ||
| 1576 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 15, | ||
| 1577 | 17, 18, 19, 21, 22, 23, 25, 26, 30, 33, 34, 35}, | ||
| 1578 | }, | ||
| 1579 | Service::Mii::RandomMiiData4{ | ||
| 1580 | .gender = Gender::Female, | ||
| 1581 | .age = Age::Normal, | ||
| 1582 | .race = Race::Black, | ||
| 1583 | .values_count = 26, | ||
| 1584 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, | ||
| 1585 | 15, 17, 18, 19, 21, 22, 23, 25, 26, 30, 33, 34, 35}, | ||
| 1586 | }, | ||
| 1587 | Service::Mii::RandomMiiData4{ | ||
| 1588 | .gender = Gender::Female, | ||
| 1589 | .age = Age::Old, | ||
| 1590 | .race = Race::Black, | ||
| 1591 | .values_count = 26, | ||
| 1592 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, | ||
| 1593 | 15, 17, 18, 19, 21, 22, 23, 25, 26, 30, 33, 34, 35}, | ||
| 1594 | }, | ||
| 1595 | Service::Mii::RandomMiiData4{ | ||
| 1596 | .gender = Gender::Female, | ||
| 1597 | .age = Age::Young, | ||
| 1598 | .race = Race::White, | ||
| 1599 | .values_count = 25, | ||
| 1600 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 15, | ||
| 1601 | 17, 18, 19, 21, 22, 23, 24, 26, 27, 29, 33, 35}, | ||
| 1602 | }, | ||
| 1603 | Service::Mii::RandomMiiData4{ | ||
| 1604 | .gender = Gender::Female, | ||
| 1605 | .age = Age::Normal, | ||
| 1606 | .race = Race::White, | ||
| 1607 | .values_count = 26, | ||
| 1608 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, | ||
| 1609 | 15, 17, 18, 19, 21, 22, 23, 24, 26, 27, 29, 33, 35}, | ||
| 1610 | }, | ||
| 1611 | Service::Mii::RandomMiiData4{ | ||
| 1612 | .gender = Gender::Female, | ||
| 1613 | .age = Age::Old, | ||
| 1614 | .race = Race::White, | ||
| 1615 | .values_count = 25, | ||
| 1616 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, | ||
| 1617 | 15, 17, 18, 19, 21, 22, 23, 24, 25, 29, 33, 35}, | ||
| 1618 | }, | ||
| 1619 | Service::Mii::RandomMiiData4{ | ||
| 1620 | .gender = Gender::Female, | ||
| 1621 | .age = Age::Young, | ||
| 1622 | .race = Race::Asian, | ||
| 1623 | .values_count = 24, | ||
| 1624 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, | ||
| 1625 | 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 29, 33}, | ||
| 1626 | }, | ||
| 1627 | Service::Mii::RandomMiiData4{ | ||
| 1628 | .gender = Gender::Female, | ||
| 1629 | .age = Age::Normal, | ||
| 1630 | .race = Race::Asian, | ||
| 1631 | .values_count = 25, | ||
| 1632 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, | ||
| 1633 | 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 29, 33}, | ||
| 1634 | }, | ||
| 1635 | Service::Mii::RandomMiiData4{ | ||
| 1636 | .gender = Gender::Female, | ||
| 1637 | .age = Age::Old, | ||
| 1638 | .race = Race::Asian, | ||
| 1639 | .values_count = 25, | ||
| 1640 | .values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, | ||
| 1641 | 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 29, 33}, | ||
| 1642 | }, | ||
| 1643 | }; | ||
| 1644 | |||
| 1645 | const std::array<Service::Mii::RandomMiiData2, 3> RandomMiiGlassType{ | ||
| 1646 | Service::Mii::RandomMiiData2{ | ||
| 1647 | .arg_1 = 0, | ||
| 1648 | .values_count = 9, | ||
| 1649 | .values = {90, 94, 96, 100, 0, 0, 0, 0, 0}, | ||
| 1650 | }, | ||
| 1651 | Service::Mii::RandomMiiData2{ | ||
| 1652 | .arg_1 = 1, | ||
| 1653 | .values_count = 9, | ||
| 1654 | .values = {83, 86, 90, 93, 94, 96, 98, 100, 0}, | ||
| 1655 | }, | ||
| 1656 | Service::Mii::RandomMiiData2{ | ||
| 1657 | .arg_1 = 2, | ||
| 1658 | .values_count = 9, | ||
| 1659 | .values = {78, 83, 0, 93, 0, 0, 98, 100, 0}, | ||
| 1660 | }, | ||
| 1661 | }; | ||
| 2260 | 1662 | ||
| 2261 | } // namespace Service::Mii::RawData | 1663 | } // namespace Service::Mii::RawData |
diff --git a/src/core/hle/service/mii/raw_data.h b/src/core/hle/service/mii/raw_data.h index a02a5c0fd..0e35d69d2 100644 --- a/src/core/hle/service/mii/raw_data.h +++ b/src/core/hle/service/mii/raw_data.h | |||
| @@ -7,21 +7,22 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "core/hle/service/mii/manager.h" | ||
| 10 | 11 | ||
| 11 | namespace Service::Mii::RawData { | 12 | namespace Service::Mii::RawData { |
| 12 | 13 | ||
| 13 | extern const std::array<u8, 1728> DefaultMii; | 14 | extern const std::array<Service::Mii::DefaultMii, 8> DefaultMii; |
| 14 | extern const std::array<u8, 3672> RandomMiiFaceline; | 15 | extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFaceline; |
| 15 | extern const std::array<u8, 1200> RandomMiiFacelineColor; | 16 | extern const std::array<Service::Mii::RandomMiiData3, 6> RandomMiiFacelineColor; |
| 16 | extern const std::array<u8, 3672> RandomMiiFacelineWrinkle; | 17 | extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFacelineWrinkle; |
| 17 | extern const std::array<u8, 3672> RandomMiiFacelineMakeup; | 18 | extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFacelineMakeup; |
| 18 | extern const std::array<u8, 3672> RandomMiiHairType; | 19 | extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiHairType; |
| 19 | extern const std::array<u8, 1800> RandomMiiHairColor; | 20 | extern const std::array<Service::Mii::RandomMiiData3, 9> RandomMiiHairColor; |
| 20 | extern const std::array<u8, 3672> RandomMiiEyeType; | 21 | extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiEyeType; |
| 21 | extern const std::array<u8, 588> RandomMiiEyeColor; | 22 | extern const std::array<Service::Mii::RandomMiiData2, 3> RandomMiiEyeColor; |
| 22 | extern const std::array<u8, 3672> RandomMiiEyebrowType; | 23 | extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiEyebrowType; |
| 23 | extern const std::array<u8, 3672> RandomMiiNoseType; | 24 | extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiNoseType; |
| 24 | extern const std::array<u8, 3672> RandomMiiMouthType; | 25 | extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiMouthType; |
| 25 | extern const std::array<u8, 588> RandomMiiGlassType; | 26 | extern const std::array<Service::Mii::RandomMiiData2, 3> RandomMiiGlassType; |
| 26 | 27 | ||
| 27 | } // namespace Service::Mii::RawData | 28 | } // namespace Service::Mii::RawData |
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 641bcadea..5d6d25696 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -8,10 +8,11 @@ | |||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/kernel/k_event.h" | ||
| 12 | #include "core/hle/kernel/k_readable_event.h" | ||
| 13 | #include "core/hle/kernel/k_thread.h" | ||
| 14 | #include "core/hle/kernel/k_writable_event.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/readable_event.h" | ||
| 13 | #include "core/hle/kernel/thread.h" | ||
| 14 | #include "core/hle/kernel/writable_event.h" | ||
| 15 | #include "core/hle/lock.h" | 16 | #include "core/hle/lock.h" |
| 16 | #include "core/hle/service/nfp/nfp.h" | 17 | #include "core/hle/service/nfp/nfp.h" |
| 17 | #include "core/hle/service/nfp/nfp_user.h" | 18 | #include "core/hle/service/nfp/nfp_user.h" |
| @@ -25,7 +26,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& syst | |||
| 25 | const char* name) | 26 | const char* name) |
| 26 | : ServiceFramework{system_, name}, module{std::move(module_)} { | 27 | : ServiceFramework{system_, name}, module{std::move(module_)} { |
| 27 | auto& kernel = system.Kernel(); | 28 | auto& kernel = system.Kernel(); |
| 28 | nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected"); | 29 | nfc_tag_load = Kernel::KEvent::Create(kernel, "IUser:NFCTagDetected"); |
| 30 | nfc_tag_load->Initialize(); | ||
| 29 | } | 31 | } |
| 30 | 32 | ||
| 31 | Module::Interface::~Interface() = default; | 33 | Module::Interface::~Interface() = default; |
| @@ -64,9 +66,10 @@ public: | |||
| 64 | RegisterHandlers(functions); | 66 | RegisterHandlers(functions); |
| 65 | 67 | ||
| 66 | auto& kernel = system.Kernel(); | 68 | auto& kernel = system.Kernel(); |
| 67 | deactivate_event = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:DeactivateEvent"); | 69 | deactivate_event = Kernel::KEvent::Create(kernel, "IUser:DeactivateEvent"); |
| 68 | availability_change_event = | 70 | deactivate_event->Initialize(); |
| 69 | Kernel::WritableEvent::CreateEventPair(kernel, "IUser:AvailabilityChangeEvent"); | 71 | availability_change_event = Kernel::KEvent::Create(kernel, "IUser:AvailabilityChangeEvent"); |
| 72 | availability_change_event->Initialize(); | ||
| 70 | } | 73 | } |
| 71 | 74 | ||
| 72 | private: | 75 | private: |
| @@ -164,7 +167,7 @@ private: | |||
| 164 | 167 | ||
| 165 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 168 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 166 | rb.Push(RESULT_SUCCESS); | 169 | rb.Push(RESULT_SUCCESS); |
| 167 | rb.PushCopyObjects(deactivate_event.readable); | 170 | rb.PushCopyObjects(deactivate_event->GetReadableEvent()); |
| 168 | } | 171 | } |
| 169 | 172 | ||
| 170 | void StopDetection(Kernel::HLERequestContext& ctx) { | 173 | void StopDetection(Kernel::HLERequestContext& ctx) { |
| @@ -173,7 +176,7 @@ private: | |||
| 173 | switch (device_state) { | 176 | switch (device_state) { |
| 174 | case DeviceState::TagFound: | 177 | case DeviceState::TagFound: |
| 175 | case DeviceState::TagNearby: | 178 | case DeviceState::TagNearby: |
| 176 | deactivate_event.writable->Signal(); | 179 | deactivate_event->GetWritableEvent()->Signal(); |
| 177 | device_state = DeviceState::Initialized; | 180 | device_state = DeviceState::Initialized; |
| 178 | break; | 181 | break; |
| 179 | case DeviceState::SearchingForTag: | 182 | case DeviceState::SearchingForTag: |
| @@ -262,7 +265,7 @@ private: | |||
| 262 | 265 | ||
| 263 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 266 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 264 | rb.Push(RESULT_SUCCESS); | 267 | rb.Push(RESULT_SUCCESS); |
| 265 | rb.PushCopyObjects(availability_change_event.readable); | 268 | rb.PushCopyObjects(availability_change_event->GetReadableEvent()); |
| 266 | } | 269 | } |
| 267 | 270 | ||
| 268 | void GetRegisterInfo(Kernel::HLERequestContext& ctx) { | 271 | void GetRegisterInfo(Kernel::HLERequestContext& ctx) { |
| @@ -316,8 +319,8 @@ private: | |||
| 316 | const u32 npad_id{0}; // Player 1 controller | 319 | const u32 npad_id{0}; // Player 1 controller |
| 317 | State state{State::NonInitialized}; | 320 | State state{State::NonInitialized}; |
| 318 | DeviceState device_state{DeviceState::Initialized}; | 321 | DeviceState device_state{DeviceState::Initialized}; |
| 319 | Kernel::EventPair deactivate_event; | 322 | std::shared_ptr<Kernel::KEvent> deactivate_event; |
| 320 | Kernel::EventPair availability_change_event; | 323 | std::shared_ptr<Kernel::KEvent> availability_change_event; |
| 321 | const Module::Interface& nfp_interface; | 324 | const Module::Interface& nfp_interface; |
| 322 | }; | 325 | }; |
| 323 | 326 | ||
| @@ -336,12 +339,12 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | |||
| 336 | } | 339 | } |
| 337 | 340 | ||
| 338 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); | 341 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); |
| 339 | nfc_tag_load.writable->Signal(); | 342 | nfc_tag_load->GetWritableEvent()->Signal(); |
| 340 | return true; | 343 | return true; |
| 341 | } | 344 | } |
| 342 | 345 | ||
| 343 | const std::shared_ptr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const { | 346 | const std::shared_ptr<Kernel::KReadableEvent>& Module::Interface::GetNFCEvent() const { |
| 344 | return nfc_tag_load.readable; | 347 | return nfc_tag_load->GetReadableEvent(); |
| 345 | } | 348 | } |
| 346 | 349 | ||
| 347 | const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { | 350 | const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { |
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 295de535b..c46551760 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h | |||
| @@ -6,10 +6,13 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include "core/hle/kernel/readable_event.h" | 9 | |
| 10 | #include "core/hle/kernel/writable_event.h" | ||
| 11 | #include "core/hle/service/service.h" | 10 | #include "core/hle/service/service.h" |
| 12 | 11 | ||
| 12 | namespace Kernel { | ||
| 13 | class KEvent; | ||
| 14 | } | ||
| 15 | |||
| 13 | namespace Service::NFP { | 16 | namespace Service::NFP { |
| 14 | 17 | ||
| 15 | class Module final { | 18 | class Module final { |
| @@ -35,11 +38,11 @@ public: | |||
| 35 | 38 | ||
| 36 | void CreateUserInterface(Kernel::HLERequestContext& ctx); | 39 | void CreateUserInterface(Kernel::HLERequestContext& ctx); |
| 37 | bool LoadAmiibo(const std::vector<u8>& buffer); | 40 | bool LoadAmiibo(const std::vector<u8>& buffer); |
| 38 | const std::shared_ptr<Kernel::ReadableEvent>& GetNFCEvent() const; | 41 | const std::shared_ptr<Kernel::KReadableEvent>& GetNFCEvent() const; |
| 39 | const AmiiboFile& GetAmiiboBuffer() const; | 42 | const AmiiboFile& GetAmiiboBuffer() const; |
| 40 | 43 | ||
| 41 | private: | 44 | private: |
| 42 | Kernel::EventPair nfc_tag_load{}; | 45 | std::shared_ptr<Kernel::KEvent> nfc_tag_load; |
| 43 | AmiiboFile amiibo{}; | 46 | AmiiboFile amiibo{}; |
| 44 | 47 | ||
| 45 | protected: | 48 | protected: |
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index ef5176bea..afb3342d6 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -4,9 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/hle/ipc_helpers.h" | 6 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/k_event.h" | ||
| 8 | #include "core/hle/kernel/k_readable_event.h" | ||
| 7 | #include "core/hle/kernel/kernel.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 8 | #include "core/hle/kernel/readable_event.h" | ||
| 9 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | #include "core/hle/service/nifm/nifm.h" | 10 | #include "core/hle/service/nifm/nifm.h" |
| 11 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 12 | #include "core/network/network.h" | 12 | #include "core/network/network.h" |
| @@ -21,6 +21,93 @@ enum class RequestState : u32 { | |||
| 21 | Connected = 3, | 21 | Connected = 3, |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | struct IpAddressSetting { | ||
| 25 | bool is_automatic{}; | ||
| 26 | Network::IPv4Address current_address{}; | ||
| 27 | Network::IPv4Address subnet_mask{}; | ||
| 28 | Network::IPv4Address gateway{}; | ||
| 29 | }; | ||
| 30 | static_assert(sizeof(IpAddressSetting) == 0xD, "IpAddressSetting has incorrect size."); | ||
| 31 | |||
| 32 | struct DnsSetting { | ||
| 33 | bool is_automatic{}; | ||
| 34 | Network::IPv4Address primary_dns{}; | ||
| 35 | Network::IPv4Address secondary_dns{}; | ||
| 36 | }; | ||
| 37 | static_assert(sizeof(DnsSetting) == 0x9, "DnsSetting has incorrect size."); | ||
| 38 | |||
| 39 | struct ProxySetting { | ||
| 40 | bool enabled{}; | ||
| 41 | INSERT_PADDING_BYTES(1); | ||
| 42 | u16 port{}; | ||
| 43 | std::array<char, 0x64> proxy_server{}; | ||
| 44 | bool automatic_auth_enabled{}; | ||
| 45 | std::array<char, 0x20> user{}; | ||
| 46 | std::array<char, 0x20> password{}; | ||
| 47 | INSERT_PADDING_BYTES(1); | ||
| 48 | }; | ||
| 49 | static_assert(sizeof(ProxySetting) == 0xAA, "ProxySetting has incorrect size."); | ||
| 50 | |||
| 51 | struct IpSettingData { | ||
| 52 | IpAddressSetting ip_address_setting{}; | ||
| 53 | DnsSetting dns_setting{}; | ||
| 54 | ProxySetting proxy_setting{}; | ||
| 55 | u16 mtu{}; | ||
| 56 | }; | ||
| 57 | static_assert(sizeof(IpSettingData) == 0xC2, "IpSettingData has incorrect size."); | ||
| 58 | |||
| 59 | struct SfWirelessSettingData { | ||
| 60 | u8 ssid_length{}; | ||
| 61 | std::array<char, 0x20> ssid{}; | ||
| 62 | u8 unknown_1{}; | ||
| 63 | u8 unknown_2{}; | ||
| 64 | u8 unknown_3{}; | ||
| 65 | std::array<char, 0x41> passphrase{}; | ||
| 66 | }; | ||
| 67 | static_assert(sizeof(SfWirelessSettingData) == 0x65, "SfWirelessSettingData has incorrect size."); | ||
| 68 | |||
| 69 | struct NifmWirelessSettingData { | ||
| 70 | u8 ssid_length{}; | ||
| 71 | std::array<char, 0x21> ssid{}; | ||
| 72 | u8 unknown_1{}; | ||
| 73 | INSERT_PADDING_BYTES(1); | ||
| 74 | u32 unknown_2{}; | ||
| 75 | u32 unknown_3{}; | ||
| 76 | std::array<char, 0x41> passphrase{}; | ||
| 77 | INSERT_PADDING_BYTES(3); | ||
| 78 | }; | ||
| 79 | static_assert(sizeof(NifmWirelessSettingData) == 0x70, | ||
| 80 | "NifmWirelessSettingData has incorrect size."); | ||
| 81 | |||
| 82 | #pragma pack(push, 1) | ||
| 83 | struct SfNetworkProfileData { | ||
| 84 | IpSettingData ip_setting_data{}; | ||
| 85 | u128 uuid{}; | ||
| 86 | std::array<char, 0x40> network_name{}; | ||
| 87 | u8 unknown_1{}; | ||
| 88 | u8 unknown_2{}; | ||
| 89 | u8 unknown_3{}; | ||
| 90 | u8 unknown_4{}; | ||
| 91 | SfWirelessSettingData wireless_setting_data{}; | ||
| 92 | INSERT_PADDING_BYTES(1); | ||
| 93 | }; | ||
| 94 | static_assert(sizeof(SfNetworkProfileData) == 0x17C, "SfNetworkProfileData has incorrect size."); | ||
| 95 | |||
| 96 | struct NifmNetworkProfileData { | ||
| 97 | u128 uuid{}; | ||
| 98 | std::array<char, 0x40> network_name{}; | ||
| 99 | u32 unknown_1{}; | ||
| 100 | u32 unknown_2{}; | ||
| 101 | u8 unknown_3{}; | ||
| 102 | u8 unknown_4{}; | ||
| 103 | INSERT_PADDING_BYTES(2); | ||
| 104 | NifmWirelessSettingData wireless_setting_data{}; | ||
| 105 | IpSettingData ip_setting_data{}; | ||
| 106 | }; | ||
| 107 | static_assert(sizeof(NifmNetworkProfileData) == 0x18E, | ||
| 108 | "NifmNetworkProfileData has incorrect size."); | ||
| 109 | #pragma pack(pop) | ||
| 110 | |||
| 24 | class IScanRequest final : public ServiceFramework<IScanRequest> { | 111 | class IScanRequest final : public ServiceFramework<IScanRequest> { |
| 25 | public: | 112 | public: |
| 26 | explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} { | 113 | explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} { |
| @@ -71,8 +158,11 @@ public: | |||
| 71 | RegisterHandlers(functions); | 158 | RegisterHandlers(functions); |
| 72 | 159 | ||
| 73 | auto& kernel = system.Kernel(); | 160 | auto& kernel = system.Kernel(); |
| 74 | event1 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event1"); | 161 | |
| 75 | event2 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event2"); | 162 | event1 = Kernel::KEvent::Create(kernel, "IRequest:Event1"); |
| 163 | event1->Initialize(); | ||
| 164 | event2 = Kernel::KEvent::Create(kernel, "IRequest:Event2"); | ||
| 165 | event2->Initialize(); | ||
| 76 | } | 166 | } |
| 77 | 167 | ||
| 78 | private: | 168 | private: |
| @@ -108,7 +198,7 @@ private: | |||
| 108 | 198 | ||
| 109 | IPC::ResponseBuilder rb{ctx, 2, 2}; | 199 | IPC::ResponseBuilder rb{ctx, 2, 2}; |
| 110 | rb.Push(RESULT_SUCCESS); | 200 | rb.Push(RESULT_SUCCESS); |
| 111 | rb.PushCopyObjects(event1.readable, event2.readable); | 201 | rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent()); |
| 112 | } | 202 | } |
| 113 | 203 | ||
| 114 | void Cancel(Kernel::HLERequestContext& ctx) { | 204 | void Cancel(Kernel::HLERequestContext& ctx) { |
| @@ -128,14 +218,18 @@ private: | |||
| 128 | void GetAppletInfo(Kernel::HLERequestContext& ctx) { | 218 | void GetAppletInfo(Kernel::HLERequestContext& ctx) { |
| 129 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 219 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 130 | 220 | ||
| 131 | IPC::ResponseBuilder rb{ctx, 8}; | 221 | std::vector<u8> out_buffer(ctx.GetWriteBufferSize()); |
| 222 | |||
| 223 | ctx.WriteBuffer(out_buffer); | ||
| 224 | |||
| 225 | IPC::ResponseBuilder rb{ctx, 5}; | ||
| 132 | rb.Push(RESULT_SUCCESS); | 226 | rb.Push(RESULT_SUCCESS); |
| 133 | rb.Push<u32>(0); | 227 | rb.Push<u32>(0); |
| 134 | rb.Push<u32>(0); | 228 | rb.Push<u32>(0); |
| 135 | rb.Push<u32>(0); | 229 | rb.Push<u32>(0); |
| 136 | } | 230 | } |
| 137 | 231 | ||
| 138 | Kernel::EventPair event1, event2; | 232 | std::shared_ptr<Kernel::KEvent> event1, event2; |
| 139 | }; | 233 | }; |
| 140 | 234 | ||
| 141 | class INetworkProfile final : public ServiceFramework<INetworkProfile> { | 235 | class INetworkProfile final : public ServiceFramework<INetworkProfile> { |
| @@ -179,6 +273,46 @@ private: | |||
| 179 | rb.Push(RESULT_SUCCESS); | 273 | rb.Push(RESULT_SUCCESS); |
| 180 | rb.PushIpcInterface<IRequest>(system); | 274 | rb.PushIpcInterface<IRequest>(system); |
| 181 | } | 275 | } |
| 276 | void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) { | ||
| 277 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 278 | |||
| 279 | const SfNetworkProfileData network_profile_data{ | ||
| 280 | .ip_setting_data{ | ||
| 281 | .ip_address_setting{ | ||
| 282 | .is_automatic{true}, | ||
| 283 | .current_address{192, 168, 1, 100}, | ||
| 284 | .subnet_mask{255, 255, 255, 0}, | ||
| 285 | .gateway{192, 168, 1, 1}, | ||
| 286 | }, | ||
| 287 | .dns_setting{ | ||
| 288 | .is_automatic{true}, | ||
| 289 | .primary_dns{1, 1, 1, 1}, | ||
| 290 | .secondary_dns{1, 0, 0, 1}, | ||
| 291 | }, | ||
| 292 | .proxy_setting{ | ||
| 293 | .enabled{false}, | ||
| 294 | .port{}, | ||
| 295 | .proxy_server{}, | ||
| 296 | .automatic_auth_enabled{}, | ||
| 297 | .user{}, | ||
| 298 | .password{}, | ||
| 299 | }, | ||
| 300 | .mtu{1500}, | ||
| 301 | }, | ||
| 302 | .uuid{0xdeadbeef, 0xdeadbeef}, | ||
| 303 | .network_name{"yuzu Network"}, | ||
| 304 | .wireless_setting_data{ | ||
| 305 | .ssid_length{12}, | ||
| 306 | .ssid{"yuzu Network"}, | ||
| 307 | .passphrase{"yuzupassword"}, | ||
| 308 | }, | ||
| 309 | }; | ||
| 310 | |||
| 311 | ctx.WriteBuffer(network_profile_data); | ||
| 312 | |||
| 313 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 314 | rb.Push(RESULT_SUCCESS); | ||
| 315 | } | ||
| 182 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { | 316 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { |
| 183 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 317 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 184 | 318 | ||
| @@ -210,6 +344,34 @@ private: | |||
| 210 | rb.PushIpcInterface<INetworkProfile>(system); | 344 | rb.PushIpcInterface<INetworkProfile>(system); |
| 211 | rb.PushRaw<u128>(uuid); | 345 | rb.PushRaw<u128>(uuid); |
| 212 | } | 346 | } |
| 347 | void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) { | ||
| 348 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 349 | |||
| 350 | struct IpConfigInfo { | ||
| 351 | IpAddressSetting ip_address_setting; | ||
| 352 | DnsSetting dns_setting; | ||
| 353 | }; | ||
| 354 | static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting), | ||
| 355 | "IpConfigInfo has incorrect size."); | ||
| 356 | |||
| 357 | const IpConfigInfo ip_config_info{ | ||
| 358 | .ip_address_setting{ | ||
| 359 | .is_automatic{true}, | ||
| 360 | .current_address{192, 168, 1, 100}, | ||
| 361 | .subnet_mask{255, 255, 255, 0}, | ||
| 362 | .gateway{192, 168, 1, 1}, | ||
| 363 | }, | ||
| 364 | .dns_setting{ | ||
| 365 | .is_automatic{true}, | ||
| 366 | .primary_dns{1, 1, 1, 1}, | ||
| 367 | .secondary_dns{1, 0, 0, 1}, | ||
| 368 | }, | ||
| 369 | }; | ||
| 370 | |||
| 371 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(IpConfigInfo) / sizeof(u32)}; | ||
| 372 | rb.Push(RESULT_SUCCESS); | ||
| 373 | rb.PushRaw<IpConfigInfo>(ip_config_info); | ||
| 374 | } | ||
| 213 | void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { | 375 | void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { |
| 214 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 376 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 215 | 377 | ||
| @@ -248,7 +410,7 @@ IGeneralService::IGeneralService(Core::System& system_) | |||
| 248 | {1, &IGeneralService::GetClientId, "GetClientId"}, | 410 | {1, &IGeneralService::GetClientId, "GetClientId"}, |
| 249 | {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, | 411 | {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, |
| 250 | {4, &IGeneralService::CreateRequest, "CreateRequest"}, | 412 | {4, &IGeneralService::CreateRequest, "CreateRequest"}, |
| 251 | {5, nullptr, "GetCurrentNetworkProfile"}, | 413 | {5, &IGeneralService::GetCurrentNetworkProfile, "GetCurrentNetworkProfile"}, |
| 252 | {6, nullptr, "EnumerateNetworkInterfaces"}, | 414 | {6, nullptr, "EnumerateNetworkInterfaces"}, |
| 253 | {7, nullptr, "EnumerateNetworkProfiles"}, | 415 | {7, nullptr, "EnumerateNetworkProfiles"}, |
| 254 | {8, nullptr, "GetNetworkProfile"}, | 416 | {8, nullptr, "GetNetworkProfile"}, |
| @@ -258,7 +420,7 @@ IGeneralService::IGeneralService(Core::System& system_) | |||
| 258 | {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"}, | 420 | {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"}, |
| 259 | {13, nullptr, "GetCurrentAccessPointOld"}, | 421 | {13, nullptr, "GetCurrentAccessPointOld"}, |
| 260 | {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"}, | 422 | {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"}, |
| 261 | {15, nullptr, "GetCurrentIpConfigInfo"}, | 423 | {15, &IGeneralService::GetCurrentIpConfigInfo, "GetCurrentIpConfigInfo"}, |
| 262 | {16, nullptr, "SetWirelessCommunicationEnabled"}, | 424 | {16, nullptr, "SetWirelessCommunicationEnabled"}, |
| 263 | {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"}, | 425 | {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"}, |
| 264 | {18, nullptr, "GetInternetConnectionStatus"}, | 426 | {18, nullptr, "GetInternetConnectionStatus"}, |
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index d16223064..f3be0b878 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp | |||
| @@ -6,9 +6,10 @@ | |||
| 6 | #include <ctime> | 6 | #include <ctime> |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/k_event.h" | ||
| 10 | #include "core/hle/kernel/k_readable_event.h" | ||
| 11 | #include "core/hle/kernel/k_writable_event.h" | ||
| 9 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/readable_event.h" | ||
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 12 | #include "core/hle/service/nim/nim.h" | 13 | #include "core/hle/service/nim/nim.h" |
| 13 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| 14 | #include "core/hle/service/sm/sm.h" | 15 | #include "core/hle/service/sm/sm.h" |
| @@ -301,17 +302,18 @@ public: | |||
| 301 | RegisterHandlers(functions); | 302 | RegisterHandlers(functions); |
| 302 | 303 | ||
| 303 | auto& kernel = system.Kernel(); | 304 | auto& kernel = system.Kernel(); |
| 304 | finished_event = Kernel::WritableEvent::CreateEventPair( | 305 | finished_event = |
| 305 | kernel, "IEnsureNetworkClockAvailabilityService:FinishEvent"); | 306 | Kernel::KEvent::Create(kernel, "IEnsureNetworkClockAvailabilityService:FinishEvent"); |
| 307 | finished_event->Initialize(); | ||
| 306 | } | 308 | } |
| 307 | 309 | ||
| 308 | private: | 310 | private: |
| 309 | Kernel::EventPair finished_event; | 311 | std::shared_ptr<Kernel::KEvent> finished_event; |
| 310 | 312 | ||
| 311 | void StartTask(Kernel::HLERequestContext& ctx) { | 313 | void StartTask(Kernel::HLERequestContext& ctx) { |
| 312 | // No need to connect to the internet, just finish the task straight away. | 314 | // No need to connect to the internet, just finish the task straight away. |
| 313 | LOG_DEBUG(Service_NIM, "called"); | 315 | LOG_DEBUG(Service_NIM, "called"); |
| 314 | finished_event.writable->Signal(); | 316 | finished_event->GetWritableEvent()->Signal(); |
| 315 | IPC::ResponseBuilder rb{ctx, 2}; | 317 | IPC::ResponseBuilder rb{ctx, 2}; |
| 316 | rb.Push(RESULT_SUCCESS); | 318 | rb.Push(RESULT_SUCCESS); |
| 317 | } | 319 | } |
| @@ -321,7 +323,7 @@ private: | |||
| 321 | 323 | ||
| 322 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 324 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 323 | rb.Push(RESULT_SUCCESS); | 325 | rb.Push(RESULT_SUCCESS); |
| 324 | rb.PushCopyObjects(finished_event.readable); | 326 | rb.PushCopyObjects(finished_event->GetReadableEvent()); |
| 325 | } | 327 | } |
| 326 | 328 | ||
| 327 | void GetResult(Kernel::HLERequestContext& ctx) { | 329 | void GetResult(Kernel::HLERequestContext& ctx) { |
| @@ -333,7 +335,7 @@ private: | |||
| 333 | 335 | ||
| 334 | void Cancel(Kernel::HLERequestContext& ctx) { | 336 | void Cancel(Kernel::HLERequestContext& ctx) { |
| 335 | LOG_DEBUG(Service_NIM, "called"); | 337 | LOG_DEBUG(Service_NIM, "called"); |
| 336 | finished_event.writable->Clear(); | 338 | finished_event->GetWritableEvent()->Clear(); |
| 337 | IPC::ResponseBuilder rb{ctx, 2}; | 339 | IPC::ResponseBuilder rb{ctx, 2}; |
| 338 | rb.Push(RESULT_SUCCESS); | 340 | rb.Push(RESULT_SUCCESS); |
| 339 | } | 341 | } |
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 71c7587db..b6ac0a81a 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -65,13 +65,18 @@ static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMem | |||
| 65 | void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) { | 65 | void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) { |
| 66 | ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); | 66 | ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); |
| 67 | 67 | ||
| 68 | if (input.size() < 2) { | ||
| 69 | LOG_ERROR(Service_NS, "Input font is empty"); | ||
| 70 | return; | ||
| 71 | } | ||
| 72 | |||
| 68 | const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor | 73 | const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor |
| 69 | std::vector<u32> transformed_font(input.size()); | 74 | std::vector<u32> transformed_font(input.size()); |
| 70 | // TODO(ogniK): Figure out a better way to do this | 75 | // TODO(ogniK): Figure out a better way to do this |
| 71 | std::transform(input.begin(), input.end(), transformed_font.begin(), | 76 | std::transform(input.begin(), input.end(), transformed_font.begin(), |
| 72 | [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); }); | 77 | [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); }); |
| 73 | transformed_font[1] = Common::swap32(transformed_font[1]) ^ KEY; // "re-encrypt" the size | 78 | std::memcpy(output.data(), transformed_font.data() + 2, |
| 74 | std::memcpy(output.data(), transformed_font.data() + 2, transformed_font.size() * sizeof(u32)); | 79 | (transformed_font.size() - 2) * sizeof(u32)); |
| 75 | } | 80 | } |
| 76 | 81 | ||
| 77 | void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, | 82 | void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index fea3b7b9f..f6129ef10 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/hle/kernel/readable_event.h" | 11 | #include "core/hle/kernel/k_event.h" |
| 12 | #include "core/hle/kernel/writable_event.h" | 12 | #include "core/hle/kernel/k_writable_event.h" |
| 13 | #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" | 13 | #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" |
| 14 | #include "video_core/gpu.h" | 14 | #include "video_core/gpu.h" |
| 15 | 15 | ||
| @@ -103,14 +103,14 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 103 | // This is mostly to take into account unimplemented features. As synced | 103 | // This is mostly to take into account unimplemented features. As synced |
| 104 | // gpu is always synced. | 104 | // gpu is always synced. |
| 105 | if (!gpu.IsAsync()) { | 105 | if (!gpu.IsAsync()) { |
| 106 | event.event.writable->Signal(); | 106 | event.event->GetWritableEvent()->Signal(); |
| 107 | return NvResult::Success; | 107 | return NvResult::Success; |
| 108 | } | 108 | } |
| 109 | auto lock = gpu.LockSync(); | 109 | auto lock = gpu.LockSync(); |
| 110 | const u32 current_syncpoint_value = event.fence.value; | 110 | const u32 current_syncpoint_value = event.fence.value; |
| 111 | const s32 diff = current_syncpoint_value - params.threshold; | 111 | const s32 diff = current_syncpoint_value - params.threshold; |
| 112 | if (diff >= 0) { | 112 | if (diff >= 0) { |
| 113 | event.event.writable->Signal(); | 113 | event.event->GetWritableEvent()->Signal(); |
| 114 | params.value = current_syncpoint_value; | 114 | params.value = current_syncpoint_value; |
| 115 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 115 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 116 | return NvResult::Success; | 116 | return NvResult::Success; |
| @@ -137,7 +137,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector | |||
| 137 | params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; | 137 | params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; |
| 138 | } | 138 | } |
| 139 | params.value |= event_id; | 139 | params.value |= event_id; |
| 140 | event.event.writable->Clear(); | 140 | event.event->GetWritableEvent()->Clear(); |
| 141 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); | 141 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); |
| 142 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 142 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 143 | return NvResult::Timeout; | 143 | return NvResult::Timeout; |
| @@ -155,7 +155,13 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve | |||
| 155 | return NvResult::BadParameter; | 155 | return NvResult::BadParameter; |
| 156 | } | 156 | } |
| 157 | if (events_interface.registered[event_id]) { | 157 | if (events_interface.registered[event_id]) { |
| 158 | return NvResult::BadParameter; | 158 | const auto event_state = events_interface.status[event_id]; |
| 159 | if (event_state != EventState::Free) { | ||
| 160 | LOG_WARNING(Service_NVDRV, "Event already registered! Unregistering previous event"); | ||
| 161 | events_interface.UnregisterEvent(event_id); | ||
| 162 | } else { | ||
| 163 | return NvResult::BadParameter; | ||
| 164 | } | ||
| 159 | } | 165 | } |
| 160 | events_interface.RegisterEvent(event_id); | 166 | events_interface.RegisterEvent(event_id); |
| 161 | return NvResult::Success; | 167 | return NvResult::Success; |
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index cc23b001c..2e1150867 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -6,10 +6,10 @@ | |||
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/k_readable_event.h" | ||
| 10 | #include "core/hle/kernel/k_thread.h" | ||
| 11 | #include "core/hle/kernel/k_writable_event.h" | ||
| 9 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/readable_event.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | ||
| 12 | #include "core/hle/kernel/writable_event.h" | ||
| 13 | #include "core/hle/service/nvdrv/interface.h" | 13 | #include "core/hle/service/nvdrv/interface.h" |
| 14 | #include "core/hle/service/nvdrv/nvdata.h" | 14 | #include "core/hle/service/nvdrv/nvdata.h" |
| 15 | #include "core/hle/service/nvdrv/nvdrv.h" | 15 | #include "core/hle/service/nvdrv/nvdrv.h" |
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 5c777c59b..0e764c53f 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 10 | 10 | ||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | class WritableEvent; | 12 | class KWritableEvent; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | namespace Service::Nvidia { | 15 | namespace Service::Nvidia { |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 620c18728..abba80112 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -7,8 +7,9 @@ | |||
| 7 | #include <fmt/format.h> | 7 | #include <fmt/format.h> |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/kernel/readable_event.h" | 10 | #include "core/hle/kernel/k_event.h" |
| 11 | #include "core/hle/kernel/writable_event.h" | 11 | #include "core/hle/kernel/k_readable_event.h" |
| 12 | #include "core/hle/kernel/k_writable_event.h" | ||
| 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | 13 | #include "core/hle/service/nvdrv/devices/nvdevice.h" |
| 13 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | 14 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" |
| 14 | #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" | 15 | #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" |
| @@ -42,7 +43,8 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { | |||
| 42 | auto& kernel = system.Kernel(); | 43 | auto& kernel = system.Kernel(); |
| 43 | for (u32 i = 0; i < MaxNvEvents; i++) { | 44 | for (u32 i = 0; i < MaxNvEvents; i++) { |
| 44 | std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); | 45 | std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); |
| 45 | events_interface.events[i] = {Kernel::WritableEvent::CreateEventPair(kernel, event_label)}; | 46 | events_interface.events[i] = {Kernel::KEvent::Create(kernel, std::move(event_label))}; |
| 47 | events_interface.events[i].event->Initialize(); | ||
| 46 | events_interface.status[i] = EventState::Free; | 48 | events_interface.status[i] = EventState::Free; |
| 47 | events_interface.registered[i] = false; | 49 | events_interface.registered[i] = false; |
| 48 | } | 50 | } |
| @@ -166,17 +168,17 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { | |||
| 166 | if (events_interface.assigned_syncpt[i] == syncpoint_id && | 168 | if (events_interface.assigned_syncpt[i] == syncpoint_id && |
| 167 | events_interface.assigned_value[i] == value) { | 169 | events_interface.assigned_value[i] == value) { |
| 168 | events_interface.LiberateEvent(i); | 170 | events_interface.LiberateEvent(i); |
| 169 | events_interface.events[i].event.writable->Signal(); | 171 | events_interface.events[i].event->GetWritableEvent()->Signal(); |
| 170 | } | 172 | } |
| 171 | } | 173 | } |
| 172 | } | 174 | } |
| 173 | 175 | ||
| 174 | std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { | 176 | std::shared_ptr<Kernel::KReadableEvent> Module::GetEvent(const u32 event_id) const { |
| 175 | return events_interface.events[event_id].event.readable; | 177 | return events_interface.events[event_id].event->GetReadableEvent(); |
| 176 | } | 178 | } |
| 177 | 179 | ||
| 178 | std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { | 180 | std::shared_ptr<Kernel::KWritableEvent> Module::GetEventWriteable(const u32 event_id) const { |
| 179 | return events_interface.events[event_id].event.writable; | 181 | return events_interface.events[event_id].event->GetWritableEvent(); |
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | } // namespace Service::Nvidia | 184 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 144e657e5..53719aadd 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -7,8 +7,8 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <unordered_map> | 8 | #include <unordered_map> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | |||
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 12 | #include "core/hle/service/nvdrv/nvdata.h" | 12 | #include "core/hle/service/nvdrv/nvdata.h" |
| 13 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | 13 | #include "core/hle/service/nvdrv/syncpoint_manager.h" |
| 14 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| @@ -17,6 +17,10 @@ namespace Core { | |||
| 17 | class System; | 17 | class System; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | namespace Kernel { | ||
| 21 | class KEvent; | ||
| 22 | } | ||
| 23 | |||
| 20 | namespace Service::NVFlinger { | 24 | namespace Service::NVFlinger { |
| 21 | class NVFlinger; | 25 | class NVFlinger; |
| 22 | } | 26 | } |
| @@ -31,7 +35,7 @@ class nvdevice; | |||
| 31 | 35 | ||
| 32 | /// Represents an Nvidia event | 36 | /// Represents an Nvidia event |
| 33 | struct NvEvent { | 37 | struct NvEvent { |
| 34 | Kernel::EventPair event; | 38 | std::shared_ptr<Kernel::KEvent> event; |
| 35 | Fence fence{}; | 39 | Fence fence{}; |
| 36 | }; | 40 | }; |
| 37 | 41 | ||
| @@ -132,9 +136,9 @@ public: | |||
| 132 | 136 | ||
| 133 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); | 137 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); |
| 134 | 138 | ||
| 135 | std::shared_ptr<Kernel::ReadableEvent> GetEvent(u32 event_id) const; | 139 | std::shared_ptr<Kernel::KReadableEvent> GetEvent(u32 event_id) const; |
| 136 | 140 | ||
| 137 | std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; | 141 | std::shared_ptr<Kernel::KWritableEvent> GetEventWriteable(u32 event_id) const; |
| 138 | 142 | ||
| 139 | private: | 143 | private: |
| 140 | /// Manages syncpoints on the host | 144 | /// Manages syncpoints on the host |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 5578181a4..7842a82ed 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -7,16 +7,17 @@ | |||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hle/kernel/k_event.h" | ||
| 11 | #include "core/hle/kernel/k_writable_event.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/readable_event.h" | ||
| 12 | #include "core/hle/kernel/writable_event.h" | ||
| 13 | #include "core/hle/service/nvflinger/buffer_queue.h" | 13 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 14 | 14 | ||
| 15 | namespace Service::NVFlinger { | 15 | namespace Service::NVFlinger { |
| 16 | 16 | ||
| 17 | BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id) | 17 | BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id) |
| 18 | : id(id), layer_id(layer_id) { | 18 | : id(id), layer_id(layer_id) { |
| 19 | buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, "BufferQueue NativeHandle"); | 19 | buffer_wait_event = Kernel::KEvent::Create(kernel, "BufferQueue:WaitEvent"); |
| 20 | buffer_wait_event->Initialize(); | ||
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | BufferQueue::~BufferQueue() = default; | 23 | BufferQueue::~BufferQueue() = default; |
| @@ -41,7 +42,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) | |||
| 41 | .multi_fence = {}, | 42 | .multi_fence = {}, |
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | buffer_wait_event.writable->Signal(); | 45 | buffer_wait_event->GetWritableEvent()->Signal(); |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, | 48 | std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, |
| @@ -119,7 +120,7 @@ void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& mult | |||
| 119 | } | 120 | } |
| 120 | free_buffers_condition.notify_one(); | 121 | free_buffers_condition.notify_one(); |
| 121 | 122 | ||
| 122 | buffer_wait_event.writable->Signal(); | 123 | buffer_wait_event->GetWritableEvent()->Signal(); |
| 123 | } | 124 | } |
| 124 | 125 | ||
| 125 | std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { | 126 | std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { |
| @@ -154,7 +155,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) { | |||
| 154 | } | 155 | } |
| 155 | free_buffers_condition.notify_one(); | 156 | free_buffers_condition.notify_one(); |
| 156 | 157 | ||
| 157 | buffer_wait_event.writable->Signal(); | 158 | buffer_wait_event->GetWritableEvent()->Signal(); |
| 158 | } | 159 | } |
| 159 | 160 | ||
| 160 | void BufferQueue::Connect() { | 161 | void BufferQueue::Connect() { |
| @@ -169,7 +170,7 @@ void BufferQueue::Disconnect() { | |||
| 169 | std::unique_lock lock{queue_sequence_mutex}; | 170 | std::unique_lock lock{queue_sequence_mutex}; |
| 170 | queue_sequence.clear(); | 171 | queue_sequence.clear(); |
| 171 | } | 172 | } |
| 172 | buffer_wait_event.writable->Signal(); | 173 | buffer_wait_event->GetWritableEvent()->Signal(); |
| 173 | is_connect = false; | 174 | is_connect = false; |
| 174 | free_buffers_condition.notify_one(); | 175 | free_buffers_condition.notify_one(); |
| 175 | } | 176 | } |
| @@ -188,12 +189,12 @@ u32 BufferQueue::Query(QueryType type) { | |||
| 188 | return 0; | 189 | return 0; |
| 189 | } | 190 | } |
| 190 | 191 | ||
| 191 | std::shared_ptr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { | 192 | std::shared_ptr<Kernel::KWritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { |
| 192 | return buffer_wait_event.writable; | 193 | return buffer_wait_event->GetWritableEvent(); |
| 193 | } | 194 | } |
| 194 | 195 | ||
| 195 | std::shared_ptr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const { | 196 | std::shared_ptr<Kernel::KReadableEvent> BufferQueue::GetBufferWaitEvent() const { |
| 196 | return buffer_wait_event.readable; | 197 | return buffer_wait_event->GetReadableEvent(); |
| 197 | } | 198 | } |
| 198 | 199 | ||
| 199 | } // namespace Service::NVFlinger | 200 | } // namespace Service::NVFlinger |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index ad7469277..163fa4c54 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -14,12 +14,14 @@ | |||
| 14 | #include "common/math_util.h" | 14 | #include "common/math_util.h" |
| 15 | #include "common/swap.h" | 15 | #include "common/swap.h" |
| 16 | #include "core/hle/kernel/object.h" | 16 | #include "core/hle/kernel/object.h" |
| 17 | #include "core/hle/kernel/writable_event.h" | ||
| 18 | #include "core/hle/service/nvdrv/nvdata.h" | 17 | #include "core/hle/service/nvdrv/nvdata.h" |
| 19 | 18 | ||
| 20 | namespace Kernel { | 19 | namespace Kernel { |
| 21 | class KernelCore; | 20 | class KernelCore; |
| 22 | } | 21 | class KEvent; |
| 22 | class KReadableEvent; | ||
| 23 | class KWritableEvent; | ||
| 24 | } // namespace Kernel | ||
| 23 | 25 | ||
| 24 | namespace Service::NVFlinger { | 26 | namespace Service::NVFlinger { |
| 25 | 27 | ||
| @@ -113,9 +115,9 @@ public: | |||
| 113 | return is_connect; | 115 | return is_connect; |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | std::shared_ptr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const; | 118 | std::shared_ptr<Kernel::KWritableEvent> GetWritableBufferWaitEvent() const; |
| 117 | 119 | ||
| 118 | std::shared_ptr<Kernel::ReadableEvent> GetBufferWaitEvent() const; | 120 | std::shared_ptr<Kernel::KReadableEvent> GetBufferWaitEvent() const; |
| 119 | 121 | ||
| 120 | private: | 122 | private: |
| 121 | BufferQueue(const BufferQueue&) = delete; | 123 | BufferQueue(const BufferQueue&) = delete; |
| @@ -127,7 +129,7 @@ private: | |||
| 127 | std::list<u32> free_buffers; | 129 | std::list<u32> free_buffers; |
| 128 | std::array<Buffer, buffer_slots> buffers; | 130 | std::array<Buffer, buffer_slots> buffers; |
| 129 | std::list<u32> queue_sequence; | 131 | std::list<u32> queue_sequence; |
| 130 | Kernel::EventPair buffer_wait_event; | 132 | std::shared_ptr<Kernel::KEvent> buffer_wait_event; |
| 131 | 133 | ||
| 132 | std::mutex free_buffers_mutex; | 134 | std::mutex free_buffers_mutex; |
| 133 | std::condition_variable free_buffers_condition; | 135 | std::condition_variable free_buffers_condition; |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index ceaa93d28..ac2906e5b 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -14,8 +14,8 @@ | |||
| 14 | #include "core/core_timing.h" | 14 | #include "core/core_timing.h" |
| 15 | #include "core/core_timing_util.h" | 15 | #include "core/core_timing_util.h" |
| 16 | #include "core/hardware_properties.h" | 16 | #include "core/hardware_properties.h" |
| 17 | #include "core/hle/kernel/k_readable_event.h" | ||
| 17 | #include "core/hle/kernel/kernel.h" | 18 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/kernel/readable_event.h" | ||
| 19 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | 19 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" |
| 20 | #include "core/hle/service/nvdrv/nvdrv.h" | 20 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 21 | #include "core/hle/service/nvflinger/buffer_queue.h" | 21 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| @@ -165,7 +165,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co | |||
| 165 | return layer->GetBufferQueue().GetId(); | 165 | return layer->GetBufferQueue().GetId(); |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { | 168 | std::shared_ptr<Kernel::KReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { |
| 169 | const auto guard = Lock(); | 169 | const auto guard = Lock(); |
| 170 | auto* const display = FindDisplay(display_id); | 170 | auto* const display = FindDisplay(display_id); |
| 171 | 171 | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index c6765259f..6fe2c7f2a 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -26,8 +26,8 @@ struct EventType; | |||
| 26 | } // namespace Core::Timing | 26 | } // namespace Core::Timing |
| 27 | 27 | ||
| 28 | namespace Kernel { | 28 | namespace Kernel { |
| 29 | class ReadableEvent; | 29 | class KReadableEvent; |
| 30 | class WritableEvent; | 30 | class KWritableEvent; |
| 31 | } // namespace Kernel | 31 | } // namespace Kernel |
| 32 | 32 | ||
| 33 | namespace Service::Nvidia { | 33 | namespace Service::Nvidia { |
| @@ -72,7 +72,7 @@ public: | |||
| 72 | /// Gets the vsync event for the specified display. | 72 | /// Gets the vsync event for the specified display. |
| 73 | /// | 73 | /// |
| 74 | /// If an invalid display ID is provided, then nullptr is returned. | 74 | /// If an invalid display ID is provided, then nullptr is returned. |
| 75 | [[nodiscard]] std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const; | 75 | [[nodiscard]] std::shared_ptr<Kernel::KReadableEvent> FindVsyncEvent(u64 display_id) const; |
| 76 | 76 | ||
| 77 | /// Obtains a buffer queue identified by the ID. | 77 | /// Obtains a buffer queue identified by the ID. |
| 78 | [[nodiscard]] BufferQueue* FindBufferQueue(u32 id); | 78 | [[nodiscard]] BufferQueue* FindBufferQueue(u32 id); |
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index 6ab1e4124..f9089bf2f 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp | |||
| @@ -50,11 +50,11 @@ public: | |||
| 50 | {1046, nullptr, "DisableFeaturesForReset"}, | 50 | {1046, nullptr, "DisableFeaturesForReset"}, |
| 51 | {1047, nullptr, "NotifyApplicationDownloadStarted"}, | 51 | {1047, nullptr, "NotifyApplicationDownloadStarted"}, |
| 52 | {1048, nullptr, "NotifyNetworkProfileCreated"}, | 52 | {1048, nullptr, "NotifyNetworkProfileCreated"}, |
| 53 | {1061, nullptr, "ConfirmStereoVisionRestrictionConfigurable"}, | 53 | {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"}, |
| 54 | {1062, nullptr, "GetStereoVisionRestriction"}, | 54 | {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"}, |
| 55 | {1063, nullptr, "SetStereoVisionRestriction"}, | 55 | {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"}, |
| 56 | {1064, nullptr, "ResetConfirmedStereoVisionPermission"}, | 56 | {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"}, |
| 57 | {1065, nullptr, "IsStereoVisionPermitted"}, | 57 | {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"}, |
| 58 | {1201, nullptr, "UnlockRestrictionTemporarily"}, | 58 | {1201, nullptr, "UnlockRestrictionTemporarily"}, |
| 59 | {1202, nullptr, "UnlockSystemSettingsRestriction"}, | 59 | {1202, nullptr, "UnlockSystemSettingsRestriction"}, |
| 60 | {1203, nullptr, "SetPinCode"}, | 60 | {1203, nullptr, "SetPinCode"}, |
| @@ -114,6 +114,7 @@ public: | |||
| 114 | {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"}, | 114 | {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"}, |
| 115 | {2016, nullptr, "RequestUpdateExemptionListAsync"}, | 115 | {2016, nullptr, "RequestUpdateExemptionListAsync"}, |
| 116 | }; | 116 | }; |
| 117 | // clang-format on | ||
| 117 | RegisterHandlers(functions); | 118 | RegisterHandlers(functions); |
| 118 | } | 119 | } |
| 119 | 120 | ||
| @@ -131,6 +132,49 @@ private: | |||
| 131 | IPC::ResponseBuilder rb{ctx, 2}; | 132 | IPC::ResponseBuilder rb{ctx, 2}; |
| 132 | rb.Push(RESULT_SUCCESS); | 133 | rb.Push(RESULT_SUCCESS); |
| 133 | } | 134 | } |
| 135 | |||
| 136 | void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) { | ||
| 137 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 138 | |||
| 139 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 140 | rb.Push(RESULT_SUCCESS); | ||
| 141 | } | ||
| 142 | |||
| 143 | void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) { | ||
| 144 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 145 | |||
| 146 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 147 | rb.Push(RESULT_SUCCESS); | ||
| 148 | rb.Push(true); | ||
| 149 | } | ||
| 150 | |||
| 151 | void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { | ||
| 152 | IPC::RequestParser rp{ctx}; | ||
| 153 | const auto can_use = rp.Pop<bool>(); | ||
| 154 | LOG_WARNING(Service_PCTL, "(STUBBED) called, can_use={}", can_use); | ||
| 155 | |||
| 156 | can_use_stereo_vision = can_use; | ||
| 157 | |||
| 158 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 159 | rb.Push(RESULT_SUCCESS); | ||
| 160 | } | ||
| 161 | |||
| 162 | void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { | ||
| 163 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 164 | |||
| 165 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 166 | rb.Push(RESULT_SUCCESS); | ||
| 167 | rb.Push(can_use_stereo_vision); | ||
| 168 | } | ||
| 169 | |||
| 170 | void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) { | ||
| 171 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | ||
| 172 | |||
| 173 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 174 | rb.Push(RESULT_SUCCESS); | ||
| 175 | } | ||
| 176 | |||
| 177 | bool can_use_stereo_vision = true; | ||
| 134 | }; | 178 | }; |
| 135 | 179 | ||
| 136 | void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { | 180 | void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { |
| @@ -149,7 +193,8 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext | |||
| 149 | rb.PushIpcInterface<IParentalControlService>(system); | 193 | rb.PushIpcInterface<IParentalControlService>(system); |
| 150 | } | 194 | } |
| 151 | 195 | ||
| 152 | Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name) | 196 | Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, |
| 197 | const char* name) | ||
| 153 | : ServiceFramework{system_, name}, module{std::move(module_)} {} | 198 | : ServiceFramework{system_, name}, module{std::move(module_)} {} |
| 154 | 199 | ||
| 155 | Module::Interface::~Interface() = default; | 200 | Module::Interface::~Interface() = default; |
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index b417624c9..d5b3b17a5 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp | |||
| @@ -23,11 +23,11 @@ public: | |||
| 23 | {10101, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::Old>, "SaveReportWithUserOld"}, | 23 | {10101, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::Old>, "SaveReportWithUserOld"}, |
| 24 | {10102, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old2>, "SaveReportOld2"}, | 24 | {10102, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old2>, "SaveReportOld2"}, |
| 25 | {10103, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::Old2>, "SaveReportWithUserOld2"}, | 25 | {10103, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::Old2>, "SaveReportWithUserOld2"}, |
| 26 | {10104, nullptr, "SaveReport"}, | 26 | {10104, &PlayReport::SaveReport<Core::Reporter::PlayReportType::New>, "SaveReport"}, |
| 27 | {10105, nullptr, "SaveReportWithUser"}, | 27 | {10105, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::New>, "SaveReportWithUser"}, |
| 28 | {10200, nullptr, "RequestImmediateTransmission"}, | 28 | {10200, &PlayReport::RequestImmediateTransmission, "RequestImmediateTransmission"}, |
| 29 | {10300, nullptr, "GetTransmissionStatus"}, | 29 | {10300, &PlayReport::GetTransmissionStatus, "GetTransmissionStatus"}, |
| 30 | {10400, nullptr, "GetSystemSessionId"}, | 30 | {10400, &PlayReport::GetSystemSessionId, "GetSystemSessionId"}, |
| 31 | {20100, &PlayReport::SaveSystemReport, "SaveSystemReport"}, | 31 | {20100, &PlayReport::SaveSystemReport, "SaveSystemReport"}, |
| 32 | {20101, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"}, | 32 | {20101, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"}, |
| 33 | {20200, nullptr, "SetOperationMode"}, | 33 | {20200, nullptr, "SetOperationMode"}, |
| @@ -59,16 +59,22 @@ private: | |||
| 59 | IPC::RequestParser rp{ctx}; | 59 | IPC::RequestParser rp{ctx}; |
| 60 | const auto process_id = rp.PopRaw<u64>(); | 60 | const auto process_id = rp.PopRaw<u64>(); |
| 61 | 61 | ||
| 62 | std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)}; | 62 | const auto data1 = ctx.ReadBuffer(0); |
| 63 | if constexpr (Type == Core::Reporter::PlayReportType::Old2) { | 63 | const auto data2 = [ctx] { |
| 64 | data.emplace_back(ctx.ReadBuffer(1)); | 64 | if (ctx.CanReadBuffer(1)) { |
| 65 | } | 65 | return ctx.ReadBuffer(1); |
| 66 | } | ||
| 66 | 67 | ||
| 67 | LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}", | 68 | return std::vector<u8>{}; |
| 68 | Type, process_id, data[0].size()); | 69 | }(); |
| 70 | |||
| 71 | LOG_DEBUG(Service_PREPO, | ||
| 72 | "called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}", | ||
| 73 | Type, process_id, data1.size(), data2.size()); | ||
| 69 | 74 | ||
| 70 | const auto& reporter{system.GetReporter()}; | 75 | const auto& reporter{system.GetReporter()}; |
| 71 | reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id); | 76 | reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2}, |
| 77 | process_id); | ||
| 72 | 78 | ||
| 73 | IPC::ResponseBuilder rb{ctx, 2}; | 79 | IPC::ResponseBuilder rb{ctx, 2}; |
| 74 | rb.Push(RESULT_SUCCESS); | 80 | rb.Push(RESULT_SUCCESS); |
| @@ -79,35 +85,67 @@ private: | |||
| 79 | IPC::RequestParser rp{ctx}; | 85 | IPC::RequestParser rp{ctx}; |
| 80 | const auto user_id = rp.PopRaw<u128>(); | 86 | const auto user_id = rp.PopRaw<u128>(); |
| 81 | const auto process_id = rp.PopRaw<u64>(); | 87 | const auto process_id = rp.PopRaw<u64>(); |
| 82 | std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)}; | ||
| 83 | 88 | ||
| 84 | if constexpr (Type == Core::Reporter::PlayReportType::Old2) { | 89 | const auto data1 = ctx.ReadBuffer(0); |
| 85 | const auto read_buffer_count = | 90 | const auto data2 = [ctx] { |
| 86 | ctx.BufferDescriptorX().size() + ctx.BufferDescriptorA().size(); | 91 | if (ctx.CanReadBuffer(1)) { |
| 87 | if (read_buffer_count > 1) { | 92 | return ctx.ReadBuffer(1); |
| 88 | data.emplace_back(ctx.ReadBuffer(1)); | ||
| 89 | } | 93 | } |
| 90 | } | ||
| 91 | 94 | ||
| 92 | LOG_DEBUG( | 95 | return std::vector<u8>{}; |
| 93 | Service_PREPO, | 96 | }(); |
| 94 | "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}", | 97 | |
| 95 | Type, user_id[1], user_id[0], process_id, data[0].size()); | 98 | LOG_DEBUG(Service_PREPO, |
| 99 | "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, " | ||
| 100 | "data1_size={:016X}, data2_size={:016X}", | ||
| 101 | Type, user_id[1], user_id[0], process_id, data1.size(), data2.size()); | ||
| 96 | 102 | ||
| 97 | const auto& reporter{system.GetReporter()}; | 103 | const auto& reporter{system.GetReporter()}; |
| 98 | reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id, | 104 | reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2}, |
| 99 | user_id); | 105 | process_id, user_id); |
| 100 | 106 | ||
| 101 | IPC::ResponseBuilder rb{ctx, 2}; | 107 | IPC::ResponseBuilder rb{ctx, 2}; |
| 102 | rb.Push(RESULT_SUCCESS); | 108 | rb.Push(RESULT_SUCCESS); |
| 103 | } | 109 | } |
| 104 | 110 | ||
| 111 | void RequestImmediateTransmission(Kernel::HLERequestContext& ctx) { | ||
| 112 | LOG_WARNING(Service_PREPO, "(STUBBED) called"); | ||
| 113 | |||
| 114 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 115 | rb.Push(RESULT_SUCCESS); | ||
| 116 | } | ||
| 117 | |||
| 118 | void GetTransmissionStatus(Kernel::HLERequestContext& ctx) { | ||
| 119 | LOG_WARNING(Service_PREPO, "(STUBBED) called"); | ||
| 120 | |||
| 121 | constexpr s32 status = 0; | ||
| 122 | |||
| 123 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 124 | rb.Push(RESULT_SUCCESS); | ||
| 125 | rb.Push(status); | ||
| 126 | } | ||
| 127 | |||
| 128 | void GetSystemSessionId(Kernel::HLERequestContext& ctx) { | ||
| 129 | LOG_WARNING(Service_PREPO, "(STUBBED) called"); | ||
| 130 | |||
| 131 | constexpr u64 system_session_id = 0; | ||
| 132 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 133 | rb.Push(RESULT_SUCCESS); | ||
| 134 | rb.Push(system_session_id); | ||
| 135 | } | ||
| 136 | |||
| 105 | void SaveSystemReport(Kernel::HLERequestContext& ctx) { | 137 | void SaveSystemReport(Kernel::HLERequestContext& ctx) { |
| 106 | IPC::RequestParser rp{ctx}; | 138 | IPC::RequestParser rp{ctx}; |
| 107 | const auto title_id = rp.PopRaw<u64>(); | 139 | const auto title_id = rp.PopRaw<u64>(); |
| 108 | 140 | ||
| 109 | const auto data1 = ctx.ReadBuffer(0); | 141 | const auto data1 = ctx.ReadBuffer(0); |
| 110 | const auto data2 = ctx.ReadBuffer(1); | 142 | const auto data2 = [ctx] { |
| 143 | if (ctx.CanReadBuffer(1)) { | ||
| 144 | return ctx.ReadBuffer(1); | ||
| 145 | } | ||
| 146 | |||
| 147 | return std::vector<u8>{}; | ||
| 148 | }(); | ||
| 111 | 149 | ||
| 112 | LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}", | 150 | LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}", |
| 113 | title_id, data1.size(), data2.size()); | 151 | title_id, data1.size(), data2.size()); |
| @@ -125,7 +163,13 @@ private: | |||
| 125 | const auto title_id = rp.PopRaw<u64>(); | 163 | const auto title_id = rp.PopRaw<u64>(); |
| 126 | 164 | ||
| 127 | const auto data1 = ctx.ReadBuffer(0); | 165 | const auto data1 = ctx.ReadBuffer(0); |
| 128 | const auto data2 = ctx.ReadBuffer(1); | 166 | const auto data2 = [ctx] { |
| 167 | if (ctx.CanReadBuffer(1)) { | ||
| 168 | return ctx.ReadBuffer(1); | ||
| 169 | } | ||
| 170 | |||
| 171 | return std::vector<u8>{}; | ||
| 172 | }(); | ||
| 129 | 173 | ||
| 130 | LOG_DEBUG(Service_PREPO, | 174 | LOG_DEBUG(Service_PREPO, |
| 131 | "called, user_id={:016X}{:016X}, title_id={:016X}, data1_size={:016X}, " | 175 | "called, user_id={:016X}{:016X}, title_id={:016X}, data1_size={:016X}, " |
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp index b4b0dd241..26ed52273 100644 --- a/src/core/hle/service/ptm/psm.cpp +++ b/src/core/hle/service/ptm/psm.cpp | |||
| @@ -5,13 +5,118 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/kernel/k_event.h" | ||
| 11 | #include "core/hle/kernel/k_readable_event.h" | ||
| 12 | #include "core/hle/kernel/k_writable_event.h" | ||
| 13 | #include "core/hle/kernel/kernel.h" | ||
| 9 | #include "core/hle/service/ptm/psm.h" | 14 | #include "core/hle/service/ptm/psm.h" |
| 10 | #include "core/hle/service/service.h" | 15 | #include "core/hle/service/service.h" |
| 11 | #include "core/hle/service/sm/sm.h" | 16 | #include "core/hle/service/sm/sm.h" |
| 12 | 17 | ||
| 13 | namespace Service::PSM { | 18 | namespace Service::PSM { |
| 14 | 19 | ||
| 20 | class IPsmSession final : public ServiceFramework<IPsmSession> { | ||
| 21 | public: | ||
| 22 | explicit IPsmSession(Core::System& system_) : ServiceFramework{system_, "IPsmSession"} { | ||
| 23 | // clang-format off | ||
| 24 | static const FunctionInfo functions[] = { | ||
| 25 | {0, &IPsmSession::BindStateChangeEvent, "BindStateChangeEvent"}, | ||
| 26 | {1, &IPsmSession::UnbindStateChangeEvent, "UnbindStateChangeEvent"}, | ||
| 27 | {2, &IPsmSession::SetChargerTypeChangeEventEnabled, "SetChargerTypeChangeEventEnabled"}, | ||
| 28 | {3, &IPsmSession::SetPowerSupplyChangeEventEnabled, "SetPowerSupplyChangeEventEnabled"}, | ||
| 29 | {4, &IPsmSession::SetBatteryVoltageStateChangeEventEnabled, "SetBatteryVoltageStateChangeEventEnabled"}, | ||
| 30 | }; | ||
| 31 | // clang-format on | ||
| 32 | |||
| 33 | RegisterHandlers(functions); | ||
| 34 | |||
| 35 | state_change_event = | ||
| 36 | Kernel::KEvent::Create(system_.Kernel(), "IPsmSession::state_change_event"); | ||
| 37 | state_change_event->Initialize(); | ||
| 38 | } | ||
| 39 | |||
| 40 | ~IPsmSession() override = default; | ||
| 41 | |||
| 42 | void SignalChargerTypeChanged() { | ||
| 43 | if (should_signal && should_signal_charger_type) { | ||
| 44 | state_change_event->GetWritableEvent()->Signal(); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | void SignalPowerSupplyChanged() { | ||
| 49 | if (should_signal && should_signal_power_supply) { | ||
| 50 | state_change_event->GetWritableEvent()->Signal(); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | void SignalBatteryVoltageStateChanged() { | ||
| 55 | if (should_signal && should_signal_battery_voltage) { | ||
| 56 | state_change_event->GetWritableEvent()->Signal(); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | private: | ||
| 61 | void BindStateChangeEvent(Kernel::HLERequestContext& ctx) { | ||
| 62 | LOG_DEBUG(Service_PSM, "called"); | ||
| 63 | |||
| 64 | should_signal = true; | ||
| 65 | |||
| 66 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 67 | rb.Push(RESULT_SUCCESS); | ||
| 68 | rb.PushCopyObjects(state_change_event->GetReadableEvent()); | ||
| 69 | } | ||
| 70 | |||
| 71 | void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) { | ||
| 72 | LOG_DEBUG(Service_PSM, "called"); | ||
| 73 | |||
| 74 | should_signal = false; | ||
| 75 | |||
| 76 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 77 | rb.Push(RESULT_SUCCESS); | ||
| 78 | } | ||
| 79 | |||
| 80 | void SetChargerTypeChangeEventEnabled(Kernel::HLERequestContext& ctx) { | ||
| 81 | IPC::RequestParser rp{ctx}; | ||
| 82 | const auto state = rp.Pop<bool>(); | ||
| 83 | LOG_DEBUG(Service_PSM, "called, state={}", state); | ||
| 84 | |||
| 85 | should_signal_charger_type = state; | ||
| 86 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 88 | rb.Push(RESULT_SUCCESS); | ||
| 89 | } | ||
| 90 | |||
| 91 | void SetPowerSupplyChangeEventEnabled(Kernel::HLERequestContext& ctx) { | ||
| 92 | IPC::RequestParser rp{ctx}; | ||
| 93 | const auto state = rp.Pop<bool>(); | ||
| 94 | LOG_DEBUG(Service_PSM, "called, state={}", state); | ||
| 95 | |||
| 96 | should_signal_power_supply = state; | ||
| 97 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 99 | rb.Push(RESULT_SUCCESS); | ||
| 100 | } | ||
| 101 | |||
| 102 | void SetBatteryVoltageStateChangeEventEnabled(Kernel::HLERequestContext& ctx) { | ||
| 103 | IPC::RequestParser rp{ctx}; | ||
| 104 | const auto state = rp.Pop<bool>(); | ||
| 105 | LOG_DEBUG(Service_PSM, "called, state={}", state); | ||
| 106 | |||
| 107 | should_signal_battery_voltage = state; | ||
| 108 | |||
| 109 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 110 | rb.Push(RESULT_SUCCESS); | ||
| 111 | } | ||
| 112 | |||
| 113 | bool should_signal_charger_type{}; | ||
| 114 | bool should_signal_power_supply{}; | ||
| 115 | bool should_signal_battery_voltage{}; | ||
| 116 | bool should_signal{}; | ||
| 117 | std::shared_ptr<Kernel::KEvent> state_change_event; | ||
| 118 | }; | ||
| 119 | |||
| 15 | class PSM final : public ServiceFramework<PSM> { | 120 | class PSM final : public ServiceFramework<PSM> { |
| 16 | public: | 121 | public: |
| 17 | explicit PSM(Core::System& system_) : ServiceFramework{system_, "psm"} { | 122 | explicit PSM(Core::System& system_) : ServiceFramework{system_, "psm"} { |
| @@ -24,7 +129,7 @@ public: | |||
| 24 | {4, nullptr, "IsBatteryChargingEnabled"}, | 129 | {4, nullptr, "IsBatteryChargingEnabled"}, |
| 25 | {5, nullptr, "AcquireControllerPowerSupply"}, | 130 | {5, nullptr, "AcquireControllerPowerSupply"}, |
| 26 | {6, nullptr, "ReleaseControllerPowerSupply"}, | 131 | {6, nullptr, "ReleaseControllerPowerSupply"}, |
| 27 | {7, nullptr, "OpenSession"}, | 132 | {7, &PSM::OpenSession, "OpenSession"}, |
| 28 | {8, nullptr, "EnableEnoughPowerChargeEmulation"}, | 133 | {8, nullptr, "EnableEnoughPowerChargeEmulation"}, |
| 29 | {9, nullptr, "DisableEnoughPowerChargeEmulation"}, | 134 | {9, nullptr, "DisableEnoughPowerChargeEmulation"}, |
| 30 | {10, nullptr, "EnableFastBatteryCharging"}, | 135 | {10, nullptr, "EnableFastBatteryCharging"}, |
| @@ -61,6 +166,14 @@ private: | |||
| 61 | rb.PushEnum(charger_type); | 166 | rb.PushEnum(charger_type); |
| 62 | } | 167 | } |
| 63 | 168 | ||
| 169 | void OpenSession(Kernel::HLERequestContext& ctx) { | ||
| 170 | LOG_DEBUG(Service_PSM, "called"); | ||
| 171 | |||
| 172 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 173 | rb.Push(RESULT_SUCCESS); | ||
| 174 | rb.PushIpcInterface<IPsmSession>(system); | ||
| 175 | } | ||
| 176 | |||
| 64 | enum class ChargerType : u32 { | 177 | enum class ChargerType : u32 { |
| 65 | Unplugged = 0, | 178 | Unplugged = 0, |
| 66 | RegularCharger = 1, | 179 | RegularCharger = 1, |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index ff2a5b1db..1da56bc27 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -11,10 +11,10 @@ | |||
| 11 | #include "core/hle/ipc.h" | 11 | #include "core/hle/ipc.h" |
| 12 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/client_port.h" | 13 | #include "core/hle/kernel/client_port.h" |
| 14 | #include "core/hle/kernel/k_thread.h" | ||
| 14 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 15 | #include "core/hle/kernel/process.h" | 16 | #include "core/hle/kernel/process.h" |
| 16 | #include "core/hle/kernel/server_port.h" | 17 | #include "core/hle/kernel/server_port.h" |
| 17 | #include "core/hle/kernel/thread.h" | ||
| 18 | #include "core/hle/service/acc/acc.h" | 18 | #include "core/hle/service/acc/acc.h" |
| 19 | #include "core/hle/service/am/am.h" | 19 | #include "core/hle/service/am/am.h" |
| 20 | #include "core/hle/service/aoc/aoc_u.h" | 20 | #include "core/hle/service/aoc/aoc_u.h" |
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 2b824059d..0b306b87a 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #include "common/microprofile.h" | 13 | #include "common/microprofile.h" |
| 14 | #include "common/thread.h" | 14 | #include "common/thread.h" |
| 15 | #include "core/hle/ipc_helpers.h" | 15 | #include "core/hle/ipc_helpers.h" |
| 16 | #include "core/hle/kernel/thread.h" | 16 | #include "core/hle/kernel/k_thread.h" |
| 17 | #include "core/hle/service/sockets/bsd.h" | 17 | #include "core/hle/service/sockets/bsd.h" |
| 18 | #include "core/hle/service/sockets/sockets_translate.h" | 18 | #include "core/hle/service/sockets/sockets_translate.h" |
| 19 | #include "core/network/network.h" | 19 | #include "core/network/network.h" |
| @@ -255,6 +255,25 @@ void BSD::GetSockName(Kernel::HLERequestContext& ctx) { | |||
| 255 | rb.Push<u32>(static_cast<u32>(write_buffer.size())); | 255 | rb.Push<u32>(static_cast<u32>(write_buffer.size())); |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | void BSD::GetSockOpt(Kernel::HLERequestContext& ctx) { | ||
| 259 | IPC::RequestParser rp{ctx}; | ||
| 260 | const s32 fd = rp.Pop<s32>(); | ||
| 261 | const u32 level = rp.Pop<u32>(); | ||
| 262 | const auto optname = static_cast<OptName>(rp.Pop<u32>()); | ||
| 263 | |||
| 264 | LOG_WARNING(Service, "(STUBBED) called. fd={} level={} optname=0x{:x}", fd, level, optname); | ||
| 265 | |||
| 266 | std::vector<u8> optval(ctx.GetWriteBufferSize()); | ||
| 267 | |||
| 268 | ctx.WriteBuffer(optval); | ||
| 269 | |||
| 270 | IPC::ResponseBuilder rb{ctx, 5}; | ||
| 271 | rb.Push(RESULT_SUCCESS); | ||
| 272 | rb.Push<s32>(-1); | ||
| 273 | rb.PushEnum(Errno::NOTCONN); | ||
| 274 | rb.Push<u32>(static_cast<u32>(optval.size())); | ||
| 275 | } | ||
| 276 | |||
| 258 | void BSD::Listen(Kernel::HLERequestContext& ctx) { | 277 | void BSD::Listen(Kernel::HLERequestContext& ctx) { |
| 259 | IPC::RequestParser rp{ctx}; | 278 | IPC::RequestParser rp{ctx}; |
| 260 | const s32 fd = rp.Pop<s32>(); | 279 | const s32 fd = rp.Pop<s32>(); |
| @@ -401,6 +420,16 @@ void BSD::Close(Kernel::HLERequestContext& ctx) { | |||
| 401 | BuildErrnoResponse(ctx, CloseImpl(fd)); | 420 | BuildErrnoResponse(ctx, CloseImpl(fd)); |
| 402 | } | 421 | } |
| 403 | 422 | ||
| 423 | void BSD::EventFd(Kernel::HLERequestContext& ctx) { | ||
| 424 | IPC::RequestParser rp{ctx}; | ||
| 425 | const u64 initval = rp.Pop<u64>(); | ||
| 426 | const u32 flags = rp.Pop<u32>(); | ||
| 427 | |||
| 428 | LOG_WARNING(Service, "(STUBBED) called. initval={}, flags={}", initval, flags); | ||
| 429 | |||
| 430 | BuildErrnoResponse(ctx, Errno::SUCCESS); | ||
| 431 | } | ||
| 432 | |||
| 404 | template <typename Work> | 433 | template <typename Work> |
| 405 | void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, Work work) { | 434 | void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, Work work) { |
| 406 | work.Execute(this); | 435 | work.Execute(this); |
| @@ -812,7 +841,7 @@ BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, na | |||
| 812 | {14, &BSD::Connect, "Connect"}, | 841 | {14, &BSD::Connect, "Connect"}, |
| 813 | {15, &BSD::GetPeerName, "GetPeerName"}, | 842 | {15, &BSD::GetPeerName, "GetPeerName"}, |
| 814 | {16, &BSD::GetSockName, "GetSockName"}, | 843 | {16, &BSD::GetSockName, "GetSockName"}, |
| 815 | {17, nullptr, "GetSockOpt"}, | 844 | {17, &BSD::GetSockOpt, "GetSockOpt"}, |
| 816 | {18, &BSD::Listen, "Listen"}, | 845 | {18, &BSD::Listen, "Listen"}, |
| 817 | {19, nullptr, "Ioctl"}, | 846 | {19, nullptr, "Ioctl"}, |
| 818 | {20, &BSD::Fcntl, "Fcntl"}, | 847 | {20, &BSD::Fcntl, "Fcntl"}, |
| @@ -826,7 +855,7 @@ BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, na | |||
| 826 | {28, nullptr, "GetResourceStatistics"}, | 855 | {28, nullptr, "GetResourceStatistics"}, |
| 827 | {29, nullptr, "RecvMMsg"}, | 856 | {29, nullptr, "RecvMMsg"}, |
| 828 | {30, nullptr, "SendMMsg"}, | 857 | {30, nullptr, "SendMMsg"}, |
| 829 | {31, nullptr, "EventFd"}, | 858 | {31, &BSD::EventFd, "EventFd"}, |
| 830 | {32, nullptr, "RegisterResourceStatisticsName"}, | 859 | {32, nullptr, "RegisterResourceStatisticsName"}, |
| 831 | {33, nullptr, "Initialize2"}, | 860 | {33, nullptr, "Initialize2"}, |
| 832 | }; | 861 | }; |
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 6da0bfeb2..1d2df9c61 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h | |||
| @@ -125,6 +125,7 @@ private: | |||
| 125 | void Connect(Kernel::HLERequestContext& ctx); | 125 | void Connect(Kernel::HLERequestContext& ctx); |
| 126 | void GetPeerName(Kernel::HLERequestContext& ctx); | 126 | void GetPeerName(Kernel::HLERequestContext& ctx); |
| 127 | void GetSockName(Kernel::HLERequestContext& ctx); | 127 | void GetSockName(Kernel::HLERequestContext& ctx); |
| 128 | void GetSockOpt(Kernel::HLERequestContext& ctx); | ||
| 128 | void Listen(Kernel::HLERequestContext& ctx); | 129 | void Listen(Kernel::HLERequestContext& ctx); |
| 129 | void Fcntl(Kernel::HLERequestContext& ctx); | 130 | void Fcntl(Kernel::HLERequestContext& ctx); |
| 130 | void SetSockOpt(Kernel::HLERequestContext& ctx); | 131 | void SetSockOpt(Kernel::HLERequestContext& ctx); |
| @@ -135,6 +136,7 @@ private: | |||
| 135 | void SendTo(Kernel::HLERequestContext& ctx); | 136 | void SendTo(Kernel::HLERequestContext& ctx); |
| 136 | void Write(Kernel::HLERequestContext& ctx); | 137 | void Write(Kernel::HLERequestContext& ctx); |
| 137 | void Close(Kernel::HLERequestContext& ctx); | 138 | void Close(Kernel::HLERequestContext& ctx); |
| 139 | void EventFd(Kernel::HLERequestContext& ctx); | ||
| 138 | 140 | ||
| 139 | template <typename Work> | 141 | template <typename Work> |
| 140 | void ExecuteWork(Kernel::HLERequestContext& ctx, Work work); | 142 | void ExecuteWork(Kernel::HLERequestContext& ctx, Work work); |
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h index 72e1921ec..b78892223 100644 --- a/src/core/hle/service/time/clock_types.h +++ b/src/core/hle/service/time/clock_types.h | |||
| @@ -73,19 +73,19 @@ struct TimeSpanType { | |||
| 73 | static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); | 73 | static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); |
| 74 | 74 | ||
| 75 | struct ClockSnapshot { | 75 | struct ClockSnapshot { |
| 76 | SystemClockContext user_context{}; | 76 | SystemClockContext user_context; |
| 77 | SystemClockContext network_context{}; | 77 | SystemClockContext network_context; |
| 78 | s64 user_time{}; | 78 | s64 user_time; |
| 79 | s64 network_time{}; | 79 | s64 network_time; |
| 80 | TimeZone::CalendarTime user_calendar_time{}; | 80 | TimeZone::CalendarTime user_calendar_time; |
| 81 | TimeZone::CalendarTime network_calendar_time{}; | 81 | TimeZone::CalendarTime network_calendar_time; |
| 82 | TimeZone::CalendarAdditionalInfo user_calendar_additional_time{}; | 82 | TimeZone::CalendarAdditionalInfo user_calendar_additional_time; |
| 83 | TimeZone::CalendarAdditionalInfo network_calendar_additional_time{}; | 83 | TimeZone::CalendarAdditionalInfo network_calendar_additional_time; |
| 84 | SteadyClockTimePoint steady_clock_time_point{}; | 84 | SteadyClockTimePoint steady_clock_time_point; |
| 85 | TimeZone::LocationName location_name{}; | 85 | TimeZone::LocationName location_name; |
| 86 | u8 is_automatic_correction_enabled{}; | 86 | u8 is_automatic_correction_enabled; |
| 87 | u8 type{}; | 87 | u8 type; |
| 88 | INSERT_PADDING_BYTES(0x2); | 88 | INSERT_PADDING_BYTES_NOINIT(0x2); |
| 89 | 89 | ||
| 90 | static ResultCode GetCurrentTime(s64& current_time, | 90 | static ResultCode GetCurrentTime(s64& current_time, |
| 91 | const SteadyClockTimePoint& steady_clock_time_point, | 91 | const SteadyClockTimePoint& steady_clock_time_point, |
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 8af17091c..b9faa474e 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 | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/kernel/writable_event.h" | 7 | #include "core/hle/kernel/k_event.h" |
| 8 | #include "core/hle/service/time/standard_local_system_clock_core.h" | 8 | #include "core/hle/service/time/standard_local_system_clock_core.h" |
| 9 | #include "core/hle/service/time/standard_network_system_clock_core.h" | 9 | #include "core/hle/service/time/standard_network_system_clock_core.h" |
| 10 | #include "core/hle/service/time/standard_user_system_clock_core.h" | 10 | #include "core/hle/service/time/standard_user_system_clock_core.h" |
| @@ -18,8 +18,10 @@ StandardUserSystemClockCore::StandardUserSystemClockCore( | |||
| 18 | local_system_clock_core{local_system_clock_core}, | 18 | local_system_clock_core{local_system_clock_core}, |
| 19 | network_system_clock_core{network_system_clock_core}, auto_correction_enabled{}, | 19 | network_system_clock_core{network_system_clock_core}, auto_correction_enabled{}, |
| 20 | auto_correction_time{SteadyClockTimePoint::GetRandom()}, | 20 | auto_correction_time{SteadyClockTimePoint::GetRandom()}, |
| 21 | auto_correction_event{Kernel::WritableEvent::CreateEventPair( | 21 | auto_correction_event{Kernel::KEvent::Create( |
| 22 | system.Kernel(), "StandardUserSystemClockCore:AutoCorrectionEvent")} {} | 22 | system.Kernel(), "StandardUserSystemClockCore:AutoCorrectionEvent")} { |
| 23 | auto_correction_event->Initialize(); | ||
| 24 | } | ||
| 23 | 25 | ||
| 24 | ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, | 26 | ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, |
| 25 | bool value) { | 27 | bool value) { |
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h index ef3d468b7..aac44d72f 100644 --- a/src/core/hle/service/time/standard_user_system_clock_core.h +++ b/src/core/hle/service/time/standard_user_system_clock_core.h | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/writable_event.h" | ||
| 8 | #include "core/hle/service/time/clock_types.h" | 7 | #include "core/hle/service/time/clock_types.h" |
| 9 | #include "core/hle/service/time/system_clock_core.h" | 8 | #include "core/hle/service/time/system_clock_core.h" |
| 10 | 9 | ||
| @@ -12,6 +11,10 @@ namespace Core { | |||
| 12 | class System; | 11 | class System; |
| 13 | } | 12 | } |
| 14 | 13 | ||
| 14 | namespace Kernel { | ||
| 15 | class KEvent; | ||
| 16 | } | ||
| 17 | |||
| 15 | namespace Service::Time::Clock { | 18 | namespace Service::Time::Clock { |
| 16 | 19 | ||
| 17 | class StandardLocalSystemClockCore; | 20 | class StandardLocalSystemClockCore; |
| @@ -51,7 +54,7 @@ private: | |||
| 51 | StandardNetworkSystemClockCore& network_system_clock_core; | 54 | StandardNetworkSystemClockCore& network_system_clock_core; |
| 52 | bool auto_correction_enabled{}; | 55 | bool auto_correction_enabled{}; |
| 53 | SteadyClockTimePoint auto_correction_time; | 56 | SteadyClockTimePoint auto_correction_time; |
| 54 | Kernel::EventPair auto_correction_event; | 57 | std::shared_ptr<Kernel::KEvent> auto_correction_event; |
| 55 | }; | 58 | }; |
| 56 | 59 | ||
| 57 | } // namespace Service::Time::Clock | 60 | } // namespace Service::Time::Clock |
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.cpp b/src/core/hle/service/time/system_clock_context_update_callback.cpp index 5cdb80703..bca7d869e 100644 --- a/src/core/hle/service/time/system_clock_context_update_callback.cpp +++ b/src/core/hle/service/time/system_clock_context_update_callback.cpp | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/hle/kernel/writable_event.h" | 5 | #include "core/hle/kernel/k_writable_event.h" |
| 6 | #include "core/hle/service/time/errors.h" | 6 | #include "core/hle/service/time/errors.h" |
| 7 | #include "core/hle/service/time/system_clock_context_update_callback.h" | 7 | #include "core/hle/service/time/system_clock_context_update_callback.h" |
| 8 | 8 | ||
| @@ -21,7 +21,7 @@ bool SystemClockContextUpdateCallback::NeedUpdate(const SystemClockContext& valu | |||
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | void SystemClockContextUpdateCallback::RegisterOperationEvent( | 23 | void SystemClockContextUpdateCallback::RegisterOperationEvent( |
| 24 | std::shared_ptr<Kernel::WritableEvent>&& writable_event) { | 24 | std::shared_ptr<Kernel::KWritableEvent>&& writable_event) { |
| 25 | operation_event_list.emplace_back(std::move(writable_event)); | 25 | operation_event_list.emplace_back(std::move(writable_event)); |
| 26 | } | 26 | } |
| 27 | 27 | ||
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.h b/src/core/hle/service/time/system_clock_context_update_callback.h index 2b0fa7e75..797954958 100644 --- a/src/core/hle/service/time/system_clock_context_update_callback.h +++ b/src/core/hle/service/time/system_clock_context_update_callback.h | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | #include "core/hle/service/time/clock_types.h" | 9 | #include "core/hle/service/time/clock_types.h" |
| 10 | 10 | ||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | class WritableEvent; | 12 | class KWritableEvent; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | namespace Service::Time::Clock { | 15 | namespace Service::Time::Clock { |
| @@ -24,7 +24,7 @@ public: | |||
| 24 | 24 | ||
| 25 | bool NeedUpdate(const SystemClockContext& value) const; | 25 | bool NeedUpdate(const SystemClockContext& value) const; |
| 26 | 26 | ||
| 27 | void RegisterOperationEvent(std::shared_ptr<Kernel::WritableEvent>&& writable_event); | 27 | void RegisterOperationEvent(std::shared_ptr<Kernel::KWritableEvent>&& writable_event); |
| 28 | 28 | ||
| 29 | void BroadcastOperationEvent(); | 29 | void BroadcastOperationEvent(); |
| 30 | 30 | ||
| @@ -37,7 +37,7 @@ protected: | |||
| 37 | 37 | ||
| 38 | private: | 38 | private: |
| 39 | bool has_context{}; | 39 | bool has_context{}; |
| 40 | std::vector<std::shared_ptr<Kernel::WritableEvent>> operation_event_list; | 40 | std::vector<std::shared_ptr<Kernel::KWritableEvent>> operation_event_list; |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | } // namespace Service::Time::Clock | 43 | } // namespace Service::Time::Clock |
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index abc753d5d..18629dd7e 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -121,7 +121,7 @@ private: | |||
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal( | 123 | ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal( |
| 124 | Kernel::Thread* thread, Clock::SystemClockContext user_context, | 124 | Kernel::KThread* thread, Clock::SystemClockContext user_context, |
| 125 | Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) { | 125 | Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) { |
| 126 | 126 | ||
| 127 | auto& time_manager{system.GetTimeManager()}; | 127 | auto& time_manager{system.GetTimeManager()}; |
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 975a8ae5b..4154c7ee9 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h | |||
| @@ -39,7 +39,7 @@ public: | |||
| 39 | 39 | ||
| 40 | private: | 40 | private: |
| 41 | ResultCode GetClockSnapshotFromSystemClockContextInternal( | 41 | ResultCode GetClockSnapshotFromSystemClockContextInternal( |
| 42 | Kernel::Thread* thread, Clock::SystemClockContext user_context, | 42 | Kernel::KThread* thread, Clock::SystemClockContext user_context, |
| 43 | Clock::SystemClockContext network_context, u8 type, | 43 | Clock::SystemClockContext network_context, u8 type, |
| 44 | Clock::ClockSnapshot& cloc_snapshot); | 44 | Clock::ClockSnapshot& cloc_snapshot); |
| 45 | 45 | ||
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h index 5976b2046..e0c3e63da 100644 --- a/src/core/hle/service/time/time_sharedmemory.h +++ b/src/core/hle/service/time/time_sharedmemory.h | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/uuid.h" | 8 | #include "common/uuid.h" |
| 9 | #include "core/hle/kernel/k_thread.h" | ||
| 9 | #include "core/hle/kernel/shared_memory.h" | 10 | #include "core/hle/kernel/shared_memory.h" |
| 10 | #include "core/hle/kernel/thread.h" | ||
| 11 | #include "core/hle/service/time/clock_types.h" | 11 | #include "core/hle/service/time/clock_types.h" |
| 12 | 12 | ||
| 13 | namespace Service::Time { | 13 | namespace Service::Time { |
diff --git a/src/core/hle/service/time/time_zone_types.h b/src/core/hle/service/time/time_zone_types.h index 9be15b53e..4a57e036d 100644 --- a/src/core/hle/service/time/time_zone_types.h +++ b/src/core/hle/service/time/time_zone_types.h | |||
| @@ -45,23 +45,23 @@ static_assert(sizeof(TimeZoneRule) == 0x4000, "TimeZoneRule is incorrect size"); | |||
| 45 | 45 | ||
| 46 | /// https://switchbrew.org/wiki/Glue_services#CalendarAdditionalInfo | 46 | /// https://switchbrew.org/wiki/Glue_services#CalendarAdditionalInfo |
| 47 | struct CalendarAdditionalInfo { | 47 | struct CalendarAdditionalInfo { |
| 48 | u32 day_of_week{}; | 48 | u32 day_of_week; |
| 49 | u32 day_of_year{}; | 49 | u32 day_of_year; |
| 50 | std::array<char, 8> timezone_name; | 50 | std::array<char, 8> timezone_name; |
| 51 | u32 is_dst{}; | 51 | u32 is_dst; |
| 52 | s32 gmt_offset{}; | 52 | s32 gmt_offset; |
| 53 | }; | 53 | }; |
| 54 | static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size"); | 54 | static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size"); |
| 55 | 55 | ||
| 56 | /// https://switchbrew.org/wiki/Glue_services#CalendarTime | 56 | /// https://switchbrew.org/wiki/Glue_services#CalendarTime |
| 57 | struct CalendarTime { | 57 | struct CalendarTime { |
| 58 | s16 year{}; | 58 | s16 year; |
| 59 | s8 month{}; | 59 | s8 month; |
| 60 | s8 day{}; | 60 | s8 day; |
| 61 | s8 hour{}; | 61 | s8 hour; |
| 62 | s8 minute{}; | 62 | s8 minute; |
| 63 | s8 second{}; | 63 | s8 second; |
| 64 | INSERT_PADDING_BYTES(1); | 64 | INSERT_PADDING_BYTES_NOINIT(1); |
| 65 | }; | 65 | }; |
| 66 | static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size"); | 66 | static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size"); |
| 67 | 67 | ||
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 5a202ac81..7f42aa4a0 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp | |||
| @@ -9,7 +9,9 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/hle/kernel/readable_event.h" | 12 | #include "core/hle/kernel/k_event.h" |
| 13 | #include "core/hle/kernel/k_readable_event.h" | ||
| 14 | #include "core/hle/kernel/k_writable_event.h" | ||
| 13 | #include "core/hle/service/vi/display/vi_display.h" | 15 | #include "core/hle/service/vi/display/vi_display.h" |
| 14 | #include "core/hle/service/vi/layer/vi_layer.h" | 16 | #include "core/hle/service/vi/layer/vi_layer.h" |
| 15 | 17 | ||
| @@ -17,8 +19,8 @@ namespace Service::VI { | |||
| 17 | 19 | ||
| 18 | Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} { | 20 | Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} { |
| 19 | auto& kernel = system.Kernel(); | 21 | auto& kernel = system.Kernel(); |
| 20 | vsync_event = | 22 | vsync_event = Kernel::KEvent::Create(kernel, fmt::format("Display VSync Event {}", id)); |
| 21 | Kernel::WritableEvent::CreateEventPair(kernel, fmt::format("Display VSync Event {}", id)); | 23 | vsync_event->Initialize(); |
| 22 | } | 24 | } |
| 23 | 25 | ||
| 24 | Display::~Display() = default; | 26 | Display::~Display() = default; |
| @@ -31,12 +33,12 @@ const Layer& Display::GetLayer(std::size_t index) const { | |||
| 31 | return *layers.at(index); | 33 | return *layers.at(index); |
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | std::shared_ptr<Kernel::ReadableEvent> Display::GetVSyncEvent() const { | 36 | std::shared_ptr<Kernel::KReadableEvent> Display::GetVSyncEvent() const { |
| 35 | return vsync_event.readable; | 37 | return vsync_event->GetReadableEvent(); |
| 36 | } | 38 | } |
| 37 | 39 | ||
| 38 | void Display::SignalVSyncEvent() { | 40 | void Display::SignalVSyncEvent() { |
| 39 | vsync_event.writable->Signal(); | 41 | vsync_event->GetWritableEvent()->Signal(); |
| 40 | } | 42 | } |
| 41 | 43 | ||
| 42 | void Display::CreateLayer(u64 id, NVFlinger::BufferQueue& buffer_queue) { | 44 | void Display::CreateLayer(u64 id, NVFlinger::BufferQueue& buffer_queue) { |
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index a3855d8cd..931c898f6 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h | |||
| @@ -9,7 +9,10 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/hle/kernel/writable_event.h" | 12 | |
| 13 | namespace Kernel { | ||
| 14 | class KEvent; | ||
| 15 | } | ||
| 13 | 16 | ||
| 14 | namespace Service::NVFlinger { | 17 | namespace Service::NVFlinger { |
| 15 | class BufferQueue; | 18 | class BufferQueue; |
| @@ -58,7 +61,7 @@ public: | |||
| 58 | const Layer& GetLayer(std::size_t index) const; | 61 | const Layer& GetLayer(std::size_t index) const; |
| 59 | 62 | ||
| 60 | /// Gets the readable vsync event. | 63 | /// Gets the readable vsync event. |
| 61 | std::shared_ptr<Kernel::ReadableEvent> GetVSyncEvent() const; | 64 | std::shared_ptr<Kernel::KReadableEvent> GetVSyncEvent() const; |
| 62 | 65 | ||
| 63 | /// Signals the internal vsync event. | 66 | /// Signals the internal vsync event. |
| 64 | void SignalVSyncEvent(); | 67 | void SignalVSyncEvent(); |
| @@ -99,7 +102,7 @@ private: | |||
| 99 | std::string name; | 102 | std::string name; |
| 100 | 103 | ||
| 101 | std::vector<std::shared_ptr<Layer>> layers; | 104 | std::vector<std::shared_ptr<Layer>> layers; |
| 102 | Kernel::EventPair vsync_event; | 105 | std::shared_ptr<Kernel::KEvent> vsync_event; |
| 103 | }; | 106 | }; |
| 104 | 107 | ||
| 105 | } // namespace Service::VI | 108 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 968cd16b6..8661895ae 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -18,9 +18,9 @@ | |||
| 18 | #include "common/swap.h" | 18 | #include "common/swap.h" |
| 19 | #include "core/core_timing.h" | 19 | #include "core/core_timing.h" |
| 20 | #include "core/hle/ipc_helpers.h" | 20 | #include "core/hle/ipc_helpers.h" |
| 21 | #include "core/hle/kernel/readable_event.h" | 21 | #include "core/hle/kernel/k_readable_event.h" |
| 22 | #include "core/hle/kernel/thread.h" | 22 | #include "core/hle/kernel/k_thread.h" |
| 23 | #include "core/hle/kernel/writable_event.h" | 23 | #include "core/hle/kernel/k_writable_event.h" |
| 24 | #include "core/hle/service/nvdrv/nvdata.h" | 24 | #include "core/hle/service/nvdrv/nvdata.h" |
| 25 | #include "core/hle/service/nvdrv/nvdrv.h" | 25 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 26 | #include "core/hle/service/nvflinger/buffer_queue.h" | 26 | #include "core/hle/service/nvflinger/buffer_queue.h" |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index ccf8cc153..f976d0a9c 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -15,9 +15,9 @@ | |||
| 15 | #include "core/file_sys/romfs_factory.h" | 15 | #include "core/file_sys/romfs_factory.h" |
| 16 | #include "core/file_sys/vfs_offset.h" | 16 | #include "core/file_sys/vfs_offset.h" |
| 17 | #include "core/hle/kernel/code_set.h" | 17 | #include "core/hle/kernel/code_set.h" |
| 18 | #include "core/hle/kernel/k_thread.h" | ||
| 18 | #include "core/hle/kernel/memory/page_table.h" | 19 | #include "core/hle/kernel/memory/page_table.h" |
| 19 | #include "core/hle/kernel/process.h" | 20 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/thread.h" | ||
| 21 | #include "core/hle/service/filesystem/filesystem.h" | 21 | #include "core/hle/service/filesystem/filesystem.h" |
| 22 | #include "core/loader/nro.h" | 22 | #include "core/loader/nro.h" |
| 23 | #include "core/loader/nso.h" | 23 | #include "core/loader/nso.h" |
| @@ -219,8 +219,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::Sy | |||
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | is_loaded = true; | 221 | is_loaded = true; |
| 222 | return {ResultStatus::Success, | 222 | return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, |
| 223 | LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}}; | 223 | Core::Memory::DEFAULT_STACK_SIZE}}; |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { | 226 | ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 95b6f339a..ea347ea83 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -15,9 +15,9 @@ | |||
| 15 | #include "core/core.h" | 15 | #include "core/core.h" |
| 16 | #include "core/file_sys/patch_manager.h" | 16 | #include "core/file_sys/patch_manager.h" |
| 17 | #include "core/hle/kernel/code_set.h" | 17 | #include "core/hle/kernel/code_set.h" |
| 18 | #include "core/hle/kernel/k_thread.h" | ||
| 18 | #include "core/hle/kernel/memory/page_table.h" | 19 | #include "core/hle/kernel/memory/page_table.h" |
| 19 | #include "core/hle/kernel/process.h" | 20 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/thread.h" | ||
| 21 | #include "core/loader/nso.h" | 21 | #include "core/loader/nso.h" |
| 22 | #include "core/memory.h" | 22 | #include "core/memory.h" |
| 23 | #include "core/settings.h" | 23 | #include "core/settings.h" |
| @@ -179,8 +179,8 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::Sy | |||
| 179 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); | 179 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); |
| 180 | 180 | ||
| 181 | is_loaded = true; | 181 | is_loaded = true; |
| 182 | return {ResultStatus::Success, | 182 | return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, |
| 183 | LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}}; | 183 | Core::Memory::DEFAULT_STACK_SIZE}}; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) { | 186 | ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) { |
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 0becdf642..f199c3362 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | #include "core/hle/kernel/memory/page_table.h" | 20 | #include "core/hle/kernel/memory/page_table.h" |
| 21 | #include "core/hle/kernel/process.h" | 21 | #include "core/hle/kernel/process.h" |
| 22 | #include "core/hle/result.h" | 22 | #include "core/hle/result.h" |
| 23 | #include "core/hle/service/lm/manager.h" | ||
| 24 | #include "core/memory.h" | 23 | #include "core/memory.h" |
| 25 | #include "core/reporter.h" | 24 | #include "core/reporter.h" |
| 26 | #include "core/settings.h" | 25 | #include "core/settings.h" |
| @@ -360,55 +359,6 @@ void Reporter::SaveErrorReport(u64 title_id, ResultCode result, | |||
| 360 | SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp)); | 359 | SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp)); |
| 361 | } | 360 | } |
| 362 | 361 | ||
| 363 | void Reporter::SaveLogReport(u32 destination, std::vector<Service::LM::LogMessage> messages) const { | ||
| 364 | if (!IsReportingEnabled()) { | ||
| 365 | return; | ||
| 366 | } | ||
| 367 | |||
| 368 | const auto timestamp = GetTimestamp(); | ||
| 369 | json out; | ||
| 370 | |||
| 371 | out["yuzu_version"] = GetYuzuVersionData(); | ||
| 372 | out["report_common"] = | ||
| 373 | GetReportCommonData(system.CurrentProcess()->GetTitleID(), RESULT_SUCCESS, timestamp); | ||
| 374 | |||
| 375 | out["log_destination"] = | ||
| 376 | fmt::format("{}", static_cast<Service::LM::DestinationFlag>(destination)); | ||
| 377 | |||
| 378 | auto json_messages = json::array(); | ||
| 379 | std::transform(messages.begin(), messages.end(), std::back_inserter(json_messages), | ||
| 380 | [](const Service::LM::LogMessage& message) { | ||
| 381 | json out; | ||
| 382 | out["is_head"] = fmt::format("{}", message.header.IsHeadLog()); | ||
| 383 | out["is_tail"] = fmt::format("{}", message.header.IsTailLog()); | ||
| 384 | out["pid"] = fmt::format("{:016X}", message.header.pid); | ||
| 385 | out["thread_context"] = | ||
| 386 | fmt::format("{:016X}", message.header.thread_context); | ||
| 387 | out["payload_size"] = fmt::format("{:016X}", message.header.payload_size); | ||
| 388 | out["flags"] = fmt::format("{:04X}", message.header.flags.Value()); | ||
| 389 | out["severity"] = fmt::format("{}", message.header.severity.Value()); | ||
| 390 | out["verbosity"] = fmt::format("{:02X}", message.header.verbosity); | ||
| 391 | |||
| 392 | auto fields = json::array(); | ||
| 393 | std::transform(message.fields.begin(), message.fields.end(), | ||
| 394 | std::back_inserter(fields), [](const auto& kv) { | ||
| 395 | json out; | ||
| 396 | out["type"] = fmt::format("{}", kv.first); | ||
| 397 | out["data"] = | ||
| 398 | Service::LM::FormatField(kv.first, kv.second); | ||
| 399 | return out; | ||
| 400 | }); | ||
| 401 | |||
| 402 | out["fields"] = std::move(fields); | ||
| 403 | return out; | ||
| 404 | }); | ||
| 405 | |||
| 406 | out["log_messages"] = std::move(json_messages); | ||
| 407 | |||
| 408 | SaveToFile(std::move(out), | ||
| 409 | GetPath("log_report", system.CurrentProcess()->GetTitleID(), timestamp)); | ||
| 410 | } | ||
| 411 | |||
| 412 | void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, | 362 | void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, |
| 413 | std::string log_message) const { | 363 | std::string log_message) const { |
| 414 | if (!IsReportingEnabled()) | 364 | if (!IsReportingEnabled()) |
diff --git a/src/core/reporter.h b/src/core/reporter.h index 86d760cf0..b2c2d9a2e 100644 --- a/src/core/reporter.h +++ b/src/core/reporter.h | |||
| @@ -72,9 +72,6 @@ public: | |||
| 72 | void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, | 72 | void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, |
| 73 | std::string log_message) const; | 73 | std::string log_message) const; |
| 74 | 74 | ||
| 75 | // Used by lm services | ||
| 76 | void SaveLogReport(u32 destination, std::vector<Service::LM::LogMessage> messages) const; | ||
| 77 | |||
| 78 | // Can be used anywhere to generate a backtrace and general info report at any point during | 75 | // Can be used anywhere to generate a backtrace and general info report at any point during |
| 79 | // execution. Not intended to be used for anything other than debugging or testing. | 76 | // execution. Not intended to be used for anything other than debugging or testing. |
| 80 | void SaveUserReport() const; | 77 | void SaveUserReport() const; |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 39306509a..2ae5196e0 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -70,6 +70,9 @@ void LogSettings() { | |||
| 70 | log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue()); | 70 | log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue()); |
| 71 | log_setting("Audio_OutputDevice", values.audio_device_id); | 71 | log_setting("Audio_OutputDevice", values.audio_device_id); |
| 72 | log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); | 72 | log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); |
| 73 | log_setting("DataStorage_CacheDir", Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)); | ||
| 74 | log_setting("DataStorage_ConfigDir", Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir)); | ||
| 75 | log_setting("DataStorage_LoadDir", Common::FS::GetUserPath(Common::FS::UserPath::LoadDir)); | ||
| 73 | log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir)); | 76 | log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir)); |
| 74 | log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)); | 77 | log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)); |
| 75 | log_setting("Debugging_ProgramArgs", values.program_args); | 78 | log_setting("Debugging_ProgramArgs", values.program_args); |
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp index 40b516f85..770893687 100755 --- a/src/input_common/analog_from_button.cpp +++ b/src/input_common/analog_from_button.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <atomic> | ||
| 5 | #include <chrono> | 6 | #include <chrono> |
| 6 | #include <cmath> | 7 | #include <cmath> |
| 7 | #include <thread> | 8 | #include <thread> |
| @@ -20,13 +21,16 @@ public: | |||
| 20 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), | 21 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), |
| 21 | right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), | 22 | right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), |
| 22 | modifier_angle(modifier_angle_) { | 23 | modifier_angle(modifier_angle_) { |
| 24 | update_thread_running.store(true); | ||
| 23 | update_thread = std::thread(&Analog::UpdateStatus, this); | 25 | update_thread = std::thread(&Analog::UpdateStatus, this); |
| 24 | } | 26 | } |
| 25 | 27 | ||
| 26 | ~Analog() override { | 28 | ~Analog() override { |
| 27 | update_thread_running = false; | 29 | if (update_thread_running.load()) { |
| 28 | if (update_thread.joinable()) { | 30 | update_thread_running.store(false); |
| 29 | update_thread.join(); | 31 | if (update_thread.joinable()) { |
| 32 | update_thread.join(); | ||
| 33 | } | ||
| 30 | } | 34 | } |
| 31 | } | 35 | } |
| 32 | 36 | ||
| @@ -58,7 +62,7 @@ public: | |||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | void UpdateStatus() { | 64 | void UpdateStatus() { |
| 61 | while (update_thread_running) { | 65 | while (update_thread_running.load()) { |
| 62 | const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; | 66 | const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; |
| 63 | 67 | ||
| 64 | bool r = right->GetStatus(); | 68 | bool r = right->GetStatus(); |
| @@ -135,6 +139,10 @@ public: | |||
| 135 | static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF)); | 139 | static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF)); |
| 136 | } | 140 | } |
| 137 | 141 | ||
| 142 | Input::AnalogProperties GetAnalogProperties() const override { | ||
| 143 | return {modifier_scale, 1.0f, 0.5f}; | ||
| 144 | } | ||
| 145 | |||
| 138 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | 146 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |
| 139 | switch (direction) { | 147 | switch (direction) { |
| 140 | case Input::AnalogDirection::RIGHT: | 148 | case Input::AnalogDirection::RIGHT: |
| @@ -160,7 +168,7 @@ private: | |||
| 160 | float angle{}; | 168 | float angle{}; |
| 161 | float amplitude{}; | 169 | float amplitude{}; |
| 162 | std::thread update_thread; | 170 | std::thread update_thread; |
| 163 | bool update_thread_running{true}; | 171 | std::atomic<bool> update_thread_running{}; |
| 164 | }; | 172 | }; |
| 165 | 173 | ||
| 166 | std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { | 174 | std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { |
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 9670bdeb2..1b6ded8d6 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -185,6 +185,16 @@ public: | |||
| 185 | return {0.0f, 0.0f}; | 185 | return {0.0f, 0.0f}; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | std::tuple<float, float> GetRawStatus() const override { | ||
| 189 | const float x = GetAxis(axis_x); | ||
| 190 | const float y = GetAxis(axis_y); | ||
| 191 | return {x, y}; | ||
| 192 | } | ||
| 193 | |||
| 194 | Input::AnalogProperties GetAnalogProperties() const override { | ||
| 195 | return {deadzone, range, 0.5f}; | ||
| 196 | } | ||
| 197 | |||
| 188 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | 198 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |
| 189 | const auto [x, y] = GetStatus(); | 199 | const auto [x, y] = GetStatus(); |
| 190 | const float directional_deadzone = 0.5f; | 200 | const float directional_deadzone = 0.5f; |
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp index 508eb0c7d..3d799b293 100644 --- a/src/input_common/mouse/mouse_poller.cpp +++ b/src/input_common/mouse/mouse_poller.cpp | |||
| @@ -106,6 +106,16 @@ public: | |||
| 106 | return {0.0f, 0.0f}; | 106 | return {0.0f, 0.0f}; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | std::tuple<float, float> GetRawStatus() const override { | ||
| 110 | const float x = GetAxis(axis_x); | ||
| 111 | const float y = GetAxis(axis_y); | ||
| 112 | return {x, y}; | ||
| 113 | } | ||
| 114 | |||
| 115 | Input::AnalogProperties GetAnalogProperties() const override { | ||
| 116 | return {deadzone, range, 0.5f}; | ||
| 117 | } | ||
| 118 | |||
| 109 | private: | 119 | private: |
| 110 | const u32 button; | 120 | const u32 button; |
| 111 | const u32 axis_x; | 121 | const u32 axis_x; |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index d32eb732a..f67de37e3 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -81,10 +81,14 @@ public: | |||
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | bool RumblePlay(u16 amp_low, u16 amp_high) { | 83 | bool RumblePlay(u16 amp_low, u16 amp_high) { |
| 84 | constexpr u32 rumble_max_duration_ms = 1000; | ||
| 85 | |||
| 84 | if (sdl_controller) { | 86 | if (sdl_controller) { |
| 85 | return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0; | 87 | return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, |
| 88 | rumble_max_duration_ms) == 0; | ||
| 86 | } else if (sdl_joystick) { | 89 | } else if (sdl_joystick) { |
| 87 | return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0; | 90 | return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, |
| 91 | rumble_max_duration_ms) == 0; | ||
| 88 | } | 92 | } |
| 89 | 93 | ||
| 90 | return false; | 94 | return false; |
| @@ -373,6 +377,16 @@ public: | |||
| 373 | return {}; | 377 | return {}; |
| 374 | } | 378 | } |
| 375 | 379 | ||
| 380 | std::tuple<float, float> GetRawStatus() const override { | ||
| 381 | const float x = joystick->GetAxis(axis_x, range); | ||
| 382 | const float y = joystick->GetAxis(axis_y, range); | ||
| 383 | return {x, -y}; | ||
| 384 | } | ||
| 385 | |||
| 386 | Input::AnalogProperties GetAnalogProperties() const override { | ||
| 387 | return {deadzone, range, 0.5f}; | ||
| 388 | } | ||
| 389 | |||
| 376 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | 390 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |
| 377 | const auto [x, y] = GetStatus(); | 391 | const auto [x, y] = GetStatus(); |
| 378 | const float directional_deadzone = 0.5f; | 392 | const float directional_deadzone = 0.5f; |
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp index a07124a86..ffbe4f2ed 100644 --- a/src/input_common/touch_from_button.cpp +++ b/src/input_common/touch_from_button.cpp | |||
| @@ -25,18 +25,19 @@ public: | |||
| 25 | } | 25 | } |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | std::tuple<float, float, bool> GetStatus() const override { | 28 | Input::TouchStatus GetStatus() const override { |
| 29 | for (const auto& m : map) { | 29 | Input::TouchStatus touch_status{}; |
| 30 | const bool state = std::get<0>(m)->GetStatus(); | 30 | for (std::size_t id = 0; id < map.size() && id < touch_status.size(); ++id) { |
| 31 | const bool state = std::get<0>(map[id])->GetStatus(); | ||
| 31 | if (state) { | 32 | if (state) { |
| 32 | const float x = static_cast<float>(std::get<1>(m)) / | 33 | const float x = static_cast<float>(std::get<1>(map[id])) / |
| 33 | static_cast<int>(Layout::ScreenUndocked::Width); | 34 | static_cast<int>(Layout::ScreenUndocked::Width); |
| 34 | const float y = static_cast<float>(std::get<2>(m)) / | 35 | const float y = static_cast<float>(std::get<2>(map[id])) / |
| 35 | static_cast<int>(Layout::ScreenUndocked::Height); | 36 | static_cast<int>(Layout::ScreenUndocked::Height); |
| 36 | return {x, y, true}; | 37 | touch_status[id] = {x, y, true}; |
| 37 | } | 38 | } |
| 38 | } | 39 | } |
| 39 | return {}; | 40 | return touch_status; |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | private: | 43 | private: |
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index 412d57896..e7e50d789 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp | |||
| @@ -136,6 +136,7 @@ static void SocketLoop(Socket* socket) { | |||
| 136 | 136 | ||
| 137 | Client::Client() { | 137 | Client::Client() { |
| 138 | LOG_INFO(Input, "Udp Initialization started"); | 138 | LOG_INFO(Input, "Udp Initialization started"); |
| 139 | finger_id.fill(MAX_TOUCH_FINGERS); | ||
| 139 | ReloadSockets(); | 140 | ReloadSockets(); |
| 140 | } | 141 | } |
| 141 | 142 | ||
| @@ -176,7 +177,7 @@ void Client::ReloadSockets() { | |||
| 176 | std::string server_token; | 177 | std::string server_token; |
| 177 | std::size_t client = 0; | 178 | std::size_t client = 0; |
| 178 | while (std::getline(servers_ss, server_token, ',')) { | 179 | while (std::getline(servers_ss, server_token, ',')) { |
| 179 | if (client == max_udp_clients) { | 180 | if (client == MAX_UDP_CLIENTS) { |
| 180 | break; | 181 | break; |
| 181 | } | 182 | } |
| 182 | std::stringstream server_ss(server_token); | 183 | std::stringstream server_ss(server_token); |
| @@ -194,7 +195,7 @@ void Client::ReloadSockets() { | |||
| 194 | for (std::size_t pad = 0; pad < 4; ++pad) { | 195 | for (std::size_t pad = 0; pad < 4; ++pad) { |
| 195 | const std::size_t client_number = | 196 | const std::size_t client_number = |
| 196 | GetClientNumber(udp_input_address, udp_input_port, pad); | 197 | GetClientNumber(udp_input_address, udp_input_port, pad); |
| 197 | if (client_number != max_udp_clients) { | 198 | if (client_number != MAX_UDP_CLIENTS) { |
| 198 | LOG_ERROR(Input, "Duplicated UDP servers found"); | 199 | LOG_ERROR(Input, "Duplicated UDP servers found"); |
| 199 | continue; | 200 | continue; |
| 200 | } | 201 | } |
| @@ -213,7 +214,7 @@ std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t | |||
| 213 | return client; | 214 | return client; |
| 214 | } | 215 | } |
| 215 | } | 216 | } |
| 216 | return max_udp_clients; | 217 | return MAX_UDP_CLIENTS; |
| 217 | } | 218 | } |
| 218 | 219 | ||
| 219 | void Client::OnVersion([[maybe_unused]] Response::Version data) { | 220 | void Client::OnVersion([[maybe_unused]] Response::Version data) { |
| @@ -259,33 +260,14 @@ void Client::OnPadData(Response::PadData data, std::size_t client) { | |||
| 259 | std::lock_guard guard(clients[client].status.update_mutex); | 260 | std::lock_guard guard(clients[client].status.update_mutex); |
| 260 | clients[client].status.motion_status = clients[client].motion.GetMotion(); | 261 | clients[client].status.motion_status = clients[client].motion.GetMotion(); |
| 261 | 262 | ||
| 262 | // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates | 263 | for (std::size_t id = 0; id < data.touch.size(); ++id) { |
| 263 | // between a simple "tap" and a hard press that causes the touch screen to click. | 264 | UpdateTouchInput(data.touch[id], client, id); |
| 264 | const bool is_active = data.touch_1.is_active != 0; | ||
| 265 | |||
| 266 | float x = 0; | ||
| 267 | float y = 0; | ||
| 268 | |||
| 269 | if (is_active && clients[client].status.touch_calibration) { | ||
| 270 | const u16 min_x = clients[client].status.touch_calibration->min_x; | ||
| 271 | const u16 max_x = clients[client].status.touch_calibration->max_x; | ||
| 272 | const u16 min_y = clients[client].status.touch_calibration->min_y; | ||
| 273 | const u16 max_y = clients[client].status.touch_calibration->max_y; | ||
| 274 | |||
| 275 | x = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) - | ||
| 276 | min_x) / | ||
| 277 | static_cast<float>(max_x - min_x); | ||
| 278 | y = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) - | ||
| 279 | min_y) / | ||
| 280 | static_cast<float>(max_y - min_y); | ||
| 281 | } | 265 | } |
| 282 | 266 | ||
| 283 | clients[client].status.touch_status = {x, y, is_active}; | ||
| 284 | |||
| 285 | if (configuring) { | 267 | if (configuring) { |
| 286 | const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); | 268 | const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); |
| 287 | const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); | 269 | const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); |
| 288 | UpdateYuzuSettings(client, accelerometer, gyroscope, is_active); | 270 | UpdateYuzuSettings(client, accelerometer, gyroscope); |
| 289 | } | 271 | } |
| 290 | } | 272 | } |
| 291 | } | 273 | } |
| @@ -320,21 +302,17 @@ void Client::Reset() { | |||
| 320 | } | 302 | } |
| 321 | 303 | ||
| 322 | void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, | 304 | void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, |
| 323 | const Common::Vec3<float>& gyro, bool touch) { | 305 | const Common::Vec3<float>& gyro) { |
| 324 | if (gyro.Length() > 0.2f) { | 306 | if (gyro.Length() > 0.2f) { |
| 325 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", | 307 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, |
| 326 | client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); | 308 | gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); |
| 327 | } | 309 | } |
| 328 | UDPPadStatus pad{ | 310 | UDPPadStatus pad{ |
| 329 | .host = clients[client].host, | 311 | .host = clients[client].host, |
| 330 | .port = clients[client].port, | 312 | .port = clients[client].port, |
| 331 | .pad_index = clients[client].pad_index, | 313 | .pad_index = clients[client].pad_index, |
| 332 | }; | 314 | }; |
| 333 | if (touch) { | 315 | for (std::size_t i = 0; i < 3; ++i) { |
| 334 | pad.touch = PadTouch::Click; | ||
| 335 | pad_queue.Push(pad); | ||
| 336 | } | ||
| 337 | for (size_t i = 0; i < 3; ++i) { | ||
| 338 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { | 316 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { |
| 339 | pad.motion = static_cast<PadMotion>(i); | 317 | pad.motion = static_cast<PadMotion>(i); |
| 340 | pad.motion_value = gyro[i]; | 318 | pad.motion_value = gyro[i]; |
| @@ -348,6 +326,50 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a | |||
| 348 | } | 326 | } |
| 349 | } | 327 | } |
| 350 | 328 | ||
| 329 | std::optional<std::size_t> Client::GetUnusedFingerID() const { | ||
| 330 | std::size_t first_free_id = 0; | ||
| 331 | while (first_free_id < MAX_TOUCH_FINGERS) { | ||
| 332 | if (!std::get<2>(touch_status[first_free_id])) { | ||
| 333 | return first_free_id; | ||
| 334 | } else { | ||
| 335 | first_free_id++; | ||
| 336 | } | ||
| 337 | } | ||
| 338 | return std::nullopt; | ||
| 339 | } | ||
| 340 | |||
| 341 | void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) { | ||
| 342 | // TODO: Use custom calibration per device | ||
| 343 | const Common::ParamPackage touch_param(Settings::values.touch_device); | ||
| 344 | const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100)); | ||
| 345 | const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50)); | ||
| 346 | const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800)); | ||
| 347 | const u16 max_y = static_cast<u16>(touch_param.Get("max_y", 850)); | ||
| 348 | const std::size_t touch_id = client * 2 + id; | ||
| 349 | if (touch_pad.is_active) { | ||
| 350 | if (finger_id[touch_id] == MAX_TOUCH_FINGERS) { | ||
| 351 | const auto first_free_id = GetUnusedFingerID(); | ||
| 352 | if (!first_free_id) { | ||
| 353 | // Invalid finger id skip to next input | ||
| 354 | return; | ||
| 355 | } | ||
| 356 | finger_id[touch_id] = *first_free_id; | ||
| 357 | } | ||
| 358 | auto& [x, y, pressed] = touch_status[finger_id[touch_id]]; | ||
| 359 | x = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.x), min_x, max_x) - min_x) / | ||
| 360 | static_cast<float>(max_x - min_x); | ||
| 361 | y = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.y), min_y, max_y) - min_y) / | ||
| 362 | static_cast<float>(max_y - min_y); | ||
| 363 | pressed = true; | ||
| 364 | return; | ||
| 365 | } | ||
| 366 | |||
| 367 | if (finger_id[touch_id] != MAX_TOUCH_FINGERS) { | ||
| 368 | touch_status[finger_id[touch_id]] = {}; | ||
| 369 | finger_id[touch_id] = MAX_TOUCH_FINGERS; | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 351 | void Client::BeginConfiguration() { | 373 | void Client::BeginConfiguration() { |
| 352 | pad_queue.Clear(); | 374 | pad_queue.Clear(); |
| 353 | configuring = true; | 375 | configuring = true; |
| @@ -360,7 +382,7 @@ void Client::EndConfiguration() { | |||
| 360 | 382 | ||
| 361 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { | 383 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { |
| 362 | const std::size_t client_number = GetClientNumber(host, port, pad); | 384 | const std::size_t client_number = GetClientNumber(host, port, pad); |
| 363 | if (client_number == max_udp_clients) { | 385 | if (client_number == MAX_UDP_CLIENTS) { |
| 364 | return clients[0].status; | 386 | return clients[0].status; |
| 365 | } | 387 | } |
| 366 | return clients[client_number].status; | 388 | return clients[client_number].status; |
| @@ -368,12 +390,20 @@ DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t | |||
| 368 | 390 | ||
| 369 | const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { | 391 | const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { |
| 370 | const std::size_t client_number = GetClientNumber(host, port, pad); | 392 | const std::size_t client_number = GetClientNumber(host, port, pad); |
| 371 | if (client_number == max_udp_clients) { | 393 | if (client_number == MAX_UDP_CLIENTS) { |
| 372 | return clients[0].status; | 394 | return clients[0].status; |
| 373 | } | 395 | } |
| 374 | return clients[client_number].status; | 396 | return clients[client_number].status; |
| 375 | } | 397 | } |
| 376 | 398 | ||
| 399 | Input::TouchStatus& Client::GetTouchState() { | ||
| 400 | return touch_status; | ||
| 401 | } | ||
| 402 | |||
| 403 | const Input::TouchStatus& Client::GetTouchState() const { | ||
| 404 | return touch_status; | ||
| 405 | } | ||
| 406 | |||
| 377 | Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { | 407 | Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { |
| 378 | return pad_queue; | 408 | return pad_queue; |
| 379 | } | 409 | } |
| @@ -426,24 +456,24 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 426 | current_status = Status::Ready; | 456 | current_status = Status::Ready; |
| 427 | status_callback(current_status); | 457 | status_callback(current_status); |
| 428 | } | 458 | } |
| 429 | if (data.touch_1.is_active == 0) { | 459 | if (data.touch[0].is_active == 0) { |
| 430 | return; | 460 | return; |
| 431 | } | 461 | } |
| 432 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, | 462 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, |
| 433 | data.touch_1.y); | 463 | data.touch[0].y); |
| 434 | min_x = std::min(min_x, static_cast<u16>(data.touch_1.x)); | 464 | min_x = std::min(min_x, static_cast<u16>(data.touch[0].x)); |
| 435 | min_y = std::min(min_y, static_cast<u16>(data.touch_1.y)); | 465 | min_y = std::min(min_y, static_cast<u16>(data.touch[0].y)); |
| 436 | if (current_status == Status::Ready) { | 466 | if (current_status == Status::Ready) { |
| 437 | // First touch - min data (min_x/min_y) | 467 | // First touch - min data (min_x/min_y) |
| 438 | current_status = Status::Stage1Completed; | 468 | current_status = Status::Stage1Completed; |
| 439 | status_callback(current_status); | 469 | status_callback(current_status); |
| 440 | } | 470 | } |
| 441 | if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD && | 471 | if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && |
| 442 | data.touch_1.y - min_y > CALIBRATION_THRESHOLD) { | 472 | data.touch[0].y - min_y > CALIBRATION_THRESHOLD) { |
| 443 | // Set the current position as max value and finishes | 473 | // Set the current position as max value and finishes |
| 444 | // configuration | 474 | // configuration |
| 445 | max_x = data.touch_1.x; | 475 | max_x = data.touch[0].x; |
| 446 | max_y = data.touch_1.y; | 476 | max_y = data.touch[0].y; |
| 447 | current_status = Status::Completed; | 477 | current_status = Status::Completed; |
| 448 | data_callback(min_x, min_y, max_x, max_y); | 478 | data_callback(min_x, min_y, max_x, max_y); |
| 449 | status_callback(current_status); | 479 | status_callback(current_status); |
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index 00c8b09f5..822f9c550 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h | |||
| @@ -28,6 +28,7 @@ class Socket; | |||
| 28 | namespace Response { | 28 | namespace Response { |
| 29 | struct PadData; | 29 | struct PadData; |
| 30 | struct PortInfo; | 30 | struct PortInfo; |
| 31 | struct TouchPad; | ||
| 31 | struct Version; | 32 | struct Version; |
| 32 | } // namespace Response | 33 | } // namespace Response |
| 33 | 34 | ||
| @@ -50,7 +51,6 @@ struct UDPPadStatus { | |||
| 50 | std::string host{"127.0.0.1"}; | 51 | std::string host{"127.0.0.1"}; |
| 51 | u16 port{26760}; | 52 | u16 port{26760}; |
| 52 | std::size_t pad_index{}; | 53 | std::size_t pad_index{}; |
| 53 | PadTouch touch{PadTouch::Undefined}; | ||
| 54 | PadMotion motion{PadMotion::Undefined}; | 54 | PadMotion motion{PadMotion::Undefined}; |
| 55 | f32 motion_value{0.0f}; | 55 | f32 motion_value{0.0f}; |
| 56 | }; | 56 | }; |
| @@ -93,6 +93,9 @@ public: | |||
| 93 | DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); | 93 | DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); |
| 94 | const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; | 94 | const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; |
| 95 | 95 | ||
| 96 | Input::TouchStatus& GetTouchState(); | ||
| 97 | const Input::TouchStatus& GetTouchState() const; | ||
| 98 | |||
| 96 | private: | 99 | private: |
| 97 | struct ClientData { | 100 | struct ClientData { |
| 98 | std::string host{"127.0.0.1"}; | 101 | std::string host{"127.0.0.1"}; |
| @@ -122,14 +125,25 @@ private: | |||
| 122 | void StartCommunication(std::size_t client, const std::string& host, u16 port, | 125 | void StartCommunication(std::size_t client, const std::string& host, u16 port, |
| 123 | std::size_t pad_index, u32 client_id); | 126 | std::size_t pad_index, u32 client_id); |
| 124 | void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, | 127 | void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, |
| 125 | const Common::Vec3<float>& gyro, bool touch); | 128 | const Common::Vec3<float>& gyro); |
| 129 | |||
| 130 | // Returns an unused finger id, if there is no fingers available std::nullopt will be | ||
| 131 | // returned | ||
| 132 | std::optional<std::size_t> GetUnusedFingerID() const; | ||
| 133 | |||
| 134 | // Merges and updates all touch inputs into the touch_status array | ||
| 135 | void UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id); | ||
| 126 | 136 | ||
| 127 | bool configuring = false; | 137 | bool configuring = false; |
| 128 | 138 | ||
| 129 | // Allocate clients for 8 udp servers | 139 | // Allocate clients for 8 udp servers |
| 130 | const std::size_t max_udp_clients = 32; | 140 | static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8; |
| 131 | std::array<ClientData, 4 * 8> clients; | 141 | // Each client can have up 2 touch inputs |
| 132 | Common::SPSCQueue<UDPPadStatus> pad_queue; | 142 | static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; |
| 143 | std::array<ClientData, MAX_UDP_CLIENTS> clients{}; | ||
| 144 | Common::SPSCQueue<UDPPadStatus> pad_queue{}; | ||
| 145 | Input::TouchStatus touch_status{}; | ||
| 146 | std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{}; | ||
| 133 | }; | 147 | }; |
| 134 | 148 | ||
| 135 | /// An async job allowing configuration of the touchpad calibration. | 149 | /// An async job allowing configuration of the touchpad calibration. |
diff --git a/src/input_common/udp/protocol.h b/src/input_common/udp/protocol.h index fc1aea4b9..a3d276697 100644 --- a/src/input_common/udp/protocol.h +++ b/src/input_common/udp/protocol.h | |||
| @@ -140,6 +140,14 @@ static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong si | |||
| 140 | static_assert(std::is_trivially_copyable_v<PortInfo>, | 140 | static_assert(std::is_trivially_copyable_v<PortInfo>, |
| 141 | "UDP Response PortInfo is not trivially copyable"); | 141 | "UDP Response PortInfo is not trivially copyable"); |
| 142 | 142 | ||
| 143 | struct TouchPad { | ||
| 144 | u8 is_active{}; | ||
| 145 | u8 id{}; | ||
| 146 | u16_le x{}; | ||
| 147 | u16_le y{}; | ||
| 148 | }; | ||
| 149 | static_assert(sizeof(TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); | ||
| 150 | |||
| 143 | #pragma pack(push, 1) | 151 | #pragma pack(push, 1) |
| 144 | struct PadData { | 152 | struct PadData { |
| 145 | PortInfo info{}; | 153 | PortInfo info{}; |
| @@ -190,12 +198,7 @@ struct PadData { | |||
| 190 | u8 button_13{}; | 198 | u8 button_13{}; |
| 191 | } analog_button; | 199 | } analog_button; |
| 192 | 200 | ||
| 193 | struct TouchPad { | 201 | std::array<TouchPad, 2> touch; |
| 194 | u8 is_active{}; | ||
| 195 | u8 id{}; | ||
| 196 | u16_le x{}; | ||
| 197 | u16_le y{}; | ||
| 198 | } touch_1, touch_2; | ||
| 199 | 202 | ||
| 200 | u64_le motion_timestamp; | 203 | u64_le motion_timestamp; |
| 201 | 204 | ||
| @@ -222,7 +225,6 @@ static_assert(sizeof(Message<PadData>) == MAX_PACKET_SIZE, | |||
| 222 | 225 | ||
| 223 | static_assert(sizeof(PadData::AnalogButton) == 12, | 226 | static_assert(sizeof(PadData::AnalogButton) == 12, |
| 224 | "UDP Response AnalogButton struct has wrong size "); | 227 | "UDP Response AnalogButton struct has wrong size "); |
| 225 | static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); | ||
| 226 | static_assert(sizeof(PadData::Accelerometer) == 12, | 228 | static_assert(sizeof(PadData::Accelerometer) == 12, |
| 227 | "UDP Response Accelerometer struct has wrong size "); | 229 | "UDP Response Accelerometer struct has wrong size "); |
| 228 | static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); | 230 | static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); |
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp index c5da27a38..b630281a0 100644 --- a/src/input_common/udp/udp.cpp +++ b/src/input_common/udp/udp.cpp | |||
| @@ -78,8 +78,8 @@ public: | |||
| 78 | explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) | 78 | explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) |
| 79 | : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} | 79 | : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} |
| 80 | 80 | ||
| 81 | std::tuple<float, float, bool> GetStatus() const override { | 81 | Input::TouchStatus GetStatus() const override { |
| 82 | return client->GetPadState(ip, port, pad).touch_status; | 82 | return client->GetTouchState(); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | private: | 85 | private: |
| @@ -107,32 +107,4 @@ std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamP | |||
| 107 | return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); | 107 | return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | void UDPTouchFactory::BeginConfiguration() { | ||
| 111 | polling = true; | ||
| 112 | client->BeginConfiguration(); | ||
| 113 | } | ||
| 114 | |||
| 115 | void UDPTouchFactory::EndConfiguration() { | ||
| 116 | polling = false; | ||
| 117 | client->EndConfiguration(); | ||
| 118 | } | ||
| 119 | |||
| 120 | Common::ParamPackage UDPTouchFactory::GetNextInput() { | ||
| 121 | Common::ParamPackage params; | ||
| 122 | CemuhookUDP::UDPPadStatus pad; | ||
| 123 | auto& queue = client->GetPadQueue(); | ||
| 124 | while (queue.Pop(pad)) { | ||
| 125 | if (pad.touch == CemuhookUDP::PadTouch::Undefined) { | ||
| 126 | continue; | ||
| 127 | } | ||
| 128 | params.Set("engine", "cemuhookudp"); | ||
| 129 | params.Set("ip", pad.host); | ||
| 130 | params.Set("port", static_cast<u16>(pad.port)); | ||
| 131 | params.Set("pad_index", static_cast<u16>(pad.pad_index)); | ||
| 132 | params.Set("touch", static_cast<u16>(pad.touch)); | ||
| 133 | return params; | ||
| 134 | } | ||
| 135 | return params; | ||
| 136 | } | ||
| 137 | |||
| 138 | } // namespace InputCommon | 110 | } // namespace InputCommon |
diff --git a/src/tests/common/ring_buffer.cpp b/src/tests/common/ring_buffer.cpp index 54def22da..903626e4b 100644 --- a/src/tests/common/ring_buffer.cpp +++ b/src/tests/common/ring_buffer.cpp | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | namespace Common { | 14 | namespace Common { |
| 15 | 15 | ||
| 16 | TEST_CASE("RingBuffer: Basic Tests", "[common]") { | 16 | TEST_CASE("RingBuffer: Basic Tests", "[common]") { |
| 17 | RingBuffer<char, 4, 1> buf; | 17 | RingBuffer<char, 4> buf; |
| 18 | 18 | ||
| 19 | // Pushing values into a ring buffer with space should succeed. | 19 | // Pushing values into a ring buffer with space should succeed. |
| 20 | for (std::size_t i = 0; i < 4; i++) { | 20 | for (std::size_t i = 0; i < 4; i++) { |
| @@ -77,7 +77,7 @@ TEST_CASE("RingBuffer: Basic Tests", "[common]") { | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | TEST_CASE("RingBuffer: Threaded Test", "[common]") { | 79 | TEST_CASE("RingBuffer: Threaded Test", "[common]") { |
| 80 | RingBuffer<char, 4, 2> buf; | 80 | RingBuffer<char, 8> buf; |
| 81 | const char seed = 42; | 81 | const char seed = 42; |
| 82 | const std::size_t count = 1000000; | 82 | const std::size_t count = 1000000; |
| 83 | std::size_t full = 0; | 83 | std::size_t full = 0; |
| @@ -92,8 +92,8 @@ TEST_CASE("RingBuffer: Threaded Test", "[common]") { | |||
| 92 | std::array<char, 2> value = {seed, seed}; | 92 | std::array<char, 2> value = {seed, seed}; |
| 93 | std::size_t i = 0; | 93 | std::size_t i = 0; |
| 94 | while (i < count) { | 94 | while (i < count) { |
| 95 | if (const std::size_t c = buf.Push(&value[0], 1); c > 0) { | 95 | if (const std::size_t c = buf.Push(&value[0], 2); c > 0) { |
| 96 | REQUIRE(c == 1U); | 96 | REQUIRE(c == 2U); |
| 97 | i++; | 97 | i++; |
| 98 | next_value(value); | 98 | next_value(value); |
| 99 | } else { | 99 | } else { |
| @@ -107,7 +107,7 @@ TEST_CASE("RingBuffer: Threaded Test", "[common]") { | |||
| 107 | std::array<char, 2> value = {seed, seed}; | 107 | std::array<char, 2> value = {seed, seed}; |
| 108 | std::size_t i = 0; | 108 | std::size_t i = 0; |
| 109 | while (i < count) { | 109 | while (i < count) { |
| 110 | if (const std::vector<char> v = buf.Pop(1); v.size() > 0) { | 110 | if (const std::vector<char> v = buf.Pop(2); v.size() > 0) { |
| 111 | REQUIRE(v.size() == 2U); | 111 | REQUIRE(v.size() == 2U); |
| 112 | REQUIRE(v[0] == value[0]); | 112 | REQUIRE(v[0] == value[0]); |
| 113 | REQUIRE(v[1] == value[1]); | 113 | REQUIRE(v[1] == value[1]); |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index e01ea55ab..2cf95937e 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -67,8 +67,6 @@ add_library(video_core STATIC | |||
| 67 | guest_driver.h | 67 | guest_driver.h |
| 68 | memory_manager.cpp | 68 | memory_manager.cpp |
| 69 | memory_manager.h | 69 | memory_manager.h |
| 70 | morton.cpp | ||
| 71 | morton.h | ||
| 72 | query_cache.h | 70 | query_cache.h |
| 73 | rasterizer_accelerated.cpp | 71 | rasterizer_accelerated.cpp |
| 74 | rasterizer_accelerated.h | 72 | rasterizer_accelerated.h |
| @@ -288,10 +286,10 @@ target_link_libraries(video_core PRIVATE sirit) | |||
| 288 | 286 | ||
| 289 | if (ENABLE_NSIGHT_AFTERMATH) | 287 | if (ENABLE_NSIGHT_AFTERMATH) |
| 290 | if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) | 288 | if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) |
| 291 | message(ERROR "Environment variable NSIGHT_AFTERMATH_SDK has to be provided") | 289 | message(FATAL_ERROR "Environment variable NSIGHT_AFTERMATH_SDK has to be provided") |
| 292 | endif() | 290 | endif() |
| 293 | if (NOT WIN32) | 291 | if (NOT WIN32) |
| 294 | message(ERROR "Nsight Aftermath doesn't support non-Windows platforms") | 292 | message(FATAL_ERROR "Nsight Aftermath doesn't support non-Windows platforms") |
| 295 | endif() | 293 | endif() |
| 296 | target_compile_definitions(video_core PRIVATE HAS_NSIGHT_AFTERMATH) | 294 | target_compile_definitions(video_core PRIVATE HAS_NSIGHT_AFTERMATH) |
| 297 | target_include_directories(video_core PRIVATE "$ENV{NSIGHT_AFTERMATH_SDK}/include") | 295 | target_include_directories(video_core PRIVATE "$ENV{NSIGHT_AFTERMATH_SDK}/include") |
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h index fd740c2c1..ee8602ce9 100644 --- a/src/video_core/buffer_cache/buffer_base.h +++ b/src/video_core/buffer_cache/buffer_base.h | |||
| @@ -446,7 +446,7 @@ private: | |||
| 446 | * @param offset Offset in bytes from the start of the buffer | 446 | * @param offset Offset in bytes from the start of the buffer |
| 447 | * @param size Size in bytes of the region to query for modifications | 447 | * @param size Size in bytes of the region to query for modifications |
| 448 | * | 448 | * |
| 449 | * @tparam True to query GPU modified pages, false for CPU pages | 449 | * @tparam gpu True to query GPU modified pages, false for CPU pages |
| 450 | */ | 450 | */ |
| 451 | template <bool gpu> | 451 | template <bool gpu> |
| 452 | [[nodiscard]] std::pair<u64, u64> ModifiedRegion(u64 offset, u64 size) const noexcept { | 452 | [[nodiscard]] std::pair<u64, u64> ModifiedRegion(u64 offset, u64 size) const noexcept { |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 9be651e24..116ad1722 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -179,22 +179,22 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume | |||
| 179 | return ProcessMacroBind(argument); | 179 | return ProcessMacroBind(argument); |
| 180 | case MAXWELL3D_REG_INDEX(firmware[4]): | 180 | case MAXWELL3D_REG_INDEX(firmware[4]): |
| 181 | return ProcessFirmwareCall4(); | 181 | return ProcessFirmwareCall4(); |
| 182 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): | 182 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data): |
| 183 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]): | 183 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 1: |
| 184 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]): | 184 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 2: |
| 185 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]): | 185 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 3: |
| 186 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]): | 186 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 4: |
| 187 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]): | 187 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 5: |
| 188 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]): | 188 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 6: |
| 189 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]): | 189 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 7: |
| 190 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]): | 190 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 8: |
| 191 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]): | 191 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 9: |
| 192 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]): | 192 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 10: |
| 193 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]): | 193 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 11: |
| 194 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]): | 194 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 12: |
| 195 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): | 195 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 13: |
| 196 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): | 196 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 14: |
| 197 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): | 197 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 15: |
| 198 | return StartCBData(method); | 198 | return StartCBData(method); |
| 199 | case MAXWELL3D_REG_INDEX(cb_bind[0]): | 199 | case MAXWELL3D_REG_INDEX(cb_bind[0]): |
| 200 | return ProcessCBBind(0); | 200 | return ProcessCBBind(0); |
| @@ -287,22 +287,22 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, | |||
| 287 | return; | 287 | return; |
| 288 | } | 288 | } |
| 289 | switch (method) { | 289 | switch (method) { |
| 290 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): | 290 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data): |
| 291 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]): | 291 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 1: |
| 292 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]): | 292 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 2: |
| 293 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]): | 293 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 3: |
| 294 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]): | 294 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 4: |
| 295 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]): | 295 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 5: |
| 296 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]): | 296 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 6: |
| 297 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]): | 297 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 7: |
| 298 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]): | 298 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 8: |
| 299 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]): | 299 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 9: |
| 300 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]): | 300 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 10: |
| 301 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]): | 301 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 11: |
| 302 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]): | 302 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 12: |
| 303 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): | 303 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 13: |
| 304 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): | 304 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 14: |
| 305 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): | 305 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data) + 15: |
| 306 | ProcessCBMultiData(method, base_start, amount); | 306 | ProcessCBMultiData(method, base_start, amount); |
| 307 | break; | 307 | break; |
| 308 | default: | 308 | default: |
| @@ -592,7 +592,7 @@ void Maxwell3D::ProcessCBData(u32 value) { | |||
| 592 | } | 592 | } |
| 593 | 593 | ||
| 594 | void Maxwell3D::StartCBData(u32 method) { | 594 | void Maxwell3D::StartCBData(u32 method) { |
| 595 | constexpr u32 first_cb_data = MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]); | 595 | constexpr u32 first_cb_data = MAXWELL3D_REG_INDEX(const_buffer.cb_data); |
| 596 | cb_data_state.start_pos = regs.const_buffer.cb_pos; | 596 | cb_data_state.start_pos = regs.const_buffer.cb_pos; |
| 597 | cb_data_state.id = method - first_cb_data; | 597 | cb_data_state.id = method - first_cb_data; |
| 598 | cb_data_state.current = method; | 598 | cb_data_state.current = method; |
| @@ -605,7 +605,7 @@ void Maxwell3D::ProcessCBMultiData(u32 method, const u32* start_base, u32 amount | |||
| 605 | if (cb_data_state.current != null_cb_data) { | 605 | if (cb_data_state.current != null_cb_data) { |
| 606 | FinishCBData(); | 606 | FinishCBData(); |
| 607 | } | 607 | } |
| 608 | constexpr u32 first_cb_data = MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]); | 608 | constexpr u32 first_cb_data = MAXWELL3D_REG_INDEX(const_buffer.cb_data); |
| 609 | cb_data_state.start_pos = regs.const_buffer.cb_pos; | 609 | cb_data_state.start_pos = regs.const_buffer.cb_pos; |
| 610 | cb_data_state.id = method - first_cb_data; | 610 | cb_data_state.id = method - first_cb_data; |
| 611 | cb_data_state.current = method; | 611 | cb_data_state.current = method; |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 326b32228..002d1b3f9 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -1337,7 +1337,7 @@ public: | |||
| 1337 | u32 cb_address_high; | 1337 | u32 cb_address_high; |
| 1338 | u32 cb_address_low; | 1338 | u32 cb_address_low; |
| 1339 | u32 cb_pos; | 1339 | u32 cb_pos; |
| 1340 | u32 cb_data[NumCBData]; | 1340 | std::array<u32, NumCBData> cb_data; |
| 1341 | 1341 | ||
| 1342 | GPUVAddr BufferAddress() const { | 1342 | GPUVAddr BufferAddress() const { |
| 1343 | return static_cast<GPUVAddr>( | 1343 | return static_cast<GPUVAddr>( |
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 4c7399d5a..28f2b8614 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -20,6 +20,7 @@ set(SHADER_FILES | |||
| 20 | find_program(GLSLANGVALIDATOR "glslangValidator" REQUIRED) | 20 | find_program(GLSLANGVALIDATOR "glslangValidator" REQUIRED) |
| 21 | 21 | ||
| 22 | set(GLSL_FLAGS "") | 22 | set(GLSL_FLAGS "") |
| 23 | set(QUIET_FLAG "--quiet") | ||
| 23 | 24 | ||
| 24 | set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include) | 25 | set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include) |
| 25 | set(SHADER_DIR ${SHADER_INCLUDE}/video_core/host_shaders) | 26 | set(SHADER_DIR ${SHADER_INCLUDE}/video_core/host_shaders) |
| @@ -28,6 +29,23 @@ set(HOST_SHADERS_INCLUDE ${SHADER_INCLUDE} PARENT_SCOPE) | |||
| 28 | set(INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/source_shader.h.in) | 29 | set(INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/source_shader.h.in) |
| 29 | set(HEADER_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/StringShaderHeader.cmake) | 30 | set(HEADER_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/StringShaderHeader.cmake) |
| 30 | 31 | ||
| 32 | # Check if `--quiet` is available on host's glslangValidator version | ||
| 33 | # glslangValidator prints to STDERR iff an unrecognized flag is passed to it | ||
| 34 | execute_process( | ||
| 35 | COMMAND | ||
| 36 | ${GLSLANGVALIDATOR} ${QUIET_FLAG} | ||
| 37 | ERROR_VARIABLE | ||
| 38 | GLSLANG_ERROR | ||
| 39 | # STDOUT variable defined to silence unnecessary output during CMake configuration | ||
| 40 | OUTPUT_VARIABLE | ||
| 41 | GLSLANG_OUTPUT | ||
| 42 | ) | ||
| 43 | |||
| 44 | if (NOT GLSLANG_ERROR STREQUAL "") | ||
| 45 | message(WARNING "Refusing to use unavailable flag `${QUIET_FLAG}` on `${GLSLANGVALIDATOR}`") | ||
| 46 | set(QUIET_FLAG "") | ||
| 47 | endif() | ||
| 48 | |||
| 31 | foreach(FILENAME IN ITEMS ${SHADER_FILES}) | 49 | foreach(FILENAME IN ITEMS ${SHADER_FILES}) |
| 32 | string(REPLACE "." "_" SHADER_NAME ${FILENAME}) | 50 | string(REPLACE "." "_" SHADER_NAME ${FILENAME}) |
| 33 | set(SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}) | 51 | set(SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}) |
| @@ -55,7 +73,7 @@ foreach(FILENAME IN ITEMS ${SHADER_FILES}) | |||
| 55 | OUTPUT | 73 | OUTPUT |
| 56 | ${SPIRV_HEADER_FILE} | 74 | ${SPIRV_HEADER_FILE} |
| 57 | COMMAND | 75 | COMMAND |
| 58 | ${GLSLANGVALIDATOR} -V ${GLSL_FLAGS} --variable-name ${SPIRV_VARIABLE_NAME} -o ${SPIRV_HEADER_FILE} ${SOURCE_FILE} | 76 | ${GLSLANGVALIDATOR} -V ${QUIET_FLAG} ${GLSL_FLAGS} --variable-name ${SPIRV_VARIABLE_NAME} -o ${SPIRV_HEADER_FILE} ${SOURCE_FILE} |
| 59 | MAIN_DEPENDENCY | 77 | MAIN_DEPENDENCY |
| 60 | ${SOURCE_FILE} | 78 | ${SOURCE_FILE} |
| 61 | ) | 79 | ) |
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 65feff588..c841f3cd7 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/alignment.h" | 5 | #include "common/alignment.h" |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/logging/log.h" | ||
| 7 | #include "core/core.h" | 8 | #include "core/core.h" |
| 8 | #include "core/hle/kernel/memory/page_table.h" | 9 | #include "core/hle/kernel/memory/page_table.h" |
| 9 | #include "core/hle/kernel/process.h" | 10 | #include "core/hle/kernel/process.h" |
| @@ -38,6 +39,12 @@ GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std | |||
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | GPUVAddr MemoryManager::Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size) { | 41 | GPUVAddr MemoryManager::Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size) { |
| 42 | const auto it = std::ranges::lower_bound(map_ranges, gpu_addr, {}, &MapRange::first); | ||
| 43 | if (it != map_ranges.end() && it->first == gpu_addr) { | ||
| 44 | it->second = size; | ||
| 45 | } else { | ||
| 46 | map_ranges.insert(it, MapRange{gpu_addr, size}); | ||
| 47 | } | ||
| 41 | return UpdateRange(gpu_addr, cpu_addr, size); | 48 | return UpdateRange(gpu_addr, cpu_addr, size); |
| 42 | } | 49 | } |
| 43 | 50 | ||
| @@ -52,10 +59,16 @@ GPUVAddr MemoryManager::MapAllocate32(VAddr cpu_addr, std::size_t size) { | |||
| 52 | } | 59 | } |
| 53 | 60 | ||
| 54 | void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) { | 61 | void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) { |
| 55 | if (!size) { | 62 | if (size == 0) { |
| 56 | return; | 63 | return; |
| 57 | } | 64 | } |
| 58 | 65 | const auto it = std::ranges::lower_bound(map_ranges, gpu_addr, {}, &MapRange::first); | |
| 66 | if (it != map_ranges.end()) { | ||
| 67 | ASSERT(it->first == gpu_addr); | ||
| 68 | map_ranges.erase(it); | ||
| 69 | } else { | ||
| 70 | UNREACHABLE_MSG("Unmapping non-existent GPU address=0x{:x}", gpu_addr); | ||
| 71 | } | ||
| 59 | // Flush and invalidate through the GPU interface, to be asynchronous if possible. | 72 | // Flush and invalidate through the GPU interface, to be asynchronous if possible. |
| 60 | const std::optional<VAddr> cpu_addr = GpuToCpuAddress(gpu_addr); | 73 | const std::optional<VAddr> cpu_addr = GpuToCpuAddress(gpu_addr); |
| 61 | ASSERT(cpu_addr); | 74 | ASSERT(cpu_addr); |
| @@ -218,6 +231,12 @@ const u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) const { | |||
| 218 | return system.Memory().GetPointer(*address); | 231 | return system.Memory().GetPointer(*address); |
| 219 | } | 232 | } |
| 220 | 233 | ||
| 234 | size_t MemoryManager::BytesToMapEnd(GPUVAddr gpu_addr) const noexcept { | ||
| 235 | auto it = std::ranges::upper_bound(map_ranges, gpu_addr, {}, &MapRange::first); | ||
| 236 | --it; | ||
| 237 | return it->second - (gpu_addr - it->first); | ||
| 238 | } | ||
| 239 | |||
| 221 | void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const { | 240 | void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const { |
| 222 | std::size_t remaining_size{size}; | 241 | std::size_t remaining_size{size}; |
| 223 | std::size_t page_index{gpu_src_addr >> page_bits}; | 242 | std::size_t page_index{gpu_src_addr >> page_bits}; |
| @@ -314,17 +333,29 @@ void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buf | |||
| 314 | } | 333 | } |
| 315 | } | 334 | } |
| 316 | 335 | ||
| 336 | void MemoryManager::FlushRegion(GPUVAddr gpu_addr, size_t size) const { | ||
| 337 | size_t remaining_size{size}; | ||
| 338 | size_t page_index{gpu_addr >> page_bits}; | ||
| 339 | size_t page_offset{gpu_addr & page_mask}; | ||
| 340 | while (remaining_size > 0) { | ||
| 341 | const size_t num_bytes{std::min(page_size - page_offset, remaining_size)}; | ||
| 342 | if (const auto page_addr{GpuToCpuAddress(page_index << page_bits)}; page_addr) { | ||
| 343 | rasterizer->FlushRegion(*page_addr + page_offset, num_bytes); | ||
| 344 | } | ||
| 345 | ++page_index; | ||
| 346 | page_offset = 0; | ||
| 347 | remaining_size -= num_bytes; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 317 | void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size) { | 351 | void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size) { |
| 318 | std::vector<u8> tmp_buffer(size); | 352 | std::vector<u8> tmp_buffer(size); |
| 319 | ReadBlock(gpu_src_addr, tmp_buffer.data(), size); | 353 | ReadBlock(gpu_src_addr, tmp_buffer.data(), size); |
| 320 | WriteBlock(gpu_dest_addr, tmp_buffer.data(), size); | ||
| 321 | } | ||
| 322 | 354 | ||
| 323 | void MemoryManager::CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, | 355 | // The output block must be flushed in case it has data modified from the GPU. |
| 324 | std::size_t size) { | 356 | // Fixes NPC geometry in Zombie Panic in Wonderland DX |
| 325 | std::vector<u8> tmp_buffer(size); | 357 | FlushRegion(gpu_dest_addr, size); |
| 326 | ReadBlockUnsafe(gpu_src_addr, tmp_buffer.data(), size); | 358 | WriteBlock(gpu_dest_addr, tmp_buffer.data(), size); |
| 327 | WriteBlockUnsafe(gpu_dest_addr, tmp_buffer.data(), size); | ||
| 328 | } | 359 | } |
| 329 | 360 | ||
| 330 | bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { | 361 | bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { |
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index c35e57689..b468a67de 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h | |||
| @@ -85,6 +85,9 @@ public: | |||
| 85 | [[nodiscard]] u8* GetPointer(GPUVAddr addr); | 85 | [[nodiscard]] u8* GetPointer(GPUVAddr addr); |
| 86 | [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const; | 86 | [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const; |
| 87 | 87 | ||
| 88 | /// Returns the number of bytes until the end of the memory map containing the given GPU address | ||
| 89 | [[nodiscard]] size_t BytesToMapEnd(GPUVAddr gpu_addr) const noexcept; | ||
| 90 | |||
| 88 | /** | 91 | /** |
| 89 | * ReadBlock and WriteBlock are full read and write operations over virtual | 92 | * ReadBlock and WriteBlock are full read and write operations over virtual |
| 90 | * GPU Memory. It's important to use these when GPU memory may not be continuous | 93 | * GPU Memory. It's important to use these when GPU memory may not be continuous |
| @@ -107,7 +110,6 @@ public: | |||
| 107 | */ | 110 | */ |
| 108 | void ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const; | 111 | void ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const; |
| 109 | void WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size); | 112 | void WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size); |
| 110 | void CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size); | ||
| 111 | 113 | ||
| 112 | /** | 114 | /** |
| 113 | * IsGranularRange checks if a gpu region can be simply read with a pointer. | 115 | * IsGranularRange checks if a gpu region can be simply read with a pointer. |
| @@ -131,6 +133,8 @@ private: | |||
| 131 | void TryLockPage(PageEntry page_entry, std::size_t size); | 133 | void TryLockPage(PageEntry page_entry, std::size_t size); |
| 132 | void TryUnlockPage(PageEntry page_entry, std::size_t size); | 134 | void TryUnlockPage(PageEntry page_entry, std::size_t size); |
| 133 | 135 | ||
| 136 | void FlushRegion(GPUVAddr gpu_addr, size_t size) const; | ||
| 137 | |||
| 134 | [[nodiscard]] static constexpr std::size_t PageEntryIndex(GPUVAddr gpu_addr) { | 138 | [[nodiscard]] static constexpr std::size_t PageEntryIndex(GPUVAddr gpu_addr) { |
| 135 | return (gpu_addr >> page_bits) & page_table_mask; | 139 | return (gpu_addr >> page_bits) & page_table_mask; |
| 136 | } | 140 | } |
| @@ -150,6 +154,9 @@ private: | |||
| 150 | VideoCore::RasterizerInterface* rasterizer = nullptr; | 154 | VideoCore::RasterizerInterface* rasterizer = nullptr; |
| 151 | 155 | ||
| 152 | std::vector<PageEntry> page_table; | 156 | std::vector<PageEntry> page_table; |
| 157 | |||
| 158 | using MapRange = std::pair<GPUVAddr, size_t>; | ||
| 159 | std::vector<MapRange> map_ranges; | ||
| 153 | }; | 160 | }; |
| 154 | 161 | ||
| 155 | } // namespace Tegra | 162 | } // namespace Tegra |
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp deleted file mode 100644 index e69de29bb..000000000 --- a/src/video_core/morton.cpp +++ /dev/null | |||
diff --git a/src/video_core/morton.h b/src/video_core/morton.h deleted file mode 100644 index e69de29bb..000000000 --- a/src/video_core/morton.h +++ /dev/null | |||
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 81b71edfb..04c267ee4 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -246,6 +246,7 @@ Device::Device() | |||
| 246 | GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2; | 246 | GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2; |
| 247 | 247 | ||
| 248 | use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); | 248 | use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); |
| 249 | use_driver_cache = is_nvidia; | ||
| 249 | 250 | ||
| 250 | LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); | 251 | LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); |
| 251 | LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug); | 252 | LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug); |
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 3e79d1e37..9141de635 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -120,6 +120,10 @@ public: | |||
| 120 | return use_asynchronous_shaders; | 120 | return use_asynchronous_shaders; |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | bool UseDriverCache() const { | ||
| 124 | return use_driver_cache; | ||
| 125 | } | ||
| 126 | |||
| 123 | private: | 127 | private: |
| 124 | static bool TestVariableAoffi(); | 128 | static bool TestVariableAoffi(); |
| 125 | static bool TestPreciseBug(); | 129 | static bool TestPreciseBug(); |
| @@ -147,6 +151,7 @@ private: | |||
| 147 | bool has_debugging_tool_attached{}; | 151 | bool has_debugging_tool_attached{}; |
| 148 | bool use_assembly_shaders{}; | 152 | bool use_assembly_shaders{}; |
| 149 | bool use_asynchronous_shaders{}; | 153 | bool use_asynchronous_shaders{}; |
| 154 | bool use_driver_cache{}; | ||
| 150 | }; | 155 | }; |
| 151 | 156 | ||
| 152 | } // namespace OpenGL | 157 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index d4841fdb7..529570ff0 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -159,6 +159,10 @@ std::unordered_set<GLenum> GetSupportedFormats() { | |||
| 159 | 159 | ||
| 160 | ProgramSharedPtr BuildShader(const Device& device, ShaderType shader_type, u64 unique_identifier, | 160 | ProgramSharedPtr BuildShader(const Device& device, ShaderType shader_type, u64 unique_identifier, |
| 161 | const ShaderIR& ir, const Registry& registry, bool hint_retrievable) { | 161 | const ShaderIR& ir, const Registry& registry, bool hint_retrievable) { |
| 162 | if (device.UseDriverCache()) { | ||
| 163 | // Ignore hint retrievable if we are using the driver cache | ||
| 164 | hint_retrievable = false; | ||
| 165 | } | ||
| 162 | const std::string shader_id = MakeShaderID(unique_identifier, shader_type); | 166 | const std::string shader_id = MakeShaderID(unique_identifier, shader_type); |
| 163 | LOG_INFO(Render_OpenGL, "{}", shader_id); | 167 | LOG_INFO(Render_OpenGL, "{}", shader_id); |
| 164 | 168 | ||
| @@ -336,7 +340,7 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop | |||
| 336 | } | 340 | } |
| 337 | 341 | ||
| 338 | std::vector<ShaderDiskCachePrecompiled> gl_cache; | 342 | std::vector<ShaderDiskCachePrecompiled> gl_cache; |
| 339 | if (!device.UseAssemblyShaders()) { | 343 | if (!device.UseAssemblyShaders() && !device.UseDriverCache()) { |
| 340 | // Only load precompiled cache when we are not using assembly shaders | 344 | // Only load precompiled cache when we are not using assembly shaders |
| 341 | gl_cache = disk_cache.LoadPrecompiled(); | 345 | gl_cache = disk_cache.LoadPrecompiled(); |
| 342 | } | 346 | } |
| @@ -356,8 +360,7 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop | |||
| 356 | std::atomic_bool gl_cache_failed = false; | 360 | std::atomic_bool gl_cache_failed = false; |
| 357 | 361 | ||
| 358 | const auto find_precompiled = [&gl_cache](u64 id) { | 362 | const auto find_precompiled = [&gl_cache](u64 id) { |
| 359 | return std::find_if(gl_cache.begin(), gl_cache.end(), | 363 | return std::ranges::find(gl_cache, id, &ShaderDiskCachePrecompiled::unique_identifier); |
| 360 | [id](const auto& entry) { return entry.unique_identifier == id; }); | ||
| 361 | }; | 364 | }; |
| 362 | 365 | ||
| 363 | const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, | 366 | const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, |
| @@ -432,8 +435,8 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop | |||
| 432 | return; | 435 | return; |
| 433 | } | 436 | } |
| 434 | 437 | ||
| 435 | if (device.UseAssemblyShaders()) { | 438 | if (device.UseAssemblyShaders() || device.UseDriverCache()) { |
| 436 | // Don't store precompiled binaries for assembly shaders. | 439 | // Don't store precompiled binaries for assembly shaders or when using the driver cache |
| 437 | return; | 440 | return; |
| 438 | } | 441 | } |
| 439 | 442 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 2e1fa252d..c35b71b6b 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "common/alignment.h" | 14 | #include "common/alignment.h" |
| 15 | #include "common/assert.h" | 15 | #include "common/assert.h" |
| 16 | #include "common/common_types.h" | 16 | #include "common/common_types.h" |
| 17 | #include "common/div_ceil.h" | ||
| 17 | #include "common/logging/log.h" | 18 | #include "common/logging/log.h" |
| 18 | #include "video_core/engines/maxwell_3d.h" | 19 | #include "video_core/engines/maxwell_3d.h" |
| 19 | #include "video_core/engines/shader_type.h" | 20 | #include "video_core/engines/shader_type.h" |
| @@ -877,7 +878,7 @@ private: | |||
| 877 | 878 | ||
| 878 | u32 binding = device.GetBaseBindings(stage).uniform_buffer; | 879 | u32 binding = device.GetBaseBindings(stage).uniform_buffer; |
| 879 | for (const auto& [index, info] : ir.GetConstantBuffers()) { | 880 | for (const auto& [index, info] : ir.GetConstantBuffers()) { |
| 880 | const u32 num_elements = Common::AlignUp(info.GetSize(), 4) / 4; | 881 | const u32 num_elements = Common::DivCeil(info.GetSize(), 4 * sizeof(u32)); |
| 881 | const u32 size = info.IsIndirect() ? MAX_CONSTBUFFER_ELEMENTS : num_elements; | 882 | const u32 size = info.IsIndirect() ? MAX_CONSTBUFFER_ELEMENTS : num_elements; |
| 882 | code.AddLine("layout (std140, binding = {}) uniform {} {{", binding++, | 883 | code.AddLine("layout (std140, binding = {}) uniform {} {{", binding++, |
| 883 | GetConstBufferBlock(index)); | 884 | GetConstBufferBlock(index)); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index dd77a543c..21159e498 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -506,7 +506,7 @@ bool RendererOpenGL::Init() { | |||
| 506 | 506 | ||
| 507 | AddTelemetryFields(); | 507 | AddTelemetryFields(); |
| 508 | 508 | ||
| 509 | if (!GLAD_GL_VERSION_4_3) { | 509 | if (!GLAD_GL_VERSION_4_6) { |
| 510 | return false; | 510 | return false; |
| 511 | } | 511 | } |
| 512 | 512 | ||
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index ca7c2c579..85121d9fd 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -110,8 +110,8 @@ VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_ | |||
| 110 | } // namespace Sampler | 110 | } // namespace Sampler |
| 111 | 111 | ||
| 112 | namespace { | 112 | namespace { |
| 113 | 113 | constexpr u32 Attachable = 1 << 0; | |
| 114 | enum : u32 { Attachable = 1, Storage = 2 }; | 114 | constexpr u32 Storage = 1 << 1; |
| 115 | 115 | ||
| 116 | struct FormatTuple { | 116 | struct FormatTuple { |
| 117 | VkFormat format; ///< Vulkan format | 117 | VkFormat format; ///< Vulkan format |
| @@ -222,22 +222,27 @@ constexpr bool IsZetaFormat(PixelFormat pixel_format) { | |||
| 222 | 222 | ||
| 223 | } // Anonymous namespace | 223 | } // Anonymous namespace |
| 224 | 224 | ||
| 225 | FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format) { | 225 | FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with_srgb, |
| 226 | ASSERT(static_cast<std::size_t>(pixel_format) < std::size(tex_format_tuples)); | 226 | PixelFormat pixel_format) { |
| 227 | 227 | ASSERT(static_cast<size_t>(pixel_format) < std::size(tex_format_tuples)); | |
| 228 | auto tuple = tex_format_tuples[static_cast<std::size_t>(pixel_format)]; | 228 | FormatTuple tuple = tex_format_tuples[static_cast<size_t>(pixel_format)]; |
| 229 | if (tuple.format == VK_FORMAT_UNDEFINED) { | 229 | if (tuple.format == VK_FORMAT_UNDEFINED) { |
| 230 | UNIMPLEMENTED_MSG("Unimplemented texture format with pixel format={}", pixel_format); | 230 | UNIMPLEMENTED_MSG("Unimplemented texture format with pixel format={}", pixel_format); |
| 231 | return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; | 231 | return FormatInfo{VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively | 234 | // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively |
| 235 | if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { | 235 | if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { |
| 236 | const bool is_srgb = VideoCore::Surface::IsPixelFormatSRGB(pixel_format); | 236 | const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format); |
| 237 | tuple.format = is_srgb ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 : VK_FORMAT_A8B8G8R8_UNORM_PACK32; | 237 | if (is_srgb) { |
| 238 | tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32; | ||
| 239 | } else { | ||
| 240 | tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 241 | tuple.usage |= Storage; | ||
| 242 | } | ||
| 238 | } | 243 | } |
| 239 | const bool attachable = tuple.usage & Attachable; | 244 | const bool attachable = (tuple.usage & Attachable) != 0; |
| 240 | const bool storage = tuple.usage & Storage; | 245 | const bool storage = (tuple.usage & Storage) != 0; |
| 241 | 246 | ||
| 242 | VkFormatFeatureFlags usage{}; | 247 | VkFormatFeatureFlags usage{}; |
| 243 | switch (format_type) { | 248 | switch (format_type) { |
| @@ -671,7 +676,7 @@ VkFrontFace FrontFace(Maxwell::FrontFace front_face) { | |||
| 671 | return {}; | 676 | return {}; |
| 672 | } | 677 | } |
| 673 | 678 | ||
| 674 | VkCullModeFlags CullFace(Maxwell::CullFace cull_face) { | 679 | VkCullModeFlagBits CullFace(Maxwell::CullFace cull_face) { |
| 675 | switch (cull_face) { | 680 | switch (cull_face) { |
| 676 | case Maxwell::CullFace::Front: | 681 | case Maxwell::CullFace::Front: |
| 677 | return VK_CULL_MODE_FRONT_BIT; | 682 | return VK_CULL_MODE_FRONT_BIT; |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h index 537969840..7c34b47dc 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.h +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h | |||
| @@ -35,7 +35,15 @@ struct FormatInfo { | |||
| 35 | bool storage; | 35 | bool storage; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format); | 38 | /** |
| 39 | * Returns format properties supported in the host | ||
| 40 | * @param device Host device | ||
| 41 | * @param format_type Type of image the buffer will use | ||
| 42 | * @param with_srgb True when the format can be sRGB when converted to another format (ASTC) | ||
| 43 | * @param pixel_format Guest pixel format to describe | ||
| 44 | */ | ||
| 45 | [[nodiscard]] FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with_srgb, | ||
| 46 | PixelFormat pixel_format); | ||
| 39 | 47 | ||
| 40 | VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage); | 48 | VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage); |
| 41 | 49 | ||
| @@ -55,7 +63,7 @@ VkBlendFactor BlendFactor(Maxwell::Blend::Factor factor); | |||
| 55 | 63 | ||
| 56 | VkFrontFace FrontFace(Maxwell::FrontFace front_face); | 64 | VkFrontFace FrontFace(Maxwell::FrontFace front_face); |
| 57 | 65 | ||
| 58 | VkCullModeFlags CullFace(Maxwell::CullFace cull_face); | 66 | VkCullModeFlagBits CullFace(Maxwell::CullFace cull_face); |
| 59 | 67 | ||
| 60 | VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle); | 68 | VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle); |
| 61 | 69 | ||
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index a5214d0bc..d50dca604 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -181,6 +181,7 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( | |||
| 181 | .pNext = nullptr, | 181 | .pNext = nullptr, |
| 182 | .flags = 0, | 182 | .flags = 0, |
| 183 | .codeSize = 0, | 183 | .codeSize = 0, |
| 184 | .pCode = nullptr, | ||
| 184 | }; | 185 | }; |
| 185 | 186 | ||
| 186 | std::vector<vk::ShaderModule> shader_modules; | 187 | std::vector<vk::ShaderModule> shader_modules; |
| @@ -326,8 +327,8 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const SPIRVProgram& program, | |||
| 326 | .rasterizerDiscardEnable = | 327 | .rasterizerDiscardEnable = |
| 327 | static_cast<VkBool32>(state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), | 328 | static_cast<VkBool32>(state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), |
| 328 | .polygonMode = VK_POLYGON_MODE_FILL, | 329 | .polygonMode = VK_POLYGON_MODE_FILL, |
| 329 | .cullMode = | 330 | .cullMode = static_cast<VkCullModeFlags>( |
| 330 | dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE, | 331 | dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE), |
| 331 | .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), | 332 | .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), |
| 332 | .depthBiasEnable = state.depth_bias_enable, | 333 | .depthBiasEnable = state.depth_bias_enable, |
| 333 | .depthBiasConstantFactor = 0.0f, | 334 | .depthBiasConstantFactor = 0.0f, |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 02282e36f..8991505ca 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -355,14 +355,12 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { | |||
| 355 | SPIRVProgram program; | 355 | SPIRVProgram program; |
| 356 | std::vector<VkDescriptorSetLayoutBinding> bindings; | 356 | std::vector<VkDescriptorSetLayoutBinding> bindings; |
| 357 | 357 | ||
| 358 | for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | 358 | for (std::size_t index = 1; index < Maxwell::MaxShaderProgram; ++index) { |
| 359 | const auto program_enum = static_cast<Maxwell::ShaderProgram>(index); | 359 | const auto program_enum = static_cast<Maxwell::ShaderProgram>(index); |
| 360 | |||
| 361 | // Skip stages that are not enabled | 360 | // Skip stages that are not enabled |
| 362 | if (!maxwell3d.regs.IsShaderConfigEnabled(index)) { | 361 | if (!maxwell3d.regs.IsShaderConfigEnabled(index)) { |
| 363 | continue; | 362 | continue; |
| 364 | } | 363 | } |
| 365 | |||
| 366 | const GPUVAddr gpu_addr = GetShaderAddress(maxwell3d, program_enum); | 364 | const GPUVAddr gpu_addr = GetShaderAddress(maxwell3d, program_enum); |
| 367 | const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr); | 365 | const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr); |
| 368 | Shader* const shader = cpu_addr ? TryGet(*cpu_addr) : null_shader.get(); | 366 | Shader* const shader = cpu_addr ? TryGet(*cpu_addr) : null_shader.get(); |
| @@ -372,12 +370,8 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { | |||
| 372 | const auto& entries = shader->GetEntries(); | 370 | const auto& entries = shader->GetEntries(); |
| 373 | program[stage] = { | 371 | program[stage] = { |
| 374 | Decompile(device, shader->GetIR(), program_type, shader->GetRegistry(), specialization), | 372 | Decompile(device, shader->GetIR(), program_type, shader->GetRegistry(), specialization), |
| 375 | entries}; | 373 | entries, |
| 376 | 374 | }; | |
| 377 | if (program_enum == Maxwell::ShaderProgram::VertexA) { | ||
| 378 | // VertexB was combined with VertexA, so we skip the VertexB iteration | ||
| 379 | ++index; | ||
| 380 | } | ||
| 381 | 375 | ||
| 382 | const u32 old_binding = specialization.base_binding; | 376 | const u32 old_binding = specialization.base_binding; |
| 383 | specialization.base_binding = | 377 | specialization.base_binding = |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 4cd43e425..15f2987eb 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h | |||
| @@ -6,10 +6,12 @@ | |||
| 6 | 6 | ||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <condition_variable> | 8 | #include <condition_variable> |
| 9 | #include <cstddef> | ||
| 9 | #include <memory> | 10 | #include <memory> |
| 10 | #include <stack> | 11 | #include <stack> |
| 11 | #include <thread> | 12 | #include <thread> |
| 12 | #include <utility> | 13 | #include <utility> |
| 14 | #include "common/alignment.h" | ||
| 13 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 14 | #include "common/threadsafe_queue.h" | 16 | #include "common/threadsafe_queue.h" |
| 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 17 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| @@ -130,12 +132,11 @@ private: | |||
| 130 | using FuncType = TypedCommand<T>; | 132 | using FuncType = TypedCommand<T>; |
| 131 | static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large"); | 133 | static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large"); |
| 132 | 134 | ||
| 135 | command_offset = Common::AlignUp(command_offset, alignof(FuncType)); | ||
| 133 | if (command_offset > sizeof(data) - sizeof(FuncType)) { | 136 | if (command_offset > sizeof(data) - sizeof(FuncType)) { |
| 134 | return false; | 137 | return false; |
| 135 | } | 138 | } |
| 136 | 139 | Command* const current_last = last; | |
| 137 | Command* current_last = last; | ||
| 138 | |||
| 139 | last = new (data.data() + command_offset) FuncType(std::move(command)); | 140 | last = new (data.data() + command_offset) FuncType(std::move(command)); |
| 140 | 141 | ||
| 141 | if (current_last) { | 142 | if (current_last) { |
| @@ -143,7 +144,6 @@ private: | |||
| 143 | } else { | 144 | } else { |
| 144 | first = last; | 145 | first = last; |
| 145 | } | 146 | } |
| 146 | |||
| 147 | command_offset += sizeof(FuncType); | 147 | command_offset += sizeof(FuncType); |
| 148 | return true; | 148 | return true; |
| 149 | } | 149 | } |
| @@ -156,8 +156,8 @@ private: | |||
| 156 | Command* first = nullptr; | 156 | Command* first = nullptr; |
| 157 | Command* last = nullptr; | 157 | Command* last = nullptr; |
| 158 | 158 | ||
| 159 | std::size_t command_offset = 0; | 159 | size_t command_offset = 0; |
| 160 | std::array<u8, 0x8000> data{}; | 160 | alignas(std::max_align_t) std::array<u8, 0x8000> data{}; |
| 161 | }; | 161 | }; |
| 162 | 162 | ||
| 163 | struct State { | 163 | struct State { |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 89cbe01ad..61d52b961 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -1334,7 +1334,10 @@ private: | |||
| 1334 | } | 1334 | } |
| 1335 | 1335 | ||
| 1336 | if (const auto comment = std::get_if<CommentNode>(&*node)) { | 1336 | if (const auto comment = std::get_if<CommentNode>(&*node)) { |
| 1337 | Name(OpUndef(t_void), comment->GetText()); | 1337 | if (device.HasDebuggingToolAttached()) { |
| 1338 | // We should insert comments with OpString instead of using named variables | ||
| 1339 | Name(OpUndef(t_int), comment->GetText()); | ||
| 1340 | } | ||
| 1338 | return {}; | 1341 | return {}; |
| 1339 | } | 1342 | } |
| 1340 | 1343 | ||
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index ab14922d7..aa7c5d7c6 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -95,20 +95,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 95 | } | 95 | } |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) { | 98 | [[nodiscard]] VkImageUsageFlags ImageUsageFlags(const MaxwellToVK::FormatInfo& info, |
| 99 | const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, info.format); | 99 | PixelFormat format) { |
| 100 | VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; | ||
| 101 | if (info.type == ImageType::e2D && info.resources.layers >= 6 && | ||
| 102 | info.size.width == info.size.height) { | ||
| 103 | flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; | ||
| 104 | } | ||
| 105 | if (info.type == ImageType::e3D) { | ||
| 106 | flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; | ||
| 107 | } | ||
| 108 | VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | | 100 | VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| 109 | VK_IMAGE_USAGE_SAMPLED_BIT; | 101 | VK_IMAGE_USAGE_SAMPLED_BIT; |
| 110 | if (format_info.attachable) { | 102 | if (info.attachable) { |
| 111 | switch (VideoCore::Surface::GetFormatType(info.format)) { | 103 | switch (VideoCore::Surface::GetFormatType(format)) { |
| 112 | case VideoCore::Surface::SurfaceType::ColorTexture: | 104 | case VideoCore::Surface::SurfaceType::ColorTexture: |
| 113 | usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; | 105 | usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
| 114 | break; | 106 | break; |
| @@ -120,9 +112,33 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 120 | UNREACHABLE_MSG("Invalid surface type"); | 112 | UNREACHABLE_MSG("Invalid surface type"); |
| 121 | } | 113 | } |
| 122 | } | 114 | } |
| 123 | if (format_info.storage) { | 115 | if (info.storage) { |
| 124 | usage |= VK_IMAGE_USAGE_STORAGE_BIT; | 116 | usage |= VK_IMAGE_USAGE_STORAGE_BIT; |
| 125 | } | 117 | } |
| 118 | return usage; | ||
| 119 | } | ||
| 120 | |||
| 121 | /// Returns the preferred format for a VkImage | ||
| 122 | [[nodiscard]] PixelFormat StorageFormat(PixelFormat format) { | ||
| 123 | switch (format) { | ||
| 124 | case PixelFormat::A8B8G8R8_SRGB: | ||
| 125 | return PixelFormat::A8B8G8R8_UNORM; | ||
| 126 | default: | ||
| 127 | return format; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) { | ||
| 132 | const PixelFormat format = StorageFormat(info.format); | ||
| 133 | const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format); | ||
| 134 | VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; | ||
| 135 | if (info.type == ImageType::e2D && info.resources.layers >= 6 && | ||
| 136 | info.size.width == info.size.height) { | ||
| 137 | flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; | ||
| 138 | } | ||
| 139 | if (info.type == ImageType::e3D) { | ||
| 140 | flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; | ||
| 141 | } | ||
| 126 | const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples); | 142 | const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples); |
| 127 | return VkImageCreateInfo{ | 143 | return VkImageCreateInfo{ |
| 128 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 144 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| @@ -130,17 +146,16 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 130 | .flags = flags, | 146 | .flags = flags, |
| 131 | .imageType = ConvertImageType(info.type), | 147 | .imageType = ConvertImageType(info.type), |
| 132 | .format = format_info.format, | 148 | .format = format_info.format, |
| 133 | .extent = | 149 | .extent{ |
| 134 | { | 150 | .width = info.size.width >> samples_x, |
| 135 | .width = info.size.width >> samples_x, | 151 | .height = info.size.height >> samples_y, |
| 136 | .height = info.size.height >> samples_y, | 152 | .depth = info.size.depth, |
| 137 | .depth = info.size.depth, | 153 | }, |
| 138 | }, | ||
| 139 | .mipLevels = static_cast<u32>(info.resources.levels), | 154 | .mipLevels = static_cast<u32>(info.resources.levels), |
| 140 | .arrayLayers = static_cast<u32>(info.resources.layers), | 155 | .arrayLayers = static_cast<u32>(info.resources.layers), |
| 141 | .samples = ConvertSampleCount(info.num_samples), | 156 | .samples = ConvertSampleCount(info.num_samples), |
| 142 | .tiling = VK_IMAGE_TILING_OPTIMAL, | 157 | .tiling = VK_IMAGE_TILING_OPTIMAL, |
| 143 | .usage = usage, | 158 | .usage = ImageUsageFlags(format_info, format), |
| 144 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 159 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 145 | .queueFamilyIndexCount = 0, | 160 | .queueFamilyIndexCount = 0, |
| 146 | .pQueueFamilyIndices = nullptr, | 161 | .pQueueFamilyIndices = nullptr, |
| @@ -209,10 +224,11 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 209 | 224 | ||
| 210 | [[nodiscard]] VkAttachmentDescription AttachmentDescription(const Device& device, | 225 | [[nodiscard]] VkAttachmentDescription AttachmentDescription(const Device& device, |
| 211 | const ImageView* image_view) { | 226 | const ImageView* image_view) { |
| 212 | const auto pixel_format = image_view->format; | 227 | using MaxwellToVK::SurfaceFormat; |
| 228 | const PixelFormat pixel_format = image_view->format; | ||
| 213 | return VkAttachmentDescription{ | 229 | return VkAttachmentDescription{ |
| 214 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, | 230 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, |
| 215 | .format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format).format, | 231 | .format = SurfaceFormat(device, FormatType::Optimal, true, pixel_format).format, |
| 216 | .samples = image_view->Samples(), | 232 | .samples = image_view->Samples(), |
| 217 | .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | 233 | .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, |
| 218 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | 234 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, |
| @@ -868,11 +884,16 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI | |||
| 868 | std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); | 884 | std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); |
| 869 | } | 885 | } |
| 870 | } | 886 | } |
| 871 | const VkFormat vk_format = | 887 | const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format); |
| 872 | MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format; | 888 | const VkFormat vk_format = format_info.format; |
| 889 | const VkImageViewUsageCreateInfo image_view_usage{ | ||
| 890 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, | ||
| 891 | .pNext = nullptr, | ||
| 892 | .usage = ImageUsageFlags(format_info, format), | ||
| 893 | }; | ||
| 873 | const VkImageViewCreateInfo create_info{ | 894 | const VkImageViewCreateInfo create_info{ |
| 874 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 895 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 875 | .pNext = nullptr, | 896 | .pNext = &image_view_usage, |
| 876 | .flags = 0, | 897 | .flags = 0, |
| 877 | .image = image.Handle(), | 898 | .image = image.Handle(), |
| 878 | .viewType = VkImageViewType{}, | 899 | .viewType = VkImageViewType{}, |
| @@ -962,7 +983,7 @@ vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) { | |||
| 962 | .flags = 0, | 983 | .flags = 0, |
| 963 | .image = image_handle, | 984 | .image = image_handle, |
| 964 | .viewType = ImageViewType(type), | 985 | .viewType = ImageViewType(type), |
| 965 | .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format, | 986 | .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format).format, |
| 966 | .components{ | 987 | .components{ |
| 967 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | 988 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, |
| 968 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | 989 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index a55d405d1..8d29361a1 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -72,7 +72,7 @@ struct TextureCacheRuntime { | |||
| 72 | MemoryAllocator& memory_allocator; | 72 | MemoryAllocator& memory_allocator; |
| 73 | StagingBufferPool& staging_buffer_pool; | 73 | StagingBufferPool& staging_buffer_pool; |
| 74 | BlitImageHelper& blit_image_helper; | 74 | BlitImageHelper& blit_image_helper; |
| 75 | std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache; | 75 | std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache{}; |
| 76 | 76 | ||
| 77 | void Finish(); | 77 | void Finish(); |
| 78 | 78 | ||
diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp index 9707136e9..3b40db9bc 100644 --- a/src/video_core/shader/async_shaders.cpp +++ b/src/video_core/shader/async_shaders.cpp | |||
| @@ -129,6 +129,15 @@ void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device, | |||
| 129 | .compiler_settings = compiler_settings, | 129 | .compiler_settings = compiler_settings, |
| 130 | .registry = registry, | 130 | .registry = registry, |
| 131 | .cpu_address = cpu_addr, | 131 | .cpu_address = cpu_addr, |
| 132 | .pp_cache = nullptr, | ||
| 133 | .vk_device = nullptr, | ||
| 134 | .scheduler = nullptr, | ||
| 135 | .descriptor_pool = nullptr, | ||
| 136 | .update_descriptor_queue = nullptr, | ||
| 137 | .bindings{}, | ||
| 138 | .program{}, | ||
| 139 | .key{}, | ||
| 140 | .num_color_buffers = 0, | ||
| 132 | }); | 141 | }); |
| 133 | cv.notify_one(); | 142 | cv.notify_one(); |
| 134 | } | 143 | } |
| @@ -143,6 +152,15 @@ void AsyncShaders::QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, | |||
| 143 | std::unique_lock lock(queue_mutex); | 152 | std::unique_lock lock(queue_mutex); |
| 144 | pending_queue.push({ | 153 | pending_queue.push({ |
| 145 | .backend = Backend::Vulkan, | 154 | .backend = Backend::Vulkan, |
| 155 | .device = nullptr, | ||
| 156 | .shader_type{}, | ||
| 157 | .uid = 0, | ||
| 158 | .code{}, | ||
| 159 | .code_b{}, | ||
| 160 | .main_offset = 0, | ||
| 161 | .compiler_settings{}, | ||
| 162 | .registry{}, | ||
| 163 | .cpu_address = 0, | ||
| 146 | .pp_cache = pp_cache, | 164 | .pp_cache = pp_cache, |
| 147 | .vk_device = &device, | 165 | .vk_device = &device, |
| 148 | .scheduler = &scheduler, | 166 | .scheduler = &scheduler, |
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index ce8fcfe0a..bb2cdef81 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -679,7 +679,7 @@ u32 CalculateLayerSize(const ImageInfo& info) noexcept { | |||
| 679 | } | 679 | } |
| 680 | 680 | ||
| 681 | std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets(const ImageInfo& info) noexcept { | 681 | std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets(const ImageInfo& info) noexcept { |
| 682 | ASSERT(info.resources.levels <= MAX_MIP_LEVELS); | 682 | ASSERT(info.resources.levels <= static_cast<s32>(MAX_MIP_LEVELS)); |
| 683 | const LevelInfo level_info = MakeLevelInfo(info); | 683 | const LevelInfo level_info = MakeLevelInfo(info); |
| 684 | std::array<u32, MAX_MIP_LEVELS> offsets{}; | 684 | std::array<u32, MAX_MIP_LEVELS> offsets{}; |
| 685 | u32 offset = 0; | 685 | u32 offset = 0; |
| @@ -1193,25 +1193,35 @@ u32 MapSizeBytes(const ImageBase& image) { | |||
| 1193 | } | 1193 | } |
| 1194 | } | 1194 | } |
| 1195 | 1195 | ||
| 1196 | using P = PixelFormat; | 1196 | static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0}, 0) == |
| 1197 | 1197 | 0x7f8000); | |
| 1198 | static_assert(CalculateLevelSize(LevelInfo{{1920, 1080}, {0, 2, 0}, {1, 1}, 2, 0}, 0) == 0x7f8000); | 1198 | static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x4000); |
| 1199 | static_assert(CalculateLevelSize(LevelInfo{{32, 32}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x4000); | 1199 | |
| 1200 | 1200 | static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 1, 0, 7) == | |
| 1201 | static_assert(CalculateLevelOffset(P::R8_SINT, {1920, 1080}, {0, 2}, 1, 0, 7) == 0x2afc00); | 1201 | 0x2afc00); |
| 1202 | static_assert(CalculateLevelOffset(P::ASTC_2D_12X12_UNORM, {8192, 4096}, {0, 2}, 1, 0, 12) == | 1202 | static_assert(CalculateLevelOffset(PixelFormat::ASTC_2D_12X12_UNORM, {8192, 4096, 1}, {0, 2, 0}, 1, |
| 1203 | 0x50d200); | 1203 | 0, 12) == 0x50d200); |
| 1204 | 1204 | ||
| 1205 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 0) == 0); | 1205 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, |
| 1206 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 1) == 0x400000); | 1206 | 0) == 0); |
| 1207 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 2) == 0x500000); | 1207 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, |
| 1208 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 3) == 0x540000); | 1208 | 1) == 0x400000); |
| 1209 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 4) == 0x550000); | 1209 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, |
| 1210 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 5) == 0x554000); | 1210 | 2) == 0x500000); |
| 1211 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 6) == 0x555000); | 1211 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, |
| 1212 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 7) == 0x555400); | 1212 | 3) == 0x540000); |
| 1213 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 8) == 0x555600); | 1213 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, |
| 1214 | static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 9) == 0x555800); | 1214 | 4) == 0x550000); |
| 1215 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, | ||
| 1216 | 5) == 0x554000); | ||
| 1217 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, | ||
| 1218 | 6) == 0x555000); | ||
| 1219 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, | ||
| 1220 | 7) == 0x555400); | ||
| 1221 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, | ||
| 1222 | 8) == 0x555600); | ||
| 1223 | static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0, | ||
| 1224 | 9) == 0x555800); | ||
| 1215 | 1225 | ||
| 1216 | constexpr u32 ValidateLayerSize(PixelFormat format, u32 width, u32 height, u32 block_height, | 1226 | constexpr u32 ValidateLayerSize(PixelFormat format, u32 width, u32 height, u32 block_height, |
| 1217 | u32 tile_width_spacing, u32 level) { | 1227 | u32 tile_width_spacing, u32 level) { |
| @@ -1221,13 +1231,14 @@ constexpr u32 ValidateLayerSize(PixelFormat format, u32 width, u32 height, u32 b | |||
| 1221 | return AlignLayerSize(offset, size, block, DefaultBlockHeight(format), tile_width_spacing); | 1231 | return AlignLayerSize(offset, size, block, DefaultBlockHeight(format), tile_width_spacing); |
| 1222 | } | 1232 | } |
| 1223 | 1233 | ||
| 1224 | static_assert(ValidateLayerSize(P::ASTC_2D_12X12_UNORM, 8192, 4096, 2, 0, 12) == 0x50d800); | 1234 | static_assert(ValidateLayerSize(PixelFormat::ASTC_2D_12X12_UNORM, 8192, 4096, 2, 0, 12) == |
| 1225 | static_assert(ValidateLayerSize(P::A8B8G8R8_UNORM, 1024, 1024, 2, 0, 10) == 0x556000); | 1235 | 0x50d800); |
| 1226 | static_assert(ValidateLayerSize(P::BC3_UNORM, 128, 128, 2, 0, 8) == 0x6000); | 1236 | static_assert(ValidateLayerSize(PixelFormat::A8B8G8R8_UNORM, 1024, 1024, 2, 0, 10) == 0x556000); |
| 1237 | static_assert(ValidateLayerSize(PixelFormat::BC3_UNORM, 128, 128, 2, 0, 8) == 0x6000); | ||
| 1227 | 1238 | ||
| 1228 | static_assert(ValidateLayerSize(P::A8B8G8R8_UNORM, 518, 572, 4, 3, 1) == 0x190000, | 1239 | static_assert(ValidateLayerSize(PixelFormat::A8B8G8R8_UNORM, 518, 572, 4, 3, 1) == 0x190000, |
| 1229 | "Tile width spacing is not working"); | 1240 | "Tile width spacing is not working"); |
| 1230 | static_assert(ValidateLayerSize(P::BC5_UNORM, 1024, 1024, 3, 4, 11) == 0x160000, | 1241 | static_assert(ValidateLayerSize(PixelFormat::BC5_UNORM, 1024, 1024, 3, 4, 11) == 0x160000, |
| 1231 | "Compressed tile width spacing is not working"); | 1242 | "Compressed tile width spacing is not working"); |
| 1232 | 1243 | ||
| 1233 | } // namespace VideoCommon | 1244 | } // namespace VideoCommon |
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp index 8d10ac29e..7a9d00d4f 100644 --- a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp +++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp | |||
| @@ -12,21 +12,12 @@ | |||
| 12 | 12 | ||
| 13 | #include <fmt/format.h> | 13 | #include <fmt/format.h> |
| 14 | 14 | ||
| 15 | #define VK_NO_PROTOTYPES | ||
| 16 | #include <vulkan/vulkan.h> | ||
| 17 | |||
| 18 | #include <GFSDK_Aftermath.h> | ||
| 19 | #include <GFSDK_Aftermath_Defines.h> | ||
| 20 | #include <GFSDK_Aftermath_GpuCrashDump.h> | ||
| 21 | #include <GFSDK_Aftermath_GpuCrashDumpDecoding.h> | ||
| 22 | |||
| 23 | #include "common/common_paths.h" | 15 | #include "common/common_paths.h" |
| 24 | #include "common/common_types.h" | 16 | #include "common/common_types.h" |
| 25 | #include "common/file_util.h" | 17 | #include "common/file_util.h" |
| 26 | #include "common/logging/log.h" | 18 | #include "common/logging/log.h" |
| 27 | #include "common/scope_exit.h" | 19 | #include "common/scope_exit.h" |
| 28 | 20 | #include "video_core/vulkan_common/nsight_aftermath_tracker.h" | |
| 29 | #include "video_core/renderer_vulkan/nsight_aftermath_tracker.h" | ||
| 30 | 21 | ||
| 31 | namespace Vulkan { | 22 | namespace Vulkan { |
| 32 | 23 | ||
| @@ -53,7 +44,7 @@ NsightAftermathTracker::NsightAftermathTracker() { | |||
| 53 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON", | 44 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON", |
| 54 | &GFSDK_Aftermath_GpuCrashDump_GetJSON)) { | 45 | &GFSDK_Aftermath_GpuCrashDump_GetJSON)) { |
| 55 | LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers"); | 46 | LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers"); |
| 56 | return false; | 47 | return; |
| 57 | } | 48 | } |
| 58 | dump_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + "gpucrash"; | 49 | dump_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + "gpucrash"; |
| 59 | 50 | ||
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.h b/src/video_core/vulkan_common/nsight_aftermath_tracker.h index cee3847fb..1ce8d4e8e 100644 --- a/src/video_core/vulkan_common/nsight_aftermath_tracker.h +++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.h | |||
| @@ -8,8 +8,9 @@ | |||
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #define VK_NO_PROTOTYPES | 11 | #include "common/common_types.h" |
| 12 | #include <vulkan/vulkan.h> | 12 | #include "common/dynamic_library.h" |
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | 14 | ||
| 14 | #ifdef HAS_NSIGHT_AFTERMATH | 15 | #ifdef HAS_NSIGHT_AFTERMATH |
| 15 | #include <GFSDK_Aftermath_Defines.h> | 16 | #include <GFSDK_Aftermath_Defines.h> |
| @@ -17,9 +18,6 @@ | |||
| 17 | #include <GFSDK_Aftermath_GpuCrashDumpDecoding.h> | 18 | #include <GFSDK_Aftermath_GpuCrashDumpDecoding.h> |
| 18 | #endif | 19 | #endif |
| 19 | 20 | ||
| 20 | #include "common/common_types.h" | ||
| 21 | #include "common/dynamic_library.h" | ||
| 22 | |||
| 23 | namespace Vulkan { | 21 | namespace Vulkan { |
| 24 | 22 | ||
| 25 | class NsightAftermathTracker { | 23 | class NsightAftermathTracker { |
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp index ea7af8ad4..5c64c9bf7 100644 --- a/src/video_core/vulkan_common/vulkan_debug_callback.cpp +++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp | |||
| @@ -39,6 +39,7 @@ vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { | |||
| 39 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | | 39 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | |
| 40 | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, | 40 | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, |
| 41 | .pfnUserCallback = Callback, | 41 | .pfnUserCallback = Callback, |
| 42 | .pUserData = nullptr, | ||
| 42 | }); | 43 | }); |
| 43 | } | 44 | } |
| 44 | 45 | ||
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.h b/src/video_core/vulkan_common/vulkan_debug_callback.h index 2efcd244c..b0519f132 100644 --- a/src/video_core/vulkan_common/vulkan_debug_callback.h +++ b/src/video_core/vulkan_common/vulkan_debug_callback.h | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | ||
| 6 | |||
| 5 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 7 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 6 | 8 | ||
| 7 | namespace Vulkan { | 9 | namespace Vulkan { |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 37d7b45a3..51f53bc39 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -84,21 +84,6 @@ VkFormatFeatureFlags GetFormatFeatures(VkFormatProperties properties, FormatType | |||
| 84 | } | 84 | } |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | [[nodiscard]] bool IsRDNA(std::string_view device_name, VkDriverIdKHR driver_id) { | ||
| 88 | static constexpr std::array RDNA_DEVICES{ | ||
| 89 | "5700", | ||
| 90 | "5600", | ||
| 91 | "5500", | ||
| 92 | "5300", | ||
| 93 | }; | ||
| 94 | if (driver_id != VK_DRIVER_ID_AMD_PROPRIETARY_KHR) { | ||
| 95 | return false; | ||
| 96 | } | ||
| 97 | return std::any_of(RDNA_DEVICES.begin(), RDNA_DEVICES.end(), [device_name](const char* name) { | ||
| 98 | return device_name.find(name) != std::string_view::npos; | ||
| 99 | }); | ||
| 100 | } | ||
| 101 | |||
| 102 | std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::PhysicalDevice physical) { | 87 | std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::PhysicalDevice physical) { |
| 103 | static constexpr std::array formats{ | 88 | static constexpr std::array formats{ |
| 104 | VK_FORMAT_A8B8G8R8_UNORM_PACK32, | 89 | VK_FORMAT_A8B8G8R8_UNORM_PACK32, |
| @@ -436,13 +421,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 436 | "Blacklisting RADV for VK_EXT_extended_dynamic state, likely due to a bug in yuzu"); | 421 | "Blacklisting RADV for VK_EXT_extended_dynamic state, likely due to a bug in yuzu"); |
| 437 | ext_extended_dynamic_state = false; | 422 | ext_extended_dynamic_state = false; |
| 438 | } | 423 | } |
| 439 | if (ext_extended_dynamic_state && IsRDNA(properties.deviceName, driver_id)) { | 424 | if (is_float16_supported && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { |
| 440 | // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but on RDNA devices it | 425 | // Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being. |
| 441 | // seems to cause stability issues | 426 | LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math"); |
| 442 | LOG_WARNING( | 427 | is_float16_supported = false; |
| 443 | Render_Vulkan, | ||
| 444 | "Blacklisting AMD proprietary on RDNA devices from VK_EXT_extended_dynamic_state"); | ||
| 445 | ext_extended_dynamic_state = false; | ||
| 446 | } | 428 | } |
| 447 | 429 | ||
| 448 | graphics_queue = logical.GetQueue(graphics_family); | 430 | graphics_queue = logical.GetQueue(graphics_family); |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index 53b3b275a..9e6cfabf9 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h | |||
| @@ -74,11 +74,10 @@ public: | |||
| 74 | MemoryAllocator(const MemoryAllocator&) = delete; | 74 | MemoryAllocator(const MemoryAllocator&) = delete; |
| 75 | 75 | ||
| 76 | /** | 76 | /** |
| 77 | * Commits a memory with the specified requeriments. | 77 | * Commits a memory with the specified requirements. |
| 78 | * | 78 | * |
| 79 | * @param requirements Requirements returned from a Vulkan call. | 79 | * @param requirements Requirements returned from a Vulkan call. |
| 80 | * @param host_visible Signals the allocator that it *must* use host visible and coherent | 80 | * @param usage Indicates how the memory will be used. |
| 81 | * memory. When passing false, it will try to allocate device local memory. | ||
| 82 | * | 81 | * |
| 83 | * @returns A memory commit. | 82 | * @returns A memory commit. |
| 84 | */ | 83 | */ |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index e1bab2112..fb9967c8f 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -71,6 +71,8 @@ add_executable(yuzu | |||
| 71 | configuration/configure_input_player.cpp | 71 | configuration/configure_input_player.cpp |
| 72 | configuration/configure_input_player.h | 72 | configuration/configure_input_player.h |
| 73 | configuration/configure_input_player.ui | 73 | configuration/configure_input_player.ui |
| 74 | configuration/configure_input_player_widget.cpp | ||
| 75 | configuration/configure_input_player_widget.h | ||
| 74 | configuration/configure_input_profile_dialog.cpp | 76 | configuration/configure_input_profile_dialog.cpp |
| 75 | configuration/configure_input_profile_dialog.h | 77 | configuration/configure_input_profile_dialog.h |
| 76 | configuration/configure_input_profile_dialog.ui | 78 | configuration/configure_input_profile_dialog.ui |
| @@ -115,6 +117,8 @@ add_executable(yuzu | |||
| 115 | configuration/input_profiles.h | 117 | configuration/input_profiles.h |
| 116 | debugger/console.cpp | 118 | debugger/console.cpp |
| 117 | debugger/console.h | 119 | debugger/console.h |
| 120 | debugger/controller.cpp | ||
| 121 | debugger/controller.h | ||
| 118 | debugger/profiler.cpp | 122 | debugger/profiler.cpp |
| 119 | debugger/profiler.h | 123 | debugger/profiler.h |
| 120 | debugger/wait_tree.cpp | 124 | debugger/wait_tree.cpp |
diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp index 4bf2bfd40..0a4c48b3d 100644 --- a/src/yuzu/applets/profile_select.cpp +++ b/src/yuzu/applets/profile_select.cpp | |||
| @@ -93,7 +93,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) | |||
| 93 | 93 | ||
| 94 | const auto& profiles = profile_manager->GetAllUsers(); | 94 | const auto& profiles = profile_manager->GetAllUsers(); |
| 95 | for (const auto& user : profiles) { | 95 | for (const auto& user : profiles) { |
| 96 | Service::Account::ProfileBase profile; | 96 | Service::Account::ProfileBase profile{}; |
| 97 | if (!profile_manager->GetProfileBase(user, profile)) | 97 | if (!profile_manager->GetProfileBase(user, profile)) |
| 98 | continue; | 98 | continue; |
| 99 | 99 | ||
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index e6c8f18af..ffdf34a4a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -126,7 +126,7 @@ public: | |||
| 126 | /// Create the original context that should be shared from | 126 | /// Create the original context that should be shared from |
| 127 | explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { | 127 | explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { |
| 128 | QSurfaceFormat format; | 128 | QSurfaceFormat format; |
| 129 | format.setVersion(4, 3); | 129 | format.setVersion(4, 6); |
| 130 | format.setProfile(QSurfaceFormat::CompatibilityProfile); | 130 | format.setProfile(QSurfaceFormat::CompatibilityProfile); |
| 131 | format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); | 131 | format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); |
| 132 | if (Settings::values.renderer_debug) { | 132 | if (Settings::values.renderer_debug) { |
| @@ -394,7 +394,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { | |||
| 394 | input_subsystem->GetMouse()->PressButton(x, y, event->button()); | 394 | input_subsystem->GetMouse()->PressButton(x, y, event->button()); |
| 395 | 395 | ||
| 396 | if (event->button() == Qt::LeftButton) { | 396 | if (event->button() == Qt::LeftButton) { |
| 397 | this->TouchPressed(x, y); | 397 | this->TouchPressed(x, y, 0); |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | emit MouseActivity(); | 400 | emit MouseActivity(); |
| @@ -409,7 +409,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { | |||
| 409 | auto pos = event->pos(); | 409 | auto pos = event->pos(); |
| 410 | const auto [x, y] = ScaleTouch(pos); | 410 | const auto [x, y] = ScaleTouch(pos); |
| 411 | input_subsystem->GetMouse()->MouseMove(x, y); | 411 | input_subsystem->GetMouse()->MouseMove(x, y); |
| 412 | this->TouchMoved(x, y); | 412 | this->TouchMoved(x, y, 0); |
| 413 | 413 | ||
| 414 | emit MouseActivity(); | 414 | emit MouseActivity(); |
| 415 | } | 415 | } |
| @@ -423,36 +423,72 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { | |||
| 423 | input_subsystem->GetMouse()->ReleaseButton(event->button()); | 423 | input_subsystem->GetMouse()->ReleaseButton(event->button()); |
| 424 | 424 | ||
| 425 | if (event->button() == Qt::LeftButton) { | 425 | if (event->button() == Qt::LeftButton) { |
| 426 | this->TouchReleased(); | 426 | this->TouchReleased(0); |
| 427 | } | 427 | } |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { | 430 | void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { |
| 431 | // TouchBegin always has exactly one touch point, so take the .first() | 431 | QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints(); |
| 432 | const auto [x, y] = ScaleTouch(event->touchPoints().first().pos()); | 432 | for (const auto& touch_point : touch_points) { |
| 433 | this->TouchPressed(x, y); | 433 | if (!TouchUpdate(touch_point)) { |
| 434 | TouchStart(touch_point); | ||
| 435 | } | ||
| 436 | } | ||
| 434 | } | 437 | } |
| 435 | 438 | ||
| 436 | void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { | 439 | void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { |
| 437 | QPointF pos; | 440 | QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints(); |
| 438 | int active_points = 0; | 441 | for (const auto& touch_point : touch_points) { |
| 439 | 442 | if (!TouchUpdate(touch_point)) { | |
| 440 | // average all active touch points | 443 | TouchStart(touch_point); |
| 441 | for (const auto& tp : event->touchPoints()) { | 444 | } |
| 442 | if (tp.state() & (Qt::TouchPointPressed | Qt::TouchPointMoved | Qt::TouchPointStationary)) { | 445 | } |
| 443 | active_points++; | 446 | // Release all inactive points |
| 444 | pos += tp.pos(); | 447 | for (std::size_t id = 0; id < touch_ids.size(); ++id) { |
| 448 | if (!TouchExist(touch_ids[id], touch_points)) { | ||
| 449 | touch_ids[id] = 0; | ||
| 450 | this->TouchReleased(id + 1); | ||
| 445 | } | 451 | } |
| 446 | } | 452 | } |
| 453 | } | ||
| 447 | 454 | ||
| 448 | pos /= active_points; | 455 | void GRenderWindow::TouchEndEvent() { |
| 456 | for (std::size_t id = 0; id < touch_ids.size(); ++id) { | ||
| 457 | if (touch_ids[id] != 0) { | ||
| 458 | touch_ids[id] = 0; | ||
| 459 | this->TouchReleased(id + 1); | ||
| 460 | } | ||
| 461 | } | ||
| 462 | } | ||
| 449 | 463 | ||
| 450 | const auto [x, y] = ScaleTouch(pos); | 464 | bool GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) { |
| 451 | this->TouchMoved(x, y); | 465 | for (std::size_t id = 0; id < touch_ids.size(); ++id) { |
| 466 | if (touch_ids[id] == 0) { | ||
| 467 | touch_ids[id] = touch_point.id() + 1; | ||
| 468 | const auto [x, y] = ScaleTouch(touch_point.pos()); | ||
| 469 | this->TouchPressed(x, y, id + 1); | ||
| 470 | return true; | ||
| 471 | } | ||
| 472 | } | ||
| 473 | return false; | ||
| 452 | } | 474 | } |
| 453 | 475 | ||
| 454 | void GRenderWindow::TouchEndEvent() { | 476 | bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) { |
| 455 | this->TouchReleased(); | 477 | for (std::size_t id = 0; id < touch_ids.size(); ++id) { |
| 478 | if (touch_ids[id] == static_cast<std::size_t>(touch_point.id() + 1)) { | ||
| 479 | const auto [x, y] = ScaleTouch(touch_point.pos()); | ||
| 480 | this->TouchMoved(x, y, id + 1); | ||
| 481 | return true; | ||
| 482 | } | ||
| 483 | } | ||
| 484 | return false; | ||
| 485 | } | ||
| 486 | |||
| 487 | bool GRenderWindow::TouchExist(std::size_t id, | ||
| 488 | const QList<QTouchEvent::TouchPoint>& touch_points) const { | ||
| 489 | return std::any_of(touch_points.begin(), touch_points.end(), [id](const auto& point) { | ||
| 490 | return id == static_cast<std::size_t>(point.id() + 1); | ||
| 491 | }); | ||
| 456 | } | 492 | } |
| 457 | 493 | ||
| 458 | bool GRenderWindow::event(QEvent* event) { | 494 | bool GRenderWindow::event(QEvent* event) { |
| @@ -615,10 +651,10 @@ bool GRenderWindow::LoadOpenGL() { | |||
| 615 | const QString renderer = | 651 | const QString renderer = |
| 616 | QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER))); | 652 | QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER))); |
| 617 | 653 | ||
| 618 | if (!GLAD_GL_VERSION_4_3) { | 654 | if (!GLAD_GL_VERSION_4_6) { |
| 619 | LOG_ERROR(Frontend, "GPU does not support OpenGL 4.3: {}", renderer.toStdString()); | 655 | LOG_ERROR(Frontend, "GPU does not support OpenGL 4.6: {}", renderer.toStdString()); |
| 620 | QMessageBox::warning(this, tr("Error while initializing OpenGL 4.3!"), | 656 | QMessageBox::warning(this, tr("Error while initializing OpenGL 4.6!"), |
| 621 | tr("Your GPU may not support OpenGL 4.3, or you do not have the " | 657 | tr("Your GPU may not support OpenGL 4.6, or you do not have the " |
| 622 | "latest graphics driver.<br><br>GL Renderer:<br>%1") | 658 | "latest graphics driver.<br><br>GL Renderer:<br>%1") |
| 623 | .arg(renderer)); | 659 | .arg(renderer)); |
| 624 | return false; | 660 | return false; |
| @@ -641,26 +677,13 @@ bool GRenderWindow::LoadOpenGL() { | |||
| 641 | QStringList GRenderWindow::GetUnsupportedGLExtensions() const { | 677 | QStringList GRenderWindow::GetUnsupportedGLExtensions() const { |
| 642 | QStringList unsupported_ext; | 678 | QStringList unsupported_ext; |
| 643 | 679 | ||
| 644 | if (!GLAD_GL_ARB_buffer_storage) | ||
| 645 | unsupported_ext.append(QStringLiteral("ARB_buffer_storage")); | ||
| 646 | if (!GLAD_GL_ARB_direct_state_access) | ||
| 647 | unsupported_ext.append(QStringLiteral("ARB_direct_state_access")); | ||
| 648 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | ||
| 649 | unsupported_ext.append(QStringLiteral("ARB_vertex_type_10f_11f_11f_rev")); | ||
| 650 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | ||
| 651 | unsupported_ext.append(QStringLiteral("ARB_texture_mirror_clamp_to_edge")); | ||
| 652 | if (!GLAD_GL_ARB_multi_bind) | ||
| 653 | unsupported_ext.append(QStringLiteral("ARB_multi_bind")); | ||
| 654 | if (!GLAD_GL_ARB_clip_control) | ||
| 655 | unsupported_ext.append(QStringLiteral("ARB_clip_control")); | ||
| 656 | |||
| 657 | // Extensions required to support some texture formats. | 680 | // Extensions required to support some texture formats. |
| 658 | if (!GLAD_GL_EXT_texture_compression_s3tc) | 681 | if (!GLAD_GL_EXT_texture_compression_s3tc) { |
| 659 | unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc")); | 682 | unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc")); |
| 660 | if (!GLAD_GL_ARB_texture_compression_rgtc) | 683 | } |
| 684 | if (!GLAD_GL_ARB_texture_compression_rgtc) { | ||
| 661 | unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc")); | 685 | unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc")); |
| 662 | if (!GLAD_GL_ARB_depth_buffer_float) | 686 | } |
| 663 | unsupported_ext.append(QStringLiteral("ARB_depth_buffer_float")); | ||
| 664 | 687 | ||
| 665 | if (!unsupported_ext.empty()) { | 688 | if (!unsupported_ext.empty()) { |
| 666 | LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", | 689 | LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 339095509..b5ec7de07 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include <QImage> | 12 | #include <QImage> |
| 13 | #include <QThread> | 13 | #include <QThread> |
| 14 | #include <QTouchEvent> | ||
| 14 | #include <QWidget> | 15 | #include <QWidget> |
| 15 | #include <QWindow> | 16 | #include <QWindow> |
| 16 | 17 | ||
| @@ -21,7 +22,6 @@ | |||
| 21 | class GRenderWindow; | 22 | class GRenderWindow; |
| 22 | class GMainWindow; | 23 | class GMainWindow; |
| 23 | class QKeyEvent; | 24 | class QKeyEvent; |
| 24 | class QTouchEvent; | ||
| 25 | class QStringList; | 25 | class QStringList; |
| 26 | 26 | ||
| 27 | namespace InputCommon { | 27 | namespace InputCommon { |
| @@ -191,6 +191,10 @@ private: | |||
| 191 | void TouchUpdateEvent(const QTouchEvent* event); | 191 | void TouchUpdateEvent(const QTouchEvent* event); |
| 192 | void TouchEndEvent(); | 192 | void TouchEndEvent(); |
| 193 | 193 | ||
| 194 | bool TouchStart(const QTouchEvent::TouchPoint& touch_point); | ||
| 195 | bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point); | ||
| 196 | bool TouchExist(std::size_t id, const QList<QTouchEvent::TouchPoint>& touch_points) const; | ||
| 197 | |||
| 194 | void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; | 198 | void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; |
| 195 | 199 | ||
| 196 | bool InitializeOpenGL(); | 200 | bool InitializeOpenGL(); |
| @@ -215,6 +219,8 @@ private: | |||
| 215 | 219 | ||
| 216 | bool first_frame = false; | 220 | bool first_frame = false; |
| 217 | 221 | ||
| 222 | std::array<std::size_t, 16> touch_ids{}; | ||
| 223 | |||
| 218 | protected: | 224 | protected: |
| 219 | void showEvent(QShowEvent* event) override; | 225 | void showEvent(QShowEvent* event) override; |
| 220 | bool eventFilter(QObject* object, QEvent* event) override; | 226 | bool eventFilter(QObject* object, QEvent* event) override; |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 9f73d37d4..8d85a1986 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -464,13 +464,7 @@ void Config::ReadMouseValues() { | |||
| 464 | void Config::ReadTouchscreenValues() { | 464 | void Config::ReadTouchscreenValues() { |
| 465 | Settings::values.touchscreen.enabled = | 465 | Settings::values.touchscreen.enabled = |
| 466 | ReadSetting(QStringLiteral("touchscreen_enabled"), true).toBool(); | 466 | ReadSetting(QStringLiteral("touchscreen_enabled"), true).toBool(); |
| 467 | Settings::values.touchscreen.device = | ||
| 468 | ReadSetting(QStringLiteral("touchscreen_device"), QStringLiteral("engine:emu_window")) | ||
| 469 | .toString() | ||
| 470 | .toStdString(); | ||
| 471 | 467 | ||
| 472 | Settings::values.touchscreen.finger = | ||
| 473 | ReadSetting(QStringLiteral("touchscreen_finger"), 0).toUInt(); | ||
| 474 | Settings::values.touchscreen.rotation_angle = | 468 | Settings::values.touchscreen.rotation_angle = |
| 475 | ReadSetting(QStringLiteral("touchscreen_angle"), 0).toUInt(); | 469 | ReadSetting(QStringLiteral("touchscreen_angle"), 0).toUInt(); |
| 476 | Settings::values.touchscreen.diameter_x = | 470 | Settings::values.touchscreen.diameter_x = |
| @@ -563,7 +557,8 @@ void Config::ReadMotionTouchValues() { | |||
| 563 | .toString() | 557 | .toString() |
| 564 | .toStdString(); | 558 | .toStdString(); |
| 565 | Settings::values.touch_device = | 559 | Settings::values.touch_device = |
| 566 | ReadSetting(QStringLiteral("touch_device"), QStringLiteral("engine:emu_window")) | 560 | ReadSetting(QStringLiteral("touch_device"), |
| 561 | QStringLiteral("min_x:100,min_y:50,max_x:1800,max_y:850")) | ||
| 567 | .toString() | 562 | .toString() |
| 568 | .toStdString(); | 563 | .toStdString(); |
| 569 | Settings::values.use_touch_from_button = | 564 | Settings::values.use_touch_from_button = |
| @@ -1088,10 +1083,7 @@ void Config::SaveTouchscreenValues() { | |||
| 1088 | const auto& touchscreen = Settings::values.touchscreen; | 1083 | const auto& touchscreen = Settings::values.touchscreen; |
| 1089 | 1084 | ||
| 1090 | WriteSetting(QStringLiteral("touchscreen_enabled"), touchscreen.enabled, true); | 1085 | WriteSetting(QStringLiteral("touchscreen_enabled"), touchscreen.enabled, true); |
| 1091 | WriteSetting(QStringLiteral("touchscreen_device"), QString::fromStdString(touchscreen.device), | ||
| 1092 | QStringLiteral("engine:emu_window")); | ||
| 1093 | 1086 | ||
| 1094 | WriteSetting(QStringLiteral("touchscreen_finger"), touchscreen.finger, 0); | ||
| 1095 | WriteSetting(QStringLiteral("touchscreen_angle"), touchscreen.rotation_angle, 0); | 1087 | WriteSetting(QStringLiteral("touchscreen_angle"), touchscreen.rotation_angle, 0); |
| 1096 | WriteSetting(QStringLiteral("touchscreen_diameter_x"), touchscreen.diameter_x, 15); | 1088 | WriteSetting(QStringLiteral("touchscreen_diameter_x"), touchscreen.diameter_x, 15); |
| 1097 | WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); | 1089 | WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index fbe36046b..c9d19c948 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "ui_configure_input_player.h" | 23 | #include "ui_configure_input_player.h" |
| 24 | #include "yuzu/configuration/config.h" | 24 | #include "yuzu/configuration/config.h" |
| 25 | #include "yuzu/configuration/configure_input_player.h" | 25 | #include "yuzu/configuration/configure_input_player.h" |
| 26 | #include "yuzu/configuration/configure_input_player_widget.h" | ||
| 26 | #include "yuzu/configuration/configure_vibration.h" | 27 | #include "yuzu/configuration/configure_vibration.h" |
| 27 | #include "yuzu/configuration/input_profiles.h" | 28 | #include "yuzu/configuration/input_profiles.h" |
| 28 | #include "yuzu/util/limitable_input_dialog.h" | 29 | #include "yuzu/util/limitable_input_dialog.h" |
| @@ -254,11 +255,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 254 | analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; | 255 | analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; |
| 255 | analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange}; | 256 | analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange}; |
| 256 | 257 | ||
| 257 | const auto ConfigureButtonClick = [&](QPushButton* button, Common::ParamPackage* param, | 258 | const auto ConfigureButtonClick = [&](QPushButton* button, std::size_t button_id, |
| 258 | int default_val, InputCommon::Polling::DeviceType type) { | 259 | Common::ParamPackage* param, int default_val, |
| 260 | InputCommon::Polling::DeviceType type) { | ||
| 259 | connect(button, &QPushButton::clicked, [=, this] { | 261 | connect(button, &QPushButton::clicked, [=, this] { |
| 260 | HandleClick( | 262 | HandleClick( |
| 261 | button, | 263 | button, button_id, |
| 262 | [=, this](Common::ParamPackage params) { | 264 | [=, this](Common::ParamPackage params) { |
| 263 | // Workaround for ZL & ZR for analog triggers like on XBOX | 265 | // Workaround for ZL & ZR for analog triggers like on XBOX |
| 264 | // controllers. Analog triggers (from controllers like the XBOX | 266 | // controllers. Analog triggers (from controllers like the XBOX |
| @@ -286,12 +288,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 286 | continue; | 288 | continue; |
| 287 | } | 289 | } |
| 288 | 290 | ||
| 289 | ConfigureButtonClick(button_map[button_id], &buttons_param[button_id], | 291 | ConfigureButtonClick(button_map[button_id], button_id, &buttons_param[button_id], |
| 290 | Config::default_buttons[button_id], | 292 | Config::default_buttons[button_id], |
| 291 | InputCommon::Polling::DeviceType::Button); | 293 | InputCommon::Polling::DeviceType::Button); |
| 292 | 294 | ||
| 293 | button->setContextMenuPolicy(Qt::CustomContextMenu); | 295 | button->setContextMenuPolicy(Qt::CustomContextMenu); |
| 294 | |||
| 295 | connect(button, &QPushButton::customContextMenuRequested, | 296 | connect(button, &QPushButton::customContextMenuRequested, |
| 296 | [=, this](const QPoint& menu_location) { | 297 | [=, this](const QPoint& menu_location) { |
| 297 | QMenu context_menu; | 298 | QMenu context_menu; |
| @@ -300,6 +301,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 300 | button_map[button_id]->setText(tr("[not set]")); | 301 | button_map[button_id]->setText(tr("[not set]")); |
| 301 | }); | 302 | }); |
| 302 | context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); | 303 | context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); |
| 304 | ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); | ||
| 303 | }); | 305 | }); |
| 304 | } | 306 | } |
| 305 | 307 | ||
| @@ -309,7 +311,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 309 | continue; | 311 | continue; |
| 310 | } | 312 | } |
| 311 | 313 | ||
| 312 | ConfigureButtonClick(motion_map[motion_id], &motions_param[motion_id], | 314 | ConfigureButtonClick(motion_map[motion_id], motion_id, &motions_param[motion_id], |
| 313 | Config::default_motions[motion_id], | 315 | Config::default_motions[motion_id], |
| 314 | InputCommon::Polling::DeviceType::Motion); | 316 | InputCommon::Polling::DeviceType::Motion); |
| 315 | 317 | ||
| @@ -348,7 +350,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 348 | } | 350 | } |
| 349 | } | 351 | } |
| 350 | HandleClick( | 352 | HandleClick( |
| 351 | analog_map_buttons[analog_id][sub_button_id], | 353 | analog_map_buttons[analog_id][sub_button_id], analog_id, |
| 352 | [=, this](const Common::ParamPackage& params) { | 354 | [=, this](const Common::ParamPackage& params) { |
| 353 | SetAnalogParam(params, analogs_param[analog_id], | 355 | SetAnalogParam(params, analogs_param[analog_id], |
| 354 | analog_sub_buttons[sub_button_id]); | 356 | analog_sub_buttons[sub_button_id]); |
| @@ -358,41 +360,43 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 358 | 360 | ||
| 359 | analog_button->setContextMenuPolicy(Qt::CustomContextMenu); | 361 | analog_button->setContextMenuPolicy(Qt::CustomContextMenu); |
| 360 | 362 | ||
| 361 | connect(analog_button, &QPushButton::customContextMenuRequested, | 363 | connect( |
| 362 | [=, this](const QPoint& menu_location) { | 364 | analog_button, &QPushButton::customContextMenuRequested, |
| 363 | QMenu context_menu; | 365 | [=, this](const QPoint& menu_location) { |
| 364 | context_menu.addAction(tr("Clear"), [&] { | 366 | QMenu context_menu; |
| 365 | analogs_param[analog_id].Clear(); | 367 | context_menu.addAction(tr("Clear"), [&] { |
| 366 | analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); | 368 | analogs_param[analog_id].Clear(); |
| 367 | }); | 369 | analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); |
| 368 | context_menu.addAction(tr("Invert axis"), [&] { | ||
| 369 | if (sub_button_id == 2 || sub_button_id == 3) { | ||
| 370 | const bool invert_value = | ||
| 371 | analogs_param[analog_id].Get("invert_x", "+") == "-"; | ||
| 372 | const std::string invert_str = invert_value ? "+" : "-"; | ||
| 373 | analogs_param[analog_id].Set("invert_x", invert_str); | ||
| 374 | } | ||
| 375 | if (sub_button_id == 0 || sub_button_id == 1) { | ||
| 376 | const bool invert_value = | ||
| 377 | analogs_param[analog_id].Get("invert_y", "+") == "-"; | ||
| 378 | const std::string invert_str = invert_value ? "+" : "-"; | ||
| 379 | analogs_param[analog_id].Set("invert_y", invert_str); | ||
| 380 | } | ||
| 381 | for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; | ||
| 382 | ++sub_button_id) { | ||
| 383 | analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( | ||
| 384 | analogs_param[analog_id], analog_sub_buttons[sub_button_id])); | ||
| 385 | } | ||
| 386 | }); | ||
| 387 | context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( | ||
| 388 | menu_location)); | ||
| 389 | }); | 370 | }); |
| 371 | context_menu.addAction(tr("Invert axis"), [&] { | ||
| 372 | if (sub_button_id == 2 || sub_button_id == 3) { | ||
| 373 | const bool invert_value = | ||
| 374 | analogs_param[analog_id].Get("invert_x", "+") == "-"; | ||
| 375 | const std::string invert_str = invert_value ? "+" : "-"; | ||
| 376 | analogs_param[analog_id].Set("invert_x", invert_str); | ||
| 377 | } | ||
| 378 | if (sub_button_id == 0 || sub_button_id == 1) { | ||
| 379 | const bool invert_value = | ||
| 380 | analogs_param[analog_id].Get("invert_y", "+") == "-"; | ||
| 381 | const std::string invert_str = invert_value ? "+" : "-"; | ||
| 382 | analogs_param[analog_id].Set("invert_y", invert_str); | ||
| 383 | } | ||
| 384 | for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; | ||
| 385 | ++sub_button_id) { | ||
| 386 | analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( | ||
| 387 | analogs_param[analog_id], analog_sub_buttons[sub_button_id])); | ||
| 388 | } | ||
| 389 | }); | ||
| 390 | context_menu.exec( | ||
| 391 | analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(menu_location)); | ||
| 392 | ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); | ||
| 393 | }); | ||
| 390 | } | 394 | } |
| 391 | 395 | ||
| 392 | // Handle clicks for the modifier buttons as well. | 396 | // Handle clicks for the modifier buttons as well. |
| 393 | connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] { | 397 | connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] { |
| 394 | HandleClick( | 398 | HandleClick( |
| 395 | analog_map_modifier_button[analog_id], | 399 | analog_map_modifier_button[analog_id], analog_id, |
| 396 | [=, this](const Common::ParamPackage& params) { | 400 | [=, this](const Common::ParamPackage& params) { |
| 397 | analogs_param[analog_id].Set("modifier", params.Serialize()); | 401 | analogs_param[analog_id].Set("modifier", params.Serialize()); |
| 398 | }, | 402 | }, |
| @@ -416,12 +420,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 416 | [=, this] { | 420 | [=, this] { |
| 417 | const auto spinbox_value = analog_map_range_spinbox[analog_id]->value(); | 421 | const auto spinbox_value = analog_map_range_spinbox[analog_id]->value(); |
| 418 | analogs_param[analog_id].Set("range", spinbox_value / 100.0f); | 422 | analogs_param[analog_id].Set("range", spinbox_value / 100.0f); |
| 423 | ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); | ||
| 419 | }); | 424 | }); |
| 420 | 425 | ||
| 421 | connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] { | 426 | connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] { |
| 422 | const auto slider_value = analog_map_deadzone_slider[analog_id]->value(); | 427 | const auto slider_value = analog_map_deadzone_slider[analog_id]->value(); |
| 423 | analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value)); | 428 | analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value)); |
| 424 | analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); | 429 | analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); |
| 430 | ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); | ||
| 425 | }); | 431 | }); |
| 426 | 432 | ||
| 427 | connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] { | 433 | connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] { |
| @@ -433,8 +439,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 433 | } | 439 | } |
| 434 | 440 | ||
| 435 | // Player Connected checkbox | 441 | // Player Connected checkbox |
| 436 | connect(ui->groupConnectedController, &QGroupBox::toggled, | 442 | connect(ui->groupConnectedController, &QGroupBox::toggled, [this](bool checked) { |
| 437 | [this](bool checked) { emit Connected(checked); }); | 443 | emit Connected(checked); |
| 444 | ui->controllerFrame->SetConnectedStatus(checked); | ||
| 445 | }); | ||
| 438 | 446 | ||
| 439 | if (player_index == 0) { | 447 | if (player_index == 0) { |
| 440 | connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), | 448 | connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), |
| @@ -553,6 +561,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 553 | 561 | ||
| 554 | // TODO(wwylele): enable this when we actually emulate it | 562 | // TODO(wwylele): enable this when we actually emulate it |
| 555 | ui->buttonHome->setEnabled(false); | 563 | ui->buttonHome->setEnabled(false); |
| 564 | ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); | ||
| 565 | ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked()); | ||
| 556 | } | 566 | } |
| 557 | 567 | ||
| 558 | ConfigureInputPlayer::~ConfigureInputPlayer() = default; | 568 | ConfigureInputPlayer::~ConfigureInputPlayer() = default; |
| @@ -580,9 +590,7 @@ void ConfigureInputPlayer::ApplyConfiguration() { | |||
| 580 | if (player_index == 0) { | 590 | if (player_index == 0) { |
| 581 | auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; | 591 | auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; |
| 582 | const auto handheld_connected = handheld.connected; | 592 | const auto handheld_connected = handheld.connected; |
| 583 | if (player.controller_type == Settings::ControllerType::Handheld) { | 593 | handheld = player; |
| 584 | handheld = player; | ||
| 585 | } | ||
| 586 | handheld.connected = handheld_connected; | 594 | handheld.connected = handheld_connected; |
| 587 | } | 595 | } |
| 588 | } | 596 | } |
| @@ -596,7 +604,7 @@ void ConfigureInputPlayer::TryConnectSelectedController() { | |||
| 596 | controller_type != Settings::ControllerType::Handheld; | 604 | controller_type != Settings::ControllerType::Handheld; |
| 597 | 605 | ||
| 598 | // Connect Handheld depending on Player 1's controller configuration. | 606 | // Connect Handheld depending on Player 1's controller configuration. |
| 599 | if (player_index == 0 && controller_type == Settings::ControllerType::Handheld) { | 607 | if (player_index == 0) { |
| 600 | auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; | 608 | auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; |
| 601 | const auto handheld_connected = ui->groupConnectedController->isChecked() && | 609 | const auto handheld_connected = ui->groupConnectedController->isChecked() && |
| 602 | controller_type == Settings::ControllerType::Handheld; | 610 | controller_type == Settings::ControllerType::Handheld; |
| @@ -877,6 +885,7 @@ void ConfigureInputPlayer::UpdateUI() { | |||
| 877 | modifier_label->setVisible(!is_controller); | 885 | modifier_label->setVisible(!is_controller); |
| 878 | modifier_slider->setVisible(!is_controller); | 886 | modifier_slider->setVisible(!is_controller); |
| 879 | range_groupbox->setVisible(is_controller); | 887 | range_groupbox->setVisible(is_controller); |
| 888 | ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); | ||
| 880 | } | 889 | } |
| 881 | } | 890 | } |
| 882 | 891 | ||
| @@ -886,7 +895,7 @@ void ConfigureInputPlayer::SetConnectableControllers() { | |||
| 886 | index_controller_type_pairs.clear(); | 895 | index_controller_type_pairs.clear(); |
| 887 | ui->comboControllerType->clear(); | 896 | ui->comboControllerType->clear(); |
| 888 | 897 | ||
| 889 | if (enable_all || npad_style_set.pro_controller == 1) { | 898 | if (enable_all || npad_style_set.fullkey == 1) { |
| 890 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 899 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), |
| 891 | Settings::ControllerType::ProController); | 900 | Settings::ControllerType::ProController); |
| 892 | ui->comboControllerType->addItem(tr("Pro Controller")); | 901 | ui->comboControllerType->addItem(tr("Pro Controller")); |
| @@ -993,8 +1002,8 @@ void ConfigureInputPlayer::UpdateControllerIcon() { | |||
| 993 | return QString{}; | 1002 | return QString{}; |
| 994 | } | 1003 | } |
| 995 | }(); | 1004 | }(); |
| 996 | 1005 | ui->controllerFrame->SetControllerType( | |
| 997 | ui->controllerFrame->setStyleSheet(stylesheet.arg(theme)); | 1006 | GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())); |
| 998 | } | 1007 | } |
| 999 | 1008 | ||
| 1000 | void ConfigureInputPlayer::UpdateControllerAvailableButtons() { | 1009 | void ConfigureInputPlayer::UpdateControllerAvailableButtons() { |
| @@ -1131,7 +1140,8 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { | |||
| 1131 | } | 1140 | } |
| 1132 | 1141 | ||
| 1133 | void ConfigureInputPlayer::HandleClick( | 1142 | void ConfigureInputPlayer::HandleClick( |
| 1134 | QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter, | 1143 | QPushButton* button, std::size_t button_id, |
| 1144 | std::function<void(const Common::ParamPackage&)> new_input_setter, | ||
| 1135 | InputCommon::Polling::DeviceType type) { | 1145 | InputCommon::Polling::DeviceType type) { |
| 1136 | if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) { | 1146 | if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) { |
| 1137 | button->setText(tr("Shake!")); | 1147 | button->setText(tr("Shake!")); |
| @@ -1175,6 +1185,12 @@ void ConfigureInputPlayer::HandleClick( | |||
| 1175 | input_subsystem->GetMouseTouch()->BeginConfiguration(); | 1185 | input_subsystem->GetMouseTouch()->BeginConfiguration(); |
| 1176 | } | 1186 | } |
| 1177 | 1187 | ||
| 1188 | if (type == InputCommon::Polling::DeviceType::Button) { | ||
| 1189 | ui->controllerFrame->BeginMappingButton(button_id); | ||
| 1190 | } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) { | ||
| 1191 | ui->controllerFrame->BeginMappingAnalog(button_id); | ||
| 1192 | } | ||
| 1193 | |||
| 1178 | timeout_timer->start(2500); // Cancel after 2.5 seconds | 1194 | timeout_timer->start(2500); // Cancel after 2.5 seconds |
| 1179 | poll_timer->start(50); // Check for new inputs every 50ms | 1195 | poll_timer->start(50); // Check for new inputs every 50ms |
| 1180 | } | 1196 | } |
| @@ -1205,6 +1221,7 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, | |||
| 1205 | 1221 | ||
| 1206 | UpdateUI(); | 1222 | UpdateUI(); |
| 1207 | UpdateInputDeviceCombobox(); | 1223 | UpdateInputDeviceCombobox(); |
| 1224 | ui->controllerFrame->EndMapping(); | ||
| 1208 | 1225 | ||
| 1209 | input_setter = std::nullopt; | 1226 | input_setter = std::nullopt; |
| 1210 | } | 1227 | } |
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index c4ae50de7..da2b89136 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h | |||
| @@ -106,7 +106,7 @@ private: | |||
| 106 | void LoadConfiguration(); | 106 | void LoadConfiguration(); |
| 107 | 107 | ||
| 108 | /// Called when the button was pressed. | 108 | /// Called when the button was pressed. |
| 109 | void HandleClick(QPushButton* button, | 109 | void HandleClick(QPushButton* button, std::size_t button_id, |
| 110 | std::function<void(const Common::ParamPackage&)> new_input_setter, | 110 | std::function<void(const Common::ParamPackage&)> new_input_setter, |
| 111 | InputCommon::Polling::DeviceType type); | 111 | InputCommon::Polling::DeviceType type); |
| 112 | 112 | ||
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index 1e78b4c10..e76aa484f 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui | |||
| @@ -1964,39 +1964,39 @@ | |||
| 1964 | </item> | 1964 | </item> |
| 1965 | </layout> | 1965 | </layout> |
| 1966 | </item> | 1966 | </item> |
| 1967 | <item> | 1967 | <item> |
| 1968 | <widget class="QFrame" name="controllerFrame"> | 1968 | <widget class="PlayerControlPreview" name="controllerFrame"> |
| 1969 | <property name="sizePolicy"> | 1969 | <property name="sizePolicy"> |
| 1970 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | 1970 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> |
| 1971 | <horstretch>0</horstretch> | 1971 | <horstretch>0</horstretch> |
| 1972 | <verstretch>0</verstretch> | 1972 | <verstretch>0</verstretch> |
| 1973 | </sizepolicy> | 1973 | </sizepolicy> |
| 1974 | </property> | 1974 | </property> |
| 1975 | <property name="font"> | 1975 | <property name="font"> |
| 1976 | <font> | 1976 | <font> |
| 1977 | <weight>75</weight> | 1977 | <weight>75</weight> |
| 1978 | <bold>true</bold> | 1978 | <bold>true</bold> |
| 1979 | </font> | 1979 | </font> |
| 1980 | </property> | 1980 | </property> |
| 1981 | <property name="styleSheet"> | 1981 | <property name="styleSheet"> |
| 1982 | <string notr="true">image: url(:/controller/pro);</string> | 1982 | <string notr="true">image: url(:/controller/pro);</string> |
| 1983 | </property> | 1983 | </property> |
| 1984 | <layout class="QVBoxLayout" name="verticalLayout_4"> | 1984 | <layout class="QVBoxLayout" name="verticalLayout_4"> |
| 1985 | <property name="leftMargin"> | 1985 | <property name="leftMargin"> |
| 1986 | <number>0</number> | 1986 | <number>0</number> |
| 1987 | </property> | 1987 | </property> |
| 1988 | <property name="topMargin"> | 1988 | <property name="topMargin"> |
| 1989 | <number>0</number> | 1989 | <number>0</number> |
| 1990 | </property> | 1990 | </property> |
| 1991 | <property name="rightMargin"> | 1991 | <property name="rightMargin"> |
| 1992 | <number>0</number> | 1992 | <number>0</number> |
| 1993 | </property> | 1993 | </property> |
| 1994 | <property name="bottomMargin"> | 1994 | <property name="bottomMargin"> |
| 1995 | <number>0</number> | 1995 | <number>0</number> |
| 1996 | </property> | 1996 | </property> |
| 1997 | </layout> | 1997 | </layout> |
| 1998 | </widget> | 1998 | </widget> |
| 1999 | </item> | 1999 | </item> |
| 2000 | <item> | 2000 | <item> |
| 2001 | <layout class="QHBoxLayout" name="miscButtons"> | 2001 | <layout class="QHBoxLayout" name="miscButtons"> |
| 2002 | <property name="spacing"> | 2002 | <property name="spacing"> |
| @@ -3087,6 +3087,14 @@ | |||
| 3087 | </item> | 3087 | </item> |
| 3088 | </layout> | 3088 | </layout> |
| 3089 | </widget> | 3089 | </widget> |
| 3090 | <customwidgets> | ||
| 3091 | <customwidget> | ||
| 3092 | <class>PlayerControlPreview</class> | ||
| 3093 | <extends>QFrame</extends> | ||
| 3094 | <header>yuzu/configuration/configure_input_player_widget.h</header> | ||
| 3095 | <container>1</container> | ||
| 3096 | </customwidget> | ||
| 3097 | </customwidgets> | ||
| 3090 | <resources> | 3098 | <resources> |
| 3091 | <include location="../../../dist/icons/controller/controller.qrc"/> | 3099 | <include location="../../../dist/icons/controller/controller.qrc"/> |
| 3092 | </resources> | 3100 | </resources> |
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp new file mode 100644 index 000000000..e3e8bde48 --- /dev/null +++ b/src/yuzu/configuration/configure_input_player_widget.cpp | |||
| @@ -0,0 +1,2694 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <QMenu> | ||
| 7 | #include <QPainter> | ||
| 8 | #include <QTimer> | ||
| 9 | #include "yuzu/configuration/configure_input_player_widget.h" | ||
| 10 | |||
| 11 | PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) { | ||
| 12 | UpdateColors(); | ||
| 13 | QTimer* timer = new QTimer(this); | ||
| 14 | connect(timer, &QTimer::timeout, this, QOverload<>::of(&PlayerControlPreview::UpdateInput)); | ||
| 15 | |||
| 16 | // refresh at 60hz | ||
| 17 | timer->start(16); | ||
| 18 | } | ||
| 19 | |||
| 20 | PlayerControlPreview::~PlayerControlPreview() = default; | ||
| 21 | |||
| 22 | void PlayerControlPreview::SetPlayerInput(std::size_t index, const ButtonParam& buttons_param, | ||
| 23 | const AnalogParam& analogs_param) { | ||
| 24 | player_index = index; | ||
| 25 | Settings::ButtonsRaw buttonss; | ||
| 26 | Settings::AnalogsRaw analogs; | ||
| 27 | std::transform(buttons_param.begin(), buttons_param.end(), buttonss.begin(), | ||
| 28 | [](const Common::ParamPackage& param) { return param.Serialize(); }); | ||
| 29 | std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(), | ||
| 30 | [](const Common::ParamPackage& param) { return param.Serialize(); }); | ||
| 31 | |||
| 32 | std::transform(buttonss.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | ||
| 33 | buttonss.begin() + Settings::NativeButton::BUTTON_NS_END, buttons.begin(), | ||
| 34 | Input::CreateDevice<Input::ButtonDevice>); | ||
| 35 | std::transform(analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, | ||
| 36 | analogs.begin() + Settings::NativeAnalog::STICK_HID_END, sticks.begin(), | ||
| 37 | Input::CreateDevice<Input::AnalogDevice>); | ||
| 38 | UpdateColors(); | ||
| 39 | } | ||
| 40 | void PlayerControlPreview::SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw buttons_, | ||
| 41 | Settings::AnalogsRaw analogs_) { | ||
| 42 | player_index = index; | ||
| 43 | std::transform(buttons_.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | ||
| 44 | buttons_.begin() + Settings::NativeButton::BUTTON_NS_END, buttons.begin(), | ||
| 45 | Input::CreateDevice<Input::ButtonDevice>); | ||
| 46 | std::transform(analogs_.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, | ||
| 47 | analogs_.begin() + Settings::NativeAnalog::STICK_HID_END, sticks.begin(), | ||
| 48 | Input::CreateDevice<Input::AnalogDevice>); | ||
| 49 | UpdateColors(); | ||
| 50 | } | ||
| 51 | |||
| 52 | PlayerControlPreview::LedPattern PlayerControlPreview::GetColorPattern(std::size_t index, | ||
| 53 | bool player_on) { | ||
| 54 | if (!player_on) { | ||
| 55 | return {0, 0, 0, 0}; | ||
| 56 | } | ||
| 57 | |||
| 58 | switch (index) { | ||
| 59 | case 0: | ||
| 60 | return {1, 0, 0, 0}; | ||
| 61 | case 1: | ||
| 62 | return {1, 1, 0, 0}; | ||
| 63 | case 2: | ||
| 64 | return {1, 1, 1, 0}; | ||
| 65 | case 3: | ||
| 66 | return {1, 1, 1, 1}; | ||
| 67 | case 4: | ||
| 68 | return {1, 0, 0, 1}; | ||
| 69 | case 5: | ||
| 70 | return {1, 0, 1, 0}; | ||
| 71 | case 6: | ||
| 72 | return {1, 0, 1, 1}; | ||
| 73 | case 7: | ||
| 74 | return {0, 1, 1, 0}; | ||
| 75 | default: | ||
| 76 | return {0, 0, 0, 0}; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | void PlayerControlPreview::SetConnectedStatus(bool checked) { | ||
| 81 | LedPattern led_pattern = GetColorPattern(player_index, checked); | ||
| 82 | |||
| 83 | led_color[0] = led_pattern.position1 ? colors.led_on : colors.led_off; | ||
| 84 | led_color[1] = led_pattern.position2 ? colors.led_on : colors.led_off; | ||
| 85 | led_color[2] = led_pattern.position3 ? colors.led_on : colors.led_off; | ||
| 86 | led_color[3] = led_pattern.position4 ? colors.led_on : colors.led_off; | ||
| 87 | } | ||
| 88 | |||
| 89 | void PlayerControlPreview::SetControllerType(const Settings::ControllerType type) { | ||
| 90 | controller_type = type; | ||
| 91 | UpdateColors(); | ||
| 92 | } | ||
| 93 | |||
| 94 | void PlayerControlPreview::BeginMappingButton(std::size_t index) { | ||
| 95 | button_mapping_index = index; | ||
| 96 | mapping_active = true; | ||
| 97 | } | ||
| 98 | |||
| 99 | void PlayerControlPreview::BeginMappingAnalog(std::size_t index) { | ||
| 100 | button_mapping_index = Settings::NativeButton::LStick + index; | ||
| 101 | analog_mapping_index = index; | ||
| 102 | mapping_active = true; | ||
| 103 | } | ||
| 104 | |||
| 105 | void PlayerControlPreview::EndMapping() { | ||
| 106 | button_mapping_index = Settings::NativeButton::BUTTON_NS_END; | ||
| 107 | analog_mapping_index = Settings::NativeAnalog::NumAnalogs; | ||
| 108 | mapping_active = false; | ||
| 109 | blink_counter = 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | void PlayerControlPreview::UpdateColors() { | ||
| 113 | if (QIcon::themeName().contains(QStringLiteral("dark")) || | ||
| 114 | QIcon::themeName().contains(QStringLiteral("midnight"))) { | ||
| 115 | colors.primary = QColor(204, 204, 204); | ||
| 116 | colors.button = QColor(35, 38, 41); | ||
| 117 | colors.button2 = QColor(26, 27, 30); | ||
| 118 | colors.slider_arrow = QColor(14, 15, 18); | ||
| 119 | colors.font2 = QColor(255, 255, 255); | ||
| 120 | colors.indicator = QColor(170, 238, 255); | ||
| 121 | colors.deadzone = QColor(204, 136, 136); | ||
| 122 | colors.slider_button = colors.button; | ||
| 123 | } | ||
| 124 | |||
| 125 | if (QIcon::themeName().contains(QStringLiteral("dark"))) { | ||
| 126 | colors.outline = QColor(160, 160, 160); | ||
| 127 | } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) { | ||
| 128 | colors.outline = QColor(145, 145, 145); | ||
| 129 | } else { | ||
| 130 | colors.outline = QColor(0, 0, 0); | ||
| 131 | colors.primary = QColor(225, 225, 225); | ||
| 132 | colors.button = QColor(109, 111, 114); | ||
| 133 | colors.button2 = QColor(109, 111, 114); | ||
| 134 | colors.button2 = QColor(77, 80, 84); | ||
| 135 | colors.slider_arrow = QColor(65, 68, 73); | ||
| 136 | colors.font2 = QColor(0, 0, 0); | ||
| 137 | colors.indicator = QColor(0, 0, 200); | ||
| 138 | colors.deadzone = QColor(170, 0, 0); | ||
| 139 | colors.slider_button = QColor(153, 149, 149); | ||
| 140 | } | ||
| 141 | |||
| 142 | // Constant colors | ||
| 143 | colors.highlight = QColor(170, 0, 0); | ||
| 144 | colors.highlight2 = QColor(119, 0, 0); | ||
| 145 | colors.slider = QColor(103, 106, 110); | ||
| 146 | colors.transparent = QColor(0, 0, 0, 0); | ||
| 147 | colors.font = QColor(255, 255, 255); | ||
| 148 | colors.led_on = QColor(255, 255, 0); | ||
| 149 | colors.led_off = QColor(170, 238, 255); | ||
| 150 | |||
| 151 | colors.left = colors.primary; | ||
| 152 | colors.right = colors.primary; | ||
| 153 | // Possible alternative to set colors from settings | ||
| 154 | // colors.left = QColor(Settings::values.players.GetValue()[player_index].body_color_left); | ||
| 155 | // colors.right = QColor(Settings::values.players.GetValue()[player_index].body_color_right); | ||
| 156 | } | ||
| 157 | |||
| 158 | void PlayerControlPreview::UpdateInput() { | ||
| 159 | bool input_changed = false; | ||
| 160 | const auto& button_state = buttons; | ||
| 161 | for (std::size_t index = 0; index < button_values.size(); ++index) { | ||
| 162 | bool value = false; | ||
| 163 | if (index < Settings::NativeButton::BUTTON_NS_END) { | ||
| 164 | value = button_state[index]->GetStatus(); | ||
| 165 | } | ||
| 166 | bool blink = mapping_active && index == button_mapping_index; | ||
| 167 | if (analog_mapping_index == Settings::NativeAnalog::NUM_STICKS_HID) { | ||
| 168 | blink &= blink_counter > 25; | ||
| 169 | } | ||
| 170 | if (button_values[index] != value || blink) { | ||
| 171 | input_changed = true; | ||
| 172 | } | ||
| 173 | button_values[index] = value || blink; | ||
| 174 | } | ||
| 175 | |||
| 176 | const auto& analog_state = sticks; | ||
| 177 | for (std::size_t index = 0; index < axis_values.size(); ++index) { | ||
| 178 | const auto [stick_x_f, stick_y_f] = analog_state[index]->GetStatus(); | ||
| 179 | const auto [stick_x_rf, stick_y_rf] = analog_state[index]->GetRawStatus(); | ||
| 180 | |||
| 181 | if (static_cast<int>(stick_x_rf * 45) != | ||
| 182 | static_cast<int>(axis_values[index].raw_value.x() * 45) || | ||
| 183 | static_cast<int>(-stick_y_rf * 45) != | ||
| 184 | static_cast<int>(axis_values[index].raw_value.y() * 45)) { | ||
| 185 | input_changed = true; | ||
| 186 | } | ||
| 187 | |||
| 188 | axis_values[index].properties = analog_state[index]->GetAnalogProperties(); | ||
| 189 | axis_values[index].value = QPointF(stick_x_f, -stick_y_f); | ||
| 190 | axis_values[index].raw_value = QPointF(stick_x_rf, -stick_y_rf); | ||
| 191 | |||
| 192 | const bool blink_analog = mapping_active && index == analog_mapping_index; | ||
| 193 | if (blink_analog) { | ||
| 194 | input_changed = true; | ||
| 195 | axis_values[index].value = | ||
| 196 | QPointF(blink_counter < 25 ? -blink_counter / 25.0f : 0, | ||
| 197 | blink_counter > 25 ? -(blink_counter - 25) / 25.0f : 0); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | if (input_changed) { | ||
| 202 | update(); | ||
| 203 | } | ||
| 204 | |||
| 205 | if (mapping_active) { | ||
| 206 | blink_counter = (blink_counter + 1) % 50; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | void PlayerControlPreview::paintEvent(QPaintEvent* event) { | ||
| 211 | QFrame::paintEvent(event); | ||
| 212 | QPainter p(this); | ||
| 213 | p.setRenderHint(QPainter::Antialiasing); | ||
| 214 | const QPointF center = rect().center(); | ||
| 215 | |||
| 216 | switch (controller_type) { | ||
| 217 | case Settings::ControllerType::Handheld: | ||
| 218 | DrawHandheldController(p, center); | ||
| 219 | break; | ||
| 220 | case Settings::ControllerType::DualJoyconDetached: | ||
| 221 | DrawDualController(p, center); | ||
| 222 | break; | ||
| 223 | case Settings::ControllerType::LeftJoycon: | ||
| 224 | DrawLeftController(p, center); | ||
| 225 | break; | ||
| 226 | case Settings::ControllerType::RightJoycon: | ||
| 227 | DrawRightController(p, center); | ||
| 228 | break; | ||
| 229 | case Settings::ControllerType::ProController: | ||
| 230 | default: | ||
| 231 | DrawProController(p, center); | ||
| 232 | break; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) { | ||
| 237 | { | ||
| 238 | using namespace Settings::NativeButton; | ||
| 239 | |||
| 240 | // Sideview left joystick | ||
| 241 | DrawJoystickSideview(p, center + QPoint(142, -69), | ||
| 242 | -axis_values[Settings::NativeAnalog::LStick].value.y(), 1.15f, | ||
| 243 | button_values[LStick]); | ||
| 244 | |||
| 245 | // Topview D-pad buttons | ||
| 246 | p.setPen(colors.outline); | ||
| 247 | button_color = colors.button; | ||
| 248 | DrawRoundButton(p, center + QPoint(-163, -21), button_values[DLeft], 11, 5, Direction::Up); | ||
| 249 | DrawRoundButton(p, center + QPoint(-117, -21), button_values[DRight], 11, 5, Direction::Up); | ||
| 250 | |||
| 251 | // Topview left joystick | ||
| 252 | DrawJoystickSideview(p, center + QPointF(-140.5f, -28), | ||
| 253 | -axis_values[Settings::NativeAnalog::LStick].value.x() + 15.0f, 1.15f, | ||
| 254 | button_values[LStick]); | ||
| 255 | |||
| 256 | // Topview minus button | ||
| 257 | p.setPen(colors.outline); | ||
| 258 | button_color = colors.button; | ||
| 259 | DrawRoundButton(p, center + QPoint(-111, -22), button_values[Minus], 8, 4, Direction::Up, | ||
| 260 | 1); | ||
| 261 | |||
| 262 | // Left trigger | ||
| 263 | DrawLeftTriggers(p, center, button_values[L]); | ||
| 264 | DrawRoundButton(p, center + QPoint(151, -146), button_values[L], 8, 4, Direction::Down); | ||
| 265 | DrawLeftZTriggers(p, center, button_values[ZL]); | ||
| 266 | |||
| 267 | // Sideview D-pad buttons | ||
| 268 | DrawRoundButton(p, center + QPoint(135, 14), button_values[DLeft], 5, 11, Direction::Right); | ||
| 269 | DrawRoundButton(p, center + QPoint(135, 36), button_values[DDown], 5, 11, Direction::Right); | ||
| 270 | DrawRoundButton(p, center + QPoint(135, -10), button_values[DUp], 5, 11, Direction::Right); | ||
| 271 | DrawRoundButton(p, center + QPoint(135, 14), button_values[DRight], 5, 11, | ||
| 272 | Direction::Right); | ||
| 273 | DrawRoundButton(p, center + QPoint(135, 71), button_values[Screenshot], 3, 8, | ||
| 274 | Direction::Right, 1); | ||
| 275 | |||
| 276 | // Sideview minus button | ||
| 277 | DrawRoundButton(p, center + QPoint(135, -118), button_values[Minus], 4, 2.66f, | ||
| 278 | Direction::Right, 1); | ||
| 279 | |||
| 280 | // Sideview SL and SR buttons | ||
| 281 | button_color = colors.slider_button; | ||
| 282 | DrawRoundButton(p, center + QPoint(59, 52), button_values[SR], 5, 12, Direction::Left); | ||
| 283 | DrawRoundButton(p, center + QPoint(59, -69), button_values[SL], 5, 12, Direction::Left); | ||
| 284 | |||
| 285 | DrawLeftBody(p, center); | ||
| 286 | |||
| 287 | // Left trigger top view | ||
| 288 | DrawLeftTriggersTopView(p, center, button_values[L]); | ||
| 289 | DrawLeftZTriggersTopView(p, center, button_values[ZL]); | ||
| 290 | } | ||
| 291 | |||
| 292 | { | ||
| 293 | // Draw joysticks | ||
| 294 | using namespace Settings::NativeAnalog; | ||
| 295 | DrawJoystick(p, center + QPointF(9, -69) + (axis_values[LStick].value * 8), 1.8f, | ||
| 296 | button_values[Settings::NativeButton::LStick]); | ||
| 297 | DrawRawJoystick(p, center + QPointF(-140, 90), axis_values[LStick].raw_value, | ||
| 298 | axis_values[LStick].properties); | ||
| 299 | } | ||
| 300 | |||
| 301 | using namespace Settings::NativeButton; | ||
| 302 | |||
| 303 | // D-pad constants | ||
| 304 | const QPointF dpad_center = center + QPoint(9, 14); | ||
| 305 | constexpr int dpad_distance = 23; | ||
| 306 | constexpr int dpad_radius = 11; | ||
| 307 | constexpr float dpad_arrow_size = 1.2f; | ||
| 308 | |||
| 309 | // D-pad buttons | ||
| 310 | p.setPen(colors.outline); | ||
| 311 | button_color = colors.button; | ||
| 312 | DrawCircleButton(p, dpad_center + QPoint(dpad_distance, 0), button_values[DRight], dpad_radius); | ||
| 313 | DrawCircleButton(p, dpad_center + QPoint(0, dpad_distance), button_values[DDown], dpad_radius); | ||
| 314 | DrawCircleButton(p, dpad_center + QPoint(0, -dpad_distance), button_values[DUp], dpad_radius); | ||
| 315 | DrawCircleButton(p, dpad_center + QPoint(-dpad_distance, 0), button_values[DLeft], dpad_radius); | ||
| 316 | |||
| 317 | // D-pad arrows | ||
| 318 | p.setPen(colors.font2); | ||
| 319 | p.setBrush(colors.font2); | ||
| 320 | DrawArrow(p, dpad_center + QPoint(dpad_distance, 0), Direction::Right, dpad_arrow_size); | ||
| 321 | DrawArrow(p, dpad_center + QPoint(0, dpad_distance), Direction::Down, dpad_arrow_size); | ||
| 322 | DrawArrow(p, dpad_center + QPoint(0, -dpad_distance), Direction::Up, dpad_arrow_size); | ||
| 323 | DrawArrow(p, dpad_center + QPoint(-dpad_distance, 0), Direction::Left, dpad_arrow_size); | ||
| 324 | |||
| 325 | // SR and SL buttons | ||
| 326 | p.setPen(colors.outline); | ||
| 327 | button_color = colors.slider_button; | ||
| 328 | DrawRoundButton(p, center + QPoint(155, 52), button_values[SR], 5.2f, 12, Direction::None, 4); | ||
| 329 | DrawRoundButton(p, center + QPoint(155, -69), button_values[SL], 5.2f, 12, Direction::None, 4); | ||
| 330 | |||
| 331 | // SR and SL text | ||
| 332 | p.setPen(colors.transparent); | ||
| 333 | p.setBrush(colors.font2); | ||
| 334 | DrawSymbol(p, center + QPointF(155, 52), Symbol::SR, 1.0f); | ||
| 335 | DrawSymbol(p, center + QPointF(155, -69), Symbol::SL, 1.0f); | ||
| 336 | |||
| 337 | // Minus button | ||
| 338 | button_color = colors.button; | ||
| 339 | DrawMinusButton(p, center + QPoint(39, -118), button_values[Minus], 16); | ||
| 340 | |||
| 341 | // Screenshot button | ||
| 342 | DrawRoundButton(p, center + QPoint(26, 71), button_values[Screenshot], 8, 8); | ||
| 343 | p.setPen(colors.font2); | ||
| 344 | p.setBrush(colors.font2); | ||
| 345 | DrawCircle(p, center + QPoint(26, 71), 5); | ||
| 346 | } | ||
| 347 | |||
| 348 | void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center) { | ||
| 349 | { | ||
| 350 | using namespace Settings::NativeButton; | ||
| 351 | |||
| 352 | // Sideview right joystick | ||
| 353 | DrawJoystickSideview(p, center + QPoint(173 - 315, 11), | ||
| 354 | axis_values[Settings::NativeAnalog::RStick].value.y() + 10.0f, 1.15f, | ||
| 355 | button_values[Settings::NativeButton::RStick]); | ||
| 356 | |||
| 357 | // Topview face buttons | ||
| 358 | p.setPen(colors.outline); | ||
| 359 | button_color = colors.button; | ||
| 360 | DrawRoundButton(p, center + QPoint(163, -21), button_values[A], 11, 5, Direction::Up); | ||
| 361 | DrawRoundButton(p, center + QPoint(117, -21), button_values[Y], 11, 5, Direction::Up); | ||
| 362 | |||
| 363 | // Topview right joystick | ||
| 364 | DrawJoystickSideview(p, center + QPointF(140, -28), | ||
| 365 | -axis_values[Settings::NativeAnalog::RStick].value.x() + 15.0f, 1.15f, | ||
| 366 | button_values[RStick]); | ||
| 367 | |||
| 368 | // Topview plus button | ||
| 369 | p.setPen(colors.outline); | ||
| 370 | button_color = colors.button; | ||
| 371 | DrawRoundButton(p, center + QPoint(111, -22), button_values[Plus], 8, 4, Direction::Up, 1); | ||
| 372 | DrawRoundButton(p, center + QPoint(111, -22), button_values[Plus], 2.66f, 4, Direction::Up, | ||
| 373 | 1); | ||
| 374 | |||
| 375 | // Right trigger | ||
| 376 | p.setPen(colors.outline); | ||
| 377 | button_color = colors.button; | ||
| 378 | DrawRightTriggers(p, center, button_values[R]); | ||
| 379 | DrawRoundButton(p, center + QPoint(-151, -146), button_values[R], 8, 4, Direction::Down); | ||
| 380 | DrawRightZTriggers(p, center, button_values[ZR]); | ||
| 381 | |||
| 382 | // Sideview face buttons | ||
| 383 | DrawRoundButton(p, center + QPoint(-135, -73), button_values[A], 5, 11, Direction::Left); | ||
| 384 | DrawRoundButton(p, center + QPoint(-135, -50), button_values[B], 5, 11, Direction::Left); | ||
| 385 | DrawRoundButton(p, center + QPoint(-135, -95), button_values[X], 5, 11, Direction::Left); | ||
| 386 | DrawRoundButton(p, center + QPoint(-135, -73), button_values[Y], 5, 11, Direction::Left); | ||
| 387 | |||
| 388 | // Sideview home and plus button | ||
| 389 | DrawRoundButton(p, center + QPoint(-135, 66), button_values[Home], 3, 12, Direction::Left); | ||
| 390 | DrawRoundButton(p, center + QPoint(-135, -118), button_values[Plus], 4, 8, Direction::Left, | ||
| 391 | 1); | ||
| 392 | DrawRoundButton(p, center + QPoint(-135, -118), button_values[Plus], 4, 2.66f, | ||
| 393 | Direction::Left, 1); | ||
| 394 | |||
| 395 | // Sideview SL and SR buttons | ||
| 396 | button_color = colors.slider_button; | ||
| 397 | DrawRoundButton(p, center + QPoint(-59, 52), button_values[SL], 5, 11, Direction::Right); | ||
| 398 | DrawRoundButton(p, center + QPoint(-59, -69), button_values[SR], 5, 11, Direction::Right); | ||
| 399 | |||
| 400 | DrawRightBody(p, center); | ||
| 401 | |||
| 402 | // Right trigger top view | ||
| 403 | DrawRightTriggersTopView(p, center, button_values[R]); | ||
| 404 | DrawRightZTriggersTopView(p, center, button_values[ZR]); | ||
| 405 | } | ||
| 406 | |||
| 407 | { | ||
| 408 | // Draw joysticks | ||
| 409 | using namespace Settings::NativeAnalog; | ||
| 410 | DrawJoystick(p, center + QPointF(-9, 11) + (axis_values[RStick].value * 8), 1.8f, | ||
| 411 | button_values[Settings::NativeButton::RStick]); | ||
| 412 | DrawRawJoystick(p, center + QPointF(140, 90), axis_values[RStick].raw_value, | ||
| 413 | axis_values[RStick].properties); | ||
| 414 | } | ||
| 415 | |||
| 416 | using namespace Settings::NativeButton; | ||
| 417 | |||
| 418 | // Face buttons constants | ||
| 419 | const QPointF face_center = center + QPoint(-9, -73); | ||
| 420 | constexpr int face_distance = 23; | ||
| 421 | constexpr int face_radius = 11; | ||
| 422 | constexpr float text_size = 1.1f; | ||
| 423 | |||
| 424 | // Face buttons | ||
| 425 | p.setPen(colors.outline); | ||
| 426 | button_color = colors.button; | ||
| 427 | DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius); | ||
| 428 | DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius); | ||
| 429 | DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius); | ||
| 430 | DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); | ||
| 431 | |||
| 432 | // Face buttons text | ||
| 433 | p.setPen(colors.transparent); | ||
| 434 | p.setBrush(colors.font); | ||
| 435 | DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size); | ||
| 436 | DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size); | ||
| 437 | DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size); | ||
| 438 | DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size); | ||
| 439 | |||
| 440 | // SR and SL buttons | ||
| 441 | p.setPen(colors.outline); | ||
| 442 | button_color = colors.slider_button; | ||
| 443 | DrawRoundButton(p, center + QPoint(-155, 52), button_values[SL], 5, 12, Direction::None, 4.0f); | ||
| 444 | DrawRoundButton(p, center + QPoint(-155, -69), button_values[SR], 5, 12, Direction::None, 4.0f); | ||
| 445 | |||
| 446 | // SR and SL text | ||
| 447 | p.setPen(colors.transparent); | ||
| 448 | p.setBrush(colors.font2); | ||
| 449 | p.rotate(-180); | ||
| 450 | DrawSymbol(p, QPointF(-center.x(), -center.y()) + QPointF(155, 69), Symbol::SR, 1.0f); | ||
| 451 | DrawSymbol(p, QPointF(-center.x(), -center.y()) + QPointF(155, -52), Symbol::SL, 1.0f); | ||
| 452 | p.rotate(180); | ||
| 453 | |||
| 454 | // Plus Button | ||
| 455 | DrawPlusButton(p, center + QPoint(-40, -118), button_values[Plus], 16); | ||
| 456 | |||
| 457 | // Home Button | ||
| 458 | p.setPen(colors.outline); | ||
| 459 | button_color = colors.slider_button; | ||
| 460 | DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 12); | ||
| 461 | button_color = colors.button; | ||
| 462 | DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 9); | ||
| 463 | p.setPen(colors.transparent); | ||
| 464 | p.setBrush(colors.font2); | ||
| 465 | DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5); | ||
| 466 | } | ||
| 467 | |||
| 468 | void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) { | ||
| 469 | { | ||
| 470 | using namespace Settings::NativeButton; | ||
| 471 | |||
| 472 | // Left/Right trigger | ||
| 473 | DrawDualTriggers(p, center, button_values[L], button_values[R]); | ||
| 474 | |||
| 475 | // Topview face buttons | ||
| 476 | p.setPen(colors.outline); | ||
| 477 | button_color = colors.button; | ||
| 478 | DrawRoundButton(p, center + QPoint(200, -71), button_values[A], 10, 5, Direction::Up); | ||
| 479 | DrawRoundButton(p, center + QPoint(160, -71), button_values[Y], 10, 5, Direction::Up); | ||
| 480 | |||
| 481 | // Topview right joystick | ||
| 482 | DrawJoystickSideview(p, center + QPointF(180, -78), | ||
| 483 | -axis_values[Settings::NativeAnalog::RStick].value.x() + 15.0f, 1, | ||
| 484 | button_values[RStick]); | ||
| 485 | |||
| 486 | // Topview plus button | ||
| 487 | p.setPen(colors.outline); | ||
| 488 | button_color = colors.button; | ||
| 489 | DrawRoundButton(p, center + QPoint(154, -72), button_values[Plus], 7, 4, Direction::Up, 1); | ||
| 490 | DrawRoundButton(p, center + QPoint(154, -72), button_values[Plus], 2.33f, 4, Direction::Up, | ||
| 491 | 1); | ||
| 492 | |||
| 493 | // Topview D-pad buttons | ||
| 494 | p.setPen(colors.outline); | ||
| 495 | button_color = colors.button; | ||
| 496 | DrawRoundButton(p, center + QPoint(-200, -71), button_values[DLeft], 10, 5, Direction::Up); | ||
| 497 | DrawRoundButton(p, center + QPoint(-160, -71), button_values[DRight], 10, 5, Direction::Up); | ||
| 498 | |||
| 499 | // Topview left joystick | ||
| 500 | DrawJoystickSideview(p, center + QPointF(-180.5f, -78), | ||
| 501 | -axis_values[Settings::NativeAnalog::LStick].value.x() + 15.0f, 1, | ||
| 502 | button_values[LStick]); | ||
| 503 | |||
| 504 | // Topview minus button | ||
| 505 | p.setPen(colors.outline); | ||
| 506 | button_color = colors.button; | ||
| 507 | DrawRoundButton(p, center + QPoint(-154, -72), button_values[Minus], 7, 4, Direction::Up, | ||
| 508 | 1); | ||
| 509 | |||
| 510 | DrawDualBody(p, center); | ||
| 511 | |||
| 512 | // Right trigger top view | ||
| 513 | DrawDualTriggersTopView(p, center, button_values[L], button_values[R]); | ||
| 514 | DrawDualZTriggersTopView(p, center, button_values[ZL], button_values[ZR]); | ||
| 515 | } | ||
| 516 | |||
| 517 | { | ||
| 518 | // Draw joysticks | ||
| 519 | using namespace Settings::NativeAnalog; | ||
| 520 | DrawJoystick(p, center + QPointF(-65, -65) + (axis_values[LStick].value * 7), 1.62f, | ||
| 521 | button_values[Settings::NativeButton::LStick]); | ||
| 522 | DrawJoystick(p, center + QPointF(65, 12) + (axis_values[RStick].value * 7), 1.62f, | ||
| 523 | button_values[Settings::NativeButton::RStick]); | ||
| 524 | DrawRawJoystick(p, center + QPointF(-180, 90), axis_values[LStick].raw_value, | ||
| 525 | axis_values[LStick].properties); | ||
| 526 | DrawRawJoystick(p, center + QPointF(180, 90), axis_values[RStick].raw_value, | ||
| 527 | axis_values[RStick].properties); | ||
| 528 | } | ||
| 529 | |||
| 530 | using namespace Settings::NativeButton; | ||
| 531 | |||
| 532 | // Face buttons constants | ||
| 533 | const QPointF face_center = center + QPoint(65, -65); | ||
| 534 | constexpr int face_distance = 20; | ||
| 535 | constexpr int face_radius = 10; | ||
| 536 | constexpr float text_size = 1.0f; | ||
| 537 | |||
| 538 | // Face buttons | ||
| 539 | p.setPen(colors.outline); | ||
| 540 | button_color = colors.button; | ||
| 541 | DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius); | ||
| 542 | DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius); | ||
| 543 | DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius); | ||
| 544 | DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); | ||
| 545 | |||
| 546 | // Face buttons text | ||
| 547 | p.setPen(colors.transparent); | ||
| 548 | p.setBrush(colors.font); | ||
| 549 | DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size); | ||
| 550 | DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size); | ||
| 551 | DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size); | ||
| 552 | DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size); | ||
| 553 | |||
| 554 | // D-pad constants | ||
| 555 | const QPointF dpad_center = center + QPoint(-65, 12); | ||
| 556 | constexpr int dpad_distance = 20; | ||
| 557 | constexpr int dpad_radius = 10; | ||
| 558 | constexpr float dpad_arrow_size = 1.1f; | ||
| 559 | |||
| 560 | // D-pad buttons | ||
| 561 | p.setPen(colors.outline); | ||
| 562 | button_color = colors.button; | ||
| 563 | DrawCircleButton(p, dpad_center + QPoint(dpad_distance, 0), button_values[DRight], dpad_radius); | ||
| 564 | DrawCircleButton(p, dpad_center + QPoint(0, dpad_distance), button_values[DDown], dpad_radius); | ||
| 565 | DrawCircleButton(p, dpad_center + QPoint(0, -dpad_distance), button_values[DUp], dpad_radius); | ||
| 566 | DrawCircleButton(p, dpad_center + QPoint(-dpad_distance, 0), button_values[DLeft], dpad_radius); | ||
| 567 | |||
| 568 | // D-pad arrows | ||
| 569 | p.setPen(colors.font2); | ||
| 570 | p.setBrush(colors.font2); | ||
| 571 | DrawArrow(p, dpad_center + QPoint(dpad_distance, 0), Direction::Right, dpad_arrow_size); | ||
| 572 | DrawArrow(p, dpad_center + QPoint(0, dpad_distance), Direction::Down, dpad_arrow_size); | ||
| 573 | DrawArrow(p, dpad_center + QPoint(0, -dpad_distance), Direction::Up, dpad_arrow_size); | ||
| 574 | DrawArrow(p, dpad_center + QPoint(-dpad_distance, 0), Direction::Left, dpad_arrow_size); | ||
| 575 | |||
| 576 | // Minus and Plus button | ||
| 577 | button_color = colors.button; | ||
| 578 | DrawMinusButton(p, center + QPoint(-39, -106), button_values[Minus], 14); | ||
| 579 | DrawPlusButton(p, center + QPoint(39, -106), button_values[Plus], 14); | ||
| 580 | |||
| 581 | // Screenshot button | ||
| 582 | p.setPen(colors.outline); | ||
| 583 | DrawRoundButton(p, center + QPoint(-52, 63), button_values[Screenshot], 8, 8); | ||
| 584 | p.setPen(colors.font2); | ||
| 585 | p.setBrush(colors.font2); | ||
| 586 | DrawCircle(p, center + QPoint(-52, 63), 5); | ||
| 587 | |||
| 588 | // Home Button | ||
| 589 | p.setPen(colors.outline); | ||
| 590 | button_color = colors.slider_button; | ||
| 591 | DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 11); | ||
| 592 | button_color = colors.button; | ||
| 593 | DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 8.5f); | ||
| 594 | p.setPen(colors.transparent); | ||
| 595 | p.setBrush(colors.font2); | ||
| 596 | DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f); | ||
| 597 | } | ||
| 598 | |||
| 599 | void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) { | ||
| 600 | DrawHandheldTriggers(p, center, button_values[Settings::NativeButton::L], | ||
| 601 | button_values[Settings::NativeButton::R]); | ||
| 602 | DrawHandheldBody(p, center); | ||
| 603 | { | ||
| 604 | // Draw joysticks | ||
| 605 | using namespace Settings::NativeAnalog; | ||
| 606 | DrawJoystick(p, center + QPointF(-171, -41) + (axis_values[LStick].value * 4), 1.0f, | ||
| 607 | button_values[Settings::NativeButton::LStick]); | ||
| 608 | DrawJoystick(p, center + QPointF(171, 8) + (axis_values[RStick].value * 4), 1.0f, | ||
| 609 | button_values[Settings::NativeButton::RStick]); | ||
| 610 | DrawRawJoystick(p, center + QPointF(-50, 0), axis_values[LStick].raw_value, | ||
| 611 | axis_values[LStick].properties); | ||
| 612 | DrawRawJoystick(p, center + QPointF(50, 0), axis_values[RStick].raw_value, | ||
| 613 | axis_values[RStick].properties); | ||
| 614 | } | ||
| 615 | |||
| 616 | using namespace Settings::NativeButton; | ||
| 617 | |||
| 618 | // Face buttons constants | ||
| 619 | const QPointF face_center = center + QPoint(171, -41); | ||
| 620 | constexpr float face_distance = 12.8f; | ||
| 621 | constexpr float face_radius = 6.4f; | ||
| 622 | constexpr float text_size = 0.6f; | ||
| 623 | |||
| 624 | // Face buttons | ||
| 625 | p.setPen(colors.outline); | ||
| 626 | button_color = colors.button; | ||
| 627 | DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius); | ||
| 628 | DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius); | ||
| 629 | DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius); | ||
| 630 | DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); | ||
| 631 | |||
| 632 | // Face buttons text | ||
| 633 | p.setPen(colors.transparent); | ||
| 634 | p.setBrush(colors.font); | ||
| 635 | DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size); | ||
| 636 | DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size); | ||
| 637 | DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size); | ||
| 638 | DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size); | ||
| 639 | |||
| 640 | // D-pad constants | ||
| 641 | const QPointF dpad_center = center + QPoint(-171, 8); | ||
| 642 | constexpr float dpad_distance = 12.8f; | ||
| 643 | constexpr float dpad_radius = 6.4f; | ||
| 644 | constexpr float dpad_arrow_size = 0.68f; | ||
| 645 | |||
| 646 | // D-pad buttons | ||
| 647 | p.setPen(colors.outline); | ||
| 648 | button_color = colors.button; | ||
| 649 | DrawCircleButton(p, dpad_center + QPoint(dpad_distance, 0), button_values[DRight], dpad_radius); | ||
| 650 | DrawCircleButton(p, dpad_center + QPoint(0, dpad_distance), button_values[DDown], dpad_radius); | ||
| 651 | DrawCircleButton(p, dpad_center + QPoint(0, -dpad_distance), button_values[DUp], dpad_radius); | ||
| 652 | DrawCircleButton(p, dpad_center + QPoint(-dpad_distance, 0), button_values[DLeft], dpad_radius); | ||
| 653 | |||
| 654 | // D-pad arrows | ||
| 655 | p.setPen(colors.font2); | ||
| 656 | p.setBrush(colors.font2); | ||
| 657 | DrawArrow(p, dpad_center + QPoint(dpad_distance, 0), Direction::Right, dpad_arrow_size); | ||
| 658 | DrawArrow(p, dpad_center + QPoint(0, dpad_distance), Direction::Down, dpad_arrow_size); | ||
| 659 | DrawArrow(p, dpad_center + QPoint(0, -dpad_distance), Direction::Up, dpad_arrow_size); | ||
| 660 | DrawArrow(p, dpad_center + QPoint(-dpad_distance, 0), Direction::Left, dpad_arrow_size); | ||
| 661 | |||
| 662 | // ZL and ZR buttons | ||
| 663 | p.setPen(colors.outline); | ||
| 664 | DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]); | ||
| 665 | DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]); | ||
| 666 | p.setPen(colors.transparent); | ||
| 667 | p.setBrush(colors.font); | ||
| 668 | DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f); | ||
| 669 | DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f); | ||
| 670 | |||
| 671 | // Minus and Plus button | ||
| 672 | p.setPen(colors.outline); | ||
| 673 | button_color = colors.button; | ||
| 674 | DrawMinusButton(p, center + QPoint(-155, -67), button_values[Minus], 8); | ||
| 675 | DrawPlusButton(p, center + QPoint(155, -67), button_values[Plus], 8); | ||
| 676 | |||
| 677 | // Screenshot button | ||
| 678 | p.setPen(colors.outline); | ||
| 679 | DrawRoundButton(p, center + QPoint(-162, 39), button_values[Screenshot], 5, 5); | ||
| 680 | p.setPen(colors.font2); | ||
| 681 | p.setBrush(colors.font2); | ||
| 682 | DrawCircle(p, center + QPoint(-162, 39), 3); | ||
| 683 | |||
| 684 | // Home Button | ||
| 685 | p.setPen(colors.outline); | ||
| 686 | button_color = colors.slider_button; | ||
| 687 | DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 7); | ||
| 688 | button_color = colors.button; | ||
| 689 | DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 5); | ||
| 690 | p.setPen(colors.transparent); | ||
| 691 | p.setBrush(colors.font2); | ||
| 692 | DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f); | ||
| 693 | } | ||
| 694 | |||
| 695 | void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) { | ||
| 696 | DrawProTriggers(p, center, button_values[Settings::NativeButton::L], | ||
| 697 | button_values[Settings::NativeButton::R]); | ||
| 698 | DrawProBody(p, center); | ||
| 699 | { | ||
| 700 | // Draw joysticks | ||
| 701 | using namespace Settings::NativeAnalog; | ||
| 702 | DrawProJoystick(p, center + QPointF(-111, -55) + (axis_values[LStick].value * 11), | ||
| 703 | button_values[Settings::NativeButton::LStick]); | ||
| 704 | DrawProJoystick(p, center + QPointF(51, 0) + (axis_values[RStick].value * 11), | ||
| 705 | button_values[Settings::NativeButton::RStick]); | ||
| 706 | DrawRawJoystick(p, center + QPointF(-50, 105), axis_values[LStick].raw_value, | ||
| 707 | axis_values[LStick].properties); | ||
| 708 | DrawRawJoystick(p, center + QPointF(50, 105), axis_values[RStick].raw_value, | ||
| 709 | axis_values[RStick].properties); | ||
| 710 | } | ||
| 711 | |||
| 712 | using namespace Settings::NativeButton; | ||
| 713 | |||
| 714 | // Face buttons constants | ||
| 715 | const QPointF face_center = center + QPoint(105, -56); | ||
| 716 | constexpr int face_distance = 31; | ||
| 717 | constexpr int face_radius = 15; | ||
| 718 | constexpr float text_size = 1.5f; | ||
| 719 | |||
| 720 | // Face buttons | ||
| 721 | p.setPen(colors.outline); | ||
| 722 | button_color = colors.button; | ||
| 723 | DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius); | ||
| 724 | DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius); | ||
| 725 | DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius); | ||
| 726 | DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); | ||
| 727 | |||
| 728 | // Face buttons text | ||
| 729 | p.setPen(colors.transparent); | ||
| 730 | p.setBrush(colors.font); | ||
| 731 | DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size); | ||
| 732 | DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size); | ||
| 733 | DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size); | ||
| 734 | DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size); | ||
| 735 | |||
| 736 | // D-pad buttons | ||
| 737 | const QPointF dpad_postion = center + QPoint(-61, 0); | ||
| 738 | DrawArrowButton(p, dpad_postion, Direction::Up, button_values[DUp]); | ||
| 739 | DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft]); | ||
| 740 | DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight]); | ||
| 741 | DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown]); | ||
| 742 | DrawArrowButtonOutline(p, dpad_postion); | ||
| 743 | |||
| 744 | // ZL and ZR buttons | ||
| 745 | p.setPen(colors.outline); | ||
| 746 | DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]); | ||
| 747 | DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]); | ||
| 748 | p.setPen(colors.transparent); | ||
| 749 | p.setBrush(colors.font); | ||
| 750 | DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f); | ||
| 751 | DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f); | ||
| 752 | |||
| 753 | // Minus and Plus buttons | ||
| 754 | p.setPen(colors.outline); | ||
| 755 | DrawCircleButton(p, center + QPoint(-50, -86), button_values[Minus], 9); | ||
| 756 | DrawCircleButton(p, center + QPoint(50, -86), button_values[Plus], 9); | ||
| 757 | |||
| 758 | // Minus and Plus symbols | ||
| 759 | p.setPen(colors.font2); | ||
| 760 | p.setBrush(colors.font2); | ||
| 761 | DrawRectangle(p, center + QPoint(-50, -86), 9, 1.5f); | ||
| 762 | DrawRectangle(p, center + QPoint(50, -86), 9, 1.5f); | ||
| 763 | DrawRectangle(p, center + QPoint(50, -86), 1.5f, 9); | ||
| 764 | |||
| 765 | // Screenshot button | ||
| 766 | p.setPen(colors.outline); | ||
| 767 | DrawRoundButton(p, center + QPoint(-29, -56), button_values[Screenshot], 7, 7); | ||
| 768 | p.setPen(colors.font2); | ||
| 769 | p.setBrush(colors.font2); | ||
| 770 | DrawCircle(p, center + QPoint(-29, -56), 4.5f); | ||
| 771 | |||
| 772 | // Home Button | ||
| 773 | p.setPen(colors.outline); | ||
| 774 | button_color = colors.slider_button; | ||
| 775 | DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 10.0f); | ||
| 776 | button_color = colors.button; | ||
| 777 | DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 7.1f); | ||
| 778 | p.setPen(colors.transparent); | ||
| 779 | p.setBrush(colors.font2); | ||
| 780 | DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f); | ||
| 781 | } | ||
| 782 | |||
| 783 | void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { | ||
| 784 | DrawGCTriggers(p, center, button_values[Settings::NativeButton::ZL], | ||
| 785 | button_values[Settings::NativeButton::ZR]); | ||
| 786 | DrawGCButtonZ(p, center, button_values[Settings::NativeButton::R]); | ||
| 787 | DrawGCBody(p, center); | ||
| 788 | { | ||
| 789 | // Draw joysticks | ||
| 790 | using namespace Settings::NativeAnalog; | ||
| 791 | DrawGCJoystick(p, center + QPointF(-111, -44) + (axis_values[LStick].value * 10), false); | ||
| 792 | button_color = colors.button2; | ||
| 793 | DrawCircleButton(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), false, | ||
| 794 | 15); | ||
| 795 | p.setPen(colors.transparent); | ||
| 796 | p.setBrush(colors.font); | ||
| 797 | DrawSymbol(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), Symbol::C, | ||
| 798 | 1.0f); | ||
| 799 | DrawRawJoystick(p, center + QPointF(-198, -125), axis_values[LStick].raw_value, | ||
| 800 | axis_values[LStick].properties); | ||
| 801 | DrawRawJoystick(p, center + QPointF(198, -125), axis_values[RStick].raw_value, | ||
| 802 | axis_values[RStick].properties); | ||
| 803 | } | ||
| 804 | |||
| 805 | using namespace Settings::NativeButton; | ||
| 806 | |||
| 807 | // Face buttons constants | ||
| 808 | constexpr float text_size = 1.1f; | ||
| 809 | |||
| 810 | // Face buttons | ||
| 811 | p.setPen(colors.outline); | ||
| 812 | button_color = colors.button; | ||
| 813 | DrawCircleButton(p, center + QPoint(111, -44), button_values[A], 21); | ||
| 814 | DrawCircleButton(p, center + QPoint(70, -23), button_values[B], 13); | ||
| 815 | DrawGCButtonX(p, center, button_values[Settings::NativeButton::X]); | ||
| 816 | DrawGCButtonY(p, center, button_values[Settings::NativeButton::Y]); | ||
| 817 | |||
| 818 | // Face buttons text | ||
| 819 | p.setPen(colors.transparent); | ||
| 820 | p.setBrush(colors.font); | ||
| 821 | DrawSymbol(p, center + QPoint(111, -44), Symbol::A, 1.5f); | ||
| 822 | DrawSymbol(p, center + QPoint(70, -23), Symbol::B, text_size); | ||
| 823 | DrawSymbol(p, center + QPoint(151, -53), Symbol::X, text_size); | ||
| 824 | DrawSymbol(p, center + QPoint(100, -83), Symbol::Y, text_size); | ||
| 825 | |||
| 826 | // D-pad buttons | ||
| 827 | const QPointF dpad_postion = center + QPoint(-61, 37); | ||
| 828 | const float dpad_size = 0.8f; | ||
| 829 | DrawArrowButton(p, dpad_postion, Direction::Up, button_values[DUp], dpad_size); | ||
| 830 | DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft], dpad_size); | ||
| 831 | DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight], dpad_size); | ||
| 832 | DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown], dpad_size); | ||
| 833 | DrawArrowButtonOutline(p, dpad_postion, dpad_size); | ||
| 834 | |||
| 835 | // Minus and Plus buttons | ||
| 836 | p.setPen(colors.outline); | ||
| 837 | DrawCircleButton(p, center + QPoint(0, -44), button_values[Plus], 8); | ||
| 838 | } | ||
| 839 | |||
| 840 | constexpr std::array<float, 13 * 2> symbol_a = { | ||
| 841 | -1.085f, -5.2f, 1.085f, -5.2f, 5.085f, 5.0f, 2.785f, 5.0f, 1.785f, | ||
| 842 | 2.65f, -1.785f, 2.65f, -2.785f, 5.0f, -5.085f, 5.0f, -1.4f, 1.0f, | ||
| 843 | 0.0f, -2.8f, 1.4f, 1.0f, -1.4f, 1.0f, -5.085f, 5.0f, | ||
| 844 | }; | ||
| 845 | constexpr std::array<float, 134 * 2> symbol_b = { | ||
| 846 | -4.0f, 0.0f, -4.0f, 0.0f, -4.0f, -0.1f, -3.8f, -5.1f, 1.8f, -5.0f, 2.3f, -4.9f, 2.6f, | ||
| 847 | -4.8f, 2.8f, -4.7f, 2.9f, -4.6f, 3.1f, -4.5f, 3.2f, -4.4f, 3.4f, -4.3f, 3.4f, -4.2f, | ||
| 848 | 3.5f, -4.1f, 3.7f, -4.0f, 3.7f, -3.9f, 3.8f, -3.8f, 3.8f, -3.7f, 3.9f, -3.6f, 3.9f, | ||
| 849 | -3.5f, 4.0f, -3.4f, 4.0f, -3.3f, 4.1f, -3.1f, 4.1f, -3.0f, 4.0f, -2.0f, 4.0f, -1.9f, | ||
| 850 | 3.9f, -1.7f, 3.9f, -1.6f, 3.8f, -1.5f, 3.8f, -1.4f, 3.7f, -1.3f, 3.7f, -1.2f, 3.6f, | ||
| 851 | -1.1f, 3.6f, -1.0f, 3.5f, -0.9f, 3.3f, -0.8f, 3.3f, -0.7f, 3.2f, -0.6f, 3.0f, -0.5f, | ||
| 852 | 2.9f, -0.4f, 2.7f, -0.3f, 2.9f, -0.2f, 3.2f, -0.1f, 3.3f, 0.0f, 3.5f, 0.1f, 3.6f, | ||
| 853 | 0.2f, 3.8f, 0.3f, 3.9f, 0.4f, 4.0f, 0.6f, 4.1f, 0.7f, 4.3f, 0.8f, 4.3f, 0.9f, | ||
| 854 | 4.4f, 1.0f, 4.4f, 1.1f, 4.5f, 1.3f, 4.5f, 1.4f, 4.6f, 1.6f, 4.6f, 1.7f, 4.5f, | ||
| 855 | 2.8f, 4.5f, 2.9f, 4.4f, 3.1f, 4.4f, 3.2f, 4.3f, 3.4f, 4.3f, 3.5f, 4.2f, 3.6f, | ||
| 856 | 4.2f, 3.7f, 4.1f, 3.8f, 4.1f, 3.9f, 4.0f, 4.0f, 3.9f, 4.2f, 3.8f, 4.3f, 3.6f, | ||
| 857 | 4.4f, 3.6f, 4.5f, 3.4f, 4.6f, 3.3f, 4.7f, 3.1f, 4.8f, 2.8f, 4.9f, 2.6f, 5.0f, | ||
| 858 | 2.1f, 5.1f, -4.0f, 5.0f, -4.0f, 4.9f, | ||
| 859 | |||
| 860 | -4.0f, 0.0f, 1.1f, 3.4f, 1.1f, 3.4f, 1.5f, 3.3f, 1.8f, 3.2f, 2.0f, 3.1f, 2.1f, | ||
| 861 | 3.0f, 2.3f, 2.9f, 2.3f, 2.8f, 2.4f, 2.7f, 2.4f, 2.6f, 2.5f, 2.3f, 2.5f, 2.2f, | ||
| 862 | 2.4f, 1.7f, 2.4f, 1.6f, 2.3f, 1.4f, 2.3f, 1.3f, 2.2f, 1.2f, 2.2f, 1.1f, 2.1f, | ||
| 863 | 1.0f, 1.9f, 0.9f, 1.6f, 0.8f, 1.4f, 0.7f, -1.9f, 0.6f, -1.9f, 0.7f, -1.8f, 3.4f, | ||
| 864 | 1.1f, 3.4f, -4.0f, 0.0f, | ||
| 865 | |||
| 866 | 0.3f, -1.1f, 0.3f, -1.1f, 1.3f, -1.2f, 1.5f, -1.3f, 1.8f, -1.4f, 1.8f, -1.5f, 1.9f, | ||
| 867 | -1.6f, 2.0f, -1.8f, 2.0f, -1.9f, 2.1f, -2.0f, 2.1f, -2.1f, 2.0f, -2.7f, 2.0f, -2.8f, | ||
| 868 | 1.9f, -2.9f, 1.9f, -3.0f, 1.8f, -3.1f, 1.6f, -3.2f, 1.6f, -3.3f, 1.3f, -3.4f, -1.9f, | ||
| 869 | -3.3f, -1.9f, -3.2f, -1.8f, -1.0f, 0.2f, -1.1f, 0.3f, -1.1f, -4.0f, 0.0f, | ||
| 870 | }; | ||
| 871 | |||
| 872 | constexpr std::array<float, 9 * 2> symbol_y = { | ||
| 873 | -4.79f, -4.9f, -2.44f, -4.9f, 0.0f, -0.9f, 2.44f, -4.9f, 4.79f, | ||
| 874 | -4.9f, 1.05f, 1.0f, 1.05f, 5.31f, -1.05f, 5.31f, -1.05f, 1.0f, | ||
| 875 | |||
| 876 | }; | ||
| 877 | |||
| 878 | constexpr std::array<float, 12 * 2> symbol_x = { | ||
| 879 | -4.4f, -5.0f, -2.0f, -5.0f, 0.0f, -1.7f, 2.0f, -5.0f, 4.4f, -5.0f, 1.2f, 0.0f, | ||
| 880 | 4.4f, 5.0f, 2.0f, 5.0f, 0.0f, 1.7f, -2.0f, 5.0f, -4.4f, 5.0f, -1.2f, 0.0f, | ||
| 881 | |||
| 882 | }; | ||
| 883 | |||
| 884 | constexpr std::array<float, 7 * 2> symbol_l = { | ||
| 885 | 2.4f, -3.23f, 2.4f, 2.1f, 5.43f, 2.1f, 5.43f, 3.22f, 0.98f, 3.22f, 0.98f, -3.23f, 2.4f, -3.23f, | ||
| 886 | }; | ||
| 887 | |||
| 888 | constexpr std::array<float, 98 * 2> symbol_r = { | ||
| 889 | 1.0f, 0.0f, 1.0f, -0.1f, 1.1f, -3.3f, 4.3f, -3.2f, 5.1f, -3.1f, 5.4f, -3.0f, 5.6f, -2.9f, | ||
| 890 | 5.7f, -2.8f, 5.9f, -2.7f, 5.9f, -2.6f, 6.0f, -2.5f, 6.1f, -2.3f, 6.2f, -2.2f, 6.2f, -2.1f, | ||
| 891 | 6.3f, -2.0f, 6.3f, -1.9f, 6.2f, -0.8f, 6.2f, -0.7f, 6.1f, -0.6f, 6.1f, -0.5f, 6.0f, -0.4f, | ||
| 892 | 6.0f, -0.3f, 5.9f, -0.2f, 5.7f, -0.1f, 5.7f, 0.0f, 5.6f, 0.1f, 5.4f, 0.2f, 5.1f, 0.3f, | ||
| 893 | 4.7f, 0.4f, 4.7f, 0.5f, 4.9f, 0.6f, 5.0f, 0.7f, 5.2f, 0.8f, 5.2f, 0.9f, 5.3f, 1.0f, | ||
| 894 | 5.5f, 1.1f, 5.5f, 1.2f, 5.6f, 1.3f, 5.7f, 1.5f, 5.8f, 1.6f, 5.9f, 1.8f, 6.0f, 1.9f, | ||
| 895 | 6.1f, 2.1f, 6.2f, 2.2f, 6.2f, 2.3f, 6.3f, 2.4f, 6.4f, 2.6f, 6.5f, 2.7f, 6.6f, 2.9f, | ||
| 896 | 6.7f, 3.0f, 6.7f, 3.1f, 6.8f, 3.2f, 6.8f, 3.3f, 5.3f, 3.2f, 5.2f, 3.1f, 5.2f, 3.0f, | ||
| 897 | 5.1f, 2.9f, 5.0f, 2.7f, 4.9f, 2.6f, 4.8f, 2.4f, 4.7f, 2.3f, 4.6f, 2.1f, 4.5f, 2.0f, | ||
| 898 | 4.4f, 1.8f, 4.3f, 1.7f, 4.1f, 1.4f, 4.0f, 1.3f, 3.9f, 1.1f, 3.8f, 1.0f, 3.6f, 0.9f, | ||
| 899 | 3.6f, 0.8f, 3.5f, 0.7f, 3.3f, 0.6f, 2.9f, 0.5f, 2.3f, 0.6f, 2.3f, 0.7f, 2.2f, 3.3f, | ||
| 900 | 1.0f, 3.2f, 1.0f, 3.1f, 1.0f, 0.0f, | ||
| 901 | |||
| 902 | 4.2f, -0.5f, 4.4f, -0.6f, 4.7f, -0.7f, 4.8f, -0.8f, 4.9f, -1.0f, 5.0f, -1.1f, 5.0f, -1.2f, | ||
| 903 | 4.9f, -1.7f, 4.9f, -1.8f, 4.8f, -1.9f, 4.8f, -2.0f, 4.6f, -2.1f, 4.3f, -2.2f, 2.3f, -2.1f, | ||
| 904 | 2.3f, -2.0f, 2.4f, -0.5f, 4.2f, -0.5f, 1.0f, 0.0f, | ||
| 905 | }; | ||
| 906 | |||
| 907 | constexpr std::array<float, 18 * 2> symbol_zl = { | ||
| 908 | -2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f, | ||
| 909 | -0.7f, 2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f, 2.4f, -3.23f, 2.4f, 2.1f, | ||
| 910 | 5.43f, 2.1f, 5.43f, 3.22f, 0.98f, 3.22f, 0.98f, -3.23f, 2.4f, -3.23f, -6.0f, 2.12f, | ||
| 911 | }; | ||
| 912 | |||
| 913 | constexpr std::array<float, 57 * 2> symbol_sl = { | ||
| 914 | -3.0f, -3.65f, -2.76f, -4.26f, -2.33f, -4.76f, -1.76f, -5.09f, -1.13f, -5.26f, -0.94f, | ||
| 915 | -4.77f, -0.87f, -4.11f, -1.46f, -3.88f, -1.91f, -3.41f, -2.05f, -2.78f, -1.98f, -2.13f, | ||
| 916 | -1.59f, -1.61f, -0.96f, -1.53f, -0.56f, -2.04f, -0.38f, -2.67f, -0.22f, -3.31f, 0.0f, | ||
| 917 | -3.93f, 0.34f, -4.49f, 0.86f, -4.89f, 1.49f, -5.05f, 2.14f, -4.95f, 2.69f, -4.6f, | ||
| 918 | 3.07f, -4.07f, 3.25f, -3.44f, 3.31f, -2.78f, 3.25f, -2.12f, 3.07f, -1.49f, 2.7f, | ||
| 919 | -0.95f, 2.16f, -0.58f, 1.52f, -0.43f, 1.41f, -0.99f, 1.38f, -1.65f, 1.97f, -1.91f, | ||
| 920 | 2.25f, -2.49f, 2.25f, -3.15f, 1.99f, -3.74f, 1.38f, -3.78f, 1.06f, -3.22f, 0.88f, | ||
| 921 | -2.58f, 0.71f, -1.94f, 0.49f, -1.32f, 0.13f, -0.77f, -0.4f, -0.4f, -1.04f, -0.25f, | ||
| 922 | -1.69f, -0.32f, -2.28f, -0.61f, -2.73f, -1.09f, -2.98f, -1.69f, -3.09f, -2.34f, | ||
| 923 | |||
| 924 | 3.23f, 2.4f, -2.1f, 2.4f, -2.1f, 5.43f, -3.22f, 5.43f, -3.22f, 0.98f, 3.23f, | ||
| 925 | 0.98f, 3.23f, 2.4f, -3.09f, -2.34f, | ||
| 926 | }; | ||
| 927 | constexpr std::array<float, 109 * 2> symbol_zr = { | ||
| 928 | -2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f, -0.7f, | ||
| 929 | 2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f, | ||
| 930 | |||
| 931 | 1.0f, 0.0f, 1.0f, -0.1f, 1.1f, -3.3f, 4.3f, -3.2f, 5.1f, -3.1f, 5.4f, -3.0f, 5.6f, | ||
| 932 | -2.9f, 5.7f, -2.8f, 5.9f, -2.7f, 5.9f, -2.6f, 6.0f, -2.5f, 6.1f, -2.3f, 6.2f, -2.2f, | ||
| 933 | 6.2f, -2.1f, 6.3f, -2.0f, 6.3f, -1.9f, 6.2f, -0.8f, 6.2f, -0.7f, 6.1f, -0.6f, 6.1f, | ||
| 934 | -0.5f, 6.0f, -0.4f, 6.0f, -0.3f, 5.9f, -0.2f, 5.7f, -0.1f, 5.7f, 0.0f, 5.6f, 0.1f, | ||
| 935 | 5.4f, 0.2f, 5.1f, 0.3f, 4.7f, 0.4f, 4.7f, 0.5f, 4.9f, 0.6f, 5.0f, 0.7f, 5.2f, | ||
| 936 | 0.8f, 5.2f, 0.9f, 5.3f, 1.0f, 5.5f, 1.1f, 5.5f, 1.2f, 5.6f, 1.3f, 5.7f, 1.5f, | ||
| 937 | 5.8f, 1.6f, 5.9f, 1.8f, 6.0f, 1.9f, 6.1f, 2.1f, 6.2f, 2.2f, 6.2f, 2.3f, 6.3f, | ||
| 938 | 2.4f, 6.4f, 2.6f, 6.5f, 2.7f, 6.6f, 2.9f, 6.7f, 3.0f, 6.7f, 3.1f, 6.8f, 3.2f, | ||
| 939 | 6.8f, 3.3f, 5.3f, 3.2f, 5.2f, 3.1f, 5.2f, 3.0f, 5.1f, 2.9f, 5.0f, 2.7f, 4.9f, | ||
| 940 | 2.6f, 4.8f, 2.4f, 4.7f, 2.3f, 4.6f, 2.1f, 4.5f, 2.0f, 4.4f, 1.8f, 4.3f, 1.7f, | ||
| 941 | 4.1f, 1.4f, 4.0f, 1.3f, 3.9f, 1.1f, 3.8f, 1.0f, 3.6f, 0.9f, 3.6f, 0.8f, 3.5f, | ||
| 942 | 0.7f, 3.3f, 0.6f, 2.9f, 0.5f, 2.3f, 0.6f, 2.3f, 0.7f, 2.2f, 3.3f, 1.0f, 3.2f, | ||
| 943 | 1.0f, 3.1f, 1.0f, 0.0f, | ||
| 944 | |||
| 945 | 4.2f, -0.5f, 4.4f, -0.6f, 4.7f, -0.7f, 4.8f, -0.8f, 4.9f, -1.0f, 5.0f, -1.1f, 5.0f, | ||
| 946 | -1.2f, 4.9f, -1.7f, 4.9f, -1.8f, 4.8f, -1.9f, 4.8f, -2.0f, 4.6f, -2.1f, 4.3f, -2.2f, | ||
| 947 | 2.3f, -2.1f, 2.3f, -2.0f, 2.4f, -0.5f, 4.2f, -0.5f, 1.0f, 0.0f, -6.0f, 2.12f, | ||
| 948 | }; | ||
| 949 | |||
| 950 | constexpr std::array<float, 148 * 2> symbol_sr = { | ||
| 951 | -3.0f, -3.65f, -2.76f, -4.26f, -2.33f, -4.76f, -1.76f, -5.09f, -1.13f, -5.26f, -0.94f, -4.77f, | ||
| 952 | -0.87f, -4.11f, -1.46f, -3.88f, -1.91f, -3.41f, -2.05f, -2.78f, -1.98f, -2.13f, -1.59f, -1.61f, | ||
| 953 | -0.96f, -1.53f, -0.56f, -2.04f, -0.38f, -2.67f, -0.22f, -3.31f, 0.0f, -3.93f, 0.34f, -4.49f, | ||
| 954 | 0.86f, -4.89f, 1.49f, -5.05f, 2.14f, -4.95f, 2.69f, -4.6f, 3.07f, -4.07f, 3.25f, -3.44f, | ||
| 955 | 3.31f, -2.78f, 3.25f, -2.12f, 3.07f, -1.49f, 2.7f, -0.95f, 2.16f, -0.58f, 1.52f, -0.43f, | ||
| 956 | 1.41f, -0.99f, 1.38f, -1.65f, 1.97f, -1.91f, 2.25f, -2.49f, 2.25f, -3.15f, 1.99f, -3.74f, | ||
| 957 | 1.38f, -3.78f, 1.06f, -3.22f, 0.88f, -2.58f, 0.71f, -1.94f, 0.49f, -1.32f, 0.13f, -0.77f, | ||
| 958 | -0.4f, -0.4f, -1.04f, -0.25f, -1.69f, -0.32f, -2.28f, -0.61f, -2.73f, -1.09f, -2.98f, -1.69f, | ||
| 959 | -3.09f, -2.34f, | ||
| 960 | |||
| 961 | -1.0f, 0.0f, 0.1f, 1.0f, 3.3f, 1.1f, 3.2f, 4.3f, 3.1f, 5.1f, 3.0f, 5.4f, | ||
| 962 | 2.9f, 5.6f, 2.8f, 5.7f, 2.7f, 5.9f, 2.6f, 5.9f, 2.5f, 6.0f, 2.3f, 6.1f, | ||
| 963 | 2.2f, 6.2f, 2.1f, 6.2f, 2.0f, 6.3f, 1.9f, 6.3f, 0.8f, 6.2f, 0.7f, 6.2f, | ||
| 964 | 0.6f, 6.1f, 0.5f, 6.1f, 0.4f, 6.0f, 0.3f, 6.0f, 0.2f, 5.9f, 0.1f, 5.7f, | ||
| 965 | 0.0f, 5.7f, -0.1f, 5.6f, -0.2f, 5.4f, -0.3f, 5.1f, -0.4f, 4.7f, -0.5f, 4.7f, | ||
| 966 | -0.6f, 4.9f, -0.7f, 5.0f, -0.8f, 5.2f, -0.9f, 5.2f, -1.0f, 5.3f, -1.1f, 5.5f, | ||
| 967 | -1.2f, 5.5f, -1.3f, 5.6f, -1.5f, 5.7f, -1.6f, 5.8f, -1.8f, 5.9f, -1.9f, 6.0f, | ||
| 968 | -2.1f, 6.1f, -2.2f, 6.2f, -2.3f, 6.2f, -2.4f, 6.3f, -2.6f, 6.4f, -2.7f, 6.5f, | ||
| 969 | -2.9f, 6.6f, -3.0f, 6.7f, -3.1f, 6.7f, -3.2f, 6.8f, -3.3f, 6.8f, -3.2f, 5.3f, | ||
| 970 | -3.1f, 5.2f, -3.0f, 5.2f, -2.9f, 5.1f, -2.7f, 5.0f, -2.6f, 4.9f, -2.4f, 4.8f, | ||
| 971 | -2.3f, 4.7f, -2.1f, 4.6f, -2.0f, 4.5f, -1.8f, 4.4f, -1.7f, 4.3f, -1.4f, 4.1f, | ||
| 972 | -1.3f, 4.0f, -1.1f, 3.9f, -1.0f, 3.8f, -0.9f, 3.6f, -0.8f, 3.6f, -0.7f, 3.5f, | ||
| 973 | -0.6f, 3.3f, -0.5f, 2.9f, -0.6f, 2.3f, -0.7f, 2.3f, -3.3f, 2.2f, -3.2f, 1.0f, | ||
| 974 | -3.1f, 1.0f, 0.0f, 1.0f, | ||
| 975 | |||
| 976 | 0.5f, 4.2f, 0.6f, 4.4f, 0.7f, 4.7f, 0.8f, 4.8f, 1.0f, 4.9f, 1.1f, 5.0f, | ||
| 977 | 1.2f, 5.0f, 1.7f, 4.9f, 1.8f, 4.9f, 1.9f, 4.8f, 2.0f, 4.8f, 2.1f, 4.6f, | ||
| 978 | 2.2f, 4.3f, 2.1f, 2.3f, 2.0f, 2.3f, 0.5f, 2.4f, 0.5f, 4.2f, -0.0f, 1.0f, | ||
| 979 | -3.09f, -2.34f, | ||
| 980 | |||
| 981 | }; | ||
| 982 | |||
| 983 | constexpr std::array<float, 30 * 2> symbol_c = { | ||
| 984 | 2.86f, 7.57f, 0.99f, 7.94f, -0.91f, 7.87f, -2.73f, 7.31f, -4.23f, 6.14f, -5.2f, 4.51f, | ||
| 985 | -5.65f, 2.66f, -5.68f, 0.75f, -5.31f, -1.12f, -4.43f, -2.81f, -3.01f, -4.08f, -1.24f, -4.78f, | ||
| 986 | 0.66f, -4.94f, 2.54f, -4.67f, 4.33f, -4.0f, 4.63f, -2.27f, 3.37f, -2.7f, 1.6f, -3.4f, | ||
| 987 | -0.3f, -3.5f, -2.09f, -2.87f, -3.34f, -1.45f, -3.91f, 0.37f, -3.95f, 2.27f, -3.49f, 4.12f, | ||
| 988 | -2.37f, 5.64f, -0.65f, 6.44f, 1.25f, 6.47f, 3.06f, 5.89f, 4.63f, 4.92f, 4.63f, 6.83f, | ||
| 989 | }; | ||
| 990 | |||
| 991 | constexpr std::array<float, 12 * 2> house = { | ||
| 992 | -1.3f, 0.0f, -0.93f, 0.0f, -0.93f, 1.15f, 0.93f, 1.15f, 0.93f, 0.0f, 1.3f, 0.0f, | ||
| 993 | 0.0f, -1.2f, -1.3f, 0.0f, -0.43f, 0.0f, -0.43f, .73f, 0.43f, .73f, 0.43f, 0.0f, | ||
| 994 | }; | ||
| 995 | |||
| 996 | constexpr std::array<float, 11 * 2> up_arrow_button = { | ||
| 997 | 9.1f, -9.1f, 9.1f, -30.0f, 8.1f, -30.1f, 7.7f, -30.1f, -8.6f, -30.0f, -9.0f, | ||
| 998 | -29.8f, -9.3f, -29.5f, -9.5f, -29.1f, -9.1f, -28.7f, -9.1f, -9.1f, 0.0f, 0.6f, | ||
| 999 | }; | ||
| 1000 | |||
| 1001 | constexpr std::array<float, 3 * 2> up_arrow_symbol = { | ||
| 1002 | 0.0f, -3.0f, -3.0f, 2.0f, 3.0f, 2.0f, | ||
| 1003 | }; | ||
| 1004 | |||
| 1005 | constexpr std::array<float, 13 * 2> up_arrow = { | ||
| 1006 | 9.4f, -9.8f, 9.4f, -10.2f, 8.9f, -29.8f, 8.5f, -30.0f, 8.1f, | ||
| 1007 | -30.1f, 7.7f, -30.1f, -8.6f, -30.0f, -9.0f, -29.8f, -9.3f, -29.5f, | ||
| 1008 | -9.5f, -29.1f, -9.5f, -28.7f, -9.1f, -9.1f, -8.8f, -8.8f, | ||
| 1009 | }; | ||
| 1010 | |||
| 1011 | constexpr std::array<float, 64 * 2> trigger_button = { | ||
| 1012 | 5.5f, -12.6f, 5.8f, -12.6f, 6.7f, -12.5f, 8.1f, -12.3f, 8.6f, -12.2f, 9.2f, -12.0f, | ||
| 1013 | 9.5f, -11.9f, 9.9f, -11.8f, 10.6f, -11.5f, 11.0f, -11.3f, 11.2f, -11.2f, 11.4f, -11.1f, | ||
| 1014 | 11.8f, -10.9f, 12.0f, -10.8f, 12.2f, -10.7f, 12.4f, -10.5f, 12.6f, -10.4f, 12.8f, -10.3f, | ||
| 1015 | 13.6f, -9.7f, 13.8f, -9.6f, 13.9f, -9.4f, 14.1f, -9.3f, 14.8f, -8.6f, 15.0f, -8.5f, | ||
| 1016 | 15.1f, -8.3f, 15.6f, -7.8f, 15.7f, -7.6f, 16.1f, -7.0f, 16.3f, -6.8f, 16.4f, -6.6f, | ||
| 1017 | 16.5f, -6.4f, 16.8f, -6.0f, 16.9f, -5.8f, 17.0f, -5.6f, 17.1f, -5.4f, 17.2f, -5.2f, | ||
| 1018 | 17.3f, -5.0f, 17.4f, -4.8f, 17.5f, -4.6f, 17.6f, -4.4f, 17.7f, -4.1f, 17.8f, -3.9f, | ||
| 1019 | 17.9f, -3.5f, 18.0f, -3.3f, 18.1f, -3.0f, 18.2f, -2.6f, 18.2f, -2.3f, 18.3f, -2.1f, | ||
| 1020 | 18.3f, -1.9f, 18.4f, -1.4f, 18.5f, -1.2f, 18.6f, -0.3f, 18.6f, 0.0f, 18.3f, 13.9f, | ||
| 1021 | -17.0f, 13.8f, -17.0f, 13.6f, -16.4f, -11.4f, -16.3f, -11.6f, -16.1f, -11.8f, -15.7f, -12.0f, | ||
| 1022 | -15.5f, -12.1f, -15.1f, -12.3f, -14.6f, -12.4f, -13.4f, -12.5f, | ||
| 1023 | }; | ||
| 1024 | |||
| 1025 | constexpr std::array<float, 36 * 2> pro_left_trigger = { | ||
| 1026 | -65.2f, -132.6f, -68.2f, -134.1f, -71.3f, -135.5f, -74.4f, -136.7f, -77.6f, | ||
| 1027 | -137.6f, -80.9f, -138.1f, -84.3f, -138.3f, -87.6f, -138.3f, -91.0f, -138.1f, | ||
| 1028 | -94.3f, -137.8f, -97.6f, -137.3f, -100.9f, -136.7f, -107.5f, -135.3f, -110.7f, | ||
| 1029 | -134.5f, -120.4f, -131.8f, -123.6f, -130.8f, -126.8f, -129.7f, -129.9f, -128.5f, | ||
| 1030 | -132.9f, -127.1f, -135.9f, -125.6f, -138.8f, -123.9f, -141.6f, -122.0f, -144.1f, | ||
| 1031 | -119.8f, -146.3f, -117.3f, -148.4f, -114.7f, -150.4f, -112.0f, -152.3f, -109.2f, | ||
| 1032 | -155.3f, -104.0f, -152.0f, -104.3f, -148.7f, -104.5f, -145.3f, -104.8f, -35.5f, | ||
| 1033 | -117.2f, -38.5f, -118.7f, -41.4f, -120.3f, -44.4f, -121.8f, -50.4f, -124.9f, | ||
| 1034 | }; | ||
| 1035 | |||
| 1036 | constexpr std::array<float, 14 * 2> pro_body_top = { | ||
| 1037 | 0.0f, -115.4f, -4.4f, -116.1f, -69.7f, -131.3f, -66.4f, -131.9f, -63.1f, -132.3f, | ||
| 1038 | -56.4f, -133.0f, -53.1f, -133.3f, -49.8f, -133.5f, -43.1f, -133.8f, -39.8f, -134.0f, | ||
| 1039 | -36.5f, -134.1f, -16.4f, -134.4f, -13.1f, -134.4f, 0.0f, -134.1f, | ||
| 1040 | }; | ||
| 1041 | |||
| 1042 | constexpr std::array<float, 145 * 2> pro_left_handle = { | ||
| 1043 | -178.7f, -47.5f, -179.0f, -46.1f, -179.3f, -44.6f, -182.0f, -29.8f, -182.3f, -28.4f, | ||
| 1044 | -182.6f, -26.9f, -182.8f, -25.4f, -183.1f, -23.9f, -183.3f, -22.4f, -183.6f, -21.0f, | ||
| 1045 | -183.8f, -19.5f, -184.1f, -18.0f, -184.3f, -16.5f, -184.6f, -15.1f, -184.8f, -13.6f, | ||
| 1046 | -185.1f, -12.1f, -185.3f, -10.6f, -185.6f, -9.1f, -185.8f, -7.7f, -186.1f, -6.2f, | ||
| 1047 | -186.3f, -4.7f, -186.6f, -3.2f, -186.8f, -1.7f, -187.1f, -0.3f, -187.3f, 1.2f, | ||
| 1048 | -187.6f, 2.7f, -187.8f, 4.2f, -188.3f, 7.1f, -188.5f, 8.6f, -188.8f, 10.1f, | ||
| 1049 | -189.0f, 11.6f, -189.3f, 13.1f, -189.5f, 14.5f, -190.0f, 17.5f, -190.2f, 19.0f, | ||
| 1050 | -190.5f, 20.5f, -190.7f, 21.9f, -191.2f, 24.9f, -191.4f, 26.4f, -191.7f, 27.9f, | ||
| 1051 | -191.9f, 29.3f, -192.4f, 32.3f, -192.6f, 33.8f, -193.1f, 36.8f, -193.3f, 38.2f, | ||
| 1052 | -193.8f, 41.2f, -194.0f, 42.7f, -194.7f, 47.1f, -194.9f, 48.6f, -199.0f, 82.9f, | ||
| 1053 | -199.1f, 84.4f, -199.1f, 85.9f, -199.2f, 87.4f, -199.2f, 88.9f, -199.1f, 94.9f, | ||
| 1054 | -198.9f, 96.4f, -198.8f, 97.8f, -198.5f, 99.3f, -198.3f, 100.8f, -198.0f, 102.3f, | ||
| 1055 | -197.7f, 103.7f, -197.4f, 105.2f, -197.0f, 106.7f, -196.6f, 108.1f, -195.7f, 111.0f, | ||
| 1056 | -195.2f, 112.4f, -194.1f, 115.2f, -193.5f, 116.5f, -192.8f, 117.9f, -192.1f, 119.2f, | ||
| 1057 | -190.6f, 121.8f, -189.8f, 123.1f, -188.9f, 124.3f, -187.0f, 126.6f, -186.0f, 127.7f, | ||
| 1058 | -183.9f, 129.8f, -182.7f, 130.8f, -180.3f, 132.6f, -179.1f, 133.4f, -177.8f, 134.1f, | ||
| 1059 | -176.4f, 134.8f, -175.1f, 135.5f, -173.7f, 136.0f, -169.4f, 137.3f, -167.9f, 137.7f, | ||
| 1060 | -166.5f, 138.0f, -165.0f, 138.3f, -163.5f, 138.4f, -162.0f, 138.4f, -160.5f, 138.3f, | ||
| 1061 | -159.0f, 138.0f, -157.6f, 137.7f, -156.1f, 137.3f, -154.7f, 136.9f, -153.2f, 136.5f, | ||
| 1062 | -151.8f, 136.0f, -150.4f, 135.4f, -149.1f, 134.8f, -147.7f, 134.1f, -146.5f, 133.3f, | ||
| 1063 | -145.2f, 132.5f, -144.0f, 131.6f, -142.8f, 130.6f, -141.7f, 129.6f, -139.6f, 127.5f, | ||
| 1064 | -138.6f, 126.4f, -137.7f, 125.2f, -135.1f, 121.5f, -134.3f, 120.3f, -133.5f, 119.0f, | ||
| 1065 | -131.9f, 116.5f, -131.1f, 115.2f, -128.8f, 111.3f, -128.0f, 110.1f, -127.2f, 108.8f, | ||
| 1066 | -126.5f, 107.5f, -125.7f, 106.2f, -125.0f, 104.9f, -124.2f, 103.6f, -123.5f, 102.3f, | ||
| 1067 | -122.0f, 99.6f, -121.3f, 98.3f, -115.8f, 87.7f, -115.1f, 86.4f, -114.4f, 85.0f, | ||
| 1068 | -113.7f, 83.7f, -112.3f, 81.0f, -111.6f, 79.7f, -110.1f, 77.1f, -109.4f, 75.8f, | ||
| 1069 | -108.0f, 73.1f, -107.2f, 71.8f, -106.4f, 70.6f, -105.7f, 69.3f, -104.8f, 68.0f, | ||
| 1070 | -104.0f, 66.8f, -103.1f, 65.6f, -101.1f, 63.3f, -100.0f, 62.3f, -98.8f, 61.4f, | ||
| 1071 | -97.6f, 60.6f, -97.9f, 59.5f, -98.8f, 58.3f, -101.5f, 54.6f, -102.4f, 53.4f, | ||
| 1072 | }; | ||
| 1073 | |||
| 1074 | constexpr std::array<float, 245 * 2> pro_body = { | ||
| 1075 | -0.7f, -129.1f, -54.3f, -129.1f, -55.0f, -129.1f, -57.8f, -129.0f, -58.5f, -129.0f, | ||
| 1076 | -60.7f, -128.9f, -61.4f, -128.9f, -62.8f, -128.8f, -63.5f, -128.8f, -65.7f, -128.7f, | ||
| 1077 | -66.4f, -128.7f, -67.8f, -128.6f, -68.5f, -128.6f, -69.2f, -128.5f, -70.0f, -128.5f, | ||
| 1078 | -70.7f, -128.4f, -71.4f, -128.4f, -72.1f, -128.3f, -72.8f, -128.3f, -73.5f, -128.2f, | ||
| 1079 | -74.2f, -128.2f, -74.9f, -128.1f, -75.7f, -128.1f, -76.4f, -128.0f, -77.1f, -128.0f, | ||
| 1080 | -77.8f, -127.9f, -78.5f, -127.9f, -79.2f, -127.8f, -80.6f, -127.7f, -81.4f, -127.6f, | ||
| 1081 | -82.1f, -127.5f, -82.8f, -127.5f, -83.5f, -127.4f, -84.9f, -127.3f, -85.6f, -127.2f, | ||
| 1082 | -87.0f, -127.1f, -87.7f, -127.0f, -88.5f, -126.9f, -89.2f, -126.8f, -89.9f, -126.8f, | ||
| 1083 | -90.6f, -126.7f, -94.1f, -126.3f, -94.8f, -126.2f, -113.2f, -123.3f, -113.9f, -123.2f, | ||
| 1084 | -114.6f, -123.0f, -115.3f, -122.9f, -116.7f, -122.6f, -117.4f, -122.5f, -118.1f, -122.3f, | ||
| 1085 | -118.8f, -122.2f, -119.5f, -122.0f, -120.9f, -121.7f, -121.6f, -121.5f, -122.3f, -121.4f, | ||
| 1086 | -122.9f, -121.2f, -123.6f, -121.0f, -126.4f, -120.3f, -127.1f, -120.1f, -127.8f, -119.8f, | ||
| 1087 | -128.4f, -119.6f, -129.1f, -119.4f, -131.2f, -118.7f, -132.5f, -118.3f, -133.2f, -118.0f, | ||
| 1088 | -133.8f, -117.7f, -134.5f, -117.4f, -135.1f, -117.2f, -135.8f, -116.9f, -136.4f, -116.5f, | ||
| 1089 | -137.0f, -116.2f, -137.7f, -115.8f, -138.3f, -115.4f, -138.9f, -115.1f, -139.5f, -114.7f, | ||
| 1090 | -160.0f, -100.5f, -160.5f, -100.0f, -162.5f, -97.9f, -162.9f, -97.4f, -163.4f, -96.8f, | ||
| 1091 | -163.8f, -96.2f, -165.3f, -93.8f, -165.7f, -93.2f, -166.0f, -92.6f, -166.4f, -91.9f, | ||
| 1092 | -166.7f, -91.3f, -167.3f, -90.0f, -167.6f, -89.4f, -167.8f, -88.7f, -168.1f, -88.0f, | ||
| 1093 | -168.4f, -87.4f, -168.6f, -86.7f, -168.9f, -86.0f, -169.1f, -85.4f, -169.3f, -84.7f, | ||
| 1094 | -169.6f, -84.0f, -169.8f, -83.3f, -170.2f, -82.0f, -170.4f, -81.3f, -172.8f, -72.3f, | ||
| 1095 | -173.0f, -71.6f, -173.5f, -69.5f, -173.7f, -68.8f, -173.9f, -68.2f, -174.0f, -67.5f, | ||
| 1096 | -174.2f, -66.8f, -174.5f, -65.4f, -174.7f, -64.7f, -174.8f, -64.0f, -175.0f, -63.3f, | ||
| 1097 | -175.3f, -61.9f, -175.5f, -61.2f, -175.8f, -59.8f, -176.0f, -59.1f, -176.1f, -58.4f, | ||
| 1098 | -176.3f, -57.7f, -176.6f, -56.3f, -176.8f, -55.6f, -176.9f, -54.9f, -177.1f, -54.2f, | ||
| 1099 | -177.3f, -53.6f, -177.4f, -52.9f, -177.6f, -52.2f, -177.9f, -50.8f, -178.1f, -50.1f, | ||
| 1100 | -178.2f, -49.4f, -178.2f, -48.7f, -177.8f, -48.1f, -177.1f, -46.9f, -176.7f, -46.3f, | ||
| 1101 | -176.4f, -45.6f, -176.0f, -45.0f, -175.3f, -43.8f, -174.9f, -43.2f, -174.2f, -42.0f, | ||
| 1102 | -173.4f, -40.7f, -173.1f, -40.1f, -172.7f, -39.5f, -172.0f, -38.3f, -171.6f, -37.7f, | ||
| 1103 | -170.5f, -35.9f, -170.1f, -35.3f, -169.7f, -34.6f, -169.3f, -34.0f, -168.6f, -32.8f, | ||
| 1104 | -168.2f, -32.2f, -166.3f, -29.2f, -165.9f, -28.6f, -163.2f, -24.4f, -162.8f, -23.8f, | ||
| 1105 | -141.8f, 6.8f, -141.4f, 7.4f, -139.4f, 10.3f, -139.0f, 10.9f, -138.5f, 11.5f, | ||
| 1106 | -138.1f, 12.1f, -137.3f, 13.2f, -136.9f, 13.8f, -136.0f, 15.0f, -135.6f, 15.6f, | ||
| 1107 | -135.2f, 16.1f, -134.8f, 16.7f, -133.9f, 17.9f, -133.5f, 18.4f, -133.1f, 19.0f, | ||
| 1108 | -131.8f, 20.7f, -131.4f, 21.3f, -130.1f, 23.0f, -129.7f, 23.6f, -128.4f, 25.3f, | ||
| 1109 | -128.0f, 25.9f, -126.7f, 27.6f, -126.3f, 28.2f, -125.4f, 29.3f, -125.0f, 29.9f, | ||
| 1110 | -124.1f, 31.0f, -123.7f, 31.6f, -122.8f, 32.7f, -122.4f, 33.3f, -121.5f, 34.4f, | ||
| 1111 | -121.1f, 35.0f, -120.6f, 35.6f, -120.2f, 36.1f, -119.7f, 36.7f, -119.3f, 37.2f, | ||
| 1112 | -118.9f, 37.8f, -118.4f, 38.4f, -118.0f, 38.9f, -117.5f, 39.5f, -117.1f, 40.0f, | ||
| 1113 | -116.6f, 40.6f, -116.2f, 41.1f, -115.7f, 41.7f, -115.2f, 42.2f, -114.8f, 42.8f, | ||
| 1114 | -114.3f, 43.3f, -113.9f, 43.9f, -113.4f, 44.4f, -112.4f, 45.5f, -112.0f, 46.0f, | ||
| 1115 | -111.5f, 46.5f, -110.5f, 47.6f, -110.0f, 48.1f, -109.6f, 48.6f, -109.1f, 49.2f, | ||
| 1116 | -108.6f, 49.7f, -107.7f, 50.8f, -107.2f, 51.3f, -105.7f, 52.9f, -105.3f, 53.4f, | ||
| 1117 | -104.8f, 53.9f, -104.3f, 54.5f, -103.8f, 55.0f, -100.7f, 58.0f, -100.2f, 58.4f, | ||
| 1118 | -99.7f, 58.9f, -99.1f, 59.3f, -97.2f, 60.3f, -96.5f, 60.1f, -95.9f, 59.7f, | ||
| 1119 | -95.3f, 59.4f, -94.6f, 59.1f, -93.9f, 58.9f, -92.6f, 58.5f, -91.9f, 58.4f, | ||
| 1120 | -91.2f, 58.2f, -90.5f, 58.1f, -89.7f, 58.0f, -89.0f, 57.9f, -86.2f, 57.6f, | ||
| 1121 | -85.5f, 57.5f, -84.1f, 57.4f, -83.4f, 57.3f, -82.6f, 57.3f, -81.9f, 57.2f, | ||
| 1122 | -81.2f, 57.2f, -80.5f, 57.1f, -79.8f, 57.1f, -78.4f, 57.0f, -77.7f, 57.0f, | ||
| 1123 | -75.5f, 56.9f, -74.8f, 56.9f, -71.9f, 56.8f, -71.2f, 56.8f, 0.0f, 56.8f, | ||
| 1124 | }; | ||
| 1125 | |||
| 1126 | constexpr std::array<float, 199 * 2> gc_body = { | ||
| 1127 | 0.0f, -138.03f, -4.91f, -138.01f, -8.02f, -137.94f, -11.14f, -137.82f, -14.25f, | ||
| 1128 | -137.67f, -17.37f, -137.48f, -20.48f, -137.25f, -23.59f, -137.0f, -26.69f, -136.72f, | ||
| 1129 | -29.8f, -136.41f, -32.9f, -136.07f, -35.99f, -135.71f, -39.09f, -135.32f, -42.18f, | ||
| 1130 | -134.91f, -45.27f, -134.48f, -48.35f, -134.03f, -51.43f, -133.55f, -54.51f, -133.05f, | ||
| 1131 | -57.59f, -132.52f, -60.66f, -131.98f, -63.72f, -131.41f, -66.78f, -130.81f, -69.84f, | ||
| 1132 | -130.2f, -72.89f, -129.56f, -75.94f, -128.89f, -78.98f, -128.21f, -82.02f, -127.49f, | ||
| 1133 | -85.05f, -126.75f, -88.07f, -125.99f, -91.09f, -125.19f, -94.1f, -124.37f, -97.1f, | ||
| 1134 | -123.52f, -100.09f, -122.64f, -103.07f, -121.72f, -106.04f, -120.77f, -109.0f, -119.79f, | ||
| 1135 | -111.95f, -118.77f, -114.88f, -117.71f, -117.8f, -116.61f, -120.7f, -115.46f, -123.58f, | ||
| 1136 | -114.27f, -126.44f, -113.03f, -129.27f, -111.73f, -132.08f, -110.38f, -134.86f, -108.96f, | ||
| 1137 | -137.6f, -107.47f, -140.3f, -105.91f, -142.95f, -104.27f, -145.55f, -102.54f, -148.07f, | ||
| 1138 | -100.71f, -150.51f, -98.77f, -152.86f, -96.71f, -155.09f, -94.54f, -157.23f, -92.27f, | ||
| 1139 | -159.26f, -89.9f, -161.2f, -87.46f, -163.04f, -84.94f, -164.78f, -82.35f, -166.42f, | ||
| 1140 | -79.7f, -167.97f, -77.0f, -169.43f, -74.24f, -170.8f, -71.44f, -172.09f, -68.6f, | ||
| 1141 | -173.29f, -65.72f, -174.41f, -62.81f, -175.45f, -59.87f, -176.42f, -56.91f, -177.31f, | ||
| 1142 | -53.92f, -178.14f, -50.91f, -178.9f, -47.89f, -179.6f, -44.85f, -180.24f, -41.8f, | ||
| 1143 | -180.82f, -38.73f, -181.34f, -35.66f, -181.8f, -32.57f, -182.21f, -29.48f, -182.57f, | ||
| 1144 | -26.38f, -182.88f, -23.28f, -183.15f, -20.17f, -183.36f, -17.06f, -183.54f, -13.95f, | ||
| 1145 | -183.71f, -10.84f, -184.0f, -7.73f, -184.23f, -4.62f, -184.44f, -1.51f, -184.62f, | ||
| 1146 | 1.6f, -184.79f, 4.72f, -184.95f, 7.83f, -185.11f, 10.95f, -185.25f, 14.06f, | ||
| 1147 | -185.38f, 17.18f, -185.51f, 20.29f, -185.63f, 23.41f, -185.74f, 26.53f, -185.85f, | ||
| 1148 | 29.64f, -185.95f, 32.76f, -186.04f, 35.88f, -186.12f, 39.0f, -186.19f, 42.11f, | ||
| 1149 | -186.26f, 45.23f, -186.32f, 48.35f, -186.37f, 51.47f, -186.41f, 54.59f, -186.44f, | ||
| 1150 | 57.7f, -186.46f, 60.82f, -186.46f, 63.94f, -186.44f, 70.18f, -186.41f, 73.3f, | ||
| 1151 | -186.36f, 76.42f, -186.3f, 79.53f, -186.22f, 82.65f, -186.12f, 85.77f, -185.99f, | ||
| 1152 | 88.88f, -185.84f, 92.0f, -185.66f, 95.11f, -185.44f, 98.22f, -185.17f, 101.33f, | ||
| 1153 | -184.85f, 104.43f, -184.46f, 107.53f, -183.97f, 110.61f, -183.37f, 113.67f, -182.65f, | ||
| 1154 | 116.7f, -181.77f, 119.69f, -180.71f, 122.62f, -179.43f, 125.47f, -177.89f, 128.18f, | ||
| 1155 | -176.05f, 130.69f, -173.88f, 132.92f, -171.36f, 134.75f, -168.55f, 136.1f, -165.55f, | ||
| 1156 | 136.93f, -162.45f, 137.29f, -156.23f, 137.03f, -153.18f, 136.41f, -150.46f, 134.9f, | ||
| 1157 | -148.14f, 132.83f, -146.14f, 130.43f, -144.39f, 127.85f, -142.83f, 125.16f, -141.41f, | ||
| 1158 | 122.38f, -140.11f, 119.54f, -138.9f, 116.67f, -137.77f, 113.76f, -136.7f, 110.84f, | ||
| 1159 | -135.68f, 107.89f, -134.71f, 104.93f, -133.77f, 101.95f, -132.86f, 98.97f, -131.97f, | ||
| 1160 | 95.98f, -131.09f, 92.99f, -130.23f, 89.99f, -129.36f, 86.99f, -128.49f, 84.0f, | ||
| 1161 | -127.63f, 81.0f, -126.76f, 78.01f, -125.9f, 75.01f, -124.17f, 69.02f, -123.31f, | ||
| 1162 | 66.02f, -121.59f, 60.03f, -120.72f, 57.03f, -119.86f, 54.03f, -118.13f, 48.04f, | ||
| 1163 | -117.27f, 45.04f, -115.55f, 39.05f, -114.68f, 36.05f, -113.82f, 33.05f, -112.96f, | ||
| 1164 | 30.06f, -110.4f, 28.29f, -107.81f, 26.55f, -105.23f, 24.8f, -97.48f, 19.55f, | ||
| 1165 | -94.9f, 17.81f, -92.32f, 16.06f, -87.15f, 12.56f, -84.57f, 10.81f, -81.99f, | ||
| 1166 | 9.07f, -79.4f, 7.32f, -76.82f, 5.57f, -69.07f, 0.33f, -66.49f, -1.42f, | ||
| 1167 | -58.74f, -6.66f, -56.16f, -8.41f, -48.4f, -13.64f, -45.72f, -15.22f, -42.93f, | ||
| 1168 | -16.62f, -40.07f, -17.86f, -37.15f, -18.96f, -34.19f, -19.94f, -31.19f, -20.79f, | ||
| 1169 | -28.16f, -21.55f, -25.12f, -22.21f, -22.05f, -22.79f, -18.97f, -23.28f, -15.88f, | ||
| 1170 | -23.7f, -12.78f, -24.05f, -9.68f, -24.33f, -6.57f, -24.55f, -3.45f, -24.69f, | ||
| 1171 | 0.0f, -24.69f, | ||
| 1172 | }; | ||
| 1173 | |||
| 1174 | constexpr std::array<float, 99 * 2> gc_left_body = { | ||
| 1175 | -74.59f, -97.22f, -70.17f, -94.19f, -65.95f, -90.89f, -62.06f, -87.21f, -58.58f, | ||
| 1176 | -83.14f, -55.58f, -78.7f, -53.08f, -73.97f, -51.05f, -69.01f, -49.46f, -63.89f, | ||
| 1177 | -48.24f, -58.67f, -47.36f, -53.39f, -46.59f, -48.09f, -45.7f, -42.8f, -44.69f, | ||
| 1178 | -37.54f, -43.54f, -32.31f, -42.25f, -27.11f, -40.8f, -21.95f, -39.19f, -16.84f, | ||
| 1179 | -37.38f, -11.8f, -35.34f, -6.84f, -33.04f, -2.0f, -30.39f, 2.65f, -27.26f, | ||
| 1180 | 7.0f, -23.84f, 11.11f, -21.19f, 15.76f, -19.18f, 20.73f, -17.73f, 25.88f, | ||
| 1181 | -16.82f, 31.16f, -16.46f, 36.5f, -16.7f, 41.85f, -17.63f, 47.13f, -19.31f, | ||
| 1182 | 52.21f, -21.8f, 56.95f, -24.91f, 61.3f, -28.41f, 65.36f, -32.28f, 69.06f, | ||
| 1183 | -36.51f, 72.35f, -41.09f, 75.13f, -45.97f, 77.32f, -51.1f, 78.86f, -56.39f, | ||
| 1184 | 79.7f, -61.74f, 79.84f, -67.07f, 79.3f, -72.3f, 78.15f, -77.39f, 76.48f, | ||
| 1185 | -82.29f, 74.31f, -86.76f, 71.37f, -90.7f, 67.75f, -94.16f, 63.66f, -97.27f, | ||
| 1186 | 59.3f, -100.21f, 54.81f, -103.09f, 50.3f, -106.03f, 45.82f, -109.11f, 41.44f, | ||
| 1187 | -112.37f, 37.19f, -115.85f, 33.11f, -119.54f, 29.22f, -123.45f, 25.56f, -127.55f, | ||
| 1188 | 22.11f, -131.77f, 18.81f, -136.04f, 15.57f, -140.34f, 12.37f, -144.62f, 9.15f, | ||
| 1189 | -148.86f, 5.88f, -153.03f, 2.51f, -157.05f, -1.03f, -160.83f, -4.83f, -164.12f, | ||
| 1190 | -9.05f, -166.71f, -13.73f, -168.91f, -18.62f, -170.77f, -23.64f, -172.3f, -28.78f, | ||
| 1191 | -173.49f, -34.0f, -174.3f, -39.3f, -174.72f, -44.64f, -174.72f, -49.99f, -174.28f, | ||
| 1192 | -55.33f, -173.37f, -60.61f, -172.0f, -65.79f, -170.17f, -70.82f, -167.79f, -75.62f, | ||
| 1193 | -164.84f, -80.09f, -161.43f, -84.22f, -157.67f, -88.03f, -153.63f, -91.55f, -149.37f, | ||
| 1194 | -94.81f, -144.94f, -97.82f, -140.37f, -100.61f, -135.65f, -103.16f, -130.73f, -105.26f, | ||
| 1195 | -125.62f, -106.86f, -120.37f, -107.95f, -115.05f, -108.56f, -109.7f, -108.69f, -104.35f, | ||
| 1196 | -108.36f, -99.05f, -107.6f, -93.82f, -106.41f, -88.72f, -104.79f, -83.78f, -102.7f, | ||
| 1197 | }; | ||
| 1198 | |||
| 1199 | constexpr std::array<float, 47 * 2> left_gc_trigger = { | ||
| 1200 | -99.69f, -125.04f, -101.81f, -126.51f, -104.02f, -127.85f, -106.3f, -129.06f, -108.65f, | ||
| 1201 | -130.12f, -111.08f, -130.99f, -113.58f, -131.62f, -116.14f, -131.97f, -121.26f, -131.55f, | ||
| 1202 | -123.74f, -130.84f, -126.17f, -129.95f, -128.53f, -128.9f, -130.82f, -127.71f, -133.03f, | ||
| 1203 | -126.38f, -135.15f, -124.92f, -137.18f, -123.32f, -139.11f, -121.6f, -140.91f, -119.75f, | ||
| 1204 | -142.55f, -117.77f, -144.0f, -115.63f, -145.18f, -113.34f, -146.17f, -110.95f, -147.05f, | ||
| 1205 | -108.53f, -147.87f, -106.08f, -148.64f, -103.61f, -149.37f, -101.14f, -149.16f, -100.12f, | ||
| 1206 | -147.12f, -101.71f, -144.99f, -103.16f, -142.8f, -104.53f, -140.57f, -105.83f, -138.31f, | ||
| 1207 | -107.08f, -136.02f, -108.27f, -133.71f, -109.42f, -131.38f, -110.53f, -129.04f, -111.61f, | ||
| 1208 | -126.68f, -112.66f, -124.31f, -113.68f, -121.92f, -114.67f, -119.53f, -115.64f, -117.13f, | ||
| 1209 | -116.58f, -114.72f, -117.51f, -112.3f, -118.41f, -109.87f, -119.29f, -107.44f, -120.16f, | ||
| 1210 | -105.0f, -121.0f, -100.11f, -122.65f, | ||
| 1211 | }; | ||
| 1212 | |||
| 1213 | constexpr std::array<float, 50 * 2> gc_button_x = { | ||
| 1214 | 142.1f, -50.67f, 142.44f, -48.65f, 142.69f, -46.62f, 142.8f, -44.57f, 143.0f, -42.54f, | ||
| 1215 | 143.56f, -40.57f, 144.42f, -38.71f, 145.59f, -37.04f, 147.08f, -35.64f, 148.86f, -34.65f, | ||
| 1216 | 150.84f, -34.11f, 152.88f, -34.03f, 154.89f, -34.38f, 156.79f, -35.14f, 158.49f, -36.28f, | ||
| 1217 | 159.92f, -37.74f, 161.04f, -39.45f, 161.85f, -41.33f, 162.4f, -43.3f, 162.72f, -45.32f, | ||
| 1218 | 162.85f, -47.37f, 162.82f, -49.41f, 162.67f, -51.46f, 162.39f, -53.48f, 162.0f, -55.5f, | ||
| 1219 | 161.51f, -57.48f, 160.9f, -59.44f, 160.17f, -61.35f, 159.25f, -63.18f, 158.19f, -64.93f, | ||
| 1220 | 157.01f, -66.61f, 155.72f, -68.2f, 154.31f, -69.68f, 152.78f, -71.04f, 151.09f, -72.2f, | ||
| 1221 | 149.23f, -73.04f, 147.22f, -73.36f, 145.19f, -73.11f, 143.26f, -72.42f, 141.51f, -71.37f, | ||
| 1222 | 140.0f, -69.99f, 138.82f, -68.32f, 138.13f, -66.4f, 138.09f, -64.36f, 138.39f, -62.34f, | ||
| 1223 | 139.05f, -60.41f, 139.91f, -58.55f, 140.62f, -56.63f, 141.21f, -54.67f, 141.67f, -52.67f, | ||
| 1224 | }; | ||
| 1225 | |||
| 1226 | constexpr std::array<float, 50 * 2> gc_button_y = { | ||
| 1227 | 104.02f, -75.23f, 106.01f, -75.74f, 108.01f, -76.15f, 110.04f, -76.42f, 112.05f, -76.78f, | ||
| 1228 | 113.97f, -77.49f, 115.76f, -78.49f, 117.33f, -79.79f, 118.6f, -81.39f, 119.46f, -83.25f, | ||
| 1229 | 119.84f, -85.26f, 119.76f, -87.3f, 119.24f, -89.28f, 118.33f, -91.11f, 117.06f, -92.71f, | ||
| 1230 | 115.49f, -94.02f, 113.7f, -95.01f, 111.77f, -95.67f, 109.76f, -96.05f, 107.71f, -96.21f, | ||
| 1231 | 105.67f, -96.18f, 103.63f, -95.99f, 101.61f, -95.67f, 99.61f, -95.24f, 97.63f, -94.69f, | ||
| 1232 | 95.69f, -94.04f, 93.79f, -93.28f, 91.94f, -92.4f, 90.19f, -91.34f, 88.53f, -90.14f, | ||
| 1233 | 86.95f, -88.84f, 85.47f, -87.42f, 84.1f, -85.9f, 82.87f, -84.26f, 81.85f, -82.49f, | ||
| 1234 | 81.15f, -80.57f, 81.0f, -78.54f, 81.41f, -76.54f, 82.24f, -74.67f, 83.43f, -73.01f, | ||
| 1235 | 84.92f, -71.61f, 86.68f, -70.57f, 88.65f, -70.03f, 90.69f, -70.15f, 92.68f, -70.61f, | ||
| 1236 | 94.56f, -71.42f, 96.34f, -72.43f, 98.2f, -73.29f, 100.11f, -74.03f, 102.06f, -74.65f, | ||
| 1237 | }; | ||
| 1238 | |||
| 1239 | constexpr std::array<float, 47 * 2> gc_button_z = { | ||
| 1240 | 95.74f, -126.41f, 98.34f, -126.38f, 100.94f, -126.24f, 103.53f, -126.01f, 106.11f, -125.7f, | ||
| 1241 | 108.69f, -125.32f, 111.25f, -124.87f, 113.8f, -124.34f, 116.33f, -123.73f, 118.84f, -123.05f, | ||
| 1242 | 121.33f, -122.3f, 123.79f, -121.47f, 126.23f, -120.56f, 128.64f, -119.58f, 131.02f, -118.51f, | ||
| 1243 | 133.35f, -117.37f, 135.65f, -116.14f, 137.9f, -114.84f, 140.1f, -113.46f, 142.25f, -111.99f, | ||
| 1244 | 144.35f, -110.45f, 146.38f, -108.82f, 148.35f, -107.13f, 150.25f, -105.35f, 151.89f, -103.38f, | ||
| 1245 | 151.43f, -100.86f, 149.15f, -100.15f, 146.73f, -101.06f, 144.36f, -102.12f, 141.98f, -103.18f, | ||
| 1246 | 139.6f, -104.23f, 137.22f, -105.29f, 134.85f, -106.35f, 132.47f, -107.41f, 127.72f, -109.53f, | ||
| 1247 | 125.34f, -110.58f, 122.96f, -111.64f, 120.59f, -112.7f, 118.21f, -113.76f, 113.46f, -115.88f, | ||
| 1248 | 111.08f, -116.93f, 108.7f, -117.99f, 106.33f, -119.05f, 103.95f, -120.11f, 99.2f, -122.23f, | ||
| 1249 | 96.82f, -123.29f, 94.44f, -124.34f, | ||
| 1250 | }; | ||
| 1251 | |||
| 1252 | constexpr std::array<float, 84 * 2> left_joycon_body = { | ||
| 1253 | -145.0f, -78.9f, -145.0f, -77.9f, -145.0f, 85.6f, -145.0f, 85.6f, -168.3f, 85.5f, | ||
| 1254 | -169.3f, 85.4f, -171.3f, 85.1f, -172.3f, 84.9f, -173.4f, 84.7f, -174.3f, 84.5f, | ||
| 1255 | -175.3f, 84.2f, -176.3f, 83.8f, -177.3f, 83.5f, -178.2f, 83.1f, -179.2f, 82.7f, | ||
| 1256 | -180.1f, 82.2f, -181.0f, 81.8f, -181.9f, 81.3f, -182.8f, 80.7f, -183.7f, 80.2f, | ||
| 1257 | -184.5f, 79.6f, -186.2f, 78.3f, -186.9f, 77.7f, -187.7f, 77.0f, -189.2f, 75.6f, | ||
| 1258 | -189.9f, 74.8f, -190.6f, 74.1f, -191.3f, 73.3f, -191.9f, 72.5f, -192.5f, 71.6f, | ||
| 1259 | -193.1f, 70.8f, -193.7f, 69.9f, -194.3f, 69.1f, -194.8f, 68.2f, -196.2f, 65.5f, | ||
| 1260 | -196.6f, 64.5f, -197.0f, 63.6f, -197.4f, 62.6f, -198.1f, 60.7f, -198.4f, 59.7f, | ||
| 1261 | -198.6f, 58.7f, -199.2f, 55.6f, -199.3f, 54.6f, -199.5f, 51.5f, -199.5f, 50.5f, | ||
| 1262 | -199.5f, -49.4f, -199.4f, -50.5f, -199.3f, -51.5f, -199.1f, -52.5f, -198.2f, -56.5f, | ||
| 1263 | -197.9f, -57.5f, -197.2f, -59.4f, -196.8f, -60.4f, -196.4f, -61.3f, -195.9f, -62.2f, | ||
| 1264 | -194.3f, -64.9f, -193.7f, -65.7f, -193.1f, -66.6f, -192.5f, -67.4f, -191.8f, -68.2f, | ||
| 1265 | -191.2f, -68.9f, -190.4f, -69.7f, -188.2f, -71.8f, -187.4f, -72.5f, -186.6f, -73.1f, | ||
| 1266 | -185.8f, -73.8f, -185.0f, -74.4f, -184.1f, -74.9f, -183.2f, -75.5f, -182.4f, -76.0f, | ||
| 1267 | -181.5f, -76.5f, -179.6f, -77.5f, -178.7f, -77.9f, -177.8f, -78.4f, -176.8f, -78.8f, | ||
| 1268 | -175.9f, -79.1f, -174.9f, -79.5f, -173.9f, -79.8f, -170.9f, -80.6f, -169.9f, -80.8f, | ||
| 1269 | -167.9f, -81.1f, -166.9f, -81.2f, -165.8f, -81.2f, -145.0f, -80.9f, | ||
| 1270 | }; | ||
| 1271 | |||
| 1272 | constexpr std::array<float, 84 * 2> left_joycon_trigger = { | ||
| 1273 | -166.8f, -83.3f, -167.9f, -83.2f, -168.9f, -83.1f, -170.0f, -83.0f, -171.0f, -82.8f, | ||
| 1274 | -172.1f, -82.6f, -173.1f, -82.4f, -174.2f, -82.1f, -175.2f, -81.9f, -176.2f, -81.5f, | ||
| 1275 | -177.2f, -81.2f, -178.2f, -80.8f, -180.1f, -80.0f, -181.1f, -79.5f, -182.0f, -79.0f, | ||
| 1276 | -183.0f, -78.5f, -183.9f, -78.0f, -184.8f, -77.4f, -185.7f, -76.9f, -186.6f, -76.3f, | ||
| 1277 | -187.4f, -75.6f, -188.3f, -75.0f, -189.1f, -74.3f, -192.2f, -71.5f, -192.9f, -70.7f, | ||
| 1278 | -193.7f, -69.9f, -194.3f, -69.1f, -195.0f, -68.3f, -195.6f, -67.4f, -196.8f, -65.7f, | ||
| 1279 | -197.3f, -64.7f, -197.8f, -63.8f, -198.2f, -62.8f, -198.9f, -60.8f, -198.6f, -59.8f, | ||
| 1280 | -197.6f, -59.7f, -196.6f, -60.0f, -195.6f, -60.5f, -194.7f, -60.9f, -193.7f, -61.4f, | ||
| 1281 | -192.8f, -61.9f, -191.8f, -62.4f, -190.9f, -62.8f, -189.9f, -63.3f, -189.0f, -63.8f, | ||
| 1282 | -187.1f, -64.8f, -186.2f, -65.2f, -185.2f, -65.7f, -184.3f, -66.2f, -183.3f, -66.7f, | ||
| 1283 | -182.4f, -67.1f, -181.4f, -67.6f, -180.5f, -68.1f, -179.5f, -68.6f, -178.6f, -69.0f, | ||
| 1284 | -177.6f, -69.5f, -176.7f, -70.0f, -175.7f, -70.5f, -174.8f, -70.9f, -173.8f, -71.4f, | ||
| 1285 | -172.9f, -71.9f, -171.9f, -72.4f, -171.0f, -72.8f, -170.0f, -73.3f, -169.1f, -73.8f, | ||
| 1286 | -168.1f, -74.3f, -167.2f, -74.7f, -166.2f, -75.2f, -165.3f, -75.7f, -164.3f, -76.2f, | ||
| 1287 | -163.4f, -76.6f, -162.4f, -77.1f, -161.5f, -77.6f, -160.5f, -78.1f, -159.6f, -78.5f, | ||
| 1288 | -158.7f, -79.0f, -157.7f, -79.5f, -156.8f, -80.0f, -155.8f, -80.4f, -154.9f, -80.9f, | ||
| 1289 | -154.2f, -81.6f, -154.3f, -82.6f, -155.2f, -83.3f, -156.2f, -83.3f, | ||
| 1290 | }; | ||
| 1291 | |||
| 1292 | constexpr std::array<float, 70 * 2> handheld_body = { | ||
| 1293 | -137.3f, -81.9f, -137.6f, -81.8f, -137.8f, -81.6f, -138.0f, -81.3f, -138.1f, -81.1f, | ||
| 1294 | -138.1f, -80.8f, -138.2f, -78.7f, -138.2f, -78.4f, -138.3f, -78.1f, -138.7f, -77.3f, | ||
| 1295 | -138.9f, -77.0f, -139.0f, -76.8f, -139.2f, -76.5f, -139.5f, -76.3f, -139.7f, -76.1f, | ||
| 1296 | -139.9f, -76.0f, -140.2f, -75.8f, -140.5f, -75.7f, -140.7f, -75.6f, -141.0f, -75.5f, | ||
| 1297 | -141.9f, -75.3f, -142.2f, -75.3f, -142.5f, -75.2f, -143.0f, -74.9f, -143.2f, -74.7f, | ||
| 1298 | -143.3f, -74.4f, -143.0f, -74.1f, -143.0f, 85.3f, -143.0f, 85.6f, -142.7f, 85.8f, | ||
| 1299 | -142.4f, 85.9f, -142.2f, 85.9f, 143.0f, 85.6f, 143.1f, 85.4f, 143.3f, 85.1f, | ||
| 1300 | 143.0f, 84.8f, 143.0f, -74.9f, 142.8f, -75.1f, 142.5f, -75.2f, 141.9f, -75.3f, | ||
| 1301 | 141.6f, -75.3f, 141.3f, -75.4f, 141.1f, -75.4f, 140.8f, -75.5f, 140.5f, -75.7f, | ||
| 1302 | 140.2f, -75.8f, 140.0f, -76.0f, 139.7f, -76.1f, 139.5f, -76.3f, 139.1f, -76.8f, | ||
| 1303 | 138.9f, -77.0f, 138.6f, -77.5f, 138.4f, -77.8f, 138.3f, -78.1f, 138.3f, -78.3f, | ||
| 1304 | 138.2f, -78.6f, 138.2f, -78.9f, 138.1f, -79.2f, 138.1f, -79.5f, 138.0f, -81.3f, | ||
| 1305 | 137.8f, -81.6f, 137.6f, -81.8f, 137.3f, -81.9f, 137.1f, -81.9f, 120.0f, -70.0f, | ||
| 1306 | -120.0f, -70.0f, -120.0f, 70.0f, 120.0f, 70.0f, 120.0f, -70.0f, 137.1f, -81.9f, | ||
| 1307 | }; | ||
| 1308 | |||
| 1309 | constexpr std::array<float, 40 * 2> handheld_bezel = { | ||
| 1310 | -131.4f, -75.9f, -132.2f, -75.7f, -132.9f, -75.3f, -134.2f, -74.3f, -134.7f, -73.6f, | ||
| 1311 | -135.1f, -72.8f, -135.4f, -72.0f, -135.5f, -71.2f, -135.5f, -70.4f, -135.2f, 76.7f, | ||
| 1312 | -134.8f, 77.5f, -134.3f, 78.1f, -133.7f, 78.8f, -133.1f, 79.2f, -132.3f, 79.6f, | ||
| 1313 | -131.5f, 79.9f, -130.7f, 80.0f, -129.8f, 80.0f, 132.2f, 79.7f, 133.0f, 79.3f, | ||
| 1314 | 133.7f, 78.8f, 134.3f, 78.3f, 134.8f, 77.6f, 135.1f, 76.8f, 135.5f, 75.2f, | ||
| 1315 | 135.5f, 74.3f, 135.2f, -72.7f, 134.8f, -73.5f, 134.4f, -74.2f, 133.8f, -74.8f, | ||
| 1316 | 133.1f, -75.3f, 132.3f, -75.6f, 130.7f, -76.0f, 129.8f, -76.0f, -112.9f, -62.2f, | ||
| 1317 | 112.9f, -62.2f, 112.9f, 62.2f, -112.9f, 62.2f, -112.9f, -62.2f, 129.8f, -76.0f, | ||
| 1318 | }; | ||
| 1319 | |||
| 1320 | constexpr std::array<float, 58 * 2> handheld_buttons = { | ||
| 1321 | -82.48f, -82.95f, -82.53f, -82.95f, -106.69f, -82.96f, -106.73f, -82.98f, -106.78f, -83.01f, | ||
| 1322 | -106.81f, -83.05f, -106.83f, -83.1f, -106.83f, -83.15f, -106.82f, -83.93f, -106.81f, -83.99f, | ||
| 1323 | -106.8f, -84.04f, -106.78f, -84.08f, -106.76f, -84.13f, -106.73f, -84.18f, -106.7f, -84.22f, | ||
| 1324 | -106.6f, -84.34f, -106.56f, -84.37f, -106.51f, -84.4f, -106.47f, -84.42f, -106.42f, -84.45f, | ||
| 1325 | -106.37f, -84.47f, -106.32f, -84.48f, -106.17f, -84.5f, -98.9f, -84.48f, -98.86f, -84.45f, | ||
| 1326 | -98.83f, -84.41f, -98.81f, -84.36f, -98.8f, -84.31f, -98.8f, -84.26f, -98.79f, -84.05f, | ||
| 1327 | -90.26f, -84.1f, -90.26f, -84.15f, -90.25f, -84.36f, -90.23f, -84.41f, -90.2f, -84.45f, | ||
| 1328 | -90.16f, -84.48f, -90.11f, -84.5f, -82.79f, -84.49f, -82.74f, -84.48f, -82.69f, -84.46f, | ||
| 1329 | -82.64f, -84.45f, -82.59f, -84.42f, -82.55f, -84.4f, -82.5f, -84.37f, -82.46f, -84.33f, | ||
| 1330 | -82.42f, -84.3f, -82.39f, -84.26f, -82.3f, -84.13f, -82.28f, -84.08f, -82.25f, -83.98f, | ||
| 1331 | -82.24f, -83.93f, -82.23f, -83.83f, -82.23f, -83.78f, -82.24f, -83.1f, -82.26f, -83.05f, | ||
| 1332 | -82.29f, -83.01f, -82.33f, -82.97f, -82.38f, -82.95f, | ||
| 1333 | }; | ||
| 1334 | |||
| 1335 | constexpr std::array<float, 47 * 2> left_joycon_slider = { | ||
| 1336 | -23.7f, -118.2f, -23.7f, -117.3f, -23.7f, 96.6f, -22.8f, 96.6f, -21.5f, 97.2f, -21.5f, | ||
| 1337 | 98.1f, -21.2f, 106.7f, -20.8f, 107.5f, -20.1f, 108.2f, -19.2f, 108.2f, -16.4f, 108.1f, | ||
| 1338 | -15.8f, 107.5f, -15.8f, 106.5f, -15.8f, 62.8f, -16.3f, 61.9f, -15.8f, 61.0f, -17.3f, | ||
| 1339 | 60.3f, -19.1f, 58.9f, -19.1f, 58.1f, -19.1f, 57.2f, -19.1f, 34.5f, -17.9f, 33.9f, | ||
| 1340 | -17.2f, 33.2f, -16.6f, 32.4f, -16.2f, 31.6f, -15.8f, 30.7f, -15.8f, 29.7f, -15.8f, | ||
| 1341 | 28.8f, -15.8f, -46.4f, -16.3f, -47.3f, -15.8f, -48.1f, -17.4f, -48.8f, -19.1f, -49.4f, | ||
| 1342 | -19.1f, -50.1f, -19.1f, -51.0f, -19.1f, -51.9f, -19.1f, -73.7f, -19.1f, -74.5f, -17.5f, | ||
| 1343 | -75.2f, -16.4f, -76.7f, -16.0f, -77.6f, -15.8f, -78.5f, -15.8f, -79.4f, -15.8f, -80.4f, | ||
| 1344 | -15.8f, -118.2f, -15.8f, -118.2f, -18.3f, -118.2f, | ||
| 1345 | }; | ||
| 1346 | |||
| 1347 | constexpr std::array<float, 66 * 2> left_joycon_sideview = { | ||
| 1348 | -158.8f, -133.5f, -159.8f, -133.5f, -173.5f, -133.3f, -174.5f, -133.0f, -175.4f, -132.6f, | ||
| 1349 | -176.2f, -132.1f, -177.0f, -131.5f, -177.7f, -130.9f, -178.3f, -130.1f, -179.4f, -128.5f, | ||
| 1350 | -179.8f, -127.6f, -180.4f, -125.7f, -180.6f, -124.7f, -180.7f, -123.8f, -180.7f, -122.8f, | ||
| 1351 | -180.0f, 128.8f, -179.6f, 129.7f, -179.1f, 130.5f, -177.9f, 132.1f, -177.2f, 132.7f, | ||
| 1352 | -176.4f, 133.3f, -175.6f, 133.8f, -174.7f, 134.3f, -173.8f, 134.6f, -172.8f, 134.8f, | ||
| 1353 | -170.9f, 135.0f, -169.9f, 135.0f, -156.1f, 134.8f, -155.2f, 134.6f, -154.2f, 134.3f, | ||
| 1354 | -153.3f, 134.0f, -152.4f, 133.6f, -151.6f, 133.1f, -150.7f, 132.6f, -149.9f, 132.0f, | ||
| 1355 | -149.2f, 131.4f, -148.5f, 130.7f, -147.1f, 129.2f, -146.5f, 128.5f, -146.0f, 127.7f, | ||
| 1356 | -145.5f, 126.8f, -145.0f, 126.0f, -144.6f, 125.1f, -144.2f, 124.1f, -143.9f, 123.2f, | ||
| 1357 | -143.7f, 122.2f, -143.6f, 121.3f, -143.5f, 120.3f, -143.5f, 119.3f, -144.4f, -123.4f, | ||
| 1358 | -144.8f, -124.3f, -145.3f, -125.1f, -145.8f, -126.0f, -146.3f, -126.8f, -147.0f, -127.5f, | ||
| 1359 | -147.6f, -128.3f, -148.3f, -129.0f, -149.0f, -129.6f, -149.8f, -130.3f, -150.6f, -130.8f, | ||
| 1360 | -151.4f, -131.4f, -152.2f, -131.9f, -153.1f, -132.3f, -155.9f, -133.3f, -156.8f, -133.5f, | ||
| 1361 | -157.8f, -133.5f, | ||
| 1362 | }; | ||
| 1363 | |||
| 1364 | constexpr std::array<float, 40 * 2> left_joycon_body_trigger = { | ||
| 1365 | -146.1f, -124.3f, -146.0f, -122.0f, -145.8f, -119.7f, -145.7f, -117.4f, -145.4f, -112.8f, | ||
| 1366 | -145.3f, -110.5f, -145.0f, -105.9f, -144.9f, -103.6f, -144.6f, -99.1f, -144.5f, -96.8f, | ||
| 1367 | -144.5f, -89.9f, -144.5f, -87.6f, -144.5f, -83.0f, -144.5f, -80.7f, -144.5f, -80.3f, | ||
| 1368 | -142.4f, -82.4f, -141.4f, -84.5f, -140.2f, -86.4f, -138.8f, -88.3f, -137.4f, -90.1f, | ||
| 1369 | -134.5f, -93.6f, -133.0f, -95.3f, -130.0f, -98.8f, -128.5f, -100.6f, -127.1f, -102.4f, | ||
| 1370 | -125.8f, -104.3f, -124.7f, -106.3f, -123.9f, -108.4f, -125.1f, -110.2f, -127.4f, -110.3f, | ||
| 1371 | -129.7f, -110.3f, -134.2f, -110.5f, -136.4f, -111.4f, -138.1f, -112.8f, -139.4f, -114.7f, | ||
| 1372 | -140.5f, -116.8f, -141.4f, -118.9f, -143.3f, -123.1f, -144.6f, -124.9f, -146.2f, -126.0f, | ||
| 1373 | }; | ||
| 1374 | |||
| 1375 | constexpr std::array<float, 49 * 2> left_joycon_topview = { | ||
| 1376 | -184.8f, -20.8f, -185.6f, -21.1f, -186.4f, -21.5f, -187.1f, -22.1f, -187.8f, -22.6f, | ||
| 1377 | -188.4f, -23.2f, -189.6f, -24.5f, -190.2f, -25.2f, -190.7f, -25.9f, -191.1f, -26.7f, | ||
| 1378 | -191.4f, -27.5f, -191.6f, -28.4f, -191.7f, -29.2f, -191.7f, -30.1f, -191.5f, -47.7f, | ||
| 1379 | -191.2f, -48.5f, -191.0f, -49.4f, -190.7f, -50.2f, -190.3f, -51.0f, -190.0f, -51.8f, | ||
| 1380 | -189.6f, -52.6f, -189.1f, -53.4f, -188.6f, -54.1f, -187.5f, -55.4f, -186.9f, -56.1f, | ||
| 1381 | -186.2f, -56.7f, -185.5f, -57.2f, -184.0f, -58.1f, -183.3f, -58.5f, -182.5f, -58.9f, | ||
| 1382 | -181.6f, -59.2f, -180.8f, -59.5f, -179.9f, -59.7f, -179.1f, -59.9f, -178.2f, -60.0f, | ||
| 1383 | -174.7f, -60.1f, -168.5f, -60.2f, -162.4f, -60.3f, -156.2f, -60.4f, -149.2f, -60.5f, | ||
| 1384 | -143.0f, -60.6f, -136.9f, -60.7f, -130.7f, -60.8f, -123.7f, -60.9f, -117.5f, -61.0f, | ||
| 1385 | -110.5f, -61.1f, -94.4f, -60.4f, -94.4f, -59.5f, -94.4f, -20.6f, | ||
| 1386 | }; | ||
| 1387 | |||
| 1388 | constexpr std::array<float, 41 * 2> left_joycon_slider_topview = { | ||
| 1389 | -95.1f, -51.5f, -95.0f, -51.5f, -91.2f, -51.6f, -91.2f, -51.7f, -91.1f, -52.4f, -91.1f, -52.6f, | ||
| 1390 | -91.0f, -54.1f, -86.3f, -54.0f, -86.0f, -53.9f, -85.9f, -53.8f, -85.6f, -53.4f, -85.5f, -53.2f, | ||
| 1391 | -85.5f, -53.1f, -85.4f, -52.9f, -85.4f, -52.8f, -85.3f, -52.4f, -85.3f, -52.3f, -85.4f, -27.2f, | ||
| 1392 | -85.4f, -27.1f, -85.5f, -27.0f, -85.5f, -26.9f, -85.6f, -26.7f, -85.6f, -26.6f, -85.7f, -26.5f, | ||
| 1393 | -85.9f, -26.4f, -86.0f, -26.3f, -86.4f, -26.0f, -86.5f, -25.9f, -86.7f, -25.8f, -87.1f, -25.7f, | ||
| 1394 | -90.4f, -25.8f, -90.7f, -25.9f, -90.8f, -26.0f, -90.9f, -26.3f, -91.0f, -26.4f, -91.0f, -26.5f, | ||
| 1395 | -91.1f, -26.7f, -91.1f, -26.9f, -91.2f, -28.9f, -95.2f, -29.1f, -95.2f, -29.2f, | ||
| 1396 | }; | ||
| 1397 | |||
| 1398 | constexpr std::array<float, 42 * 2> left_joycon_sideview_zl = { | ||
| 1399 | -148.9f, -128.2f, -148.7f, -126.6f, -148.4f, -124.9f, -148.2f, -123.3f, -147.9f, -121.7f, | ||
| 1400 | -147.7f, -120.1f, -147.4f, -118.5f, -147.2f, -116.9f, -146.9f, -115.3f, -146.4f, -112.1f, | ||
| 1401 | -146.1f, -110.5f, -145.9f, -108.9f, -145.6f, -107.3f, -144.2f, -107.3f, -142.6f, -107.5f, | ||
| 1402 | -141.0f, -107.8f, -137.8f, -108.3f, -136.2f, -108.6f, -131.4f, -109.4f, -129.8f, -109.7f, | ||
| 1403 | -125.6f, -111.4f, -124.5f, -112.7f, -123.9f, -114.1f, -123.8f, -115.8f, -123.8f, -117.4f, | ||
| 1404 | -123.9f, -120.6f, -124.5f, -122.1f, -125.8f, -123.1f, -127.4f, -123.4f, -129.0f, -123.6f, | ||
| 1405 | -130.6f, -124.0f, -132.1f, -124.4f, -133.7f, -124.8f, -135.3f, -125.3f, -136.8f, -125.9f, | ||
| 1406 | -138.3f, -126.4f, -139.9f, -126.9f, -141.4f, -127.5f, -142.9f, -128.0f, -144.5f, -128.5f, | ||
| 1407 | -146.0f, -129.0f, -147.6f, -129.4f, | ||
| 1408 | }; | ||
| 1409 | |||
| 1410 | constexpr std::array<float, 72 * 2> left_joystick_sideview = { | ||
| 1411 | -14.7f, -3.8f, -15.2f, -5.6f, -15.2f, -7.6f, -15.5f, -17.6f, -17.4f, -18.3f, -19.4f, -18.2f, | ||
| 1412 | -21.3f, -17.6f, -22.8f, -16.4f, -23.4f, -14.5f, -23.4f, -12.5f, -24.1f, -8.6f, -24.8f, -6.7f, | ||
| 1413 | -25.3f, -4.8f, -25.7f, -2.8f, -25.9f, -0.8f, -26.0f, 1.2f, -26.0f, 3.2f, -25.8f, 5.2f, | ||
| 1414 | -25.5f, 7.2f, -25.0f, 9.2f, -24.4f, 11.1f, -23.7f, 13.0f, -23.4f, 14.9f, -23.4f, 16.9f, | ||
| 1415 | -23.3f, 18.9f, -22.0f, 20.5f, -20.2f, 21.3f, -18.3f, 21.6f, -16.3f, 21.4f, -15.3f, 19.9f, | ||
| 1416 | -15.3f, 17.8f, -15.2f, 7.8f, -13.5f, 6.4f, -12.4f, 7.2f, -11.4f, 8.9f, -10.2f, 10.5f, | ||
| 1417 | -8.7f, 11.8f, -7.1f, 13.0f, -5.3f, 14.0f, -3.5f, 14.7f, -1.5f, 15.0f, 0.5f, 15.0f, | ||
| 1418 | 2.5f, 14.7f, 4.4f, 14.2f, 6.3f, 13.4f, 8.0f, 12.4f, 9.6f, 11.1f, 10.9f, 9.6f, | ||
| 1419 | 12.0f, 7.9f, 12.7f, 6.0f, 13.2f, 4.1f, 13.3f, 2.1f, 13.2f, 0.1f, 12.9f, -1.9f, | ||
| 1420 | 12.2f, -3.8f, 11.3f, -5.6f, 10.2f, -7.2f, 8.8f, -8.6f, 7.1f, -9.8f, 5.4f, -10.8f, | ||
| 1421 | 3.5f, -11.5f, 1.5f, -11.9f, -0.5f, -12.0f, -2.5f, -11.8f, -4.4f, -11.3f, -6.2f, -10.4f, | ||
| 1422 | -8.0f, -9.4f, -9.6f, -8.2f, -10.9f, -6.7f, -11.9f, -4.9f, -12.8f, -3.2f, -13.5f, -3.8f, | ||
| 1423 | }; | ||
| 1424 | |||
| 1425 | constexpr std::array<float, 63 * 2> left_joystick_L_topview = { | ||
| 1426 | -186.7f, -43.7f, -186.4f, -43.7f, -110.6f, -43.4f, -110.6f, -43.1f, -110.7f, -34.3f, | ||
| 1427 | -110.7f, -34.0f, -110.8f, -33.7f, -111.1f, -32.9f, -111.2f, -32.6f, -111.4f, -32.3f, | ||
| 1428 | -111.5f, -32.1f, -111.7f, -31.8f, -111.8f, -31.5f, -112.0f, -31.3f, -112.2f, -31.0f, | ||
| 1429 | -112.4f, -30.8f, -112.8f, -30.3f, -113.0f, -30.1f, -114.1f, -29.1f, -114.3f, -28.9f, | ||
| 1430 | -114.6f, -28.7f, -114.8f, -28.6f, -115.1f, -28.4f, -115.3f, -28.3f, -115.6f, -28.1f, | ||
| 1431 | -115.9f, -28.0f, -116.4f, -27.8f, -116.7f, -27.7f, -117.3f, -27.6f, -117.6f, -27.5f, | ||
| 1432 | -182.9f, -27.6f, -183.5f, -27.7f, -183.8f, -27.8f, -184.4f, -27.9f, -184.6f, -28.1f, | ||
| 1433 | -184.9f, -28.2f, -185.4f, -28.5f, -185.7f, -28.7f, -185.9f, -28.8f, -186.2f, -29.0f, | ||
| 1434 | -186.4f, -29.2f, -187.0f, -29.9f, -187.2f, -30.1f, -187.6f, -30.6f, -187.8f, -30.8f, | ||
| 1435 | -187.9f, -31.1f, -188.1f, -31.3f, -188.2f, -31.6f, -188.4f, -31.9f, -188.5f, -32.1f, | ||
| 1436 | -188.6f, -32.4f, -188.8f, -33.3f, -188.9f, -33.6f, -188.9f, -33.9f, -188.8f, -39.9f, | ||
| 1437 | -188.8f, -40.2f, -188.7f, -41.1f, -188.7f, -41.4f, -188.6f, -41.7f, -188.0f, -43.1f, | ||
| 1438 | -187.9f, -43.4f, -187.6f, -43.6f, -187.3f, -43.7f, | ||
| 1439 | }; | ||
| 1440 | |||
| 1441 | constexpr std::array<float, 44 * 2> left_joystick_ZL_topview = { | ||
| 1442 | -179.4f, -53.3f, -177.4f, -53.3f, -111.2f, -53.3f, -111.3f, -53.3f, -111.5f, -58.6f, | ||
| 1443 | -111.8f, -60.5f, -112.2f, -62.4f, -113.1f, -66.1f, -113.8f, -68.0f, -114.5f, -69.8f, | ||
| 1444 | -115.3f, -71.5f, -116.3f, -73.2f, -117.3f, -74.8f, -118.5f, -76.4f, -119.8f, -77.8f, | ||
| 1445 | -121.2f, -79.1f, -122.8f, -80.2f, -124.4f, -81.2f, -126.2f, -82.0f, -128.1f, -82.6f, | ||
| 1446 | -130.0f, -82.9f, -131.9f, -83.0f, -141.5f, -82.9f, -149.3f, -82.8f, -153.1f, -82.6f, | ||
| 1447 | -155.0f, -82.1f, -156.8f, -81.6f, -158.7f, -80.9f, -160.4f, -80.2f, -162.2f, -79.3f, | ||
| 1448 | -163.8f, -78.3f, -165.4f, -77.2f, -166.9f, -76.0f, -168.4f, -74.7f, -169.7f, -73.3f, | ||
| 1449 | -172.1f, -70.3f, -173.2f, -68.7f, -174.2f, -67.1f, -175.2f, -65.4f, -176.1f, -63.7f, | ||
| 1450 | -178.7f, -58.5f, -179.6f, -56.8f, -180.4f, -55.1f, -181.3f, -53.3f, | ||
| 1451 | }; | ||
| 1452 | |||
| 1453 | void PlayerControlPreview::DrawProBody(QPainter& p, const QPointF center) { | ||
| 1454 | std::array<QPointF, pro_left_handle.size() / 2> qleft_handle; | ||
| 1455 | std::array<QPointF, pro_left_handle.size() / 2> qright_handle; | ||
| 1456 | std::array<QPointF, pro_body.size()> qbody; | ||
| 1457 | constexpr int radius1 = 32; | ||
| 1458 | |||
| 1459 | for (std::size_t point = 0; point < pro_left_handle.size() / 2; ++point) { | ||
| 1460 | qleft_handle[point] = | ||
| 1461 | center + QPointF(pro_left_handle[point * 2], pro_left_handle[point * 2 + 1]); | ||
| 1462 | qright_handle[point] = | ||
| 1463 | center + QPointF(-pro_left_handle[point * 2], pro_left_handle[point * 2 + 1]); | ||
| 1464 | } | ||
| 1465 | for (std::size_t point = 0; point < pro_body.size() / 2; ++point) { | ||
| 1466 | qbody[point] = center + QPointF(pro_body[point * 2], pro_body[point * 2 + 1]); | ||
| 1467 | qbody[pro_body.size() - 1 - point] = | ||
| 1468 | center + QPointF(-pro_body[point * 2], pro_body[point * 2 + 1]); | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | // Draw left handle body | ||
| 1472 | p.setPen(colors.outline); | ||
| 1473 | p.setBrush(colors.left); | ||
| 1474 | DrawPolygon(p, qleft_handle); | ||
| 1475 | |||
| 1476 | // Draw right handle body | ||
| 1477 | p.setBrush(colors.right); | ||
| 1478 | DrawPolygon(p, qright_handle); | ||
| 1479 | |||
| 1480 | // Draw body | ||
| 1481 | p.setBrush(colors.primary); | ||
| 1482 | DrawPolygon(p, qbody); | ||
| 1483 | |||
| 1484 | // Draw joycon circles | ||
| 1485 | p.setBrush(colors.transparent); | ||
| 1486 | p.drawEllipse(center + QPoint(-111, -55), radius1, radius1); | ||
| 1487 | p.drawEllipse(center + QPoint(51, 0), radius1, radius1); | ||
| 1488 | } | ||
| 1489 | |||
| 1490 | void PlayerControlPreview::DrawGCBody(QPainter& p, const QPointF center) { | ||
| 1491 | std::array<QPointF, gc_left_body.size() / 2> qleft_handle; | ||
| 1492 | std::array<QPointF, gc_left_body.size() / 2> qright_handle; | ||
| 1493 | std::array<QPointF, gc_body.size()> qbody; | ||
| 1494 | std::array<QPointF, 8> left_hex; | ||
| 1495 | std::array<QPointF, 8> right_hex; | ||
| 1496 | constexpr float angle = 2 * 3.1415f / 8; | ||
| 1497 | |||
| 1498 | for (std::size_t point = 0; point < gc_left_body.size() / 2; ++point) { | ||
| 1499 | qleft_handle[point] = | ||
| 1500 | center + QPointF(gc_left_body[point * 2], gc_left_body[point * 2 + 1]); | ||
| 1501 | qright_handle[point] = | ||
| 1502 | center + QPointF(-gc_left_body[point * 2], gc_left_body[point * 2 + 1]); | ||
| 1503 | } | ||
| 1504 | for (std::size_t point = 0; point < gc_body.size() / 2; ++point) { | ||
| 1505 | qbody[point] = center + QPointF(gc_body[point * 2], gc_body[point * 2 + 1]); | ||
| 1506 | qbody[gc_body.size() - 1 - point] = | ||
| 1507 | center + QPointF(-gc_body[point * 2], gc_body[point * 2 + 1]); | ||
| 1508 | } | ||
| 1509 | for (std::size_t point = 0; point < 8; ++point) { | ||
| 1510 | left_hex[point] = | ||
| 1511 | center + QPointF(34 * std::cos(point * angle) - 111, 34 * std::sin(point * angle) - 44); | ||
| 1512 | right_hex[point] = | ||
| 1513 | center + QPointF(26 * std::cos(point * angle) + 61, 26 * std::sin(point * angle) + 37); | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | // Draw body | ||
| 1517 | p.setPen(colors.outline); | ||
| 1518 | p.setBrush(colors.primary); | ||
| 1519 | DrawPolygon(p, qbody); | ||
| 1520 | |||
| 1521 | // Draw left handle body | ||
| 1522 | p.setBrush(colors.left); | ||
| 1523 | DrawPolygon(p, qleft_handle); | ||
| 1524 | |||
| 1525 | // Draw right handle body | ||
| 1526 | p.setBrush(colors.right); | ||
| 1527 | DrawPolygon(p, qright_handle); | ||
| 1528 | |||
| 1529 | DrawText(p, center + QPoint(0, -58), 4.7f, tr("START/PAUSE")); | ||
| 1530 | |||
| 1531 | // Draw right joystick body | ||
| 1532 | p.setBrush(colors.button); | ||
| 1533 | DrawCircle(p, center + QPointF(61, 37), 23.5f); | ||
| 1534 | |||
| 1535 | // Draw joystick details | ||
| 1536 | p.setBrush(colors.transparent); | ||
| 1537 | DrawPolygon(p, left_hex); | ||
| 1538 | DrawPolygon(p, right_hex); | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | void PlayerControlPreview::DrawHandheldBody(QPainter& p, const QPointF center) { | ||
| 1542 | const std::size_t body_outline_end = handheld_body.size() / 2 - 6; | ||
| 1543 | const std::size_t bezel_outline_end = handheld_bezel.size() / 2 - 6; | ||
| 1544 | const std::size_t bezel_inline_size = 4; | ||
| 1545 | const std::size_t bezel_inline_start = 35; | ||
| 1546 | std::array<QPointF, left_joycon_body.size() / 2> left_joycon; | ||
| 1547 | std::array<QPointF, left_joycon_body.size() / 2> right_joycon; | ||
| 1548 | std::array<QPointF, handheld_body.size() / 2> qhandheld_body; | ||
| 1549 | std::array<QPointF, body_outline_end> qhandheld_body_outline; | ||
| 1550 | std::array<QPointF, handheld_bezel.size() / 2> qhandheld_bezel; | ||
| 1551 | std::array<QPointF, bezel_inline_size> qhandheld_bezel_inline; | ||
| 1552 | std::array<QPointF, bezel_outline_end> qhandheld_bezel_outline; | ||
| 1553 | std::array<QPointF, handheld_buttons.size() / 2> qhandheld_buttons; | ||
| 1554 | |||
| 1555 | for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) { | ||
| 1556 | left_joycon[point] = | ||
| 1557 | center + QPointF(left_joycon_body[point * 2], left_joycon_body[point * 2 + 1]); | ||
| 1558 | right_joycon[point] = | ||
| 1559 | center + QPointF(-left_joycon_body[point * 2], left_joycon_body[point * 2 + 1]); | ||
| 1560 | } | ||
| 1561 | for (std::size_t point = 0; point < body_outline_end; ++point) { | ||
| 1562 | qhandheld_body_outline[point] = | ||
| 1563 | center + QPointF(handheld_body[point * 2], handheld_body[point * 2 + 1]); | ||
| 1564 | } | ||
| 1565 | for (std::size_t point = 0; point < handheld_body.size() / 2; ++point) { | ||
| 1566 | qhandheld_body[point] = | ||
| 1567 | center + QPointF(handheld_body[point * 2], handheld_body[point * 2 + 1]); | ||
| 1568 | } | ||
| 1569 | for (std::size_t point = 0; point < handheld_bezel.size() / 2; ++point) { | ||
| 1570 | qhandheld_bezel[point] = | ||
| 1571 | center + QPointF(handheld_bezel[point * 2], handheld_bezel[point * 2 + 1]); | ||
| 1572 | } | ||
| 1573 | for (std::size_t point = 0; point < bezel_outline_end; ++point) { | ||
| 1574 | qhandheld_bezel_outline[point] = | ||
| 1575 | center + QPointF(handheld_bezel[point * 2], handheld_bezel[point * 2 + 1]); | ||
| 1576 | } | ||
| 1577 | for (std::size_t point = 0; point < bezel_inline_size; ++point) { | ||
| 1578 | qhandheld_bezel_inline[point] = | ||
| 1579 | center + QPointF(handheld_bezel[(point + bezel_inline_start) * 2], | ||
| 1580 | handheld_bezel[(point + bezel_inline_start) * 2 + 1]); | ||
| 1581 | } | ||
| 1582 | for (std::size_t point = 0; point < handheld_buttons.size() / 2; ++point) { | ||
| 1583 | qhandheld_buttons[point] = | ||
| 1584 | center + QPointF(handheld_buttons[point * 2], handheld_buttons[point * 2 + 1]); | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | // Draw left joycon | ||
| 1588 | p.setPen(colors.outline); | ||
| 1589 | p.setBrush(colors.left); | ||
| 1590 | DrawPolygon(p, left_joycon); | ||
| 1591 | |||
| 1592 | // Draw right joycon | ||
| 1593 | p.setPen(colors.outline); | ||
| 1594 | p.setBrush(colors.right); | ||
| 1595 | DrawPolygon(p, right_joycon); | ||
| 1596 | |||
| 1597 | // Draw Handheld buttons | ||
| 1598 | p.setPen(colors.outline); | ||
| 1599 | p.setBrush(colors.button); | ||
| 1600 | DrawPolygon(p, qhandheld_buttons); | ||
| 1601 | |||
| 1602 | // Draw handheld body | ||
| 1603 | p.setPen(colors.transparent); | ||
| 1604 | p.setBrush(colors.primary); | ||
| 1605 | DrawPolygon(p, qhandheld_body); | ||
| 1606 | p.setPen(colors.outline); | ||
| 1607 | p.setBrush(colors.transparent); | ||
| 1608 | DrawPolygon(p, qhandheld_body_outline); | ||
| 1609 | |||
| 1610 | // Draw Handheld bezel | ||
| 1611 | p.setPen(colors.transparent); | ||
| 1612 | p.setBrush(colors.button); | ||
| 1613 | DrawPolygon(p, qhandheld_bezel); | ||
| 1614 | p.setPen(colors.outline); | ||
| 1615 | p.setBrush(colors.transparent); | ||
| 1616 | DrawPolygon(p, qhandheld_bezel_outline); | ||
| 1617 | DrawPolygon(p, qhandheld_bezel_inline); | ||
| 1618 | } | ||
| 1619 | |||
| 1620 | void PlayerControlPreview::DrawDualBody(QPainter& p, const QPointF center) { | ||
| 1621 | std::array<QPointF, left_joycon_body.size() / 2> left_joycon; | ||
| 1622 | std::array<QPointF, left_joycon_body.size() / 2> right_joycon; | ||
| 1623 | std::array<QPointF, left_joycon_slider.size() / 2> qleft_joycon_slider; | ||
| 1624 | std::array<QPointF, left_joycon_slider.size() / 2> qright_joycon_slider; | ||
| 1625 | std::array<QPointF, left_joycon_slider_topview.size() / 2> qleft_joycon_slider_topview; | ||
| 1626 | std::array<QPointF, left_joycon_slider_topview.size() / 2> qright_joycon_slider_topview; | ||
| 1627 | std::array<QPointF, left_joycon_topview.size() / 2> qleft_joycon_topview; | ||
| 1628 | std::array<QPointF, left_joycon_topview.size() / 2> qright_joycon_topview; | ||
| 1629 | constexpr float size = 1.61f; | ||
| 1630 | constexpr float size2 = 0.9f; | ||
| 1631 | constexpr float offset = 209.3f; | ||
| 1632 | |||
| 1633 | for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) { | ||
| 1634 | left_joycon[point] = center + QPointF(left_joycon_body[point * 2] * size + offset, | ||
| 1635 | left_joycon_body[point * 2 + 1] * size - 1); | ||
| 1636 | right_joycon[point] = center + QPointF(-left_joycon_body[point * 2] * size - offset, | ||
| 1637 | left_joycon_body[point * 2 + 1] * size - 1); | ||
| 1638 | } | ||
| 1639 | for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) { | ||
| 1640 | qleft_joycon_slider[point] = | ||
| 1641 | center + QPointF(left_joycon_slider[point * 2], left_joycon_slider[point * 2 + 1]); | ||
| 1642 | qright_joycon_slider[point] = | ||
| 1643 | center + QPointF(-left_joycon_slider[point * 2], left_joycon_slider[point * 2 + 1]); | ||
| 1644 | } | ||
| 1645 | for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) { | ||
| 1646 | qleft_joycon_topview[point] = | ||
| 1647 | center + QPointF(left_joycon_topview[point * 2] * size2 - 52, | ||
| 1648 | left_joycon_topview[point * 2 + 1] * size2 - 52); | ||
| 1649 | qright_joycon_topview[point] = | ||
| 1650 | center + QPointF(-left_joycon_topview[point * 2] * size2 + 52, | ||
| 1651 | left_joycon_topview[point * 2 + 1] * size2 - 52); | ||
| 1652 | } | ||
| 1653 | for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) { | ||
| 1654 | qleft_joycon_slider_topview[point] = | ||
| 1655 | center + QPointF(left_joycon_slider_topview[point * 2] * size2 - 52, | ||
| 1656 | left_joycon_slider_topview[point * 2 + 1] * size2 - 52); | ||
| 1657 | qright_joycon_slider_topview[point] = | ||
| 1658 | center + QPointF(-left_joycon_slider_topview[point * 2] * size2 + 52, | ||
| 1659 | left_joycon_slider_topview[point * 2 + 1] * size2 - 52); | ||
| 1660 | } | ||
| 1661 | |||
| 1662 | // right joycon body | ||
| 1663 | p.setPen(colors.outline); | ||
| 1664 | p.setBrush(colors.right); | ||
| 1665 | DrawPolygon(p, right_joycon); | ||
| 1666 | |||
| 1667 | // Left joycon body | ||
| 1668 | p.setPen(colors.outline); | ||
| 1669 | p.setBrush(colors.left); | ||
| 1670 | DrawPolygon(p, left_joycon); | ||
| 1671 | |||
| 1672 | // Slider release button top view | ||
| 1673 | p.setBrush(colors.button); | ||
| 1674 | DrawRoundRectangle(p, center + QPoint(-149, -108), 12, 11, 2); | ||
| 1675 | DrawRoundRectangle(p, center + QPoint(149, -108), 12, 11, 2); | ||
| 1676 | |||
| 1677 | // Joycon slider top view | ||
| 1678 | p.setBrush(colors.slider); | ||
| 1679 | DrawPolygon(p, qleft_joycon_slider_topview); | ||
| 1680 | p.drawLine(center + QPointF(-133.8f, -99.0f), center + QPointF(-133.8f, -78.5f)); | ||
| 1681 | DrawPolygon(p, qright_joycon_slider_topview); | ||
| 1682 | p.drawLine(center + QPointF(133.8f, -99.0f), center + QPointF(133.8f, -78.5f)); | ||
| 1683 | |||
| 1684 | // Joycon body top view | ||
| 1685 | p.setBrush(colors.left); | ||
| 1686 | DrawPolygon(p, qleft_joycon_topview); | ||
| 1687 | p.setBrush(colors.right); | ||
| 1688 | DrawPolygon(p, qright_joycon_topview); | ||
| 1689 | |||
| 1690 | // Right SR and SL sideview buttons | ||
| 1691 | p.setPen(colors.outline); | ||
| 1692 | p.setBrush(colors.slider_button); | ||
| 1693 | DrawRoundRectangle(p, center + QPoint(19, 47), 7, 22, 1); | ||
| 1694 | DrawRoundRectangle(p, center + QPoint(19, -62), 7, 22, 1); | ||
| 1695 | |||
| 1696 | // Left SR and SL sideview buttons | ||
| 1697 | DrawRoundRectangle(p, center + QPoint(-19, 47), 7, 22, 1); | ||
| 1698 | DrawRoundRectangle(p, center + QPoint(-19, -62), 7, 22, 1); | ||
| 1699 | |||
| 1700 | // Right Sideview body | ||
| 1701 | p.setBrush(colors.slider); | ||
| 1702 | DrawPolygon(p, qright_joycon_slider); | ||
| 1703 | |||
| 1704 | // Left Sideview body | ||
| 1705 | p.setBrush(colors.slider); | ||
| 1706 | DrawPolygon(p, qleft_joycon_slider); | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | void PlayerControlPreview::DrawLeftBody(QPainter& p, const QPointF center) { | ||
| 1710 | std::array<QPointF, left_joycon_body.size() / 2> left_joycon; | ||
| 1711 | std::array<QPointF, left_joycon_sideview.size() / 2> qleft_joycon_sideview; | ||
| 1712 | std::array<QPointF, left_joycon_body_trigger.size() / 2> qleft_joycon_trigger; | ||
| 1713 | std::array<QPointF, left_joycon_slider.size() / 2> qleft_joycon_slider; | ||
| 1714 | std::array<QPointF, left_joycon_slider_topview.size() / 2> qleft_joycon_slider_topview; | ||
| 1715 | std::array<QPointF, left_joycon_topview.size() / 2> qleft_joycon_topview; | ||
| 1716 | constexpr float size = 1.78f; | ||
| 1717 | constexpr float size2 = 1.1115f; | ||
| 1718 | constexpr float offset = 312.39f; | ||
| 1719 | constexpr float offset2 = 335; | ||
| 1720 | |||
| 1721 | for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) { | ||
| 1722 | left_joycon[point] = center + QPointF(left_joycon_body[point * 2] * size + offset, | ||
| 1723 | left_joycon_body[point * 2 + 1] * size - 1); | ||
| 1724 | } | ||
| 1725 | |||
| 1726 | for (std::size_t point = 0; point < left_joycon_sideview.size() / 2; ++point) { | ||
| 1727 | qleft_joycon_sideview[point] = | ||
| 1728 | center + QPointF(left_joycon_sideview[point * 2] * size2 + offset2, | ||
| 1729 | left_joycon_sideview[point * 2 + 1] * size2 + 2); | ||
| 1730 | } | ||
| 1731 | for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) { | ||
| 1732 | qleft_joycon_slider[point] = center + QPointF(left_joycon_slider[point * 2] * size2 + 81, | ||
| 1733 | left_joycon_slider[point * 2 + 1] * size2); | ||
| 1734 | } | ||
| 1735 | for (std::size_t point = 0; point < left_joycon_body_trigger.size() / 2; ++point) { | ||
| 1736 | qleft_joycon_trigger[point] = | ||
| 1737 | center + QPointF(left_joycon_body_trigger[point * 2] * size2 + offset2, | ||
| 1738 | left_joycon_body_trigger[point * 2 + 1] * size2 + 2); | ||
| 1739 | } | ||
| 1740 | for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) { | ||
| 1741 | qleft_joycon_topview[point] = | ||
| 1742 | center + QPointF(left_joycon_topview[point * 2], left_joycon_topview[point * 2 + 1]); | ||
| 1743 | } | ||
| 1744 | for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) { | ||
| 1745 | qleft_joycon_slider_topview[point] = | ||
| 1746 | center + QPointF(left_joycon_slider_topview[point * 2], | ||
| 1747 | left_joycon_slider_topview[point * 2 + 1]); | ||
| 1748 | } | ||
| 1749 | |||
| 1750 | // Joycon body | ||
| 1751 | p.setPen(colors.outline); | ||
| 1752 | p.setBrush(colors.left); | ||
| 1753 | DrawPolygon(p, left_joycon); | ||
| 1754 | DrawPolygon(p, qleft_joycon_trigger); | ||
| 1755 | |||
| 1756 | // Slider release button top view | ||
| 1757 | p.setBrush(colors.button); | ||
| 1758 | DrawRoundRectangle(p, center + QPoint(-107, -62), 14, 12, 2); | ||
| 1759 | |||
| 1760 | // Joycon slider top view | ||
| 1761 | p.setBrush(colors.slider); | ||
| 1762 | DrawPolygon(p, qleft_joycon_slider_topview); | ||
| 1763 | p.drawLine(center + QPointF(-91.1f, -51.7f), center + QPointF(-91.1f, -26.5f)); | ||
| 1764 | |||
| 1765 | // Joycon body top view | ||
| 1766 | p.setBrush(colors.left); | ||
| 1767 | DrawPolygon(p, qleft_joycon_topview); | ||
| 1768 | |||
| 1769 | // Slider release button | ||
| 1770 | p.setBrush(colors.button); | ||
| 1771 | DrawRoundRectangle(p, center + QPoint(175, -110), 12, 14, 2); | ||
| 1772 | |||
| 1773 | // Sideview body | ||
| 1774 | p.setBrush(colors.left); | ||
| 1775 | DrawPolygon(p, qleft_joycon_sideview); | ||
| 1776 | p.setBrush(colors.slider); | ||
| 1777 | DrawPolygon(p, qleft_joycon_slider); | ||
| 1778 | |||
| 1779 | const QPointF sideview_center = QPointF(155, 0) + center; | ||
| 1780 | |||
| 1781 | // Sideview slider body | ||
| 1782 | p.setBrush(colors.slider); | ||
| 1783 | DrawRoundRectangle(p, sideview_center + QPointF(0, -5), 28, 253, 3); | ||
| 1784 | p.setBrush(colors.button2); | ||
| 1785 | DrawRoundRectangle(p, sideview_center + QPointF(0, 97), 22.44f, 44.66f, 3); | ||
| 1786 | |||
| 1787 | // Slider decorations | ||
| 1788 | p.setPen(colors.outline); | ||
| 1789 | p.setBrush(colors.slider_arrow); | ||
| 1790 | DrawArrow(p, sideview_center + QPoint(0, 83), Direction::Down, 2.2f); | ||
| 1791 | DrawArrow(p, sideview_center + QPoint(0, 96), Direction::Down, 2.2f); | ||
| 1792 | DrawArrow(p, sideview_center + QPoint(0, 109), Direction::Down, 2.2f); | ||
| 1793 | DrawCircle(p, sideview_center + QPointF(0, 19), 4.44f); | ||
| 1794 | |||
| 1795 | // LED indicators | ||
| 1796 | const float led_size = 5.0f; | ||
| 1797 | const QPointF led_position = sideview_center + QPointF(0, -36); | ||
| 1798 | int led_count = 0; | ||
| 1799 | for (const auto color : led_color) { | ||
| 1800 | p.setBrush(color); | ||
| 1801 | DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); | ||
| 1802 | } | ||
| 1803 | } | ||
| 1804 | |||
| 1805 | void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { | ||
| 1806 | std::array<QPointF, left_joycon_body.size() / 2> right_joycon; | ||
| 1807 | std::array<QPointF, left_joycon_sideview.size() / 2> qright_joycon_sideview; | ||
| 1808 | std::array<QPointF, left_joycon_body_trigger.size() / 2> qright_joycon_trigger; | ||
| 1809 | std::array<QPointF, left_joycon_slider.size() / 2> qright_joycon_slider; | ||
| 1810 | std::array<QPointF, left_joycon_slider_topview.size() / 2> qright_joycon_slider_topview; | ||
| 1811 | std::array<QPointF, left_joycon_topview.size() / 2> qright_joycon_topview; | ||
| 1812 | constexpr float size = 1.78f; | ||
| 1813 | constexpr float size2 = 1.1115f; | ||
| 1814 | constexpr float offset = 312.39f; | ||
| 1815 | constexpr float offset2 = 335; | ||
| 1816 | |||
| 1817 | for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) { | ||
| 1818 | right_joycon[point] = center + QPointF(-left_joycon_body[point * 2] * size - offset, | ||
| 1819 | left_joycon_body[point * 2 + 1] * size - 1); | ||
| 1820 | } | ||
| 1821 | |||
| 1822 | for (std::size_t point = 0; point < left_joycon_sideview.size() / 2; ++point) { | ||
| 1823 | qright_joycon_sideview[point] = | ||
| 1824 | center + QPointF(-left_joycon_sideview[point * 2] * size2 - offset2, | ||
| 1825 | left_joycon_sideview[point * 2 + 1] * size2 + 2); | ||
| 1826 | } | ||
| 1827 | for (std::size_t point = 0; point < left_joycon_body_trigger.size() / 2; ++point) { | ||
| 1828 | qright_joycon_trigger[point] = | ||
| 1829 | center + QPointF(-left_joycon_body_trigger[point * 2] * size2 - offset2, | ||
| 1830 | left_joycon_body_trigger[point * 2 + 1] * size2 + 2); | ||
| 1831 | } | ||
| 1832 | for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) { | ||
| 1833 | qright_joycon_slider[point] = center + QPointF(-left_joycon_slider[point * 2] * size2 - 81, | ||
| 1834 | left_joycon_slider[point * 2 + 1] * size2); | ||
| 1835 | } | ||
| 1836 | for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) { | ||
| 1837 | qright_joycon_topview[point] = | ||
| 1838 | center + QPointF(-left_joycon_topview[point * 2], left_joycon_topview[point * 2 + 1]); | ||
| 1839 | } | ||
| 1840 | for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) { | ||
| 1841 | qright_joycon_slider_topview[point] = | ||
| 1842 | center + QPointF(-left_joycon_slider_topview[point * 2], | ||
| 1843 | left_joycon_slider_topview[point * 2 + 1]); | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | // Joycon body | ||
| 1847 | p.setPen(colors.outline); | ||
| 1848 | p.setBrush(colors.left); | ||
| 1849 | DrawPolygon(p, right_joycon); | ||
| 1850 | DrawPolygon(p, qright_joycon_trigger); | ||
| 1851 | |||
| 1852 | // Slider release button top view | ||
| 1853 | p.setBrush(colors.button); | ||
| 1854 | DrawRoundRectangle(p, center + QPoint(107, -62), 14, 12, 2); | ||
| 1855 | |||
| 1856 | // Joycon slider top view | ||
| 1857 | p.setBrush(colors.slider); | ||
| 1858 | DrawPolygon(p, qright_joycon_slider_topview); | ||
| 1859 | p.drawLine(center + QPointF(91.1f, -51.7f), center + QPointF(91.1f, -26.5f)); | ||
| 1860 | |||
| 1861 | // Joycon body top view | ||
| 1862 | p.setBrush(colors.left); | ||
| 1863 | DrawPolygon(p, qright_joycon_topview); | ||
| 1864 | |||
| 1865 | // Slider release button | ||
| 1866 | p.setBrush(colors.button); | ||
| 1867 | DrawRoundRectangle(p, center + QPoint(-175, -110), 12, 14, 2); | ||
| 1868 | |||
| 1869 | // Sideview body | ||
| 1870 | p.setBrush(colors.left); | ||
| 1871 | DrawPolygon(p, qright_joycon_sideview); | ||
| 1872 | p.setBrush(colors.slider); | ||
| 1873 | DrawPolygon(p, qright_joycon_slider); | ||
| 1874 | |||
| 1875 | const QPointF sideview_center = QPointF(-155, 0) + center; | ||
| 1876 | |||
| 1877 | // Sideview slider body | ||
| 1878 | p.setBrush(colors.slider); | ||
| 1879 | DrawRoundRectangle(p, sideview_center + QPointF(0, -5), 28, 253, 3); | ||
| 1880 | p.setBrush(colors.button2); | ||
| 1881 | DrawRoundRectangle(p, sideview_center + QPointF(0, 97), 22.44f, 44.66f, 3); | ||
| 1882 | |||
| 1883 | // Slider decorations | ||
| 1884 | p.setPen(colors.outline); | ||
| 1885 | p.setBrush(colors.slider_arrow); | ||
| 1886 | DrawArrow(p, sideview_center + QPoint(0, 83), Direction::Down, 2.2f); | ||
| 1887 | DrawArrow(p, sideview_center + QPoint(0, 96), Direction::Down, 2.2f); | ||
| 1888 | DrawArrow(p, sideview_center + QPoint(0, 109), Direction::Down, 2.2f); | ||
| 1889 | DrawCircle(p, sideview_center + QPointF(0, 19), 4.44f); | ||
| 1890 | |||
| 1891 | // LED indicators | ||
| 1892 | const float led_size = 5.0f; | ||
| 1893 | const QPointF led_position = sideview_center + QPointF(0, -36); | ||
| 1894 | int led_count = 0; | ||
| 1895 | for (const auto color : led_color) { | ||
| 1896 | p.setBrush(color); | ||
| 1897 | DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); | ||
| 1898 | } | ||
| 1899 | } | ||
| 1900 | |||
| 1901 | void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, bool left_pressed, | ||
| 1902 | bool right_pressed) { | ||
| 1903 | std::array<QPointF, pro_left_trigger.size() / 2> qleft_trigger; | ||
| 1904 | std::array<QPointF, pro_left_trigger.size() / 2> qright_trigger; | ||
| 1905 | std::array<QPointF, pro_body_top.size()> qbody_top; | ||
| 1906 | |||
| 1907 | for (std::size_t point = 0; point < pro_left_trigger.size() / 2; ++point) { | ||
| 1908 | qleft_trigger[point] = | ||
| 1909 | center + QPointF(pro_left_trigger[point * 2], | ||
| 1910 | pro_left_trigger[point * 2 + 1] + (left_pressed ? 2 : 0)); | ||
| 1911 | qright_trigger[point] = | ||
| 1912 | center + QPointF(-pro_left_trigger[point * 2], | ||
| 1913 | pro_left_trigger[point * 2 + 1] + (right_pressed ? 2 : 0)); | ||
| 1914 | } | ||
| 1915 | |||
| 1916 | for (std::size_t point = 0; point < pro_body_top.size() / 2; ++point) { | ||
| 1917 | qbody_top[pro_body_top.size() - 1 - point] = | ||
| 1918 | center + QPointF(-pro_body_top[point * 2], pro_body_top[point * 2 + 1]); | ||
| 1919 | qbody_top[point] = center + QPointF(pro_body_top[point * 2], pro_body_top[point * 2 + 1]); | ||
| 1920 | } | ||
| 1921 | |||
| 1922 | // Pro body detail | ||
| 1923 | p.setPen(colors.outline); | ||
| 1924 | p.setBrush(colors.primary); | ||
| 1925 | DrawPolygon(p, qbody_top); | ||
| 1926 | |||
| 1927 | // Left trigger | ||
| 1928 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 1929 | DrawPolygon(p, qleft_trigger); | ||
| 1930 | |||
| 1931 | // Right trigger | ||
| 1932 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 1933 | DrawPolygon(p, qright_trigger); | ||
| 1934 | } | ||
| 1935 | |||
| 1936 | void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, bool left_pressed, | ||
| 1937 | bool right_pressed) { | ||
| 1938 | std::array<QPointF, left_gc_trigger.size() / 2> qleft_trigger; | ||
| 1939 | std::array<QPointF, left_gc_trigger.size() / 2> qright_trigger; | ||
| 1940 | |||
| 1941 | for (std::size_t point = 0; point < left_gc_trigger.size() / 2; ++point) { | ||
| 1942 | qleft_trigger[point] = | ||
| 1943 | center + QPointF(left_gc_trigger[point * 2], | ||
| 1944 | left_gc_trigger[point * 2 + 1] + (left_pressed ? 10 : 0)); | ||
| 1945 | qright_trigger[point] = | ||
| 1946 | center + QPointF(-left_gc_trigger[point * 2], | ||
| 1947 | left_gc_trigger[point * 2 + 1] + (right_pressed ? 10 : 0)); | ||
| 1948 | } | ||
| 1949 | |||
| 1950 | // Left trigger | ||
| 1951 | p.setPen(colors.outline); | ||
| 1952 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 1953 | DrawPolygon(p, qleft_trigger); | ||
| 1954 | |||
| 1955 | // Right trigger | ||
| 1956 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 1957 | DrawPolygon(p, qright_trigger); | ||
| 1958 | |||
| 1959 | // Draw L text | ||
| 1960 | p.setPen(colors.transparent); | ||
| 1961 | p.setBrush(colors.font); | ||
| 1962 | DrawSymbol(p, center + QPointF(-132, -119 + (left_pressed ? 10 : 0)), Symbol::L, 1.7f); | ||
| 1963 | |||
| 1964 | // Draw R text | ||
| 1965 | p.setPen(colors.transparent); | ||
| 1966 | p.setBrush(colors.font); | ||
| 1967 | DrawSymbol(p, center + QPointF(121.5f, -119 + (right_pressed ? 10 : 0)), Symbol::R, 1.7f); | ||
| 1968 | } | ||
| 1969 | |||
| 1970 | void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF center, | ||
| 1971 | bool left_pressed, bool right_pressed) { | ||
| 1972 | std::array<QPointF, left_joycon_trigger.size() / 2> qleft_trigger; | ||
| 1973 | std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger; | ||
| 1974 | |||
| 1975 | for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { | ||
| 1976 | qleft_trigger[point] = | ||
| 1977 | center + QPointF(left_joycon_trigger[point * 2], | ||
| 1978 | left_joycon_trigger[point * 2 + 1] + (left_pressed ? 0.5f : 0)); | ||
| 1979 | qright_trigger[point] = | ||
| 1980 | center + QPointF(-left_joycon_trigger[point * 2], | ||
| 1981 | left_joycon_trigger[point * 2 + 1] + (right_pressed ? 0.5f : 0)); | ||
| 1982 | } | ||
| 1983 | |||
| 1984 | // Left trigger | ||
| 1985 | p.setPen(colors.outline); | ||
| 1986 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 1987 | DrawPolygon(p, qleft_trigger); | ||
| 1988 | |||
| 1989 | // Right trigger | ||
| 1990 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 1991 | DrawPolygon(p, qright_trigger); | ||
| 1992 | } | ||
| 1993 | |||
| 1994 | void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, bool left_pressed, | ||
| 1995 | bool right_pressed) { | ||
| 1996 | std::array<QPointF, left_joycon_trigger.size() / 2> qleft_trigger; | ||
| 1997 | std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger; | ||
| 1998 | constexpr float size = 1.62f; | ||
| 1999 | constexpr float offset = 210.6f; | ||
| 2000 | for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { | ||
| 2001 | qleft_trigger[point] = | ||
| 2002 | center + QPointF(left_joycon_trigger[point * 2] * size + offset, | ||
| 2003 | left_joycon_trigger[point * 2 + 1] * size + (left_pressed ? 0.5f : 0)); | ||
| 2004 | qright_trigger[point] = center + QPointF(-left_joycon_trigger[point * 2] * size - offset, | ||
| 2005 | left_joycon_trigger[point * 2 + 1] * size + | ||
| 2006 | (right_pressed ? 0.5f : 0)); | ||
| 2007 | } | ||
| 2008 | |||
| 2009 | // Left trigger | ||
| 2010 | p.setPen(colors.outline); | ||
| 2011 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 2012 | DrawPolygon(p, qleft_trigger); | ||
| 2013 | |||
| 2014 | // Right trigger | ||
| 2015 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 2016 | DrawPolygon(p, qright_trigger); | ||
| 2017 | } | ||
| 2018 | |||
| 2019 | void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF center, | ||
| 2020 | bool left_pressed, bool right_pressed) { | ||
| 2021 | std::array<QPointF, left_joystick_L_topview.size() / 2> qleft_trigger; | ||
| 2022 | std::array<QPointF, left_joystick_L_topview.size() / 2> qright_trigger; | ||
| 2023 | constexpr float size = 0.9f; | ||
| 2024 | |||
| 2025 | for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { | ||
| 2026 | qleft_trigger[point] = center + QPointF(left_joystick_L_topview[point * 2] * size - 50, | ||
| 2027 | left_joystick_L_topview[point * 2 + 1] * size - 52); | ||
| 2028 | } | ||
| 2029 | for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { | ||
| 2030 | qright_trigger[point] = | ||
| 2031 | center + QPointF(-left_joystick_L_topview[point * 2] * size + 50, | ||
| 2032 | left_joystick_L_topview[point * 2 + 1] * size - 52); | ||
| 2033 | } | ||
| 2034 | |||
| 2035 | p.setPen(colors.outline); | ||
| 2036 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 2037 | DrawPolygon(p, qleft_trigger); | ||
| 2038 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 2039 | DrawPolygon(p, qright_trigger); | ||
| 2040 | |||
| 2041 | // Draw L text | ||
| 2042 | p.setPen(colors.transparent); | ||
| 2043 | p.setBrush(colors.font2); | ||
| 2044 | DrawSymbol(p, center + QPointF(-183, -84), Symbol::L, 1.0f); | ||
| 2045 | |||
| 2046 | // Draw R text | ||
| 2047 | p.setPen(colors.transparent); | ||
| 2048 | p.setBrush(colors.font2); | ||
| 2049 | DrawSymbol(p, center + QPointF(177, -84), Symbol::R, 1.0f); | ||
| 2050 | } | ||
| 2051 | |||
| 2052 | void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF center, | ||
| 2053 | bool left_pressed, bool right_pressed) { | ||
| 2054 | std::array<QPointF, left_joystick_ZL_topview.size() / 2> qleft_trigger; | ||
| 2055 | std::array<QPointF, left_joystick_ZL_topview.size() / 2> qright_trigger; | ||
| 2056 | constexpr float size = 0.9f; | ||
| 2057 | |||
| 2058 | for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { | ||
| 2059 | qleft_trigger[point] = | ||
| 2060 | center + QPointF(left_joystick_ZL_topview[point * 2] * size - 52, | ||
| 2061 | left_joystick_ZL_topview[point * 2 + 1] * size - 52); | ||
| 2062 | } | ||
| 2063 | for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { | ||
| 2064 | qright_trigger[point] = | ||
| 2065 | center + QPointF(-left_joystick_ZL_topview[point * 2] * size + 52, | ||
| 2066 | left_joystick_ZL_topview[point * 2 + 1] * size - 52); | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | p.setPen(colors.outline); | ||
| 2070 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 2071 | DrawPolygon(p, qleft_trigger); | ||
| 2072 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 2073 | DrawPolygon(p, qright_trigger); | ||
| 2074 | |||
| 2075 | // Draw ZL text | ||
| 2076 | p.setPen(colors.transparent); | ||
| 2077 | p.setBrush(colors.font2); | ||
| 2078 | DrawSymbol(p, center + QPointF(-180, -113), Symbol::ZL, 1.0f); | ||
| 2079 | |||
| 2080 | // Draw ZR text | ||
| 2081 | p.setPen(colors.transparent); | ||
| 2082 | p.setBrush(colors.font2); | ||
| 2083 | DrawSymbol(p, center + QPointF(180, -113), Symbol::ZR, 1.0f); | ||
| 2084 | } | ||
| 2085 | |||
| 2086 | void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, bool left_pressed) { | ||
| 2087 | std::array<QPointF, left_joycon_trigger.size() / 2> qleft_trigger; | ||
| 2088 | constexpr float size = 1.78f; | ||
| 2089 | constexpr float offset = 311.5f; | ||
| 2090 | |||
| 2091 | for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { | ||
| 2092 | qleft_trigger[point] = center + QPointF(left_joycon_trigger[point * 2] * size + offset, | ||
| 2093 | left_joycon_trigger[point * 2 + 1] * size - | ||
| 2094 | (left_pressed ? 0.5f : 1.0f)); | ||
| 2095 | } | ||
| 2096 | |||
| 2097 | p.setPen(colors.outline); | ||
| 2098 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 2099 | DrawPolygon(p, qleft_trigger); | ||
| 2100 | } | ||
| 2101 | |||
| 2102 | void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, bool left_pressed) { | ||
| 2103 | std::array<QPointF, left_joycon_sideview_zl.size() / 2> qleft_trigger; | ||
| 2104 | constexpr float size = 1.1115f; | ||
| 2105 | constexpr float offset2 = 335; | ||
| 2106 | |||
| 2107 | for (std::size_t point = 0; point < left_joycon_sideview_zl.size() / 2; ++point) { | ||
| 2108 | qleft_trigger[point] = center + QPointF(left_joycon_sideview_zl[point * 2] * size + offset2, | ||
| 2109 | left_joycon_sideview_zl[point * 2 + 1] * size + | ||
| 2110 | (left_pressed ? 1.5f : 1.0f)); | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | p.setPen(colors.outline); | ||
| 2114 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 2115 | DrawPolygon(p, qleft_trigger); | ||
| 2116 | p.drawArc(center.x() + 158, center.y() + (left_pressed ? -203.5f : -204.0f), 77, 77, 225 * 16, | ||
| 2117 | 44 * 16); | ||
| 2118 | } | ||
| 2119 | |||
| 2120 | void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF center, | ||
| 2121 | bool left_pressed) { | ||
| 2122 | std::array<QPointF, left_joystick_L_topview.size() / 2> qleft_trigger; | ||
| 2123 | |||
| 2124 | for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { | ||
| 2125 | qleft_trigger[point] = center + QPointF(left_joystick_L_topview[point * 2], | ||
| 2126 | left_joystick_L_topview[point * 2 + 1]); | ||
| 2127 | } | ||
| 2128 | |||
| 2129 | p.setPen(colors.outline); | ||
| 2130 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 2131 | DrawPolygon(p, qleft_trigger); | ||
| 2132 | |||
| 2133 | // Draw L text | ||
| 2134 | p.setPen(colors.transparent); | ||
| 2135 | p.setBrush(colors.font2); | ||
| 2136 | DrawSymbol(p, center + QPointF(-143, -36), Symbol::L, 1.0f); | ||
| 2137 | } | ||
| 2138 | |||
| 2139 | void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF center, | ||
| 2140 | bool left_pressed) { | ||
| 2141 | std::array<QPointF, left_joystick_ZL_topview.size() / 2> qleft_trigger; | ||
| 2142 | |||
| 2143 | for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { | ||
| 2144 | qleft_trigger[point] = center + QPointF(left_joystick_ZL_topview[point * 2], | ||
| 2145 | left_joystick_ZL_topview[point * 2 + 1]); | ||
| 2146 | } | ||
| 2147 | |||
| 2148 | p.setPen(colors.outline); | ||
| 2149 | p.setBrush(left_pressed ? colors.highlight : colors.button); | ||
| 2150 | DrawPolygon(p, qleft_trigger); | ||
| 2151 | |||
| 2152 | // Draw ZL text | ||
| 2153 | p.setPen(colors.transparent); | ||
| 2154 | p.setBrush(colors.font2); | ||
| 2155 | DrawSymbol(p, center + QPointF(-140, -68), Symbol::ZL, 1.0f); | ||
| 2156 | } | ||
| 2157 | |||
| 2158 | void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, | ||
| 2159 | bool right_pressed) { | ||
| 2160 | std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger; | ||
| 2161 | constexpr float size = 1.78f; | ||
| 2162 | constexpr float offset = 311.5f; | ||
| 2163 | |||
| 2164 | for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { | ||
| 2165 | qright_trigger[point] = center + QPointF(-left_joycon_trigger[point * 2] * size - offset, | ||
| 2166 | left_joycon_trigger[point * 2 + 1] * size - | ||
| 2167 | (right_pressed ? 0.5f : 1.0f)); | ||
| 2168 | } | ||
| 2169 | |||
| 2170 | p.setPen(colors.outline); | ||
| 2171 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 2172 | DrawPolygon(p, qright_trigger); | ||
| 2173 | } | ||
| 2174 | |||
| 2175 | void PlayerControlPreview::DrawRightZTriggers(QPainter& p, const QPointF center, | ||
| 2176 | bool right_pressed) { | ||
| 2177 | std::array<QPointF, left_joycon_sideview_zl.size() / 2> qright_trigger; | ||
| 2178 | constexpr float size = 1.1115f; | ||
| 2179 | constexpr float offset2 = 335; | ||
| 2180 | |||
| 2181 | for (std::size_t point = 0; point < left_joycon_sideview_zl.size() / 2; ++point) { | ||
| 2182 | qright_trigger[point] = | ||
| 2183 | center + | ||
| 2184 | QPointF(-left_joycon_sideview_zl[point * 2] * size - offset2, | ||
| 2185 | left_joycon_sideview_zl[point * 2 + 1] * size + (right_pressed ? 0.5f : 0) + 1); | ||
| 2186 | } | ||
| 2187 | |||
| 2188 | p.setPen(colors.outline); | ||
| 2189 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 2190 | DrawPolygon(p, qright_trigger); | ||
| 2191 | p.drawArc(center.x() - 236, center.y() + (right_pressed ? -203.5f : -204.0f), 77, 77, 271 * 16, | ||
| 2192 | 44 * 16); | ||
| 2193 | } | ||
| 2194 | |||
| 2195 | void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF center, | ||
| 2196 | bool right_pressed) { | ||
| 2197 | std::array<QPointF, left_joystick_L_topview.size() / 2> qright_trigger; | ||
| 2198 | |||
| 2199 | for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { | ||
| 2200 | qright_trigger[point] = center + QPointF(-left_joystick_L_topview[point * 2], | ||
| 2201 | left_joystick_L_topview[point * 2 + 1]); | ||
| 2202 | } | ||
| 2203 | |||
| 2204 | p.setPen(colors.outline); | ||
| 2205 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 2206 | DrawPolygon(p, qright_trigger); | ||
| 2207 | |||
| 2208 | // Draw R text | ||
| 2209 | p.setPen(colors.transparent); | ||
| 2210 | p.setBrush(colors.font2); | ||
| 2211 | DrawSymbol(p, center + QPointF(137, -36), Symbol::R, 1.0f); | ||
| 2212 | } | ||
| 2213 | |||
| 2214 | void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF center, | ||
| 2215 | bool right_pressed) { | ||
| 2216 | std::array<QPointF, left_joystick_ZL_topview.size() / 2> qright_trigger; | ||
| 2217 | |||
| 2218 | for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { | ||
| 2219 | qright_trigger[point] = center + QPointF(-left_joystick_ZL_topview[point * 2], | ||
| 2220 | left_joystick_ZL_topview[point * 2 + 1]); | ||
| 2221 | } | ||
| 2222 | |||
| 2223 | p.setPen(colors.outline); | ||
| 2224 | p.setBrush(right_pressed ? colors.highlight : colors.button); | ||
| 2225 | DrawPolygon(p, qright_trigger); | ||
| 2226 | |||
| 2227 | // Draw ZR text | ||
| 2228 | p.setPen(colors.transparent); | ||
| 2229 | p.setBrush(colors.font2); | ||
| 2230 | DrawSymbol(p, center + QPointF(140, -68), Symbol::ZR, 1.0f); | ||
| 2231 | } | ||
| 2232 | |||
| 2233 | void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float size, | ||
| 2234 | bool pressed) { | ||
| 2235 | const float radius1 = 13.0f * size; | ||
| 2236 | const float radius2 = 9.0f * size; | ||
| 2237 | |||
| 2238 | // Outer circle | ||
| 2239 | p.setPen(colors.outline); | ||
| 2240 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2241 | DrawCircle(p, center, radius1); | ||
| 2242 | |||
| 2243 | // Cross | ||
| 2244 | p.drawLine(center - QPoint(radius1, 0), center + QPoint(radius1, 0)); | ||
| 2245 | p.drawLine(center - QPoint(0, radius1), center + QPoint(0, radius1)); | ||
| 2246 | |||
| 2247 | // Inner circle | ||
| 2248 | p.setBrush(pressed ? colors.highlight2 : colors.button2); | ||
| 2249 | DrawCircle(p, center, radius2); | ||
| 2250 | } | ||
| 2251 | |||
| 2252 | void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF center, float angle, | ||
| 2253 | float size, bool pressed) { | ||
| 2254 | QVector<QPointF> joystick; | ||
| 2255 | joystick.reserve(static_cast<int>(left_joystick_sideview.size() / 2)); | ||
| 2256 | |||
| 2257 | for (std::size_t point = 0; point < left_joystick_sideview.size() / 2; ++point) { | ||
| 2258 | joystick.append(QPointF(left_joystick_sideview[point * 2] * size + (pressed ? 1 : 0), | ||
| 2259 | left_joystick_sideview[point * 2 + 1] * size - 1)); | ||
| 2260 | } | ||
| 2261 | |||
| 2262 | // Rotate joystick | ||
| 2263 | QTransform t; | ||
| 2264 | t.translate(center.x(), center.y()); | ||
| 2265 | t.rotate(18 * angle); | ||
| 2266 | QPolygonF p2 = t.map(QPolygonF(joystick)); | ||
| 2267 | |||
| 2268 | // Draw joystick | ||
| 2269 | p.setPen(colors.outline); | ||
| 2270 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2271 | p.drawPolygon(p2); | ||
| 2272 | p.drawLine(p2.at(1), p2.at(30)); | ||
| 2273 | p.drawLine(p2.at(32), p2.at(71)); | ||
| 2274 | } | ||
| 2275 | |||
| 2276 | void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, bool pressed) { | ||
| 2277 | // Outer circle | ||
| 2278 | p.setPen(colors.outline); | ||
| 2279 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2280 | DrawCircle(p, center, 24.0f); | ||
| 2281 | |||
| 2282 | // Inner circle | ||
| 2283 | p.setBrush(pressed ? colors.highlight2 : colors.button2); | ||
| 2284 | DrawCircle(p, center, 17.0f); | ||
| 2285 | } | ||
| 2286 | |||
| 2287 | void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, bool pressed) { | ||
| 2288 | // Outer circle | ||
| 2289 | p.setPen(colors.outline); | ||
| 2290 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2291 | DrawCircle(p, center, 26.0f); | ||
| 2292 | |||
| 2293 | // Inner circle | ||
| 2294 | p.setBrush(pressed ? colors.highlight2 : colors.button2); | ||
| 2295 | DrawCircle(p, center, 19.0f); | ||
| 2296 | p.setBrush(colors.transparent); | ||
| 2297 | DrawCircle(p, center, 13.5f); | ||
| 2298 | DrawCircle(p, center, 7.5f); | ||
| 2299 | } | ||
| 2300 | |||
| 2301 | void PlayerControlPreview::DrawRawJoystick(QPainter& p, const QPointF center, const QPointF value, | ||
| 2302 | const Input::AnalogProperties properties) { | ||
| 2303 | constexpr float size = 45.0f; | ||
| 2304 | const float range = size * properties.range; | ||
| 2305 | const float deadzone = size * properties.deadzone; | ||
| 2306 | |||
| 2307 | // Max range zone circle | ||
| 2308 | p.setPen(colors.outline); | ||
| 2309 | p.setBrush(colors.transparent); | ||
| 2310 | QPen pen = p.pen(); | ||
| 2311 | pen.setStyle(Qt::DotLine); | ||
| 2312 | p.setPen(pen); | ||
| 2313 | DrawCircle(p, center, range); | ||
| 2314 | |||
| 2315 | // Deadzone circle | ||
| 2316 | pen.setColor(colors.deadzone); | ||
| 2317 | p.setPen(pen); | ||
| 2318 | DrawCircle(p, center, deadzone); | ||
| 2319 | |||
| 2320 | // Dot pointer | ||
| 2321 | p.setPen(colors.indicator); | ||
| 2322 | p.setBrush(colors.indicator); | ||
| 2323 | DrawCircle(p, center + (value * range), 2); | ||
| 2324 | } | ||
| 2325 | |||
| 2326 | void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, | ||
| 2327 | float height, Direction direction, float radius) { | ||
| 2328 | p.setBrush(button_color); | ||
| 2329 | if (pressed) { | ||
| 2330 | switch (direction) { | ||
| 2331 | case Direction::Left: | ||
| 2332 | center.setX(center.x() - 1); | ||
| 2333 | break; | ||
| 2334 | case Direction::Right: | ||
| 2335 | center.setX(center.x() + 1); | ||
| 2336 | break; | ||
| 2337 | case Direction::Down: | ||
| 2338 | center.setY(center.y() + 1); | ||
| 2339 | break; | ||
| 2340 | case Direction::Up: | ||
| 2341 | center.setY(center.y() - 1); | ||
| 2342 | break; | ||
| 2343 | case Direction::None: | ||
| 2344 | break; | ||
| 2345 | } | ||
| 2346 | p.setBrush(colors.highlight); | ||
| 2347 | } | ||
| 2348 | QRectF rect = {center.x() - width, center.y() - height, width * 2.0f, height * 2.0f}; | ||
| 2349 | p.drawRoundedRect(rect, radius, radius); | ||
| 2350 | } | ||
| 2351 | void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, bool pressed, | ||
| 2352 | int button_size) { | ||
| 2353 | p.setPen(colors.outline); | ||
| 2354 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2355 | DrawRectangle(p, center, button_size, button_size / 3.0f); | ||
| 2356 | } | ||
| 2357 | void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, bool pressed, | ||
| 2358 | int button_size) { | ||
| 2359 | // Draw outer line | ||
| 2360 | p.setPen(colors.outline); | ||
| 2361 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2362 | DrawRectangle(p, center, button_size, button_size / 3.0f); | ||
| 2363 | DrawRectangle(p, center, button_size / 3.0f, button_size); | ||
| 2364 | |||
| 2365 | // Scale down size | ||
| 2366 | button_size *= 0.88f; | ||
| 2367 | |||
| 2368 | // Draw inner color | ||
| 2369 | p.setPen(colors.transparent); | ||
| 2370 | DrawRectangle(p, center, button_size, button_size / 3.0f); | ||
| 2371 | DrawRectangle(p, center, button_size / 3.0f, button_size); | ||
| 2372 | } | ||
| 2373 | |||
| 2374 | void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, bool pressed) { | ||
| 2375 | std::array<QPointF, gc_button_x.size() / 2> button_x; | ||
| 2376 | |||
| 2377 | for (std::size_t point = 0; point < gc_button_x.size() / 2; ++point) { | ||
| 2378 | button_x[point] = center + QPointF(gc_button_x[point * 2], gc_button_x[point * 2 + 1]); | ||
| 2379 | } | ||
| 2380 | |||
| 2381 | p.setPen(colors.outline); | ||
| 2382 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2383 | DrawPolygon(p, button_x); | ||
| 2384 | } | ||
| 2385 | |||
| 2386 | void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, bool pressed) { | ||
| 2387 | std::array<QPointF, gc_button_y.size() / 2> button_x; | ||
| 2388 | |||
| 2389 | for (std::size_t point = 0; point < gc_button_y.size() / 2; ++point) { | ||
| 2390 | button_x[point] = center + QPointF(gc_button_y[point * 2], gc_button_y[point * 2 + 1]); | ||
| 2391 | } | ||
| 2392 | |||
| 2393 | p.setPen(colors.outline); | ||
| 2394 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2395 | DrawPolygon(p, button_x); | ||
| 2396 | } | ||
| 2397 | |||
| 2398 | void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, bool pressed) { | ||
| 2399 | std::array<QPointF, gc_button_z.size() / 2> button_x; | ||
| 2400 | |||
| 2401 | for (std::size_t point = 0; point < gc_button_z.size() / 2; ++point) { | ||
| 2402 | button_x[point] = center + QPointF(gc_button_z[point * 2], | ||
| 2403 | gc_button_z[point * 2 + 1] + (pressed ? 1 : 0)); | ||
| 2404 | } | ||
| 2405 | |||
| 2406 | p.setPen(colors.outline); | ||
| 2407 | p.setBrush(pressed ? colors.highlight : colors.button2); | ||
| 2408 | DrawPolygon(p, button_x); | ||
| 2409 | } | ||
| 2410 | |||
| 2411 | void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, bool pressed, | ||
| 2412 | float button_size) { | ||
| 2413 | p.setBrush(button_color); | ||
| 2414 | if (pressed) { | ||
| 2415 | p.setBrush(colors.highlight); | ||
| 2416 | } | ||
| 2417 | p.drawEllipse(center, button_size, button_size); | ||
| 2418 | } | ||
| 2419 | |||
| 2420 | void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF center, float size) { | ||
| 2421 | const std::size_t arrow_points = up_arrow_button.size() / 2; | ||
| 2422 | std::array<QPointF, (arrow_points - 1) * 4> arrow_button_outline; | ||
| 2423 | |||
| 2424 | for (std::size_t point = 0; point < arrow_points - 1; ++point) { | ||
| 2425 | arrow_button_outline[point] = center + QPointF(up_arrow_button[point * 2] * size, | ||
| 2426 | up_arrow_button[point * 2 + 1] * size); | ||
| 2427 | arrow_button_outline[(arrow_points - 1) * 2 - point - 1] = | ||
| 2428 | center + | ||
| 2429 | QPointF(up_arrow_button[point * 2 + 1] * size, up_arrow_button[point * 2] * size); | ||
| 2430 | arrow_button_outline[(arrow_points - 1) * 2 + point] = | ||
| 2431 | center + | ||
| 2432 | QPointF(-up_arrow_button[point * 2] * size, -up_arrow_button[point * 2 + 1] * size); | ||
| 2433 | arrow_button_outline[(arrow_points - 1) * 4 - point - 1] = | ||
| 2434 | center + | ||
| 2435 | QPointF(-up_arrow_button[point * 2 + 1] * size, -up_arrow_button[point * 2] * size); | ||
| 2436 | } | ||
| 2437 | // Draw arrow button outline | ||
| 2438 | p.setPen(colors.outline); | ||
| 2439 | p.setBrush(colors.transparent); | ||
| 2440 | DrawPolygon(p, arrow_button_outline); | ||
| 2441 | } | ||
| 2442 | |||
| 2443 | void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, | ||
| 2444 | const Direction direction, bool pressed, float size) { | ||
| 2445 | std::array<QPointF, up_arrow_button.size() / 2> arrow_button; | ||
| 2446 | QPoint offset; | ||
| 2447 | |||
| 2448 | for (std::size_t point = 0; point < up_arrow_button.size() / 2; ++point) { | ||
| 2449 | switch (direction) { | ||
| 2450 | case Direction::Up: | ||
| 2451 | arrow_button[point] = center + QPointF(up_arrow_button[point * 2] * size, | ||
| 2452 | up_arrow_button[point * 2 + 1] * size); | ||
| 2453 | break; | ||
| 2454 | case Direction::Left: | ||
| 2455 | arrow_button[point] = center + QPointF(up_arrow_button[point * 2 + 1] * size, | ||
| 2456 | up_arrow_button[point * 2] * size); | ||
| 2457 | break; | ||
| 2458 | case Direction::Right: | ||
| 2459 | arrow_button[point] = center + QPointF(-up_arrow_button[point * 2 + 1] * size, | ||
| 2460 | up_arrow_button[point * 2] * size); | ||
| 2461 | break; | ||
| 2462 | case Direction::Down: | ||
| 2463 | arrow_button[point] = center + QPointF(up_arrow_button[point * 2] * size, | ||
| 2464 | -up_arrow_button[point * 2 + 1] * size); | ||
| 2465 | break; | ||
| 2466 | case Direction::None: | ||
| 2467 | break; | ||
| 2468 | } | ||
| 2469 | } | ||
| 2470 | |||
| 2471 | // Draw arrow button | ||
| 2472 | p.setPen(pressed ? colors.highlight : colors.button); | ||
| 2473 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2474 | DrawPolygon(p, arrow_button); | ||
| 2475 | |||
| 2476 | switch (direction) { | ||
| 2477 | case Direction::Up: | ||
| 2478 | offset = QPoint(0, -20 * size); | ||
| 2479 | break; | ||
| 2480 | case Direction::Left: | ||
| 2481 | offset = QPoint(-20 * size, 0); | ||
| 2482 | break; | ||
| 2483 | case Direction::Right: | ||
| 2484 | offset = QPoint(20 * size, 0); | ||
| 2485 | break; | ||
| 2486 | case Direction::Down: | ||
| 2487 | offset = QPoint(0, 20 * size); | ||
| 2488 | break; | ||
| 2489 | case Direction::None: | ||
| 2490 | offset = QPoint(0, 0); | ||
| 2491 | break; | ||
| 2492 | } | ||
| 2493 | |||
| 2494 | // Draw arrow icon | ||
| 2495 | p.setPen(colors.font2); | ||
| 2496 | p.setBrush(colors.font2); | ||
| 2497 | DrawArrow(p, center + offset, direction, size); | ||
| 2498 | } | ||
| 2499 | |||
| 2500 | void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, | ||
| 2501 | const Direction direction, bool pressed) { | ||
| 2502 | std::array<QPointF, trigger_button.size() / 2> qtrigger_button; | ||
| 2503 | QPoint offset; | ||
| 2504 | |||
| 2505 | for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) { | ||
| 2506 | switch (direction) { | ||
| 2507 | case Direction::Left: | ||
| 2508 | qtrigger_button[point] = | ||
| 2509 | center + QPointF(-trigger_button[point * 2], trigger_button[point * 2 + 1]); | ||
| 2510 | break; | ||
| 2511 | case Direction::Right: | ||
| 2512 | qtrigger_button[point] = | ||
| 2513 | center + QPointF(trigger_button[point * 2], trigger_button[point * 2 + 1]); | ||
| 2514 | break; | ||
| 2515 | case Direction::Up: | ||
| 2516 | case Direction::Down: | ||
| 2517 | case Direction::None: | ||
| 2518 | break; | ||
| 2519 | } | ||
| 2520 | } | ||
| 2521 | |||
| 2522 | // Draw arrow button | ||
| 2523 | p.setPen(colors.outline); | ||
| 2524 | p.setBrush(pressed ? colors.highlight : colors.button); | ||
| 2525 | DrawPolygon(p, qtrigger_button); | ||
| 2526 | } | ||
| 2527 | |||
| 2528 | void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol symbol, | ||
| 2529 | float icon_size) { | ||
| 2530 | std::array<QPointF, house.size() / 2> house_icon; | ||
| 2531 | std::array<QPointF, symbol_a.size() / 2> a_icon; | ||
| 2532 | std::array<QPointF, symbol_b.size() / 2> b_icon; | ||
| 2533 | std::array<QPointF, symbol_x.size() / 2> x_icon; | ||
| 2534 | std::array<QPointF, symbol_y.size() / 2> y_icon; | ||
| 2535 | std::array<QPointF, symbol_l.size() / 2> l_icon; | ||
| 2536 | std::array<QPointF, symbol_r.size() / 2> r_icon; | ||
| 2537 | std::array<QPointF, symbol_c.size() / 2> c_icon; | ||
| 2538 | std::array<QPointF, symbol_zl.size() / 2> zl_icon; | ||
| 2539 | std::array<QPointF, symbol_sl.size() / 2> sl_icon; | ||
| 2540 | std::array<QPointF, symbol_zr.size() / 2> zr_icon; | ||
| 2541 | std::array<QPointF, symbol_sr.size() / 2> sr_icon; | ||
| 2542 | switch (symbol) { | ||
| 2543 | case Symbol::House: | ||
| 2544 | for (std::size_t point = 0; point < house.size() / 2; ++point) { | ||
| 2545 | house_icon[point] = center + QPointF(house[point * 2] * icon_size, | ||
| 2546 | (house[point * 2 + 1] - 0.025f) * icon_size); | ||
| 2547 | } | ||
| 2548 | p.drawPolygon(house_icon.data(), static_cast<int>(house_icon.size())); | ||
| 2549 | break; | ||
| 2550 | case Symbol::A: | ||
| 2551 | for (std::size_t point = 0; point < symbol_a.size() / 2; ++point) { | ||
| 2552 | a_icon[point] = center + QPointF(symbol_a[point * 2] * icon_size, | ||
| 2553 | symbol_a[point * 2 + 1] * icon_size); | ||
| 2554 | } | ||
| 2555 | p.drawPolygon(a_icon.data(), static_cast<int>(a_icon.size())); | ||
| 2556 | break; | ||
| 2557 | case Symbol::B: | ||
| 2558 | for (std::size_t point = 0; point < symbol_b.size() / 2; ++point) { | ||
| 2559 | b_icon[point] = center + QPointF(symbol_b[point * 2] * icon_size, | ||
| 2560 | symbol_b[point * 2 + 1] * icon_size); | ||
| 2561 | } | ||
| 2562 | p.drawPolygon(b_icon.data(), static_cast<int>(b_icon.size())); | ||
| 2563 | break; | ||
| 2564 | case Symbol::X: | ||
| 2565 | for (std::size_t point = 0; point < symbol_x.size() / 2; ++point) { | ||
| 2566 | x_icon[point] = center + QPointF(symbol_x[point * 2] * icon_size, | ||
| 2567 | symbol_x[point * 2 + 1] * icon_size); | ||
| 2568 | } | ||
| 2569 | p.drawPolygon(x_icon.data(), static_cast<int>(x_icon.size())); | ||
| 2570 | break; | ||
| 2571 | case Symbol::Y: | ||
| 2572 | for (std::size_t point = 0; point < symbol_y.size() / 2; ++point) { | ||
| 2573 | y_icon[point] = center + QPointF(symbol_y[point * 2] * icon_size, | ||
| 2574 | (symbol_y[point * 2 + 1] - 1.0f) * icon_size); | ||
| 2575 | } | ||
| 2576 | p.drawPolygon(y_icon.data(), static_cast<int>(y_icon.size())); | ||
| 2577 | break; | ||
| 2578 | case Symbol::L: | ||
| 2579 | for (std::size_t point = 0; point < symbol_l.size() / 2; ++point) { | ||
| 2580 | l_icon[point] = center + QPointF(symbol_l[point * 2] * icon_size, | ||
| 2581 | (symbol_l[point * 2 + 1] - 1.0f) * icon_size); | ||
| 2582 | } | ||
| 2583 | p.drawPolygon(l_icon.data(), static_cast<int>(l_icon.size())); | ||
| 2584 | break; | ||
| 2585 | case Symbol::R: | ||
| 2586 | for (std::size_t point = 0; point < symbol_r.size() / 2; ++point) { | ||
| 2587 | r_icon[point] = center + QPointF(symbol_r[point * 2] * icon_size, | ||
| 2588 | (symbol_r[point * 2 + 1] - 1.0f) * icon_size); | ||
| 2589 | } | ||
| 2590 | p.drawPolygon(r_icon.data(), static_cast<int>(r_icon.size())); | ||
| 2591 | break; | ||
| 2592 | case Symbol::C: | ||
| 2593 | for (std::size_t point = 0; point < symbol_c.size() / 2; ++point) { | ||
| 2594 | c_icon[point] = center + QPointF(symbol_c[point * 2] * icon_size, | ||
| 2595 | (symbol_c[point * 2 + 1] - 1.0f) * icon_size); | ||
| 2596 | } | ||
| 2597 | p.drawPolygon(c_icon.data(), static_cast<int>(c_icon.size())); | ||
| 2598 | break; | ||
| 2599 | case Symbol::ZL: | ||
| 2600 | for (std::size_t point = 0; point < symbol_zl.size() / 2; ++point) { | ||
| 2601 | zl_icon[point] = center + QPointF(symbol_zl[point * 2] * icon_size, | ||
| 2602 | symbol_zl[point * 2 + 1] * icon_size); | ||
| 2603 | } | ||
| 2604 | p.drawPolygon(zl_icon.data(), static_cast<int>(zl_icon.size())); | ||
| 2605 | break; | ||
| 2606 | case Symbol::SL: | ||
| 2607 | for (std::size_t point = 0; point < symbol_sl.size() / 2; ++point) { | ||
| 2608 | sl_icon[point] = center + QPointF(symbol_sl[point * 2] * icon_size, | ||
| 2609 | symbol_sl[point * 2 + 1] * icon_size); | ||
| 2610 | } | ||
| 2611 | p.drawPolygon(sl_icon.data(), static_cast<int>(sl_icon.size())); | ||
| 2612 | break; | ||
| 2613 | case Symbol::ZR: | ||
| 2614 | for (std::size_t point = 0; point < symbol_zr.size() / 2; ++point) { | ||
| 2615 | zr_icon[point] = center + QPointF(symbol_zr[point * 2] * icon_size, | ||
| 2616 | symbol_zr[point * 2 + 1] * icon_size); | ||
| 2617 | } | ||
| 2618 | p.drawPolygon(zr_icon.data(), static_cast<int>(zr_icon.size())); | ||
| 2619 | break; | ||
| 2620 | case Symbol::SR: | ||
| 2621 | for (std::size_t point = 0; point < symbol_sr.size() / 2; ++point) { | ||
| 2622 | sr_icon[point] = center + QPointF(symbol_sr[point * 2] * icon_size, | ||
| 2623 | symbol_sr[point * 2 + 1] * icon_size); | ||
| 2624 | } | ||
| 2625 | p.drawPolygon(sr_icon.data(), static_cast<int>(sr_icon.size())); | ||
| 2626 | break; | ||
| 2627 | } | ||
| 2628 | } | ||
| 2629 | |||
| 2630 | void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Direction direction, | ||
| 2631 | float size) { | ||
| 2632 | |||
| 2633 | std::array<QPointF, up_arrow_symbol.size() / 2> arrow_symbol; | ||
| 2634 | |||
| 2635 | for (std::size_t point = 0; point < up_arrow_symbol.size() / 2; ++point) { | ||
| 2636 | switch (direction) { | ||
| 2637 | case Direction::Up: | ||
| 2638 | arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2] * size, | ||
| 2639 | up_arrow_symbol[point * 2 + 1] * size); | ||
| 2640 | break; | ||
| 2641 | case Direction::Left: | ||
| 2642 | arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2 + 1] * size, | ||
| 2643 | up_arrow_symbol[point * 2] * size); | ||
| 2644 | break; | ||
| 2645 | case Direction::Right: | ||
| 2646 | arrow_symbol[point] = center + QPointF(-up_arrow_symbol[point * 2 + 1] * size, | ||
| 2647 | up_arrow_symbol[point * 2] * size); | ||
| 2648 | break; | ||
| 2649 | case Direction::Down: | ||
| 2650 | arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2] * size, | ||
| 2651 | -up_arrow_symbol[point * 2 + 1] * size); | ||
| 2652 | break; | ||
| 2653 | case Direction::None: | ||
| 2654 | break; | ||
| 2655 | } | ||
| 2656 | } | ||
| 2657 | |||
| 2658 | DrawPolygon(p, arrow_symbol); | ||
| 2659 | } | ||
| 2660 | |||
| 2661 | template <size_t N> | ||
| 2662 | void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) { | ||
| 2663 | p.drawPolygon(polygon.data(), static_cast<int>(polygon.size())); | ||
| 2664 | } | ||
| 2665 | |||
| 2666 | void PlayerControlPreview::DrawCircle(QPainter& p, const QPointF center, float size) { | ||
| 2667 | p.drawEllipse(center, size, size); | ||
| 2668 | } | ||
| 2669 | |||
| 2670 | void PlayerControlPreview::DrawRectangle(QPainter& p, const QPointF center, float width, | ||
| 2671 | float height) { | ||
| 2672 | const QRectF rect = QRectF(center.x() - (width / 2), center.y() - (height / 2), width, height); | ||
| 2673 | p.drawRect(rect); | ||
| 2674 | } | ||
| 2675 | void PlayerControlPreview::DrawRoundRectangle(QPainter& p, const QPointF center, float width, | ||
| 2676 | float height, float round) { | ||
| 2677 | const QRectF rect = QRectF(center.x() - (width / 2), center.y() - (height / 2), width, height); | ||
| 2678 | p.drawRoundedRect(rect, round, round); | ||
| 2679 | } | ||
| 2680 | |||
| 2681 | void PlayerControlPreview::DrawText(QPainter& p, const QPointF center, float text_size, | ||
| 2682 | const QString& text) { | ||
| 2683 | SetTextFont(p, text_size); | ||
| 2684 | const QFontMetrics fm(p.font()); | ||
| 2685 | const QPointF offset = {fm.horizontalAdvance(text) / 2.0f, -text_size / 2.0f}; | ||
| 2686 | p.drawText(center - offset, text); | ||
| 2687 | } | ||
| 2688 | |||
| 2689 | void PlayerControlPreview::SetTextFont(QPainter& p, float text_size, const QString& font_family) { | ||
| 2690 | QFont font = p.font(); | ||
| 2691 | font.setPointSizeF(text_size); | ||
| 2692 | font.setFamily(font_family); | ||
| 2693 | p.setFont(font); | ||
| 2694 | } | ||
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h new file mode 100644 index 000000000..39565f795 --- /dev/null +++ b/src/yuzu/configuration/configure_input_player_widget.h | |||
| @@ -0,0 +1,192 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <QFrame> | ||
| 9 | #include <QPointer> | ||
| 10 | #include "core/frontend/input.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | class QLabel; | ||
| 14 | |||
| 15 | using AnalogParam = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>; | ||
| 16 | using ButtonParam = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>; | ||
| 17 | |||
| 18 | // Widget for representing controller animations | ||
| 19 | class PlayerControlPreview : public QFrame { | ||
| 20 | Q_OBJECT | ||
| 21 | |||
| 22 | public: | ||
| 23 | explicit PlayerControlPreview(QWidget* parent); | ||
| 24 | ~PlayerControlPreview() override; | ||
| 25 | |||
| 26 | void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param, | ||
| 27 | const AnalogParam& analogs_param); | ||
| 28 | void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw buttons_, | ||
| 29 | Settings::AnalogsRaw analogs_); | ||
| 30 | void SetConnectedStatus(bool checked); | ||
| 31 | void SetControllerType(Settings::ControllerType type); | ||
| 32 | void BeginMappingButton(std::size_t button_id); | ||
| 33 | void BeginMappingAnalog(std::size_t button_id); | ||
| 34 | void EndMapping(); | ||
| 35 | void UpdateInput(); | ||
| 36 | |||
| 37 | protected: | ||
| 38 | void paintEvent(QPaintEvent* event) override; | ||
| 39 | |||
| 40 | private: | ||
| 41 | enum class Direction : std::size_t { | ||
| 42 | None, | ||
| 43 | Up, | ||
| 44 | Right, | ||
| 45 | Down, | ||
| 46 | Left, | ||
| 47 | }; | ||
| 48 | |||
| 49 | enum class Symbol { | ||
| 50 | House, | ||
| 51 | A, | ||
| 52 | B, | ||
| 53 | X, | ||
| 54 | Y, | ||
| 55 | L, | ||
| 56 | R, | ||
| 57 | C, | ||
| 58 | SL, | ||
| 59 | ZL, | ||
| 60 | ZR, | ||
| 61 | SR, | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct AxisValue { | ||
| 65 | QPointF value{}; | ||
| 66 | QPointF raw_value{}; | ||
| 67 | Input::AnalogProperties properties{}; | ||
| 68 | int size{}; | ||
| 69 | QPoint offset{}; | ||
| 70 | bool active{}; | ||
| 71 | }; | ||
| 72 | |||
| 73 | struct LedPattern { | ||
| 74 | bool position1; | ||
| 75 | bool position2; | ||
| 76 | bool position3; | ||
| 77 | bool position4; | ||
| 78 | }; | ||
| 79 | |||
| 80 | struct ColorMapping { | ||
| 81 | QColor outline{}; | ||
| 82 | QColor primary{}; | ||
| 83 | QColor left{}; | ||
| 84 | QColor right{}; | ||
| 85 | QColor button{}; | ||
| 86 | QColor button2{}; | ||
| 87 | QColor font{}; | ||
| 88 | QColor font2{}; | ||
| 89 | QColor highlight{}; | ||
| 90 | QColor highlight2{}; | ||
| 91 | QColor transparent{}; | ||
| 92 | QColor indicator{}; | ||
| 93 | QColor led_on{}; | ||
| 94 | QColor led_off{}; | ||
| 95 | QColor slider{}; | ||
| 96 | QColor slider_button{}; | ||
| 97 | QColor slider_arrow{}; | ||
| 98 | QColor deadzone{}; | ||
| 99 | }; | ||
| 100 | |||
| 101 | static LedPattern GetColorPattern(std::size_t index, bool player_on); | ||
| 102 | void UpdateColors(); | ||
| 103 | |||
| 104 | // Draw controller functions | ||
| 105 | void DrawHandheldController(QPainter& p, QPointF center); | ||
| 106 | void DrawDualController(QPainter& p, QPointF center); | ||
| 107 | void DrawLeftController(QPainter& p, QPointF center); | ||
| 108 | void DrawRightController(QPainter& p, QPointF center); | ||
| 109 | void DrawProController(QPainter& p, QPointF center); | ||
| 110 | void DrawGCController(QPainter& p, QPointF center); | ||
| 111 | |||
| 112 | // Draw body functions | ||
| 113 | void DrawHandheldBody(QPainter& p, QPointF center); | ||
| 114 | void DrawDualBody(QPainter& p, QPointF center); | ||
| 115 | void DrawLeftBody(QPainter& p, QPointF center); | ||
| 116 | void DrawRightBody(QPainter& p, QPointF center); | ||
| 117 | void DrawProBody(QPainter& p, QPointF center); | ||
| 118 | void DrawGCBody(QPainter& p, QPointF center); | ||
| 119 | |||
| 120 | // Draw triggers functions | ||
| 121 | void DrawProTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); | ||
| 122 | void DrawGCTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); | ||
| 123 | void DrawHandheldTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); | ||
| 124 | void DrawDualTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); | ||
| 125 | void DrawDualTriggersTopView(QPainter& p, QPointF center, bool left_pressed, | ||
| 126 | bool right_pressed); | ||
| 127 | void DrawDualZTriggersTopView(QPainter& p, QPointF center, bool left_pressed, | ||
| 128 | bool right_pressed); | ||
| 129 | void DrawLeftTriggers(QPainter& p, QPointF center, bool left_pressed); | ||
| 130 | void DrawLeftZTriggers(QPainter& p, QPointF center, bool left_pressed); | ||
| 131 | void DrawLeftTriggersTopView(QPainter& p, QPointF center, bool left_pressed); | ||
| 132 | void DrawLeftZTriggersTopView(QPainter& p, QPointF center, bool left_pressed); | ||
| 133 | void DrawRightTriggers(QPainter& p, QPointF center, bool right_pressed); | ||
| 134 | void DrawRightZTriggers(QPainter& p, QPointF center, bool right_pressed); | ||
| 135 | void DrawRightTriggersTopView(QPainter& p, QPointF center, bool right_pressed); | ||
| 136 | void DrawRightZTriggersTopView(QPainter& p, QPointF center, bool right_pressed); | ||
| 137 | |||
| 138 | // Draw joystick functions | ||
| 139 | void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed); | ||
| 140 | void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed); | ||
| 141 | void DrawRawJoystick(QPainter& p, QPointF center, const QPointF value, | ||
| 142 | const Input::AnalogProperties properties); | ||
| 143 | void DrawProJoystick(QPainter& p, QPointF center, bool pressed); | ||
| 144 | void DrawGCJoystick(QPainter& p, QPointF center, bool pressed); | ||
| 145 | |||
| 146 | // Draw button functions | ||
| 147 | void DrawCircleButton(QPainter& p, QPointF center, bool pressed, float button_size); | ||
| 148 | void DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, float height, | ||
| 149 | Direction direction = Direction::None, float radius = 2); | ||
| 150 | void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size); | ||
| 151 | void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size); | ||
| 152 | void DrawGCButtonX(QPainter& p, QPointF center, bool pressed); | ||
| 153 | void DrawGCButtonY(QPainter& p, QPointF center, bool pressed); | ||
| 154 | void DrawGCButtonZ(QPainter& p, QPointF center, bool pressed); | ||
| 155 | void DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f); | ||
| 156 | void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed, | ||
| 157 | float size = 1.0f); | ||
| 158 | void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, bool pressed); | ||
| 159 | |||
| 160 | // Draw icon functions | ||
| 161 | void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); | ||
| 162 | void DrawArrow(QPainter& p, QPointF center, Direction direction, float size); | ||
| 163 | |||
| 164 | // Draw primitive types | ||
| 165 | template <size_t N> | ||
| 166 | void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon); | ||
| 167 | void DrawCircle(QPainter& p, QPointF center, float size); | ||
| 168 | void DrawRectangle(QPainter& p, QPointF center, float width, float height); | ||
| 169 | void DrawRoundRectangle(QPainter& p, QPointF center, float width, float height, float round); | ||
| 170 | void DrawText(QPainter& p, QPointF center, float text_size, const QString& text); | ||
| 171 | void SetTextFont(QPainter& p, float text_size, | ||
| 172 | const QString& font_family = QStringLiteral("sans-serif")); | ||
| 173 | |||
| 174 | using ButtonArray = | ||
| 175 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::BUTTON_NS_END>; | ||
| 176 | using StickArray = | ||
| 177 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>; | ||
| 178 | |||
| 179 | bool mapping_active{}; | ||
| 180 | int blink_counter{}; | ||
| 181 | QColor button_color{}; | ||
| 182 | ColorMapping colors{}; | ||
| 183 | std::array<QColor, 4> led_color{}; | ||
| 184 | ButtonArray buttons{}; | ||
| 185 | StickArray sticks{}; | ||
| 186 | std::size_t player_index{}; | ||
| 187 | std::size_t button_mapping_index{Settings::NativeButton::BUTTON_NS_END}; | ||
| 188 | std::size_t analog_mapping_index{Settings::NativeAnalog::NUM_STICKS_HID}; | ||
| 189 | std::array<AxisValue, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{}; | ||
| 190 | std::array<bool, Settings::NativeButton::NumButtons> button_values{}; | ||
| 191 | Settings::ControllerType controller_type{Settings::ControllerType::ProController}; | ||
| 192 | }; | ||
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index caaa85930..1f2b792e4 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp | |||
| @@ -81,19 +81,11 @@ void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) { | |||
| 81 | cancel_button->setText(text); | 81 | cancel_button->setText(text); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{ | ||
| 85 | {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")}, | ||
| 86 | {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}, | ||
| 87 | }}; | ||
| 88 | |||
| 89 | ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, | 84 | ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, |
| 90 | InputCommon::InputSubsystem* input_subsystem_) | 85 | InputCommon::InputSubsystem* input_subsystem_) |
| 91 | : QDialog(parent), input_subsystem{input_subsystem_}, | 86 | : QDialog(parent), input_subsystem{input_subsystem_}, |
| 92 | ui(std::make_unique<Ui::ConfigureMotionTouch>()) { | 87 | ui(std::make_unique<Ui::ConfigureMotionTouch>()) { |
| 93 | ui->setupUi(this); | 88 | ui->setupUi(this); |
| 94 | for (const auto& [provider, name] : TouchProviders) { | ||
| 95 | ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider)); | ||
| 96 | } | ||
| 97 | 89 | ||
| 98 | ui->udp_learn_more->setOpenExternalLinks(true); | 90 | ui->udp_learn_more->setOpenExternalLinks(true); |
| 99 | ui->udp_learn_more->setText( | 91 | ui->udp_learn_more->setText( |
| @@ -112,10 +104,7 @@ ConfigureMotionTouch::~ConfigureMotionTouch() = default; | |||
| 112 | void ConfigureMotionTouch::SetConfiguration() { | 104 | void ConfigureMotionTouch::SetConfiguration() { |
| 113 | const Common::ParamPackage motion_param(Settings::values.motion_device); | 105 | const Common::ParamPackage motion_param(Settings::values.motion_device); |
| 114 | const Common::ParamPackage touch_param(Settings::values.touch_device); | 106 | const Common::ParamPackage touch_param(Settings::values.touch_device); |
| 115 | const std::string touch_engine = touch_param.Get("engine", "emu_window"); | ||
| 116 | 107 | ||
| 117 | ui->touch_provider->setCurrentIndex( | ||
| 118 | ui->touch_provider->findData(QString::fromStdString(touch_engine))); | ||
| 119 | ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button); | 108 | ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button); |
| 120 | touch_from_button_maps = Settings::values.touch_from_button_maps; | 109 | touch_from_button_maps = Settings::values.touch_from_button_maps; |
| 121 | for (const auto& touch_map : touch_from_button_maps) { | 110 | for (const auto& touch_map : touch_from_button_maps) { |
| @@ -148,30 +137,21 @@ void ConfigureMotionTouch::SetConfiguration() { | |||
| 148 | } | 137 | } |
| 149 | 138 | ||
| 150 | void ConfigureMotionTouch::UpdateUiDisplay() { | 139 | void ConfigureMotionTouch::UpdateUiDisplay() { |
| 151 | const QString touch_engine = ui->touch_provider->currentData().toString(); | ||
| 152 | const QString cemuhook_udp = QStringLiteral("cemuhookudp"); | 140 | const QString cemuhook_udp = QStringLiteral("cemuhookudp"); |
| 153 | 141 | ||
| 154 | ui->motion_sensitivity_label->setVisible(true); | 142 | ui->motion_sensitivity_label->setVisible(true); |
| 155 | ui->motion_sensitivity->setVisible(true); | 143 | ui->motion_sensitivity->setVisible(true); |
| 156 | 144 | ||
| 157 | if (touch_engine == cemuhook_udp) { | 145 | ui->touch_calibration->setVisible(true); |
| 158 | ui->touch_calibration->setVisible(true); | 146 | ui->touch_calibration_config->setVisible(true); |
| 159 | ui->touch_calibration_config->setVisible(true); | 147 | ui->touch_calibration_label->setVisible(true); |
| 160 | ui->touch_calibration_label->setVisible(true); | 148 | ui->touch_calibration->setText( |
| 161 | ui->touch_calibration->setText( | 149 | QStringLiteral("(%1, %2) - (%3, %4)").arg(min_x).arg(min_y).arg(max_x).arg(max_y)); |
| 162 | QStringLiteral("(%1, %2) - (%3, %4)").arg(min_x).arg(min_y).arg(max_x).arg(max_y)); | ||
| 163 | } else { | ||
| 164 | ui->touch_calibration->setVisible(false); | ||
| 165 | ui->touch_calibration_config->setVisible(false); | ||
| 166 | ui->touch_calibration_label->setVisible(false); | ||
| 167 | } | ||
| 168 | 150 | ||
| 169 | ui->udp_config_group_box->setVisible(true); | 151 | ui->udp_config_group_box->setVisible(true); |
| 170 | } | 152 | } |
| 171 | 153 | ||
| 172 | void ConfigureMotionTouch::ConnectEvents() { | 154 | void ConfigureMotionTouch::ConnectEvents() { |
| 173 | connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||
| 174 | [this](int index) { UpdateUiDisplay(); }); | ||
| 175 | connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); | 155 | connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); |
| 176 | connect(ui->udp_add, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPAddServer); | 156 | connect(ui->udp_add, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPAddServer); |
| 177 | connect(ui->udp_remove, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPDeleteServer); | 157 | connect(ui->udp_remove, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPDeleteServer); |
| @@ -327,16 +307,11 @@ void ConfigureMotionTouch::ApplyConfiguration() { | |||
| 327 | return; | 307 | return; |
| 328 | } | 308 | } |
| 329 | 309 | ||
| 330 | std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); | ||
| 331 | |||
| 332 | Common::ParamPackage touch_param{}; | 310 | Common::ParamPackage touch_param{}; |
| 333 | if (touch_engine == "cemuhookudp") { | 311 | touch_param.Set("min_x", min_x); |
| 334 | touch_param.Set("min_x", min_x); | 312 | touch_param.Set("min_y", min_y); |
| 335 | touch_param.Set("min_y", min_y); | 313 | touch_param.Set("max_x", max_x); |
| 336 | touch_param.Set("max_x", max_x); | 314 | touch_param.Set("max_y", max_y); |
| 337 | touch_param.Set("max_y", max_y); | ||
| 338 | } | ||
| 339 | touch_param.Set("engine", std::move(touch_engine)); | ||
| 340 | 315 | ||
| 341 | Settings::values.touch_device = touch_param.Serialize(); | 316 | Settings::values.touch_device = touch_param.Serialize(); |
| 342 | Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); | 317 | Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); |
diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui index ebca835ac..1e35ea946 100644 --- a/src/yuzu/configuration/configure_motion_touch.ui +++ b/src/yuzu/configuration/configure_motion_touch.ui | |||
| @@ -68,23 +68,9 @@ | |||
| 68 | <item> | 68 | <item> |
| 69 | <layout class="QHBoxLayout"> | 69 | <layout class="QHBoxLayout"> |
| 70 | <item> | 70 | <item> |
| 71 | <widget class="QLabel" name="touch_provider_label"> | ||
| 72 | <property name="text"> | ||
| 73 | <string>Touch Provider:</string> | ||
| 74 | </property> | ||
| 75 | </widget> | ||
| 76 | </item> | ||
| 77 | <item> | ||
| 78 | <widget class="QComboBox" name="touch_provider"/> | ||
| 79 | </item> | ||
| 80 | </layout> | ||
| 81 | </item> | ||
| 82 | <item> | ||
| 83 | <layout class="QHBoxLayout"> | ||
| 84 | <item> | ||
| 85 | <widget class="QLabel" name="touch_calibration_label"> | 71 | <widget class="QLabel" name="touch_calibration_label"> |
| 86 | <property name="text"> | 72 | <property name="text"> |
| 87 | <string>Calibration:</string> | 73 | <string>UDP Calibration:</string> |
| 88 | </property> | 74 | </property> |
| 89 | </widget> | 75 | </widget> |
| 90 | </item> | 76 | </item> |
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index 13d9a4757..51647a028 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp | |||
| @@ -40,7 +40,7 @@ QString GetImagePath(Common::UUID uuid) { | |||
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | QString GetAccountUsername(const Service::Account::ProfileManager& manager, Common::UUID uuid) { | 42 | QString GetAccountUsername(const Service::Account::ProfileManager& manager, Common::UUID uuid) { |
| 43 | Service::Account::ProfileBase profile; | 43 | Service::Account::ProfileBase profile{}; |
| 44 | if (!manager.GetProfileBase(uuid, profile)) { | 44 | if (!manager.GetProfileBase(uuid, profile)) { |
| 45 | return {}; | 45 | return {}; |
| 46 | } | 46 | } |
| @@ -116,8 +116,8 @@ ConfigureProfileManager ::ConfigureProfileManager(QWidget* parent) | |||
| 116 | scene = new QGraphicsScene; | 116 | scene = new QGraphicsScene; |
| 117 | ui->current_user_icon->setScene(scene); | 117 | ui->current_user_icon->setScene(scene); |
| 118 | 118 | ||
| 119 | SetConfiguration(); | ||
| 120 | RetranslateUI(); | 119 | RetranslateUI(); |
| 120 | SetConfiguration(); | ||
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | ConfigureProfileManager::~ConfigureProfileManager() = default; | 123 | ConfigureProfileManager::~ConfigureProfileManager() = default; |
| @@ -147,7 +147,7 @@ void ConfigureProfileManager::SetConfiguration() { | |||
| 147 | void ConfigureProfileManager::PopulateUserList() { | 147 | void ConfigureProfileManager::PopulateUserList() { |
| 148 | const auto& profiles = profile_manager->GetAllUsers(); | 148 | const auto& profiles = profile_manager->GetAllUsers(); |
| 149 | for (const auto& user : profiles) { | 149 | for (const auto& user : profiles) { |
| 150 | Service::Account::ProfileBase profile; | 150 | Service::Account::ProfileBase profile{}; |
| 151 | if (!profile_manager->GetProfileBase(user, profile)) | 151 | if (!profile_manager->GetProfileBase(user, profile)) |
| 152 | continue; | 152 | continue; |
| 153 | 153 | ||
| @@ -212,7 +212,7 @@ void ConfigureProfileManager::RenameUser() { | |||
| 212 | const auto uuid = profile_manager->GetUser(user); | 212 | const auto uuid = profile_manager->GetUser(user); |
| 213 | ASSERT(uuid); | 213 | ASSERT(uuid); |
| 214 | 214 | ||
| 215 | Service::Account::ProfileBase profile; | 215 | Service::Account::ProfileBase profile{}; |
| 216 | if (!profile_manager->GetProfileBase(*uuid, profile)) | 216 | if (!profile_manager->GetProfileBase(*uuid, profile)) |
| 217 | return; | 217 | return; |
| 218 | 218 | ||
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_service.cpp index 0de7a4f0b..b580cfff2 100644 --- a/src/yuzu/configuration/configure_service.cpp +++ b/src/yuzu/configuration/configure_service.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "ui_configure_service.h" | 9 | #include "ui_configure_service.h" |
| 10 | #include "yuzu/configuration/configure_service.h" | 10 | #include "yuzu/configuration/configure_service.h" |
| 11 | 11 | ||
| 12 | #ifdef YUZU_ENABLE_BOXCAT | ||
| 12 | namespace { | 13 | namespace { |
| 13 | QString FormatEventStatusString(const Service::BCAT::EventStatus& status) { | 14 | QString FormatEventStatusString(const Service::BCAT::EventStatus& status) { |
| 14 | QString out; | 15 | QString out; |
| @@ -32,6 +33,7 @@ QString FormatEventStatusString(const Service::BCAT::EventStatus& status) { | |||
| 32 | return out; | 33 | return out; |
| 33 | } | 34 | } |
| 34 | } // Anonymous namespace | 35 | } // Anonymous namespace |
| 36 | #endif | ||
| 35 | 37 | ||
| 36 | ConfigureService::ConfigureService(QWidget* parent) | 38 | ConfigureService::ConfigureService(QWidget* parent) |
| 37 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureService>()) { | 39 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureService>()) { |
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.cpp b/src/yuzu/configuration/configure_touchscreen_advanced.cpp index 7d7cc00b7..29c86c7bc 100644 --- a/src/yuzu/configuration/configure_touchscreen_advanced.cpp +++ b/src/yuzu/configuration/configure_touchscreen_advanced.cpp | |||
| @@ -33,21 +33,18 @@ void ConfigureTouchscreenAdvanced::RetranslateUI() { | |||
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | void ConfigureTouchscreenAdvanced::ApplyConfiguration() { | 35 | void ConfigureTouchscreenAdvanced::ApplyConfiguration() { |
| 36 | Settings::values.touchscreen.finger = ui->finger_box->value(); | ||
| 37 | Settings::values.touchscreen.diameter_x = ui->diameter_x_box->value(); | 36 | Settings::values.touchscreen.diameter_x = ui->diameter_x_box->value(); |
| 38 | Settings::values.touchscreen.diameter_y = ui->diameter_y_box->value(); | 37 | Settings::values.touchscreen.diameter_y = ui->diameter_y_box->value(); |
| 39 | Settings::values.touchscreen.rotation_angle = ui->angle_box->value(); | 38 | Settings::values.touchscreen.rotation_angle = ui->angle_box->value(); |
| 40 | } | 39 | } |
| 41 | 40 | ||
| 42 | void ConfigureTouchscreenAdvanced::LoadConfiguration() { | 41 | void ConfigureTouchscreenAdvanced::LoadConfiguration() { |
| 43 | ui->finger_box->setValue(Settings::values.touchscreen.finger); | ||
| 44 | ui->diameter_x_box->setValue(Settings::values.touchscreen.diameter_x); | 42 | ui->diameter_x_box->setValue(Settings::values.touchscreen.diameter_x); |
| 45 | ui->diameter_y_box->setValue(Settings::values.touchscreen.diameter_y); | 43 | ui->diameter_y_box->setValue(Settings::values.touchscreen.diameter_y); |
| 46 | ui->angle_box->setValue(Settings::values.touchscreen.rotation_angle); | 44 | ui->angle_box->setValue(Settings::values.touchscreen.rotation_angle); |
| 47 | } | 45 | } |
| 48 | 46 | ||
| 49 | void ConfigureTouchscreenAdvanced::RestoreDefaults() { | 47 | void ConfigureTouchscreenAdvanced::RestoreDefaults() { |
| 50 | ui->finger_box->setValue(0); | ||
| 51 | ui->diameter_x_box->setValue(15); | 48 | ui->diameter_x_box->setValue(15); |
| 52 | ui->diameter_y_box->setValue(15); | 49 | ui->diameter_y_box->setValue(15); |
| 53 | ui->angle_box->setValue(0); | 50 | ui->angle_box->setValue(0); |
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.ui b/src/yuzu/configuration/configure_touchscreen_advanced.ui index 30ceccddb..88e7cf050 100644 --- a/src/yuzu/configuration/configure_touchscreen_advanced.ui +++ b/src/yuzu/configuration/configure_touchscreen_advanced.ui | |||
| @@ -65,20 +65,13 @@ | |||
| 65 | </property> | 65 | </property> |
| 66 | </spacer> | 66 | </spacer> |
| 67 | </item> | 67 | </item> |
| 68 | <item row="2" column="1"> | 68 | <item row="1" column="1"> |
| 69 | <widget class="QLabel" name="label_4"> | 69 | <widget class="QLabel" name="label_4"> |
| 70 | <property name="text"> | 70 | <property name="text"> |
| 71 | <string>Touch Diameter Y</string> | 71 | <string>Touch Diameter Y</string> |
| 72 | </property> | 72 | </property> |
| 73 | </widget> | 73 | </widget> |
| 74 | </item> | 74 | </item> |
| 75 | <item row="0" column="1"> | ||
| 76 | <widget class="QLabel" name="label"> | ||
| 77 | <property name="text"> | ||
| 78 | <string>Finger</string> | ||
| 79 | </property> | ||
| 80 | </widget> | ||
| 81 | </item> | ||
| 82 | <item row="0" column="3"> | 75 | <item row="0" column="3"> |
| 83 | <spacer name="horizontalSpacer_2"> | 76 | <spacer name="horizontalSpacer_2"> |
| 84 | <property name="orientation"> | 77 | <property name="orientation"> |
| @@ -92,37 +85,27 @@ | |||
| 92 | </property> | 85 | </property> |
| 93 | </spacer> | 86 | </spacer> |
| 94 | </item> | 87 | </item> |
| 95 | <item row="1" column="1"> | 88 | <item row="0" column="1"> |
| 96 | <widget class="QLabel" name="label_3"> | 89 | <widget class="QLabel" name="label_3"> |
| 97 | <property name="text"> | 90 | <property name="text"> |
| 98 | <string>Touch Diameter X</string> | 91 | <string>Touch Diameter X</string> |
| 99 | </property> | 92 | </property> |
| 100 | </widget> | 93 | </widget> |
| 101 | </item> | 94 | </item> |
| 102 | <item row="0" column="2"> | 95 | <item row="2" column="1"> |
| 103 | <widget class="QSpinBox" name="finger_box"> | ||
| 104 | <property name="minimumSize"> | ||
| 105 | <size> | ||
| 106 | <width>80</width> | ||
| 107 | <height>0</height> | ||
| 108 | </size> | ||
| 109 | </property> | ||
| 110 | </widget> | ||
| 111 | </item> | ||
| 112 | <item row="3" column="1"> | ||
| 113 | <widget class="QLabel" name="label_5"> | 96 | <widget class="QLabel" name="label_5"> |
| 114 | <property name="text"> | 97 | <property name="text"> |
| 115 | <string>Rotational Angle</string> | 98 | <string>Rotational Angle</string> |
| 116 | </property> | 99 | </property> |
| 117 | </widget> | 100 | </widget> |
| 118 | </item> | 101 | </item> |
| 119 | <item row="1" column="2"> | 102 | <item row="0" column="2"> |
| 120 | <widget class="QSpinBox" name="diameter_x_box"/> | 103 | <widget class="QSpinBox" name="diameter_x_box"/> |
| 121 | </item> | 104 | </item> |
| 122 | <item row="2" column="2"> | 105 | <item row="1" column="2"> |
| 123 | <widget class="QSpinBox" name="diameter_y_box"/> | 106 | <widget class="QSpinBox" name="diameter_y_box"/> |
| 124 | </item> | 107 | </item> |
| 125 | <item row="3" column="2"> | 108 | <item row="2" column="2"> |
| 126 | <widget class="QSpinBox" name="angle_box"/> | 109 | <widget class="QSpinBox" name="angle_box"/> |
| 127 | </item> | 110 | </item> |
| 128 | </layout> | 111 | </layout> |
diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp new file mode 100644 index 000000000..85724a8f3 --- /dev/null +++ b/src/yuzu/debugger/controller.cpp | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QAction> | ||
| 6 | #include <QLayout> | ||
| 7 | #include <QString> | ||
| 8 | #include "core/settings.h" | ||
| 9 | #include "yuzu/configuration/configure_input_player_widget.h" | ||
| 10 | #include "yuzu/debugger/controller.h" | ||
| 11 | |||
| 12 | ControllerDialog::ControllerDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) { | ||
| 13 | setObjectName(QStringLiteral("Controller")); | ||
| 14 | setWindowTitle(tr("Controller P1")); | ||
| 15 | resize(500, 350); | ||
| 16 | setMinimumSize(500, 350); | ||
| 17 | // Remove the "?" button from the titlebar and enable the maximize button | ||
| 18 | setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) | | ||
| 19 | Qt::WindowMaximizeButtonHint); | ||
| 20 | |||
| 21 | widget = new PlayerControlPreview(this); | ||
| 22 | refreshConfiguration(); | ||
| 23 | QLayout* layout = new QVBoxLayout(this); | ||
| 24 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 25 | layout->addWidget(widget); | ||
| 26 | setLayout(layout); | ||
| 27 | |||
| 28 | // Configure focus so that widget is focusable and the dialog automatically forwards focus to | ||
| 29 | // it. | ||
| 30 | setFocusProxy(widget); | ||
| 31 | widget->setFocusPolicy(Qt::StrongFocus); | ||
| 32 | widget->setFocus(); | ||
| 33 | } | ||
| 34 | |||
| 35 | void ControllerDialog::refreshConfiguration() { | ||
| 36 | const auto& players = Settings::values.players.GetValue(); | ||
| 37 | constexpr std::size_t player = 0; | ||
| 38 | widget->SetPlayerInputRaw(player, players[player].buttons, players[player].analogs); | ||
| 39 | widget->SetConnectedStatus(players[player].connected); | ||
| 40 | widget->SetControllerType(players[player].controller_type); | ||
| 41 | } | ||
| 42 | |||
| 43 | QAction* ControllerDialog::toggleViewAction() { | ||
| 44 | if (toggle_view_action == nullptr) { | ||
| 45 | toggle_view_action = new QAction(windowTitle(), this); | ||
| 46 | toggle_view_action->setCheckable(true); | ||
| 47 | toggle_view_action->setChecked(isVisible()); | ||
| 48 | connect(toggle_view_action, &QAction::toggled, this, &ControllerDialog::setVisible); | ||
| 49 | } | ||
| 50 | |||
| 51 | return toggle_view_action; | ||
| 52 | } | ||
| 53 | |||
| 54 | void ControllerDialog::showEvent(QShowEvent* ev) { | ||
| 55 | if (toggle_view_action) { | ||
| 56 | toggle_view_action->setChecked(isVisible()); | ||
| 57 | } | ||
| 58 | QWidget::showEvent(ev); | ||
| 59 | } | ||
| 60 | |||
| 61 | void ControllerDialog::hideEvent(QHideEvent* ev) { | ||
| 62 | if (toggle_view_action) { | ||
| 63 | toggle_view_action->setChecked(isVisible()); | ||
| 64 | } | ||
| 65 | QWidget::hideEvent(ev); | ||
| 66 | } | ||
diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h new file mode 100644 index 000000000..c54750070 --- /dev/null +++ b/src/yuzu/debugger/controller.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <QWidget> | ||
| 8 | |||
| 9 | class QAction; | ||
| 10 | class QHideEvent; | ||
| 11 | class QShowEvent; | ||
| 12 | class PlayerControlPreview; | ||
| 13 | |||
| 14 | class ControllerDialog : public QWidget { | ||
| 15 | Q_OBJECT | ||
| 16 | |||
| 17 | public: | ||
| 18 | explicit ControllerDialog(QWidget* parent = nullptr); | ||
| 19 | |||
| 20 | /// Returns a QAction that can be used to toggle visibility of this dialog. | ||
| 21 | QAction* toggleViewAction(); | ||
| 22 | void refreshConfiguration(); | ||
| 23 | |||
| 24 | protected: | ||
| 25 | void showEvent(QShowEvent* ev) override; | ||
| 26 | void hideEvent(QHideEvent* ev) override; | ||
| 27 | |||
| 28 | private: | ||
| 29 | QAction* toggle_view_action = nullptr; | ||
| 30 | PlayerControlPreview* widget; | ||
| 31 | }; | ||
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index a93b5d3c2..3bca6277b 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -13,12 +13,13 @@ | |||
| 13 | #include "core/arm/arm_interface.h" | 13 | #include "core/arm/arm_interface.h" |
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/hle/kernel/handle_table.h" | 15 | #include "core/hle/kernel/handle_table.h" |
| 16 | #include "core/hle/kernel/k_readable_event.h" | ||
| 16 | #include "core/hle/kernel/k_scheduler.h" | 17 | #include "core/hle/kernel/k_scheduler.h" |
| 17 | #include "core/hle/kernel/k_synchronization_object.h" | 18 | #include "core/hle/kernel/k_synchronization_object.h" |
| 19 | #include "core/hle/kernel/k_thread.h" | ||
| 18 | #include "core/hle/kernel/process.h" | 20 | #include "core/hle/kernel/process.h" |
| 19 | #include "core/hle/kernel/readable_event.h" | ||
| 20 | #include "core/hle/kernel/svc_common.h" | 21 | #include "core/hle/kernel/svc_common.h" |
| 21 | #include "core/hle/kernel/thread.h" | 22 | #include "core/hle/kernel/svc_types.h" |
| 22 | #include "core/memory.h" | 23 | #include "core/memory.h" |
| 23 | 24 | ||
| 24 | namespace { | 25 | namespace { |
| @@ -90,9 +91,9 @@ std::size_t WaitTreeItem::Row() const { | |||
| 90 | std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { | 91 | std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { |
| 91 | std::vector<std::unique_ptr<WaitTreeThread>> item_list; | 92 | std::vector<std::unique_ptr<WaitTreeThread>> item_list; |
| 92 | std::size_t row = 0; | 93 | std::size_t row = 0; |
| 93 | auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::Thread>>& threads) { | 94 | auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::KThread>>& threads) { |
| 94 | for (std::size_t i = 0; i < threads.size(); ++i) { | 95 | for (std::size_t i = 0; i < threads.size(); ++i) { |
| 95 | if (!threads[i]->IsHLEThread()) { | 96 | if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) { |
| 96 | item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i])); | 97 | item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i])); |
| 97 | item_list.back()->row = row; | 98 | item_list.back()->row = row; |
| 98 | } | 99 | } |
| @@ -117,7 +118,7 @@ WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTa | |||
| 117 | : mutex_address(mutex_address) { | 118 | : mutex_address(mutex_address) { |
| 118 | mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address); | 119 | mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address); |
| 119 | owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask); | 120 | owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask); |
| 120 | owner = handle_table.Get<Kernel::Thread>(owner_handle); | 121 | owner = handle_table.Get<Kernel::KThread>(owner_handle); |
| 121 | } | 122 | } |
| 122 | 123 | ||
| 123 | WaitTreeMutexInfo::~WaitTreeMutexInfo() = default; | 124 | WaitTreeMutexInfo::~WaitTreeMutexInfo() = default; |
| @@ -139,7 +140,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() cons | |||
| 139 | return list; | 140 | return list; |
| 140 | } | 141 | } |
| 141 | 142 | ||
| 142 | WaitTreeCallstack::WaitTreeCallstack(const Kernel::Thread& thread) : thread(thread) {} | 143 | WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread) : thread(thread) {} |
| 143 | WaitTreeCallstack::~WaitTreeCallstack() = default; | 144 | WaitTreeCallstack::~WaitTreeCallstack() = default; |
| 144 | 145 | ||
| 145 | QString WaitTreeCallstack::GetText() const { | 146 | QString WaitTreeCallstack::GetText() const { |
| @@ -149,7 +150,7 @@ QString WaitTreeCallstack::GetText() const { | |||
| 149 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { | 150 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { |
| 150 | std::vector<std::unique_ptr<WaitTreeItem>> list; | 151 | std::vector<std::unique_ptr<WaitTreeItem>> list; |
| 151 | 152 | ||
| 152 | if (thread.IsHLEThread()) { | 153 | if (thread.GetThreadTypeForDebugging() != Kernel::ThreadType::User) { |
| 153 | return list; | 154 | return list; |
| 154 | } | 155 | } |
| 155 | 156 | ||
| @@ -192,9 +193,9 @@ std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::ma | |||
| 192 | const Kernel::KSynchronizationObject& object) { | 193 | const Kernel::KSynchronizationObject& object) { |
| 193 | switch (object.GetHandleType()) { | 194 | switch (object.GetHandleType()) { |
| 194 | case Kernel::HandleType::ReadableEvent: | 195 | case Kernel::HandleType::ReadableEvent: |
| 195 | return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object)); | 196 | return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::KReadableEvent&>(object)); |
| 196 | case Kernel::HandleType::Thread: | 197 | case Kernel::HandleType::Thread: |
| 197 | return std::make_unique<WaitTreeThread>(static_cast<const Kernel::Thread&>(object)); | 198 | return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object)); |
| 198 | default: | 199 | default: |
| 199 | return std::make_unique<WaitTreeSynchronizationObject>(object); | 200 | return std::make_unique<WaitTreeSynchronizationObject>(object); |
| 200 | } | 201 | } |
| @@ -231,21 +232,17 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() con | |||
| 231 | return list; | 232 | return list; |
| 232 | } | 233 | } |
| 233 | 234 | ||
| 234 | WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread) | 235 | WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread) |
| 235 | : WaitTreeSynchronizationObject(thread) {} | 236 | : WaitTreeSynchronizationObject(thread) {} |
| 236 | WaitTreeThread::~WaitTreeThread() = default; | 237 | WaitTreeThread::~WaitTreeThread() = default; |
| 237 | 238 | ||
| 238 | QString WaitTreeThread::GetText() const { | 239 | QString WaitTreeThread::GetText() const { |
| 239 | const auto& thread = static_cast<const Kernel::Thread&>(object); | 240 | const auto& thread = static_cast<const Kernel::KThread&>(object); |
| 240 | QString status; | 241 | QString status; |
| 241 | switch (thread.GetState()) { | 242 | switch (thread.GetState()) { |
| 242 | case Kernel::ThreadState::Runnable: | 243 | case Kernel::ThreadState::Runnable: |
| 243 | if (!thread.IsPaused()) { | 244 | if (!thread.IsSuspended()) { |
| 244 | if (thread.WasRunning()) { | 245 | status = tr("runnable"); |
| 245 | status = tr("running"); | ||
| 246 | } else { | ||
| 247 | status = tr("ready"); | ||
| 248 | } | ||
| 249 | } else { | 246 | } else { |
| 250 | status = tr("paused"); | 247 | status = tr("paused"); |
| 251 | } | 248 | } |
| @@ -297,15 +294,11 @@ QString WaitTreeThread::GetText() const { | |||
| 297 | QColor WaitTreeThread::GetColor() const { | 294 | QColor WaitTreeThread::GetColor() const { |
| 298 | const std::size_t color_index = IsDarkTheme() ? 1 : 0; | 295 | const std::size_t color_index = IsDarkTheme() ? 1 : 0; |
| 299 | 296 | ||
| 300 | const auto& thread = static_cast<const Kernel::Thread&>(object); | 297 | const auto& thread = static_cast<const Kernel::KThread&>(object); |
| 301 | switch (thread.GetState()) { | 298 | switch (thread.GetState()) { |
| 302 | case Kernel::ThreadState::Runnable: | 299 | case Kernel::ThreadState::Runnable: |
| 303 | if (!thread.IsPaused()) { | 300 | if (!thread.IsSuspended()) { |
| 304 | if (thread.WasRunning()) { | 301 | return QColor(WaitTreeColors[0][color_index]); |
| 305 | return QColor(WaitTreeColors[0][color_index]); | ||
| 306 | } else { | ||
| 307 | return QColor(WaitTreeColors[1][color_index]); | ||
| 308 | } | ||
| 309 | } else { | 302 | } else { |
| 310 | return QColor(WaitTreeColors[2][color_index]); | 303 | return QColor(WaitTreeColors[2][color_index]); |
| 311 | } | 304 | } |
| @@ -336,27 +329,21 @@ QColor WaitTreeThread::GetColor() const { | |||
| 336 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | 329 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { |
| 337 | std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeSynchronizationObject::GetChildren()); | 330 | std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeSynchronizationObject::GetChildren()); |
| 338 | 331 | ||
| 339 | const auto& thread = static_cast<const Kernel::Thread&>(object); | 332 | const auto& thread = static_cast<const Kernel::KThread&>(object); |
| 340 | 333 | ||
| 341 | QString processor; | 334 | QString processor; |
| 342 | switch (thread.GetProcessorID()) { | 335 | switch (thread.GetActiveCore()) { |
| 343 | case Kernel::ThreadProcessorId::THREADPROCESSORID_IDEAL: | 336 | case Kernel::Svc::IdealCoreUseProcessValue: |
| 344 | processor = tr("ideal"); | 337 | processor = tr("ideal"); |
| 345 | break; | 338 | break; |
| 346 | case Kernel::ThreadProcessorId::THREADPROCESSORID_0: | ||
| 347 | case Kernel::ThreadProcessorId::THREADPROCESSORID_1: | ||
| 348 | case Kernel::ThreadProcessorId::THREADPROCESSORID_2: | ||
| 349 | case Kernel::ThreadProcessorId::THREADPROCESSORID_3: | ||
| 350 | processor = tr("core %1").arg(thread.GetProcessorID()); | ||
| 351 | break; | ||
| 352 | default: | 339 | default: |
| 353 | processor = tr("Unknown processor %1").arg(thread.GetProcessorID()); | 340 | processor = tr("core %1").arg(thread.GetActiveCore()); |
| 354 | break; | 341 | break; |
| 355 | } | 342 | } |
| 356 | 343 | ||
| 357 | list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor))); | 344 | list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor))); |
| 358 | list.push_back( | 345 | list.push_back(std::make_unique<WaitTreeText>( |
| 359 | std::make_unique<WaitTreeText>(tr("ideal core = %1").arg(thread.GetIdealCore()))); | 346 | tr("ideal core = %1").arg(thread.GetIdealCoreForDebugging()))); |
| 360 | list.push_back(std::make_unique<WaitTreeText>( | 347 | list.push_back(std::make_unique<WaitTreeText>( |
| 361 | tr("affinity mask = %1").arg(thread.GetAffinityMask().GetAffinityMask()))); | 348 | tr("affinity mask = %1").arg(thread.GetAffinityMask().GetAffinityMask()))); |
| 362 | list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadID()))); | 349 | list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadID()))); |
| @@ -386,11 +373,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | |||
| 386 | return list; | 373 | return list; |
| 387 | } | 374 | } |
| 388 | 375 | ||
| 389 | WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) | 376 | WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object) |
| 390 | : WaitTreeSynchronizationObject(object) {} | 377 | : WaitTreeSynchronizationObject(object) {} |
| 391 | WaitTreeEvent::~WaitTreeEvent() = default; | 378 | WaitTreeEvent::~WaitTreeEvent() = default; |
| 392 | 379 | ||
| 393 | WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::Thread*>& list) | 380 | WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::KThread*>& list) |
| 394 | : thread_list(list) {} | 381 | : thread_list(list) {} |
| 395 | WaitTreeThreadList::~WaitTreeThreadList() = default; | 382 | WaitTreeThreadList::~WaitTreeThreadList() = default; |
| 396 | 383 | ||
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h index cf96911ea..3da2fdfd2 100644 --- a/src/yuzu/debugger/wait_tree.h +++ b/src/yuzu/debugger/wait_tree.h | |||
| @@ -18,9 +18,9 @@ class EmuThread; | |||
| 18 | 18 | ||
| 19 | namespace Kernel { | 19 | namespace Kernel { |
| 20 | class HandleTable; | 20 | class HandleTable; |
| 21 | class KReadableEvent; | ||
| 21 | class KSynchronizationObject; | 22 | class KSynchronizationObject; |
| 22 | class ReadableEvent; | 23 | class KThread; |
| 23 | class Thread; | ||
| 24 | } // namespace Kernel | 24 | } // namespace Kernel |
| 25 | 25 | ||
| 26 | class WaitTreeThread; | 26 | class WaitTreeThread; |
| @@ -83,20 +83,20 @@ private: | |||
| 83 | VAddr mutex_address; | 83 | VAddr mutex_address; |
| 84 | u32 mutex_value; | 84 | u32 mutex_value; |
| 85 | Kernel::Handle owner_handle; | 85 | Kernel::Handle owner_handle; |
| 86 | std::shared_ptr<Kernel::Thread> owner; | 86 | std::shared_ptr<Kernel::KThread> owner; |
| 87 | }; | 87 | }; |
| 88 | 88 | ||
| 89 | class WaitTreeCallstack : public WaitTreeExpandableItem { | 89 | class WaitTreeCallstack : public WaitTreeExpandableItem { |
| 90 | Q_OBJECT | 90 | Q_OBJECT |
| 91 | public: | 91 | public: |
| 92 | explicit WaitTreeCallstack(const Kernel::Thread& thread); | 92 | explicit WaitTreeCallstack(const Kernel::KThread& thread); |
| 93 | ~WaitTreeCallstack() override; | 93 | ~WaitTreeCallstack() override; |
| 94 | 94 | ||
| 95 | QString GetText() const override; | 95 | QString GetText() const override; |
| 96 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | 96 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; |
| 97 | 97 | ||
| 98 | private: | 98 | private: |
| 99 | const Kernel::Thread& thread; | 99 | const Kernel::KThread& thread; |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { | 102 | class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { |
| @@ -131,7 +131,7 @@ private: | |||
| 131 | class WaitTreeThread : public WaitTreeSynchronizationObject { | 131 | class WaitTreeThread : public WaitTreeSynchronizationObject { |
| 132 | Q_OBJECT | 132 | Q_OBJECT |
| 133 | public: | 133 | public: |
| 134 | explicit WaitTreeThread(const Kernel::Thread& thread); | 134 | explicit WaitTreeThread(const Kernel::KThread& thread); |
| 135 | ~WaitTreeThread() override; | 135 | ~WaitTreeThread() override; |
| 136 | 136 | ||
| 137 | QString GetText() const override; | 137 | QString GetText() const override; |
| @@ -142,21 +142,21 @@ public: | |||
| 142 | class WaitTreeEvent : public WaitTreeSynchronizationObject { | 142 | class WaitTreeEvent : public WaitTreeSynchronizationObject { |
| 143 | Q_OBJECT | 143 | Q_OBJECT |
| 144 | public: | 144 | public: |
| 145 | explicit WaitTreeEvent(const Kernel::ReadableEvent& object); | 145 | explicit WaitTreeEvent(const Kernel::KReadableEvent& object); |
| 146 | ~WaitTreeEvent() override; | 146 | ~WaitTreeEvent() override; |
| 147 | }; | 147 | }; |
| 148 | 148 | ||
| 149 | class WaitTreeThreadList : public WaitTreeExpandableItem { | 149 | class WaitTreeThreadList : public WaitTreeExpandableItem { |
| 150 | Q_OBJECT | 150 | Q_OBJECT |
| 151 | public: | 151 | public: |
| 152 | explicit WaitTreeThreadList(const std::vector<Kernel::Thread*>& list); | 152 | explicit WaitTreeThreadList(const std::vector<Kernel::KThread*>& list); |
| 153 | ~WaitTreeThreadList() override; | 153 | ~WaitTreeThreadList() override; |
| 154 | 154 | ||
| 155 | QString GetText() const override; | 155 | QString GetText() const override; |
| 156 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | 156 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; |
| 157 | 157 | ||
| 158 | private: | 158 | private: |
| 159 | const std::vector<Kernel::Thread*>& thread_list; | 159 | const std::vector<Kernel::KThread*>& thread_list; |
| 160 | }; | 160 | }; |
| 161 | 161 | ||
| 162 | class WaitTreeModel : public QAbstractItemModel { | 162 | class WaitTreeModel : public QAbstractItemModel { |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 37b0d1a0e..9afd5b45f 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -173,8 +173,8 @@ void GameList::OnItemExpanded(const QModelIndex& item) { | |||
| 173 | return; | 173 | return; |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | auto* game_dir = item.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); | 176 | UISettings::values.game_dirs[item.data(GameListDir::GameDirRole).toInt()].expanded = |
| 177 | game_dir->expanded = tree_view->isExpanded(item); | 177 | tree_view->isExpanded(item); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | // Event in order to filter the gamelist after editing the searchfield | 180 | // Event in order to filter the gamelist after editing the searchfield |
| @@ -262,9 +262,9 @@ void GameList::OnUpdateThemedIcons() { | |||
| 262 | Qt::DecorationRole); | 262 | Qt::DecorationRole); |
| 263 | break; | 263 | break; |
| 264 | case GameListItemType::CustomDir: { | 264 | case GameListItemType::CustomDir: { |
| 265 | const UISettings::GameDir* game_dir = | 265 | const UISettings::GameDir& game_dir = |
| 266 | child->data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); | 266 | UISettings::values.game_dirs[child->data(GameListDir::GameDirRole).toInt()]; |
| 267 | const QString icon_name = QFileInfo::exists(game_dir->path) | 267 | const QString icon_name = QFileInfo::exists(game_dir.path) |
| 268 | ? QStringLiteral("folder") | 268 | ? QStringLiteral("folder") |
| 269 | : QStringLiteral("bad_folder"); | 269 | : QStringLiteral("bad_folder"); |
| 270 | child->setData( | 270 | child->setData( |
| @@ -366,7 +366,7 @@ void GameList::AddDirEntry(GameListDir* entry_items) { | |||
| 366 | item_model->invisibleRootItem()->appendRow(entry_items); | 366 | item_model->invisibleRootItem()->appendRow(entry_items); |
| 367 | tree_view->setExpanded( | 367 | tree_view->setExpanded( |
| 368 | entry_items->index(), | 368 | entry_items->index(), |
| 369 | entry_items->data(GameListDir::GameDirRole).value<UISettings::GameDir*>()->expanded); | 369 | UISettings::values.game_dirs[entry_items->data(GameListDir::GameDirRole).toInt()].expanded); |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | void GameList::AddEntry(const QList<QStandardItem*>& entry_items, GameListDir* parent) { | 372 | void GameList::AddEntry(const QList<QStandardItem*>& entry_items, GameListDir* parent) { |
| @@ -549,7 +549,7 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri | |||
| 549 | 549 | ||
| 550 | void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) { | 550 | void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) { |
| 551 | UISettings::GameDir& game_dir = | 551 | UISettings::GameDir& game_dir = |
| 552 | *selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); | 552 | UISettings::values.game_dirs[selected.data(GameListDir::GameDirRole).toInt()]; |
| 553 | 553 | ||
| 554 | QAction* deep_scan = context_menu.addAction(tr("Scan Subfolders")); | 554 | QAction* deep_scan = context_menu.addAction(tr("Scan Subfolders")); |
| 555 | QAction* delete_dir = context_menu.addAction(tr("Remove Game Directory")); | 555 | QAction* delete_dir = context_menu.addAction(tr("Remove Game Directory")); |
| @@ -568,8 +568,7 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) { | |||
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | 570 | void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { |
| 571 | UISettings::GameDir& game_dir = | 571 | const int game_dir_index = selected.data(GameListDir::GameDirRole).toInt(); |
| 572 | *selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); | ||
| 573 | 572 | ||
| 574 | QAction* move_up = context_menu.addAction(tr("\u25B2 Move Up")); | 573 | QAction* move_up = context_menu.addAction(tr("\u25B2 Move Up")); |
| 575 | QAction* move_down = context_menu.addAction(tr("\u25bc Move Down")); | 574 | QAction* move_down = context_menu.addAction(tr("\u25bc Move Down")); |
| @@ -580,34 +579,39 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | |||
| 580 | move_up->setEnabled(row > 0); | 579 | move_up->setEnabled(row > 0); |
| 581 | move_down->setEnabled(row < item_model->rowCount() - 2); | 580 | move_down->setEnabled(row < item_model->rowCount() - 2); |
| 582 | 581 | ||
| 583 | connect(move_up, &QAction::triggered, [this, selected, row, &game_dir] { | 582 | connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] { |
| 584 | // find the indices of the items in settings and swap them | 583 | const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt(); |
| 585 | std::swap(UISettings::values.game_dirs[UISettings::values.game_dirs.indexOf(game_dir)], | 584 | // swap the items in the settings |
| 586 | UISettings::values.game_dirs[UISettings::values.game_dirs.indexOf( | 585 | std::swap(UISettings::values.game_dirs[game_dir_index], |
| 587 | *selected.sibling(row - 1, 0) | 586 | UISettings::values.game_dirs[other_index]); |
| 588 | .data(GameListDir::GameDirRole) | 587 | // swap the indexes held by the QVariants |
| 589 | .value<UISettings::GameDir*>())]); | 588 | item_model->setData(selected, QVariant(other_index), GameListDir::GameDirRole); |
| 589 | item_model->setData(selected.sibling(row - 1, 0), QVariant(game_dir_index), | ||
| 590 | GameListDir::GameDirRole); | ||
| 590 | // move the treeview items | 591 | // move the treeview items |
| 591 | QList<QStandardItem*> item = item_model->takeRow(row); | 592 | QList<QStandardItem*> item = item_model->takeRow(row); |
| 592 | item_model->invisibleRootItem()->insertRow(row - 1, item); | 593 | item_model->invisibleRootItem()->insertRow(row - 1, item); |
| 593 | tree_view->setExpanded(selected, game_dir.expanded); | 594 | tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); |
| 594 | }); | 595 | }); |
| 595 | 596 | ||
| 596 | connect(move_down, &QAction::triggered, [this, selected, row, &game_dir] { | 597 | connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] { |
| 597 | // find the indices of the items in settings and swap them | 598 | const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt(); |
| 598 | std::swap(UISettings::values.game_dirs[UISettings::values.game_dirs.indexOf(game_dir)], | 599 | // swap the items in the settings |
| 599 | UISettings::values.game_dirs[UISettings::values.game_dirs.indexOf( | 600 | std::swap(UISettings::values.game_dirs[game_dir_index], |
| 600 | *selected.sibling(row + 1, 0) | 601 | UISettings::values.game_dirs[other_index]); |
| 601 | .data(GameListDir::GameDirRole) | 602 | // swap the indexes held by the QVariants |
| 602 | .value<UISettings::GameDir*>())]); | 603 | item_model->setData(selected, QVariant(other_index), GameListDir::GameDirRole); |
| 604 | item_model->setData(selected.sibling(row + 1, 0), QVariant(game_dir_index), | ||
| 605 | GameListDir::GameDirRole); | ||
| 603 | // move the treeview items | 606 | // move the treeview items |
| 604 | const QList<QStandardItem*> item = item_model->takeRow(row); | 607 | const QList<QStandardItem*> item = item_model->takeRow(row); |
| 605 | item_model->invisibleRootItem()->insertRow(row + 1, item); | 608 | item_model->invisibleRootItem()->insertRow(row + 1, item); |
| 606 | tree_view->setExpanded(selected, game_dir.expanded); | 609 | tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); |
| 607 | }); | 610 | }); |
| 608 | 611 | ||
| 609 | connect(open_directory_location, &QAction::triggered, | 612 | connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { |
| 610 | [this, game_dir] { emit OpenDirectory(game_dir.path); }); | 613 | emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path); |
| 614 | }); | ||
| 611 | } | 615 | } |
| 612 | 616 | ||
| 613 | void GameList::LoadCompatibilityList() { | 617 | void GameList::LoadCompatibilityList() { |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index df935022d..f25445f18 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -230,7 +230,7 @@ public: | |||
| 230 | setData(type(), TypeRole); | 230 | setData(type(), TypeRole); |
| 231 | 231 | ||
| 232 | UISettings::GameDir* game_dir = &directory; | 232 | UISettings::GameDir* game_dir = &directory; |
| 233 | setData(QVariant::fromValue(game_dir), GameDirRole); | 233 | setData(QVariant(UISettings::values.game_dirs.indexOf(directory)), GameDirRole); |
| 234 | 234 | ||
| 235 | const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64); | 235 | const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64); |
| 236 | switch (dir_type) { | 236 | switch (dir_type) { |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2e74037d1..ef92c25bc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "applets/profile_select.h" | 16 | #include "applets/profile_select.h" |
| 17 | #include "applets/software_keyboard.h" | 17 | #include "applets/software_keyboard.h" |
| 18 | #include "applets/web_browser.h" | 18 | #include "applets/web_browser.h" |
| 19 | #include "common/nvidia_flags.h" | ||
| 19 | #include "configuration/configure_input.h" | 20 | #include "configuration/configure_input.h" |
| 20 | #include "configuration/configure_per_game.h" | 21 | #include "configuration/configure_per_game.h" |
| 21 | #include "configuration/configure_vibration.h" | 22 | #include "configuration/configure_vibration.h" |
| @@ -108,6 +109,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 108 | #include "yuzu/configuration/config.h" | 109 | #include "yuzu/configuration/config.h" |
| 109 | #include "yuzu/configuration/configure_dialog.h" | 110 | #include "yuzu/configuration/configure_dialog.h" |
| 110 | #include "yuzu/debugger/console.h" | 111 | #include "yuzu/debugger/console.h" |
| 112 | #include "yuzu/debugger/controller.h" | ||
| 111 | #include "yuzu/debugger/profiler.h" | 113 | #include "yuzu/debugger/profiler.h" |
| 112 | #include "yuzu/debugger/wait_tree.h" | 114 | #include "yuzu/debugger/wait_tree.h" |
| 113 | #include "yuzu/discord.h" | 115 | #include "yuzu/discord.h" |
| @@ -687,6 +689,11 @@ void GMainWindow::InitializeDebugWidgets() { | |||
| 687 | addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); | 689 | addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); |
| 688 | waitTreeWidget->hide(); | 690 | waitTreeWidget->hide(); |
| 689 | debug_menu->addAction(waitTreeWidget->toggleViewAction()); | 691 | debug_menu->addAction(waitTreeWidget->toggleViewAction()); |
| 692 | |||
| 693 | controller_dialog = new ControllerDialog(this); | ||
| 694 | controller_dialog->hide(); | ||
| 695 | debug_menu->addAction(controller_dialog->toggleViewAction()); | ||
| 696 | |||
| 690 | connect(this, &GMainWindow::EmulationStarting, waitTreeWidget, | 697 | connect(this, &GMainWindow::EmulationStarting, waitTreeWidget, |
| 691 | &WaitTreeWidget::OnEmulationStarting); | 698 | &WaitTreeWidget::OnEmulationStarting); |
| 692 | connect(this, &GMainWindow::EmulationStopping, waitTreeWidget, | 699 | connect(this, &GMainWindow::EmulationStopping, waitTreeWidget, |
| @@ -1038,8 +1045,6 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { | |||
| 1038 | std::make_unique<QtWebBrowser>(*this), // Web Browser | 1045 | std::make_unique<QtWebBrowser>(*this), // Web Browser |
| 1039 | }); | 1046 | }); |
| 1040 | 1047 | ||
| 1041 | system.RegisterHostThread(); | ||
| 1042 | |||
| 1043 | const Core::System::ResultStatus result{ | 1048 | const Core::System::ResultStatus result{ |
| 1044 | system.Load(*render_window, filename.toStdString(), program_index)}; | 1049 | system.Load(*render_window, filename.toStdString(), program_index)}; |
| 1045 | 1050 | ||
| @@ -2337,6 +2342,7 @@ void GMainWindow::OnConfigure() { | |||
| 2337 | } | 2342 | } |
| 2338 | 2343 | ||
| 2339 | configure_dialog.ApplyConfiguration(); | 2344 | configure_dialog.ApplyConfiguration(); |
| 2345 | controller_dialog->refreshConfiguration(); | ||
| 2340 | InitializeHotkeys(); | 2346 | InitializeHotkeys(); |
| 2341 | if (UISettings::values.theme != old_theme) { | 2347 | if (UISettings::values.theme != old_theme) { |
| 2342 | UpdateUITheme(); | 2348 | UpdateUITheme(); |
| @@ -3023,6 +3029,8 @@ int main(int argc, char* argv[]) { | |||
| 3023 | MicroProfileOnThreadCreate("Frontend"); | 3029 | MicroProfileOnThreadCreate("Frontend"); |
| 3024 | SCOPE_EXIT({ MicroProfileShutdown(); }); | 3030 | SCOPE_EXIT({ MicroProfileShutdown(); }); |
| 3025 | 3031 | ||
| 3032 | Common::ConfigureNvidiaEnvironmentFlags(); | ||
| 3033 | |||
| 3026 | // Init settings params | 3034 | // Init settings params |
| 3027 | QCoreApplication::setOrganizationName(QStringLiteral("yuzu team")); | 3035 | QCoreApplication::setOrganizationName(QStringLiteral("yuzu team")); |
| 3028 | QCoreApplication::setApplicationName(QStringLiteral("yuzu")); | 3036 | QCoreApplication::setApplicationName(QStringLiteral("yuzu")); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 31788ea62..04d37d4ae 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -27,6 +27,7 @@ class GRenderWindow; | |||
| 27 | class LoadingScreen; | 27 | class LoadingScreen; |
| 28 | class MicroProfileDialog; | 28 | class MicroProfileDialog; |
| 29 | class ProfilerWidget; | 29 | class ProfilerWidget; |
| 30 | class ControllerDialog; | ||
| 30 | class QLabel; | 31 | class QLabel; |
| 31 | class QPushButton; | 32 | class QPushButton; |
| 32 | class QProgressDialog; | 33 | class QProgressDialog; |
| @@ -313,6 +314,7 @@ private: | |||
| 313 | ProfilerWidget* profilerWidget; | 314 | ProfilerWidget* profilerWidget; |
| 314 | MicroProfileDialog* microProfileDialog; | 315 | MicroProfileDialog* microProfileDialog; |
| 315 | WaitTreeWidget* waitTreeWidget; | 316 | WaitTreeWidget* waitTreeWidget; |
| 317 | ControllerDialog* controller_dialog; | ||
| 316 | 318 | ||
| 317 | QAction* actions_recent_files[max_recent_files_item]; | 319 | QAction* actions_recent_files[max_recent_files_item]; |
| 318 | 320 | ||
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 41ef6f6b8..f76102459 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -296,10 +296,6 @@ void Config::ReadValues() { | |||
| 296 | sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true)); | 296 | sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true)); |
| 297 | Settings::values.touchscreen.enabled = | 297 | Settings::values.touchscreen.enabled = |
| 298 | sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true); | 298 | sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true); |
| 299 | Settings::values.touchscreen.device = | ||
| 300 | sdl2_config->Get("ControlsGeneral", "touch_device", "engine:emu_window"); | ||
| 301 | Settings::values.touchscreen.finger = | ||
| 302 | sdl2_config->GetInteger("ControlsGeneral", "touch_finger", 0); | ||
| 303 | Settings::values.touchscreen.rotation_angle = | 299 | Settings::values.touchscreen.rotation_angle = |
| 304 | sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0); | 300 | sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0); |
| 305 | Settings::values.touchscreen.diameter_x = | 301 | Settings::values.touchscreen.diameter_x = |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index e32bed5e6..7843d5167 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -29,16 +29,16 @@ EmuWindow_SDL2::~EmuWindow_SDL2() { | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { | 31 | void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { |
| 32 | TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); | 32 | TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); |
| 33 | input_subsystem->GetMouse()->MouseMove(x, y); | 33 | input_subsystem->GetMouse()->MouseMove(x, y); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { | 36 | void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { |
| 37 | if (button == SDL_BUTTON_LEFT) { | 37 | if (button == SDL_BUTTON_LEFT) { |
| 38 | if (state == SDL_PRESSED) { | 38 | if (state == SDL_PRESSED) { |
| 39 | TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); | 39 | TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); |
| 40 | } else { | 40 | } else { |
| 41 | TouchReleased(); | 41 | TouchReleased(0); |
| 42 | } | 42 | } |
| 43 | } else if (button == SDL_BUTTON_RIGHT) { | 43 | } else if (button == SDL_BUTTON_RIGHT) { |
| 44 | if (state == SDL_PRESSED) { | 44 | if (state == SDL_PRESSED) { |
| @@ -66,16 +66,16 @@ void EmuWindow_SDL2::OnFingerDown(float x, float y) { | |||
| 66 | // 3DS does | 66 | // 3DS does |
| 67 | 67 | ||
| 68 | const auto [px, py] = TouchToPixelPos(x, y); | 68 | const auto [px, py] = TouchToPixelPos(x, y); |
| 69 | TouchPressed(px, py); | 69 | TouchPressed(px, py, 0); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | void EmuWindow_SDL2::OnFingerMotion(float x, float y) { | 72 | void EmuWindow_SDL2::OnFingerMotion(float x, float y) { |
| 73 | const auto [px, py] = TouchToPixelPos(x, y); | 73 | const auto [px, py] = TouchToPixelPos(x, y); |
| 74 | TouchMoved(px, py); | 74 | TouchMoved(px, py, 0); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | void EmuWindow_SDL2::OnFingerUp() { | 77 | void EmuWindow_SDL2::OnFingerUp() { |
| 78 | TouchReleased(); | 78 | TouchReleased(0); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { | 81 | void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { |
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 a103b04bd..deddea9ee 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | |||
| @@ -59,29 +59,17 @@ private: | |||
| 59 | bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | 59 | bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { |
| 60 | std::vector<std::string_view> unsupported_ext; | 60 | std::vector<std::string_view> unsupported_ext; |
| 61 | 61 | ||
| 62 | if (!GLAD_GL_ARB_buffer_storage) | ||
| 63 | unsupported_ext.push_back("ARB_buffer_storage"); | ||
| 64 | if (!GLAD_GL_ARB_direct_state_access) | ||
| 65 | unsupported_ext.push_back("ARB_direct_state_access"); | ||
| 66 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | ||
| 67 | unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); | ||
| 68 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | ||
| 69 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); | ||
| 70 | if (!GLAD_GL_ARB_multi_bind) | ||
| 71 | unsupported_ext.push_back("ARB_multi_bind"); | ||
| 72 | if (!GLAD_GL_ARB_clip_control) | ||
| 73 | unsupported_ext.push_back("ARB_clip_control"); | ||
| 74 | |||
| 75 | // Extensions required to support some texture formats. | 62 | // Extensions required to support some texture formats. |
| 76 | if (!GLAD_GL_EXT_texture_compression_s3tc) | 63 | if (!GLAD_GL_EXT_texture_compression_s3tc) { |
| 77 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); | 64 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); |
| 78 | if (!GLAD_GL_ARB_texture_compression_rgtc) | 65 | } |
| 66 | if (!GLAD_GL_ARB_texture_compression_rgtc) { | ||
| 79 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); | 67 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); |
| 80 | if (!GLAD_GL_ARB_depth_buffer_float) | 68 | } |
| 81 | unsupported_ext.push_back("ARB_depth_buffer_float"); | ||
| 82 | 69 | ||
| 83 | for (const auto& extension : unsupported_ext) | 70 | for (const auto& extension : unsupported_ext) { |
| 84 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension); | 71 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension); |
| 72 | } | ||
| 85 | 73 | ||
| 86 | return unsupported_ext.empty(); | 74 | return unsupported_ext.empty(); |
| 87 | } | 75 | } |
| @@ -89,7 +77,7 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | |||
| 89 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) | 77 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) |
| 90 | : EmuWindow_SDL2{input_subsystem} { | 78 | : EmuWindow_SDL2{input_subsystem} { |
| 91 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | 79 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); |
| 92 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | 80 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); |
| 93 | 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); |
| 94 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | 82 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
| 95 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | 83 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 4faf62ede..0e1f3bdb3 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "common/logging/filter.h" | 17 | #include "common/logging/filter.h" |
| 18 | #include "common/logging/log.h" | 18 | #include "common/logging/log.h" |
| 19 | #include "common/microprofile.h" | 19 | #include "common/microprofile.h" |
| 20 | #include "common/nvidia_flags.h" | ||
| 20 | #include "common/scm_rev.h" | 21 | #include "common/scm_rev.h" |
| 21 | #include "common/scope_exit.h" | 22 | #include "common/scope_exit.h" |
| 22 | #include "common/string_util.h" | 23 | #include "common/string_util.h" |
| @@ -152,6 +153,8 @@ int main(int argc, char** argv) { | |||
| 152 | MicroProfileOnThreadCreate("EmuThread"); | 153 | MicroProfileOnThreadCreate("EmuThread"); |
| 153 | SCOPE_EXIT({ MicroProfileShutdown(); }); | 154 | SCOPE_EXIT({ MicroProfileShutdown(); }); |
| 154 | 155 | ||
| 156 | Common::ConfigureNvidiaEnvironmentFlags(); | ||
| 157 | |||
| 155 | if (filepath.empty()) { | 158 | if (filepath.empty()) { |
| 156 | LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); | 159 | LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); |
| 157 | return -1; | 160 | return -1; |