summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md2
-rw-r--r--dist/icons/controller/controller.qrc21
-rw-r--r--dist/icons/controller/dual_joycon.pngbin36466 -> 0 bytes
-rw-r--r--dist/icons/controller/dual_joycon_dark.pngbin36261 -> 0 bytes
-rw-r--r--dist/icons/controller/dual_joycon_midnight.pngbin34667 -> 0 bytes
-rw-r--r--dist/icons/controller/handheld.pngbin14108 -> 0 bytes
-rw-r--r--dist/icons/controller/handheld_dark.pngbin13731 -> 0 bytes
-rw-r--r--dist/icons/controller/handheld_midnight.pngbin13366 -> 0 bytes
-rw-r--r--dist/icons/controller/pro_controller.pngbin36710 -> 0 bytes
-rw-r--r--dist/icons/controller/pro_controller_dark.pngbin34897 -> 0 bytes
-rw-r--r--dist/icons/controller/pro_controller_midnight.pngbin35893 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left.pngbin25565 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_dark.pngbin25682 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_midnight.pngbin24405 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical.pngbin24764 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical_dark.pngbin24938 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical_midnight.pngbin23681 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right.pngbin28320 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_dark.pngbin28157 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_midnight.pngbin27006 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical.pngbin27655 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical_dark.pngbin27729 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical_midnight.pngbin26354 -> 0 bytes
m---------externals/dynarmic0
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/audio_core/command_generator.cpp5
-rw-r--r--src/audio_core/stream.cpp8
-rw-r--r--src/audio_core/stream.h3
-rw-r--r--src/audio_core/voice_context.h36
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/bit_util.h49
-rw-r--r--src/common/common_funcs.h17
-rw-r--r--src/common/nvidia_flags.cpp27
-rw-r--r--src/common/nvidia_flags.h10
-rw-r--r--src/common/ring_buffer.h21
-rw-r--r--src/common/scope_exit.h6
-rw-r--r--src/common/string_util.cpp14
-rw-r--r--src/common/uuid.h4
-rw-r--r--src/core/CMakeLists.txt25
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp11
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp6
-rw-r--r--src/core/core.cpp14
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/cpu_manager.cpp25
-rw-r--r--src/core/crypto/key_manager.cpp5
-rw-r--r--src/core/file_sys/savedata_factory.h4
-rw-r--r--src/core/file_sys/vfs_real.cpp14
-rw-r--r--src/core/frontend/emu_window.cpp43
-rw-r--r--src/core/frontend/emu_window.h13
-rw-r--r--src/core/frontend/input.h18
-rw-r--r--src/core/hardware_properties.h36
-rw-r--r--src/core/hle/ipc.h4
-rw-r--r--src/core/hle/kernel/client_port.h2
-rw-r--r--src/core/hle/kernel/client_session.cpp4
-rw-r--r--src/core/hle/kernel/client_session.h6
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp4
-rw-r--r--src/core/hle/kernel/global_scheduler_context.h19
-rw-r--r--src/core/hle/kernel/handle_table.cpp6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp32
-rw-r--r--src/core/hle/kernel/hle_ipc.h25
-rw-r--r--src/core/hle/kernel/k_address_arbiter.cpp118
-rw-r--r--src/core/hle/kernel/k_affinity_mask.h2
-rw-r--r--src/core/hle/kernel/k_condition_variable.cpp42
-rw-r--r--src/core/hle/kernel/k_condition_variable.h10
-rw-r--r--src/core/hle/kernel/k_event.cpp32
-rw-r--r--src/core/hle/kernel/k_event.h57
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h57
-rw-r--r--src/core/hle/kernel/k_light_lock.cpp130
-rw-r--r--src/core/hle/kernel/k_light_lock.h41
-rw-r--r--src/core/hle/kernel/k_priority_queue.h22
-rw-r--r--src/core/hle/kernel/k_readable_event.cpp57
-rw-r--r--src/core/hle/kernel/k_readable_event.h51
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp152
-rw-r--r--src/core/hle/kernel/k_resource_limit.h81
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp255
-rw-r--r--src/core/hle/kernel/k_scheduler.h49
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h34
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h18
-rw-r--r--src/core/hle/kernel/k_synchronization_object.cpp23
-rw-r--r--src/core/hle/kernel/k_synchronization_object.h7
-rw-r--r--src/core/hle/kernel/k_thread.cpp1050
-rw-r--r--src/core/hle/kernel/k_thread.h768
-rw-r--r--src/core/hle/kernel/k_thread_queue.h81
-rw-r--r--src/core/hle/kernel/k_writable_event.cpp27
-rw-r--r--src/core/hle/kernel/k_writable_event.h44
-rw-r--r--src/core/hle/kernel/kernel.cpp102
-rw-r--r--src/core/hle/kernel/kernel.h22
-rw-r--r--src/core/hle/kernel/memory/page_table.cpp10
-rw-r--r--src/core/hle/kernel/object.cpp6
-rw-r--r--src/core/hle/kernel/object.h9
-rw-r--r--src/core/hle/kernel/process.cpp134
-rw-r--r--src/core/hle/kernel/process.h96
-rw-r--r--src/core/hle/kernel/readable_event.cpp52
-rw-r--r--src/core/hle/kernel/readable_event.h57
-rw-r--r--src/core/hle/kernel/resource_limit.cpp73
-rw-r--r--src/core/hle/kernel/resource_limit.h104
-rw-r--r--src/core/hle/kernel/server_port.cpp2
-rw-r--r--src/core/hle/kernel/server_port.h2
-rw-r--r--src/core/hle/kernel/server_session.cpp8
-rw-r--r--src/core/hle/kernel/server_session.h12
-rw-r--r--src/core/hle/kernel/session.h2
-rw-r--r--src/core/hle/kernel/shared_memory.h2
-rw-r--r--src/core/hle/kernel/svc.cpp685
-rw-r--r--src/core/hle/kernel/svc_results.h6
-rw-r--r--src/core/hle/kernel/svc_types.h18
-rw-r--r--src/core/hle/kernel/svc_wrap.h56
-rw-r--r--src/core/hle/kernel/thread.cpp460
-rw-r--r--src/core/hle/kernel/thread.h782
-rw-r--r--src/core/hle/kernel/time_manager.cpp44
-rw-r--r--src/core/hle/kernel/time_manager.h10
-rw-r--r--src/core/hle/kernel/transfer_memory.h2
-rw-r--r--src/core/hle/kernel/writable_event.cpp45
-rw-r--r--src/core/hle/kernel/writable_event.h59
-rw-r--r--src/core/hle/service/acc/acc.cpp63
-rw-r--r--src/core/hle/service/acc/acc.h5
-rw-r--r--src/core/hle/service/acc/acc_su.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp2
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp20
-rw-r--r--src/core/hle/service/acc/profile_manager.h18
-rw-r--r--src/core/hle/service/am/am.cpp120
-rw-r--r--src/core/hle/service/am/am.h26
-rw-r--r--src/core/hle/service/am/applets/applets.cpp40
-rw-r--r--src/core/hle/service/am/applets/applets.h18
-rw-r--r--src/core/hle/service/am/applets/controller.cpp2
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp20
-rw-r--r--src/core/hle/service/aoc/aoc_u.h4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp27
-rw-r--r--src/core/hle/service/audio/audren_u.cpp43
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp16
-rw-r--r--src/core/hle/service/bcat/backend/backend.h10
-rw-r--r--src/core/hle/service/bcat/module.cpp8
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp11
-rw-r--r--src/core/hle/service/btm/btm.cpp34
-rw-r--r--src/core/hle/service/friend/friend.cpp14
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp17
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h21
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp11
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h26
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp252
-rw-r--r--src/core/hle/service/hid/controllers/npad.h227
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp127
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h32
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h70
-rw-r--r--src/core/hle/service/hid/hid.cpp256
-rw-r--r--src/core/hle/service/hid/hid.h13
-rw-r--r--src/core/hle/service/lbl/lbl.cpp283
-rw-r--r--src/core/hle/service/lm/lm.cpp321
-rw-r--r--src/core/hle/service/lm/manager.cpp134
-rw-r--r--src/core/hle/service/lm/manager.h106
-rw-r--r--src/core/hle/service/mii/manager.cpp51
-rw-r--r--src/core/hle/service/mii/manager.h112
-rw-r--r--src/core/hle/service/mii/raw_data.cpp3848
-rw-r--r--src/core/hle/service/mii/raw_data.h27
-rw-r--r--src/core/hle/service/nfp/nfp.cpp33
-rw-r--r--src/core/hle/service/nfp/nfp.h11
-rw-r--r--src/core/hle/service/nifm/nifm.cpp180
-rw-r--r--src/core/hle/service/nim/nim.cpp18
-rw-r--r--src/core/hle/service/ns/pl_u.cpp9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp18
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp6
-rw-r--r--src/core/hle/service/nvdrv/interface.h2
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp18
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h12
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp23
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h12
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp4
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h6
-rw-r--r--src/core/hle/service/pctl/module.cpp57
-rw-r--r--src/core/hle/service/prepo/prepo.cpp98
-rw-r--r--src/core/hle/service/ptm/psm.cpp115
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/sockets/bsd.cpp35
-rw-r--r--src/core/hle/service/sockets/bsd.h2
-rw-r--r--src/core/hle/service/time/clock_types.h26
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.cpp8
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.h7
-rw-r--r--src/core/hle/service/time/system_clock_context_update_callback.cpp4
-rw-r--r--src/core/hle/service/time/system_clock_context_update_callback.h6
-rw-r--r--src/core/hle/service/time/time.cpp2
-rw-r--r--src/core/hle/service/time/time.h2
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h2
-rw-r--r--src/core/hle/service/time/time_zone_types.h22
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp14
-rw-r--r--src/core/hle/service/vi/display/vi_display.h9
-rw-r--r--src/core/hle/service/vi/vi.cpp6
-rw-r--r--src/core/loader/nro.cpp6
-rw-r--r--src/core/loader/nso.cpp6
-rw-r--r--src/core/reporter.cpp50
-rw-r--r--src/core/reporter.h3
-rw-r--r--src/core/settings.cpp3
-rwxr-xr-xsrc/input_common/analog_from_button.cpp18
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp10
-rw-r--r--src/input_common/mouse/mouse_poller.cpp10
-rw-r--r--src/input_common/sdl/sdl_impl.cpp18
-rw-r--r--src/input_common/touch_from_button.cpp15
-rw-r--r--src/input_common/udp/client.cpp118
-rw-r--r--src/input_common/udp/client.h24
-rw-r--r--src/input_common/udp/protocol.h16
-rw-r--r--src/input_common/udp/udp.cpp32
-rw-r--r--src/tests/common/ring_buffer.cpp10
-rw-r--r--src/video_core/CMakeLists.txt6
-rw-r--r--src/video_core/buffer_cache/buffer_base.h2
-rw-r--r--src/video_core/engines/maxwell_3d.cpp68
-rw-r--r--src/video_core/engines/maxwell_3d.h2
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt20
-rw-r--r--src/video_core/memory_manager.cpp49
-rw-r--r--src/video_core/memory_manager.h9
-rw-r--r--src/video_core/morton.cpp0
-rw-r--r--src/video_core/morton.h0
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_device.h5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp3
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp29
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.h12
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h12
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp73
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h2
-rw-r--r--src/video_core/shader/async_shaders.cpp18
-rw-r--r--src/video_core/texture_cache/util.cpp61
-rw-r--r--src/video_core/vulkan_common/nsight_aftermath_tracker.cpp13
-rw-r--r--src/video_core/vulkan_common/nsight_aftermath_tracker.h8
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.cpp1
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp26
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h5
-rw-r--r--src/yuzu/CMakeLists.txt4
-rw-r--r--src/yuzu/applets/profile_select.cpp2
-rw-r--r--src/yuzu/bootmanager.cpp105
-rw-r--r--src/yuzu/bootmanager.h8
-rw-r--r--src/yuzu/configuration/config.cpp12
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp109
-rw-r--r--src/yuzu/configuration/configure_input_player.h2
-rw-r--r--src/yuzu/configuration/configure_input_player.ui74
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp2694
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h192
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp43
-rw-r--r--src/yuzu/configuration/configure_motion_touch.ui16
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp8
-rw-r--r--src/yuzu/configuration/configure_service.cpp2
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.cpp3
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.ui29
-rw-r--r--src/yuzu/debugger/controller.cpp66
-rw-r--r--src/yuzu/debugger/controller.h31
-rw-r--r--src/yuzu/debugger/wait_tree.cpp63
-rw-r--r--src/yuzu/debugger/wait_tree.h18
-rw-r--r--src/yuzu/game_list.cpp58
-rw-r--r--src/yuzu/game_list_p.h2
-rw-r--r--src/yuzu/main.cpp12
-rw-r--r--src/yuzu/main.h2
-rw-r--r--src/yuzu_cmd/config.cpp4
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp12
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp26
-rw-r--r--src/yuzu_cmd/yuzu.cpp3
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()
266endif() 266endif()
267 267
diff --git a/README.md b/README.md
index fbf62eb7c..cb1a64d8c 100644
--- a/README.md
+++ b/README.md
@@ -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
36We 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: 36We 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)
64else() 64else()
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
54bool 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
54void Stream::SetVolume(float volume) { 62void 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 {
86static_assert(sizeof(BehaviorFlags) == 0x4, "BehaviorFlags is an invalid size"); 86static_assert(sizeof(BehaviorFlags) == 0x4, "BehaviorFlags is an invalid size");
87 87
88struct ADPCMContext { 88struct ADPCMContext {
89 u16 header{}; 89 u16 header;
90 s16 yn1{}; 90 s16 yn1;
91 s16 yn2{}; 91 s16 yn2;
92}; 92};
93static_assert(sizeof(ADPCMContext) == 0x6, "ADPCMContext is an invalid size"); 93static_assert(sizeof(ADPCMContext) == 0x6, "ADPCMContext is an invalid size");
94 94
95struct VoiceState { 95struct 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
113class VoiceChannelResource { 113class 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
16namespace Common { 13namespace 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
104namespace Common { 121namespace 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
13namespace Common {
14
15void 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
5namespace Common {
6
7/// Configure platform specific flags for Nvidia's driver
8void 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 22template <typename T, std::size_t capacity>
23template <typename T, std::size_t capacity, std::size_t granularity = 1>
24class RingBuffer { 23class 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
143std::string UTF16ToUTF8(const std::u16string& input) { 143std::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
155std::u16string UTF8ToUTF16(const std::string& input) { 148std::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
15struct UUID { 15struct 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
257void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { 258void 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
266void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { 270void 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
296void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { 296void 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
307void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { 310void 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
723Service::LM::Manager& System::GetLogManager() {
724 return impl->lm_manager;
725}
726
727const Service::LM::Manager& System::GetLogManager() const {
728 return impl->lm_manager;
729}
730
731Service::Time::TimeManager& System::GetTimeManager() { 719Service::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 {
62class ARPManager; 62class ARPManager;
63} 63}
64 64
65namespace LM {
66class Manager;
67} // namespace LM
68
69namespace SM { 65namespace SM {
70class ServiceManager; 66class 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
19namespace Core { 19namespace 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
209void CpuManager::SingleCoreRunGuestLoop() { 209void 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
256void CpuManager::PreemptSingleCore(bool from_running_enviroment) { 255void 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
29private: 26private:
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
82void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { 79void 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
97void EmuWindow::TouchReleased() { 98void 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
104void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { 106void 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
114void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { 119void 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};
24struct 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.).
26template <typename StatusType> 31template <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
163using MotionDevice = InputDevice<MotionStatus>; 174using 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 */
169using TouchStatus = std::tuple<float, float, bool>; 181using 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
11namespace Core { 13namespace Core {
@@ -18,34 +20,12 @@ constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz u
18constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed 20constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed
19constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores 21constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
20 22
21} // namespace Hardware 23// Virtual to Physical core map.
22 24constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
23constexpr 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,
25struct 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
147struct DataPayloadHeader { 147struct DataPayloadHeader {
148 u32_le magic; 148 u32_le magic;
149 INSERT_PADDING_WORDS(1); 149 INSERT_PADDING_WORDS_NOINIT(1);
150}; 150};
151static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadHeader size is incorrect"); 151static_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};
180static_assert(sizeof(DomainMessageHeader) == 16, "DomainMessageHeader size is incorrect"); 180static_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
54private: 56private:
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
13namespace Kernel { 13namespace 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
41ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread, 41ResultCode 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
25class KernelCore; 25class KernelCore;
26class Session; 26class Session;
27class Thread; 27class KThread;
28 28
29class ClientSession final : public KSynchronizationObject { 29class ClientSession final : public KSynchronizationObject {
30public: 30public:
@@ -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
54private: 56private:
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
18GlobalSchedulerContext::~GlobalSchedulerContext() = default; 18GlobalSchedulerContext::~GlobalSchedulerContext() = default;
19 19
20void GlobalSchedulerContext::AddThread(std::shared_ptr<Thread> thread) { 20void 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
25void GlobalSchedulerContext::RemoveThread(std::shared_ptr<Thread> thread) { 25void 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
17namespace Kernel { 18namespace Kernel {
18 19
@@ -20,8 +21,12 @@ class KernelCore;
20class SchedulerLock; 21class SchedulerLock;
21 22
22using KSchedulerPriorityQueue = 23using KSchedulerPriorityQueue =
23 KPriorityQueue<Thread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>; 24 KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority,
24constexpr s32 HighestCoreMigrationAllowedPriority = 2; 25 Svc::HighestThreadPriority>;
26
27static constexpr s32 HighestCoreMigrationAllowedPriority = 2;
28static_assert(Svc::LowestThreadPriority >= HighestCoreMigrationAllowedPriority);
29static_assert(Svc::HighestThreadPriority <= HighestCoreMigrationAllowedPriority);
25 30
26class GlobalSchedulerContext final { 31class 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
16namespace Kernel { 16namespace Kernel {
17namespace { 17namespace {
@@ -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
32namespace Kernel { 32namespace Kernel {
@@ -48,7 +48,7 @@ void SessionRequestHandler::ClientDisconnected(
48 48
49HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, 49HLERequestContext::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
185ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { 185ResultCode 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
341bool 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
352bool 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
341std::string HLERequestContext::Description() const { 363std::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;
40class KernelCore; 40class KernelCore;
41class Process; 41class Process;
42class ServerSession; 42class ServerSession;
43class Thread; 43class KThread;
44class ReadableEvent; 44class KReadableEvent;
45class WritableEvent; 45class KWritableEvent;
46 46
47enum class ThreadWakeupReason; 47enum class ThreadWakeupReason;
48 48
@@ -110,7 +110,7 @@ class HLERequestContext {
110public: 110public:
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
232ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { 214ResultCode 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
303ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { 281ResultCode 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
20namespace Kernel { 20namespace Kernel {
@@ -66,7 +66,7 @@ KConditionVariable::KConditionVariable(Core::System& system_)
66KConditionVariable::~KConditionVariable() = default; 66KConditionVariable::~KConditionVariable() = default;
67 67
68ResultCode KConditionVariable::SignalToAddress(VAddr addr) { 68ResultCode 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
105ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { 105ResultCode 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
157Thread* KConditionVariable::SignalImpl(Thread* thread) { 157KThread* 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
258ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { 258ResultCode 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
15namespace Core { 15namespace Core {
@@ -20,7 +20,7 @@ namespace Kernel {
20 20
21class KConditionVariable { 21class KConditionVariable {
22public: 22public:
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
36private: 36private:
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
45inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, 45inline 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
52inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, 52inline 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
9namespace Kernel {
10
11KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {}
12
13KEvent::~KEvent() = default;
14
15std::shared_ptr<KEvent> KEvent::Create(KernelCore& kernel, std::string&& name) {
16 return std::make_shared<KEvent>(kernel, std::move(name));
17}
18
19void 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
9namespace Kernel {
10
11class KernelCore;
12class KReadableEvent;
13class KWritableEvent;
14
15class KEvent final : public Object {
16public:
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
51private:
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
16namespace Kernel {
17class KernelCore;
18
19class KLightConditionVariable {
20public:
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
36private:
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
10namespace Kernel {
11
12void 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
34void 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
44void 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
84void 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
126bool 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
12namespace Kernel {
13
14class KernelCore;
15
16class KLightLock {
17public:
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
34private:
35 std::atomic<uintptr_t> tag{};
36 KernelCore& kernel;
37};
38
39using 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
19namespace Kernel { 19namespace Kernel {
20 20
21class Thread; 21class KThread;
22 22
23template <typename T> 23template <typename T>
24concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) { 24concept 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
58template <typename Member, size_t _NumCores, int LowestPriority, int HighestPriority> 58template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
59requires KPriorityQueueMember<Member> class KPriorityQueue { 59requires KPriorityQueueMember<Member> class KPriorityQueue {
60public: 60public:
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
17namespace Kernel {
18
19KReadableEvent::KReadableEvent(KernelCore& kernel, std::string&& name)
20 : KSynchronizationObject{kernel, std::move(name)} {}
21KReadableEvent::~KReadableEvent() = default;
22
23bool KReadableEvent::IsSignaled() const {
24 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
25
26 return is_signaled;
27}
28
29ResultCode 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
40ResultCode KReadableEvent::Clear() {
41 Reset();
42
43 return RESULT_SUCCESS;
44}
45
46ResultCode 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
11namespace Kernel {
12
13class KernelCore;
14class KEvent;
15
16class KReadableEvent final : public KSynchronizationObject {
17public:
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
46private:
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
15namespace Kernel {
16constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
17
18KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system)
19 : Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {}
20KResourceLimit::~KResourceLimit() = default;
21
22s64 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
35s64 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
48s64 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
61s64 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
75ResultCode 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
85bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
86 return Reserve(which, value, system.CoreTiming().GetGlobalTimeNs().count() + DefaultTimeout);
87}
88
89bool 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
129void KResourceLimit::Release(LimitableResource which, s64 value) {
130 Release(which, value, value);
131}
132
133void 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
16union ResultCode;
17
18namespace Core {
19class System;
20}
21
22namespace Kernel {
23class KernelCore;
24enum class LimitableResource : u32 {
25 PhysicalMemory = 0,
26 Threads = 1,
27 Events = 2,
28 TransferMemory = 3,
29 Sessions = 4,
30
31 Count,
32};
33
34constexpr bool IsValidResourceType(LimitableResource type) {
35 return type < LimitableResource::Count;
36}
37
38class KResourceLimit final : public Object {
39public:
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
69private:
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
26namespace Kernel { 26namespace Kernel {
27 27
28static void IncrementScheduledCount(Kernel::Thread* thread) { 28static 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
34void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, 34void 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
59u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) { 64u64 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
185void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state) { 202void 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
215void 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
208void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority) { 238void 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
220void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, 250void 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
355void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling, 385void 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
363u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { 395u64 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
375void KScheduler::YieldWithoutCoreMigration() { 407void 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
416void KScheduler::YieldWithCoreMigration() { 446void 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
506void KScheduler::YieldToAnyThread() { 534void 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
584KScheduler::KScheduler(Core::System& system, std::size_t core_id) 610KScheduler::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
595KScheduler::~KScheduler() = default; 620KScheduler::~KScheduler() = default;
596 621
597Thread* KScheduler::GetCurrentThread() const { 622KThread* 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
627void KScheduler::Unload(Thread* thread) { 652void 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
646void KScheduler::Reload(Thread* thread) { 676void 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
669void KScheduler::SwitchContextStep2() { 696void 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
676void KScheduler::ScheduleImpl() { 703void 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 = &current_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
747void KScheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { 783void 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
778KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) 809KScopedSchedulerLock::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 {
29class KernelCore; 29class KernelCore;
30class Process; 30class Process;
31class SchedulerLock; 31class SchedulerLock;
32class Thread; 32class KThread;
33 33
34class KScheduler final { 34class KScheduler final {
35public: 35public:
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
121private: 126private:
@@ -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
15namespace Kernel { 16namespace 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
16namespace Kernel { 16namespace Kernel {
17 17
18class KScopedSchedulerLockAndSleep { 18class KScopedSchedulerLockAndSleep {
19public: 19public:
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
43private: 40private:
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
14namespace Kernel { 14namespace 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
137KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} 133KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {}
138 134
139KSynchronizationObject ::~KSynchronizationObject() = default; 135KSynchronizationObject::KSynchronizationObject(KernelCore& kernel, std::string&& name)
136 : Object{kernel, std::move(name)} {}
137
138KSynchronizationObject::~KSynchronizationObject() = default;
140 139
141void KSynchronizationObject::NotifyAvailable(ResultCode result) { 140void 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
159std::vector<Thread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const { 158std::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
14class KernelCore; 14class KernelCore;
15class Synchronization; 15class Synchronization;
16class Thread; 16class 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
19class KSynchronizationObject : public Object { 19class KSynchronizationObject : public Object {
20public: 20public:
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
34protected: 34protected:
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
43namespace {
44static 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
52static 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
63namespace Kernel {
64
65KThread::KThread(KernelCore& kernel)
66 : KSynchronizationObject{kernel}, activity_pause_lock{kernel} {}
67KThread::~KThread() = default;
68
69ResultCode 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
212ResultCode 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
221void 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
254bool KThread::IsSignaled() const {
255 return signaled;
256}
257
258void 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
270void 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
300void 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
349void 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
410ResultCode 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
420ResultCode 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
436ResultCode 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
559void 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
571void 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
582void 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
598void 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
617void 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
631void 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
643void 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
654ResultCode 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
738ResultCode 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
773void 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
795void 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
808void 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
853void KThread::AddWaiter(KThread* thread) {
854 AddWaiterImpl(thread);
855 RestorePriority(kernel, this);
856}
857
858void KThread::RemoveWaiter(KThread* thread) {
859 RemoveWaiterImpl(thread);
860 RestorePriority(kernel, this);
861}
862
863KThread* 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
903ResultCode 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
932void 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
953ResultCode 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
981void 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
996std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
997 return host_context;
998}
999
1000ResultVal<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
1010ResultVal<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
1038KThread* GetCurrentThreadPointer(KernelCore& kernel) {
1039 return kernel.GetCurrentEmuThread();
1040}
1041
1042KThread& GetCurrentThread(KernelCore& kernel) {
1043 return *GetCurrentThreadPointer(kernel);
1044}
1045
1046s32 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
27namespace Common {
28class Fiber;
29}
30
31namespace Core {
32class ARM_Interface;
33class System;
34} // namespace Core
35
36namespace Kernel {
37
38class GlobalSchedulerContext;
39class KernelCore;
40class Process;
41class KScheduler;
42class KThreadQueue;
43
44using KThreadFunction = VAddr;
45
46enum class ThreadType : u32 {
47 Main = 0,
48 Kernel = 1,
49 HighPriority = 2,
50 User = 3,
51};
52DECLARE_ENUM_FLAG_OPERATORS(ThreadType);
53
54enum class SuspendType : u32 {
55 Process = 0,
56 Thread = 1,
57 Debug = 2,
58 Backtrace = 3,
59 Init = 4,
60
61 Count,
62};
63
64enum 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};
81DECLARE_ENUM_FLAG_OPERATORS(ThreadState);
82
83enum class DpcFlag : u32 {
84 Terminating = (1 << 0),
85 Terminated = (1 << 1),
86};
87
88enum 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
102class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
103 friend class KScheduler;
104 friend class Process;
105
106public:
107 static constexpr s32 DefaultThreadPriority = 44;
108 static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1;
109
110 explicit KThread(KernelCore& kernel);
111 ~KThread() override;
112
113public:
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
606private:
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
731public:
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
9namespace Kernel {
10
11class KThreadQueue {
12public:
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
76private:
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
9namespace Kernel {
10
11KWritableEvent::KWritableEvent(KernelCore& kernel, std::string&& name)
12 : Object{kernel, std::move(name)} {}
13KWritableEvent::~KWritableEvent() = default;
14
15void KWritableEvent::Initialize(KEvent* parent_) {
16 parent = parent_;
17}
18
19ResultCode KWritableEvent::Signal() {
20 return parent->GetReadableEvent()->Signal();
21}
22
23ResultCode 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
10namespace Kernel {
11
12class KernelCore;
13class KEvent;
14
15class KWritableEvent final : public Object {
16public:
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
40private:
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
379std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { 393std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const {
380 return impl->system_resource_limit; 394 return impl->system_resource_limit;
381} 395}
382 396
383std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { 397std::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
387void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { 401void 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
549Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { 563KThread* KernelCore::GetCurrentEmuThread() const {
550 return impl->GetCurrentEmuThreadID(); 564 return impl->GetCurrentEmuThread();
551} 565}
552 566
553Memory::MemoryManager& KernelCore::MemoryManager() { 567Memory::MemoryManager& KernelCore::MemoryManager() {
@@ -645,4 +659,12 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> servi
645 }); 659 });
646} 660}
647 661
662bool KernelCore::IsPhantomModeForSingleCore() const {
663 return impl->IsPhantomModeForSingleCore();
664}
665
666void 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;
38class HandleTable; 38class HandleTable;
39class PhysicalCore; 39class PhysicalCore;
40class Process; 40class Process;
41class ResourceLimit; 41class KResourceLimit;
42class KScheduler; 42class KScheduler;
43class SharedMemory; 43class SharedMemory;
44class ServiceThread; 44class ServiceThread;
45class Synchronization; 45class Synchronization;
46class Thread; 46class KThread;
47class TimeManager; 47class TimeManager;
48 48
49using EmuThreadHandle = uintptr_t;
50constexpr EmuThreadHandle EmuThreadHandleInvalid{};
51constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63};
52
49/// Represents a single instance of the kernel. 53/// Represents a single instance of the kernel.
50class KernelCore { 54class KernelCore {
51private: 55private:
@@ -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
240private: 248private:
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
21namespace Kernel::Memory { 21namespace 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
9namespace Kernel { 9namespace Kernel {
10 10
11Object::Object(KernelCore& kernel) : kernel{kernel}, object_id{kernel.CreateNewObjectID()} {} 11Object::Object(KernelCore& kernel_)
12 : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{"[UNKNOWN KERNEL OBJECT]"} {}
13Object::Object(KernelCore& kernel_, std::string&& name_)
14 : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{std::move(name_)} {}
12Object::~Object() = default; 15Object::~Object() = default;
13 16
14bool Object::IsWaitable() const { 17bool 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
19enum class HandleType : u32 { 19enum 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
35class Object : NonCopyable, public std::enable_shared_from_this<Object> { 36class Object : NonCopyable, public std::enable_shared_from_this<Object> {
36public: 37public:
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
64protected: 68protected:
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
68private: 72private:
69 std::atomic<u32> object_id{0}; 73 std::atomic<u32> object_id{0};
74 std::string name;
70}; 75};
71 76
72template <typename T> 77template <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 */
39void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { 40void 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
136std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const { 136std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
137 return resource_limit; 137 return resource_limit;
138} 138}
139 139
140void 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
149void 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
140u64 Process::GetTotalPhysicalMemoryAvailable() const { 157u64 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
165void Process::RegisterThread(const Thread* thread) { 182bool 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
207void 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
222void 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
237void Process::RegisterThread(const KThread* thread) {
166 thread_list.push_back(thread); 238 thread_list.push_back(thread);
167} 239}
168 240
169void Process::UnregisterThread(const Thread* thread) { 241void Process::UnregisterThread(const KThread* thread) {
170 thread_list.remove(thread); 242 thread_list.remove(thread);
171} 243}
172 244
173ResultCode Process::ClearSignalState() { 245ResultCode 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
267void Process::PrepareForTermination() { 337void 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 {
372Process::Process(Core::System& system) 442Process::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
377Process::~Process() = default; 447Process::~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;
29namespace Kernel { 29namespace Kernel {
30 30
31class KernelCore; 31class KernelCore;
32class ResourceLimit; 32class KResourceLimit;
33class Thread; 33class KThread;
34class TLSPage; 34class TLSPage;
35 35
36struct CodeSet; 36struct 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
315private: 364private:
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
15namespace Kernel {
16
17ReadableEvent::ReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {}
18ReadableEvent::~ReadableEvent() = default;
19
20void ReadableEvent::Signal() {
21 if (is_signaled) {
22 return;
23 }
24
25 is_signaled = true;
26 NotifyAvailable();
27}
28
29bool ReadableEvent::IsSignaled() const {
30 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
31
32 return is_signaled;
33}
34
35void ReadableEvent::Clear() {
36 is_signaled = false;
37}
38
39ResultCode 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
10union ResultCode;
11
12namespace Kernel {
13
14class KernelCore;
15class WritableEvent;
16
17class ReadableEvent final : public KSynchronizationObject {
18 friend class WritableEvent;
19
20public:
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
50private:
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
9namespace Kernel {
10namespace {
11constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
12 return static_cast<std::size_t>(type);
13}
14} // Anonymous namespace
15
16ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
17ResourceLimit::~ResourceLimit() = default;
18
19bool ResourceLimit::Reserve(ResourceType resource, s64 amount) {
20 return Reserve(resource, amount, 10000000000);
21}
22
23bool 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
39void ResourceLimit::Release(ResourceType resource, u64 amount) {
40 Release(resource, amount, amount);
41}
42
43void 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
50std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
51 return std::make_shared<ResourceLimit>(kernel);
52}
53
54s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
55 return limit.at(ResourceTypeToIndex(resource)) - current.at(ResourceTypeToIndex(resource));
56}
57
58s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
59 return limit.at(ResourceTypeToIndex(resource));
60}
61
62ResultCode 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
13union ResultCode;
14
15namespace Kernel {
16
17class KernelCore;
18
19enum 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
30constexpr bool IsValidResourceType(ResourceType type) {
31 return type < ResourceType::ResourceTypeCount;
32}
33
34class ResourceLimit final : public Object {
35public:
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
88private:
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
14namespace Kernel { 14namespace 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
84private: 86private:
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
25namespace Kernel { 25namespace Kernel {
@@ -116,7 +116,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
116 return RESULT_SUCCESS; 116 return RESULT_SUCCESS;
117} 117}
118 118
119ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, 119ResultCode 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
164ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, 164ResultCode 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;
29class KernelCore; 29class KernelCore;
30class Session; 30class Session;
31class SessionRequestHandler; 31class SessionRequestHandler;
32class Thread; 32class 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
129private: 131private:
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
74private: 76private:
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 {
141ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, 143ResultVal<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
357static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { 360static 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.
362static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) { 365static 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
376static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high, 381static 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
473static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { 478static 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
1029static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { 1050static 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
1060static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) { 1094static 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
1065static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { 1100static 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
1105static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { 1138static 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
1110static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) { 1143static 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
1125static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) { 1159static 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
1130static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { 1164static 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
1444static void ExitProcess32(Core::System& system) { 1476static void ExitProcess32(Core::System& system) {
1445 ExitProcess(system); 1477 ExitProcess(system);
1446} 1478}
1447 1479
1480static 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
1449static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, 1485static 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
1517static ResultCode StartThread(Core::System& system, Handle thread_handle) { 1549static 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
1533static ResultCode StartThread32(Core::System& system, Handle thread_handle) { 1572static 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
1546static void ExitThread32(Core::System& system) { 1585static 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
1551static void SleepThread(Core::System& system, s64 nanoseconds) { 1590static 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) {
1766static ResultCode ResetSignal(Core::System& system, Handle handle) { 1823static 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
1785static ResultCode ResetSignal32(Core::System& system, Handle handle) { 1850static 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
1842static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, 1907static 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
1862static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, 1929static 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
1871static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, 1938static 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
1927static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, 1996static 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
1933static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { 2002static 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
1961static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) { 2018static 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
1965static ResultCode ClearEvent(Core::System& system, Handle handle) { 2022static 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
1986static ResultCode ClearEvent32(Core::System& system, Handle handle) { 2049static ResultCode ClearEvent32(Core::System& system, Handle event_handle) {
1987 return ClearEvent(system, handle); 2050 return ClearEvent(system, event_handle);
1988} 2051}
1989 2052
1990static ResultCode SignalEvent(Core::System& system, Handle handle) { 2053static 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
2005static ResultCode SignalEvent32(Core::System& system, Handle handle) { 2092static 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
2009static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { 2096static 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
9namespace Kernel::Svc { 9namespace Kernel::Svc {
10 10
11constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
11constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59}; 12constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
12constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102}; 13constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
14constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103};
13constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106}; 15constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
16constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
17constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113};
14constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114}; 18constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
19constexpr ResultCode ResultInvalidCombination{ErrorModule::Kernel, 116};
15constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117}; 20constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
16constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118}; 21constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
17constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120}; 22constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120};
23constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122};
18constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; 24constexpr 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
80enum class YieldType : s64 {
81 WithoutCoreMigration = 0,
82 WithCoreMigration = -1,
83 ToAnyThread = -2,
84};
85
86enum class ThreadActivity : u32 {
87 Runnable = 0,
88 Paused = 1,
89};
90
91constexpr inline s32 IdealCoreDontCare = -1;
92constexpr inline s32 IdealCoreUseProcessValue = -2;
93constexpr inline s32 IdealCoreNoUpdate = -3;
94
95constexpr inline s32 LowestThreadPriority = 63;
96constexpr 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
62template <ResultCode func(Core::System&, Handle, Svc::ThreadActivity)>
63void 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
61template <ResultCode func(Core::System&, u32, u64, u64, u64)> 69template <ResultCode func(Core::System&, u32, u64, u64, u64)>
62void SvcWrap64(Core::System& system) { 70void 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
161template <ResultCode func(Core::System&, u32, u32*, u64*)> 169// Used by SetThreadCoreMask
170template <ResultCode func(Core::System&, Handle, s32, u64)>
162void SvcWrap64(Core::System& system) { 171void 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
178template <ResultCode func(Core::System&, Handle, s32*, u64*)>
179void 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)), &param_1, &param_2); 182 const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), &param_1, &param_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
494template <ResultCode func(Core::System&, Handle, s32*, u32*, u32*)>
495void 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), &param_1, &param_2, &param_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
477template <void func(Core::System&, u32, s32)> 508template <void func(Core::System&, u32, s32)>
478void SvcWrap32(Core::System& system) { 509void 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
514template <ResultCode func(Core::System&, Handle, Svc::ThreadActivity)>
515void 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
483template <ResultCode func(Core::System&, Handle, u32)> 523template <ResultCode func(Core::System&, Handle, u32)>
484void SvcWrap32(Core::System& system) { 524void 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
491template <ResultCode func(Core::System&, Handle, u32, u32, u32)> 531template <ResultCode func(Core::System&, Handle, u32, u32, u32)>
492void SvcWrap32(Core::System& system) { 532void 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
541template <ResultCode func(Core::System&, Handle, s32, u32, u32)>
542void 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
501template <ResultCode func(Core::System&, u32, u32, Handle, u32, u32)> 551template <ResultCode func(Core::System&, u32, u32, Handle, u32, u32)>
502void SvcWrap32(Core::System& system) { 552void 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
37namespace Kernel {
38
39bool Thread::IsSignaled() const {
40 return signaled;
41}
42
43Thread::Thread(KernelCore& kernel) : KSynchronizationObject{kernel} {}
44Thread::~Thread() = default;
45
46void 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
65void Thread::Wakeup() {
66 KScopedSchedulerLock lock(kernel);
67 SetState(ThreadState::Runnable);
68}
69
70ResultCode Thread::Start() {
71 KScopedSchedulerLock lock(kernel);
72 SetState(ThreadState::Runnable);
73 return RESULT_SUCCESS;
74}
75
76void 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
88static 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
96static 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
106std::shared_ptr<Common::Fiber>& Thread::GetHostContext() {
107 return host_context;
108}
109
110ResultVal<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
120ResultVal<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
191void 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
204void Thread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) {
205 signaling_object = object;
206 signaling_result = result;
207}
208
209VAddr 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
215void 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
230void 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
252void 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
265void 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
310void Thread::AddWaiter(Thread* thread) {
311 AddWaiterImpl(thread);
312 RestorePriority(kernel, this);
313}
314
315void Thread::RemoveWaiter(Thread* thread) {
316 RemoveWaiterImpl(thread);
317 RestorePriority(kernel, this);
318}
319
320Thread* 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
360ResultCode 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
387ResultCode 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
402void 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
410void 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
418ResultCode 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
26namespace Common {
27class Fiber;
28}
29
30namespace Core {
31class ARM_Interface;
32class System;
33} // namespace Core
34
35namespace Kernel {
36
37class GlobalSchedulerContext;
38class KernelCore;
39class Process;
40class KScheduler;
41
42enum 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
51enum ThreadType : u32 {
52 THREADTYPE_USER = 0x1,
53 THREADTYPE_KERNEL = 0x2,
54 THREADTYPE_HLE = 0x4,
55 THREADTYPE_IDLE = 0x8,
56 THREADTYPE_SUSPEND = 0x10,
57};
58
59enum 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
81enum 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};
98DECLARE_ENUM_FLAG_OPERATORS(ThreadState);
99
100enum 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
105enum class ThreadActivity : u32 {
106 Normal = 0,
107 Paused = 1,
108};
109
110enum class ThreadSchedFlags : u32 {
111 ProcessPauseFlag = 1 << 4,
112 ThreadPauseFlag = 1 << 5,
113 ProcessDebugPauseFlag = 1 << 6,
114 KernelInitPauseFlag = 1 << 8,
115};
116
117enum 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
127class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
128 friend class KScheduler;
129 friend class Process;
130
131public:
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
579private:
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
631public:
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
679private:
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
15namespace Kernel { 15namespace 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
38void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { 30void 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
52void 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
61void TimeManager::CancelTimeEvent(Thread* time_task) { 41void 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
21namespace Kernel { 21namespace Kernel {
22 22
23class Thread; 23class 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
42private: 39private:
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
75private: 77private:
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
13namespace Kernel {
14
15WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
16WritableEvent::~WritableEvent() = default;
17
18EventPair 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
29std::shared_ptr<ReadableEvent> WritableEvent::GetReadableEvent() const {
30 return readable;
31}
32
33void WritableEvent::Signal() {
34 readable->Signal();
35}
36
37void WritableEvent::Clear() {
38 readable->Clear();
39}
40
41bool 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
11namespace Kernel {
12
13class KernelCore;
14class ReadableEvent;
15class WritableEvent;
16
17struct EventPair {
18 std::shared_ptr<ReadableEvent> readable;
19 std::shared_ptr<WritableEvent> writable;
20};
21
22class WritableEvent final : public Object {
23public:
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
51private:
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
33namespace Service::Account { 33namespace Service::Account {
34 34
35constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30}; 35constexpr ResultCode ERR_INVALID_USER_ID{ErrorModule::Account, 20};
36constexpr ResultCode ERR_INVALID_APPLICATION_ID{ErrorModule::Account, 22};
37constexpr ResultCode ERR_INVALID_BUFFER{ErrorModule::Account, 30};
38constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 31};
36constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100}; 39constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
37 40
41// Thumbnails are hard coded to be at least this size
42constexpr std::size_t THUMBNAIL_SIZE = 0x24000;
43
38static std::string GetImagePath(Common::UUID uuid) { 44static 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
820void 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
833void 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
842void 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
814void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { 869void 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/
41ProfileManager::ProfileManager() { 41ProfileManager::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
229UserIDArray ProfileManager::GetAllUsers() const { 235UserIDArray 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
238UserIDArray ProfileManager::GetOpenUsers() const { 244UserIDArray 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
25struct ProfileData { 25struct 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};
33static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size"); 33static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size");
34 34
@@ -43,9 +43,9 @@ struct ProfileInfo {
43}; 43};
44 44
45struct ProfileBase { 45struct 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
319ISelfController::~ISelfController() = default; 321ISelfController::~ISelfController() = default;
@@ -372,11 +374,11 @@ void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) {
372void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { 374void 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
382void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { 384void 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
561AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { 563AppletMessageQueue::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
568AppletMessageQueue::~AppletMessageQueue() = default; 571AppletMessageQueue::~AppletMessageQueue() = default;
569 572
570const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const { 573const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const {
571 return on_new_message.readable; 574 return on_new_message->GetReadableEvent();
572} 575}
573 576
574const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() 577const 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
579void AppletMessageQueue::PushMessage(AppletMessage msg) { 582void 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
584AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { 587AppletMessageQueue::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 {
601void AppletMessageQueue::OperationModeChanged() { 604void 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
607void AppletMessageQueue::RequestExit() { 610void 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
738void 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
735void ICommonStateGetter::EndVrModeEx(Kernel::HLERequestContext& ctx) { 745void 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
1225IApplicationFunctions::~IApplicationFunctions() = default; 1246IApplicationFunctions::~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
1490void 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
1469void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { 1500void 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
1612void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) { 1643void 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
1651void 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
1659void 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
1620void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, 1667void 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
1657IHomeMenuFunctions::~IHomeMenuFunctions() = default; 1705IHomeMenuFunctions::~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
1674IGlobalStateController::IGlobalStateController(Core::System& system_) 1722IGlobalStateController::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
13namespace Kernel { 13namespace Kernel {
14class KernelCore; 14class KernelCore;
15class KEvent;
15class TransferMemory; 16class 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
66private: 67private:
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
72class IWindowController final : public ServiceFramework<IWindowController> { 73class 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
298class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 304class 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
310class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { 316class 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
28AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) { 30AppletDataBroker::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
37AppletDataBroker::~AppletDataBroker() = default; 41AppletDataBroker::~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
97void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { 101void 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
102void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { 106void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
@@ -105,23 +109,23 @@ void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& s
105 109
106void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) { 110void 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
111void AppletDataBroker::SignalStateChanged() const { 115void AppletDataBroker::SignalStateChanged() const {
112 state_changed_event.writable->Signal(); 116 state_changed_event->GetWritableEvent()->Signal();
113} 117}
114 118
115std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const { 119std::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
119std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { 123std::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
123std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const { 127std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
124 return state_changed_event.readable; 128 return state_changed_event->GetReadableEvent();
125} 129}
126 130
127Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {} 131Applet::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
13union ResultCode; 13union ResultCode;
14 14
@@ -29,7 +29,9 @@ class WebBrowserApplet;
29 29
30namespace Kernel { 30namespace Kernel {
31class KernelCore; 31class KernelCore;
32} 32class KEvent;
33class KReadableEvent;
34} // namespace Kernel
33 35
34namespace Service::AM { 36namespace 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
94private: 96private:
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
118class Applet { 120class 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
69private: 71private:
@@ -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
105AOC_U::AOC_U(Core::System& system_) 107AOC_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
131AOC_U::~AOC_U() = default; 133AOC_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
258void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) { 260void 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
13namespace Kernel { 13namespace Kernel {
14class WritableEvent; 14class KEvent;
15} 15}
16 16
17namespace Service::AOC { 17namespace 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};
29struct AudoutParams { 30struct 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};
34static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size"); 35static_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
203private: 206private:
@@ -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
13ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel, 16ProgressServiceBackend::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
19std::shared_ptr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const { 23std::shared_ptr<Kernel::KReadableEvent> ProgressServiceBackend::GetEvent() const {
20 return event.readable; 24 return event->GetReadableEvent();
21} 25}
22 26
23DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { 27DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
@@ -85,9 +89,9 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
85void ProgressServiceBackend::SignalUpdate() const { 89void 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
18namespace Core { 16namespace Core {
@@ -21,7 +19,9 @@ class System;
21 19
22namespace Kernel { 20namespace Kernel {
23class KernelCore; 21class KernelCore;
24} 22class KEvent;
23class KReadableEvent;
24} // namespace Kernel
25 25
26namespace Service::BCAT { 26namespace Service::BCAT {
27 27
@@ -98,13 +98,13 @@ public:
98private: 98private:
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 {
89class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { 89class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
90public: 90public:
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
41private: 42private:
@@ -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
53class BtDrv final : public ServiceFramework<BtDrv> { 54class 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
69private: 71private:
@@ -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
108class BTM_USR final : public ServiceFramework<BTM_USR> { 110class 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
190private: 192private:
@@ -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
33private: 34private:
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
32private: 33private:
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
144Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} 145Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {
146 latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
147}
145 148
146Controller_NPad::~Controller_NPad() { 149Controller_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) {
231void Controller_NPad::OnInit() { 241void 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
713void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) { 733void 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
873std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { 893std::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
878void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { 899void 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
882void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { 903void 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
976void Controller_NPad::SetSixAxisFusionParameters(f32 parameter1, f32 parameter2) {
977 sixaxis_fusion_parameter1 = parameter1;
978 sixaxis_fusion_parameter2 = parameter2;
979}
980
981std::pair<f32, f32> Controller_NPad::GetSixAxisFusionParameters() {
982 return {
983 sixaxis_fusion_parameter1,
984 sixaxis_fusion_parameter2,
985 };
986}
987
988void Controller_NPad::ResetSixAxisFusionParameters() {
989 sixaxis_fusion_parameter1 = 0.0f;
990 sixaxis_fusion_parameter2 = 0.0f;
991}
992
947void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { 993void 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
16namespace Kernel {
17class KEvent;
18class KReadableEvent;
19} // namespace Kernel
20
17namespace Service::HID { 21namespace Service::HID {
18 22
19constexpr u32 NPAD_HANDHELD = 32; 23constexpr 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;
16Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} 17Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {}
17Controller_Touchscreen::~Controller_Touchscreen() = default; 18Controller_Touchscreen::~Controller_Touchscreen() = default;
18 19
19void Controller_Touchscreen::OnInit() {} 20void 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
21void Controller_Touchscreen::OnRelease() {} 28void 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
69void Controller_Touchscreen::OnLoadInputDevices() { 100void 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
106std::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
118std::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
32private: 32private:
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
30private: 31private:
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) {
411void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { 417void 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) {
441void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { 447void 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) {
462void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { 468void 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) {
483void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { 489void 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) {
504void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { 510void 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) {
525void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { 531void 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
554void 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
580void 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
608void 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
547void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 631void 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) {
566void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 650void 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) {
587void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 671void 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) {
609void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { 693void 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) {
630void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { 714void 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) {
712void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { 796void 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) {
732void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { 816void 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) {
810void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { 894void 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) {
854void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { 938void 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) {
962void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { 1046void 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
981void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) { 1065void 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) {
1036void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { 1120void 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) {
1060void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { 1144void 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) {
1157void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { 1241void 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) {
1190void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 1274void 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) {
1210void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 1294void 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
57private: 57private:
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
87void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { 326void 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
17namespace Service::LM { 19namespace Service::LM {
20enum 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
29struct 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
39namespace std {
40template <>
41struct 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
53namespace Service::LM {
54
55enum class LogDestination : u32 {
56 TargetManager = 1 << 0,
57 Uart = 1 << 1,
58 UartSleep = 1 << 2,
59 All = 0xffff,
60};
61DECLARE_ENUM_FLAG_OPERATORS(LogDestination);
62
63enum class LogPacketFlags : u8 {
64 Head = 1 << 0,
65 Tail = 1 << 1,
66 LittleEndian = 1 << 2,
67};
68DECLARE_ENUM_FLAG_OPERATORS(LogPacketFlags);
18 69
19class ILogger final : public ServiceFramework<ILogger> { 70class ILogger final : public ServiceFramework<ILogger> {
20public: 71public:
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
31private: 80private:
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
83class LM final : public ServiceFramework<LM> { 342class 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
11namespace Service::LM {
12
13std::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
32std::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
49std::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
70std::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
94Manager::Manager(Core::Reporter& reporter) : reporter(reporter) {}
95
96Manager::~Manager() = default;
97
98void Manager::SetEnabled(bool enabled) {
99 this->enabled = enabled;
100}
101
102void Manager::SetDestination(DestinationFlag destination) {
103 this->destination = destination;
104}
105
106void 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
118void Manager::Flush() {
119 FinalizeLog();
120}
121
122void Manager::InitializeLog() {
123 current_log.clear();
124
125 LOG_INFO(Service_LM, "Initialized new log session");
126}
127
128void 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
14namespace Core {
15class Reporter;
16}
17
18namespace Service::LM {
19
20enum class DestinationFlag : u32 {
21 Default = 1,
22 UART = 2,
23 UARTSleeping = 4,
24
25 All = 0xFFFF,
26};
27
28struct 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};
57static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size");
58
59enum 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
69std::ostream& operator<<(std::ostream& os, DestinationFlag dest);
70std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity);
71std::ostream& operator<<(std::ostream& os, Field field);
72
73using FieldMap = std::map<Field, std::vector<u8>>;
74
75struct LogMessage {
76 MessageHeader header;
77 FieldMap fields;
78};
79
80std::string FormatField(Field type, const std::vector<u8>& data);
81
82class Manager {
83public:
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
94private:
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
22constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; 22constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4};
23 23
24constexpr std::size_t DefaultMiiCount{sizeof(RawData::DefaultMii) / sizeof(DefaultMii)}; 24constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()};
25 25
26constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'}; 26constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'};
27constexpr std::array<u8, 8> HairColorLookup{8, 1, 2, 3, 4, 5, 6, 7}; 27constexpr 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
143template <typename T>
144T 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
150MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { 144MiiStoreData 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
456MiiInfo MiiManager::BuildDefault(std::size_t index) { 438MiiInfo 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
461ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { 442ResultVal<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 {
27DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); 27DECLARE_ENUM_FLAG_OPERATORS(SourceFlag);
28 28
29struct MiiInfo { 29struct 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};
238static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size."); 238static_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};
246static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size."); 246static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size.");
247 247
248struct RandomMiiData2 { 248struct 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};
253static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size."); 253static_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
326private: 326private:
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
23namespace Service::Mii::RawData { 23namespace Service::Mii::RawData {
24 24
25const std::array<u8, 1728> DefaultMii{ 25const 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
135const 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
367const std::array<u8, 1200> RandomMiiFacelineColor{ 437const 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
444const std::array<u8, 3672> RandomMiiFacelineWrinkle{ 566const 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
676const std::array<u8, 3672> RandomMiiFacelineMakeup{ 605const 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
908const std::array<u8, 3672> RandomMiiHairType{ 734const 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
1140const std::array<u8, 1800> RandomMiiHairColor{ 863const 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
1255const std::array<u8, 3672> RandomMiiEyeType{ 1012const 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
1487const std::array<u8, 588> RandomMiiEyeColor{ 1069const 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
1526const std::array<u8, 3672> RandomMiiEyebrowType{ 1219const 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
1758const std::array<u8, 3672> RandomMiiNoseType{ 1237const 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
1990const std::array<u8, 3672> RandomMiiMouthType{ 1369const 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
2222const std::array<u8, 588> RandomMiiGlassType{ 1498const 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
1645const 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
11namespace Service::Mii::RawData { 12namespace Service::Mii::RawData {
12 13
13extern const std::array<u8, 1728> DefaultMii; 14extern const std::array<Service::Mii::DefaultMii, 8> DefaultMii;
14extern const std::array<u8, 3672> RandomMiiFaceline; 15extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFaceline;
15extern const std::array<u8, 1200> RandomMiiFacelineColor; 16extern const std::array<Service::Mii::RandomMiiData3, 6> RandomMiiFacelineColor;
16extern const std::array<u8, 3672> RandomMiiFacelineWrinkle; 17extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFacelineWrinkle;
17extern const std::array<u8, 3672> RandomMiiFacelineMakeup; 18extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiFacelineMakeup;
18extern const std::array<u8, 3672> RandomMiiHairType; 19extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiHairType;
19extern const std::array<u8, 1800> RandomMiiHairColor; 20extern const std::array<Service::Mii::RandomMiiData3, 9> RandomMiiHairColor;
20extern const std::array<u8, 3672> RandomMiiEyeType; 21extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiEyeType;
21extern const std::array<u8, 588> RandomMiiEyeColor; 22extern const std::array<Service::Mii::RandomMiiData2, 3> RandomMiiEyeColor;
22extern const std::array<u8, 3672> RandomMiiEyebrowType; 23extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiEyebrowType;
23extern const std::array<u8, 3672> RandomMiiNoseType; 24extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiNoseType;
24extern const std::array<u8, 3672> RandomMiiMouthType; 25extern const std::array<Service::Mii::RandomMiiData4, 18> RandomMiiMouthType;
25extern const std::array<u8, 588> RandomMiiGlassType; 26extern 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
31Module::Interface::~Interface() = default; 33Module::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
72private: 75private:
@@ -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
343const std::shared_ptr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const { 346const 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
347const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { 350const 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
12namespace Kernel {
13class KEvent;
14}
15
13namespace Service::NFP { 16namespace Service::NFP {
14 17
15class Module final { 18class 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
24struct IpAddressSetting {
25 bool is_automatic{};
26 Network::IPv4Address current_address{};
27 Network::IPv4Address subnet_mask{};
28 Network::IPv4Address gateway{};
29};
30static_assert(sizeof(IpAddressSetting) == 0xD, "IpAddressSetting has incorrect size.");
31
32struct DnsSetting {
33 bool is_automatic{};
34 Network::IPv4Address primary_dns{};
35 Network::IPv4Address secondary_dns{};
36};
37static_assert(sizeof(DnsSetting) == 0x9, "DnsSetting has incorrect size.");
38
39struct 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};
49static_assert(sizeof(ProxySetting) == 0xAA, "ProxySetting has incorrect size.");
50
51struct IpSettingData {
52 IpAddressSetting ip_address_setting{};
53 DnsSetting dns_setting{};
54 ProxySetting proxy_setting{};
55 u16 mtu{};
56};
57static_assert(sizeof(IpSettingData) == 0xC2, "IpSettingData has incorrect size.");
58
59struct 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};
67static_assert(sizeof(SfWirelessSettingData) == 0x65, "SfWirelessSettingData has incorrect size.");
68
69struct 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};
79static_assert(sizeof(NifmWirelessSettingData) == 0x70,
80 "NifmWirelessSettingData has incorrect size.");
81
82#pragma pack(push, 1)
83struct 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};
94static_assert(sizeof(SfNetworkProfileData) == 0x17C, "SfNetworkProfileData has incorrect size.");
95
96struct 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};
107static_assert(sizeof(NifmNetworkProfileData) == 0x18E,
108 "NifmNetworkProfileData has incorrect size.");
109#pragma pack(pop)
110
24class IScanRequest final : public ServiceFramework<IScanRequest> { 111class IScanRequest final : public ServiceFramework<IScanRequest> {
25public: 112public:
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
78private: 168private:
@@ -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
141class INetworkProfile final : public ServiceFramework<INetworkProfile> { 235class 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
308private: 310private:
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
65void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) { 65void 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
77void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, 82void 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(), &params, sizeof(params)); 115 std::memcpy(output.data(), &params, 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(), &params, sizeof(params)); 142 std::memcpy(output.data(), &params, 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
11namespace Kernel { 11namespace Kernel {
12class WritableEvent; 12class KWritableEvent;
13} 13}
14 14
15namespace Service::Nvidia { 15namespace 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
174std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { 176std::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
178std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { 180std::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 {
17class System; 17class System;
18} 18}
19 19
20namespace Kernel {
21class KEvent;
22}
23
20namespace Service::NVFlinger { 24namespace Service::NVFlinger {
21class NVFlinger; 25class NVFlinger;
22} 26}
@@ -31,7 +35,7 @@ class nvdevice;
31 35
32/// Represents an Nvidia event 36/// Represents an Nvidia event
33struct NvEvent { 37struct 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
139private: 143private:
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
15namespace Service::NVFlinger { 15namespace Service::NVFlinger {
16 16
17BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id) 17BufferQueue::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
22BufferQueue::~BufferQueue() = default; 23BufferQueue::~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
47std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, 48std::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
125std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { 126std::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
160void BufferQueue::Connect() { 161void 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
191std::shared_ptr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { 192std::shared_ptr<Kernel::KWritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
192 return buffer_wait_event.writable; 193 return buffer_wait_event->GetWritableEvent();
193} 194}
194 195
195std::shared_ptr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const { 196std::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
20namespace Kernel { 19namespace Kernel {
21class KernelCore; 20class KernelCore;
22} 21class KEvent;
22class KReadableEvent;
23class KWritableEvent;
24} // namespace Kernel
23 25
24namespace Service::NVFlinger { 26namespace 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
120private: 122private:
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
168std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { 168std::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
28namespace Kernel { 28namespace Kernel {
29class ReadableEvent; 29class KReadableEvent;
30class WritableEvent; 30class KWritableEvent;
31} // namespace Kernel 31} // namespace Kernel
32 32
33namespace Service::Nvidia { 33namespace 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
136void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { 180void 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
152Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name) 196Module::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
155Module::Interface::~Interface() = default; 200Module::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
13namespace Service::PSM { 18namespace Service::PSM {
14 19
20class IPsmSession final : public ServiceFramework<IPsmSession> {
21public:
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
60private:
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
15class PSM final : public ServiceFramework<PSM> { 120class PSM final : public ServiceFramework<PSM> {
16public: 121public:
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
258void 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
258void BSD::Listen(Kernel::HLERequestContext& ctx) { 277void 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
423void 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
404template <typename Work> 433template <typename Work>
405void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, Work work) { 434void 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 {
73static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); 73static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size");
74 74
75struct ClockSnapshot { 75struct 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
24ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, 26ResultCode 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 {
12class System; 11class System;
13} 12}
14 13
14namespace Kernel {
15class KEvent;
16}
17
15namespace Service::Time::Clock { 18namespace Service::Time::Clock {
16 19
17class StandardLocalSystemClockCore; 20class 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
23void SystemClockContextUpdateCallback::RegisterOperationEvent( 23void 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
11namespace Kernel { 11namespace Kernel {
12class WritableEvent; 12class KWritableEvent;
13} 13}
14 14
15namespace Service::Time::Clock { 15namespace 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
38private: 38private:
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
123ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal( 123ResultCode 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
13namespace Service::Time { 13namespace 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
47struct CalendarAdditionalInfo { 47struct 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};
54static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size"); 54static_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
57struct CalendarTime { 57struct 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};
66static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size"); 66static_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
18Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} { 20Display::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
24Display::~Display() = default; 26Display::~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
34std::shared_ptr<Kernel::ReadableEvent> Display::GetVSyncEvent() const { 36std::shared_ptr<Kernel::KReadableEvent> Display::GetVSyncEvent() const {
35 return vsync_event.readable; 37 return vsync_event->GetReadableEvent();
36} 38}
37 39
38void Display::SignalVSyncEvent() { 40void Display::SignalVSyncEvent() {
39 vsync_event.writable->Signal(); 41 vsync_event->GetWritableEvent()->Signal();
40} 42}
41 43
42void Display::CreateLayer(u64 id, NVFlinger::BufferQueue& buffer_queue) { 44void 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
13namespace Kernel {
14class KEvent;
15}
13 16
14namespace Service::NVFlinger { 17namespace Service::NVFlinger {
15class BufferQueue; 18class 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
226ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { 226ResultStatus 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
186ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) { 186ResultStatus 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
363void 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
412void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, 362void 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
166std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { 174std::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
109private: 119private:
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
42private: 43private:
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
137Client::Client() { 137Client::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
219void Client::OnVersion([[maybe_unused]] Response::Version data) { 220void 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
322void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 304void 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
329std::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
341void 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
351void Client::BeginConfiguration() { 373void 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
361DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { 383DeviceStatus& 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
369const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { 391const 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
399Input::TouchStatus& Client::GetTouchState() {
400 return touch_status;
401}
402
403const Input::TouchStatus& Client::GetTouchState() const {
404 return touch_status;
405}
406
377Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { 407Common::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;
28namespace Response { 28namespace Response {
29struct PadData; 29struct PadData;
30struct PortInfo; 30struct PortInfo;
31struct TouchPad;
31struct Version; 32struct 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
96private: 99private:
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
140static_assert(std::is_trivially_copyable_v<PortInfo>, 140static_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
143struct TouchPad {
144 u8 is_active{};
145 u8 id{};
146 u16_le x{};
147 u16_le y{};
148};
149static_assert(sizeof(TouchPad) == 6, "UDP Response TouchPad struct has wrong size ");
150
143#pragma pack(push, 1) 151#pragma pack(push, 1)
144struct PadData { 152struct 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
223static_assert(sizeof(PadData::AnalogButton) == 12, 226static_assert(sizeof(PadData::AnalogButton) == 12,
224 "UDP Response AnalogButton struct has wrong size "); 227 "UDP Response AnalogButton struct has wrong size ");
225static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size ");
226static_assert(sizeof(PadData::Accelerometer) == 12, 228static_assert(sizeof(PadData::Accelerometer) == 12,
227 "UDP Response Accelerometer struct has wrong size "); 229 "UDP Response Accelerometer struct has wrong size ");
228static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); 230static_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
85private: 85private:
@@ -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
110void UDPTouchFactory::BeginConfiguration() {
111 polling = true;
112 client->BeginConfiguration();
113}
114
115void UDPTouchFactory::EndConfiguration() {
116 polling = false;
117 client->EndConfiguration();
118}
119
120Common::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 @@
14namespace Common { 14namespace Common {
15 15
16TEST_CASE("RingBuffer: Basic Tests", "[common]") { 16TEST_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
79TEST_CASE("RingBuffer: Threaded Test", "[common]") { 79TEST_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
289if (ENABLE_NSIGHT_AFTERMATH) 287if (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
594void Maxwell3D::StartCBData(u32 method) { 594void 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
20find_program(GLSLANGVALIDATOR "glslangValidator" REQUIRED) 20find_program(GLSLANGVALIDATOR "glslangValidator" REQUIRED)
21 21
22set(GLSL_FLAGS "") 22set(GLSL_FLAGS "")
23set(QUIET_FLAG "--quiet")
23 24
24set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include) 25set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include)
25set(SHADER_DIR ${SHADER_INCLUDE}/video_core/host_shaders) 26set(SHADER_DIR ${SHADER_INCLUDE}/video_core/host_shaders)
@@ -28,6 +29,23 @@ set(HOST_SHADERS_INCLUDE ${SHADER_INCLUDE} PARENT_SCOPE)
28set(INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/source_shader.h.in) 29set(INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/source_shader.h.in)
29set(HEADER_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/StringShaderHeader.cmake) 30set(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
34execute_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
44if (NOT GLSLANG_ERROR STREQUAL "")
45 message(WARNING "Refusing to use unavailable flag `${QUIET_FLAG}` on `${GLSLANGVALIDATOR}`")
46 set(QUIET_FLAG "")
47endif()
48
31foreach(FILENAME IN ITEMS ${SHADER_FILES}) 49foreach(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
40GPUVAddr MemoryManager::Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size) { 41GPUVAddr 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
54void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) { 61void 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
234size_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
221void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const { 240void 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
336void 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
317void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size) { 351void 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
323void 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
330bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { 361bool 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
123private: 127private:
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
160ProgramSharedPtr BuildShader(const Device& device, ShaderType shader_type, u64 unique_identifier, 160ProgramSharedPtr 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
112namespace { 112namespace {
113 113constexpr u32 Attachable = 1 << 0;
114enum : u32 { Attachable = 1, Storage = 2 }; 114constexpr u32 Storage = 1 << 1;
115 115
116struct FormatTuple { 116struct 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
225FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format) { 225FormatInfo 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
674VkCullModeFlags CullFace(Maxwell::CullFace cull_face) { 679VkCullModeFlagBits 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
38FormatInfo 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
40VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage); 48VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage);
41 49
@@ -55,7 +63,7 @@ VkBlendFactor BlendFactor(Maxwell::Blend::Factor factor);
55 63
56VkFrontFace FrontFace(Maxwell::FrontFace front_face); 64VkFrontFace FrontFace(Maxwell::FrontFace front_face);
57 65
58VkCullModeFlags CullFace(Maxwell::CullFace cull_face); 66VkCullModeFlagBits CullFace(Maxwell::CullFace cull_face);
59 67
60VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle); 68VkComponentSwizzle 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
681std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets(const ImageInfo& info) noexcept { 681std::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
1196using P = PixelFormat; 1196static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0}, 0) ==
1197 1197 0x7f8000);
1198static_assert(CalculateLevelSize(LevelInfo{{1920, 1080}, {0, 2, 0}, {1, 1}, 2, 0}, 0) == 0x7f8000); 1198static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x4000);
1199static_assert(CalculateLevelSize(LevelInfo{{32, 32}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x4000); 1199
1200 1200static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 1, 0, 7) ==
1201static_assert(CalculateLevelOffset(P::R8_SINT, {1920, 1080}, {0, 2}, 1, 0, 7) == 0x2afc00); 1201 0x2afc00);
1202static_assert(CalculateLevelOffset(P::ASTC_2D_12X12_UNORM, {8192, 4096}, {0, 2}, 1, 0, 12) == 1202static_assert(CalculateLevelOffset(PixelFormat::ASTC_2D_12X12_UNORM, {8192, 4096, 1}, {0, 2, 0}, 1,
1203 0x50d200); 1203 0, 12) == 0x50d200);
1204 1204
1205static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 0) == 0); 1205static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1206static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 1) == 0x400000); 1206 0) == 0);
1207static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 2) == 0x500000); 1207static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1208static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 3) == 0x540000); 1208 1) == 0x400000);
1209static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 4) == 0x550000); 1209static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1210static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 5) == 0x554000); 1210 2) == 0x500000);
1211static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 6) == 0x555000); 1211static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1212static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 7) == 0x555400); 1212 3) == 0x540000);
1213static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 8) == 0x555600); 1213static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1214static_assert(CalculateLevelOffset(P::A8B8G8R8_UNORM, {1024, 1024}, {0, 4}, 1, 0, 9) == 0x555800); 1214 4) == 0x550000);
1215static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1216 5) == 0x554000);
1217static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1218 6) == 0x555000);
1219static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1220 7) == 0x555400);
1221static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1222 8) == 0x555600);
1223static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
1224 9) == 0x555800);
1215 1225
1216constexpr u32 ValidateLayerSize(PixelFormat format, u32 width, u32 height, u32 block_height, 1226constexpr 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
1224static_assert(ValidateLayerSize(P::ASTC_2D_12X12_UNORM, 8192, 4096, 2, 0, 12) == 0x50d800); 1234static_assert(ValidateLayerSize(PixelFormat::ASTC_2D_12X12_UNORM, 8192, 4096, 2, 0, 12) ==
1225static_assert(ValidateLayerSize(P::A8B8G8R8_UNORM, 1024, 1024, 2, 0, 10) == 0x556000); 1235 0x50d800);
1226static_assert(ValidateLayerSize(P::BC3_UNORM, 128, 128, 2, 0, 8) == 0x6000); 1236static_assert(ValidateLayerSize(PixelFormat::A8B8G8R8_UNORM, 1024, 1024, 2, 0, 10) == 0x556000);
1237static_assert(ValidateLayerSize(PixelFormat::BC3_UNORM, 128, 128, 2, 0, 8) == 0x6000);
1227 1238
1228static_assert(ValidateLayerSize(P::A8B8G8R8_UNORM, 518, 572, 4, 3, 1) == 0x190000, 1239static_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");
1230static_assert(ValidateLayerSize(P::BC5_UNORM, 1024, 1024, 3, 4, 11) == 0x160000, 1241static_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
31namespace Vulkan { 22namespace 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
23namespace Vulkan { 21namespace Vulkan {
24 22
25class NsightAftermathTracker { 23class 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
7namespace Vulkan { 9namespace 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
102std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::PhysicalDevice physical) { 87std::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
430void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { 430void 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
436void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { 439void 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; 455void 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); 464bool 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
454void GRenderWindow::TouchEndEvent() { 476bool 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
487bool 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
458bool GRenderWindow::event(QEvent* event) { 494bool 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() {
641QStringList GRenderWindow::GetUnsupportedGLExtensions() const { 677QStringList 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 @@
21class GRenderWindow; 22class GRenderWindow;
22class GMainWindow; 23class GMainWindow;
23class QKeyEvent; 24class QKeyEvent;
24class QTouchEvent;
25class QStringList; 25class QStringList;
26 26
27namespace InputCommon { 27namespace 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
218protected: 224protected:
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() {
464void Config::ReadTouchscreenValues() { 464void 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
558ConfigureInputPlayer::~ConfigureInputPlayer() = default; 568ConfigureInputPlayer::~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
1000void ConfigureInputPlayer::UpdateControllerAvailableButtons() { 1009void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
@@ -1131,7 +1140,8 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
1131} 1140}
1132 1141
1133void ConfigureInputPlayer::HandleClick( 1142void 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
11PlayerControlPreview::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
20PlayerControlPreview::~PlayerControlPreview() = default;
21
22void 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}
40void 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
52PlayerControlPreview::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
80void 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
89void PlayerControlPreview::SetControllerType(const Settings::ControllerType type) {
90 controller_type = type;
91 UpdateColors();
92}
93
94void PlayerControlPreview::BeginMappingButton(std::size_t index) {
95 button_mapping_index = index;
96 mapping_active = true;
97}
98
99void 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
105void 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
112void 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
158void 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
210void 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
236void 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
348void 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
468void 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
599void 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
695void 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
783void 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
840constexpr 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};
845constexpr 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
872constexpr 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
878constexpr 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
884constexpr 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
888constexpr 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
907constexpr 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
913constexpr 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};
927constexpr 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
950constexpr 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
983constexpr 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
991constexpr 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
996constexpr 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
1001constexpr std::array<float, 3 * 2> up_arrow_symbol = {
1002 0.0f, -3.0f, -3.0f, 2.0f, 3.0f, 2.0f,
1003};
1004
1005constexpr 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
1011constexpr 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
1025constexpr 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
1036constexpr 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
1042constexpr 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
1074constexpr 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
1126constexpr 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
1174constexpr 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
1199constexpr 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
1213constexpr 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
1226constexpr 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
1239constexpr 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
1252constexpr 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
1272constexpr 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
1292constexpr 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
1309constexpr 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
1320constexpr 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
1335constexpr 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
1347constexpr 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
1364constexpr 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
1375constexpr 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
1388constexpr 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
1398constexpr 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
1410constexpr 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
1425constexpr 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
1441constexpr 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
1453void 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
1490void 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
1541void 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
1620void 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
1709void 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
1805void 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
1901void 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
1936void 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
1970void 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
1994void 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
2019void 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
2052void 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
2086void 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
2102void 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
2120void 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
2139void 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
2158void 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
2175void 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
2195void 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
2214void 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
2233void 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
2252void 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
2276void 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
2287void 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
2301void 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
2326void 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}
2351void 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}
2357void 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
2374void 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
2386void 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
2398void 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
2411void 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
2420void 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
2443void 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
2500void 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
2528void 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
2630void 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
2661template <size_t N>
2662void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) {
2663 p.drawPolygon(polygon.data(), static_cast<int>(polygon.size()));
2664}
2665
2666void PlayerControlPreview::DrawCircle(QPainter& p, const QPointF center, float size) {
2667 p.drawEllipse(center, size, size);
2668}
2669
2670void 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}
2675void 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
2681void 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
2689void 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
13class QLabel;
14
15using AnalogParam = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
16using ButtonParam = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
17
18// Widget for representing controller animations
19class PlayerControlPreview : public QFrame {
20 Q_OBJECT
21
22public:
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
37protected:
38 void paintEvent(QPaintEvent* event) override;
39
40private:
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
84constexpr 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
89ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, 84ConfigureMotionTouch::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;
112void ConfigureMotionTouch::SetConfiguration() { 104void 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
150void ConfigureMotionTouch::UpdateUiDisplay() { 139void 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
172void ConfigureMotionTouch::ConnectEvents() { 154void 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
42QString GetAccountUsername(const Service::Account::ProfileManager& manager, Common::UUID uuid) { 42QString 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
123ConfigureProfileManager::~ConfigureProfileManager() = default; 123ConfigureProfileManager::~ConfigureProfileManager() = default;
@@ -147,7 +147,7 @@ void ConfigureProfileManager::SetConfiguration() {
147void ConfigureProfileManager::PopulateUserList() { 147void 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
12namespace { 13namespace {
13QString FormatEventStatusString(const Service::BCAT::EventStatus& status) { 14QString 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
36ConfigureService::ConfigureService(QWidget* parent) 38ConfigureService::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
35void ConfigureTouchscreenAdvanced::ApplyConfiguration() { 35void 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
42void ConfigureTouchscreenAdvanced::LoadConfiguration() { 41void 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
49void ConfigureTouchscreenAdvanced::RestoreDefaults() { 47void 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
12ControllerDialog::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
35void 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
43QAction* 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
54void ControllerDialog::showEvent(QShowEvent* ev) {
55 if (toggle_view_action) {
56 toggle_view_action->setChecked(isVisible());
57 }
58 QWidget::showEvent(ev);
59}
60
61void 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
9class QAction;
10class QHideEvent;
11class QShowEvent;
12class PlayerControlPreview;
13
14class ControllerDialog : public QWidget {
15 Q_OBJECT
16
17public:
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
24protected:
25 void showEvent(QShowEvent* ev) override;
26 void hideEvent(QHideEvent* ev) override;
27
28private:
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
24namespace { 25namespace {
@@ -90,9 +91,9 @@ std::size_t WaitTreeItem::Row() const {
90std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { 91std::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
123WaitTreeMutexInfo::~WaitTreeMutexInfo() = default; 124WaitTreeMutexInfo::~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
142WaitTreeCallstack::WaitTreeCallstack(const Kernel::Thread& thread) : thread(thread) {} 143WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread) : thread(thread) {}
143WaitTreeCallstack::~WaitTreeCallstack() = default; 144WaitTreeCallstack::~WaitTreeCallstack() = default;
144 145
145QString WaitTreeCallstack::GetText() const { 146QString WaitTreeCallstack::GetText() const {
@@ -149,7 +150,7 @@ QString WaitTreeCallstack::GetText() const {
149std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { 150std::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
234WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread) 235WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread)
235 : WaitTreeSynchronizationObject(thread) {} 236 : WaitTreeSynchronizationObject(thread) {}
236WaitTreeThread::~WaitTreeThread() = default; 237WaitTreeThread::~WaitTreeThread() = default;
237 238
238QString WaitTreeThread::GetText() const { 239QString 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 {
297QColor WaitTreeThread::GetColor() const { 294QColor 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 {
336std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { 329std::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
389WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) 376WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object)
390 : WaitTreeSynchronizationObject(object) {} 377 : WaitTreeSynchronizationObject(object) {}
391WaitTreeEvent::~WaitTreeEvent() = default; 378WaitTreeEvent::~WaitTreeEvent() = default;
392 379
393WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::Thread*>& list) 380WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::KThread*>& list)
394 : thread_list(list) {} 381 : thread_list(list) {}
395WaitTreeThreadList::~WaitTreeThreadList() = default; 382WaitTreeThreadList::~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
19namespace Kernel { 19namespace Kernel {
20class HandleTable; 20class HandleTable;
21class KReadableEvent;
21class KSynchronizationObject; 22class KSynchronizationObject;
22class ReadableEvent; 23class KThread;
23class Thread;
24} // namespace Kernel 24} // namespace Kernel
25 25
26class WaitTreeThread; 26class 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
89class WaitTreeCallstack : public WaitTreeExpandableItem { 89class WaitTreeCallstack : public WaitTreeExpandableItem {
90 Q_OBJECT 90 Q_OBJECT
91public: 91public:
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
98private: 98private:
99 const Kernel::Thread& thread; 99 const Kernel::KThread& thread;
100}; 100};
101 101
102class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { 102class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
@@ -131,7 +131,7 @@ private:
131class WaitTreeThread : public WaitTreeSynchronizationObject { 131class WaitTreeThread : public WaitTreeSynchronizationObject {
132 Q_OBJECT 132 Q_OBJECT
133public: 133public:
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:
142class WaitTreeEvent : public WaitTreeSynchronizationObject { 142class WaitTreeEvent : public WaitTreeSynchronizationObject {
143 Q_OBJECT 143 Q_OBJECT
144public: 144public:
145 explicit WaitTreeEvent(const Kernel::ReadableEvent& object); 145 explicit WaitTreeEvent(const Kernel::KReadableEvent& object);
146 ~WaitTreeEvent() override; 146 ~WaitTreeEvent() override;
147}; 147};
148 148
149class WaitTreeThreadList : public WaitTreeExpandableItem { 149class WaitTreeThreadList : public WaitTreeExpandableItem {
150 Q_OBJECT 150 Q_OBJECT
151public: 151public:
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
158private: 158private:
159 const std::vector<Kernel::Thread*>& thread_list; 159 const std::vector<Kernel::KThread*>& thread_list;
160}; 160};
161 161
162class WaitTreeModel : public QAbstractItemModel { 162class 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
372void GameList::AddEntry(const QList<QStandardItem*>& entry_items, GameListDir* parent) { 372void 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
550void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) { 550void 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
570void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { 570void 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
613void GameList::LoadCompatibilityList() { 617void 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;
27class LoadingScreen; 27class LoadingScreen;
28class MicroProfileDialog; 28class MicroProfileDialog;
29class ProfilerWidget; 29class ProfilerWidget;
30class ControllerDialog;
30class QLabel; 31class QLabel;
31class QPushButton; 32class QPushButton;
32class QProgressDialog; 33class 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
31void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { 31void 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
36void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { 36void 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
72void EmuWindow_SDL2::OnFingerMotion(float x, float y) { 72void 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
77void EmuWindow_SDL2::OnFingerUp() { 77void EmuWindow_SDL2::OnFingerUp() {
78 TouchReleased(); 78 TouchReleased(0);
79} 79}
80 80
81void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { 81void 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:
59bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { 59bool 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() {
89EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) 77EmuWindow_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;