summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_out.cpp2
-rw-r--r--src/audio_core/audio_renderer.cpp2
-rw-r--r--src/audio_core/cubeb_sink.cpp2
-rw-r--r--src/audio_core/stream.cpp2
-rw-r--r--src/common/CMakeLists.txt6
-rw-r--r--src/common/assert.cpp14
-rw-r--r--src/common/assert.h14
-rw-r--r--src/common/common_sizes.h43
-rw-r--r--src/common/logging/backend.cpp28
-rw-r--r--src/common/logging/backend.h4
-rw-r--r--src/common/logging/filter.cpp4
-rw-r--r--src/common/logging/filter.h4
-rw-r--r--src/common/logging/log.h35
-rw-r--r--src/common/logging/text_formatter.cpp4
-rw-r--r--src/common/logging/text_formatter.h4
-rw-r--r--src/common/nvidia_flags.h2
-rw-r--r--src/common/settings.cpp (renamed from src/core/settings.cpp)15
-rw-r--r--src/common/settings.h (renamed from src/core/settings.h)17
-rw-r--r--src/common/settings_input.cpp (renamed from src/input_common/settings.cpp)2
-rw-r--r--src/common/settings_input.h (renamed from src/input_common/settings.h)1
-rw-r--r--src/common/threadsafe_queue.h10
-rw-r--r--src/core/CMakeLists.txt14
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp37
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp44
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h5
-rw-r--r--src/core/core.cpp13
-rw-r--r--src/core/core.h3
-rw-r--r--src/core/crypto/key_manager.cpp2
-rw-r--r--src/core/file_sys/control_metadata.cpp8
-rw-r--r--src/core/file_sys/control_metadata.h2
-rw-r--r--src/core/file_sys/patch_manager.cpp2
-rw-r--r--src/core/frontend/applets/profile_select.cpp2
-rw-r--r--src/core/frontend/applets/software_keyboard.cpp148
-rw-r--r--src/core/frontend/applets/software_keyboard.h118
-rw-r--r--src/core/frontend/emu_window.cpp2
-rw-r--r--src/core/frontend/framebuffer_layout.cpp2
-rw-r--r--src/core/frontend/input_interpreter.cpp15
-rw-r--r--src/core/frontend/input_interpreter.h3
-rw-r--r--src/core/hle/kernel/arch/arm64/k_memory_region_device_types.inc20
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc52
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp164
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.h28
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/secure_monitor.h26
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp8
-rw-r--r--src/core/hle/kernel/hle_ipc.h10
-rw-r--r--src/core/hle/kernel/k_address_space_info.cpp43
-rw-r--r--src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp199
-rw-r--r--src/core/hle/kernel/k_memory_layout.cpp166
-rw-r--r--src/core/hle/kernel/k_memory_layout.h397
-rw-r--r--src/core/hle/kernel/k_memory_manager.cpp12
-rw-r--r--src/core/hle/kernel/k_memory_manager.h18
-rw-r--r--src/core/hle/kernel/k_memory_region.h350
-rw-r--r--src/core/hle/kernel/k_memory_region_type.h338
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp13
-rw-r--r--src/core/hle/kernel/k_resource_limit.h12
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp22
-rw-r--r--src/core/hle/kernel/k_scheduler.h11
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h11
-rw-r--r--src/core/hle/kernel/k_scoped_lock.h13
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h4
-rw-r--r--src/core/hle/kernel/k_spin_lock.h6
-rw-r--r--src/core/hle/kernel/k_system_control.cpp42
-rw-r--r--src/core/hle/kernel/k_system_control.h18
-rw-r--r--src/core/hle/kernel/k_thread.h6
-rw-r--r--src/core/hle/kernel/k_trace.h12
-rw-r--r--src/core/hle/kernel/kernel.cpp362
-rw-r--r--src/core/hle/kernel/kernel.h2
-rw-r--r--src/core/hle/kernel/process.cpp26
-rw-r--r--src/core/hle/kernel/process_capability.cpp5
-rw-r--r--src/core/hle/kernel/process_capability.h2
-rw-r--r--src/core/hle/kernel/svc.cpp134
-rw-r--r--src/core/hle/service/acc/acc.cpp17
-rw-r--r--src/core/hle/service/acc/acc_su.cpp36
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp28
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp118
-rw-r--r--src/core/hle/service/am/am.h2
-rw-r--r--src/core/hle/service/am/applets/applets.cpp18
-rw-r--r--src/core/hle/service/am/applets/applets.h10
-rw-r--r--src/core/hle/service/am/applets/controller.cpp5
-rw-r--r--src/core/hle/service/am/applets/controller.h4
-rw-r--r--src/core/hle/service/am/applets/error.cpp5
-rw-r--r--src/core/hle/service/am/applets/error.h4
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp14
-rw-r--r--src/core/hle/service/am/applets/general_backend.h11
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp4
-rw-r--r--src/core/hle/service/am/applets/profile_select.h3
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp1153
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h187
-rw-r--r--src/core/hle/service/am/applets/software_keyboard_types.h295
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp5
-rw-r--r--src/core/hle/service/am/applets/web_browser.h4
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp4
-rw-r--r--src/core/hle/service/apm/controller.cpp2
-rw-r--r--src/core/hle/service/audio/audin_a.cpp8
-rw-r--r--src/core/hle/service/audio/audin_u.cpp14
-rw-r--r--src/core/hle/service/audio/audout_a.cpp12
-rw-r--r--src/core/hle/service/audio/audout_u.cpp6
-rw-r--r--src/core/hle/service/audio/audrec_a.cpp4
-rw-r--r--src/core/hle/service/audio/audrec_u.cpp7
-rw-r--r--src/core/hle/service/audio/audren_a.cpp12
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/audren_u.h2
-rw-r--r--src/core/hle/service/audio/codecctl.cpp26
-rw-r--r--src/core/hle/service/audio/hwopus.cpp4
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp2
-rw-r--r--src/core/hle/service/bcat/module.cpp4
-rw-r--r--src/core/hle/service/bpc/bpc.cpp4
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp19
-rw-r--r--src/core/hle/service/btm/btm.cpp1
-rw-r--r--src/core/hle/service/caps/caps_a.cpp1
-rw-r--r--src/core/hle/service/caps/caps_u.cpp1
-rw-r--r--src/core/hle/service/erpt/erpt.cpp7
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp19
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h2
-rw-r--r--src/core/hle/service/friend/friend.cpp14
-rw-r--r--src/core/hle/service/glue/arp.cpp11
-rw-r--r--src/core/hle/service/glue/arp.h2
-rw-r--r--src/core/hle/service/glue/bgtc.cpp27
-rw-r--r--src/core/hle/service/glue/bgtc.h8
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h2
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp14
-rw-r--r--src/core/hle/service/hid/controllers/npad.h4
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp108
-rw-r--r--src/core/hle/service/hid/hid.h1
-rw-r--r--src/core/hle/service/hid/xcd.cpp2
-rw-r--r--src/core/hle/service/ldr/ldr.cpp32
-rw-r--r--src/core/hle/service/nfc/nfc.cpp2
-rw-r--r--src/core/hle/service/nifm/nifm.cpp2
-rw-r--r--src/core/hle/service/nim/nim.cpp99
-rw-r--r--src/core/hle/service/npns/npns.cpp3
-rw-r--r--src/core/hle/service/ns/ns.cpp43
-rw-r--r--src/core/hle/service/ns/pl_u.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp17
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp2
-rw-r--r--src/core/hle/service/olsc/olsc.cpp1
-rw-r--r--src/core/hle/service/pcie/pcie.cpp2
-rw-r--r--src/core/hle/service/pctl/module.cpp251
-rw-r--r--src/core/hle/service/pctl/module.h19
-rw-r--r--src/core/hle/service/pctl/pctl.cpp5
-rw-r--r--src/core/hle/service/pctl/pctl.h3
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/set/set.cpp2
-rw-r--r--src/core/hle/service/set/set_sys.cpp6
-rw-r--r--src/core/hle/service/sm/sm.cpp9
-rw-r--r--src/core/hle/service/sockets/ethc.cpp1
-rw-r--r--src/core/hle/service/sockets/nsd.cpp1
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp4
-rw-r--r--src/core/hle/service/spl/module.cpp2
-rw-r--r--src/core/hle/service/spl/spl.cpp3
-rw-r--r--src/core/hle/service/time/clock_types.h8
-rw-r--r--src/core/hle/service/time/time.cpp48
-rw-r--r--src/core/hle/service/time/time.h2
-rw-r--r--src/core/hle/service/time/time_manager.cpp8
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp2
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp2
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp1
-rw-r--r--src/core/hle/service/time/time_zone_types.h4
-rw-r--r--src/core/hle/service/usb/usb.cpp42
-rw-r--r--src/core/hle/service/vi/vi.cpp10
-rw-r--r--src/core/hle/service/wlan/wlan.cpp7
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/loader/nso.cpp2
-rw-r--r--src/core/perf_stats.cpp2
-rw-r--r--src/core/reporter.cpp2
-rw-r--r--src/core/telemetry_session.cpp2
-rw-r--r--src/input_common/CMakeLists.txt2
-rwxr-xr-xsrc/input_common/analog_from_button.cpp2
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp2
-rw-r--r--src/input_common/mouse/mouse_input.cpp2
-rw-r--r--src/input_common/mouse/mouse_poller.cpp2
-rw-r--r--src/input_common/sdl/sdl_impl.cpp28
-rw-r--r--src/input_common/sdl/sdl_impl.h4
-rw-r--r--src/input_common/touch_from_button.cpp2
-rw-r--r--src/input_common/udp/client.cpp149
-rw-r--r--src/input_common/udp/client.h44
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h2
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp16
-rw-r--r--src/video_core/engines/engine_interface.h3
-rw-r--r--src/video_core/engines/fermi_2d.h2
-rw-r--r--src/video_core/engines/kepler_memory.h2
-rw-r--r--src/video_core/engines/maxwell_dma.cpp2
-rw-r--r--src/video_core/engines/maxwell_dma.h2
-rw-r--r--src/video_core/gpu.cpp6
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/gpu_thread.cpp64
-rw-r--r--src/video_core/gpu_thread.h15
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt1
-rw-r--r--src/video_core/host_shaders/StringShaderHeader.cmake22
-rw-r--r--src/video_core/host_shaders/astc_decoder.comp1339
-rw-r--r--src/video_core/host_shaders/source_shader.h.in4
-rw-r--r--src/video_core/macro/macro.cpp2
-rw-r--r--src/video_core/query_cache.h11
-rw-r--r--src/video_core/renderer_base.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/video_core/renderer_opengl/util_shaders.cpp76
-rw-r--r--src/video_core/renderer_opengl/util_shaders.h5
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp2
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp333
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h32
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp60
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h19
-rw-r--r--src/video_core/texture_cache/accelerated_swizzle.h4
-rw-r--r--src/video_core/texture_cache/image_view_base.cpp2
-rw-r--r--src/video_core/texture_cache/util.cpp35
-rw-r--r--src/video_core/texture_cache/util.h5
-rw-r--r--src/video_core/textures/astc.cpp1710
-rw-r--r--src/video_core/textures/astc.h124
-rw-r--r--src/video_core/textures/decoders.cpp23
-rw-r--r--src/video_core/textures/decoders.h18
-rw-r--r--src/video_core/textures/texture.cpp2
-rw-r--r--src/video_core/video_core.cpp2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp13
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp8
-rw-r--r--src/yuzu/CMakeLists.txt4
-rw-r--r--src/yuzu/applets/controller.cpp16
-rw-r--r--src/yuzu/applets/controller.h3
-rw-r--r--src/yuzu/applets/error.cpp22
-rw-r--r--src/yuzu/applets/error.h2
-rw-r--r--src/yuzu/applets/software_keyboard.cpp1712
-rw-r--r--src/yuzu/applets/software_keyboard.h283
-rw-r--r--src/yuzu/applets/software_keyboard.ui3503
-rw-r--r--src/yuzu/bootmanager.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp20
-rw-r--r--src/yuzu/configuration/config.h4
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp2
-rw-r--r--src/yuzu/configuration/configuration_shared.h2
-rw-r--r--src/yuzu/configuration/configure_audio.cpp2
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp2
-rw-r--r--src/yuzu/configuration/configure_cpu.h2
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.h2
-rw-r--r--src/yuzu/configuration/configure_debug.cpp10
-rw-r--r--src/yuzu/configuration/configure_debug.ui29
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp4
-rw-r--r--src/yuzu/configuration/configure_filesystem.cpp2
-rw-r--r--src/yuzu/configuration/configure_general.cpp2
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp23
-rw-r--r--src/yuzu/configuration/configure_graphics.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.ui41
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp2
-rw-r--r--src/yuzu/configuration/configure_hotkeys.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_player.h2
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h2
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp11
-rw-r--r--src/yuzu/configuration/configure_motion_touch.h3
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp2
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp4
-rw-r--r--src/yuzu/configuration/configure_service.cpp2
-rw-r--r--src/yuzu/configuration/configure_system.cpp4
-rw-r--r--src/yuzu/configuration/configure_touch_from_button.cpp2
-rw-r--r--src/yuzu/configuration/configure_ui.cpp4
-rw-r--r--src/yuzu/configuration/configure_vibration.cpp2
-rw-r--r--src/yuzu/configuration/configure_web.cpp2
-rw-r--r--src/yuzu/debugger/console.cpp8
-rw-r--r--src/yuzu/debugger/controller.cpp2
-rw-r--r--src/yuzu/main.cpp285
-rw-r--r--src/yuzu/main.h35
-rw-r--r--src/yuzu/util/overlay_dialog.cpp249
-rw-r--r--src/yuzu/util/overlay_dialog.h107
-rw-r--r--src/yuzu/util/overlay_dialog.ui404
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/default_ini.h6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp2
-rw-r--r--src/yuzu_cmd/yuzu.cpp10
290 files changed, 14086 insertions, 3182 deletions
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp
index fe3a898ad..20a756dce 100644
--- a/src/audio_core/audio_out.cpp
+++ b/src/audio_core/audio_out.cpp
@@ -7,7 +7,7 @@
7#include "audio_core/sink_details.h" 7#include "audio_core/sink_details.h"
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/settings.h" 10#include "common/settings.h"
11 11
12namespace AudioCore { 12namespace AudioCore {
13 13
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index d2ce8c814..ae2201c36 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -11,8 +11,8 @@
11#include "audio_core/info_updater.h" 11#include "audio_core/info_updater.h"
12#include "audio_core/voice_context.h" 12#include "audio_core/voice_context.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/settings.h"
14#include "core/memory.h" 15#include "core/memory.h"
15#include "core/settings.h"
16 16
17namespace { 17namespace {
18[[nodiscard]] static constexpr s16 ClampToS16(s32 value) { 18[[nodiscard]] static constexpr s16 ClampToS16(s32 value) {
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 043447eaa..93c35e785 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -11,7 +11,7 @@
11#include "common/assert.h" 11#include "common/assert.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/ring_buffer.h" 13#include "common/ring_buffer.h"
14#include "core/settings.h" 14#include "common/settings.h"
15 15
16#ifdef _WIN32 16#ifdef _WIN32
17#include <objbase.h> 17#include <objbase.h>
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index b0f6f0c34..ad6c587c2 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -11,8 +11,8 @@
11#include "audio_core/stream.h" 11#include "audio_core/stream.h"
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/settings.h"
14#include "core/core_timing.h" 15#include "core/core_timing.h"
15#include "core/settings.h"
16 16
17namespace AudioCore { 17namespace AudioCore {
18 18
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 788516ded..88644eeb6 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -97,6 +97,7 @@ add_custom_command(OUTPUT scm_rev.cpp
97add_library(common STATIC 97add_library(common STATIC
98 algorithm.h 98 algorithm.h
99 alignment.h 99 alignment.h
100 assert.cpp
100 assert.h 101 assert.h
101 atomic_ops.h 102 atomic_ops.h
102 detached_tasks.cpp 103 detached_tasks.cpp
@@ -109,6 +110,7 @@ add_library(common STATIC
109 cityhash.h 110 cityhash.h
110 common_funcs.h 111 common_funcs.h
111 common_paths.h 112 common_paths.h
113 common_sizes.h
112 common_types.h 114 common_types.h
113 concepts.h 115 concepts.h
114 div_ceil.h 116 div_ceil.h
@@ -150,6 +152,10 @@ add_library(common STATIC
150 scm_rev.cpp 152 scm_rev.cpp
151 scm_rev.h 153 scm_rev.h
152 scope_exit.h 154 scope_exit.h
155 settings.cpp
156 settings.h
157 settings_input.cpp
158 settings_input.h
153 spin_lock.cpp 159 spin_lock.cpp
154 spin_lock.h 160 spin_lock.h
155 stream.cpp 161 stream.cpp
diff --git a/src/common/assert.cpp b/src/common/assert.cpp
new file mode 100644
index 000000000..72f1121aa
--- /dev/null
+++ b/src/common/assert.cpp
@@ -0,0 +1,14 @@
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 "common/assert.h"
6#include "common/common_funcs.h"
7
8#include "common/settings.h"
9
10void assert_handle_failure() {
11 if (Settings::values.use_debug_asserts) {
12 Crash();
13 }
14}
diff --git a/src/common/assert.h b/src/common/assert.h
index 06d7b5612..b3ba35c0f 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -4,10 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstdlib>
8#include "common/common_funcs.h"
9#include "common/logging/log.h" 7#include "common/logging/log.h"
10 8
9// Sometimes we want to try to continue even after hitting an assert.
10// However touching this file yields a global recompilation as this header is included almost
11// everywhere. So let's just move the handling of the failed assert to a single cpp file.
12void assert_handle_failure();
13
11// For asserts we'd like to keep all the junk executed when an assert happens away from the 14// For asserts we'd like to keep all the junk executed when an assert happens away from the
12// important code in the function. One way of doing this is to put all the relevant code inside a 15// important code in the function. One way of doing this is to put all the relevant code inside a
13// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to 16// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to
@@ -17,15 +20,14 @@
17// enough for our purposes. 20// enough for our purposes.
18template <typename Fn> 21template <typename Fn>
19#if defined(_MSC_VER) 22#if defined(_MSC_VER)
20[[msvc::noinline, noreturn]] 23[[msvc::noinline]]
21#elif defined(__GNUC__) 24#elif defined(__GNUC__)
22[[gnu::cold, gnu::noinline, noreturn]] 25[[gnu::cold, gnu::noinline]]
23#endif 26#endif
24static void 27static void
25assert_noinline_call(const Fn& fn) { 28assert_noinline_call(const Fn& fn) {
26 fn(); 29 fn();
27 Crash(); 30 assert_handle_failure();
28 exit(1); // Keeps GCC's mouth shut about this actually returning
29} 31}
30 32
31#define ASSERT(_a_) \ 33#define ASSERT(_a_) \
diff --git a/src/common/common_sizes.h b/src/common/common_sizes.h
new file mode 100644
index 000000000..7e9fd968b
--- /dev/null
+++ b/src/common/common_sizes.h
@@ -0,0 +1,43 @@
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 <limits>
8
9#include "common/common_types.h"
10
11namespace Common {
12
13enum : u64 {
14 Size_1_KB = 0x400ULL,
15 Size_64_KB = 64ULL * Size_1_KB,
16 Size_128_KB = 128ULL * Size_1_KB,
17 Size_1_MB = 0x100000ULL,
18 Size_2_MB = 2ULL * Size_1_MB,
19 Size_4_MB = 4ULL * Size_1_MB,
20 Size_5_MB = 5ULL * Size_1_MB,
21 Size_14_MB = 14ULL * Size_1_MB,
22 Size_32_MB = 32ULL * Size_1_MB,
23 Size_33_MB = 33ULL * Size_1_MB,
24 Size_128_MB = 128ULL * Size_1_MB,
25 Size_448_MB = 448ULL * Size_1_MB,
26 Size_507_MB = 507ULL * Size_1_MB,
27 Size_562_MB = 562ULL * Size_1_MB,
28 Size_1554_MB = 1554ULL * Size_1_MB,
29 Size_2048_MB = 2048ULL * Size_1_MB,
30 Size_2193_MB = 2193ULL * Size_1_MB,
31 Size_3285_MB = 3285ULL * Size_1_MB,
32 Size_4916_MB = 4916ULL * Size_1_MB,
33 Size_1_GB = 0x40000000ULL,
34 Size_2_GB = 2ULL * Size_1_GB,
35 Size_4_GB = 4ULL * Size_1_GB,
36 Size_6_GB = 6ULL * Size_1_GB,
37 Size_8_GB = 8ULL * Size_1_GB,
38 Size_64_GB = 64ULL * Size_1_GB,
39 Size_512_GB = 512ULL * Size_1_GB,
40 Size_Invalid = std::numeric_limits<u64>::max(),
41};
42
43} // namespace Common
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 2d4d2e9e7..bc82905c0 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -21,11 +21,11 @@
21#include "common/logging/backend.h" 21#include "common/logging/backend.h"
22#include "common/logging/log.h" 22#include "common/logging/log.h"
23#include "common/logging/text_formatter.h" 23#include "common/logging/text_formatter.h"
24#include "common/settings.h"
24#include "common/string_util.h" 25#include "common/string_util.h"
25#include "common/threadsafe_queue.h" 26#include "common/threadsafe_queue.h"
26#include "core/settings.h"
27 27
28namespace Log { 28namespace Common::Log {
29 29
30/** 30/**
31 * Static state as a singleton. 31 * Static state as a singleton.
@@ -37,8 +37,11 @@ public:
37 return backend; 37 return backend;
38 } 38 }
39 39
40 Impl(Impl const&) = delete; 40 Impl(const Impl&) = delete;
41 const Impl& operator=(Impl const&) = delete; 41 Impl& operator=(const Impl&) = delete;
42
43 Impl(Impl&&) = delete;
44 Impl& operator=(Impl&&) = delete;
42 45
43 void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num, 46 void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
44 const char* function, std::string message) { 47 const char* function, std::string message) {
@@ -132,7 +135,7 @@ private:
132 std::mutex writing_mutex; 135 std::mutex writing_mutex;
133 std::thread backend_thread; 136 std::thread backend_thread;
134 std::vector<std::unique_ptr<Backend>> backends; 137 std::vector<std::unique_ptr<Backend>> backends;
135 Common::MPSCQueue<Log::Entry> message_queue; 138 MPSCQueue<Entry> message_queue;
136 Filter filter; 139 Filter filter;
137 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()}; 140 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
138}; 141};
@@ -146,16 +149,16 @@ void ColorConsoleBackend::Write(const Entry& entry) {
146} 149}
147 150
148FileBackend::FileBackend(const std::string& filename) : bytes_written(0) { 151FileBackend::FileBackend(const std::string& filename) : bytes_written(0) {
149 if (Common::FS::Exists(filename + ".old.txt")) { 152 if (FS::Exists(filename + ".old.txt")) {
150 Common::FS::Delete(filename + ".old.txt"); 153 FS::Delete(filename + ".old.txt");
151 } 154 }
152 if (Common::FS::Exists(filename)) { 155 if (FS::Exists(filename)) {
153 Common::FS::Rename(filename, filename + ".old.txt"); 156 FS::Rename(filename, filename + ".old.txt");
154 } 157 }
155 158
156 // _SH_DENYWR allows read only access to the file for other programs. 159 // _SH_DENYWR allows read only access to the file for other programs.
157 // It is #defined to 0 on other platforms 160 // It is #defined to 0 on other platforms
158 file = Common::FS::IOFile(filename, "w", _SH_DENYWR); 161 file = FS::IOFile(filename, "w", _SH_DENYWR);
159} 162}
160 163
161void FileBackend::Write(const Entry& entry) { 164void FileBackend::Write(const Entry& entry) {
@@ -182,7 +185,7 @@ void FileBackend::Write(const Entry& entry) {
182 185
183void DebuggerBackend::Write(const Entry& entry) { 186void DebuggerBackend::Write(const Entry& entry) {
184#ifdef _WIN32 187#ifdef _WIN32
185 ::OutputDebugStringW(Common::UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str()); 188 ::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
186#endif 189#endif
187} 190}
188 191
@@ -212,6 +215,7 @@ void DebuggerBackend::Write(const Entry& entry) {
212 SUB(Service, ARP) \ 215 SUB(Service, ARP) \
213 SUB(Service, BCAT) \ 216 SUB(Service, BCAT) \
214 SUB(Service, BPC) \ 217 SUB(Service, BPC) \
218 SUB(Service, BGTC) \
215 SUB(Service, BTDRV) \ 219 SUB(Service, BTDRV) \
216 SUB(Service, BTM) \ 220 SUB(Service, BTM) \
217 SUB(Service, Capture) \ 221 SUB(Service, Capture) \
@@ -341,4 +345,4 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
341 instance.PushEntry(log_class, log_level, filename, line_num, function, 345 instance.PushEntry(log_class, log_level, filename, line_num, function,
342 fmt::vformat(format, args)); 346 fmt::vformat(format, args));
343} 347}
344} // namespace Log 348} // namespace Common::Log
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index da1c2f185..84a544ea4 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -11,7 +11,7 @@
11#include "common/logging/filter.h" 11#include "common/logging/filter.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13 13
14namespace Log { 14namespace Common::Log {
15 15
16class Filter; 16class Filter;
17 17
@@ -135,4 +135,4 @@ const char* GetLevelName(Level log_level);
135 * never get the message 135 * never get the message
136 */ 136 */
137void SetGlobalFilter(const Filter& filter); 137void SetGlobalFilter(const Filter& filter);
138} // namespace Log \ No newline at end of file 138} // namespace Common::Log \ No newline at end of file
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 2eccbcd8d..20a2dd106 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -7,7 +7,7 @@
7#include "common/logging/filter.h" 7#include "common/logging/filter.h"
8#include "common/string_util.h" 8#include "common/string_util.h"
9 9
10namespace Log { 10namespace Common::Log {
11namespace { 11namespace {
12template <typename It> 12template <typename It>
13Level GetLevelByName(const It begin, const It end) { 13Level GetLevelByName(const It begin, const It end) {
@@ -103,4 +103,4 @@ bool Filter::IsDebug() const {
103 }); 103 });
104} 104}
105 105
106} // namespace Log 106} // namespace Common::Log
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
index 773df6f2c..f5673a9f6 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -9,7 +9,7 @@
9#include <string_view> 9#include <string_view>
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11 11
12namespace Log { 12namespace Common::Log {
13 13
14/** 14/**
15 * Implements a log message filter which allows different log classes to have different minimum 15 * Implements a log message filter which allows different log classes to have different minimum
@@ -51,4 +51,4 @@ public:
51private: 51private:
52 std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels; 52 std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels;
53}; 53};
54} // namespace Log 54} // namespace Common::Log
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 835894918..1f0f8db52 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -7,7 +7,7 @@
7#include <fmt/format.h> 7#include <fmt/format.h>
8#include "common/common_types.h" 8#include "common/common_types.h"
9 9
10namespace Log { 10namespace Common::Log {
11 11
12// trims up to and including the last of ../, ..\, src/, src\ in a string 12// trims up to and including the last of ../, ..\, src/, src\ in a string
13constexpr const char* TrimSourcePath(std::string_view source) { 13constexpr const char* TrimSourcePath(std::string_view source) {
@@ -66,6 +66,7 @@ enum class Class : ClassType {
66 Service_ARP, ///< The ARP service 66 Service_ARP, ///< The ARP service
67 Service_Audio, ///< The Audio (Audio control) service 67 Service_Audio, ///< The Audio (Audio control) service
68 Service_BCAT, ///< The BCAT service 68 Service_BCAT, ///< The BCAT service
69 Service_BGTC, ///< The BGTC (Background Task Controller) service
69 Service_BPC, ///< The BPC service 70 Service_BPC, ///< The BPC service
70 Service_BTDRV, ///< The Bluetooth driver service 71 Service_BTDRV, ///< The Bluetooth driver service
71 Service_BTM, ///< The BTM service 72 Service_BTM, ///< The BTM service
@@ -147,28 +148,34 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig
147 fmt::make_format_args(args...)); 148 fmt::make_format_args(args...));
148} 149}
149 150
150} // namespace Log 151} // namespace Common::Log
151 152
152#ifdef _DEBUG 153#ifdef _DEBUG
153#define LOG_TRACE(log_class, ...) \ 154#define LOG_TRACE(log_class, ...) \
154 ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, \ 155 Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Trace, \
155 ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) 156 Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
157 __VA_ARGS__)
156#else 158#else
157#define LOG_TRACE(log_class, fmt, ...) (void(0)) 159#define LOG_TRACE(log_class, fmt, ...) (void(0))
158#endif 160#endif
159 161
160#define LOG_DEBUG(log_class, ...) \ 162#define LOG_DEBUG(log_class, ...) \
161 ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, \ 163 Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Debug, \
162 ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) 164 Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
165 __VA_ARGS__)
163#define LOG_INFO(log_class, ...) \ 166#define LOG_INFO(log_class, ...) \
164 ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, \ 167 Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Info, \
165 ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) 168 Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
169 __VA_ARGS__)
166#define LOG_WARNING(log_class, ...) \ 170#define LOG_WARNING(log_class, ...) \
167 ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, \ 171 Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Warning, \
168 ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) 172 Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
173 __VA_ARGS__)
169#define LOG_ERROR(log_class, ...) \ 174#define LOG_ERROR(log_class, ...) \
170 ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, \ 175 Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Error, \
171 ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) 176 Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
177 __VA_ARGS__)
172#define LOG_CRITICAL(log_class, ...) \ 178#define LOG_CRITICAL(log_class, ...) \
173 ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, \ 179 Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Critical, \
174 ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) 180 Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
181 __VA_ARGS__)
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
index 6a0605c63..80ee2cca1 100644
--- a/src/common/logging/text_formatter.cpp
+++ b/src/common/logging/text_formatter.cpp
@@ -16,7 +16,7 @@
16#include "common/logging/text_formatter.h" 16#include "common/logging/text_formatter.h"
17#include "common/string_util.h" 17#include "common/string_util.h"
18 18
19namespace Log { 19namespace Common::Log {
20 20
21std::string FormatLogMessage(const Entry& entry) { 21std::string FormatLogMessage(const Entry& entry) {
22 unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000); 22 unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
@@ -108,4 +108,4 @@ void PrintColoredMessage(const Entry& entry) {
108#undef ESC 108#undef ESC
109#endif 109#endif
110} 110}
111} // namespace Log 111} // namespace Common::Log
diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h
index b6d9e57c8..171e74cfe 100644
--- a/src/common/logging/text_formatter.h
+++ b/src/common/logging/text_formatter.h
@@ -7,7 +7,7 @@
7#include <cstddef> 7#include <cstddef>
8#include <string> 8#include <string>
9 9
10namespace Log { 10namespace Common::Log {
11 11
12struct Entry; 12struct Entry;
13 13
@@ -17,4 +17,4 @@ std::string FormatLogMessage(const Entry& entry);
17void PrintMessage(const Entry& entry); 17void PrintMessage(const Entry& entry);
18/// Prints the same message as `PrintMessage`, but colored according to the severity level. 18/// Prints the same message as `PrintMessage`, but colored according to the severity level.
19void PrintColoredMessage(const Entry& entry); 19void PrintColoredMessage(const Entry& entry);
20} // namespace Log 20} // namespace Common::Log
diff --git a/src/common/nvidia_flags.h b/src/common/nvidia_flags.h
index 75a0233ac..8930efcec 100644
--- a/src/common/nvidia_flags.h
+++ b/src/common/nvidia_flags.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
5namespace Common { 7namespace Common {
6 8
7/// Configure platform specific flags for Nvidia's driver 9/// Configure platform specific flags for Nvidia's driver
diff --git a/src/core/settings.cpp b/src/common/settings.cpp
index 2ae5196e0..702b6598d 100644
--- a/src/core/settings.cpp
+++ b/src/common/settings.cpp
@@ -1,4 +1,4 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2021 yuzu Emulator Project
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
@@ -7,10 +7,7 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h" 10#include "common/settings.h"
11#include "core/hle/service/hid/hid.h"
12#include "core/settings.h"
13#include "video_core/renderer_base.h"
14 11
15namespace Settings { 12namespace Settings {
16 13
@@ -32,14 +29,6 @@ std::string GetTimeZoneString() {
32 return timezones[time_zone_index]; 29 return timezones[time_zone_index];
33} 30}
34 31
35void Apply(Core::System& system) {
36 if (system.IsPoweredOn()) {
37 system.Renderer().RefreshBaseSettings();
38 }
39
40 Service::HID::ReloadInputDevices();
41}
42
43void LogSettings() { 32void LogSettings() {
44 const auto log_setting = [](std::string_view name, const auto& value) { 33 const auto log_setting = [](std::string_view name, const auto& value) {
45 LOG_INFO(Config, "{}: {}", name, value); 34 LOG_INFO(Config, "{}: {}", name, value);
diff --git a/src/core/settings.h b/src/common/settings.h
index d849dded3..d39b4aa45 100644
--- a/src/core/settings.h
+++ b/src/common/settings.h
@@ -1,4 +1,4 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2021 yuzu Emulator Project
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
@@ -11,16 +11,13 @@
11#include <optional> 11#include <optional>
12#include <string> 12#include <string>
13#include <vector> 13#include <vector>
14#include "common/common_types.h"
15#include "input_common/settings.h"
16 14
17namespace Core { 15#include "common/common_types.h"
18class System; 16#include "common/settings_input.h"
19}
20 17
21namespace Settings { 18namespace Settings {
22 19
23enum class RendererBackend { 20enum class RendererBackend : u32 {
24 OpenGL = 0, 21 OpenGL = 0,
25 Vulkan = 1, 22 Vulkan = 1,
26}; 23};
@@ -31,7 +28,7 @@ enum class GPUAccuracy : u32 {
31 Extreme = 2, 28 Extreme = 2,
32}; 29};
33 30
34enum class CPUAccuracy { 31enum class CPUAccuracy : u32 {
35 Accurate = 0, 32 Accurate = 0,
36 Unsafe = 1, 33 Unsafe = 1,
37 DebugMode = 2, 34 DebugMode = 2,
@@ -139,6 +136,7 @@ struct Values {
139 Setting<int> vulkan_device; 136 Setting<int> vulkan_device;
140 137
141 Setting<u16> resolution_factor{1}; 138 Setting<u16> resolution_factor{1};
139 Setting<int> fullscreen_mode;
142 Setting<int> aspect_ratio; 140 Setting<int> aspect_ratio;
143 Setting<int> max_anisotropy; 141 Setting<int> max_anisotropy;
144 Setting<bool> use_frame_limit; 142 Setting<bool> use_frame_limit;
@@ -222,6 +220,8 @@ struct Values {
222 bool quest_flag; 220 bool quest_flag;
223 bool disable_macro_jit; 221 bool disable_macro_jit;
224 bool extended_logging; 222 bool extended_logging;
223 bool use_debug_asserts;
224 bool use_auto_stub;
225 225
226 // Miscellaneous 226 // Miscellaneous
227 std::string log_filter; 227 std::string log_filter;
@@ -253,7 +253,6 @@ float Volume();
253 253
254std::string GetTimeZoneString(); 254std::string GetTimeZoneString();
255 255
256void Apply(Core::System& system);
257void LogSettings(); 256void LogSettings();
258 257
259// Restore the global state of all applicable settings in the Values struct 258// Restore the global state of all applicable settings in the Values struct
diff --git a/src/input_common/settings.cpp b/src/common/settings_input.cpp
index 557e7a9a0..bea2b837b 100644
--- a/src/input_common/settings.cpp
+++ b/src/common/settings_input.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 "input_common/settings.h" 5#include "common/settings_input.h"
6 6
7namespace Settings { 7namespace Settings {
8namespace NativeButton { 8namespace NativeButton {
diff --git a/src/input_common/settings.h b/src/common/settings_input.h
index a59f5d461..609600582 100644
--- a/src/input_common/settings.h
+++ b/src/common/settings_input.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <string> 8#include <string>
9
9#include "common/common_types.h" 10#include "common/common_types.h"
10 11
11namespace Settings { 12namespace Settings {
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index a4647314a..ad04df8ca 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -83,11 +83,15 @@ public:
83 return true; 83 return true;
84 } 84 }
85 85
86 T PopWait() { 86 void Wait() {
87 if (Empty()) { 87 if (Empty()) {
88 std::unique_lock lock{cv_mutex}; 88 std::unique_lock lock{cv_mutex};
89 cv.wait(lock, [this]() { return !Empty(); }); 89 cv.wait(lock, [this]() { return !Empty(); });
90 } 90 }
91 }
92
93 T PopWait() {
94 Wait();
91 T t; 95 T t;
92 Pop(t); 96 Pop(t);
93 return t; 97 return t;
@@ -156,6 +160,10 @@ public:
156 return spsc_queue.Pop(t); 160 return spsc_queue.Pop(t);
157 } 161 }
158 162
163 void Wait() {
164 spsc_queue.Wait();
165 }
166
159 T PopWait() { 167 T PopWait() {
160 return spsc_queue.PopWait(); 168 return spsc_queue.PopWait();
161 } 169 }
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 17f251c37..532e418b0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -141,6 +141,9 @@ add_library(core STATIC
141 hardware_interrupt_manager.h 141 hardware_interrupt_manager.h
142 hle/ipc.h 142 hle/ipc.h
143 hle/ipc_helpers.h 143 hle/ipc_helpers.h
144 hle/kernel/board/nintendo/nx/k_system_control.cpp
145 hle/kernel/board/nintendo/nx/k_system_control.h
146 hle/kernel/board/nintendo/nx/secure_monitor.h
144 hle/kernel/client_port.cpp 147 hle/kernel/client_port.cpp
145 hle/kernel/client_port.h 148 hle/kernel/client_port.h
146 hle/kernel/client_session.cpp 149 hle/kernel/client_session.cpp
@@ -169,9 +172,13 @@ add_library(core STATIC
169 hle/kernel/k_memory_block.h 172 hle/kernel/k_memory_block.h
170 hle/kernel/k_memory_block_manager.cpp 173 hle/kernel/k_memory_block_manager.cpp
171 hle/kernel/k_memory_block_manager.h 174 hle/kernel/k_memory_block_manager.h
175 hle/kernel/k_memory_layout.cpp
176 hle/kernel/k_memory_layout.board.nintendo_nx.cpp
172 hle/kernel/k_memory_layout.h 177 hle/kernel/k_memory_layout.h
173 hle/kernel/k_memory_manager.cpp 178 hle/kernel/k_memory_manager.cpp
174 hle/kernel/k_memory_manager.h 179 hle/kernel/k_memory_manager.h
180 hle/kernel/k_memory_region.h
181 hle/kernel/k_memory_region_type.h
175 hle/kernel/k_page_bitmap.h 182 hle/kernel/k_page_bitmap.h
176 hle/kernel/k_page_heap.cpp 183 hle/kernel/k_page_heap.cpp
177 hle/kernel/k_page_heap.h 184 hle/kernel/k_page_heap.h
@@ -196,11 +203,11 @@ add_library(core STATIC
196 hle/kernel/k_spin_lock.h 203 hle/kernel/k_spin_lock.h
197 hle/kernel/k_synchronization_object.cpp 204 hle/kernel/k_synchronization_object.cpp
198 hle/kernel/k_synchronization_object.h 205 hle/kernel/k_synchronization_object.h
199 hle/kernel/k_system_control.cpp
200 hle/kernel/k_system_control.h 206 hle/kernel/k_system_control.h
201 hle/kernel/k_thread.cpp 207 hle/kernel/k_thread.cpp
202 hle/kernel/k_thread.h 208 hle/kernel/k_thread.h
203 hle/kernel/k_thread_queue.h 209 hle/kernel/k_thread_queue.h
210 hle/kernel/k_trace.h
204 hle/kernel/k_writable_event.cpp 211 hle/kernel/k_writable_event.cpp
205 hle/kernel/k_writable_event.h 212 hle/kernel/k_writable_event.h
206 hle/kernel/kernel.cpp 213 hle/kernel/kernel.cpp
@@ -266,6 +273,7 @@ add_library(core STATIC
266 hle/service/am/applets/profile_select.h 273 hle/service/am/applets/profile_select.h
267 hle/service/am/applets/software_keyboard.cpp 274 hle/service/am/applets/software_keyboard.cpp
268 hle/service/am/applets/software_keyboard.h 275 hle/service/am/applets/software_keyboard.h
276 hle/service/am/applets/software_keyboard_types.h
269 hle/service/am/applets/web_browser.cpp 277 hle/service/am/applets/web_browser.cpp
270 hle/service/am/applets/web_browser.h 278 hle/service/am/applets/web_browser.h
271 hle/service/am/applets/web_types.h 279 hle/service/am/applets/web_types.h
@@ -614,8 +622,6 @@ add_library(core STATIC
614 perf_stats.h 622 perf_stats.h
615 reporter.cpp 623 reporter.cpp
616 reporter.h 624 reporter.h
617 settings.cpp
618 settings.h
619 telemetry_session.cpp 625 telemetry_session.cpp
620 telemetry_session.h 626 telemetry_session.h
621 tools/freezer.cpp 627 tools/freezer.cpp
@@ -666,7 +672,7 @@ endif()
666create_target_directory_groups(core) 672create_target_directory_groups(core)
667 673
668target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 674target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
669target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip) 675target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus zip)
670 676
671if (YUZU_ENABLE_BOXCAT) 677if (YUZU_ENABLE_BOXCAT)
672 target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT) 678 target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 53d78de32..7aeb2a658 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -10,6 +10,7 @@
10#include "common/assert.h" 10#include "common/assert.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/page_table.h" 12#include "common/page_table.h"
13#include "common/settings.h"
13#include "core/arm/cpu_interrupt_handler.h" 14#include "core/arm/cpu_interrupt_handler.h"
14#include "core/arm/dynarmic/arm_dynarmic_32.h" 15#include "core/arm/dynarmic/arm_dynarmic_32.h"
15#include "core/arm/dynarmic/arm_dynarmic_cp15.h" 16#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
@@ -18,7 +19,6 @@
18#include "core/core_timing.h" 19#include "core/core_timing.h"
19#include "core/hle/kernel/svc.h" 20#include "core/hle/kernel/svc.h"
20#include "core/memory.h" 21#include "core/memory.h"
21#include "core/settings.h"
22 22
23namespace Core { 23namespace Core {
24 24
@@ -114,18 +114,17 @@ public:
114 static constexpr u64 minimum_run_cycles = 1000U; 114 static constexpr u64 minimum_run_cycles = 1000U;
115}; 115};
116 116
117std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, 117std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
118 std::size_t address_space_bits) const {
119 Dynarmic::A32::UserConfig config; 118 Dynarmic::A32::UserConfig config;
120 config.callbacks = cb.get(); 119 config.callbacks = cb.get();
121 // TODO(bunnei): Implement page table for 32-bit
122 // config.page_table = &page_table.pointers;
123 config.coprocessors[15] = cp15; 120 config.coprocessors[15] = cp15;
124 config.define_unpredictable_behaviour = true; 121 config.define_unpredictable_behaviour = true;
125 static constexpr std::size_t PAGE_BITS = 12; 122 static constexpr std::size_t PAGE_BITS = 12;
126 static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS); 123 static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
127 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( 124 if (page_table) {
128 page_table.pointers.data()); 125 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
126 page_table->pointers.data());
127 }
129 config.absolute_offset_page_table = true; 128 config.absolute_offset_page_table = true;
130 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; 129 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
131 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; 130 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
@@ -138,6 +137,10 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
138 // Timing 137 // Timing
139 config.wall_clock_cntpct = uses_wall_clock; 138 config.wall_clock_cntpct = uses_wall_clock;
140 139
140 // Code cache size
141 config.code_cache_size = 512 * 1024 * 1024;
142 config.far_code_offset = 256 * 1024 * 1024;
143
141 // Safe optimizations 144 // Safe optimizations
142 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { 145 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
143 if (!Settings::values.cpuopt_page_tables) { 146 if (!Settings::values.cpuopt_page_tables) {
@@ -201,7 +204,8 @@ ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handle
201 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, 204 : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
202 cb(std::make_unique<DynarmicCallbacks32>(*this)), 205 cb(std::make_unique<DynarmicCallbacks32>(*this)),
203 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index}, 206 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index},
204 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} 207 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
208 jit(MakeJit(nullptr)) {}
205 209
206ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; 210ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
207 211
@@ -256,9 +260,6 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
256} 260}
257 261
258void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { 262void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
259 if (!jit) {
260 return;
261 }
262 Dynarmic::A32::Context context; 263 Dynarmic::A32::Context context;
263 jit->SaveContext(context); 264 jit->SaveContext(context);
264 ctx.cpu_registers = context.Regs(); 265 ctx.cpu_registers = context.Regs();
@@ -268,9 +269,6 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
268} 269}
269 270
270void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { 271void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
271 if (!jit) {
272 return;
273 }
274 Dynarmic::A32::Context context; 272 Dynarmic::A32::Context context;
275 context.Regs() = ctx.cpu_registers; 273 context.Regs() = ctx.cpu_registers;
276 context.ExtRegs() = ctx.extension_registers; 274 context.ExtRegs() = ctx.extension_registers;
@@ -284,23 +282,14 @@ void ARM_Dynarmic_32::PrepareReschedule() {
284} 282}
285 283
286void ARM_Dynarmic_32::ClearInstructionCache() { 284void ARM_Dynarmic_32::ClearInstructionCache() {
287 if (!jit) {
288 return;
289 }
290 jit->ClearCache(); 285 jit->ClearCache();
291} 286}
292 287
293void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) { 288void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
294 if (!jit) {
295 return;
296 }
297 jit->InvalidateCacheRange(static_cast<u32>(addr), size); 289 jit->InvalidateCacheRange(static_cast<u32>(addr), size);
298} 290}
299 291
300void ARM_Dynarmic_32::ClearExclusiveState() { 292void ARM_Dynarmic_32::ClearExclusiveState() {
301 if (!jit) {
302 return;
303 }
304 jit->ClearExclusiveState(); 293 jit->ClearExclusiveState();
305} 294}
306 295
@@ -316,7 +305,7 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
316 LoadContext(ctx); 305 LoadContext(ctx);
317 return; 306 return;
318 } 307 }
319 jit = MakeJit(page_table, new_address_space_size_in_bits); 308 jit = MakeJit(&page_table);
320 LoadContext(ctx); 309 LoadContext(ctx);
321 jit_cache.emplace(key, jit); 310 jit_cache.emplace(key, jit);
322} 311}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index f6c4d4db9..d40aef7a9 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -68,8 +68,7 @@ public:
68 std::size_t new_address_space_size_in_bits) override; 68 std::size_t new_address_space_size_in_bits) override;
69 69
70private: 70private:
71 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable& page_table, 71 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
72 std::size_t address_space_bits) const;
73 72
74 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; 73 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
75 using JitCacheType = 74 using JitCacheType =
@@ -80,10 +79,10 @@ private:
80 79
81 std::unique_ptr<DynarmicCallbacks32> cb; 80 std::unique_ptr<DynarmicCallbacks32> cb;
82 JitCacheType jit_cache; 81 JitCacheType jit_cache;
83 std::shared_ptr<Dynarmic::A32::Jit> jit;
84 std::shared_ptr<DynarmicCP15> cp15; 82 std::shared_ptr<DynarmicCP15> cp15;
85 std::size_t core_index; 83 std::size_t core_index;
86 DynarmicExclusiveMonitor& exclusive_monitor; 84 DynarmicExclusiveMonitor& exclusive_monitor;
85 std::shared_ptr<Dynarmic::A32::Jit> jit;
87}; 86};
88 87
89} // namespace Core 88} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index b36b7d918..040529f4d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -9,6 +9,7 @@
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/page_table.h" 11#include "common/page_table.h"
12#include "common/settings.h"
12#include "core/arm/cpu_interrupt_handler.h" 13#include "core/arm/cpu_interrupt_handler.h"
13#include "core/arm/dynarmic/arm_dynarmic_64.h" 14#include "core/arm/dynarmic/arm_dynarmic_64.h"
14#include "core/arm/dynarmic/arm_exclusive_monitor.h" 15#include "core/arm/dynarmic/arm_exclusive_monitor.h"
@@ -19,7 +20,6 @@
19#include "core/hle/kernel/process.h" 20#include "core/hle/kernel/process.h"
20#include "core/hle/kernel/svc.h" 21#include "core/hle/kernel/svc.h"
21#include "core/memory.h" 22#include "core/memory.h"
22#include "core/settings.h"
23 23
24namespace Core { 24namespace Core {
25 25
@@ -142,7 +142,7 @@ public:
142 static constexpr u64 minimum_run_cycles = 1000U; 142 static constexpr u64 minimum_run_cycles = 1000U;
143}; 143};
144 144
145std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, 145std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
146 std::size_t address_space_bits) const { 146 std::size_t address_space_bits) const {
147 Dynarmic::A64::UserConfig config; 147 Dynarmic::A64::UserConfig config;
148 148
@@ -150,13 +150,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
150 config.callbacks = cb.get(); 150 config.callbacks = cb.get();
151 151
152 // Memory 152 // Memory
153 config.page_table = reinterpret_cast<void**>(page_table.pointers.data()); 153 if (page_table) {
154 config.page_table_address_space_bits = address_space_bits; 154 config.page_table = reinterpret_cast<void**>(page_table->pointers.data());
155 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; 155 config.page_table_address_space_bits = address_space_bits;
156 config.silently_mirror_page_table = false; 156 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
157 config.absolute_offset_page_table = true; 157 config.silently_mirror_page_table = false;
158 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; 158 config.absolute_offset_page_table = true;
159 config.only_detect_misalignment_via_page_table_on_page_boundary = true; 159 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
160 config.only_detect_misalignment_via_page_table_on_page_boundary = true;
161 }
160 162
161 // Multi-process state 163 // Multi-process state
162 config.processor_id = core_index; 164 config.processor_id = core_index;
@@ -175,6 +177,10 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
175 // Timing 177 // Timing
176 config.wall_clock_cntpct = uses_wall_clock; 178 config.wall_clock_cntpct = uses_wall_clock;
177 179
180 // Code cache size
181 config.code_cache_size = 512 * 1024 * 1024;
182 config.far_code_offset = 256 * 1024 * 1024;
183
178 // Safe optimizations 184 // Safe optimizations
179 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { 185 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
180 if (!Settings::values.cpuopt_page_tables) { 186 if (!Settings::values.cpuopt_page_tables) {
@@ -237,7 +243,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
237 std::size_t core_index) 243 std::size_t core_index)
238 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, 244 : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
239 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index}, 245 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
240 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} 246 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
247 jit(MakeJit(nullptr, 48)) {}
241 248
242ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; 249ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
243 250
@@ -294,9 +301,6 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
294} 301}
295 302
296void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { 303void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
297 if (!jit) {
298 return;
299 }
300 ctx.cpu_registers = jit->GetRegisters(); 304 ctx.cpu_registers = jit->GetRegisters();
301 ctx.sp = jit->GetSP(); 305 ctx.sp = jit->GetSP();
302 ctx.pc = jit->GetPC(); 306 ctx.pc = jit->GetPC();
@@ -308,9 +312,6 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
308} 312}
309 313
310void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { 314void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
311 if (!jit) {
312 return;
313 }
314 jit->SetRegisters(ctx.cpu_registers); 315 jit->SetRegisters(ctx.cpu_registers);
315 jit->SetSP(ctx.sp); 316 jit->SetSP(ctx.sp);
316 jit->SetPC(ctx.pc); 317 jit->SetPC(ctx.pc);
@@ -326,23 +327,14 @@ void ARM_Dynarmic_64::PrepareReschedule() {
326} 327}
327 328
328void ARM_Dynarmic_64::ClearInstructionCache() { 329void ARM_Dynarmic_64::ClearInstructionCache() {
329 if (!jit) {
330 return;
331 }
332 jit->ClearCache(); 330 jit->ClearCache();
333} 331}
334 332
335void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) { 333void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
336 if (!jit) {
337 return;
338 }
339 jit->InvalidateCacheRange(addr, size); 334 jit->InvalidateCacheRange(addr, size);
340} 335}
341 336
342void ARM_Dynarmic_64::ClearExclusiveState() { 337void ARM_Dynarmic_64::ClearExclusiveState() {
343 if (!jit) {
344 return;
345 }
346 jit->ClearExclusiveState(); 338 jit->ClearExclusiveState();
347} 339}
348 340
@@ -358,7 +350,7 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
358 LoadContext(ctx); 350 LoadContext(ctx);
359 return; 351 return;
360 } 352 }
361 jit = MakeJit(page_table, new_address_space_size_in_bits); 353 jit = MakeJit(&page_table, new_address_space_size_in_bits);
362 LoadContext(ctx); 354 LoadContext(ctx);
363 jit_cache.emplace(key, jit); 355 jit_cache.emplace(key, jit);
364} 356}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 329b59a32..edef04376 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -61,7 +61,7 @@ public:
61 std::size_t new_address_space_size_in_bits) override; 61 std::size_t new_address_space_size_in_bits) override;
62 62
63private: 63private:
64 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table, 64 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
65 std::size_t address_space_bits) const; 65 std::size_t address_space_bits) const;
66 66
67 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; 67 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
@@ -71,10 +71,11 @@ private:
71 friend class DynarmicCallbacks64; 71 friend class DynarmicCallbacks64;
72 std::unique_ptr<DynarmicCallbacks64> cb; 72 std::unique_ptr<DynarmicCallbacks64> cb;
73 JitCacheType jit_cache; 73 JitCacheType jit_cache;
74 std::shared_ptr<Dynarmic::A64::Jit> jit;
75 74
76 std::size_t core_index; 75 std::size_t core_index;
77 DynarmicExclusiveMonitor& exclusive_monitor; 76 DynarmicExclusiveMonitor& exclusive_monitor;
77
78 std::shared_ptr<Dynarmic::A64::Jit> jit;
78}; 79};
79 80
80} // namespace Core 81} // namespace Core
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 305f56ff1..d459d6c34 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -9,6 +9,7 @@
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/microprofile.h" 11#include "common/microprofile.h"
12#include "common/settings.h"
12#include "common/string_util.h" 13#include "common/string_util.h"
13#include "core/arm/exclusive_monitor.h" 14#include "core/arm/exclusive_monitor.h"
14#include "core/core.h" 15#include "core/core.h"
@@ -36,6 +37,7 @@
36#include "core/hle/service/apm/controller.h" 37#include "core/hle/service/apm/controller.h"
37#include "core/hle/service/filesystem/filesystem.h" 38#include "core/hle/service/filesystem/filesystem.h"
38#include "core/hle/service/glue/manager.h" 39#include "core/hle/service/glue/manager.h"
40#include "core/hle/service/hid/hid.h"
39#include "core/hle/service/service.h" 41#include "core/hle/service/service.h"
40#include "core/hle/service/sm/sm.h" 42#include "core/hle/service/sm/sm.h"
41#include "core/hle/service/time/time_manager.h" 43#include "core/hle/service/time/time_manager.h"
@@ -45,7 +47,6 @@
45#include "core/network/network.h" 47#include "core/network/network.h"
46#include "core/perf_stats.h" 48#include "core/perf_stats.h"
47#include "core/reporter.h" 49#include "core/reporter.h"
48#include "core/settings.h"
49#include "core/telemetry_session.h" 50#include "core/telemetry_session.h"
50#include "core/tools/freezer.h" 51#include "core/tools/freezer.h"
51#include "video_core/renderer_base.h" 52#include "video_core/renderer_base.h"
@@ -296,7 +297,7 @@ struct System::Impl {
296 exit_lock = false; 297 exit_lock = false;
297 298
298 if (gpu_core) { 299 if (gpu_core) {
299 gpu_core->WaitIdle(); 300 gpu_core->ShutDown();
300 } 301 }
301 302
302 services.reset(); 303 services.reset();
@@ -774,4 +775,12 @@ void System::ExecuteProgram(std::size_t program_index) {
774 } 775 }
775} 776}
776 777
778void System::ApplySettings() {
779 if (IsPoweredOn()) {
780 Renderer().RefreshBaseSettings();
781 }
782
783 Service::HID::ReloadInputDevices();
784}
785
777} // namespace Core 786} // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index 3a8e040c1..f1068d23f 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -388,6 +388,9 @@ public:
388 */ 388 */
389 void ExecuteProgram(std::size_t program_index); 389 void ExecuteProgram(std::size_t program_index);
390 390
391 /// Applies any changes to settings to this core instance.
392 void ApplySettings();
393
391private: 394private:
392 System(); 395 System();
393 396
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index ad116dcc0..070ed439e 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -22,6 +22,7 @@
22#include "common/file_util.h" 22#include "common/file_util.h"
23#include "common/hex_util.h" 23#include "common/hex_util.h"
24#include "common/logging/log.h" 24#include "common/logging/log.h"
25#include "common/settings.h"
25#include "common/string_util.h" 26#include "common/string_util.h"
26#include "core/crypto/aes_util.h" 27#include "core/crypto/aes_util.h"
27#include "core/crypto/key_manager.h" 28#include "core/crypto/key_manager.h"
@@ -32,7 +33,6 @@
32#include "core/file_sys/registered_cache.h" 33#include "core/file_sys/registered_cache.h"
33#include "core/hle/service/filesystem/filesystem.h" 34#include "core/hle/service/filesystem/filesystem.h"
34#include "core/loader/loader.h" 35#include "core/loader/loader.h"
35#include "core/settings.h"
36 36
37namespace Core::Crypto { 37namespace Core::Crypto {
38namespace { 38namespace {
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index b0a130345..f66759815 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -100,6 +100,14 @@ u64 NACP::GetDeviceSaveDataSize() const {
100 return raw.device_save_data_size; 100 return raw.device_save_data_size;
101} 101}
102 102
103u32 NACP::GetParentalControlFlag() const {
104 return raw.parental_control;
105}
106
107const std::array<u8, 0x20>& NACP::GetRatingAge() const {
108 return raw.rating_age;
109}
110
103std::vector<u8> NACP::GetRawBytes() const { 111std::vector<u8> NACP::GetRawBytes() const {
104 std::vector<u8> out(sizeof(RawNACP)); 112 std::vector<u8> out(sizeof(RawNACP));
105 std::memcpy(out.data(), &raw, sizeof(RawNACP)); 113 std::memcpy(out.data(), &raw, sizeof(RawNACP));
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 403c4219a..dd9837cf5 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -114,6 +114,8 @@ public:
114 std::vector<u8> GetRawBytes() const; 114 std::vector<u8> GetRawBytes() const;
115 bool GetUserAccountSwitchLock() const; 115 bool GetUserAccountSwitchLock() const;
116 u64 GetDeviceSaveDataSize() const; 116 u64 GetDeviceSaveDataSize() const;
117 u32 GetParentalControlFlag() const;
118 const std::array<u8, 0x20>& GetRatingAge() const;
117 119
118private: 120private:
119 RawNACP raw{}; 121 RawNACP raw{};
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 7c3284df8..cc9b4b637 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -10,6 +10,7 @@
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/hex_util.h" 11#include "common/hex_util.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/settings.h"
13#include "common/string_util.h" 14#include "common/string_util.h"
14#include "core/core.h" 15#include "core/core.h"
15#include "core/file_sys/common_funcs.h" 16#include "core/file_sys/common_funcs.h"
@@ -25,7 +26,6 @@
25#include "core/loader/loader.h" 26#include "core/loader/loader.h"
26#include "core/loader/nso.h" 27#include "core/loader/nso.h"
27#include "core/memory/cheat_engine.h" 28#include "core/memory/cheat_engine.h"
28#include "core/settings.h"
29 29
30namespace FileSys { 30namespace FileSys {
31namespace { 31namespace {
diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp
index 4df3574d2..8d960d1ca 100644
--- a/src/core/frontend/applets/profile_select.cpp
+++ b/src/core/frontend/applets/profile_select.cpp
@@ -2,9 +2,9 @@
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 "common/settings.h"
5#include "core/frontend/applets/profile_select.h" 6#include "core/frontend/applets/profile_select.h"
6#include "core/hle/service/acc/profile_manager.h" 7#include "core/hle/service/acc/profile_manager.h"
7#include "core/settings.h"
8 8
9namespace Core::Frontend { 9namespace Core::Frontend {
10 10
diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp
index 856ed33da..12c76c9ee 100644
--- a/src/core/frontend/applets/software_keyboard.cpp
+++ b/src/core/frontend/applets/software_keyboard.cpp
@@ -1,29 +1,149 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2021 yuzu Emulator Project
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 "common/logging/backend.h" 5#include <thread>
6
7#include "common/logging/log.h"
6#include "common/string_util.h" 8#include "common/string_util.h"
7#include "core/frontend/applets/software_keyboard.h" 9#include "core/frontend/applets/software_keyboard.h"
8 10
9namespace Core::Frontend { 11namespace Core::Frontend {
12
10SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default; 13SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
11 14
12void DefaultSoftwareKeyboardApplet::RequestText( 15DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
13 std::function<void(std::optional<std::u16string>)> out, 16
14 SoftwareKeyboardParameters parameters) const { 17void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
15 if (parameters.initial_text.empty()) 18 bool is_inline, KeyboardInitializeParameters initialize_parameters,
16 out(u"yuzu"); 19 std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
20 std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
21 submit_inline_callback_) {
22 if (is_inline) {
23 LOG_WARNING(
24 Service_AM,
25 "(STUBBED) called, backend requested to initialize the inline software keyboard.");
26
27 submit_inline_callback = std::move(submit_inline_callback_);
28 } else {
29 LOG_WARNING(
30 Service_AM,
31 "(STUBBED) called, backend requested to initialize the normal software keyboard.");
32
33 submit_normal_callback = std::move(submit_normal_callback_);
34 }
35
36 parameters = std::move(initialize_parameters);
37
38 LOG_INFO(Service_AM,
39 "\nKeyboardInitializeParameters:"
40 "\nok_text={}"
41 "\nheader_text={}"
42 "\nsub_text={}"
43 "\nguide_text={}"
44 "\ninitial_text={}"
45 "\nmax_text_length={}"
46 "\nmin_text_length={}"
47 "\ninitial_cursor_position={}"
48 "\ntype={}"
49 "\npassword_mode={}"
50 "\ntext_draw_type={}"
51 "\nkey_disable_flags={}"
52 "\nuse_blur_background={}"
53 "\nenable_backspace_button={}"
54 "\nenable_return_button={}"
55 "\ndisable_cancel_button={}",
56 Common::UTF16ToUTF8(parameters.ok_text), Common::UTF16ToUTF8(parameters.header_text),
57 Common::UTF16ToUTF8(parameters.sub_text), Common::UTF16ToUTF8(parameters.guide_text),
58 Common::UTF16ToUTF8(parameters.initial_text), parameters.max_text_length,
59 parameters.min_text_length, parameters.initial_cursor_position, parameters.type,
60 parameters.password_mode, parameters.text_draw_type, parameters.key_disable_flags.raw,
61 parameters.use_blur_background, parameters.enable_backspace_button,
62 parameters.enable_return_button, parameters.disable_cancel_button);
63}
64
65void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
66 LOG_WARNING(Service_AM,
67 "(STUBBED) called, backend requested to show the normal software keyboard.");
68
69 SubmitNormalText(u"yuzu");
70}
71
72void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
73 Service::AM::Applets::SwkbdTextCheckResult text_check_result,
74 std::u16string text_check_message) const {
75 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
76}
77
78void DefaultSoftwareKeyboardApplet::ShowInlineKeyboard(
79 InlineAppearParameters appear_parameters) const {
80 LOG_WARNING(Service_AM,
81 "(STUBBED) called, backend requested to show the inline software keyboard.");
82
83 LOG_INFO(Service_AM,
84 "\nInlineAppearParameters:"
85 "\nmax_text_length={}"
86 "\nmin_text_length={}"
87 "\nkey_top_scale_x={}"
88 "\nkey_top_scale_y={}"
89 "\nkey_top_translate_x={}"
90 "\nkey_top_translate_y={}"
91 "\ntype={}"
92 "\nkey_disable_flags={}"
93 "\nkey_top_as_floating={}"
94 "\nenable_backspace_button={}"
95 "\nenable_return_button={}"
96 "\ndisable_cancel_button={}",
97 appear_parameters.max_text_length, appear_parameters.min_text_length,
98 appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y,
99 appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y,
100 appear_parameters.type, appear_parameters.key_disable_flags.raw,
101 appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button,
102 appear_parameters.enable_return_button, appear_parameters.disable_cancel_button);
103
104 std::thread([this] { SubmitInlineText(u"yuzu"); }).detach();
105}
17 106
18 out(parameters.initial_text); 107void DefaultSoftwareKeyboardApplet::HideInlineKeyboard() const {
108 LOG_WARNING(Service_AM,
109 "(STUBBED) called, backend requested to hide the inline software keyboard.");
19} 110}
20 111
21void DefaultSoftwareKeyboardApplet::SendTextCheckDialog( 112void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_parameters) const {
22 std::u16string error_message, std::function<void()> finished_check) const {
23 LOG_WARNING(Service_AM, 113 LOG_WARNING(Service_AM,
24 "(STUBBED) called - Default fallback software keyboard does not support text " 114 "(STUBBED) called, backend requested to change the inline keyboard text.");
25 "check! (error_message={})", 115
26 Common::UTF16ToUTF8(error_message)); 116 LOG_INFO(Service_AM,
27 finished_check(); 117 "\nInlineTextParameters:"
118 "\ninput_text={}"
119 "\ncursor_position={}",
120 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
121
122 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
123 text_parameters.input_text, text_parameters.cursor_position);
124}
125
126void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
127 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to exit the software keyboard.");
28} 128}
129
130void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
131 submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text);
132}
133
134void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
135 std::this_thread::sleep_for(std::chrono::milliseconds(500));
136
137 for (std::size_t index = 0; index < text.size(); ++index) {
138 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
139 std::u16string(text.data(), text.data() + index + 1),
140 static_cast<s32>(index) + 1);
141
142 std::this_thread::sleep_for(std::chrono::milliseconds(250));
143 }
144
145 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text),
146 static_cast<s32>(text.size()));
147}
148
29} // namespace Core::Frontend 149} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h
index f9b202664..506eb35bb 100644
--- a/src/core/frontend/applets/software_keyboard.h
+++ b/src/core/frontend/applets/software_keyboard.h
@@ -1,54 +1,116 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2021 yuzu Emulator Project
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 5#pragma once
6 6
7#include <functional> 7#include <functional>
8#include <optional> 8#include <thread>
9#include <string> 9
10#include "common/bit_field.h"
11#include "common/common_types.h" 10#include "common/common_types.h"
12 11
12#include "core/hle/service/am/applets/software_keyboard_types.h"
13
13namespace Core::Frontend { 14namespace Core::Frontend {
14struct SoftwareKeyboardParameters { 15
15 std::u16string submit_text; 16struct KeyboardInitializeParameters {
17 std::u16string ok_text;
16 std::u16string header_text; 18 std::u16string header_text;
17 std::u16string sub_text; 19 std::u16string sub_text;
18 std::u16string guide_text; 20 std::u16string guide_text;
19 std::u16string initial_text; 21 std::u16string initial_text;
20 std::size_t max_length; 22 u32 max_text_length;
21 bool password; 23 u32 min_text_length;
22 bool cursor_at_beginning; 24 s32 initial_cursor_position;
23 25 Service::AM::Applets::SwkbdType type;
24 union { 26 Service::AM::Applets::SwkbdPasswordMode password_mode;
25 u8 value; 27 Service::AM::Applets::SwkbdTextDrawType text_draw_type;
26 28 Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
27 BitField<1, 1, u8> disable_space; 29 bool use_blur_background;
28 BitField<2, 1, u8> disable_address; 30 bool enable_backspace_button;
29 BitField<3, 1, u8> disable_percent; 31 bool enable_return_button;
30 BitField<4, 1, u8> disable_slash; 32 bool disable_cancel_button;
31 BitField<6, 1, u8> disable_number; 33};
32 BitField<7, 1, u8> disable_download_code; 34
33 }; 35struct InlineAppearParameters {
36 u32 max_text_length;
37 u32 min_text_length;
38 f32 key_top_scale_x;
39 f32 key_top_scale_y;
40 f32 key_top_translate_x;
41 f32 key_top_translate_y;
42 Service::AM::Applets::SwkbdType type;
43 Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
44 bool key_top_as_floating;
45 bool enable_backspace_button;
46 bool enable_return_button;
47 bool disable_cancel_button;
48};
49
50struct InlineTextParameters {
51 std::u16string input_text;
52 s32 cursor_position;
34}; 53};
35 54
36class SoftwareKeyboardApplet { 55class SoftwareKeyboardApplet {
37public: 56public:
38 virtual ~SoftwareKeyboardApplet(); 57 virtual ~SoftwareKeyboardApplet();
39 58
40 virtual void RequestText(std::function<void(std::optional<std::u16string>)> out, 59 virtual void InitializeKeyboard(
41 SoftwareKeyboardParameters parameters) const = 0; 60 bool is_inline, KeyboardInitializeParameters initialize_parameters,
42 virtual void SendTextCheckDialog(std::u16string error_message, 61 std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
43 std::function<void()> finished_check) const = 0; 62 submit_normal_callback_,
63 std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
64 submit_inline_callback_) = 0;
65
66 virtual void ShowNormalKeyboard() const = 0;
67
68 virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
69 std::u16string text_check_message) const = 0;
70
71 virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;
72
73 virtual void HideInlineKeyboard() const = 0;
74
75 virtual void InlineTextChanged(InlineTextParameters text_parameters) const = 0;
76
77 virtual void ExitKeyboard() const = 0;
44}; 78};
45 79
46class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet { 80class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
47public: 81public:
48 void RequestText(std::function<void(std::optional<std::u16string>)> out, 82 ~DefaultSoftwareKeyboardApplet() override;
49 SoftwareKeyboardParameters parameters) const override; 83
50 void SendTextCheckDialog(std::u16string error_message, 84 void InitializeKeyboard(
51 std::function<void()> finished_check) const override; 85 bool is_inline, KeyboardInitializeParameters initialize_parameters,
86 std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
87 submit_normal_callback_,
88 std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
89 submit_inline_callback_) override;
90
91 void ShowNormalKeyboard() const override;
92
93 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
94 std::u16string text_check_message) const override;
95
96 void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override;
97
98 void HideInlineKeyboard() const override;
99
100 void InlineTextChanged(InlineTextParameters text_parameters) const override;
101
102 void ExitKeyboard() const override;
103
104private:
105 void SubmitNormalText(std::u16string text) const;
106 void SubmitInlineText(std::u16string_view text) const;
107
108 KeyboardInitializeParameters parameters;
109
110 mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
111 submit_normal_callback;
112 mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
113 submit_inline_callback;
52}; 114};
53 115
54} // namespace Core::Frontend 116} // namespace Core::Frontend
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index ee7a58b1c..474de9206 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -4,9 +4,9 @@
4 4
5#include <cmath> 5#include <cmath>
6#include <mutex> 6#include <mutex>
7#include "common/settings.h"
7#include "core/frontend/emu_window.h" 8#include "core/frontend/emu_window.h"
8#include "core/frontend/input.h" 9#include "core/frontend/input.h"
9#include "core/settings.h"
10 10
11namespace Core::Frontend { 11namespace Core::Frontend {
12 12
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index b9a270a55..0832463d6 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -5,8 +5,8 @@
5#include <cmath> 5#include <cmath>
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/settings.h"
8#include "core/frontend/framebuffer_layout.h" 9#include "core/frontend/framebuffer_layout.h"
9#include "core/settings.h"
10 10
11namespace Layout { 11namespace Layout {
12 12
diff --git a/src/core/frontend/input_interpreter.cpp b/src/core/frontend/input_interpreter.cpp
index ec5fe660e..9f6a90e8f 100644
--- a/src/core/frontend/input_interpreter.cpp
+++ b/src/core/frontend/input_interpreter.cpp
@@ -12,7 +12,9 @@ InputInterpreter::InputInterpreter(Core::System& system)
12 : npad{system.ServiceManager() 12 : npad{system.ServiceManager()
13 .GetService<Service::HID::Hid>("hid") 13 .GetService<Service::HID::Hid>("hid")
14 ->GetAppletResource() 14 ->GetAppletResource()
15 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {} 15 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
16 ResetButtonStates();
17}
16 18
17InputInterpreter::~InputInterpreter() = default; 19InputInterpreter::~InputInterpreter() = default;
18 20
@@ -25,6 +27,17 @@ void InputInterpreter::PollInput() {
25 button_states[current_index] = button_state; 27 button_states[current_index] = button_state;
26} 28}
27 29
30void InputInterpreter::ResetButtonStates() {
31 previous_index = 0;
32 current_index = 0;
33
34 button_states[0] = 0xFFFFFFFF;
35
36 for (std::size_t i = 1; i < button_states.size(); ++i) {
37 button_states[i] = 0;
38 }
39}
40
28bool InputInterpreter::IsButtonPressed(HIDButton button) const { 41bool InputInterpreter::IsButtonPressed(HIDButton button) const {
29 return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; 42 return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0;
30} 43}
diff --git a/src/core/frontend/input_interpreter.h b/src/core/frontend/input_interpreter.h
index 73fc47ffb..9495e3daf 100644
--- a/src/core/frontend/input_interpreter.h
+++ b/src/core/frontend/input_interpreter.h
@@ -66,6 +66,9 @@ public:
66 /// Gets a button state from HID and inserts it into the array of button states. 66 /// Gets a button state from HID and inserts it into the array of button states.
67 void PollInput(); 67 void PollInput();
68 68
69 /// Resets all the button states to their defaults.
70 void ResetButtonStates();
71
69 /** 72 /**
70 * Checks whether the button is pressed. 73 * Checks whether the button is pressed.
71 * 74 *
diff --git a/src/core/hle/kernel/arch/arm64/k_memory_region_device_types.inc b/src/core/hle/kernel/arch/arm64/k_memory_region_device_types.inc
new file mode 100644
index 000000000..857b512ba
--- /dev/null
+++ b/src/core/hle/kernel/arch/arm64/k_memory_region_device_types.inc
@@ -0,0 +1,20 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// All architectures must define NumArchitectureDeviceRegions.
6constexpr inline const auto NumArchitectureDeviceRegions = 3;
7
8constexpr inline const auto KMemoryRegionType_Uart =
9 KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0);
10constexpr inline const auto KMemoryRegionType_InterruptCpuInterface =
11 KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1)
12 .SetAttribute(KMemoryRegionAttr_NoUserMap);
13constexpr inline const auto KMemoryRegionType_InterruptDistributor =
14 KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2)
15 .SetAttribute(KMemoryRegionAttr_NoUserMap);
16static_assert(KMemoryRegionType_Uart.GetValue() == (0x1D));
17static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() ==
18 (0x2D | KMemoryRegionAttr_NoUserMap));
19static_assert(KMemoryRegionType_InterruptDistributor.GetValue() ==
20 (0x4D | KMemoryRegionAttr_NoUserMap));
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc b/src/core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc
new file mode 100644
index 000000000..58d6c0b16
--- /dev/null
+++ b/src/core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc
@@ -0,0 +1,52 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// All architectures must define NumBoardDeviceRegions.
6constexpr inline const auto NumBoardDeviceRegions = 6;
7// UNUSED: .Derive(NumBoardDeviceRegions, 0);
8constexpr inline const auto KMemoryRegionType_MemoryController =
9 KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 1)
10 .SetAttribute(KMemoryRegionAttr_NoUserMap);
11constexpr inline const auto KMemoryRegionType_MemoryController1 =
12 KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 2)
13 .SetAttribute(KMemoryRegionAttr_NoUserMap);
14constexpr inline const auto KMemoryRegionType_MemoryController0 =
15 KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 3)
16 .SetAttribute(KMemoryRegionAttr_NoUserMap);
17constexpr inline const auto KMemoryRegionType_PowerManagementController =
18 KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 4).DeriveTransition();
19constexpr inline const auto KMemoryRegionType_LegacyLpsDevices =
20 KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 5);
21static_assert(KMemoryRegionType_MemoryController.GetValue() ==
22 (0x55 | KMemoryRegionAttr_NoUserMap));
23static_assert(KMemoryRegionType_MemoryController1.GetValue() ==
24 (0x65 | KMemoryRegionAttr_NoUserMap));
25static_assert(KMemoryRegionType_MemoryController0.GetValue() ==
26 (0x95 | KMemoryRegionAttr_NoUserMap));
27static_assert(KMemoryRegionType_PowerManagementController.GetValue() == (0x1A5));
28
29static_assert(KMemoryRegionType_LegacyLpsDevices.GetValue() == 0xC5);
30
31constexpr inline const auto NumLegacyLpsDevices = 7;
32constexpr inline const auto KMemoryRegionType_LegacyLpsExceptionVectors =
33 KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 0);
34constexpr inline const auto KMemoryRegionType_LegacyLpsIram =
35 KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 1);
36constexpr inline const auto KMemoryRegionType_LegacyLpsFlowController =
37 KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 2);
38constexpr inline const auto KMemoryRegionType_LegacyLpsPrimaryICtlr =
39 KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 3);
40constexpr inline const auto KMemoryRegionType_LegacyLpsSemaphore =
41 KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 4);
42constexpr inline const auto KMemoryRegionType_LegacyLpsAtomics =
43 KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 5);
44constexpr inline const auto KMemoryRegionType_LegacyLpsClkRst =
45 KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 6);
46static_assert(KMemoryRegionType_LegacyLpsExceptionVectors.GetValue() == 0x3C5);
47static_assert(KMemoryRegionType_LegacyLpsIram.GetValue() == 0x5C5);
48static_assert(KMemoryRegionType_LegacyLpsFlowController.GetValue() == 0x6C5);
49static_assert(KMemoryRegionType_LegacyLpsPrimaryICtlr.GetValue() == 0x9C5);
50static_assert(KMemoryRegionType_LegacyLpsSemaphore.GetValue() == 0xAC5);
51static_assert(KMemoryRegionType_LegacyLpsAtomics.GetValue() == 0xCC5);
52static_assert(KMemoryRegionType_LegacyLpsClkRst.GetValue() == 0x11C5);
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
new file mode 100644
index 000000000..86472b5ce
--- /dev/null
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -0,0 +1,164 @@
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 <random>
6
7#include "common/common_sizes.h"
8#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
9#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
10#include "core/hle/kernel/k_trace.h"
11
12namespace Kernel::Board::Nintendo::Nx {
13
14namespace impl {
15
16constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2238 * 4 * 1024;
17constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x710 * 4 * 1024;
18constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4 * 1024;
19
20} // namespace impl
21
22constexpr const std::size_t RequiredNonSecureSystemMemorySize =
23 impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices +
24 impl::RequiredNonSecureSystemMemorySizeMisc;
25
26namespace {
27
28u32 GetMemoryModeForInit() {
29 return 0x01;
30}
31
32u32 GetMemorySizeForInit() {
33 return 0;
34}
35
36Smc::MemoryArrangement GetMemoryArrangeForInit() {
37 switch (GetMemoryModeForInit() & 0x3F) {
38 case 0x01:
39 default:
40 return Smc::MemoryArrangement_4GB;
41 case 0x02:
42 return Smc::MemoryArrangement_4GBForAppletDev;
43 case 0x03:
44 return Smc::MemoryArrangement_4GBForSystemDev;
45 case 0x11:
46 return Smc::MemoryArrangement_6GB;
47 case 0x12:
48 return Smc::MemoryArrangement_6GBForAppletDev;
49 case 0x21:
50 return Smc::MemoryArrangement_8GB;
51 }
52}
53} // namespace
54
55// Initialization.
56size_t KSystemControl::Init::GetIntendedMemorySize() {
57 switch (GetMemorySizeForInit()) {
58 case Smc::MemorySize_4GB:
59 default: // All invalid modes should go to 4GB.
60 return Common::Size_4_GB;
61 case Smc::MemorySize_6GB:
62 return Common::Size_6_GB;
63 case Smc::MemorySize_8GB:
64 return Common::Size_8_GB;
65 }
66}
67
68PAddr KSystemControl::Init::GetKernelPhysicalBaseAddress(u64 base_address) {
69 return base_address;
70}
71
72bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
73 return true;
74}
75
76std::size_t KSystemControl::Init::GetApplicationPoolSize() {
77 // Get the base pool size.
78 const size_t base_pool_size = []() -> size_t {
79 switch (GetMemoryArrangeForInit()) {
80 case Smc::MemoryArrangement_4GB:
81 default:
82 return Common::Size_3285_MB;
83 case Smc::MemoryArrangement_4GBForAppletDev:
84 return Common::Size_2048_MB;
85 case Smc::MemoryArrangement_4GBForSystemDev:
86 return Common::Size_3285_MB;
87 case Smc::MemoryArrangement_6GB:
88 return Common::Size_4916_MB;
89 case Smc::MemoryArrangement_6GBForAppletDev:
90 return Common::Size_3285_MB;
91 case Smc::MemoryArrangement_8GB:
92 return Common::Size_4916_MB;
93 }
94 }();
95
96 // Return (possibly) adjusted size.
97 return base_pool_size;
98}
99
100size_t KSystemControl::Init::GetAppletPoolSize() {
101 // Get the base pool size.
102 const size_t base_pool_size = []() -> size_t {
103 switch (GetMemoryArrangeForInit()) {
104 case Smc::MemoryArrangement_4GB:
105 default:
106 return Common::Size_507_MB;
107 case Smc::MemoryArrangement_4GBForAppletDev:
108 return Common::Size_1554_MB;
109 case Smc::MemoryArrangement_4GBForSystemDev:
110 return Common::Size_448_MB;
111 case Smc::MemoryArrangement_6GB:
112 return Common::Size_562_MB;
113 case Smc::MemoryArrangement_6GBForAppletDev:
114 return Common::Size_2193_MB;
115 case Smc::MemoryArrangement_8GB:
116 return Common::Size_2193_MB;
117 }
118 }();
119
120 // Return (possibly) adjusted size.
121 constexpr size_t ExtraSystemMemoryForAtmosphere = Common::Size_33_MB;
122 return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
123}
124
125size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
126 // Verify that our minimum is at least as large as Nintendo's.
127 constexpr size_t MinimumSize = RequiredNonSecureSystemMemorySize;
128 static_assert(MinimumSize >= 0x29C8000);
129
130 return MinimumSize;
131}
132
133namespace {
134template <typename F>
135u64 GenerateUniformRange(u64 min, u64 max, F f) {
136 // Handle the case where the difference is too large to represent.
137 if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
138 return f();
139 }
140
141 // Iterate until we get a value in range.
142 const u64 range_size = ((max + 1) - min);
143 const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
144 while (true) {
145 if (const u64 rnd = f(); rnd < effective_max) {
146 return min + (rnd % range_size);
147 }
148 }
149}
150
151} // Anonymous namespace
152
153u64 KSystemControl::GenerateRandomU64() {
154 static std::random_device device;
155 static std::mt19937 gen(device());
156 static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
157 return distribution(gen);
158}
159
160u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
161 return GenerateUniformRange(min, max, GenerateRandomU64);
162}
163
164} // namespace Kernel::Board::Nintendo::Nx
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.h b/src/core/hle/kernel/board/nintendo/nx/k_system_control.h
new file mode 100644
index 000000000..52f230ced
--- /dev/null
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.h
@@ -0,0 +1,28 @@
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 "common/common_types.h"
8
9namespace Kernel::Board::Nintendo::Nx {
10
11class KSystemControl {
12public:
13 class Init {
14 public:
15 // Initialization.
16 static std::size_t GetIntendedMemorySize();
17 static PAddr GetKernelPhysicalBaseAddress(u64 base_address);
18 static bool ShouldIncreaseThreadResourceLimit();
19 static std::size_t GetApplicationPoolSize();
20 static std::size_t GetAppletPoolSize();
21 static std::size_t GetMinimumNonSecureSystemPoolSize();
22 };
23
24 static u64 GenerateRandomRange(u64 min, u64 max);
25 static u64 GenerateRandomU64();
26};
27
28} // namespace Kernel::Board::Nintendo::Nx
diff --git a/src/core/hle/kernel/board/nintendo/nx/secure_monitor.h b/src/core/hle/kernel/board/nintendo/nx/secure_monitor.h
new file mode 100644
index 000000000..0c366b252
--- /dev/null
+++ b/src/core/hle/kernel/board/nintendo/nx/secure_monitor.h
@@ -0,0 +1,26 @@
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 "common/common_types.h"
8
9namespace Kernel::Board::Nintendo::Nx::Smc {
10
11enum MemorySize {
12 MemorySize_4GB = 0,
13 MemorySize_6GB = 1,
14 MemorySize_8GB = 2,
15};
16
17enum MemoryArrangement {
18 MemoryArrangement_4GB = 0,
19 MemoryArrangement_4GBForAppletDev = 1,
20 MemoryArrangement_4GBForSystemDev = 2,
21 MemoryArrangement_6GB = 3,
22 MemoryArrangement_6GBForAppletDev = 4,
23 MemoryArrangement_8GB = 5,
24};
25
26} // namespace Kernel::Board::Nintendo::Nx::Smc
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 161d9f782..2b363b1d9 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -75,10 +75,14 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
75 if (incoming) { 75 if (incoming) {
76 // Populate the object lists with the data in the IPC request. 76 // Populate the object lists with the data in the IPC request.
77 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { 77 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
78 copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>())); 78 const u32 copy_handle{rp.Pop<Handle>()};
79 copy_handles.push_back(copy_handle);
80 copy_objects.push_back(handle_table.GetGeneric(copy_handle));
79 } 81 }
80 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { 82 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
81 move_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>())); 83 const u32 move_handle{rp.Pop<Handle>()};
84 move_handles.push_back(move_handle);
85 move_objects.push_back(handle_table.GetGeneric(move_handle));
82 } 86 }
83 } else { 87 } else {
84 // For responses we just ignore the handles, they're empty and will be populated when 88 // For responses we just ignore the handles, they're empty and will be populated when
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 9a769781b..6fba42615 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -210,6 +210,14 @@ public:
210 /// Helper function to test whether the output buffer at buffer_index can be written 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; 211 bool CanWriteBuffer(std::size_t buffer_index = 0) const;
212 212
213 Handle GetCopyHandle(std::size_t index) const {
214 return copy_handles.at(index);
215 }
216
217 Handle GetMoveHandle(std::size_t index) const {
218 return move_handles.at(index);
219 }
220
213 template <typename T> 221 template <typename T>
214 std::shared_ptr<T> GetCopyObject(std::size_t index) { 222 std::shared_ptr<T> GetCopyObject(std::size_t index) {
215 return DynamicObjectCast<T>(copy_objects.at(index)); 223 return DynamicObjectCast<T>(copy_objects.at(index));
@@ -285,6 +293,8 @@ private:
285 std::shared_ptr<Kernel::ServerSession> server_session; 293 std::shared_ptr<Kernel::ServerSession> server_session;
286 std::shared_ptr<KThread> thread; 294 std::shared_ptr<KThread> thread;
287 // TODO(yuriks): Check common usage of this and optimize size accordingly 295 // TODO(yuriks): Check common usage of this and optimize size accordingly
296 boost::container::small_vector<Handle, 8> move_handles;
297 boost::container::small_vector<Handle, 8> copy_handles;
288 boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; 298 boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
289 boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; 299 boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
290 boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; 300 boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp
index 24944d15b..c7549f7a2 100644
--- a/src/core/hle/kernel/k_address_space_info.cpp
+++ b/src/core/hle/kernel/k_address_space_info.cpp
@@ -5,45 +5,34 @@
5#include <array> 5#include <array>
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/common_sizes.h"
8#include "core/hle/kernel/k_address_space_info.h" 9#include "core/hle/kernel/k_address_space_info.h"
9 10
10namespace Kernel { 11namespace Kernel {
11 12
12namespace { 13namespace {
13 14
14enum : u64 {
15 Size_1_MB = 0x100000,
16 Size_2_MB = 2 * Size_1_MB,
17 Size_128_MB = 128 * Size_1_MB,
18 Size_1_GB = 0x40000000,
19 Size_2_GB = 2 * Size_1_GB,
20 Size_4_GB = 4 * Size_1_GB,
21 Size_6_GB = 6 * Size_1_GB,
22 Size_64_GB = 64 * Size_1_GB,
23 Size_512_GB = 512 * Size_1_GB,
24 Invalid = std::numeric_limits<u64>::max(),
25};
26
27// clang-format off 15// clang-format off
28constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{ 16constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
29 { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, }, 17 { .bit_width = 32, .address = Common::Size_2_MB , .size = Common::Size_1_GB - Common::Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
30 { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, }, 18 { .bit_width = 32, .address = Common::Size_1_GB , .size = Common::Size_4_GB - Common::Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
31 { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, }, 19 { .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
32 { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, }, 20 { .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
33 { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, }, 21 { .bit_width = 36, .address = Common::Size_128_MB , .size = Common::Size_2_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
34 { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, }, 22 { .bit_width = 36, .address = Common::Size_2_GB , .size = Common::Size_64_GB - Common::Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
35 { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, }, 23 { .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
36 { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, }, 24 { .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
37 { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, }, 25 { .bit_width = 39, .address = Common::Size_128_MB , .size = Common::Size_512_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
38 { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall }, 26 { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
39 { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, }, 27 { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
40 { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, }, 28 { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
41 { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, }, 29 { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
42}}; 30}};
43// clang-format on 31// clang-format on
44 32
45constexpr bool IsAllowedIndexForAddress(std::size_t index) { 33constexpr bool IsAllowedIndexForAddress(std::size_t index) {
46 return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid; 34 return index < AddressSpaceInfos.size() &&
35 AddressSpaceInfos[index].address != Common::Size_Invalid;
47} 36}
48 37
49using IndexArray = 38using IndexArray =
diff --git a/src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp b/src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp
new file mode 100644
index 000000000..a78551291
--- /dev/null
+++ b/src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp
@@ -0,0 +1,199 @@
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 "common/alignment.h"
6#include "core/hle/kernel/k_memory_layout.h"
7#include "core/hle/kernel/k_memory_manager.h"
8#include "core/hle/kernel/k_system_control.h"
9#include "core/hle/kernel/k_trace.h"
10
11namespace Kernel {
12
13namespace {
14
15constexpr size_t CarveoutAlignment = 0x20000;
16constexpr size_t CarveoutSizeMax = (512ULL * 1024 * 1024) - CarveoutAlignment;
17
18bool SetupPowerManagementControllerMemoryRegion(KMemoryLayout& memory_layout) {
19 // Above firmware 2.0.0, the PMC is not mappable.
20 return memory_layout.GetPhysicalMemoryRegionTree().Insert(
21 0x7000E000, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap) &&
22 memory_layout.GetPhysicalMemoryRegionTree().Insert(
23 0x7000E400, 0xC00,
24 KMemoryRegionType_PowerManagementController | KMemoryRegionAttr_NoUserMap);
25}
26
27void InsertPoolPartitionRegionIntoBothTrees(KMemoryLayout& memory_layout, size_t start, size_t size,
28 KMemoryRegionType phys_type,
29 KMemoryRegionType virt_type, u32& cur_attr) {
30 const u32 attr = cur_attr++;
31 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(start, size,
32 static_cast<u32>(phys_type), attr));
33 const KMemoryRegion* phys = memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
34 static_cast<u32>(phys_type), attr);
35 ASSERT(phys != nullptr);
36 ASSERT(phys->GetEndAddress() != 0);
37 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size,
38 static_cast<u32>(virt_type), attr));
39}
40
41} // namespace
42
43namespace Init {
44
45void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout) {
46 ASSERT(SetupPowerManagementControllerMemoryRegion(memory_layout));
47 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
48 0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap));
49 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
50 0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap));
51 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
52 0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap));
53 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
54 0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
55 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
56 0x50041000, 0x1000,
57 KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap));
58 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
59 0x50042000, 0x1000,
60 KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap));
61 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
62 0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
63
64 // Map IRAM unconditionally, to support debug-logging-to-iram build config.
65 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
66 0x40000000, 0x40000, KMemoryRegionType_LegacyLpsIram | KMemoryRegionAttr_ShouldKernelMap));
67
68 // Above firmware 2.0.0, prevent mapping the bpmp exception vectors or the ipatch region.
69 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
70 0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
71 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
72 0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
73}
74
75void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout) {
76 const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize();
77 const PAddr physical_memory_base_address =
78 KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress);
79
80 // Insert blocks into the tree.
81 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
82 physical_memory_base_address, intended_memory_size, KMemoryRegionType_Dram));
83 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
84 physical_memory_base_address, ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly));
85
86 // Insert the KTrace block at the end of Dram, if KTrace is enabled.
87 static_assert(!IsKTraceEnabled || KTraceBufferSize > 0);
88 if constexpr (IsKTraceEnabled) {
89 const PAddr ktrace_buffer_phys_addr =
90 physical_memory_base_address + intended_memory_size - KTraceBufferSize;
91 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
92 ktrace_buffer_phys_addr, KTraceBufferSize, KMemoryRegionType_KernelTraceBuffer));
93 }
94}
95
96void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout) {
97 // Start by identifying the extents of the DRAM memory region.
98 const auto dram_extents = memory_layout.GetMainMemoryPhysicalExtents();
99 ASSERT(dram_extents.GetEndAddress() != 0);
100
101 // Determine the end of the pool region.
102 const u64 pool_end = dram_extents.GetEndAddress() - KTraceBufferSize;
103
104 // Find the start of the kernel DRAM region.
105 const KMemoryRegion* kernel_dram_region =
106 memory_layout.GetPhysicalMemoryRegionTree().FindFirstDerived(
107 KMemoryRegionType_DramKernelBase);
108 ASSERT(kernel_dram_region != nullptr);
109
110 const u64 kernel_dram_start = kernel_dram_region->GetAddress();
111 ASSERT(Common::IsAligned(kernel_dram_start, CarveoutAlignment));
112
113 // Find the start of the pool partitions region.
114 const KMemoryRegion* pool_partitions_region =
115 memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
116 KMemoryRegionType_DramPoolPartition, 0);
117 ASSERT(pool_partitions_region != nullptr);
118 const u64 pool_partitions_start = pool_partitions_region->GetAddress();
119
120 // Setup the pool partition layouts.
121 // On 5.0.0+, setup modern 4-pool-partition layout.
122
123 // Get Application and Applet pool sizes.
124 const size_t application_pool_size = KSystemControl::Init::GetApplicationPoolSize();
125 const size_t applet_pool_size = KSystemControl::Init::GetAppletPoolSize();
126 const size_t unsafe_system_pool_min_size =
127 KSystemControl::Init::GetMinimumNonSecureSystemPoolSize();
128
129 // Decide on starting addresses for our pools.
130 const u64 application_pool_start = pool_end - application_pool_size;
131 const u64 applet_pool_start = application_pool_start - applet_pool_size;
132 const u64 unsafe_system_pool_start = std::min(
133 kernel_dram_start + CarveoutSizeMax,
134 Common::AlignDown(applet_pool_start - unsafe_system_pool_min_size, CarveoutAlignment));
135 const size_t unsafe_system_pool_size = applet_pool_start - unsafe_system_pool_start;
136
137 // We want to arrange application pool depending on where the middle of dram is.
138 const u64 dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2;
139 u32 cur_pool_attr = 0;
140 size_t total_overhead_size = 0;
141 if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) {
142 InsertPoolPartitionRegionIntoBothTrees(
143 memory_layout, application_pool_start, application_pool_size,
144 KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
145 cur_pool_attr);
146 total_overhead_size +=
147 KMemoryManager::CalculateManagementOverheadSize(application_pool_size);
148 } else {
149 const size_t first_application_pool_size = dram_midpoint - application_pool_start;
150 const size_t second_application_pool_size =
151 application_pool_start + application_pool_size - dram_midpoint;
152 InsertPoolPartitionRegionIntoBothTrees(
153 memory_layout, application_pool_start, first_application_pool_size,
154 KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
155 cur_pool_attr);
156 InsertPoolPartitionRegionIntoBothTrees(
157 memory_layout, dram_midpoint, second_application_pool_size,
158 KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
159 cur_pool_attr);
160 total_overhead_size +=
161 KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size);
162 total_overhead_size +=
163 KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size);
164 }
165
166 // Insert the applet pool.
167 InsertPoolPartitionRegionIntoBothTrees(memory_layout, applet_pool_start, applet_pool_size,
168 KMemoryRegionType_DramAppletPool,
169 KMemoryRegionType_VirtualDramAppletPool, cur_pool_attr);
170 total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(applet_pool_size);
171
172 // Insert the nonsecure system pool.
173 InsertPoolPartitionRegionIntoBothTrees(
174 memory_layout, unsafe_system_pool_start, unsafe_system_pool_size,
175 KMemoryRegionType_DramSystemNonSecurePool, KMemoryRegionType_VirtualDramSystemNonSecurePool,
176 cur_pool_attr);
177 total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(unsafe_system_pool_size);
178
179 // Insert the pool management region.
180 total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(
181 (unsafe_system_pool_start - pool_partitions_start) - total_overhead_size);
182 const u64 pool_management_start = unsafe_system_pool_start - total_overhead_size;
183 const size_t pool_management_size = total_overhead_size;
184 u32 pool_management_attr = 0;
185 InsertPoolPartitionRegionIntoBothTrees(
186 memory_layout, pool_management_start, pool_management_size,
187 KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement,
188 pool_management_attr);
189
190 // Insert the system pool.
191 const u64 system_pool_size = pool_management_start - pool_partitions_start;
192 InsertPoolPartitionRegionIntoBothTrees(memory_layout, pool_partitions_start, system_pool_size,
193 KMemoryRegionType_DramSystemPool,
194 KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr);
195}
196
197} // namespace Init
198
199} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_layout.cpp b/src/core/hle/kernel/k_memory_layout.cpp
new file mode 100644
index 000000000..fb1e2435f
--- /dev/null
+++ b/src/core/hle/kernel/k_memory_layout.cpp
@@ -0,0 +1,166 @@
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 <array>
6
7#include "common/alignment.h"
8#include "core/hle/kernel/k_memory_layout.h"
9#include "core/hle/kernel/k_system_control.h"
10
11namespace Kernel {
12
13namespace {
14
15template <typename... Args>
16KMemoryRegion* AllocateRegion(KMemoryRegionAllocator& memory_region_allocator, Args&&... args) {
17 return memory_region_allocator.Allocate(std::forward<Args>(args)...);
18}
19
20} // namespace
21
22KMemoryRegionTree::KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_)
23 : memory_region_allocator{memory_region_allocator_} {}
24
25void KMemoryRegionTree::InsertDirectly(u64 address, u64 last_address, u32 attr, u32 type_id) {
26 this->insert(*AllocateRegion(memory_region_allocator, address, last_address, attr, type_id));
27}
28
29bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) {
30 // Locate the memory region that contains the address.
31 KMemoryRegion* found = this->FindModifiable(address);
32
33 // We require that the old attr is correct.
34 if (found->GetAttributes() != old_attr) {
35 return false;
36 }
37
38 // We further require that the region can be split from the old region.
39 const u64 inserted_region_end = address + size;
40 const u64 inserted_region_last = inserted_region_end - 1;
41 if (found->GetLastAddress() < inserted_region_last) {
42 return false;
43 }
44
45 // Further, we require that the type id is a valid transformation.
46 if (!found->CanDerive(type_id)) {
47 return false;
48 }
49
50 // Cache information from the region before we remove it.
51 const u64 old_address = found->GetAddress();
52 const u64 old_last = found->GetLastAddress();
53 const u64 old_pair = found->GetPairAddress();
54 const u32 old_type = found->GetType();
55
56 // Erase the existing region from the tree.
57 this->erase(this->iterator_to(*found));
58
59 // Insert the new region into the tree.
60 if (old_address == address) {
61 // Reuse the old object for the new region, if we can.
62 found->Reset(address, inserted_region_last, old_pair, new_attr, type_id);
63 this->insert(*found);
64 } else {
65 // If we can't re-use, adjust the old region.
66 found->Reset(old_address, address - 1, old_pair, old_attr, old_type);
67 this->insert(*found);
68
69 // Insert a new region for the split.
70 const u64 new_pair = (old_pair != std::numeric_limits<u64>::max())
71 ? old_pair + (address - old_address)
72 : old_pair;
73 this->insert(*AllocateRegion(memory_region_allocator, address, inserted_region_last,
74 new_pair, new_attr, type_id));
75 }
76
77 // If we need to insert a region after the region, do so.
78 if (old_last != inserted_region_last) {
79 const u64 after_pair = (old_pair != std::numeric_limits<u64>::max())
80 ? old_pair + (inserted_region_end - old_address)
81 : old_pair;
82 this->insert(*AllocateRegion(memory_region_allocator, inserted_region_end, old_last,
83 after_pair, old_attr, old_type));
84 }
85
86 return true;
87}
88
89VAddr KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id) {
90 // We want to find the total extents of the type id.
91 const auto extents = this->GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
92
93 // Ensure that our alignment is correct.
94 ASSERT(Common::IsAligned(extents.GetAddress(), alignment));
95
96 const u64 first_address = extents.GetAddress();
97 const u64 last_address = extents.GetLastAddress();
98
99 const u64 first_index = first_address / alignment;
100 const u64 last_index = last_address / alignment;
101
102 while (true) {
103 const u64 candidate =
104 KSystemControl::GenerateRandomRange(first_index, last_index) * alignment;
105
106 // Ensure that the candidate doesn't overflow with the size.
107 if (!(candidate < candidate + size)) {
108 continue;
109 }
110
111 const u64 candidate_last = candidate + size - 1;
112
113 // Ensure that the candidate fits within the region.
114 if (candidate_last > last_address) {
115 continue;
116 }
117
118 // Locate the candidate region, and ensure it fits and has the correct type id.
119 if (const auto& candidate_region = *this->Find(candidate);
120 !(candidate_last <= candidate_region.GetLastAddress() &&
121 candidate_region.GetType() == type_id)) {
122 continue;
123 }
124
125 return candidate;
126 }
127}
128
129KMemoryLayout::KMemoryLayout()
130 : virtual_tree{memory_region_allocator}, physical_tree{memory_region_allocator},
131 virtual_linear_tree{memory_region_allocator}, physical_linear_tree{memory_region_allocator} {}
132
133void KMemoryLayout::InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
134 VAddr linear_virtual_start) {
135 // Set static differences.
136 linear_phys_to_virt_diff = linear_virtual_start - aligned_linear_phys_start;
137 linear_virt_to_phys_diff = aligned_linear_phys_start - linear_virtual_start;
138
139 // Initialize linear trees.
140 for (auto& region : GetPhysicalMemoryRegionTree()) {
141 if (region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
142 GetPhysicalLinearMemoryRegionTree().InsertDirectly(
143 region.GetAddress(), region.GetLastAddress(), region.GetAttributes(),
144 region.GetType());
145 }
146 }
147
148 for (auto& region : GetVirtualMemoryRegionTree()) {
149 if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
150 GetVirtualLinearMemoryRegionTree().InsertDirectly(
151 region.GetAddress(), region.GetLastAddress(), region.GetAttributes(),
152 region.GetType());
153 }
154 }
155}
156
157size_t KMemoryLayout::GetResourceRegionSizeForInit() {
158 // Calculate resource region size based on whether we allow extra threads.
159 const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
160 size_t resource_region_size =
161 KernelResourceSize + (use_extra_resources ? KernelSlabHeapAdditionalSize : 0);
162
163 return resource_region_size;
164}
165
166} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_layout.h b/src/core/hle/kernel/k_memory_layout.h
index 0821d2d8c..288642d9a 100644
--- a/src/core/hle/kernel/k_memory_layout.h
+++ b/src/core/hle/kernel/k_memory_layout.h
@@ -1,23 +1,69 @@
1// Copyright 2020 yuzu Emulator Project 1// Copyright 2021 yuzu Emulator Project
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 5#pragma once
6 6
7#include <utility>
8
9#include "common/alignment.h"
10#include "common/common_sizes.h"
7#include "common/common_types.h" 11#include "common/common_types.h"
8#include "core/device_memory.h" 12#include "core/device_memory.h"
13#include "core/hle/kernel/k_memory_region.h"
14#include "core/hle/kernel/k_memory_region_type.h"
15#include "core/hle/kernel/memory_types.h"
9 16
10namespace Kernel { 17namespace Kernel {
11 18
12constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024; 19constexpr std::size_t L1BlockSize = Common::Size_1_GB;
20constexpr std::size_t L2BlockSize = Common::Size_2_MB;
21
22constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
23 return (Common::DivideUp(size, L1BlockSize) + Common::DivideUp(size, L2BlockSize)) * PageSize;
24}
25
26constexpr std::size_t MainMemorySize = Common::Size_4_GB;
27constexpr std::size_t MainMemorySizeMax = Common::Size_8_GB;
28
29constexpr std::size_t ReservedEarlyDramSize = 0x60000;
30constexpr std::size_t DramPhysicalAddress = 0x80000000;
31
32constexpr std::size_t KernelAslrAlignment = Common::Size_2_MB;
13constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39; 33constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
14constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48; 34constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
35
15constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth; 36constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth;
16constexpr std::size_t KernelVirtualAddressSpaceEnd = 37constexpr std::size_t KernelVirtualAddressSpaceEnd =
17 KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment); 38 KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment);
18constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1; 39constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1ULL;
19constexpr std::size_t KernelVirtualAddressSpaceSize = 40constexpr std::size_t KernelVirtualAddressSpaceSize =
20 KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase; 41 KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
42constexpr std::size_t KernelVirtualAddressCodeBase = KernelVirtualAddressSpaceBase;
43constexpr std::size_t KernelVirtualAddressCodeSize = 0x62000;
44constexpr std::size_t KernelVirtualAddressCodeEnd =
45 KernelVirtualAddressCodeBase + KernelVirtualAddressCodeSize;
46
47constexpr std::size_t KernelPhysicalAddressSpaceBase = 0ULL;
48constexpr std::size_t KernelPhysicalAddressSpaceEnd =
49 KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceWidth;
50constexpr std::size_t KernelPhysicalAddressSpaceLast = KernelPhysicalAddressSpaceEnd - 1ULL;
51constexpr std::size_t KernelPhysicalAddressSpaceSize =
52 KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase;
53constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
54
55constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
56constexpr std::size_t KernelInitialPageHeapSize = Common::Size_128_KB;
57
58constexpr std::size_t KernelSlabHeapDataSize = Common::Size_5_MB;
59constexpr std::size_t KernelSlabHeapGapsSize = Common::Size_2_MB - Common::Size_64_KB;
60constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
61
62// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
63constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000ULL;
64
65constexpr std::size_t KernelResourceSize =
66 KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
21 67
22constexpr bool IsKernelAddressKey(VAddr key) { 68constexpr bool IsKernelAddressKey(VAddr key) {
23 return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast; 69 return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
@@ -27,64 +73,327 @@ constexpr bool IsKernelAddress(VAddr address) {
27 return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; 73 return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
28} 74}
29 75
30class KMemoryRegion final { 76class KMemoryLayout final {
31 friend class KMemoryLayout;
32
33public: 77public:
34 constexpr PAddr StartAddress() const { 78 KMemoryLayout();
35 return start_address; 79
80 KMemoryRegionTree& GetVirtualMemoryRegionTree() {
81 return virtual_tree;
82 }
83 const KMemoryRegionTree& GetVirtualMemoryRegionTree() const {
84 return virtual_tree;
85 }
86 KMemoryRegionTree& GetPhysicalMemoryRegionTree() {
87 return physical_tree;
88 }
89 const KMemoryRegionTree& GetPhysicalMemoryRegionTree() const {
90 return physical_tree;
91 }
92 KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() {
93 return virtual_linear_tree;
94 }
95 const KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() const {
96 return virtual_linear_tree;
97 }
98 KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() {
99 return physical_linear_tree;
100 }
101 const KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() const {
102 return physical_linear_tree;
103 }
104
105 VAddr GetLinearVirtualAddress(PAddr address) const {
106 return address + linear_phys_to_virt_diff;
107 }
108 PAddr GetLinearPhysicalAddress(VAddr address) const {
109 return address + linear_virt_to_phys_diff;
110 }
111
112 const KMemoryRegion* FindVirtual(VAddr address) const {
113 return Find(address, GetVirtualMemoryRegionTree());
114 }
115 const KMemoryRegion* FindPhysical(PAddr address) const {
116 return Find(address, GetPhysicalMemoryRegionTree());
117 }
118
119 const KMemoryRegion* FindVirtualLinear(VAddr address) const {
120 return Find(address, GetVirtualLinearMemoryRegionTree());
121 }
122 const KMemoryRegion* FindPhysicalLinear(PAddr address) const {
123 return Find(address, GetPhysicalLinearMemoryRegionTree());
124 }
125
126 VAddr GetMainStackTopAddress(s32 core_id) const {
127 return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack);
128 }
129 VAddr GetIdleStackTopAddress(s32 core_id) const {
130 return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack);
131 }
132 VAddr GetExceptionStackTopAddress(s32 core_id) const {
133 return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
134 }
135
136 VAddr GetSlabRegionAddress() const {
137 return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
138 .GetAddress();
139 }
140
141 const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
142 return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
143 }
144 PAddr GetDevicePhysicalAddress(KMemoryRegionType type) const {
145 return GetDeviceRegion(type).GetAddress();
146 }
147 VAddr GetDeviceVirtualAddress(KMemoryRegionType type) const {
148 return GetDeviceRegion(type).GetPairAddress();
149 }
150
151 const KMemoryRegion& GetPoolManagementRegion() const {
152 return Dereference(
153 GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramPoolManagement));
154 }
155 const KMemoryRegion& GetPageTableHeapRegion() const {
156 return Dereference(
157 GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelPtHeap));
158 }
159 const KMemoryRegion& GetKernelStackRegion() const {
160 return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelStack));
161 }
162 const KMemoryRegion& GetTempRegion() const {
163 return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelTemp));
164 }
165
166 const KMemoryRegion& GetKernelTraceBufferRegion() const {
167 return Dereference(GetVirtualLinearMemoryRegionTree().FindByType(
168 KMemoryRegionType_VirtualDramKernelTraceBuffer));
169 }
170
171 const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
172 return Dereference(FindVirtualLinear(address));
173 }
174
175 const KMemoryRegion* GetPhysicalKernelTraceBufferRegion() const {
176 return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_KernelTraceBuffer);
177 }
178 const KMemoryRegion* GetPhysicalOnMemoryBootImageRegion() const {
179 return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_OnMemoryBootImage);
180 }
181 const KMemoryRegion* GetPhysicalDTBRegion() const {
182 return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB);
183 }
184
185 bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
186 return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
187 KMemoryRegionType_DramUserPool);
188 }
189 bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address) const {
190 return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(),
191 KMemoryRegionType_VirtualDramUserPool);
192 }
193
194 bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address, size_t size) const {
195 return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
196 KMemoryRegionType_DramUserPool);
197 }
198 bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address, size_t size) const {
199 return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(),
200 KMemoryRegionType_VirtualDramUserPool);
201 }
202
203 bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
204 return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
205 static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
206 }
207 bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address,
208 size_t size) const {
209 return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
210 static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
211 }
212
213 std::pair<size_t, size_t> GetTotalAndKernelMemorySizes() const {
214 size_t total_size = 0, kernel_size = 0;
215 for (const auto& region : GetPhysicalMemoryRegionTree()) {
216 if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
217 total_size += region.GetSize();
218 if (!region.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
219 kernel_size += region.GetSize();
220 }
221 }
222 }
223 return std::make_pair(total_size, kernel_size);
224 }
225
226 void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
227 VAddr linear_virtual_start);
228 static size_t GetResourceRegionSizeForInit();
229
230 auto GetKernelRegionExtents() const {
231 return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel);
232 }
233 auto GetKernelCodeRegionExtents() const {
234 return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode);
235 }
236 auto GetKernelStackRegionExtents() const {
237 return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelStack);
238 }
239 auto GetKernelMiscRegionExtents() const {
240 return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelMisc);
241 }
242 auto GetKernelSlabRegionExtents() const {
243 return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelSlab);
244 }
245
246 auto GetLinearRegionPhysicalExtents() const {
247 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
248 KMemoryRegionAttr_LinearMapped);
249 }
250
251 auto GetLinearRegionVirtualExtents() const {
252 const auto physical = GetLinearRegionPhysicalExtents();
253 return KMemoryRegion(GetLinearVirtualAddress(physical.GetAddress()),
254 GetLinearVirtualAddress(physical.GetLastAddress()), 0,
255 KMemoryRegionType_None);
256 }
257
258 auto GetMainMemoryPhysicalExtents() const {
259 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Dram);
260 }
261 auto GetCarveoutRegionExtents() const {
262 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
263 KMemoryRegionAttr_CarveoutProtected);
264 }
265
266 auto GetKernelRegionPhysicalExtents() const {
267 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
268 KMemoryRegionType_DramKernelBase);
269 }
270 auto GetKernelCodeRegionPhysicalExtents() const {
271 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
272 KMemoryRegionType_DramKernelCode);
273 }
274 auto GetKernelSlabRegionPhysicalExtents() const {
275 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
276 KMemoryRegionType_DramKernelSlab);
277 }
278 auto GetKernelPageTableHeapRegionPhysicalExtents() const {
279 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
280 KMemoryRegionType_DramKernelPtHeap);
281 }
282 auto GetKernelInitPageTableRegionPhysicalExtents() const {
283 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
284 KMemoryRegionType_DramKernelInitPt);
285 }
286
287 auto GetKernelPoolManagementRegionPhysicalExtents() const {
288 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
289 KMemoryRegionType_DramPoolManagement);
290 }
291 auto GetKernelPoolPartitionRegionPhysicalExtents() const {
292 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
293 KMemoryRegionType_DramPoolPartition);
294 }
295 auto GetKernelSystemPoolRegionPhysicalExtents() const {
296 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
297 KMemoryRegionType_DramSystemPool);
298 }
299 auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() const {
300 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
301 KMemoryRegionType_DramSystemNonSecurePool);
302 }
303 auto GetKernelAppletPoolRegionPhysicalExtents() const {
304 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
305 KMemoryRegionType_DramAppletPool);
306 }
307 auto GetKernelApplicationPoolRegionPhysicalExtents() const {
308 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
309 KMemoryRegionType_DramApplicationPool);
36 } 310 }
37 311
38 constexpr PAddr EndAddress() const { 312 auto GetKernelTraceBufferRegionPhysicalExtents() const {
39 return end_address; 313 return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
314 KMemoryRegionType_KernelTraceBuffer);
40 } 315 }
41 316
42private: 317private:
43 constexpr KMemoryRegion() = default; 318 template <typename AddressType>
44 constexpr KMemoryRegion(PAddr start_address, PAddr end_address) 319 static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address,
45 : start_address{start_address}, end_address{end_address} {} 320 const KMemoryRegionTree& tree, KMemoryRegionType type) {
321 // Check if the cached region already contains the address.
322 if (region != nullptr && region->Contains(address)) {
323 return true;
324 }
46 325
47 const PAddr start_address{}; 326 // Find the containing region, and update the cache.
48 const PAddr end_address{}; 327 if (const KMemoryRegion* found = tree.Find(address);
49}; 328 found != nullptr && found->IsDerivedFrom(type)) {
329 region = found;
330 return true;
331 } else {
332 return false;
333 }
334 }
50 335
51class KMemoryLayout final { 336 template <typename AddressType>
52public: 337 static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address, size_t size,
53 constexpr const KMemoryRegion& Application() const { 338 const KMemoryRegionTree& tree, KMemoryRegionType type) {
54 return application; 339 // Get the end of the checked region.
340 const u64 last_address = address + size - 1;
341
342 // Walk the tree to verify the region is correct.
343 const KMemoryRegion* cur =
344 (region != nullptr && region->Contains(address)) ? region : tree.Find(address);
345 while (cur != nullptr && cur->IsDerivedFrom(type)) {
346 if (last_address <= cur->GetLastAddress()) {
347 region = cur;
348 return true;
349 }
350
351 cur = cur->GetNext();
352 }
353 return false;
55 } 354 }
56 355
57 constexpr const KMemoryRegion& Applet() const { 356 template <typename AddressType>
58 return applet; 357 static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
358 return tree.Find(address);
59 } 359 }
60 360
61 constexpr const KMemoryRegion& System() const { 361 static KMemoryRegion& Dereference(KMemoryRegion* region) {
62 return system; 362 ASSERT(region != nullptr);
363 return *region;
63 } 364 }
64 365
65 static constexpr KMemoryLayout GetDefaultLayout() { 366 static const KMemoryRegion& Dereference(const KMemoryRegion* region) {
66 constexpr std::size_t application_size{0xcd500000}; 367 ASSERT(region != nullptr);
67 constexpr std::size_t applet_size{0x1fb00000}; 368 return *region;
68 constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size}; 369 }
69 constexpr PAddr application_end_address{Core::DramMemoryMap::End}; 370
70 constexpr PAddr applet_start_address{application_start_address - applet_size}; 371 VAddr GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
71 constexpr PAddr applet_end_address{applet_start_address + applet_size}; 372 const auto& region = Dereference(
72 constexpr PAddr system_start_address{Core::DramMemoryMap::SlabHeapEnd}; 373 GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
73 constexpr PAddr system_end_address{applet_start_address}; 374 ASSERT(region.GetEndAddress() != 0);
74 return {application_start_address, application_end_address, applet_start_address, 375 return region.GetEndAddress();
75 applet_end_address, system_start_address, system_end_address};
76 } 376 }
77 377
78private: 378private:
79 constexpr KMemoryLayout(PAddr application_start_address, std::size_t application_size, 379 u64 linear_phys_to_virt_diff{};
80 PAddr applet_start_address, std::size_t applet_size, 380 u64 linear_virt_to_phys_diff{};
81 PAddr system_start_address, std::size_t system_size) 381 KMemoryRegionAllocator memory_region_allocator;
82 : application{application_start_address, application_size}, 382 KMemoryRegionTree virtual_tree;
83 applet{applet_start_address, applet_size}, system{system_start_address, system_size} {} 383 KMemoryRegionTree physical_tree;
84 384 KMemoryRegionTree virtual_linear_tree;
85 const KMemoryRegion application; 385 KMemoryRegionTree physical_linear_tree;
86 const KMemoryRegion applet;
87 const KMemoryRegion system;
88}; 386};
89 387
388namespace Init {
389
390// These should be generic, regardless of board.
391void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout);
392
393// These may be implemented in a board-specific manner.
394void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout);
395void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout);
396
397} // namespace Init
398
90} // namespace Kernel 399} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp
index 9027602bf..aa71697b2 100644
--- a/src/core/hle/kernel/k_memory_manager.cpp
+++ b/src/core/hle/kernel/k_memory_manager.cpp
@@ -173,4 +173,16 @@ ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_page
173 return RESULT_SUCCESS; 173 return RESULT_SUCCESS;
174} 174}
175 175
176std::size_t KMemoryManager::Impl::CalculateManagementOverheadSize(std::size_t region_size) {
177 const std::size_t ref_count_size = (region_size / PageSize) * sizeof(u16);
178 const std::size_t optimize_map_size =
179 (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
180 Common::BitSize<u64>()) *
181 sizeof(u64);
182 const std::size_t manager_meta_size =
183 Common::AlignUp(optimize_map_size + ref_count_size, PageSize);
184 const std::size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region_size);
185 return manager_meta_size + page_heap_size;
186}
187
176} // namespace Kernel 188} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_manager.h b/src/core/hle/kernel/k_memory_manager.h
index ae9f683b8..ac840b3d0 100644
--- a/src/core/hle/kernel/k_memory_manager.h
+++ b/src/core/hle/kernel/k_memory_manager.h
@@ -29,6 +29,10 @@ public:
29 29
30 Shift = 4, 30 Shift = 4,
31 Mask = (0xF << Shift), 31 Mask = (0xF << Shift),
32
33 // Aliases.
34 Unsafe = Application,
35 Secure = System,
32 }; 36 };
33 37
34 enum class Direction : u32 { 38 enum class Direction : u32 {
@@ -56,6 +60,10 @@ public:
56 static constexpr std::size_t MaxManagerCount = 10; 60 static constexpr std::size_t MaxManagerCount = 10;
57 61
58public: 62public:
63 static std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
64 return Impl::CalculateManagementOverheadSize(region_size);
65 }
66
59 static constexpr u32 EncodeOption(Pool pool, Direction dir) { 67 static constexpr u32 EncodeOption(Pool pool, Direction dir) {
60 return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) | 68 return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) |
61 (static_cast<u32>(dir) << static_cast<u32>(Direction::Shift)); 69 (static_cast<u32>(dir) << static_cast<u32>(Direction::Shift));
@@ -86,6 +94,16 @@ private:
86 Pool pool{}; 94 Pool pool{};
87 95
88 public: 96 public:
97 static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
98
99 static constexpr std::size_t CalculateOptimizedProcessOverheadSize(
100 std::size_t region_size) {
101 return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
102 Common::BitSize<u64>()) *
103 sizeof(u64);
104 }
105
106 public:
89 Impl() = default; 107 Impl() = default;
90 108
91 std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address); 109 std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address);
diff --git a/src/core/hle/kernel/k_memory_region.h b/src/core/hle/kernel/k_memory_region.h
new file mode 100644
index 000000000..a861c04ab
--- /dev/null
+++ b/src/core/hle/kernel/k_memory_region.h
@@ -0,0 +1,350 @@
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 "common/assert.h"
8#include "common/common_types.h"
9#include "common/intrusive_red_black_tree.h"
10#include "core/hle/kernel/k_memory_region_type.h"
11
12namespace Kernel {
13
14class KMemoryRegionAllocator;
15
16class KMemoryRegion final : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryRegion>,
17 NonCopyable {
18 friend class KMemoryRegionTree;
19
20public:
21 constexpr KMemoryRegion() = default;
22 constexpr KMemoryRegion(u64 address_, u64 last_address_)
23 : address{address_}, last_address{last_address_} {}
24 constexpr KMemoryRegion(u64 address_, u64 last_address_, u64 pair_address_, u32 attributes_,
25 u32 type_id_)
26 : address(address_), last_address(last_address_), pair_address(pair_address_),
27 attributes(attributes_), type_id(type_id_) {}
28 constexpr KMemoryRegion(u64 address_, u64 last_address_, u32 attributes_, u32 type_id_)
29 : KMemoryRegion(address_, last_address_, std::numeric_limits<u64>::max(), attributes_,
30 type_id_) {}
31
32 static constexpr int Compare(const KMemoryRegion& lhs, const KMemoryRegion& rhs) {
33 if (lhs.GetAddress() < rhs.GetAddress()) {
34 return -1;
35 } else if (lhs.GetAddress() <= rhs.GetLastAddress()) {
36 return 0;
37 } else {
38 return 1;
39 }
40 }
41
42private:
43 constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
44 address = a;
45 pair_address = p;
46 last_address = la;
47 attributes = r;
48 type_id = t;
49 }
50
51public:
52 constexpr u64 GetAddress() const {
53 return address;
54 }
55
56 constexpr u64 GetPairAddress() const {
57 return pair_address;
58 }
59
60 constexpr u64 GetLastAddress() const {
61 return last_address;
62 }
63
64 constexpr u64 GetEndAddress() const {
65 return this->GetLastAddress() + 1;
66 }
67
68 constexpr size_t GetSize() const {
69 return this->GetEndAddress() - this->GetAddress();
70 }
71
72 constexpr u32 GetAttributes() const {
73 return attributes;
74 }
75
76 constexpr u32 GetType() const {
77 return type_id;
78 }
79
80 constexpr void SetType(u32 type) {
81 ASSERT(this->CanDerive(type));
82 type_id = type;
83 }
84
85 constexpr bool Contains(u64 address) const {
86 ASSERT(this->GetEndAddress() != 0);
87 return this->GetAddress() <= address && address <= this->GetLastAddress();
88 }
89
90 constexpr bool IsDerivedFrom(u32 type) const {
91 return (this->GetType() | type) == this->GetType();
92 }
93
94 constexpr bool HasTypeAttribute(u32 attr) const {
95 return (this->GetType() | attr) == this->GetType();
96 }
97
98 constexpr bool CanDerive(u32 type) const {
99 return (this->GetType() | type) == type;
100 }
101
102 constexpr void SetPairAddress(u64 a) {
103 pair_address = a;
104 }
105
106 constexpr void SetTypeAttribute(u32 attr) {
107 type_id |= attr;
108 }
109
110private:
111 u64 address{};
112 u64 last_address{};
113 u64 pair_address{};
114 u32 attributes{};
115 u32 type_id{};
116};
117
118class KMemoryRegionTree final : NonCopyable {
119public:
120 struct DerivedRegionExtents {
121 const KMemoryRegion* first_region{};
122 const KMemoryRegion* last_region{};
123
124 constexpr DerivedRegionExtents() = default;
125
126 constexpr u64 GetAddress() const {
127 return this->first_region->GetAddress();
128 }
129
130 constexpr u64 GetLastAddress() const {
131 return this->last_region->GetLastAddress();
132 }
133
134 constexpr u64 GetEndAddress() const {
135 return this->GetLastAddress() + 1;
136 }
137
138 constexpr size_t GetSize() const {
139 return this->GetEndAddress() - this->GetAddress();
140 }
141 };
142
143private:
144 using TreeType =
145 Common::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>;
146
147public:
148 using value_type = TreeType::value_type;
149 using size_type = TreeType::size_type;
150 using difference_type = TreeType::difference_type;
151 using pointer = TreeType::pointer;
152 using const_pointer = TreeType::const_pointer;
153 using reference = TreeType::reference;
154 using const_reference = TreeType::const_reference;
155 using iterator = TreeType::iterator;
156 using const_iterator = TreeType::const_iterator;
157
158private:
159 TreeType m_tree{};
160 KMemoryRegionAllocator& memory_region_allocator;
161
162public:
163 explicit KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_);
164
165public:
166 KMemoryRegion* FindModifiable(u64 address) {
167 if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->end()) {
168 return std::addressof(*it);
169 } else {
170 return nullptr;
171 }
172 }
173
174 const KMemoryRegion* Find(u64 address) const {
175 if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->cend()) {
176 return std::addressof(*it);
177 } else {
178 return nullptr;
179 }
180 }
181
182 const KMemoryRegion* FindByType(KMemoryRegionType type_id) const {
183 for (auto it = this->cbegin(); it != this->cend(); ++it) {
184 if (it->GetType() == static_cast<u32>(type_id)) {
185 return std::addressof(*it);
186 }
187 }
188 return nullptr;
189 }
190
191 const KMemoryRegion* FindByTypeAndAttribute(u32 type_id, u32 attr) const {
192 for (auto it = this->cbegin(); it != this->cend(); ++it) {
193 if (it->GetType() == type_id && it->GetAttributes() == attr) {
194 return std::addressof(*it);
195 }
196 }
197 return nullptr;
198 }
199
200 const KMemoryRegion* FindFirstDerived(KMemoryRegionType type_id) const {
201 for (auto it = this->cbegin(); it != this->cend(); it++) {
202 if (it->IsDerivedFrom(type_id)) {
203 return std::addressof(*it);
204 }
205 }
206 return nullptr;
207 }
208
209 const KMemoryRegion* FindLastDerived(KMemoryRegionType type_id) const {
210 const KMemoryRegion* region = nullptr;
211 for (auto it = this->begin(); it != this->end(); it++) {
212 if (it->IsDerivedFrom(type_id)) {
213 region = std::addressof(*it);
214 }
215 }
216 return region;
217 }
218
219 DerivedRegionExtents GetDerivedRegionExtents(KMemoryRegionType type_id) const {
220 DerivedRegionExtents extents;
221
222 ASSERT(extents.first_region == nullptr);
223 ASSERT(extents.last_region == nullptr);
224
225 for (auto it = this->cbegin(); it != this->cend(); it++) {
226 if (it->IsDerivedFrom(type_id)) {
227 if (extents.first_region == nullptr) {
228 extents.first_region = std::addressof(*it);
229 }
230 extents.last_region = std::addressof(*it);
231 }
232 }
233
234 ASSERT(extents.first_region != nullptr);
235 ASSERT(extents.last_region != nullptr);
236
237 return extents;
238 }
239
240 DerivedRegionExtents GetDerivedRegionExtents(u32 type_id) const {
241 return GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
242 }
243
244public:
245 void InsertDirectly(u64 address, u64 last_address, u32 attr = 0, u32 type_id = 0);
246 bool Insert(u64 address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0);
247
248 VAddr GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);
249
250 VAddr GetRandomAlignedRegionWithGuard(size_t size, size_t alignment, u32 type_id,
251 size_t guard_size) {
252 return this->GetRandomAlignedRegion(size + 2 * guard_size, alignment, type_id) + guard_size;
253 }
254
255public:
256 // Iterator accessors.
257 iterator begin() {
258 return m_tree.begin();
259 }
260
261 const_iterator begin() const {
262 return m_tree.begin();
263 }
264
265 iterator end() {
266 return m_tree.end();
267 }
268
269 const_iterator end() const {
270 return m_tree.end();
271 }
272
273 const_iterator cbegin() const {
274 return this->begin();
275 }
276
277 const_iterator cend() const {
278 return this->end();
279 }
280
281 iterator iterator_to(reference ref) {
282 return m_tree.iterator_to(ref);
283 }
284
285 const_iterator iterator_to(const_reference ref) const {
286 return m_tree.iterator_to(ref);
287 }
288
289 // Content management.
290 bool empty() const {
291 return m_tree.empty();
292 }
293
294 reference back() {
295 return m_tree.back();
296 }
297
298 const_reference back() const {
299 return m_tree.back();
300 }
301
302 reference front() {
303 return m_tree.front();
304 }
305
306 const_reference front() const {
307 return m_tree.front();
308 }
309
310 iterator insert(reference ref) {
311 return m_tree.insert(ref);
312 }
313
314 iterator erase(iterator it) {
315 return m_tree.erase(it);
316 }
317
318 iterator find(const_reference ref) const {
319 return m_tree.find(ref);
320 }
321
322 iterator nfind(const_reference ref) const {
323 return m_tree.nfind(ref);
324 }
325};
326
327class KMemoryRegionAllocator final : NonCopyable {
328public:
329 static constexpr size_t MaxMemoryRegions = 200;
330
331 constexpr KMemoryRegionAllocator() = default;
332
333 template <typename... Args>
334 KMemoryRegion* Allocate(Args&&... args) {
335 // Ensure we stay within the bounds of our heap.
336 ASSERT(this->num_regions < MaxMemoryRegions);
337
338 // Create the new region.
339 KMemoryRegion* region = std::addressof(this->region_heap[this->num_regions++]);
340 new (region) KMemoryRegion(std::forward<Args>(args)...);
341
342 return region;
343 }
344
345private:
346 std::array<KMemoryRegion, MaxMemoryRegions> region_heap{};
347 size_t num_regions{};
348};
349
350} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_region_type.h b/src/core/hle/kernel/k_memory_region_type.h
new file mode 100644
index 000000000..a05e66677
--- /dev/null
+++ b/src/core/hle/kernel/k_memory_region_type.h
@@ -0,0 +1,338 @@
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 "common/bit_util.h"
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11#define ARCH_ARM64
12#define BOARD_NINTENDO_NX
13
14namespace Kernel {
15
16enum KMemoryRegionType : u32 {
17 KMemoryRegionAttr_CarveoutProtected = 0x04000000,
18 KMemoryRegionAttr_DidKernelMap = 0x08000000,
19 KMemoryRegionAttr_ShouldKernelMap = 0x10000000,
20 KMemoryRegionAttr_UserReadOnly = 0x20000000,
21 KMemoryRegionAttr_NoUserMap = 0x40000000,
22 KMemoryRegionAttr_LinearMapped = 0x80000000,
23};
24DECLARE_ENUM_FLAG_OPERATORS(KMemoryRegionType);
25
26namespace impl {
27
28constexpr size_t BitsForDeriveSparse(size_t n) {
29 return n + 1;
30}
31
32constexpr size_t BitsForDeriveDense(size_t n) {
33 size_t low = 0, high = 1;
34 for (size_t i = 0; i < n - 1; ++i) {
35 if ((++low) == high) {
36 ++high;
37 low = 0;
38 }
39 }
40 return high + 1;
41}
42
43class KMemoryRegionTypeValue {
44public:
45 using ValueType = std::underlying_type_t<KMemoryRegionType>;
46
47 constexpr KMemoryRegionTypeValue() = default;
48
49 constexpr operator KMemoryRegionType() const {
50 return static_cast<KMemoryRegionType>(m_value);
51 }
52
53 constexpr ValueType GetValue() const {
54 return m_value;
55 }
56
57 constexpr const KMemoryRegionTypeValue& Finalize() {
58 m_finalized = true;
59 return *this;
60 }
61
62 constexpr const KMemoryRegionTypeValue& SetSparseOnly() {
63 m_sparse_only = true;
64 return *this;
65 }
66
67 constexpr const KMemoryRegionTypeValue& SetDenseOnly() {
68 m_dense_only = true;
69 return *this;
70 }
71
72 constexpr KMemoryRegionTypeValue& SetAttribute(u32 attr) {
73 m_value |= attr;
74 return *this;
75 }
76
77 constexpr KMemoryRegionTypeValue DeriveInitial(
78 size_t i, size_t next = Common::BitSize<ValueType>()) const {
79 KMemoryRegionTypeValue new_type = *this;
80 new_type.m_value = (ValueType{1} << i);
81 new_type.m_next_bit = next;
82 return new_type;
83 }
84
85 constexpr KMemoryRegionTypeValue DeriveAttribute(u32 attr) const {
86 KMemoryRegionTypeValue new_type = *this;
87 new_type.m_value |= attr;
88 return new_type;
89 }
90
91 constexpr KMemoryRegionTypeValue DeriveTransition(size_t ofs = 0, size_t adv = 1) const {
92 KMemoryRegionTypeValue new_type = *this;
93 new_type.m_value |= (ValueType{1} << (m_next_bit + ofs));
94 new_type.m_next_bit += adv;
95 return new_type;
96 }
97
98 constexpr KMemoryRegionTypeValue DeriveSparse(size_t ofs, size_t n, size_t i) const {
99 KMemoryRegionTypeValue new_type = *this;
100 new_type.m_value |= (ValueType{1} << (m_next_bit + ofs));
101 new_type.m_value |= (ValueType{1} << (m_next_bit + ofs + 1 + i));
102 new_type.m_next_bit += ofs + n + 1;
103 return new_type;
104 }
105
106 constexpr KMemoryRegionTypeValue Derive(size_t n, size_t i) const {
107 size_t low = 0, high = 1;
108 for (size_t j = 0; j < i; ++j) {
109 if ((++low) == high) {
110 ++high;
111 low = 0;
112 }
113 }
114
115 KMemoryRegionTypeValue new_type = *this;
116 new_type.m_value |= (ValueType{1} << (m_next_bit + low));
117 new_type.m_value |= (ValueType{1} << (m_next_bit + high));
118 new_type.m_next_bit += BitsForDeriveDense(n);
119 return new_type;
120 }
121
122 constexpr KMemoryRegionTypeValue Advance(size_t n) const {
123 KMemoryRegionTypeValue new_type = *this;
124 new_type.m_next_bit += n;
125 return new_type;
126 }
127
128 constexpr bool IsAncestorOf(ValueType v) const {
129 return (m_value | v) == v;
130 }
131
132private:
133 constexpr KMemoryRegionTypeValue(ValueType v) : m_value(v) {}
134
135private:
136 ValueType m_value{};
137 size_t m_next_bit{};
138 bool m_finalized{};
139 bool m_sparse_only{};
140 bool m_dense_only{};
141};
142
143} // namespace impl
144
145constexpr auto KMemoryRegionType_None = impl::KMemoryRegionTypeValue();
146constexpr auto KMemoryRegionType_Kernel = KMemoryRegionType_None.DeriveInitial(0, 2);
147constexpr auto KMemoryRegionType_Dram = KMemoryRegionType_None.DeriveInitial(1, 2);
148static_assert(KMemoryRegionType_Kernel.GetValue() == 0x1);
149static_assert(KMemoryRegionType_Dram.GetValue() == 0x2);
150
151constexpr auto KMemoryRegionType_DramKernelBase =
152 KMemoryRegionType_Dram.DeriveSparse(0, 3, 0)
153 .SetAttribute(KMemoryRegionAttr_NoUserMap)
154 .SetAttribute(KMemoryRegionAttr_CarveoutProtected);
155constexpr auto KMemoryRegionType_DramReservedBase = KMemoryRegionType_Dram.DeriveSparse(0, 3, 1);
156constexpr auto KMemoryRegionType_DramHeapBase =
157 KMemoryRegionType_Dram.DeriveSparse(0, 3, 2).SetAttribute(KMemoryRegionAttr_LinearMapped);
158static_assert(KMemoryRegionType_DramKernelBase.GetValue() ==
159 (0xE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
160static_assert(KMemoryRegionType_DramReservedBase.GetValue() == (0x16));
161static_assert(KMemoryRegionType_DramHeapBase.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped));
162
163constexpr auto KMemoryRegionType_DramKernelCode =
164 KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 0);
165constexpr auto KMemoryRegionType_DramKernelSlab =
166 KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 1);
167constexpr auto KMemoryRegionType_DramKernelPtHeap =
168 KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 2).SetAttribute(
169 KMemoryRegionAttr_LinearMapped);
170constexpr auto KMemoryRegionType_DramKernelInitPt =
171 KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 3).SetAttribute(
172 KMemoryRegionAttr_LinearMapped);
173static_assert(KMemoryRegionType_DramKernelCode.GetValue() ==
174 (0xCE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
175static_assert(KMemoryRegionType_DramKernelSlab.GetValue() ==
176 (0x14E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
177static_assert(KMemoryRegionType_DramKernelPtHeap.GetValue() ==
178 (0x24E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
179 KMemoryRegionAttr_LinearMapped));
180static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() ==
181 (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
182 KMemoryRegionAttr_LinearMapped));
183
184constexpr auto KMemoryRegionType_DramReservedEarly =
185 KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
186static_assert(KMemoryRegionType_DramReservedEarly.GetValue() ==
187 (0x16 | KMemoryRegionAttr_NoUserMap));
188
189constexpr auto KMemoryRegionType_KernelTraceBuffer =
190 KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 0)
191 .SetAttribute(KMemoryRegionAttr_LinearMapped)
192 .SetAttribute(KMemoryRegionAttr_UserReadOnly);
193constexpr auto KMemoryRegionType_OnMemoryBootImage =
194 KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 1);
195constexpr auto KMemoryRegionType_DTB = KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 2);
196static_assert(KMemoryRegionType_KernelTraceBuffer.GetValue() ==
197 (0xD6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_UserReadOnly));
198static_assert(KMemoryRegionType_OnMemoryBootImage.GetValue() == 0x156);
199static_assert(KMemoryRegionType_DTB.GetValue() == 0x256);
200
201constexpr auto KMemoryRegionType_DramPoolPartition =
202 KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
203static_assert(KMemoryRegionType_DramPoolPartition.GetValue() ==
204 (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
205
206constexpr auto KMemoryRegionType_DramPoolManagement =
207 KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(
208 KMemoryRegionAttr_CarveoutProtected);
209constexpr auto KMemoryRegionType_DramUserPool =
210 KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
211static_assert(KMemoryRegionType_DramPoolManagement.GetValue() ==
212 (0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
213 KMemoryRegionAttr_CarveoutProtected));
214static_assert(KMemoryRegionType_DramUserPool.GetValue() ==
215 (0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
216
217constexpr auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
218constexpr auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
219constexpr auto KMemoryRegionType_DramSystemNonSecurePool =
220 KMemoryRegionType_DramUserPool.Derive(4, 2);
221constexpr auto KMemoryRegionType_DramSystemPool =
222 KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
223static_assert(KMemoryRegionType_DramApplicationPool.GetValue() ==
224 (0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
225static_assert(KMemoryRegionType_DramAppletPool.GetValue() ==
226 (0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
227static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() ==
228 (0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
229static_assert(KMemoryRegionType_DramSystemPool.GetValue() ==
230 (0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
231 KMemoryRegionAttr_CarveoutProtected));
232
233constexpr auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
234constexpr auto KMemoryRegionType_VirtualDramKernelPtHeap =
235 KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
236constexpr auto KMemoryRegionType_VirtualDramKernelTraceBuffer =
237 KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
238static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A);
239static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A);
240static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
241
242constexpr auto KMemoryRegionType_VirtualDramKernelInitPt =
243 KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
244constexpr auto KMemoryRegionType_VirtualDramPoolManagement =
245 KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
246constexpr auto KMemoryRegionType_VirtualDramUserPool =
247 KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
248static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x19A);
249static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
250static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x31A);
251
252// NOTE: For unknown reason, the pools are derived out-of-order here. It's worth eventually trying
253// to understand why Nintendo made this choice.
254// UNUSED: .Derive(6, 0);
255// UNUSED: .Derive(6, 1);
256constexpr auto KMemoryRegionType_VirtualDramAppletPool =
257 KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
258constexpr auto KMemoryRegionType_VirtualDramApplicationPool =
259 KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
260constexpr auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
261 KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
262constexpr auto KMemoryRegionType_VirtualDramSystemPool =
263 KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
264static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x1B1A);
265static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x271A);
266static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
267static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x331A);
268
269constexpr auto KMemoryRegionType_ArchDeviceBase =
270 KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
271constexpr auto KMemoryRegionType_BoardDeviceBase =
272 KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
273static_assert(KMemoryRegionType_ArchDeviceBase.GetValue() == 0x5);
274static_assert(KMemoryRegionType_BoardDeviceBase.GetValue() == 0x5);
275
276#if defined(ARCH_ARM64)
277#include "core/hle/kernel/arch/arm64/k_memory_region_device_types.inc"
278#elif defined(ARCH_ARM)
279#error "Unimplemented"
280#else
281// Default to no architecture devices.
282constexpr auto NumArchitectureDeviceRegions = 0;
283#endif
284static_assert(NumArchitectureDeviceRegions >= 0);
285
286#if defined(BOARD_NINTENDO_NX)
287#include "core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc"
288#else
289// Default to no board devices.
290constexpr auto NumBoardDeviceRegions = 0;
291#endif
292static_assert(NumBoardDeviceRegions >= 0);
293
294constexpr auto KMemoryRegionType_KernelCode = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 0);
295constexpr auto KMemoryRegionType_KernelStack = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 1);
296constexpr auto KMemoryRegionType_KernelMisc = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 2);
297constexpr auto KMemoryRegionType_KernelSlab = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 3);
298static_assert(KMemoryRegionType_KernelCode.GetValue() == 0x19);
299static_assert(KMemoryRegionType_KernelStack.GetValue() == 0x29);
300static_assert(KMemoryRegionType_KernelMisc.GetValue() == 0x49);
301static_assert(KMemoryRegionType_KernelSlab.GetValue() == 0x89);
302
303constexpr auto KMemoryRegionType_KernelMiscDerivedBase =
304 KMemoryRegionType_KernelMisc.DeriveTransition();
305static_assert(KMemoryRegionType_KernelMiscDerivedBase.GetValue() == 0x149);
306
307// UNUSED: .Derive(7, 0);
308constexpr auto KMemoryRegionType_KernelMiscMainStack =
309 KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 1);
310constexpr auto KMemoryRegionType_KernelMiscMappedDevice =
311 KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 2);
312constexpr auto KMemoryRegionType_KernelMiscExceptionStack =
313 KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 3);
314constexpr auto KMemoryRegionType_KernelMiscUnknownDebug =
315 KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 4);
316// UNUSED: .Derive(7, 5);
317constexpr auto KMemoryRegionType_KernelMiscIdleStack =
318 KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 6);
319static_assert(KMemoryRegionType_KernelMiscMainStack.GetValue() == 0xB49);
320static_assert(KMemoryRegionType_KernelMiscMappedDevice.GetValue() == 0xD49);
321static_assert(KMemoryRegionType_KernelMiscExceptionStack.GetValue() == 0x1349);
322static_assert(KMemoryRegionType_KernelMiscUnknownDebug.GetValue() == 0x1549);
323static_assert(KMemoryRegionType_KernelMiscIdleStack.GetValue() == 0x2349);
324
325constexpr auto KMemoryRegionType_KernelTemp = KMemoryRegionType_Kernel.Advance(2).Derive(2, 0);
326static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
327
328constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
329 if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
330 return KMemoryRegionType_VirtualDramKernelTraceBuffer;
331 } else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
332 return KMemoryRegionType_VirtualDramKernelPtHeap;
333 } else {
334 return KMemoryRegionType_Dram;
335 }
336}
337
338} // namespace Kernel
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
index d7a4a38e6..d05b34ea3 100644
--- a/src/core/hle/kernel/k_resource_limit.cpp
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -2,21 +2,16 @@
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// 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" 5#include "common/assert.h"
9#include "core/core.h"
10#include "core/core_timing.h" 6#include "core/core_timing.h"
11#include "core/core_timing_util.h"
12#include "core/hle/kernel/k_resource_limit.h" 7#include "core/hle/kernel/k_resource_limit.h"
13#include "core/hle/kernel/svc_results.h" 8#include "core/hle/kernel/svc_results.h"
14 9
15namespace Kernel { 10namespace Kernel {
16constexpr s64 DefaultTimeout = 10000000000; // 10 seconds 11constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
17 12
18KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system) 13KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_)
19 : Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {} 14 : Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {}
20KResourceLimit::~KResourceLimit() = default; 15KResourceLimit::~KResourceLimit() = default;
21 16
22s64 KResourceLimit::GetLimitValue(LimitableResource which) const { 17s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
@@ -83,7 +78,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
83} 78}
84 79
85bool KResourceLimit::Reserve(LimitableResource which, s64 value) { 80bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
86 return Reserve(which, value, system.CoreTiming().GetGlobalTimeNs().count() + DefaultTimeout); 81 return Reserve(which, value, core_timing.GetGlobalTimeNs().count() + DefaultTimeout);
87} 82}
88 83
89bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { 84bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
@@ -114,7 +109,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
114 } 109 }
115 110
116 if (current_hints[index] + value <= limit_values[index] && 111 if (current_hints[index] + value <= limit_values[index] &&
117 (timeout < 0 || system.CoreTiming().GetGlobalTimeNs().count() < timeout)) { 112 (timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) {
118 waiter_count++; 113 waiter_count++;
119 cond_var.Wait(&lock, timeout); 114 cond_var.Wait(&lock, timeout);
120 waiter_count--; 115 waiter_count--;
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h
index 58ae456f1..4542317d0 100644
--- a/src/core/hle/kernel/k_resource_limit.h
+++ b/src/core/hle/kernel/k_resource_limit.h
@@ -2,9 +2,6 @@
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// 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 5#pragma once
9 6
10#include <array> 7#include <array>
@@ -15,8 +12,8 @@
15 12
16union ResultCode; 13union ResultCode;
17 14
18namespace Core { 15namespace Core::Timing {
19class System; 16class CoreTiming;
20} 17}
21 18
22namespace Kernel { 19namespace Kernel {
@@ -37,7 +34,7 @@ constexpr bool IsValidResourceType(LimitableResource type) {
37 34
38class KResourceLimit final : public Object { 35class KResourceLimit final : public Object {
39public: 36public:
40 explicit KResourceLimit(KernelCore& kernel, Core::System& system); 37 explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_);
41 ~KResourceLimit(); 38 ~KResourceLimit();
42 39
43 s64 GetLimitValue(LimitableResource which) const; 40 s64 GetLimitValue(LimitableResource which) const;
@@ -75,7 +72,6 @@ private:
75 mutable KLightLock lock; 72 mutable KLightLock lock;
76 s32 waiter_count{}; 73 s32 waiter_count{};
77 KLightConditionVariable cond_var; 74 KLightConditionVariable cond_var;
78 KernelCore& kernel; 75 const Core::Timing::CoreTiming& core_timing;
79 Core::System& system;
80}; 76};
81} // namespace Kernel 77} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index e7de48476..d1df97305 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -62,7 +62,7 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
62} 62}
63 63
64u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { 64u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
65 std::scoped_lock lock{guard}; 65 KScopedSpinLock lk{guard};
66 if (KThread* prev_highest_thread = state.highest_priority_thread; 66 if (KThread* prev_highest_thread = state.highest_priority_thread;
67 prev_highest_thread != highest_thread) { 67 prev_highest_thread != highest_thread) {
68 if (prev_highest_thread != nullptr) { 68 if (prev_highest_thread != nullptr) {
@@ -637,11 +637,11 @@ void KScheduler::RescheduleCurrentCore() {
637 if (phys_core.IsInterrupted()) { 637 if (phys_core.IsInterrupted()) {
638 phys_core.ClearInterrupt(); 638 phys_core.ClearInterrupt();
639 } 639 }
640 guard.lock(); 640 guard.Lock();
641 if (state.needs_scheduling.load()) { 641 if (state.needs_scheduling.load()) {
642 Schedule(); 642 Schedule();
643 } else { 643 } else {
644 guard.unlock(); 644 guard.Unlock();
645 } 645 }
646} 646}
647 647
@@ -669,7 +669,7 @@ void KScheduler::Unload(KThread* thread) {
669 } else { 669 } else {
670 prev_thread = nullptr; 670 prev_thread = nullptr;
671 } 671 }
672 thread->context_guard.unlock(); 672 thread->context_guard.Unlock();
673 } 673 }
674} 674}
675 675
@@ -713,7 +713,7 @@ void KScheduler::ScheduleImpl() {
713 713
714 // If we're not actually switching thread, there's nothing to do. 714 // If we're not actually switching thread, there's nothing to do.
715 if (next_thread == current_thread.load()) { 715 if (next_thread == current_thread.load()) {
716 guard.unlock(); 716 guard.Unlock();
717 return; 717 return;
718 } 718 }
719 719
@@ -732,7 +732,7 @@ void KScheduler::ScheduleImpl() {
732 } else { 732 } else {
733 old_context = &idle_thread->GetHostContext(); 733 old_context = &idle_thread->GetHostContext();
734 } 734 }
735 guard.unlock(); 735 guard.Unlock();
736 736
737 Common::Fiber::YieldTo(*old_context, *switch_fiber); 737 Common::Fiber::YieldTo(*old_context, *switch_fiber);
738 /// When a thread wakes up, the scheduler may have changed to other in another core. 738 /// When a thread wakes up, the scheduler may have changed to other in another core.
@@ -748,24 +748,24 @@ void KScheduler::OnSwitch(void* this_scheduler) {
748void KScheduler::SwitchToCurrent() { 748void KScheduler::SwitchToCurrent() {
749 while (true) { 749 while (true) {
750 { 750 {
751 std::scoped_lock lock{guard}; 751 KScopedSpinLock lk{guard};
752 current_thread.store(state.highest_priority_thread); 752 current_thread.store(state.highest_priority_thread);
753 state.needs_scheduling.store(false); 753 state.needs_scheduling.store(false);
754 } 754 }
755 const auto is_switch_pending = [this] { 755 const auto is_switch_pending = [this] {
756 std::scoped_lock lock{guard}; 756 KScopedSpinLock lk{guard};
757 return state.needs_scheduling.load(); 757 return state.needs_scheduling.load();
758 }; 758 };
759 do { 759 do {
760 auto next_thread = current_thread.load(); 760 auto next_thread = current_thread.load();
761 if (next_thread != nullptr) { 761 if (next_thread != nullptr) {
762 next_thread->context_guard.lock(); 762 next_thread->context_guard.Lock();
763 if (next_thread->GetRawState() != ThreadState::Runnable) { 763 if (next_thread->GetRawState() != ThreadState::Runnable) {
764 next_thread->context_guard.unlock(); 764 next_thread->context_guard.Unlock();
765 break; 765 break;
766 } 766 }
767 if (next_thread->GetActiveCore() != core_id) { 767 if (next_thread->GetActiveCore() != core_id) {
768 next_thread->context_guard.unlock(); 768 next_thread->context_guard.Unlock();
769 break; 769 break;
770 } 770 }
771 } 771 }
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index f595b9a5c..8e32865aa 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -2,19 +2,16 @@
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// 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 5#pragma once
9 6
10#include <atomic> 7#include <atomic>
11 8
12#include "common/common_types.h" 9#include "common/common_types.h"
13#include "common/spin_lock.h"
14#include "core/hle/kernel/global_scheduler_context.h" 10#include "core/hle/kernel/global_scheduler_context.h"
15#include "core/hle/kernel/k_priority_queue.h" 11#include "core/hle/kernel/k_priority_queue.h"
16#include "core/hle/kernel/k_scheduler_lock.h" 12#include "core/hle/kernel/k_scheduler_lock.h"
17#include "core/hle/kernel/k_scoped_lock.h" 13#include "core/hle/kernel/k_scoped_lock.h"
14#include "core/hle/kernel/k_spin_lock.h"
18 15
19namespace Common { 16namespace Common {
20class Fiber; 17class Fiber;
@@ -195,12 +192,12 @@ private:
195 u64 last_context_switch_time{}; 192 u64 last_context_switch_time{};
196 const s32 core_id; 193 const s32 core_id;
197 194
198 Common::SpinLock guard{}; 195 KSpinLock guard{};
199}; 196};
200 197
201class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> { 198class [[nodiscard]] KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
202public: 199public:
203 explicit KScopedSchedulerLock(KernelCore& kernel); 200 explicit KScopedSchedulerLock(KernelCore & kernel);
204 ~KScopedSchedulerLock(); 201 ~KScopedSchedulerLock();
205}; 202};
206 203
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 169455d18..47e315555 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -2,14 +2,11 @@
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// 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 5#pragma once
9 6
10#include "common/assert.h" 7#include "common/assert.h"
11#include "common/spin_lock.h"
12#include "core/hardware_properties.h" 8#include "core/hardware_properties.h"
9#include "core/hle/kernel/k_spin_lock.h"
13#include "core/hle/kernel/k_thread.h" 10#include "core/hle/kernel/k_thread.h"
14#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
15 12
@@ -34,7 +31,7 @@ public:
34 } else { 31 } else {
35 // Otherwise, we want to disable scheduling and acquire the spinlock. 32 // Otherwise, we want to disable scheduling and acquire the spinlock.
36 SchedulerType::DisableScheduling(kernel); 33 SchedulerType::DisableScheduling(kernel);
37 spin_lock.lock(); 34 spin_lock.Lock();
38 35
39 // For debug, ensure that our state is valid. 36 // For debug, ensure that our state is valid.
40 ASSERT(lock_count == 0); 37 ASSERT(lock_count == 0);
@@ -58,7 +55,7 @@ public:
58 55
59 // Note that we no longer hold the lock, and unlock the spinlock. 56 // Note that we no longer hold the lock, and unlock the spinlock.
60 owner_thread = nullptr; 57 owner_thread = nullptr;
61 spin_lock.unlock(); 58 spin_lock.Unlock();
62 59
63 // Enable scheduling, and perform a rescheduling operation. 60 // Enable scheduling, and perform a rescheduling operation.
64 SchedulerType::EnableScheduling(kernel, cores_needing_scheduling); 61 SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
@@ -67,7 +64,7 @@ public:
67 64
68private: 65private:
69 KernelCore& kernel; 66 KernelCore& kernel;
70 Common::SpinLock spin_lock{}; 67 KAlignedSpinLock spin_lock{};
71 s32 lock_count{}; 68 s32 lock_count{};
72 KThread* owner_thread{}; 69 KThread* owner_thread{};
73}; 70};
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h
index d7cc557b2..72c3b0252 100644
--- a/src/core/hle/kernel/k_scoped_lock.h
+++ b/src/core/hle/kernel/k_scoped_lock.h
@@ -20,19 +20,22 @@ concept KLockable = !std::is_reference_v<T> && requires(T & t) {
20}; 20};
21 21
22template <typename T> 22template <typename T>
23requires KLockable<T> class KScopedLock { 23requires KLockable<T> class [[nodiscard]] KScopedLock {
24public: 24public:
25 explicit KScopedLock(T* l) : lock_ptr(l) { 25 explicit KScopedLock(T * l) : lock_ptr(l) {
26 this->lock_ptr->Lock(); 26 this->lock_ptr->Lock();
27 } 27 }
28 explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) { /* ... */ 28 explicit KScopedLock(T & l) : KScopedLock(std::addressof(l)) {}
29 } 29
30 ~KScopedLock() { 30 ~KScopedLock() {
31 this->lock_ptr->Unlock(); 31 this->lock_ptr->Unlock();
32 } 32 }
33 33
34 KScopedLock(const KScopedLock&) = delete; 34 KScopedLock(const KScopedLock&) = delete;
35 KScopedLock(KScopedLock&&) = delete; 35 KScopedLock& operator=(const KScopedLock&) = delete;
36
37 KScopedLock(KScopedLock &&) = delete;
38 KScopedLock& operator=(KScopedLock&&) = delete;
36 39
37private: 40private:
38 T* lock_ptr; 41 T* lock_ptr;
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 f8189e107..ebecf0c77 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
@@ -15,9 +15,9 @@
15 15
16namespace Kernel { 16namespace Kernel {
17 17
18class KScopedSchedulerLockAndSleep { 18class [[nodiscard]] KScopedSchedulerLockAndSleep {
19public: 19public:
20 explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout) 20 explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout)
21 : kernel(kernel), thread(t), timeout_tick(timeout) { 21 : kernel(kernel), thread(t), timeout_tick(timeout) {
22 // Lock the scheduler. 22 // Lock the scheduler.
23 kernel.GlobalSchedulerContext().scheduler_lock.Lock(); 23 kernel.GlobalSchedulerContext().scheduler_lock.Lock();
diff --git a/src/core/hle/kernel/k_spin_lock.h b/src/core/hle/kernel/k_spin_lock.h
index 12c4b2e88..4d87d006a 100644
--- a/src/core/hle/kernel/k_spin_lock.h
+++ b/src/core/hle/kernel/k_spin_lock.h
@@ -28,6 +28,12 @@ private:
28 std::atomic_flag lck = ATOMIC_FLAG_INIT; 28 std::atomic_flag lck = ATOMIC_FLAG_INIT;
29}; 29};
30 30
31// TODO(bunnei): Alias for now, in case we want to implement these accurately in the future.
32using KAlignedSpinLock = KSpinLock;
33using KNotAlignedSpinLock = KSpinLock;
34
31using KScopedSpinLock = KScopedLock<KSpinLock>; 35using KScopedSpinLock = KScopedLock<KSpinLock>;
36using KScopedAlignedSpinLock = KScopedLock<KAlignedSpinLock>;
37using KScopedNotAlignedSpinLock = KScopedLock<KNotAlignedSpinLock>;
32 38
33} // namespace Kernel 39} // namespace Kernel
diff --git a/src/core/hle/kernel/k_system_control.cpp b/src/core/hle/kernel/k_system_control.cpp
deleted file mode 100644
index aa1682f69..000000000
--- a/src/core/hle/kernel/k_system_control.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
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 <random>
6
7#include "core/hle/kernel/k_system_control.h"
8
9namespace Kernel {
10
11namespace {
12template <typename F>
13u64 GenerateUniformRange(u64 min, u64 max, F f) {
14 // Handle the case where the difference is too large to represent.
15 if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
16 return f();
17 }
18
19 // Iterate until we get a value in range.
20 const u64 range_size = ((max + 1) - min);
21 const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
22 while (true) {
23 if (const u64 rnd = f(); rnd < effective_max) {
24 return min + (rnd % range_size);
25 }
26 }
27}
28
29} // Anonymous namespace
30
31u64 KSystemControl::GenerateRandomU64() {
32 static std::random_device device;
33 static std::mt19937 gen(device());
34 static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
35 return distribution(gen);
36}
37
38u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
39 return GenerateUniformRange(min, max, GenerateRandomU64);
40}
41
42} // namespace Kernel
diff --git a/src/core/hle/kernel/k_system_control.h b/src/core/hle/kernel/k_system_control.h
index 1d5b64ffa..d755082c2 100644
--- a/src/core/hle/kernel/k_system_control.h
+++ b/src/core/hle/kernel/k_system_control.h
@@ -6,14 +6,18 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9namespace Kernel { 9#define BOARD_NINTENDO_NX
10
11#ifdef BOARD_NINTENDO_NX
10 12
11class KSystemControl { 13#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
12public:
13 KSystemControl() = default;
14 14
15 static u64 GenerateRandomRange(u64 min, u64 max); 15namespace Kernel {
16 static u64 GenerateRandomU64(); 16
17}; 17using Kernel::Board::Nintendo::Nx::KSystemControl;
18 18
19} // namespace Kernel 19} // namespace Kernel
20
21#else
22#error "Unknown board for KSystemControl"
23#endif
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 1c19b23dc..b442dfe57 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -14,10 +14,10 @@
14 14
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "common/intrusive_red_black_tree.h" 16#include "common/intrusive_red_black_tree.h"
17#include "common/spin_lock.h"
18#include "core/arm/arm_interface.h" 17#include "core/arm/arm_interface.h"
19#include "core/hle/kernel/k_affinity_mask.h" 18#include "core/hle/kernel/k_affinity_mask.h"
20#include "core/hle/kernel/k_light_lock.h" 19#include "core/hle/kernel/k_light_lock.h"
20#include "core/hle/kernel/k_spin_lock.h"
21#include "core/hle/kernel/k_synchronization_object.h" 21#include "core/hle/kernel/k_synchronization_object.h"
22#include "core/hle/kernel/object.h" 22#include "core/hle/kernel/object.h"
23#include "core/hle/kernel/svc_common.h" 23#include "core/hle/kernel/svc_common.h"
@@ -402,7 +402,7 @@ public:
402 return wait_cancelled; 402 return wait_cancelled;
403 } 403 }
404 404
405 [[nodiscard]] void ClearWaitCancelled() { 405 void ClearWaitCancelled() {
406 wait_cancelled = false; 406 wait_cancelled = false;
407 } 407 }
408 408
@@ -732,7 +732,7 @@ private:
732 s8 priority_inheritance_count{}; 732 s8 priority_inheritance_count{};
733 bool resource_limit_release_hint{}; 733 bool resource_limit_release_hint{};
734 StackParameters stack_parameters{}; 734 StackParameters stack_parameters{};
735 Common::SpinLock context_guard{}; 735 KSpinLock context_guard{};
736 736
737 // For emulation 737 // For emulation
738 std::shared_ptr<Common::Fiber> host_context{}; 738 std::shared_ptr<Common::Fiber> host_context{};
diff --git a/src/core/hle/kernel/k_trace.h b/src/core/hle/kernel/k_trace.h
new file mode 100644
index 000000000..91ebf9ab2
--- /dev/null
+++ b/src/core/hle/kernel/k_trace.h
@@ -0,0 +1,12 @@
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
7namespace Kernel {
8
9constexpr bool IsKTraceEnabled = false;
10constexpr std::size_t KTraceBufferSize = IsKTraceEnabled ? 16 * 1024 * 1024 : 0;
11
12} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 5b6c7792e..5c4f45ab4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1,4 +1,4 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2021 yuzu Emulator Project
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
@@ -12,6 +12,7 @@
12#include <utility> 12#include <utility>
13 13
14#include "common/assert.h" 14#include "common/assert.h"
15#include "common/common_sizes.h"
15#include "common/logging/log.h" 16#include "common/logging/log.h"
16#include "common/microprofile.h" 17#include "common/microprofile.h"
17#include "common/thread.h" 18#include "common/thread.h"
@@ -66,8 +67,13 @@ struct KernelCore::Impl {
66 is_phantom_mode_for_singlecore = false; 67 is_phantom_mode_for_singlecore = false;
67 68
68 InitializePhysicalCores(); 69 InitializePhysicalCores();
69 InitializeSystemResourceLimit(kernel, system); 70
70 InitializeMemoryLayout(); 71 // Derive the initial memory layout from the emulated board
72 KMemoryLayout memory_layout;
73 DeriveInitialMemoryLayout(memory_layout);
74 InitializeMemoryLayout(memory_layout);
75 InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout);
76 InitializeSlabHeaps();
71 InitializeSchedulers(); 77 InitializeSchedulers();
72 InitializeSuspendThreads(); 78 InitializeSuspendThreads();
73 InitializePreemption(kernel); 79 InitializePreemption(kernel);
@@ -136,27 +142,33 @@ struct KernelCore::Impl {
136 } 142 }
137 143
138 // Creates the default system resource limit 144 // Creates the default system resource limit
139 void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) { 145 void InitializeSystemResourceLimit(KernelCore& kernel,
140 system_resource_limit = std::make_shared<KResourceLimit>(kernel, system); 146 const Core::Timing::CoreTiming& core_timing,
147 const KMemoryLayout& memory_layout) {
148 system_resource_limit = std::make_shared<KResourceLimit>(kernel, core_timing);
149 const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes();
141 150
142 // If setting the default system values fails, then something seriously wrong has occurred. 151 // If setting the default system values fails, then something seriously wrong has occurred.
143 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000) 152 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size)
144 .IsSuccess()); 153 .IsSuccess());
145 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess()); 154 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
146 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess()); 155 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
147 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200) 156 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
148 .IsSuccess()); 157 .IsSuccess());
149 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 933).IsSuccess()); 158 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
159 system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size);
150 160
151 // Derived from recent software updates. The kernel reserves 27MB
152 constexpr u64 kernel_size{0x1b00000};
153 if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size)) {
154 UNREACHABLE();
155 }
156 // Reserve secure applet memory, introduced in firmware 5.0.0 161 // Reserve secure applet memory, introduced in firmware 5.0.0
157 constexpr u64 secure_applet_memory_size{0x400000}; 162 constexpr u64 secure_applet_memory_size{Common::Size_4_MB};
158 ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory, 163 ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
159 secure_applet_memory_size)); 164 secure_applet_memory_size));
165
166 // This memory seems to be reserved on hardware, but is not reserved/used by yuzu.
167 // Likely Horizon OS reserved memory
168 // TODO(ameerj): Derive the memory rather than hardcode it.
169 constexpr u64 unknown_reserved_memory{0x2f896000};
170 ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
171 unknown_reserved_memory));
160 } 172 }
161 173
162 void InitializePreemption(KernelCore& kernel) { 174 void InitializePreemption(KernelCore& kernel) {
@@ -268,51 +280,319 @@ struct KernelCore::Impl {
268 return schedulers[thread_id]->GetCurrentThread(); 280 return schedulers[thread_id]->GetCurrentThread();
269 } 281 }
270 282
271 void InitializeMemoryLayout() { 283 void DeriveInitialMemoryLayout(KMemoryLayout& memory_layout) {
272 // Initialize memory layout 284 // Insert the root region for the virtual memory tree, from which all other regions will
273 constexpr KMemoryLayout layout{KMemoryLayout::GetDefaultLayout()}; 285 // derive.
286 memory_layout.GetVirtualMemoryRegionTree().InsertDirectly(
287 KernelVirtualAddressSpaceBase,
288 KernelVirtualAddressSpaceBase + KernelVirtualAddressSpaceSize - 1);
289
290 // Insert the root region for the physical memory tree, from which all other regions will
291 // derive.
292 memory_layout.GetPhysicalMemoryRegionTree().InsertDirectly(
293 KernelPhysicalAddressSpaceBase,
294 KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1);
295
296 // Save start and end for ease of use.
297 const VAddr code_start_virt_addr = KernelVirtualAddressCodeBase;
298 const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
299
300 // Setup the containing kernel region.
301 constexpr size_t KernelRegionSize = Common::Size_1_GB;
302 constexpr size_t KernelRegionAlign = Common::Size_1_GB;
303 constexpr VAddr kernel_region_start =
304 Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
305 size_t kernel_region_size = KernelRegionSize;
306 if (!(kernel_region_start + KernelRegionSize - 1 <= KernelVirtualAddressSpaceLast)) {
307 kernel_region_size = KernelVirtualAddressSpaceEnd - kernel_region_start;
308 }
309 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
310 kernel_region_start, kernel_region_size, KMemoryRegionType_Kernel));
311
312 // Setup the code region.
313 constexpr size_t CodeRegionAlign = PageSize;
314 constexpr VAddr code_region_start =
315 Common::AlignDown(code_start_virt_addr, CodeRegionAlign);
316 constexpr VAddr code_region_end = Common::AlignUp(code_end_virt_addr, CodeRegionAlign);
317 constexpr size_t code_region_size = code_region_end - code_region_start;
318 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
319 code_region_start, code_region_size, KMemoryRegionType_KernelCode));
320
321 // Setup board-specific device physical regions.
322 Init::SetupDevicePhysicalMemoryRegions(memory_layout);
323
324 // Determine the amount of space needed for the misc region.
325 size_t misc_region_needed_size;
326 {
327 // Each core has a one page stack for all three stack types (Main, Idle, Exception).
328 misc_region_needed_size = Core::Hardware::NUM_CPU_CORES * (3 * (PageSize + PageSize));
329
330 // Account for each auto-map device.
331 for (const auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
332 if (region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
333 // Check that the region is valid.
334 ASSERT(region.GetEndAddress() != 0);
335
336 // Account for the region.
337 misc_region_needed_size +=
338 PageSize + (Common::AlignUp(region.GetLastAddress(), PageSize) -
339 Common::AlignDown(region.GetAddress(), PageSize));
340 }
341 }
342
343 // Multiply the needed size by three, to account for the need for guard space.
344 misc_region_needed_size *= 3;
345 }
346
347 // Decide on the actual size for the misc region.
348 constexpr size_t MiscRegionAlign = KernelAslrAlignment;
349 constexpr size_t MiscRegionMinimumSize = Common::Size_32_MB;
350 const size_t misc_region_size = Common::AlignUp(
351 std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
352 ASSERT(misc_region_size > 0);
353
354 // Setup the misc region.
355 const VAddr misc_region_start =
356 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
357 misc_region_size, MiscRegionAlign, KMemoryRegionType_Kernel);
358 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
359 misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
360
361 // Setup the stack region.
362 constexpr size_t StackRegionSize = Common::Size_14_MB;
363 constexpr size_t StackRegionAlign = KernelAslrAlignment;
364 const VAddr stack_region_start =
365 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
366 StackRegionSize, StackRegionAlign, KMemoryRegionType_Kernel);
367 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
368 stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
369
370 // Determine the size of the resource region.
371 const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit();
372
373 // Determine the size of the slab region.
374 const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize);
375 ASSERT(slab_region_size <= resource_region_size);
376
377 // Setup the slab region.
378 const PAddr code_start_phys_addr = KernelPhysicalAddressCodeBase;
379 const PAddr code_end_phys_addr = code_start_phys_addr + code_region_size;
380 const PAddr slab_start_phys_addr = code_end_phys_addr;
381 const PAddr slab_end_phys_addr = slab_start_phys_addr + slab_region_size;
382 constexpr size_t SlabRegionAlign = KernelAslrAlignment;
383 const size_t slab_region_needed_size =
384 Common::AlignUp(code_end_phys_addr + slab_region_size, SlabRegionAlign) -
385 Common::AlignDown(code_end_phys_addr, SlabRegionAlign);
386 const VAddr slab_region_start =
387 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
388 slab_region_needed_size, SlabRegionAlign, KMemoryRegionType_Kernel) +
389 (code_end_phys_addr % SlabRegionAlign);
390 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
391 slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
392
393 // Setup the temp region.
394 constexpr size_t TempRegionSize = Common::Size_128_MB;
395 constexpr size_t TempRegionAlign = KernelAslrAlignment;
396 const VAddr temp_region_start =
397 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
398 TempRegionSize, TempRegionAlign, KMemoryRegionType_Kernel);
399 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(temp_region_start, TempRegionSize,
400 KMemoryRegionType_KernelTemp));
401
402 // Automatically map in devices that have auto-map attributes.
403 for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
404 // We only care about kernel regions.
405 if (!region.IsDerivedFrom(KMemoryRegionType_Kernel)) {
406 continue;
407 }
408
409 // Check whether we should map the region.
410 if (!region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
411 continue;
412 }
413
414 // If this region has already been mapped, no need to consider it.
415 if (region.HasTypeAttribute(KMemoryRegionAttr_DidKernelMap)) {
416 continue;
417 }
418
419 // Check that the region is valid.
420 ASSERT(region.GetEndAddress() != 0);
421
422 // Set the attribute to note we've mapped this region.
423 region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap);
424
425 // Create a virtual pair region and insert it into the tree.
426 const PAddr map_phys_addr = Common::AlignDown(region.GetAddress(), PageSize);
427 const size_t map_size =
428 Common::AlignUp(region.GetEndAddress(), PageSize) - map_phys_addr;
429 const VAddr map_virt_addr =
430 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
431 map_size, PageSize, KMemoryRegionType_KernelMisc, PageSize);
432 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
433 map_virt_addr, map_size, KMemoryRegionType_KernelMiscMappedDevice));
434 region.SetPairAddress(map_virt_addr + region.GetAddress() - map_phys_addr);
435 }
436
437 Init::SetupDramPhysicalMemoryRegions(memory_layout);
438
439 // Insert a physical region for the kernel code region.
440 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
441 code_start_phys_addr, code_region_size, KMemoryRegionType_DramKernelCode));
442
443 // Insert a physical region for the kernel slab region.
444 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
445 slab_start_phys_addr, slab_region_size, KMemoryRegionType_DramKernelSlab));
446
447 // Determine size available for kernel page table heaps, requiring > 8 MB.
448 const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
449 const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
450 ASSERT(page_table_heap_size / Common::Size_4_MB > 2);
451
452 // Insert a physical region for the kernel page table heap region
453 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
454 slab_end_phys_addr, page_table_heap_size, KMemoryRegionType_DramKernelPtHeap));
455
456 // All DRAM regions that we haven't tagged by this point will be mapped under the linear
457 // mapping. Tag them.
458 for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
459 if (region.GetType() == KMemoryRegionType_Dram) {
460 // Check that the region is valid.
461 ASSERT(region.GetEndAddress() != 0);
462
463 // Set the linear map attribute.
464 region.SetTypeAttribute(KMemoryRegionAttr_LinearMapped);
465 }
466 }
467
468 // Get the linear region extents.
469 const auto linear_extents =
470 memory_layout.GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
471 KMemoryRegionAttr_LinearMapped);
472 ASSERT(linear_extents.GetEndAddress() != 0);
473
474 // Setup the linear mapping region.
475 constexpr size_t LinearRegionAlign = Common::Size_1_GB;
476 const PAddr aligned_linear_phys_start =
477 Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
478 const size_t linear_region_size =
479 Common::AlignUp(linear_extents.GetEndAddress(), LinearRegionAlign) -
480 aligned_linear_phys_start;
481 const VAddr linear_region_start =
482 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
483 linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign);
484
485 const u64 linear_region_phys_to_virt_diff = linear_region_start - aligned_linear_phys_start;
486
487 // Map and create regions for all the linearly-mapped data.
488 {
489 PAddr cur_phys_addr = 0;
490 u64 cur_size = 0;
491 for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
492 if (!region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
493 continue;
494 }
495
496 ASSERT(region.GetEndAddress() != 0);
497
498 if (cur_size == 0) {
499 cur_phys_addr = region.GetAddress();
500 cur_size = region.GetSize();
501 } else if (cur_phys_addr + cur_size == region.GetAddress()) {
502 cur_size += region.GetSize();
503 } else {
504 cur_phys_addr = region.GetAddress();
505 cur_size = region.GetSize();
506 }
507
508 const VAddr region_virt_addr =
509 region.GetAddress() + linear_region_phys_to_virt_diff;
510 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
511 region_virt_addr, region.GetSize(),
512 GetTypeForVirtualLinearMapping(region.GetType())));
513 region.SetPairAddress(region_virt_addr);
514
515 KMemoryRegion* virt_region =
516 memory_layout.GetVirtualMemoryRegionTree().FindModifiable(region_virt_addr);
517 ASSERT(virt_region != nullptr);
518 virt_region->SetPairAddress(region.GetAddress());
519 }
520 }
521
522 // Insert regions for the initial page table region.
523 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
524 resource_end_phys_addr, KernelPageTableHeapSize, KMemoryRegionType_DramKernelInitPt));
525 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
526 resource_end_phys_addr + linear_region_phys_to_virt_diff, KernelPageTableHeapSize,
527 KMemoryRegionType_VirtualDramKernelInitPt));
528
529 // All linear-mapped DRAM regions that we haven't tagged by this point will be allocated to
530 // some pool partition. Tag them.
531 for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
532 if (region.GetType() == (KMemoryRegionType_Dram | KMemoryRegionAttr_LinearMapped)) {
533 region.SetType(KMemoryRegionType_DramPoolPartition);
534 }
535 }
536
537 // Setup all other memory regions needed to arrange the pool partitions.
538 Init::SetupPoolPartitionMemoryRegions(memory_layout);
539
540 // Cache all linear regions in their own trees for faster access, later.
541 memory_layout.InitializeLinearMemoryRegionTrees(aligned_linear_phys_start,
542 linear_region_start);
543 }
544
545 void InitializeMemoryLayout(const KMemoryLayout& memory_layout) {
546 const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
547 const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
548 const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
549
550 // Initialize memory managers
551 memory_manager = std::make_unique<KMemoryManager>();
552 memory_manager->InitializeManager(KMemoryManager::Pool::Application,
553 application_pool.GetAddress(),
554 application_pool.GetEndAddress());
555 memory_manager->InitializeManager(KMemoryManager::Pool::Applet, applet_pool.GetAddress(),
556 applet_pool.GetEndAddress());
557 memory_manager->InitializeManager(KMemoryManager::Pool::System, system_pool.GetAddress(),
558 system_pool.GetEndAddress());
559
560 // Setup memory regions for emulated processes
561 // TODO(bunnei): These should not be hardcoded regions initialized within the kernel
274 constexpr std::size_t hid_size{0x40000}; 562 constexpr std::size_t hid_size{0x40000};
275 constexpr std::size_t font_size{0x1100000}; 563 constexpr std::size_t font_size{0x1100000};
276 constexpr std::size_t irs_size{0x8000}; 564 constexpr std::size_t irs_size{0x8000};
277 constexpr std::size_t time_size{0x1000}; 565 constexpr std::size_t time_size{0x1000};
278 constexpr PAddr hid_addr{layout.System().StartAddress()};
279 constexpr PAddr font_pa{layout.System().StartAddress() + hid_size};
280 constexpr PAddr irs_addr{layout.System().StartAddress() + hid_size + font_size};
281 constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
282 566
283 // Initialize memory manager 567 const PAddr hid_phys_addr{system_pool.GetAddress()};
284 memory_manager = std::make_unique<KMemoryManager>(); 568 const PAddr font_phys_addr{system_pool.GetAddress() + hid_size};
285 memory_manager->InitializeManager(KMemoryManager::Pool::Application, 569 const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
286 layout.Application().StartAddress(), 570 const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
287 layout.Application().EndAddress());
288 memory_manager->InitializeManager(KMemoryManager::Pool::Applet,
289 layout.Applet().StartAddress(),
290 layout.Applet().EndAddress());
291 memory_manager->InitializeManager(KMemoryManager::Pool::System,
292 layout.System().StartAddress(),
293 layout.System().EndAddress());
294 571
295 hid_shared_mem = Kernel::KSharedMemory::Create( 572 hid_shared_mem = Kernel::KSharedMemory::Create(
296 system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / PageSize}, 573 system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize},
297 KMemoryPermission::None, KMemoryPermission::Read, hid_addr, hid_size, 574 KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size,
298 "HID:SharedMemory"); 575 "HID:SharedMemory");
299 font_shared_mem = Kernel::KSharedMemory::Create( 576 font_shared_mem = Kernel::KSharedMemory::Create(
300 system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / PageSize}, 577 system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize},
301 KMemoryPermission::None, KMemoryPermission::Read, font_pa, font_size, 578 KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size,
302 "Font:SharedMemory"); 579 "Font:SharedMemory");
303 irs_shared_mem = Kernel::KSharedMemory::Create( 580 irs_shared_mem = Kernel::KSharedMemory::Create(
304 system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / PageSize}, 581 system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize},
305 KMemoryPermission::None, KMemoryPermission::Read, irs_addr, irs_size, 582 KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size,
306 "IRS:SharedMemory"); 583 "IRS:SharedMemory");
307 time_shared_mem = Kernel::KSharedMemory::Create( 584 time_shared_mem = Kernel::KSharedMemory::Create(
308 system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / PageSize}, 585 system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
309 KMemoryPermission::None, KMemoryPermission::Read, time_addr, time_size, 586 KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
310 "Time:SharedMemory"); 587 "Time:SharedMemory");
588 }
311 589
590 void InitializeSlabHeaps() {
312 // Allocate slab heaps 591 // Allocate slab heaps
313 user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>(); 592 user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
314 593
315 constexpr u64 user_slab_heap_size{0x1ef000}; 594 // TODO(ameerj): This should be derived, not hardcoded within the kernel
595 constexpr u64 user_slab_heap_size{0x3de000};
316 // Reserve slab heaps 596 // Reserve slab heaps
317 ASSERT( 597 ASSERT(
318 system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size)); 598 system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size));
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 56906f2da..a500e63bc 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -1,4 +1,4 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2021 yuzu Emulator Project
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
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 9d5956ead..e35deb8e2 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -10,6 +10,7 @@
10#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/assert.h" 11#include "common/assert.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/settings.h"
13#include "core/core.h" 14#include "core/core.h"
14#include "core/device_memory.h" 15#include "core/device_memory.h"
15#include "core/file_sys/program_metadata.h" 16#include "core/file_sys/program_metadata.h"
@@ -26,7 +27,6 @@
26#include "core/hle/kernel/svc_results.h" 27#include "core/hle/kernel/svc_results.h"
27#include "core/hle/lock.h" 28#include "core/hle/lock.h"
28#include "core/memory.h" 29#include "core/memory.h"
29#include "core/settings.h"
30 30
31namespace Kernel { 31namespace Kernel {
32namespace { 32namespace {
@@ -120,9 +120,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
120 std::shared_ptr<Process> process = std::make_shared<Process>(system); 120 std::shared_ptr<Process> process = std::make_shared<Process>(system);
121 process->name = std::move(name); 121 process->name = std::move(name);
122 122
123 // TODO: This is inaccurate 123 process->resource_limit = kernel.GetSystemResourceLimit();
124 // The process should hold a reference to the kernel-wide resource limit.
125 process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
126 process->status = ProcessStatus::Created; 124 process->status = ProcessStatus::Created;
127 process->program_id = 0; 125 process->program_id = 0;
128 process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() 126 process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@@ -160,17 +158,13 @@ void Process::DecrementThreadCount() {
160} 158}
161 159
162u64 Process::GetTotalPhysicalMemoryAvailable() const { 160u64 Process::GetTotalPhysicalMemoryAvailable() const {
163 // TODO: This is expected to always return the application memory pool size after accurately
164 // reserving kernel resources. The current workaround uses a process-local resource limit of
165 // application memory pool size, which is inaccurate.
166 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + 161 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
167 page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + 162 page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
168 main_thread_stack_size}; 163 main_thread_stack_size};
169 164 ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
170 if (capacity < memory_usage_capacity) { 165 if (capacity < memory_usage_capacity) {
171 return capacity; 166 return capacity;
172 } 167 }
173
174 return memory_usage_capacity; 168 return memory_usage_capacity;
175} 169}
176 170
@@ -272,10 +266,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
272 system_resource_size = metadata.GetSystemResourceSize(); 266 system_resource_size = metadata.GetSystemResourceSize();
273 image_size = code_size; 267 image_size = code_size;
274 268
275 // Set initial resource limits
276 resource_limit->SetLimitValue(
277 LimitableResource::PhysicalMemory,
278 kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
279 KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, 269 KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
280 code_size + system_resource_size); 270 code_size + system_resource_size);
281 if (!memory_reservation.Succeeded()) { 271 if (!memory_reservation.Succeeded()) {
@@ -324,16 +314,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
324 UNREACHABLE(); 314 UNREACHABLE();
325 } 315 }
326 316
327 // Set initial resource limits
328 resource_limit->SetLimitValue(
329 LimitableResource::PhysicalMemory,
330 kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
331
332 resource_limit->SetLimitValue(LimitableResource::Threads, 608);
333 resource_limit->SetLimitValue(LimitableResource::Events, 700);
334 resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
335 resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
336
337 // Create TLS region 317 // Create TLS region
338 tls_region_address = CreateTLSRegion(); 318 tls_region_address = CreateTLSRegion();
339 memory_reservation.Commit(); 319 memory_reservation.Commit();
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp
index 3fc326eab..1006ee50c 100644
--- a/src/core/hle/kernel/process_capability.cpp
+++ b/src/core/hle/kernel/process_capability.cpp
@@ -281,11 +281,6 @@ ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags)
281 continue; 281 continue;
282 } 282 }
283 283
284 if (svc_number >= svc_capabilities.size()) {
285 LOG_ERROR(Kernel, "Process svc capability is out of range! svc_number={}", svc_number);
286 return ResultOutOfRange;
287 }
288
289 svc_capabilities[svc_number] = true; 284 svc_capabilities[svc_number] = true;
290 } 285 }
291 286
diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h
index 73ad197fa..b7a9b2e45 100644
--- a/src/core/hle/kernel/process_capability.h
+++ b/src/core/hle/kernel/process_capability.h
@@ -68,7 +68,7 @@ enum class ProgramType {
68class ProcessCapabilities { 68class ProcessCapabilities {
69public: 69public:
70 using InterruptCapabilities = std::bitset<1024>; 70 using InterruptCapabilities = std::bitset<1024>;
71 using SyscallCapabilities = std::bitset<128>; 71 using SyscallCapabilities = std::bitset<192>;
72 72
73 ProcessCapabilities() = default; 73 ProcessCapabilities() = default;
74 ProcessCapabilities(const ProcessCapabilities&) = delete; 74 ProcessCapabilities(const ProcessCapabilities&) = delete;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 326d3b9ec..bebb86154 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2156,7 +2156,7 @@ static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle)
2156 LOG_DEBUG(Kernel_SVC, "called"); 2156 LOG_DEBUG(Kernel_SVC, "called");
2157 2157
2158 auto& kernel = system.Kernel(); 2158 auto& kernel = system.Kernel();
2159 auto resource_limit = std::make_shared<KResourceLimit>(kernel, system); 2159 auto resource_limit = std::make_shared<KResourceLimit>(kernel, system.CoreTiming());
2160 2160
2161 auto* const current_process = kernel.CurrentProcess(); 2161 auto* const current_process = kernel.CurrentProcess();
2162 ASSERT(current_process != nullptr); 2162 ASSERT(current_process != nullptr);
@@ -2455,6 +2455,74 @@ static const FunctionDef SVC_Table_32[] = {
2455 {0x79, nullptr, "Unknown"}, 2455 {0x79, nullptr, "Unknown"},
2456 {0x7A, nullptr, "Unknown"}, 2456 {0x7A, nullptr, "Unknown"},
2457 {0x7B, nullptr, "TerminateProcess32"}, 2457 {0x7B, nullptr, "TerminateProcess32"},
2458 {0x7C, nullptr, "GetProcessInfo32"},
2459 {0x7D, nullptr, "CreateResourceLimit32"},
2460 {0x7E, nullptr, "SetResourceLimitLimitValue32"},
2461 {0x7F, nullptr, "CallSecureMonitor32"},
2462 {0x80, nullptr, "Unknown"},
2463 {0x81, nullptr, "Unknown"},
2464 {0x82, nullptr, "Unknown"},
2465 {0x83, nullptr, "Unknown"},
2466 {0x84, nullptr, "Unknown"},
2467 {0x85, nullptr, "Unknown"},
2468 {0x86, nullptr, "Unknown"},
2469 {0x87, nullptr, "Unknown"},
2470 {0x88, nullptr, "Unknown"},
2471 {0x89, nullptr, "Unknown"},
2472 {0x8A, nullptr, "Unknown"},
2473 {0x8B, nullptr, "Unknown"},
2474 {0x8C, nullptr, "Unknown"},
2475 {0x8D, nullptr, "Unknown"},
2476 {0x8E, nullptr, "Unknown"},
2477 {0x8F, nullptr, "Unknown"},
2478 {0x90, nullptr, "Unknown"},
2479 {0x91, nullptr, "Unknown"},
2480 {0x92, nullptr, "Unknown"},
2481 {0x93, nullptr, "Unknown"},
2482 {0x94, nullptr, "Unknown"},
2483 {0x95, nullptr, "Unknown"},
2484 {0x96, nullptr, "Unknown"},
2485 {0x97, nullptr, "Unknown"},
2486 {0x98, nullptr, "Unknown"},
2487 {0x99, nullptr, "Unknown"},
2488 {0x9A, nullptr, "Unknown"},
2489 {0x9B, nullptr, "Unknown"},
2490 {0x9C, nullptr, "Unknown"},
2491 {0x9D, nullptr, "Unknown"},
2492 {0x9E, nullptr, "Unknown"},
2493 {0x9F, nullptr, "Unknown"},
2494 {0xA0, nullptr, "Unknown"},
2495 {0xA1, nullptr, "Unknown"},
2496 {0xA2, nullptr, "Unknown"},
2497 {0xA3, nullptr, "Unknown"},
2498 {0xA4, nullptr, "Unknown"},
2499 {0xA5, nullptr, "Unknown"},
2500 {0xA6, nullptr, "Unknown"},
2501 {0xA7, nullptr, "Unknown"},
2502 {0xA8, nullptr, "Unknown"},
2503 {0xA9, nullptr, "Unknown"},
2504 {0xAA, nullptr, "Unknown"},
2505 {0xAB, nullptr, "Unknown"},
2506 {0xAC, nullptr, "Unknown"},
2507 {0xAD, nullptr, "Unknown"},
2508 {0xAE, nullptr, "Unknown"},
2509 {0xAF, nullptr, "Unknown"},
2510 {0xB0, nullptr, "Unknown"},
2511 {0xB1, nullptr, "Unknown"},
2512 {0xB2, nullptr, "Unknown"},
2513 {0xB3, nullptr, "Unknown"},
2514 {0xB4, nullptr, "Unknown"},
2515 {0xB5, nullptr, "Unknown"},
2516 {0xB6, nullptr, "Unknown"},
2517 {0xB7, nullptr, "Unknown"},
2518 {0xB8, nullptr, "Unknown"},
2519 {0xB9, nullptr, "Unknown"},
2520 {0xBA, nullptr, "Unknown"},
2521 {0xBB, nullptr, "Unknown"},
2522 {0xBC, nullptr, "Unknown"},
2523 {0xBD, nullptr, "Unknown"},
2524 {0xBE, nullptr, "Unknown"},
2525 {0xBF, nullptr, "Unknown"},
2458}; 2526};
2459 2527
2460static const FunctionDef SVC_Table_64[] = { 2528static const FunctionDef SVC_Table_64[] = {
@@ -2586,6 +2654,70 @@ static const FunctionDef SVC_Table_64[] = {
2586 {0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"}, 2654 {0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"},
2587 {0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"}, 2655 {0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
2588 {0x7F, nullptr, "CallSecureMonitor"}, 2656 {0x7F, nullptr, "CallSecureMonitor"},
2657 {0x80, nullptr, "Unknown"},
2658 {0x81, nullptr, "Unknown"},
2659 {0x82, nullptr, "Unknown"},
2660 {0x83, nullptr, "Unknown"},
2661 {0x84, nullptr, "Unknown"},
2662 {0x85, nullptr, "Unknown"},
2663 {0x86, nullptr, "Unknown"},
2664 {0x87, nullptr, "Unknown"},
2665 {0x88, nullptr, "Unknown"},
2666 {0x89, nullptr, "Unknown"},
2667 {0x8A, nullptr, "Unknown"},
2668 {0x8B, nullptr, "Unknown"},
2669 {0x8C, nullptr, "Unknown"},
2670 {0x8D, nullptr, "Unknown"},
2671 {0x8E, nullptr, "Unknown"},
2672 {0x8F, nullptr, "Unknown"},
2673 {0x90, nullptr, "Unknown"},
2674 {0x91, nullptr, "Unknown"},
2675 {0x92, nullptr, "Unknown"},
2676 {0x93, nullptr, "Unknown"},
2677 {0x94, nullptr, "Unknown"},
2678 {0x95, nullptr, "Unknown"},
2679 {0x96, nullptr, "Unknown"},
2680 {0x97, nullptr, "Unknown"},
2681 {0x98, nullptr, "Unknown"},
2682 {0x99, nullptr, "Unknown"},
2683 {0x9A, nullptr, "Unknown"},
2684 {0x9B, nullptr, "Unknown"},
2685 {0x9C, nullptr, "Unknown"},
2686 {0x9D, nullptr, "Unknown"},
2687 {0x9E, nullptr, "Unknown"},
2688 {0x9F, nullptr, "Unknown"},
2689 {0xA0, nullptr, "Unknown"},
2690 {0xA1, nullptr, "Unknown"},
2691 {0xA2, nullptr, "Unknown"},
2692 {0xA3, nullptr, "Unknown"},
2693 {0xA4, nullptr, "Unknown"},
2694 {0xA5, nullptr, "Unknown"},
2695 {0xA6, nullptr, "Unknown"},
2696 {0xA7, nullptr, "Unknown"},
2697 {0xA8, nullptr, "Unknown"},
2698 {0xA9, nullptr, "Unknown"},
2699 {0xAA, nullptr, "Unknown"},
2700 {0xAB, nullptr, "Unknown"},
2701 {0xAC, nullptr, "Unknown"},
2702 {0xAD, nullptr, "Unknown"},
2703 {0xAE, nullptr, "Unknown"},
2704 {0xAF, nullptr, "Unknown"},
2705 {0xB0, nullptr, "Unknown"},
2706 {0xB1, nullptr, "Unknown"},
2707 {0xB2, nullptr, "Unknown"},
2708 {0xB3, nullptr, "Unknown"},
2709 {0xB4, nullptr, "Unknown"},
2710 {0xB5, nullptr, "Unknown"},
2711 {0xB6, nullptr, "Unknown"},
2712 {0xB7, nullptr, "Unknown"},
2713 {0xB8, nullptr, "Unknown"},
2714 {0xB9, nullptr, "Unknown"},
2715 {0xBA, nullptr, "Unknown"},
2716 {0xBB, nullptr, "Unknown"},
2717 {0xBC, nullptr, "Unknown"},
2718 {0xBD, nullptr, "Unknown"},
2719 {0xBE, nullptr, "Unknown"},
2720 {0xBF, nullptr, "Unknown"},
2589}; 2721};
2590 2722
2591static const FunctionDef* GetSVCInfo32(u32 func_num) { 2723static const FunctionDef* GetSVCInfo32(u32 func_num) {
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 615e20a54..52535ecc0 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -610,12 +610,17 @@ public:
610 explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} { 610 explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} {
611 // clang-format off 611 // clang-format off
612 static const FunctionInfo functions[] = { 612 static const FunctionInfo functions[] = {
613 {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData 613 {0, nullptr, "EnsureAuthenticationTokenCacheAsync"},
614 {1, nullptr, "LoadAuthenticationTokenCache"}, // 6.0.0+ 614 {1, nullptr, "LoadAuthenticationTokenCache"},
615 {2, nullptr, "InvalidateAuthenticationTokenCache"}, // 6.0.0+ 615 {2, nullptr, "InvalidateAuthenticationTokenCache"},
616 {10, nullptr, "EnsureEdgeTokenCacheAsync"}, // 6.0.0+ 616 {10, nullptr, "EnsureEdgeTokenCacheAsync"},
617 {11, nullptr, "LoadEdgeTokenCache"}, // 6.0.0+ 617 {11, nullptr, "LoadEdgeTokenCache"},
618 {12, nullptr, "InvalidateEdgeTokenCache"}, // 6.0.0+ 618 {12, nullptr, "InvalidateEdgeTokenCache"},
619 {20, nullptr, "EnsureApplicationAuthenticationCacheAsync"},
620 {21, nullptr, "LoadApplicationAuthenticationTokenCache"},
621 {22, nullptr, "LoadApplicationNetworkServiceClientConfigCache"},
622 {23, nullptr, "IsApplicationAuthenticationCacheAvailable"},
623 {24, nullptr, "InvalidateApplicationAuthenticationCache"},
619 }; 624 };
620 // clang-format on 625 // clang-format on
621 626
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index 49b22583e..bb6118abf 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -17,28 +17,30 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
17 {3, &ACC_SU::ListOpenUsers, "ListOpenUsers"}, 17 {3, &ACC_SU::ListOpenUsers, "ListOpenUsers"},
18 {4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"}, 18 {4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"},
19 {5, &ACC_SU::GetProfile, "GetProfile"}, 19 {5, &ACC_SU::GetProfile, "GetProfile"},
20 {6, nullptr, "GetProfileDigest"}, // 3.0.0+ 20 {6, nullptr, "GetProfileDigest"},
21 {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, 21 {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
22 {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, 22 {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
23 {60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 23 {60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
24 {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ 24 {99, nullptr, "DebugActivateOpenContextRetention"},
25 {100, nullptr, "GetUserRegistrationNotifier"}, 25 {100, nullptr, "GetUserRegistrationNotifier"},
26 {101, nullptr, "GetUserStateChangeNotifier"}, 26 {101, nullptr, "GetUserStateChangeNotifier"},
27 {102, nullptr, "GetBaasAccountManagerForSystemService"}, 27 {102, nullptr, "GetBaasAccountManagerForSystemService"},
28 {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, 28 {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
29 {104, nullptr, "GetProfileUpdateNotifier"}, 29 {104, nullptr, "GetProfileUpdateNotifier"},
30 {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ 30 {105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
31 {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ 31 {106, nullptr, "GetProfileSyncNotifier"},
32 {110, &ACC_SU::StoreSaveDataThumbnailSystem, "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"},
36 {120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+ 36 {120, nullptr, "ListOpenUsersInApplication"},
37 {130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+ 37 {130, nullptr, "ActivateOpenContextRetention"},
38 {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ 38 {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"},
39 {150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+ 39 {150, nullptr, "AuthenticateApplicationAsync"},
40 {190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0 40 {151, nullptr, "Unknown151"},
41 {191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+ 41 {152, nullptr, "Unknown152"},
42 {190, nullptr, "GetUserLastOpenedApplication"},
43 {191, nullptr, "ActivateOpenContextHolder"},
42 {200, nullptr, "BeginUserRegistration"}, 44 {200, nullptr, "BeginUserRegistration"},
43 {201, nullptr, "CompleteUserRegistration"}, 45 {201, nullptr, "CompleteUserRegistration"},
44 {202, nullptr, "CancelUserRegistration"}, 46 {202, nullptr, "CancelUserRegistration"},
@@ -46,15 +48,15 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
46 {204, nullptr, "SetUserPosition"}, 48 {204, nullptr, "SetUserPosition"},
47 {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"}, 49 {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
48 {206, nullptr, "CompleteUserRegistrationForcibly"}, 50 {206, nullptr, "CompleteUserRegistrationForcibly"},
49 {210, nullptr, "CreateFloatingRegistrationRequest"}, // 3.0.0+ 51 {210, nullptr, "CreateFloatingRegistrationRequest"},
50 {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+ 52 {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"},
51 {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+ 53 {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"},
52 {230, nullptr, "AuthenticateServiceAsync"}, 54 {230, nullptr, "AuthenticateServiceAsync"},
53 {250, nullptr, "GetBaasAccountAdministrator"}, 55 {250, nullptr, "GetBaasAccountAdministrator"},
54 {290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"}, 56 {290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"},
55 {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"}, // 3.0.0+ 57 {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
56 {299, nullptr, "SuspendBackgroundDaemon"}, 58 {299, nullptr, "SuspendBackgroundDaemon"},
57 {997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+ 59 {997, nullptr, "DebugInvalidateTokenCacheForUser"},
58 {998, nullptr, "DebugSetUserStateClose"}, 60 {998, nullptr, "DebugSetUserStateClose"},
59 {999, nullptr, "DebugSetUserStateOpen"}, 61 {999, nullptr, "DebugSetUserStateOpen"},
60 }; 62 };
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index 951081cd0..71982ad5a 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -17,29 +17,31 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
17 {3, &ACC_U1::ListOpenUsers, "ListOpenUsers"}, 17 {3, &ACC_U1::ListOpenUsers, "ListOpenUsers"},
18 {4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"}, 18 {4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"},
19 {5, &ACC_U1::GetProfile, "GetProfile"}, 19 {5, &ACC_U1::GetProfile, "GetProfile"},
20 {6, nullptr, "GetProfileDigest"}, // 3.0.0+ 20 {6, nullptr, "GetProfileDigest"},
21 {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, 21 {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
22 {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, 22 {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
23 {60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 23 {60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
24 {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ 24 {99, nullptr, "DebugActivateOpenContextRetention"},
25 {100, nullptr, "GetUserRegistrationNotifier"}, 25 {100, nullptr, "GetUserRegistrationNotifier"},
26 {101, nullptr, "GetUserStateChangeNotifier"}, 26 {101, nullptr, "GetUserStateChangeNotifier"},
27 {102, nullptr, "GetBaasAccountManagerForSystemService"}, 27 {102, nullptr, "GetBaasAccountManagerForSystemService"},
28 {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, 28 {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
29 {104, nullptr, "GetProfileUpdateNotifier"}, 29 {104, nullptr, "GetProfileUpdateNotifier"},
30 {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ 30 {105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
31 {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ 31 {106, nullptr, "GetProfileSyncNotifier"},
32 {110, &ACC_U1::StoreSaveDataThumbnailApplication, "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"},
36 {120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+ 36 {120, nullptr, "ListOpenUsersInApplication"},
37 {130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+ 37 {130, nullptr, "ActivateOpenContextRetention"},
38 {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ 38 {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"},
39 {150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+ 39 {150, nullptr, "AuthenticateApplicationAsync"},
40 {190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0 40 {151, nullptr, "Unknown151"},
41 {191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+ 41 {152, nullptr, "Unknown152"},
42 {997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+ 42 {190, nullptr, "GetUserLastOpenedApplication"},
43 {191, nullptr, "ActivateOpenContextHolder"},
44 {997, nullptr, "DebugInvalidateTokenCacheForUser"},
43 {998, nullptr, "DebugSetUserStateClose"}, 45 {998, nullptr, "DebugSetUserStateClose"},
44 {999, nullptr, "DebugSetUserStateOpen"}, 46 {999, nullptr, "DebugSetUserStateOpen"},
45 }; 47 };
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 50b2c58e2..de83d82a4 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -8,8 +8,8 @@
8#include <fmt/format.h> 8#include <fmt/format.h>
9 9
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/settings.h"
11#include "core/hle/service/acc/profile_manager.h" 12#include "core/hle/service/acc/profile_manager.h"
12#include "core/settings.h"
13 13
14namespace Service::Account { 14namespace Service::Account {
15 15
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 8e1fe9438..c59054468 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -7,6 +7,7 @@
7#include <cinttypes> 7#include <cinttypes>
8#include <cstring> 8#include <cstring>
9#include "audio_core/audio_renderer.h" 9#include "audio_core/audio_renderer.h"
10#include "common/settings.h"
10#include "core/core.h" 11#include "core/core.h"
11#include "core/file_sys/control_metadata.h" 12#include "core/file_sys/control_metadata.h"
12#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
@@ -41,7 +42,6 @@
41#include "core/hle/service/set/set.h" 42#include "core/hle/service/set/set.h"
42#include "core/hle/service/sm/sm.h" 43#include "core/hle/service/sm/sm.h"
43#include "core/hle/service/vi/vi.h" 44#include "core/hle/service/vi/vi.h"
44#include "core/settings.h"
45 45
46namespace Service::AM { 46namespace Service::AM {
47 47
@@ -231,6 +231,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
231 {10, nullptr, "PerformSystemButtonPressing"}, 231 {10, nullptr, "PerformSystemButtonPressing"},
232 {20, nullptr, "InvalidateTransitionLayer"}, 232 {20, nullptr, "InvalidateTransitionLayer"},
233 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, 233 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
234 {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
234 {40, nullptr, "GetAppletResourceUsageInfo"}, 235 {40, nullptr, "GetAppletResourceUsageInfo"},
235 {100, nullptr, "SetCpuBoostModeForApplet"}, 236 {100, nullptr, "SetCpuBoostModeForApplet"},
236 {101, nullptr, "CancelCpuBoostModeForApplet"}, 237 {101, nullptr, "CancelCpuBoostModeForApplet"},
@@ -242,6 +243,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
242 {130, nullptr, "FriendInvitationSetApplicationParameter"}, 243 {130, nullptr, "FriendInvitationSetApplicationParameter"},
243 {131, nullptr, "FriendInvitationClearApplicationParameter"}, 244 {131, nullptr, "FriendInvitationClearApplicationParameter"},
244 {132, nullptr, "FriendInvitationPushApplicationParameter"}, 245 {132, nullptr, "FriendInvitationPushApplicationParameter"},
246 {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
245 }; 247 };
246 // clang-format on 248 // clang-format on
247 249
@@ -295,8 +297,9 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
295 {80, nullptr, "SetWirelessPriorityMode"}, 297 {80, nullptr, "SetWirelessPriorityMode"},
296 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"}, 298 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
297 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, 299 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
298 {100, nullptr, "SetAlbumImageTakenNotificationEnabled"}, 300 {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
299 {110, nullptr, "SetApplicationAlbumUserData"}, 301 {110, nullptr, "SetApplicationAlbumUserData"},
302 {120, nullptr, "SaveCurrentScreenshot"},
300 {1000, nullptr, "GetDebugStorageChannel"}, 303 {1000, nullptr, "GetDebugStorageChannel"},
301 }; 304 };
302 // clang-format on 305 // clang-format on
@@ -560,6 +563,21 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
560 rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); 563 rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
561} 564}
562 565
566void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) {
567 IPC::RequestParser rp{ctx};
568
569 // This service call sets an internal flag whether a notification is shown when an image is
570 // captured. Currently we do not support capturing images via the capture button, so this can be
571 // stubbed for now.
572 const bool album_image_taken_notification_enabled = rp.Pop<bool>();
573
574 LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}",
575 album_image_taken_notification_enabled);
576
577 IPC::ResponseBuilder rb{ctx, 2};
578 rb.Push(RESULT_SUCCESS);
579}
580
563AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { 581AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
564 on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived"); 582 on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived");
565 on_new_message->Initialize(); 583 on_new_message->Initialize();
@@ -630,6 +648,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
630 {11, nullptr, "ReleaseSleepLock"}, 648 {11, nullptr, "ReleaseSleepLock"},
631 {12, nullptr, "ReleaseSleepLockTransiently"}, 649 {12, nullptr, "ReleaseSleepLockTransiently"},
632 {13, nullptr, "GetAcquiredSleepLockEvent"}, 650 {13, nullptr, "GetAcquiredSleepLockEvent"},
651 {14, nullptr, "GetWakeupCount"},
633 {20, nullptr, "PushToGeneralChannel"}, 652 {20, nullptr, "PushToGeneralChannel"},
634 {30, nullptr, "GetHomeButtonReaderLockAccessor"}, 653 {30, nullptr, "GetHomeButtonReaderLockAccessor"},
635 {31, nullptr, "GetReaderLockAccessorEx"}, 654 {31, nullptr, "GetReaderLockAccessorEx"},
@@ -641,6 +660,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
641 {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"}, 660 {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
642 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, 661 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
643 {55, nullptr, "IsInControllerFirmwareUpdateSection"}, 662 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
663 {59, nullptr, "SetVrPositionForDebug"},
644 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, 664 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
645 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, 665 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
646 {62, nullptr, "GetHdcpAuthenticationState"}, 666 {62, nullptr, "GetHdcpAuthenticationState"},
@@ -649,14 +669,21 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
649 {65, nullptr, "GetApplicationIdByContentActionName"}, 669 {65, nullptr, "GetApplicationIdByContentActionName"},
650 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, 670 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
651 {67, nullptr, "CancelCpuBoostMode"}, 671 {67, nullptr, "CancelCpuBoostMode"},
672 {68, nullptr, "GetBuiltInDisplayType"},
652 {80, nullptr, "PerformSystemButtonPressingIfInFocus"}, 673 {80, nullptr, "PerformSystemButtonPressingIfInFocus"},
653 {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, 674 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
654 {91, nullptr, "GetCurrentPerformanceConfiguration"}, 675 {91, nullptr, "GetCurrentPerformanceConfiguration"},
655 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, 676 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
677 {110, nullptr, "OpenMyGpuErrorHandler"},
656 {200, nullptr, "GetOperationModeSystemInfo"}, 678 {200, nullptr, "GetOperationModeSystemInfo"},
657 {300, nullptr, "GetSettingsPlatformRegion"}, 679 {300, nullptr, "GetSettingsPlatformRegion"},
658 {400, nullptr, "ActivateMigrationService"}, 680 {400, nullptr, "ActivateMigrationService"},
659 {401, nullptr, "DeactivateMigrationService"}, 681 {401, nullptr, "DeactivateMigrationService"},
682 {500, nullptr, "DisableSleepTillShutdown"},
683 {501, nullptr, "SuppressDisablingSleepTemporarily"},
684 {502, nullptr, "IsSleepEnabled"},
685 {503, nullptr, "IsDisablingSleepSuppressed"},
686 {900, nullptr, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
660 }; 687 };
661 // clang-format on 688 // clang-format on
662 689
@@ -944,7 +971,7 @@ private:
944 971
945 auto storage = applet->GetBroker().PopNormalDataToGame(); 972 auto storage = applet->GetBroker().PopNormalDataToGame();
946 if (storage == nullptr) { 973 if (storage == nullptr) {
947 LOG_ERROR(Service_AM, 974 LOG_DEBUG(Service_AM,
948 "storage is a nullptr. There is no data in the current normal channel"); 975 "storage is a nullptr. There is no data in the current normal channel");
949 IPC::ResponseBuilder rb{ctx, 2}; 976 IPC::ResponseBuilder rb{ctx, 2};
950 rb.Push(ERR_NO_DATA_IN_CHANNEL); 977 rb.Push(ERR_NO_DATA_IN_CHANNEL);
@@ -975,7 +1002,7 @@ private:
975 1002
976 auto storage = applet->GetBroker().PopInteractiveDataToGame(); 1003 auto storage = applet->GetBroker().PopInteractiveDataToGame();
977 if (storage == nullptr) { 1004 if (storage == nullptr) {
978 LOG_ERROR(Service_AM, 1005 LOG_DEBUG(Service_AM,
979 "storage is a nullptr. There is no data in the current interactive channel"); 1006 "storage is a nullptr. There is no data in the current interactive channel");
980 IPC::ResponseBuilder rb{ctx, 2}; 1007 IPC::ResponseBuilder rb{ctx, 2};
981 rb.Push(ERR_NO_DATA_IN_CHANNEL); 1008 rb.Push(ERR_NO_DATA_IN_CHANNEL);
@@ -1098,7 +1125,7 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
1098 {2, nullptr, "AreAnyLibraryAppletsLeft"}, 1125 {2, nullptr, "AreAnyLibraryAppletsLeft"},
1099 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, 1126 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
1100 {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, 1127 {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
1101 {12, nullptr, "CreateHandleStorage"}, 1128 {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
1102 }; 1129 };
1103 RegisterHandlers(functions); 1130 RegisterHandlers(functions);
1104} 1131}
@@ -1107,14 +1134,15 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default;
1107 1134
1108void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { 1135void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
1109 IPC::RequestParser rp{ctx}; 1136 IPC::RequestParser rp{ctx};
1137
1110 const auto applet_id = rp.PopRaw<Applets::AppletId>(); 1138 const auto applet_id = rp.PopRaw<Applets::AppletId>();
1111 const auto applet_mode = rp.PopRaw<u32>(); 1139 const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>();
1112 1140
1113 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, 1141 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
1114 applet_mode); 1142 applet_mode);
1115 1143
1116 const auto& applet_manager{system.GetAppletManager()}; 1144 const auto& applet_manager{system.GetAppletManager()};
1117 const auto applet = applet_manager.GetApplet(applet_id); 1145 const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
1118 1146
1119 if (applet == nullptr) { 1147 if (applet == nullptr) {
1120 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); 1148 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
@@ -1132,9 +1160,18 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
1132 1160
1133void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { 1161void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
1134 IPC::RequestParser rp{ctx}; 1162 IPC::RequestParser rp{ctx};
1135 const u64 size{rp.Pop<u64>()}; 1163
1164 const s64 size{rp.Pop<s64>()};
1165
1136 LOG_DEBUG(Service_AM, "called, size={}", size); 1166 LOG_DEBUG(Service_AM, "called, size={}", size);
1137 1167
1168 if (size <= 0) {
1169 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1170 IPC::ResponseBuilder rb{ctx, 2};
1171 rb.Push(RESULT_UNKNOWN);
1172 return;
1173 }
1174
1138 std::vector<u8> buffer(size); 1175 std::vector<u8> buffer(size);
1139 1176
1140 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1177 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -1143,18 +1180,65 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
1143} 1180}
1144 1181
1145void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { 1182void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
1146 LOG_DEBUG(Service_AM, "called"); 1183 IPC::RequestParser rp{ctx};
1184
1185 struct Parameters {
1186 u8 permissions;
1187 s64 size;
1188 };
1189
1190 const auto parameters{rp.PopRaw<Parameters>()};
1191 const auto handle{ctx.GetCopyHandle(0)};
1192
1193 LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions,
1194 parameters.size, handle);
1195
1196 if (parameters.size <= 0) {
1197 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1198 IPC::ResponseBuilder rb{ctx, 2};
1199 rb.Push(RESULT_UNKNOWN);
1200 return;
1201 }
1202
1203 auto transfer_mem =
1204 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
1205
1206 if (transfer_mem == nullptr) {
1207 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
1208 IPC::ResponseBuilder rb{ctx, 2};
1209 rb.Push(RESULT_UNKNOWN);
1210 return;
1211 }
1212
1213 const u8* const mem_begin = transfer_mem->GetPointer();
1214 const u8* const mem_end = mem_begin + transfer_mem->GetSize();
1215 std::vector<u8> memory{mem_begin, mem_end};
1216
1217 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1218 rb.Push(RESULT_SUCCESS);
1219 rb.PushIpcInterface<IStorage>(system, std::move(memory));
1220}
1147 1221
1222void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) {
1148 IPC::RequestParser rp{ctx}; 1223 IPC::RequestParser rp{ctx};
1149 1224
1150 rp.SetCurrentOffset(3); 1225 const s64 size{rp.Pop<s64>()};
1151 const auto handle{rp.Pop<Kernel::Handle>()}; 1226 const auto handle{ctx.GetCopyHandle(0)};
1227
1228 LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
1229
1230 if (size <= 0) {
1231 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1232 IPC::ResponseBuilder rb{ctx, 2};
1233 rb.Push(RESULT_UNKNOWN);
1234 return;
1235 }
1152 1236
1153 auto transfer_mem = 1237 auto transfer_mem =
1154 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); 1238 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
1155 1239
1156 if (transfer_mem == nullptr) { 1240 if (transfer_mem == nullptr) {
1157 LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); 1241 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
1158 IPC::ResponseBuilder rb{ctx, 2}; 1242 IPC::ResponseBuilder rb{ctx, 2};
1159 rb.Push(RESULT_UNKNOWN); 1243 rb.Push(RESULT_UNKNOWN);
1160 return; 1244 return;
@@ -1188,11 +1272,14 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1188 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, 1272 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
1189 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, 1273 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
1190 {27, nullptr, "CreateCacheStorage"}, 1274 {27, nullptr, "CreateCacheStorage"},
1275 {28, nullptr, "GetSaveDataSizeMax"},
1276 {29, nullptr, "GetCacheStorageMax"},
1191 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, 1277 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
1192 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, 1278 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
1193 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, 1279 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
1194 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, 1280 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
1195 {34, nullptr, "SelectApplicationLicense"}, 1281 {34, nullptr, "SelectApplicationLicense"},
1282 {35, nullptr, "GetDeviceSaveDataSizeMax"},
1196 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, 1283 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
1197 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, 1284 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
1198 {60, nullptr, "SetMediaPlaybackStateForApplication"}, 1285 {60, nullptr, "SetMediaPlaybackStateForApplication"},
@@ -1216,6 +1303,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1216 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, 1303 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
1217 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, 1304 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
1218 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, 1305 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
1306 {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
1219 {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, 1307 {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
1220 {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"}, 1308 {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
1221 {150, nullptr, "GetNotificationStorageChannelEvent"}, 1309 {150, nullptr, "GetNotificationStorageChannelEvent"},
@@ -1224,6 +1312,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1224 {170, nullptr, "SetHdcpAuthenticationActivated"}, 1312 {170, nullptr, "SetHdcpAuthenticationActivated"},
1225 {180, nullptr, "GetLaunchRequiredVersion"}, 1313 {180, nullptr, "GetLaunchRequiredVersion"},
1226 {181, nullptr, "UpgradeLaunchRequiredVersion"}, 1314 {181, nullptr, "UpgradeLaunchRequiredVersion"},
1315 {190, nullptr, "SendServerMaintenanceOverlayNotification"},
1316 {200, nullptr, "GetLastApplicationExitReason"},
1227 {500, nullptr, "StartContinuousRecordingFlushForDebug"}, 1317 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
1228 {1000, nullptr, "CreateMovieMaker"}, 1318 {1000, nullptr, "CreateMovieMaker"},
1229 {1001, nullptr, "PrepareForJit"}, 1319 {1001, nullptr, "PrepareForJit"},
@@ -1690,9 +1780,12 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
1690 {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"}, 1780 {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
1691 {30, nullptr, "GetHomeButtonWriterLockAccessor"}, 1781 {30, nullptr, "GetHomeButtonWriterLockAccessor"},
1692 {31, nullptr, "GetWriterLockAccessorEx"}, 1782 {31, nullptr, "GetWriterLockAccessorEx"},
1783 {40, nullptr, "IsSleepEnabled"},
1784 {41, nullptr, "IsRebootEnabled"},
1693 {100, nullptr, "PopRequestLaunchApplicationForDebug"}, 1785 {100, nullptr, "PopRequestLaunchApplicationForDebug"},
1694 {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"}, 1786 {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
1695 {200, nullptr, "LaunchDevMenu"}, 1787 {200, nullptr, "LaunchDevMenu"},
1788 {1000, nullptr, "SetLastApplicationExitReason"},
1696 }; 1789 };
1697 // clang-format on 1790 // clang-format on
1698 1791
@@ -1736,6 +1829,7 @@ IGlobalStateController::IGlobalStateController(Core::System& system_)
1736 {13, nullptr, "UpdateDefaultDisplayResolution"}, 1829 {13, nullptr, "UpdateDefaultDisplayResolution"},
1737 {14, nullptr, "ShouldSleepOnBoot"}, 1830 {14, nullptr, "ShouldSleepOnBoot"},
1738 {15, nullptr, "GetHdcpAuthenticationFailedEvent"}, 1831 {15, nullptr, "GetHdcpAuthenticationFailedEvent"},
1832 {30, nullptr, "OpenCradleFirmwareUpdater"},
1739 }; 1833 };
1740 // clang-format on 1834 // clang-format on
1741 1835
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 6911f0d6e..aefbdf0d5 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -146,6 +146,7 @@ private:
146 void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx); 146 void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx);
147 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); 147 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
148 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); 148 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
149 void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx);
149 150
150 enum class ScreenshotPermission : u32 { 151 enum class ScreenshotPermission : u32 {
151 Inherit = 0, 152 Inherit = 0,
@@ -253,6 +254,7 @@ private:
253 void CreateLibraryApplet(Kernel::HLERequestContext& ctx); 254 void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
254 void CreateStorage(Kernel::HLERequestContext& ctx); 255 void CreateStorage(Kernel::HLERequestContext& ctx);
255 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); 256 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
257 void CreateHandleStorage(Kernel::HLERequestContext& ctx);
256}; 258};
257 259
258class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { 260class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index e2f3b7563..5ddad851a 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -241,31 +241,31 @@ void AppletManager::ClearAll() {
241 frontend = {}; 241 frontend = {};
242} 242}
243 243
244std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { 244std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const {
245 switch (id) { 245 switch (id) {
246 case AppletId::Auth: 246 case AppletId::Auth:
247 return std::make_shared<Auth>(system, *frontend.parental_controls); 247 return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
248 case AppletId::Controller: 248 case AppletId::Controller:
249 return std::make_shared<Controller>(system, *frontend.controller); 249 return std::make_shared<Controller>(system, mode, *frontend.controller);
250 case AppletId::Error: 250 case AppletId::Error:
251 return std::make_shared<Error>(system, *frontend.error); 251 return std::make_shared<Error>(system, mode, *frontend.error);
252 case AppletId::ProfileSelect: 252 case AppletId::ProfileSelect:
253 return std::make_shared<ProfileSelect>(system, *frontend.profile_select); 253 return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
254 case AppletId::SoftwareKeyboard: 254 case AppletId::SoftwareKeyboard:
255 return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard); 255 return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
256 case AppletId::Web: 256 case AppletId::Web:
257 case AppletId::Shop: 257 case AppletId::Shop:
258 case AppletId::OfflineWeb: 258 case AppletId::OfflineWeb:
259 case AppletId::LoginShare: 259 case AppletId::LoginShare:
260 case AppletId::WebAuth: 260 case AppletId::WebAuth:
261 return std::make_shared<WebBrowser>(system, *frontend.web_browser); 261 return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser);
262 case AppletId::PhotoViewer: 262 case AppletId::PhotoViewer:
263 return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer); 263 return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer);
264 default: 264 default:
265 UNIMPLEMENTED_MSG( 265 UNIMPLEMENTED_MSG(
266 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", 266 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
267 static_cast<u8>(id)); 267 static_cast<u8>(id));
268 return std::make_shared<StubApplet>(system, id); 268 return std::make_shared<StubApplet>(system, id, mode);
269 } 269 }
270} 270}
271 271
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index b9a006317..26b482015 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -62,6 +62,14 @@ enum class AppletId : u32 {
62 MyPage = 0x1A, 62 MyPage = 0x1A,
63}; 63};
64 64
65enum class LibraryAppletMode : u32 {
66 AllForeground = 0,
67 Background = 1,
68 NoUI = 2,
69 BackgroundIndirectDisplay = 3,
70 AllForegroundInitiallyHidden = 4,
71};
72
65class AppletDataBroker final { 73class AppletDataBroker final {
66public: 74public:
67 explicit AppletDataBroker(Kernel::KernelCore& kernel_); 75 explicit AppletDataBroker(Kernel::KernelCore& kernel_);
@@ -200,7 +208,7 @@ public:
200 void SetDefaultAppletsIfMissing(); 208 void SetDefaultAppletsIfMissing();
201 void ClearAll(); 209 void ClearAll();
202 210
203 std::shared_ptr<Applet> GetApplet(AppletId id) const; 211 std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
204 212
205private: 213private:
206 AppletFrontendSet frontend; 214 AppletFrontendSet frontend;
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
index c2bfe698f..a33f05f97 100644
--- a/src/core/hle/service/am/applets/controller.cpp
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -45,8 +45,9 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
45 }; 45 };
46} 46}
47 47
48Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) 48Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_,
49 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} 49 const Core::Frontend::ControllerApplet& frontend_)
50 : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
50 51
51Controller::~Controller() = default; 52Controller::~Controller() = default;
52 53
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h
index d4c9da7b1..07cb92bf9 100644
--- a/src/core/hle/service/am/applets/controller.h
+++ b/src/core/hle/service/am/applets/controller.h
@@ -106,7 +106,8 @@ static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
106 106
107class Controller final : public Applet { 107class Controller final : public Applet {
108public: 108public:
109 explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_); 109 explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_,
110 const Core::Frontend::ControllerApplet& frontend_);
110 ~Controller() override; 111 ~Controller() override;
111 112
112 void Initialize() override; 113 void Initialize() override;
@@ -119,6 +120,7 @@ public:
119 void ConfigurationComplete(); 120 void ConfigurationComplete();
120 121
121private: 122private:
123 LibraryAppletMode applet_mode;
122 const Core::Frontend::ControllerApplet& frontend; 124 const Core::Frontend::ControllerApplet& frontend;
123 Core::System& system; 125 Core::System& system;
124 126
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index 0c8b632e8..a9f0a9c95 100644
--- a/src/core/hle/service/am/applets/error.cpp
+++ b/src/core/hle/service/am/applets/error.cpp
@@ -86,8 +86,9 @@ ResultCode Decode64BitError(u64 error) {
86 86
87} // Anonymous namespace 87} // Anonymous namespace
88 88
89Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_) 89Error::Error(Core::System& system_, LibraryAppletMode applet_mode_,
90 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} 90 const Core::Frontend::ErrorApplet& frontend_)
91 : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
91 92
92Error::~Error() = default; 93Error::~Error() = default;
93 94
diff --git a/src/core/hle/service/am/applets/error.h b/src/core/hle/service/am/applets/error.h
index a105cdb0c..a3e520cd4 100644
--- a/src/core/hle/service/am/applets/error.h
+++ b/src/core/hle/service/am/applets/error.h
@@ -25,7 +25,8 @@ enum class ErrorAppletMode : u8 {
25 25
26class Error final : public Applet { 26class Error final : public Applet {
27public: 27public:
28 explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_); 28 explicit Error(Core::System& system_, LibraryAppletMode applet_mode_,
29 const Core::Frontend::ErrorApplet& frontend_);
29 ~Error() override; 30 ~Error() override;
30 31
31 void Initialize() override; 32 void Initialize() override;
@@ -40,6 +41,7 @@ public:
40private: 41private:
41 union ErrorArguments; 42 union ErrorArguments;
42 43
44 LibraryAppletMode applet_mode;
43 const Core::Frontend::ErrorApplet& frontend; 45 const Core::Frontend::ErrorApplet& frontend;
44 ResultCode error_code = RESULT_SUCCESS; 46 ResultCode error_code = RESULT_SUCCESS;
45 ErrorAppletMode mode = ErrorAppletMode::ShowError; 47 ErrorAppletMode mode = ErrorAppletMode::ShowError;
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index 4d1df5cbe..71016cce7 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -37,8 +37,9 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
37 } 37 }
38} 38}
39 39
40Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_) 40Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_,
41 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} 41 Core::Frontend::ParentalControlsApplet& frontend_)
42 : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
42 43
43Auth::~Auth() = default; 44Auth::~Auth() = default;
44 45
@@ -152,8 +153,9 @@ void Auth::AuthFinished(bool is_successful) {
152 broker.SignalStateChanged(); 153 broker.SignalStateChanged();
153} 154}
154 155
155PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_) 156PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
156 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} 157 const Core::Frontend::PhotoViewerApplet& frontend_)
158 : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
157 159
158PhotoViewer::~PhotoViewer() = default; 160PhotoViewer::~PhotoViewer() = default;
159 161
@@ -202,8 +204,8 @@ void PhotoViewer::ViewFinished() {
202 broker.SignalStateChanged(); 204 broker.SignalStateChanged();
203} 205}
204 206
205StubApplet::StubApplet(Core::System& system_, AppletId id_) 207StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_)
206 : Applet{system_.Kernel()}, id{id_}, system{system_} {} 208 : Applet{system_.Kernel()}, id{id_}, applet_mode{applet_mode_}, system{system_} {}
207 209
208StubApplet::~StubApplet() = default; 210StubApplet::~StubApplet() = default;
209 211
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h
index ba76ae3d3..d9e6d4384 100644
--- a/src/core/hle/service/am/applets/general_backend.h
+++ b/src/core/hle/service/am/applets/general_backend.h
@@ -20,7 +20,8 @@ enum class AuthAppletType : u32 {
20 20
21class Auth final : public Applet { 21class Auth final : public Applet {
22public: 22public:
23 explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_); 23 explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_,
24 Core::Frontend::ParentalControlsApplet& frontend_);
24 ~Auth() override; 25 ~Auth() override;
25 26
26 void Initialize() override; 27 void Initialize() override;
@@ -32,6 +33,7 @@ public:
32 void AuthFinished(bool is_successful = true); 33 void AuthFinished(bool is_successful = true);
33 34
34private: 35private:
36 LibraryAppletMode applet_mode;
35 Core::Frontend::ParentalControlsApplet& frontend; 37 Core::Frontend::ParentalControlsApplet& frontend;
36 Core::System& system; 38 Core::System& system;
37 bool complete = false; 39 bool complete = false;
@@ -50,7 +52,8 @@ enum class PhotoViewerAppletMode : u8 {
50 52
51class PhotoViewer final : public Applet { 53class PhotoViewer final : public Applet {
52public: 54public:
53 explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_); 55 explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
56 const Core::Frontend::PhotoViewerApplet& frontend_);
54 ~PhotoViewer() override; 57 ~PhotoViewer() override;
55 58
56 void Initialize() override; 59 void Initialize() override;
@@ -62,6 +65,7 @@ public:
62 void ViewFinished(); 65 void ViewFinished();
63 66
64private: 67private:
68 LibraryAppletMode applet_mode;
65 const Core::Frontend::PhotoViewerApplet& frontend; 69 const Core::Frontend::PhotoViewerApplet& frontend;
66 bool complete = false; 70 bool complete = false;
67 PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; 71 PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
@@ -70,7 +74,7 @@ private:
70 74
71class StubApplet final : public Applet { 75class StubApplet final : public Applet {
72public: 76public:
73 explicit StubApplet(Core::System& system_, AppletId id_); 77 explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_);
74 ~StubApplet() override; 78 ~StubApplet() override;
75 79
76 void Initialize() override; 80 void Initialize() override;
@@ -82,6 +86,7 @@ public:
82 86
83private: 87private:
84 AppletId id; 88 AppletId id;
89 LibraryAppletMode applet_mode;
85 Core::System& system; 90 Core::System& system;
86}; 91};
87 92
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
index 77fba16c7..ab8b6fcc5 100644
--- a/src/core/hle/service/am/applets/profile_select.cpp
+++ b/src/core/hle/service/am/applets/profile_select.cpp
@@ -15,9 +15,9 @@ namespace Service::AM::Applets {
15 15
16constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; 16constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
17 17
18ProfileSelect::ProfileSelect(Core::System& system_, 18ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
19 const Core::Frontend::ProfileSelectApplet& frontend_) 19 const Core::Frontend::ProfileSelectApplet& frontend_)
20 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} 20 : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
21 21
22ProfileSelect::~ProfileSelect() = default; 22ProfileSelect::~ProfileSelect() = default;
23 23
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h
index 648d33a24..90f054030 100644
--- a/src/core/hle/service/am/applets/profile_select.h
+++ b/src/core/hle/service/am/applets/profile_select.h
@@ -33,7 +33,7 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco
33 33
34class ProfileSelect final : public Applet { 34class ProfileSelect final : public Applet {
35public: 35public:
36 explicit ProfileSelect(Core::System& system_, 36 explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
37 const Core::Frontend::ProfileSelectApplet& frontend_); 37 const Core::Frontend::ProfileSelectApplet& frontend_);
38 ~ProfileSelect() override; 38 ~ProfileSelect() override;
39 39
@@ -47,6 +47,7 @@ public:
47 void SelectionComplete(std::optional<Common::UUID> uuid); 47 void SelectionComplete(std::optional<Common::UUID> uuid);
48 48
49private: 49private:
50 LibraryAppletMode applet_mode;
50 const Core::Frontend::ProfileSelectApplet& frontend; 51 const Core::Frontend::ProfileSelectApplet& frontend;
51 52
52 UserSelectionConfig config; 53 UserSelectionConfig config;
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 79b209c6b..c3a05de9c 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -1,93 +1,80 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2021 yuzu Emulator Project
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 <cstring>
6#include "common/assert.h"
7#include "common/string_util.h" 5#include "common/string_util.h"
8#include "core/core.h" 6#include "core/core.h"
9#include "core/frontend/applets/software_keyboard.h" 7#include "core/frontend/applets/software_keyboard.h"
10#include "core/hle/result.h"
11#include "core/hle/service/am/am.h" 8#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/software_keyboard.h" 9#include "core/hle/service/am/applets/software_keyboard.h"
13 10
14namespace Service::AM::Applets { 11namespace Service::AM::Applets {
15 12
16namespace { 13namespace {
17enum class Request : u32 { 14
18 Finalize = 0x4, 15// The maximum number of UTF-16 characters that can be input into the swkbd text field.
19 SetUserWordInfo = 0x6, 16constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500;
20 SetCustomizeDic = 0x7, 17
21 Calc = 0xa, 18constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType);
22 SetCustomizedDictionaries = 0xb, 19constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4;
23 UnsetCustomizedDictionaries = 0xc, 20constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC;
24 UnknownD = 0xd, 21
25 UnknownE = 0xe, 22constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) {
26}; 23 switch (text_check_result) {
27constexpr std::size_t SWKBD_INLINE_INIT_SIZE = 0x8; 24 case SwkbdTextCheckResult::Success:
28constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; 25 return "Success";
29constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4; 26 case SwkbdTextCheckResult::Failure:
30constexpr std::size_t DEFAULT_MAX_LENGTH = 500; 27 return "Failure";
31constexpr bool INTERACTIVE_STATUS_OK = false; 28 case SwkbdTextCheckResult::Confirm:
29 return "Confirm";
30 case SwkbdTextCheckResult::Silent:
31 return "Silent";
32 default:
33 UNIMPLEMENTED_MSG("Unknown TextCheckResult={}", text_check_result);
34 return "Unknown";
35 }
36}
37
38void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply_type) {
39 std::memcpy(reply.data(), &state, sizeof(SwkbdState));
40 std::memcpy(reply.data() + sizeof(SwkbdState), &reply_type, sizeof(SwkbdReplyType));
41}
42
32} // Anonymous namespace 43} // Anonymous namespace
33static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( 44
34 KeyboardConfig config, std::u16string initial_text) { 45SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
35 Core::Frontend::SoftwareKeyboardParameters params{}; 46 Core::Frontend::SoftwareKeyboardApplet& frontend_)
36 47 : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
37 params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
38 config.submit_text.data(), config.submit_text.size());
39 params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
40 config.header_text.data(), config.header_text.size());
41 params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(),
42 config.sub_text.size());
43 params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(),
44 config.guide_text.size());
45 params.initial_text = std::move(initial_text);
46 params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit;
47 params.password = static_cast<bool>(config.is_password);
48 params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position);
49 params.value = static_cast<u8>(config.keyset_disable_bitmask);
50
51 return params;
52}
53
54SoftwareKeyboard::SoftwareKeyboard(Core::System& system_,
55 const Core::Frontend::SoftwareKeyboardApplet& frontend_)
56 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
57 48
58SoftwareKeyboard::~SoftwareKeyboard() = default; 49SoftwareKeyboard::~SoftwareKeyboard() = default;
59 50
60void SoftwareKeyboard::Initialize() { 51void SoftwareKeyboard::Initialize() {
61 complete = false;
62 is_inline = false;
63 initial_text.clear();
64 final_data.clear();
65
66 Applet::Initialize(); 52 Applet::Initialize();
67 53
68 const auto keyboard_config_storage = broker.PopNormalDataToApplet(); 54 LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}",
69 ASSERT(keyboard_config_storage != nullptr); 55 applet_mode);
70 const auto& keyboard_config = keyboard_config_storage->GetData();
71
72 if (keyboard_config.size() == SWKBD_INLINE_INIT_SIZE) {
73 is_inline = true;
74 return;
75 }
76
77 ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
78 std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
79 56
80 const auto work_buffer_storage = broker.PopNormalDataToApplet(); 57 LOG_DEBUG(Service_AM,
81 ASSERT_OR_EXECUTE(work_buffer_storage != nullptr, { return; }); 58 "Initializing Applet with common_args: arg_version={}, lib_version={}, "
82 const auto& work_buffer = work_buffer_storage->GetData(); 59 "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
60 common_args.arguments_version, common_args.library_version,
61 common_args.play_startup_sound, common_args.size, common_args.system_tick,
62 common_args.theme_color);
83 63
84 if (config.initial_string_size == 0) 64 swkbd_applet_version = SwkbdAppletVersion{common_args.library_version};
85 return;
86 65
87 std::vector<char16_t> string(config.initial_string_size); 66 switch (applet_mode) {
88 std::memcpy(string.data(), work_buffer.data() + config.initial_string_offset, 67 case LibraryAppletMode::AllForeground:
89 string.size() * 2); 68 InitializeForeground();
90 initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()); 69 break;
70 case LibraryAppletMode::Background:
71 case LibraryAppletMode::BackgroundIndirectDisplay:
72 InitializeBackground(applet_mode);
73 break;
74 default:
75 UNREACHABLE_MSG("Invalid LibraryAppletMode={}", applet_mode);
76 break;
77 }
91} 78}
92 79
93bool SoftwareKeyboard::TransactionComplete() const { 80bool SoftwareKeyboard::TransactionComplete() const {
@@ -95,106 +82,996 @@ bool SoftwareKeyboard::TransactionComplete() const {
95} 82}
96 83
97ResultCode SoftwareKeyboard::GetStatus() const { 84ResultCode SoftwareKeyboard::GetStatus() const {
98 return RESULT_SUCCESS; 85 return status;
99} 86}
100 87
101void SoftwareKeyboard::ExecuteInteractive() { 88void SoftwareKeyboard::ExecuteInteractive() {
102 if (complete) 89 if (complete) {
103 return; 90 return;
91 }
104 92
105 const auto storage = broker.PopInteractiveDataToApplet(); 93 if (is_background) {
106 ASSERT(storage != nullptr); 94 ProcessInlineKeyboardRequest();
107 const auto data = storage->GetData();
108 if (!is_inline) {
109 const auto status = static_cast<bool>(data[0]);
110 if (status == INTERACTIVE_STATUS_OK) {
111 complete = true;
112 } else {
113 std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
114 std::memcpy(string.data(), data.data() + 4, string.size() * 2);
115 frontend.SendTextCheckDialog(
116 Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
117 [this] { broker.SignalStateChanged(); });
118 }
119 } else { 95 } else {
120 Request request{}; 96 ProcessTextCheck();
121 std::memcpy(&request, data.data(), sizeof(Request)); 97 }
98}
99
100void SoftwareKeyboard::Execute() {
101 if (complete) {
102 return;
103 }
104
105 if (is_background) {
106 return;
107 }
108
109 ShowNormalKeyboard();
110}
122 111
123 switch (request) { 112void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text) {
124 case Request::Finalize: 113 if (complete) {
125 complete = true; 114 return;
126 broker.SignalStateChanged(); 115 }
116
117 if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) {
118 SubmitForTextCheck(submitted_text);
119 } else {
120 SubmitNormalOutputAndExit(result, submitted_text);
121 }
122}
123
124void SoftwareKeyboard::SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
125 s32 cursor_position) {
126 if (complete) {
127 return;
128 }
129
130 current_text = std::move(submitted_text);
131 current_cursor_position = cursor_position;
132
133 if (inline_use_utf8) {
134 switch (reply_type) {
135 case SwkbdReplyType::ChangedString:
136 reply_type = SwkbdReplyType::ChangedStringUtf8;
127 break; 137 break;
128 case Request::Calc: { 138 case SwkbdReplyType::MovedCursor:
129 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1})); 139 reply_type = SwkbdReplyType::MovedCursorUtf8;
130 broker.SignalStateChanged(); 140 break;
141 case SwkbdReplyType::DecidedEnter:
142 reply_type = SwkbdReplyType::DecidedEnterUtf8;
143 break;
144 default:
131 break; 145 break;
132 } 146 }
147 }
148
149 if (use_changed_string_v2) {
150 switch (reply_type) {
151 case SwkbdReplyType::ChangedString:
152 reply_type = SwkbdReplyType::ChangedStringV2;
153 break;
154 case SwkbdReplyType::ChangedStringUtf8:
155 reply_type = SwkbdReplyType::ChangedStringUtf8V2;
156 break;
133 default: 157 default:
134 UNIMPLEMENTED_MSG("Request {:X} is not implemented", request);
135 break; 158 break;
136 } 159 }
137 } 160 }
161
162 if (use_moved_cursor_v2) {
163 switch (reply_type) {
164 case SwkbdReplyType::MovedCursor:
165 reply_type = SwkbdReplyType::MovedCursorV2;
166 break;
167 case SwkbdReplyType::MovedCursorUtf8:
168 reply_type = SwkbdReplyType::MovedCursorUtf8V2;
169 break;
170 default:
171 break;
172 }
173 }
174
175 SendReply(reply_type);
138} 176}
139 177
140void SoftwareKeyboard::Execute() { 178void SoftwareKeyboard::InitializeForeground() {
141 if (complete) { 179 LOG_INFO(Service_AM, "Initializing Normal Software Keyboard Applet.");
142 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); 180
143 broker.SignalStateChanged(); 181 is_background = false;
182
183 const auto swkbd_config_storage = broker.PopNormalDataToApplet();
184 ASSERT(swkbd_config_storage != nullptr);
185
186 const auto& swkbd_config_data = swkbd_config_storage->GetData();
187 ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon));
188
189 std::memcpy(&swkbd_config_common, swkbd_config_data.data(), sizeof(SwkbdConfigCommon));
190
191 switch (swkbd_applet_version) {
192 case SwkbdAppletVersion::Version5:
193 case SwkbdAppletVersion::Version65542:
194 ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld));
195 std::memcpy(&swkbd_config_old, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
196 sizeof(SwkbdConfigOld));
197 break;
198 case SwkbdAppletVersion::Version196615:
199 case SwkbdAppletVersion::Version262152:
200 case SwkbdAppletVersion::Version327689:
201 ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld2));
202 std::memcpy(&swkbd_config_old2, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
203 sizeof(SwkbdConfigOld2));
204 break;
205 case SwkbdAppletVersion::Version393227:
206 case SwkbdAppletVersion::Version524301:
207 ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew));
208 std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
209 sizeof(SwkbdConfigNew));
210 break;
211 default:
212 UNIMPLEMENTED_MSG("Unknown SwkbdConfig revision={} with size={}", swkbd_applet_version,
213 swkbd_config_data.size());
214 ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew));
215 std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
216 sizeof(SwkbdConfigNew));
217 break;
218 }
219
220 const auto work_buffer_storage = broker.PopNormalDataToApplet();
221 ASSERT(work_buffer_storage != nullptr);
222
223 if (swkbd_config_common.initial_string_length == 0) {
224 InitializeFrontendKeyboard();
144 return; 225 return;
145 } 226 }
146 227
147 const auto parameters = ConvertToFrontendParameters(config, initial_text); 228 const auto& work_buffer = work_buffer_storage->GetData();
148 if (!is_inline) { 229
149 frontend.RequestText( 230 std::vector<char16_t> initial_string(swkbd_config_common.initial_string_length);
150 [this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, parameters); 231
232 std::memcpy(initial_string.data(),
233 work_buffer.data() + swkbd_config_common.initial_string_offset,
234 swkbd_config_common.initial_string_length * sizeof(char16_t));
235
236 initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(initial_string.data(),
237 initial_string.size());
238
239 LOG_DEBUG(Service_AM, "\nInitial Text: {}", Common::UTF16ToUTF8(initial_text));
240
241 InitializeFrontendKeyboard();
242}
243
244void SoftwareKeyboard::InitializeBackground(LibraryAppletMode applet_mode) {
245 LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
246
247 is_background = true;
248
249 const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet();
250 ASSERT(swkbd_inline_initialize_arg_storage != nullptr);
251
252 const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData();
253 ASSERT(swkbd_inline_initialize_arg.size() == sizeof(SwkbdInitializeArg));
254
255 std::memcpy(&swkbd_initialize_arg, swkbd_inline_initialize_arg.data(),
256 swkbd_inline_initialize_arg.size());
257
258 if (swkbd_initialize_arg.library_applet_mode_flag) {
259 ASSERT(applet_mode == LibraryAppletMode::Background);
260 } else {
261 ASSERT(applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
262 }
263}
264
265void SoftwareKeyboard::ProcessTextCheck() {
266 const auto text_check_storage = broker.PopInteractiveDataToApplet();
267 ASSERT(text_check_storage != nullptr);
268
269 const auto& text_check_data = text_check_storage->GetData();
270 ASSERT(text_check_data.size() == sizeof(SwkbdTextCheck));
271
272 SwkbdTextCheck swkbd_text_check;
273
274 std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck));
275
276 std::u16string text_check_message = Common::UTF16StringFromFixedZeroTerminatedBuffer(
277 swkbd_text_check.text_check_message.data(), swkbd_text_check.text_check_message.size());
278
279 LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}",
280 GetTextCheckResultName(swkbd_text_check.text_check_result),
281 Common::UTF16ToUTF8(text_check_message));
282
283 switch (swkbd_text_check.text_check_result) {
284 case SwkbdTextCheckResult::Success:
285 SubmitNormalOutputAndExit(SwkbdResult::Ok, current_text);
286 break;
287 case SwkbdTextCheckResult::Failure:
288 ShowTextCheckDialog(SwkbdTextCheckResult::Failure, text_check_message);
289 break;
290 case SwkbdTextCheckResult::Confirm:
291 ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, text_check_message);
292 break;
293 case SwkbdTextCheckResult::Silent:
294 default:
295 break;
151 } 296 }
152} 297}
153 298
154void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { 299void SoftwareKeyboard::ProcessInlineKeyboardRequest() {
155 std::vector<u8> output_main(SWKBD_OUTPUT_BUFFER_SIZE); 300 const auto request_data_storage = broker.PopInteractiveDataToApplet();
301 ASSERT(request_data_storage != nullptr);
302
303 const auto& request_data = request_data_storage->GetData();
304 ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand));
156 305
157 if (text.has_value()) { 306 SwkbdRequestCommand request_command;
158 std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
159 307
160 if (config.utf_8) { 308 std::memcpy(&request_command, request_data.data(), sizeof(SwkbdRequestCommand));
161 const u64 size = text->size() + sizeof(u64);
162 const auto new_text = Common::UTF16ToUTF8(*text);
163 309
164 std::memcpy(output_sub.data(), &size, sizeof(u64)); 310 switch (request_command) {
165 std::memcpy(output_sub.data() + 8, new_text.data(), 311 case SwkbdRequestCommand::Finalize:
166 std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8)); 312 RequestFinalize(request_data);
313 break;
314 case SwkbdRequestCommand::SetUserWordInfo:
315 RequestSetUserWordInfo(request_data);
316 break;
317 case SwkbdRequestCommand::SetCustomizeDic:
318 RequestSetCustomizeDic(request_data);
319 break;
320 case SwkbdRequestCommand::Calc:
321 RequestCalc(request_data);
322 break;
323 case SwkbdRequestCommand::SetCustomizedDictionaries:
324 RequestSetCustomizedDictionaries(request_data);
325 break;
326 case SwkbdRequestCommand::UnsetCustomizedDictionaries:
327 RequestUnsetCustomizedDictionaries(request_data);
328 break;
329 case SwkbdRequestCommand::SetChangedStringV2Flag:
330 RequestSetChangedStringV2Flag(request_data);
331 break;
332 case SwkbdRequestCommand::SetMovedCursorV2Flag:
333 RequestSetMovedCursorV2Flag(request_data);
334 break;
335 default:
336 UNIMPLEMENTED_MSG("Unknown SwkbdRequestCommand={}", request_command);
337 break;
338 }
339}
167 340
168 output_main[0] = INTERACTIVE_STATUS_OK; 341void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result,
169 std::memcpy(output_main.data() + 4, new_text.data(), 342 std::u16string submitted_text) {
170 std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); 343 std::vector<u8> out_data(sizeof(SwkbdResult) + STRING_BUFFER_SIZE);
171 } else {
172 const u64 size = text->size() * 2 + sizeof(u64);
173 std::memcpy(output_sub.data(), &size, sizeof(u64));
174 std::memcpy(output_sub.data() + 8, text->data(),
175 std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
176 344
177 output_main[0] = INTERACTIVE_STATUS_OK; 345 if (swkbd_config_common.use_utf8) {
178 std::memcpy(output_main.data() + 4, text->data(), 346 std::string utf8_submitted_text = Common::UTF16ToUTF8(submitted_text);
179 std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
180 }
181 347
182 complete = !config.text_check; 348 LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-8 Submitted Text: {}", result,
183 final_data = output_main; 349 utf8_submitted_text);
184 350
185 if (complete) { 351 std::memcpy(out_data.data(), &result, sizeof(SwkbdResult));
186 broker.PushNormalDataFromApplet( 352 std::memcpy(out_data.data() + sizeof(SwkbdResult), utf8_submitted_text.data(),
187 std::make_shared<IStorage>(system, std::move(output_main))); 353 utf8_submitted_text.size());
188 broker.SignalStateChanged();
189 } else {
190 broker.PushInteractiveDataFromApplet(
191 std::make_shared<IStorage>(system, std::move(output_sub)));
192 }
193 } else { 354 } else {
194 output_main[0] = 1; 355 LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-16 Submitted Text: {}", result,
195 complete = true; 356 Common::UTF16ToUTF8(submitted_text));
196 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(output_main))); 357
197 broker.SignalStateChanged(); 358 std::memcpy(out_data.data(), &result, sizeof(SwkbdResult));
359 std::memcpy(out_data.data() + sizeof(SwkbdResult), submitted_text.data(),
360 submitted_text.size() * sizeof(char16_t));
361 }
362
363 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
364
365 ExitKeyboard();
366}
367
368void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
369 current_text = std::move(submitted_text);
370
371 std::vector<u8> out_data(sizeof(u64) + STRING_BUFFER_SIZE);
372
373 if (swkbd_config_common.use_utf8) {
374 std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text);
375 const u64 buffer_size = sizeof(u64) + utf8_submitted_text.size();
376
377 LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size,
378 utf8_submitted_text);
379
380 std::memcpy(out_data.data(), &buffer_size, sizeof(u64));
381 std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(),
382 utf8_submitted_text.size());
383 } else {
384 const u64 buffer_size = sizeof(u64) + current_text.size() * sizeof(char16_t);
385
386 LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size,
387 Common::UTF16ToUTF8(current_text));
388
389 std::memcpy(out_data.data(), &buffer_size, sizeof(u64));
390 std::memcpy(out_data.data() + sizeof(u64), current_text.data(),
391 current_text.size() * sizeof(char16_t));
392 }
393
394 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
395}
396
397void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) {
398 switch (reply_type) {
399 case SwkbdReplyType::FinishedInitialize:
400 ReplyFinishedInitialize();
401 break;
402 case SwkbdReplyType::Default:
403 ReplyDefault();
404 break;
405 case SwkbdReplyType::ChangedString:
406 ReplyChangedString();
407 break;
408 case SwkbdReplyType::MovedCursor:
409 ReplyMovedCursor();
410 break;
411 case SwkbdReplyType::MovedTab:
412 ReplyMovedTab();
413 break;
414 case SwkbdReplyType::DecidedEnter:
415 ReplyDecidedEnter();
416 break;
417 case SwkbdReplyType::DecidedCancel:
418 ReplyDecidedCancel();
419 break;
420 case SwkbdReplyType::ChangedStringUtf8:
421 ReplyChangedStringUtf8();
422 break;
423 case SwkbdReplyType::MovedCursorUtf8:
424 ReplyMovedCursorUtf8();
425 break;
426 case SwkbdReplyType::DecidedEnterUtf8:
427 ReplyDecidedEnterUtf8();
428 break;
429 case SwkbdReplyType::UnsetCustomizeDic:
430 ReplyUnsetCustomizeDic();
431 break;
432 case SwkbdReplyType::ReleasedUserWordInfo:
433 ReplyReleasedUserWordInfo();
434 break;
435 case SwkbdReplyType::UnsetCustomizedDictionaries:
436 ReplyUnsetCustomizedDictionaries();
437 break;
438 case SwkbdReplyType::ChangedStringV2:
439 ReplyChangedStringV2();
440 break;
441 case SwkbdReplyType::MovedCursorV2:
442 ReplyMovedCursorV2();
443 break;
444 case SwkbdReplyType::ChangedStringUtf8V2:
445 ReplyChangedStringUtf8V2();
446 break;
447 case SwkbdReplyType::MovedCursorUtf8V2:
448 ReplyMovedCursorUtf8V2();
449 break;
450 default:
451 UNIMPLEMENTED_MSG("Unknown SwkbdReplyType={}", reply_type);
452 ReplyDefault();
453 break;
454 }
455}
456
457void SoftwareKeyboard::ChangeState(SwkbdState state) {
458 swkbd_state = state;
459
460 ReplyDefault();
461}
462
463void SoftwareKeyboard::InitializeFrontendKeyboard() {
464 if (is_background) {
465 const auto& appear_arg = swkbd_calc_arg.appear_arg;
466
467 std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
468 appear_arg.ok_text.data(), appear_arg.ok_text.size());
469
470 const u32 max_text_length =
471 appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
472 ? appear_arg.max_text_length
473 : DEFAULT_MAX_TEXT_LENGTH;
474
475 const u32 min_text_length =
476 appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
477
478 const s32 initial_cursor_position =
479 current_cursor_position > 0 ? current_cursor_position : 0;
480
481 const auto text_draw_type =
482 max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
483
484 Core::Frontend::KeyboardInitializeParameters initialize_parameters{
485 .ok_text{ok_text},
486 .header_text{},
487 .sub_text{},
488 .guide_text{},
489 .initial_text{current_text},
490 .max_text_length{max_text_length},
491 .min_text_length{min_text_length},
492 .initial_cursor_position{initial_cursor_position},
493 .type{appear_arg.type},
494 .password_mode{SwkbdPasswordMode::Disabled},
495 .text_draw_type{text_draw_type},
496 .key_disable_flags{appear_arg.key_disable_flags},
497 .use_blur_background{false},
498 .enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
499 .enable_return_button{appear_arg.enable_return_button},
500 .disable_cancel_button{appear_arg.disable_cancel_button},
501 };
502
503 frontend.InitializeKeyboard(
504 true, std::move(initialize_parameters), {},
505 [this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) {
506 SubmitTextInline(reply_type, submitted_text, cursor_position);
507 });
508 } else {
509 std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
510 swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size());
511
512 std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
513 swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size());
514
515 std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
516 swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size());
517
518 std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
519 swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size());
520
521 const u32 max_text_length =
522 swkbd_config_common.max_text_length > 0 &&
523 swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
524 ? swkbd_config_common.max_text_length
525 : DEFAULT_MAX_TEXT_LENGTH;
526
527 const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length
528 ? swkbd_config_common.min_text_length
529 : 0;
530
531 const s32 initial_cursor_position = [this] {
532 switch (swkbd_config_common.initial_cursor_position) {
533 case SwkbdInitialCursorPosition::Start:
534 default:
535 return 0;
536 case SwkbdInitialCursorPosition::End:
537 return static_cast<s32>(initial_text.size());
538 }
539 }();
540
541 const auto text_draw_type = [this, max_text_length] {
542 switch (swkbd_config_common.text_draw_type) {
543 case SwkbdTextDrawType::Line:
544 default:
545 return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
546 case SwkbdTextDrawType::Box:
547 case SwkbdTextDrawType::DownloadCode:
548 return swkbd_config_common.text_draw_type;
549 }
550 }();
551
552 const auto enable_return_button = text_draw_type == SwkbdTextDrawType::Box
553 ? swkbd_config_common.enable_return_button
554 : false;
555
556 const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227
557 ? swkbd_config_new.disable_cancel_button
558 : false;
559
560 Core::Frontend::KeyboardInitializeParameters initialize_parameters{
561 .ok_text{ok_text},
562 .header_text{header_text},
563 .sub_text{sub_text},
564 .guide_text{guide_text},
565 .initial_text{initial_text},
566 .max_text_length{max_text_length},
567 .min_text_length{min_text_length},
568 .initial_cursor_position{initial_cursor_position},
569 .type{swkbd_config_common.type},
570 .password_mode{swkbd_config_common.password_mode},
571 .text_draw_type{text_draw_type},
572 .key_disable_flags{swkbd_config_common.key_disable_flags},
573 .use_blur_background{swkbd_config_common.use_blur_background},
574 .enable_backspace_button{true},
575 .enable_return_button{enable_return_button},
576 .disable_cancel_button{disable_cancel_button},
577 };
578
579 frontend.InitializeKeyboard(false, std::move(initialize_parameters),
580 [this](SwkbdResult result, std::u16string submitted_text) {
581 SubmitTextNormal(result, submitted_text);
582 },
583 {});
584 }
585}
586
587void SoftwareKeyboard::ShowNormalKeyboard() {
588 frontend.ShowNormalKeyboard();
589}
590
591void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
592 std::u16string text_check_message) {
593 frontend.ShowTextCheckDialog(text_check_result, text_check_message);
594}
595
596void SoftwareKeyboard::ShowInlineKeyboard() {
597 if (swkbd_state != SwkbdState::InitializedIsHidden) {
598 return;
599 }
600
601 ChangeState(SwkbdState::InitializedIsAppearing);
602
603 const auto& appear_arg = swkbd_calc_arg.appear_arg;
604
605 const u32 max_text_length =
606 appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
607 ? appear_arg.max_text_length
608 : DEFAULT_MAX_TEXT_LENGTH;
609
610 const u32 min_text_length =
611 appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
612
613 Core::Frontend::InlineAppearParameters appear_parameters{
614 .max_text_length{max_text_length},
615 .min_text_length{min_text_length},
616 .key_top_scale_x{swkbd_calc_arg.key_top_scale_x},
617 .key_top_scale_y{swkbd_calc_arg.key_top_scale_y},
618 .key_top_translate_x{swkbd_calc_arg.key_top_translate_x},
619 .key_top_translate_y{swkbd_calc_arg.key_top_translate_y},
620 .type{appear_arg.type},
621 .key_disable_flags{appear_arg.key_disable_flags},
622 .key_top_as_floating{swkbd_calc_arg.key_top_as_floating},
623 .enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
624 .enable_return_button{appear_arg.enable_return_button},
625 .disable_cancel_button{appear_arg.disable_cancel_button},
626 };
627
628 frontend.ShowInlineKeyboard(std::move(appear_parameters));
629
630 ChangeState(SwkbdState::InitializedIsShown);
631}
632
633void SoftwareKeyboard::HideInlineKeyboard() {
634 if (swkbd_state != SwkbdState::InitializedIsShown) {
635 return;
636 }
637
638 ChangeState(SwkbdState::InitializedIsDisappearing);
639
640 frontend.HideInlineKeyboard();
641
642 ChangeState(SwkbdState::InitializedIsHidden);
643}
644
645void SoftwareKeyboard::InlineTextChanged() {
646 Core::Frontend::InlineTextParameters text_parameters{
647 .input_text{current_text},
648 .cursor_position{current_cursor_position},
649 };
650
651 frontend.InlineTextChanged(std::move(text_parameters));
652}
653
654void SoftwareKeyboard::ExitKeyboard() {
655 complete = true;
656 status = RESULT_SUCCESS;
657
658 frontend.ExitKeyboard();
659
660 broker.SignalStateChanged();
661}
662
663// Inline Software Keyboard Requests
664
665void SoftwareKeyboard::RequestFinalize(const std::vector<u8>& request_data) {
666 LOG_DEBUG(Service_AM, "Processing Request: Finalize");
667
668 ChangeState(SwkbdState::NotInitialized);
669
670 ExitKeyboard();
671}
672
673void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector<u8>& request_data) {
674 LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented.");
675}
676
677void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector<u8>& request_data) {
678 LOG_WARNING(Service_AM, "SetCustomizeDic is not implemented.");
679}
680
681void SoftwareKeyboard::RequestCalc(const std::vector<u8>& request_data) {
682 LOG_DEBUG(Service_AM, "Processing Request: Calc");
683
684 ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArg));
685
686 std::memcpy(&swkbd_calc_arg, request_data.data() + sizeof(SwkbdRequestCommand),
687 sizeof(SwkbdCalcArg));
688
689 if (swkbd_calc_arg.flags.set_input_text) {
690 current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
691 swkbd_calc_arg.input_text.data(), swkbd_calc_arg.input_text.size());
692 }
693
694 if (swkbd_calc_arg.flags.set_cursor_position) {
695 current_cursor_position = swkbd_calc_arg.cursor_position;
696 }
697
698 if (swkbd_calc_arg.flags.set_utf8_mode) {
699 inline_use_utf8 = swkbd_calc_arg.utf8_mode;
700 }
701
702 if (swkbd_state <= SwkbdState::InitializedIsHidden &&
703 swkbd_calc_arg.flags.unset_customize_dic) {
704 ReplyUnsetCustomizeDic();
198 } 705 }
706
707 if (swkbd_state <= SwkbdState::InitializedIsHidden &&
708 swkbd_calc_arg.flags.unset_user_word_info) {
709 ReplyReleasedUserWordInfo();
710 }
711
712 if (swkbd_state == SwkbdState::NotInitialized && swkbd_calc_arg.flags.set_initialize_arg) {
713 InitializeFrontendKeyboard();
714
715 ChangeState(SwkbdState::InitializedIsHidden);
716
717 ReplyFinishedInitialize();
718 }
719
720 if (!swkbd_calc_arg.flags.set_initialize_arg &&
721 (swkbd_calc_arg.flags.set_input_text || swkbd_calc_arg.flags.set_cursor_position)) {
722 InlineTextChanged();
723 }
724
725 if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg.flags.appear) {
726 ShowInlineKeyboard();
727 return;
728 }
729
730 if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg.flags.disappear) {
731 HideInlineKeyboard();
732 return;
733 }
734}
735
736void SoftwareKeyboard::RequestSetCustomizedDictionaries(const std::vector<u8>& request_data) {
737 LOG_WARNING(Service_AM, "SetCustomizedDictionaries is not implemented.");
738}
739
740void SoftwareKeyboard::RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data) {
741 LOG_WARNING(Service_AM, "(STUBBED) Processing Request: UnsetCustomizedDictionaries");
742
743 ReplyUnsetCustomizedDictionaries();
744}
745
746void SoftwareKeyboard::RequestSetChangedStringV2Flag(const std::vector<u8>& request_data) {
747 LOG_DEBUG(Service_AM, "Processing Request: SetChangedStringV2Flag");
748
749 ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1);
750
751 std::memcpy(&use_changed_string_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1);
752}
753
754void SoftwareKeyboard::RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data) {
755 LOG_DEBUG(Service_AM, "Processing Request: SetMovedCursorV2Flag");
756
757 ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1);
758
759 std::memcpy(&use_moved_cursor_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1);
760}
761
762// Inline Software Keyboard Replies
763
764void SoftwareKeyboard::ReplyFinishedInitialize() {
765 LOG_DEBUG(Service_AM, "Sending Reply: FinishedInitialize");
766
767 std::vector<u8> reply(REPLY_BASE_SIZE + 1);
768
769 SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize);
770
771 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
772}
773
774void SoftwareKeyboard::ReplyDefault() {
775 LOG_DEBUG(Service_AM, "Sending Reply: Default");
776
777 std::vector<u8> reply(REPLY_BASE_SIZE);
778
779 SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default);
780
781 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
782}
783
784void SoftwareKeyboard::ReplyChangedString() {
785 LOG_DEBUG(Service_AM, "Sending Reply: ChangedString");
786
787 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg));
788
789 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedString);
790
791 const SwkbdChangedStringArg changed_string_arg{
792 .text_length{static_cast<u32>(current_text.size())},
793 .dictionary_start_cursor_position{-1},
794 .dictionary_end_cursor_position{-1},
795 .cursor_position{current_cursor_position},
796 };
797
798 std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
799 current_text.size() * sizeof(char16_t));
800 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
801 sizeof(SwkbdChangedStringArg));
802
803 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
804}
805
806void SoftwareKeyboard::ReplyMovedCursor() {
807 LOG_DEBUG(Service_AM, "Sending Reply: MovedCursor");
808
809 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg));
810
811 SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursor);
812
813 const SwkbdMovedCursorArg moved_cursor_arg{
814 .text_length{static_cast<u32>(current_text.size())},
815 .cursor_position{current_cursor_position},
816 };
817
818 std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
819 current_text.size() * sizeof(char16_t));
820 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
821 sizeof(SwkbdMovedCursorArg));
822
823 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
824}
825
826void SoftwareKeyboard::ReplyMovedTab() {
827 LOG_DEBUG(Service_AM, "Sending Reply: MovedTab");
828
829 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedTabArg));
830
831 SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedTab);
832
833 const SwkbdMovedTabArg moved_tab_arg{
834 .text_length{static_cast<u32>(current_text.size())},
835 .cursor_position{current_cursor_position},
836 };
837
838 std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
839 current_text.size() * sizeof(char16_t));
840 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg,
841 sizeof(SwkbdMovedTabArg));
842
843 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
844}
845
846void SoftwareKeyboard::ReplyDecidedEnter() {
847 LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnter");
848
849 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdDecidedEnterArg));
850
851 SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnter);
852
853 const SwkbdDecidedEnterArg decided_enter_arg{
854 .text_length{static_cast<u32>(current_text.size())},
855 };
856
857 std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
858 current_text.size() * sizeof(char16_t));
859 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg,
860 sizeof(SwkbdDecidedEnterArg));
861
862 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
863
864 HideInlineKeyboard();
865}
866
867void SoftwareKeyboard::ReplyDecidedCancel() {
868 LOG_DEBUG(Service_AM, "Sending Reply: DecidedCancel");
869
870 std::vector<u8> reply(REPLY_BASE_SIZE);
871
872 SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel);
873
874 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
875
876 HideInlineKeyboard();
877}
878
879void SoftwareKeyboard::ReplyChangedStringUtf8() {
880 LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8");
881
882 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg));
883
884 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8);
885
886 std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
887
888 const SwkbdChangedStringArg changed_string_arg{
889 .text_length{static_cast<u32>(current_text.size())},
890 .dictionary_start_cursor_position{-1},
891 .dictionary_end_cursor_position{-1},
892 .cursor_position{current_cursor_position},
893 };
894
895 std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
896 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
897 sizeof(SwkbdChangedStringArg));
898
899 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
199} 900}
901
902void SoftwareKeyboard::ReplyMovedCursorUtf8() {
903 LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8");
904
905 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg));
906
907 SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8);
908
909 std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
910
911 const SwkbdMovedCursorArg moved_cursor_arg{
912 .text_length{static_cast<u32>(current_text.size())},
913 .cursor_position{current_cursor_position},
914 };
915
916 std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
917 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
918 sizeof(SwkbdMovedCursorArg));
919
920 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
921}
922
923void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
924 LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnterUtf8");
925
926 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdDecidedEnterArg));
927
928 SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnterUtf8);
929
930 std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
931
932 const SwkbdDecidedEnterArg decided_enter_arg{
933 .text_length{static_cast<u32>(current_text.size())},
934 };
935
936 std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
937 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg,
938 sizeof(SwkbdDecidedEnterArg));
939
940 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
941
942 HideInlineKeyboard();
943}
944
945void SoftwareKeyboard::ReplyUnsetCustomizeDic() {
946 LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizeDic");
947
948 std::vector<u8> reply(REPLY_BASE_SIZE);
949
950 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic);
951
952 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
953}
954
955void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
956 LOG_DEBUG(Service_AM, "Sending Reply: ReleasedUserWordInfo");
957
958 std::vector<u8> reply(REPLY_BASE_SIZE);
959
960 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo);
961
962 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
963}
964
965void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
966 LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizedDictionaries");
967
968 std::vector<u8> reply(REPLY_BASE_SIZE);
969
970 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries);
971
972 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
973}
974
975void SoftwareKeyboard::ReplyChangedStringV2() {
976 LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringV2");
977
978 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg) + 1);
979
980 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringV2);
981
982 const SwkbdChangedStringArg changed_string_arg{
983 .text_length{static_cast<u32>(current_text.size())},
984 .dictionary_start_cursor_position{-1},
985 .dictionary_end_cursor_position{-1},
986 .cursor_position{current_cursor_position},
987 };
988
989 constexpr u8 flag = 0;
990
991 std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
992 current_text.size() * sizeof(char16_t));
993 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
994 sizeof(SwkbdChangedStringArg));
995 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg),
996 &flag, 1);
997
998 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
999}
1000
1001void SoftwareKeyboard::ReplyMovedCursorV2() {
1002 LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorV2");
1003
1004 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg) + 1);
1005
1006 SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorV2);
1007
1008 const SwkbdMovedCursorArg moved_cursor_arg{
1009 .text_length{static_cast<u32>(current_text.size())},
1010 .cursor_position{current_cursor_position},
1011 };
1012
1013 constexpr u8 flag = 0;
1014
1015 std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
1016 current_text.size() * sizeof(char16_t));
1017 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
1018 sizeof(SwkbdMovedCursorArg));
1019 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg),
1020 &flag, 1);
1021
1022 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
1023}
1024
1025void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
1026 LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8V2");
1027
1028 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg) + 1);
1029
1030 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8V2);
1031
1032 std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
1033
1034 const SwkbdChangedStringArg changed_string_arg{
1035 .text_length{static_cast<u32>(current_text.size())},
1036 .dictionary_start_cursor_position{-1},
1037 .dictionary_end_cursor_position{-1},
1038 .cursor_position{current_cursor_position},
1039 };
1040
1041 constexpr u8 flag = 0;
1042
1043 std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
1044 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
1045 sizeof(SwkbdChangedStringArg));
1046 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg),
1047 &flag, 1);
1048
1049 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
1050}
1051
1052void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
1053 LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8V2");
1054
1055 std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg) + 1);
1056
1057 SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8V2);
1058
1059 std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
1060
1061 const SwkbdMovedCursorArg moved_cursor_arg{
1062 .text_length{static_cast<u32>(current_text.size())},
1063 .cursor_position{current_cursor_position},
1064 };
1065
1066 constexpr u8 flag = 0;
1067
1068 std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
1069 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
1070 sizeof(SwkbdMovedCursorArg));
1071 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg),
1072 &flag, 1);
1073
1074 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
1075}
1076
200} // namespace Service::AM::Applets 1077} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index 1d260fef8..85aeb4eb1 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -1,20 +1,14 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2021 yuzu Emulator Project
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 5#pragma once
6 6
7#include <array>
8#include <string>
9#include <vector>
10
11#include "common/common_funcs.h" 7#include "common/common_funcs.h"
12#include "common/common_types.h" 8#include "common/common_types.h"
13#include "common/swap.h" 9#include "core/hle/result.h"
14#include "core/hle/service/am/am.h"
15#include "core/hle/service/am/applets/applets.h" 10#include "core/hle/service/am/applets/applets.h"
16 11#include "core/hle/service/am/applets/software_keyboard_types.h"
17union ResultCode;
18 12
19namespace Core { 13namespace Core {
20class System; 14class System;
@@ -22,45 +16,10 @@ class System;
22 16
23namespace Service::AM::Applets { 17namespace Service::AM::Applets {
24 18
25enum class KeysetDisable : u32 {
26 Space = 0x02,
27 Address = 0x04,
28 Percent = 0x08,
29 Slashes = 0x10,
30 Numbers = 0x40,
31 DownloadCode = 0x80,
32};
33
34struct KeyboardConfig {
35 INSERT_PADDING_BYTES(4);
36 std::array<char16_t, 9> submit_text;
37 u16_le left_symbol_key;
38 u16_le right_symbol_key;
39 INSERT_PADDING_BYTES(1);
40 KeysetDisable keyset_disable_bitmask;
41 u32_le initial_cursor_position;
42 std::array<char16_t, 65> header_text;
43 std::array<char16_t, 129> sub_text;
44 std::array<char16_t, 257> guide_text;
45 u32_le length_limit;
46 INSERT_PADDING_BYTES(4);
47 u32_le is_password;
48 INSERT_PADDING_BYTES(5);
49 bool utf_8;
50 bool draw_background;
51 u32_le initial_string_offset;
52 u32_le initial_string_size;
53 u32_le user_dictionary_offset;
54 u32_le user_dictionary_size;
55 bool text_check;
56 u64_le text_check_callback;
57};
58static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size.");
59
60class SoftwareKeyboard final : public Applet { 19class SoftwareKeyboard final : public Applet {
61public: 20public:
62 explicit SoftwareKeyboard(Core::System& system_, 21 explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
63 const Core::Frontend::SoftwareKeyboardApplet& frontend_); 22 Core::Frontend::SoftwareKeyboardApplet& frontend_);
64 ~SoftwareKeyboard() override; 23 ~SoftwareKeyboard() override;
65 24
66 void Initialize() override; 25 void Initialize() override;
@@ -70,17 +29,139 @@ public:
70 void ExecuteInteractive() override; 29 void ExecuteInteractive() override;
71 void Execute() override; 30 void Execute() override;
72 31
73 void WriteText(std::optional<std::u16string> text); 32 /**
33 * Submits the input text to the application.
34 * If text checking is enabled, the application will verify the input text.
35 * If use_utf8 is enabled, the input text will be converted to UTF-8 prior to being submitted.
36 * This should only be used by the normal software keyboard.
37 *
38 * @param result SwkbdResult enum
39 * @param submitted_text UTF-16 encoded string
40 */
41 void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text);
42
43 /**
44 * Submits the input text to the application.
45 * If utf8_mode is enabled, the input text will be converted to UTF-8 prior to being submitted.
46 * This should only be used by the inline software keyboard.
47 *
48 * @param reply_type SwkbdReplyType enum
49 * @param submitted_text UTF-16 encoded string
50 * @param cursor_position The current position of the text cursor
51 */
52 void SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
53 s32 cursor_position);
74 54
75private: 55private:
76 const Core::Frontend::SoftwareKeyboardApplet& frontend; 56 /// Initializes the normal software keyboard.
57 void InitializeForeground();
77 58
78 KeyboardConfig config; 59 /// Initializes the inline software keyboard.
79 std::u16string initial_text; 60 void InitializeBackground(LibraryAppletMode applet_mode);
80 bool complete = false; 61
81 bool is_inline = false; 62 /// Processes the text check sent by the application.
82 std::vector<u8> final_data; 63 void ProcessTextCheck();
64
65 /// Processes the inline software keyboard request command sent by the application.
66 void ProcessInlineKeyboardRequest();
67
68 /// Submits the input text and exits the applet.
69 void SubmitNormalOutputAndExit(SwkbdResult result, std::u16string submitted_text);
70
71 /// Submits the input text for text checking.
72 void SubmitForTextCheck(std::u16string submitted_text);
73
74 /// Sends a reply to the application after processing a request command.
75 void SendReply(SwkbdReplyType reply_type);
76
77 /// Changes the inline keyboard state.
78 void ChangeState(SwkbdState state);
79
80 /**
81 * Signals the frontend to initialize the software keyboard with common parameters.
82 * This initializes either the normal software keyboard or the inline software keyboard
83 * depending on the state of is_background.
84 * Note that this does not cause the keyboard to appear.
85 * Use the respective Show*Keyboard() functions to cause the respective keyboards to appear.
86 */
87 void InitializeFrontendKeyboard();
88
89 /// Signals the frontend to show the normal software keyboard.
90 void ShowNormalKeyboard();
91
92 /// Signals the frontend to show the text check dialog.
93 void ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
94 std::u16string text_check_message);
95
96 /// Signals the frontend to show the inline software keyboard.
97 void ShowInlineKeyboard();
98
99 /// Signals the frontend to hide the inline software keyboard.
100 void HideInlineKeyboard();
101
102 /// Signals the frontend that the current inline keyboard text has changed.
103 void InlineTextChanged();
104
105 /// Signals both the frontend and application that the software keyboard is exiting.
106 void ExitKeyboard();
107
108 // Inline Software Keyboard Requests
109
110 void RequestFinalize(const std::vector<u8>& request_data);
111 void RequestSetUserWordInfo(const std::vector<u8>& request_data);
112 void RequestSetCustomizeDic(const std::vector<u8>& request_data);
113 void RequestCalc(const std::vector<u8>& request_data);
114 void RequestSetCustomizedDictionaries(const std::vector<u8>& request_data);
115 void RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data);
116 void RequestSetChangedStringV2Flag(const std::vector<u8>& request_data);
117 void RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data);
118
119 // Inline Software Keyboard Replies
120
121 void ReplyFinishedInitialize();
122 void ReplyDefault();
123 void ReplyChangedString();
124 void ReplyMovedCursor();
125 void ReplyMovedTab();
126 void ReplyDecidedEnter();
127 void ReplyDecidedCancel();
128 void ReplyChangedStringUtf8();
129 void ReplyMovedCursorUtf8();
130 void ReplyDecidedEnterUtf8();
131 void ReplyUnsetCustomizeDic();
132 void ReplyReleasedUserWordInfo();
133 void ReplyUnsetCustomizedDictionaries();
134 void ReplyChangedStringV2();
135 void ReplyMovedCursorV2();
136 void ReplyChangedStringUtf8V2();
137 void ReplyMovedCursorUtf8V2();
138
139 LibraryAppletMode applet_mode;
140 Core::Frontend::SoftwareKeyboardApplet& frontend;
83 Core::System& system; 141 Core::System& system;
142
143 SwkbdAppletVersion swkbd_applet_version;
144
145 SwkbdConfigCommon swkbd_config_common;
146 SwkbdConfigOld swkbd_config_old;
147 SwkbdConfigOld2 swkbd_config_old2;
148 SwkbdConfigNew swkbd_config_new;
149 std::u16string initial_text;
150
151 SwkbdState swkbd_state{SwkbdState::NotInitialized};
152 SwkbdInitializeArg swkbd_initialize_arg;
153 SwkbdCalcArg swkbd_calc_arg;
154 bool use_changed_string_v2{false};
155 bool use_moved_cursor_v2{false};
156 bool inline_use_utf8{false};
157 s32 current_cursor_position{};
158
159 std::u16string current_text;
160
161 bool is_background{false};
162
163 bool complete{false};
164 ResultCode status{RESULT_SUCCESS};
84}; 165};
85 166
86} // namespace Service::AM::Applets 167} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/software_keyboard_types.h b/src/core/hle/service/am/applets/software_keyboard_types.h
new file mode 100644
index 000000000..21aa8e800
--- /dev/null
+++ b/src/core/hle/service/am/applets/software_keyboard_types.h
@@ -0,0 +1,295 @@
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
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12#include "common/swap.h"
13
14namespace Service::AM::Applets {
15
16constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
17constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
18constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
19constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
20constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
21
22enum class SwkbdAppletVersion : u32_le {
23 Version5 = 0x5, // 1.0.0
24 Version65542 = 0x10006, // 2.0.0 - 2.3.0
25 Version196615 = 0x30007, // 3.0.0 - 3.0.2
26 Version262152 = 0x40008, // 4.0.0 - 4.1.0
27 Version327689 = 0x50009, // 5.0.0 - 5.1.0
28 Version393227 = 0x6000B, // 6.0.0 - 7.0.1
29 Version524301 = 0x8000D, // 8.0.0+
30};
31
32enum class SwkbdType : u32 {
33 Normal,
34 NumberPad,
35 Qwerty,
36 Unknown3,
37 Latin,
38 SimplifiedChinese,
39 TraditionalChinese,
40 Korean,
41};
42
43enum class SwkbdInitialCursorPosition : u32 {
44 Start,
45 End,
46};
47
48enum class SwkbdPasswordMode : u32 {
49 Disabled,
50 Enabled,
51};
52
53enum class SwkbdTextDrawType : u32 {
54 Line,
55 Box,
56 DownloadCode,
57};
58
59enum class SwkbdResult : u32 {
60 Ok,
61 Cancel,
62};
63
64enum class SwkbdTextCheckResult : u32 {
65 Success,
66 Failure,
67 Confirm,
68 Silent,
69};
70
71enum class SwkbdState : u32 {
72 NotInitialized = 0x0,
73 InitializedIsHidden = 0x1,
74 InitializedIsAppearing = 0x2,
75 InitializedIsShown = 0x3,
76 InitializedIsDisappearing = 0x4,
77};
78
79enum class SwkbdRequestCommand : u32 {
80 Finalize = 0x4,
81 SetUserWordInfo = 0x6,
82 SetCustomizeDic = 0x7,
83 Calc = 0xA,
84 SetCustomizedDictionaries = 0xB,
85 UnsetCustomizedDictionaries = 0xC,
86 SetChangedStringV2Flag = 0xD,
87 SetMovedCursorV2Flag = 0xE,
88};
89
90enum class SwkbdReplyType : u32 {
91 FinishedInitialize = 0x0,
92 Default = 0x1,
93 ChangedString = 0x2,
94 MovedCursor = 0x3,
95 MovedTab = 0x4,
96 DecidedEnter = 0x5,
97 DecidedCancel = 0x6,
98 ChangedStringUtf8 = 0x7,
99 MovedCursorUtf8 = 0x8,
100 DecidedEnterUtf8 = 0x9,
101 UnsetCustomizeDic = 0xA,
102 ReleasedUserWordInfo = 0xB,
103 UnsetCustomizedDictionaries = 0xC,
104 ChangedStringV2 = 0xD,
105 MovedCursorV2 = 0xE,
106 ChangedStringUtf8V2 = 0xF,
107 MovedCursorUtf8V2 = 0x10,
108};
109
110struct SwkbdKeyDisableFlags {
111 union {
112 u32 raw{};
113
114 BitField<1, 1, u32> space;
115 BitField<2, 1, u32> at;
116 BitField<3, 1, u32> percent;
117 BitField<4, 1, u32> slash;
118 BitField<5, 1, u32> backslash;
119 BitField<6, 1, u32> numbers;
120 BitField<7, 1, u32> download_code;
121 BitField<8, 1, u32> username;
122 };
123};
124static_assert(sizeof(SwkbdKeyDisableFlags) == 0x4, "SwkbdKeyDisableFlags has incorrect size.");
125
126struct SwkbdConfigCommon {
127 SwkbdType type{};
128 std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{};
129 char16_t left_optional_symbol_key{};
130 char16_t right_optional_symbol_key{};
131 bool use_prediction{};
132 INSERT_PADDING_BYTES(1);
133 SwkbdKeyDisableFlags key_disable_flags{};
134 SwkbdInitialCursorPosition initial_cursor_position{};
135 std::array<char16_t, MAX_HEADER_TEXT_LENGTH + 1> header_text{};
136 std::array<char16_t, MAX_SUB_TEXT_LENGTH + 1> sub_text{};
137 std::array<char16_t, MAX_GUIDE_TEXT_LENGTH + 1> guide_text{};
138 u32 max_text_length{};
139 u32 min_text_length{};
140 SwkbdPasswordMode password_mode{};
141 SwkbdTextDrawType text_draw_type{};
142 bool enable_return_button{};
143 bool use_utf8{};
144 bool use_blur_background{};
145 INSERT_PADDING_BYTES(1);
146 u32 initial_string_offset{};
147 u32 initial_string_length{};
148 u32 user_dictionary_offset{};
149 u32 user_dictionary_entries{};
150 bool use_text_check{};
151 INSERT_PADDING_BYTES(3);
152};
153static_assert(sizeof(SwkbdConfigCommon) == 0x3D4, "SwkbdConfigCommon has incorrect size.");
154
155#pragma pack(push, 4)
156// SwkbdAppletVersion 0x5, 0x10006
157struct SwkbdConfigOld {
158 INSERT_PADDING_WORDS(1);
159 VAddr text_check_callback{};
160};
161static_assert(sizeof(SwkbdConfigOld) == 0x3E0 - sizeof(SwkbdConfigCommon),
162 "SwkbdConfigOld has incorrect size.");
163
164// SwkbdAppletVersion 0x30007, 0x40008, 0x50009
165struct SwkbdConfigOld2 {
166 INSERT_PADDING_WORDS(1);
167 VAddr text_check_callback{};
168 std::array<u32, 8> text_grouping{};
169};
170static_assert(sizeof(SwkbdConfigOld2) == 0x400 - sizeof(SwkbdConfigCommon),
171 "SwkbdConfigOld2 has incorrect size.");
172
173// SwkbdAppletVersion 0x6000B, 0x8000D
174struct SwkbdConfigNew {
175 std::array<u32, 8> text_grouping{};
176 std::array<u64, 24> customized_dictionary_set_entries{};
177 u8 total_customized_dictionary_set_entries{};
178 bool disable_cancel_button{};
179 INSERT_PADDING_BYTES(18);
180};
181static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon),
182 "SwkbdConfigNew has incorrect size.");
183#pragma pack(pop)
184
185struct SwkbdTextCheck {
186 SwkbdTextCheckResult text_check_result{};
187 std::array<char16_t, STRING_BUFFER_SIZE / 2> text_check_message{};
188};
189static_assert(sizeof(SwkbdTextCheck) == 0x7D8, "SwkbdTextCheck has incorrect size.");
190
191struct SwkbdCalcArgFlags {
192 union {
193 u64 raw{};
194
195 BitField<0, 1, u64> set_initialize_arg;
196 BitField<1, 1, u64> set_volume;
197 BitField<2, 1, u64> appear;
198 BitField<3, 1, u64> set_input_text;
199 BitField<4, 1, u64> set_cursor_position;
200 BitField<5, 1, u64> set_utf8_mode;
201 BitField<6, 1, u64> unset_customize_dic;
202 BitField<7, 1, u64> disappear;
203 BitField<8, 1, u64> unknown;
204 BitField<9, 1, u64> set_key_top_translate_scale;
205 BitField<10, 1, u64> unset_user_word_info;
206 BitField<11, 1, u64> set_disable_hardware_keyboard;
207 };
208};
209static_assert(sizeof(SwkbdCalcArgFlags) == 0x8, "SwkbdCalcArgFlags has incorrect size.");
210
211struct SwkbdInitializeArg {
212 u32 unknown{};
213 bool library_applet_mode_flag{};
214 bool is_above_hos_500{};
215 INSERT_PADDING_BYTES(2);
216};
217static_assert(sizeof(SwkbdInitializeArg) == 0x8, "SwkbdInitializeArg has incorrect size.");
218
219struct SwkbdAppearArg {
220 SwkbdType type{};
221 std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{};
222 char16_t left_optional_symbol_key{};
223 char16_t right_optional_symbol_key{};
224 bool use_prediction{};
225 bool disable_cancel_button{};
226 SwkbdKeyDisableFlags key_disable_flags{};
227 u32 max_text_length{};
228 u32 min_text_length{};
229 bool enable_return_button{};
230 INSERT_PADDING_BYTES(3);
231 u32 flags{};
232 INSERT_PADDING_WORDS(6);
233};
234static_assert(sizeof(SwkbdAppearArg) == 0x48, "SwkbdAppearArg has incorrect size.");
235
236struct SwkbdCalcArg {
237 u32 unknown{};
238 u16 calc_arg_size{};
239 INSERT_PADDING_BYTES(2);
240 SwkbdCalcArgFlags flags{};
241 SwkbdInitializeArg initialize_arg{};
242 f32 volume{};
243 s32 cursor_position{};
244 SwkbdAppearArg appear_arg{};
245 std::array<char16_t, 0x1FA> input_text{};
246 bool utf8_mode{};
247 INSERT_PADDING_BYTES(1);
248 bool enable_backspace_button{};
249 INSERT_PADDING_BYTES(3);
250 bool key_top_as_floating{};
251 bool footer_scalable{};
252 bool alpha_enabled_in_input_mode{};
253 u8 input_mode_fade_type{};
254 bool disable_touch{};
255 bool disable_hardware_keyboard{};
256 INSERT_PADDING_BYTES(8);
257 f32 key_top_scale_x{};
258 f32 key_top_scale_y{};
259 f32 key_top_translate_x{};
260 f32 key_top_translate_y{};
261 f32 key_top_bg_alpha{};
262 f32 footer_bg_alpha{};
263 f32 balloon_scale{};
264 INSERT_PADDING_WORDS(4);
265 u8 se_group{};
266 INSERT_PADDING_BYTES(3);
267};
268static_assert(sizeof(SwkbdCalcArg) == 0x4A0, "SwkbdCalcArg has incorrect size.");
269
270struct SwkbdChangedStringArg {
271 u32 text_length{};
272 s32 dictionary_start_cursor_position{};
273 s32 dictionary_end_cursor_position{};
274 s32 cursor_position{};
275};
276static_assert(sizeof(SwkbdChangedStringArg) == 0x10, "SwkbdChangedStringArg has incorrect size.");
277
278struct SwkbdMovedCursorArg {
279 u32 text_length{};
280 s32 cursor_position{};
281};
282static_assert(sizeof(SwkbdMovedCursorArg) == 0x8, "SwkbdMovedCursorArg has incorrect size.");
283
284struct SwkbdMovedTabArg {
285 u32 text_length{};
286 s32 cursor_position{};
287};
288static_assert(sizeof(SwkbdMovedTabArg) == 0x8, "SwkbdMovedTabArg has incorrect size.");
289
290struct SwkbdDecidedEnterArg {
291 u32 text_length{};
292};
293static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size.");
294
295} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 2ab420789..b28b849bc 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -208,8 +208,9 @@ void ExtractSharedFonts(Core::System& system) {
208 208
209} // namespace 209} // namespace
210 210
211WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_) 211WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
212 : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} 212 const Core::Frontend::WebBrowserApplet& frontend_)
213 : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend(frontend_), system{system_} {}
213 214
214WebBrowser::~WebBrowser() = default; 215WebBrowser::~WebBrowser() = default;
215 216
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
index 04c274754..5eafbae7b 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -25,7 +25,8 @@ namespace Service::AM::Applets {
25 25
26class WebBrowser final : public Applet { 26class WebBrowser final : public Applet {
27public: 27public:
28 WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_); 28 WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
29 const Core::Frontend::WebBrowserApplet& frontend_);
29 30
30 ~WebBrowser() override; 31 ~WebBrowser() override;
31 32
@@ -63,6 +64,7 @@ private:
63 void ExecuteWifi(); 64 void ExecuteWifi();
64 void ExecuteLobby(); 65 void ExecuteLobby();
65 66
67 LibraryAppletMode applet_mode;
66 const Core::Frontend::WebBrowserApplet& frontend; 68 const Core::Frontend::WebBrowserApplet& frontend;
67 69
68 bool complete{false}; 70 bool complete{false};
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 8d657c0bf..75867e349 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -7,6 +7,7 @@
7#include <vector> 7#include <vector>
8 8
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/settings.h"
10#include "core/core.h" 11#include "core/core.h"
11#include "core/file_sys/common_funcs.h" 12#include "core/file_sys/common_funcs.h"
12#include "core/file_sys/content_archive.h" 13#include "core/file_sys/content_archive.h"
@@ -21,7 +22,6 @@
21#include "core/hle/kernel/process.h" 22#include "core/hle/kernel/process.h"
22#include "core/hle/service/aoc/aoc_u.h" 23#include "core/hle/service/aoc/aoc_u.h"
23#include "core/loader/loader.h" 24#include "core/loader/loader.h"
24#include "core/settings.h"
25 25
26namespace Service::AOC { 26namespace Service::AOC {
27 27
@@ -118,8 +118,10 @@ AOC_U::AOC_U(Core::System& system_)
118 {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, 118 {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
119 {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, 119 {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
120 {9, nullptr, "GetAddOnContentLostErrorCode"}, 120 {9, nullptr, "GetAddOnContentLostErrorCode"},
121 {10, nullptr, "GetAddOnContentListChangedEventWithProcessId"},
121 {100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"}, 122 {100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
122 {101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"}, 123 {101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
124 {110, nullptr, "CreateContentsServiceManager"},
123 }; 125 };
124 // clang-format on 126 // clang-format on
125 127
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
index 03636642b..00c174bb0 100644
--- a/src/core/hle/service/apm/controller.cpp
+++ b/src/core/hle/service/apm/controller.cpp
@@ -7,9 +7,9 @@
7#include <utility> 7#include <utility>
8 8
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/settings.h"
10#include "core/core_timing.h" 11#include "core/core_timing.h"
11#include "core/hle/service/apm/controller.h" 12#include "core/hle/service/apm/controller.h"
12#include "core/settings.h"
13 13
14namespace Service::APM { 14namespace Service::APM {
15 15
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp
index 79c3aa920..10acaad19 100644
--- a/src/core/hle/service/audio/audin_a.cpp
+++ b/src/core/hle/service/audio/audin_a.cpp
@@ -9,10 +9,10 @@ namespace Service::Audio {
9AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} { 9AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioIns"}, 12 {0, nullptr, "RequestSuspend"},
13 {1, nullptr, "RequestResumeAudioIns"}, 13 {1, nullptr, "RequestResume"},
14 {2, nullptr, "GetAudioInsProcessMasterVolume"}, 14 {2, nullptr, "GetProcessMasterVolume"},
15 {3, nullptr, "SetAudioInsProcessMasterVolume"}, 15 {3, nullptr, "SetProcessMasterVolume"},
16 }; 16 };
17 // clang-format on 17 // clang-format on
18 18
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 26a6deddf..ecd05e4a6 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -15,19 +15,19 @@ public:
15 // clang-format off 15 // clang-format off
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GetAudioInState"}, 17 {0, nullptr, "GetAudioInState"},
18 {1, nullptr, "StartAudioIn"}, 18 {1, nullptr, "Start"},
19 {2, nullptr, "StopAudioIn"}, 19 {2, nullptr, "Stop"},
20 {3, nullptr, "AppendAudioInBuffer"}, 20 {3, nullptr, "AppendAudioInBuffer"},
21 {4, nullptr, "RegisterBufferEvent"}, 21 {4, nullptr, "RegisterBufferEvent"},
22 {5, nullptr, "GetReleasedAudioInBuffer"}, 22 {5, nullptr, "GetReleasedAudioInBuffer"},
23 {6, nullptr, "ContainsAudioInBuffer"}, 23 {6, nullptr, "ContainsAudioInBuffer"},
24 {7, nullptr, "AppendAudioInBufferWithUserEvent"}, 24 {7, nullptr, "AppendUacInBuffer"},
25 {8, nullptr, "AppendAudioInBufferAuto"}, 25 {8, nullptr, "AppendAudioInBufferAuto"},
26 {9, nullptr, "GetReleasedAudioInBufferAuto"}, 26 {9, nullptr, "GetReleasedAudioInBuffersAuto"},
27 {10, nullptr, "AppendAudioInBufferWithUserEventAuto"}, 27 {10, nullptr, "AppendUacInBufferAuto"},
28 {11, nullptr, "GetAudioInBufferCount"}, 28 {11, nullptr, "GetAudioInBufferCount"},
29 {12, nullptr, "SetAudioInDeviceGain"}, 29 {12, nullptr, "SetDeviceGain"},
30 {13, nullptr, "GetAudioInDeviceGain"}, 30 {13, nullptr, "GetDeviceGain"},
31 {14, nullptr, "FlushAudioInBuffers"}, 31 {14, nullptr, "FlushAudioInBuffers"},
32 }; 32 };
33 // clang-format on 33 // clang-format on
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp
index 19825fd5d..3ee522b50 100644
--- a/src/core/hle/service/audio/audout_a.cpp
+++ b/src/core/hle/service/audio/audout_a.cpp
@@ -9,12 +9,12 @@ namespace Service::Audio {
9AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} { 9AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioOuts"}, 12 {0, nullptr, "RequestSuspend"},
13 {1, nullptr, "RequestResumeAudioOuts"}, 13 {1, nullptr, "RequestResume"},
14 {2, nullptr, "GetAudioOutsProcessMasterVolume"}, 14 {2, nullptr, "GetProcessMasterVolume"},
15 {3, nullptr, "SetAudioOutsProcessMasterVolume"}, 15 {3, nullptr, "SetProcessMasterVolume"},
16 {4, nullptr, "GetAudioOutsProcessRecordVolume"}, 16 {4, nullptr, "GetProcessRecordVolume"},
17 {5, nullptr, "SetAudioOutsProcessRecordVolume"}, 17 {5, nullptr, "SetProcessRecordVolume"},
18 }; 18 };
19 // clang-format on 19 // clang-format on
20 20
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 5ed9cb20e..5f51fca9a 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -49,11 +49,11 @@ public:
49 // clang-format off 49 // clang-format off
50 static const FunctionInfo functions[] = { 50 static const FunctionInfo functions[] = {
51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
52 {1, &IAudioOut::StartAudioOut, "StartAudioOut"}, 52 {1, &IAudioOut::StartAudioOut, "Start"},
53 {2, &IAudioOut::StopAudioOut, "StopAudioOut"}, 53 {2, &IAudioOut::StopAudioOut, "Stop"},
54 {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"}, 54 {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
55 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, 55 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
56 {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"}, 56 {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffers"},
57 {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"}, 57 {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
58 {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"}, 58 {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
59 {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"}, 59 {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp
index c5ab7cad4..70fc17ae2 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/audrec_a.cpp
@@ -9,8 +9,8 @@ namespace Service::Audio {
9AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} { 9AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendFinalOutputRecorders"}, 12 {0, nullptr, "RequestSuspend"},
13 {1, nullptr, "RequestResumeFinalOutputRecorders"}, 13 {1, nullptr, "RequestResume"},
14 }; 14 };
15 // clang-format on 15 // clang-format on
16 16
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp
index eb5c63c62..74a65ccff 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/audrec_u.cpp
@@ -13,16 +13,17 @@ public:
13 // clang-format off 13 // clang-format off
14 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
15 {0, nullptr, "GetFinalOutputRecorderState"}, 15 {0, nullptr, "GetFinalOutputRecorderState"},
16 {1, nullptr, "StartFinalOutputRecorder"}, 16 {1, nullptr, "Start"},
17 {2, nullptr, "StopFinalOutputRecorder"}, 17 {2, nullptr, "Stop"},
18 {3, nullptr, "AppendFinalOutputRecorderBuffer"}, 18 {3, nullptr, "AppendFinalOutputRecorderBuffer"},
19 {4, nullptr, "RegisterBufferEvent"}, 19 {4, nullptr, "RegisterBufferEvent"},
20 {5, nullptr, "GetReleasedFinalOutputRecorderBuffer"}, 20 {5, nullptr, "GetReleasedFinalOutputRecorderBuffers"},
21 {6, nullptr, "ContainsFinalOutputRecorderBuffer"}, 21 {6, nullptr, "ContainsFinalOutputRecorderBuffer"},
22 {7, nullptr, "GetFinalOutputRecorderBufferEndTime"}, 22 {7, nullptr, "GetFinalOutputRecorderBufferEndTime"},
23 {8, nullptr, "AppendFinalOutputRecorderBufferAuto"}, 23 {8, nullptr, "AppendFinalOutputRecorderBufferAuto"},
24 {9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"}, 24 {9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"},
25 {10, nullptr, "FlushFinalOutputRecorderBuffers"}, 25 {10, nullptr, "FlushFinalOutputRecorderBuffers"},
26 {11, nullptr, "AttachWorkBuffer"},
26 }; 27 };
27 // clang-format on 28 // clang-format on
28 29
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp
index 5e9f866f0..cf8c34a15 100644
--- a/src/core/hle/service/audio/audren_a.cpp
+++ b/src/core/hle/service/audio/audren_a.cpp
@@ -9,14 +9,14 @@ namespace Service::Audio {
9AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} { 9AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioRenderers"}, 12 {0, nullptr, "RequestSuspend"},
13 {1, nullptr, "RequestResumeAudioRenderers"}, 13 {1, nullptr, "RequestResume"},
14 {2, nullptr, "GetAudioRenderersProcessMasterVolume"}, 14 {2, nullptr, "GetProcessMasterVolume"},
15 {3, nullptr, "SetAudioRenderersProcessMasterVolume"}, 15 {3, nullptr, "SetProcessMasterVolume"},
16 {4, nullptr, "RegisterAppletResourceUserId"}, 16 {4, nullptr, "RegisterAppletResourceUserId"},
17 {5, nullptr, "UnregisterAppletResourceUserId"}, 17 {5, nullptr, "UnregisterAppletResourceUserId"},
18 {6, nullptr, "GetAudioRenderersProcessRecordVolume"}, 18 {6, nullptr, "GetProcessRecordVolume"},
19 {7, nullptr, "SetAudioRenderersProcessRecordVolume"}, 19 {7, nullptr, "SetProcessRecordVolume"},
20 }; 20 };
21 // clang-format on 21 // clang-format on
22 22
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index b2b2ffc5a..572be8e00 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -332,9 +332,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"}
332 // clang-format off 332 // clang-format off
333 static const FunctionInfo functions[] = { 333 static const FunctionInfo functions[] = {
334 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, 334 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
335 {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"}, 335 {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetWorkBufferSize"},
336 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"}, 336 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
337 {3, &AudRenU::OpenAudioRendererAuto, "OpenAudioRendererAuto"}, 337 {3, &AudRenU::OpenAudioRendererForManualExecution, "OpenAudioRendererForManualExecution"},
338 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"}, 338 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
339 }; 339 };
340 // clang-format on 340 // clang-format on
@@ -665,7 +665,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
665 rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1')); 665 rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1'));
666} 666}
667 667
668void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { 668void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
669 LOG_DEBUG(Service_Audio, "called"); 669 LOG_DEBUG(Service_Audio, "called");
670 670
671 OpenAudioRendererImpl(ctx); 671 OpenAudioRendererImpl(ctx);
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index d693dc406..37e8b4716 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -25,7 +25,7 @@ private:
25 void OpenAudioRenderer(Kernel::HLERequestContext& ctx); 25 void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
26 void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); 26 void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
27 void GetAudioDeviceService(Kernel::HLERequestContext& ctx); 27 void GetAudioDeviceService(Kernel::HLERequestContext& ctx);
28 void OpenAudioRendererAuto(Kernel::HLERequestContext& ctx); 28 void OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx);
29 void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx); 29 void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
30 30
31 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); 31 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp
index 94afec1b6..42961d908 100644
--- a/src/core/hle/service/audio/codecctl.cpp
+++ b/src/core/hle/service/audio/codecctl.cpp
@@ -8,19 +8,19 @@ namespace Service::Audio {
8 8
9CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} { 9CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} {
10 static const FunctionInfo functions[] = { 10 static const FunctionInfo functions[] = {
11 {0, nullptr, "InitializeCodecController"}, 11 {0, nullptr, "Initialize"},
12 {1, nullptr, "FinalizeCodecController"}, 12 {1, nullptr, "Finalize"},
13 {2, nullptr, "SleepCodecController"}, 13 {2, nullptr, "Sleep"},
14 {3, nullptr, "WakeCodecController"}, 14 {3, nullptr, "Wake"},
15 {4, nullptr, "SetCodecVolume"}, 15 {4, nullptr, "SetVolume"},
16 {5, nullptr, "GetCodecVolumeMax"}, 16 {5, nullptr, "GetVolumeMax"},
17 {6, nullptr, "GetCodecVolumeMin"}, 17 {6, nullptr, "GetVolumeMin"},
18 {7, nullptr, "SetCodecActiveTarget"}, 18 {7, nullptr, "SetActiveTarget"},
19 {8, nullptr, "GetCodecActiveTarget"}, 19 {8, nullptr, "GetActiveTarget"},
20 {9, nullptr, "BindCodecHeadphoneMicJackInterrupt"}, 20 {9, nullptr, "BindHeadphoneMicJackInterrupt"},
21 {10, nullptr, "IsCodecHeadphoneMicJackInserted"}, 21 {10, nullptr, "IsHeadphoneMicJackInserted"},
22 {11, nullptr, "ClearCodecHeadphoneMicJackInterrupt"}, 22 {11, nullptr, "ClearHeadphoneMicJackInterrupt"},
23 {12, nullptr, "IsCodecDeviceRequested"}, 23 {12, nullptr, "IsRequested"},
24 }; 24 };
25 RegisterHandlers(functions); 25 RegisterHandlers(functions);
26} 26}
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index ea3414fd2..19c578b3a 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -297,6 +297,10 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
297 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, 297 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
298 {2, nullptr, "OpenOpusDecoderForMultiStream"}, 298 {2, nullptr, "OpenOpusDecoderForMultiStream"},
299 {3, nullptr, "GetWorkBufferSizeForMultiStream"}, 299 {3, nullptr, "GetWorkBufferSizeForMultiStream"},
300 {4, nullptr, "OpenHardwareOpusDecoderEx"},
301 {5, nullptr, "GetWorkBufferSizeEx"},
302 {6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
303 {7, nullptr, "GetWorkBufferSizeForMultiStreamEx"},
300 }; 304 };
301 RegisterHandlers(functions); 305 RegisterHandlers(functions);
302} 306}
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index e43f3f47f..78c047bd2 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -9,6 +9,7 @@
9#include "common/hex_util.h" 9#include "common/hex_util.h"
10#include "common/logging/backend.h" 10#include "common/logging/backend.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/settings.h"
12#include "core/core.h" 13#include "core/core.h"
13#include "core/file_sys/vfs.h" 14#include "core/file_sys/vfs.h"
14#include "core/file_sys/vfs_libzip.h" 15#include "core/file_sys/vfs_libzip.h"
@@ -16,7 +17,6 @@
16#include "core/frontend/applets/error.h" 17#include "core/frontend/applets/error.h"
17#include "core/hle/service/am/applets/applets.h" 18#include "core/hle/service/am/applets/applets.h"
18#include "core/hle/service/bcat/backend/boxcat.h" 19#include "core/hle/service/bcat/backend/boxcat.h"
19#include "core/settings.h"
20 20
21namespace Service::BCAT { 21namespace Service::BCAT {
22namespace { 22namespace {
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 503109fdd..c7dd04a6e 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -7,6 +7,7 @@
7#include "backend/boxcat.h" 7#include "backend/boxcat.h"
8#include "common/hex_util.h" 8#include "common/hex_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/settings.h"
10#include "common/string_util.h" 11#include "common/string_util.h"
11#include "core/core.h" 12#include "core/core.h"
12#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs.h"
@@ -18,7 +19,6 @@
18#include "core/hle/service/bcat/bcat.h" 19#include "core/hle/service/bcat/bcat.h"
19#include "core/hle/service/bcat/module.h" 20#include "core/hle/service/bcat/module.h"
20#include "core/hle/service/filesystem/filesystem.h" 21#include "core/hle/service/filesystem/filesystem.h"
21#include "core/settings.h"
22 22
23namespace Service::BCAT { 23namespace Service::BCAT {
24 24
@@ -155,10 +155,12 @@ public:
155 {30210, nullptr, "SetDeliveryTaskTimer"}, 155 {30210, nullptr, "SetDeliveryTaskTimer"},
156 {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"}, 156 {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"},
157 {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, 157 {90100, nullptr, "EnumerateBackgroundDeliveryTask"},
158 {90101, nullptr, "Unknown90101"},
158 {90200, nullptr, "GetDeliveryList"}, 159 {90200, nullptr, "GetDeliveryList"},
159 {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, 160 {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"},
160 {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"}, 161 {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
161 {90300, nullptr, "GetPushNotificationLog"}, 162 {90300, nullptr, "GetPushNotificationLog"},
163 {90301, nullptr, "Unknown90301"},
162 }; 164 };
163 // clang-format on 165 // clang-format on
164 RegisterHandlers(functions); 166 RegisterHandlers(functions);
diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp
index e4630320e..78e01d8d8 100644
--- a/src/core/hle/service/bpc/bpc.cpp
+++ b/src/core/hle/service/bpc/bpc.cpp
@@ -29,8 +29,8 @@ public:
29 {11, nullptr, "CreateWakeupTimerEx"}, 29 {11, nullptr, "CreateWakeupTimerEx"},
30 {12, nullptr, "GetLastEnabledWakeupTimerType"}, 30 {12, nullptr, "GetLastEnabledWakeupTimerType"},
31 {13, nullptr, "CleanAllWakeupTimers"}, 31 {13, nullptr, "CleanAllWakeupTimers"},
32 {14, nullptr, "Unknown"}, 32 {14, nullptr, "GetPowerButton"},
33 {15, nullptr, "Unknown2"}, 33 {15, nullptr, "SetEnableWakeupTimer"},
34 }; 34 };
35 // clang-format on 35 // clang-format on
36 36
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 17a2ac899..af3a5842d 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -156,6 +156,25 @@ public:
156 {97, nullptr, "RegisterBleHidEvent"}, 156 {97, nullptr, "RegisterBleHidEvent"},
157 {98, nullptr, "SetBleScanParameter"}, 157 {98, nullptr, "SetBleScanParameter"},
158 {99, nullptr, "MoveToSecondaryPiconet"}, 158 {99, nullptr, "MoveToSecondaryPiconet"},
159 {100, nullptr, "IsBluetoothEnabled"},
160 {128, nullptr, "AcquireAudioEvent"},
161 {129, nullptr, "GetAudioEventInfo"},
162 {130, nullptr, "OpenAudioConnection"},
163 {131, nullptr, "CloseAudioConnection"},
164 {132, nullptr, "OpenAudioOut"},
165 {133, nullptr, "CloseAudioOut"},
166 {134, nullptr, "AcquireAudioOutStateChangedEvent"},
167 {135, nullptr, "StartAudioOut"},
168 {136, nullptr, "StopAudioOut"},
169 {137, nullptr, "GetAudioOutState"},
170 {138, nullptr, "GetAudioOutFeedingCodec"},
171 {139, nullptr, "GetAudioOutFeedingParameter"},
172 {140, nullptr, "AcquireAudioOutBufferAvailableEvent"},
173 {141, nullptr, "SendAudioData"},
174 {142, nullptr, "AcquireAudioControlInputStateChangedEvent"},
175 {143, nullptr, "GetAudioControlInputState"},
176 {144, nullptr, "AcquireAudioConnectionStateChangedEvent"},
177 {145, nullptr, "GetConnectedAudioDevice"},
159 {256, nullptr, "IsManufacturingMode"}, 178 {256, nullptr, "IsManufacturingMode"},
160 {257, nullptr, "EmulateBluetoothCrash"}, 179 {257, nullptr, "EmulateBluetoothCrash"},
161 {258, nullptr, "GetBleChannelMap"}, 180 {258, nullptr, "GetBleChannelMap"},
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 9cf2ee92a..d1ebc2388 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -223,6 +223,7 @@ public:
223 {10, nullptr, "GetGattClientDisconnectionReason"}, 223 {10, nullptr, "GetGattClientDisconnectionReason"},
224 {11, nullptr, "GetBleConnectionParameter"}, 224 {11, nullptr, "GetBleConnectionParameter"},
225 {12, nullptr, "GetBleConnectionParameterRequest"}, 225 {12, nullptr, "GetBleConnectionParameterRequest"},
226 {13, nullptr, "Unknown13"},
226 }; 227 };
227 // clang-format on 228 // clang-format on
228 229
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp
index 1fe4f0e14..6220e9f77 100644
--- a/src/core/hle/service/caps/caps_a.cpp
+++ b/src/core/hle/service/caps/caps_a.cpp
@@ -49,6 +49,7 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
49 {16, nullptr, "GetAlbumMountResult"}, 49 {16, nullptr, "GetAlbumMountResult"},
50 {17, nullptr, "GetAlbumUsage16"}, 50 {17, nullptr, "GetAlbumUsage16"},
51 {18, nullptr, "Unknown18"}, 51 {18, nullptr, "Unknown18"},
52 {19, nullptr, "Unknown19"},
52 {100, nullptr, "GetAlbumFileCountEx0"}, 53 {100, nullptr, "GetAlbumFileCountEx0"},
53 {101, nullptr, "GetAlbumFileListEx0"}, 54 {101, nullptr, "GetAlbumFileListEx0"},
54 {202, nullptr, "SaveEditedScreenShot"}, 55 {202, nullptr, "SaveEditedScreenShot"},
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
index 842316a2e..10b8d54b1 100644
--- a/src/core/hle/service/caps/caps_u.cpp
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -43,6 +43,7 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
43 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, 43 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
44 {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, 44 {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
45 {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, 45 {143, nullptr, "GetAlbumFileList4AaeUidAruid"},
46 {144, nullptr, "GetAllAlbumFileList3AaeAruid"},
46 {60002, nullptr, "OpenAccessorSessionForApplication"}, 47 {60002, nullptr, "OpenAccessorSessionForApplication"},
47 }; 48 };
48 // clang-format on 49 // clang-format on
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index 4924c61c3..c767926a4 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -16,7 +16,7 @@ public:
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SubmitContext"}, 18 {0, nullptr, "SubmitContext"},
19 {1, nullptr, "CreateReport"}, 19 {1, nullptr, "CreateReportV0"},
20 {2, nullptr, "SetInitialLaunchSettingsCompletionTime"}, 20 {2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
21 {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"}, 21 {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
22 {4, nullptr, "UpdatePowerOnTime"}, 22 {4, nullptr, "UpdatePowerOnTime"},
@@ -26,6 +26,11 @@ public:
26 {8, nullptr, "ClearApplicationLaunchTime"}, 26 {8, nullptr, "ClearApplicationLaunchTime"},
27 {9, nullptr, "SubmitAttachment"}, 27 {9, nullptr, "SubmitAttachment"},
28 {10, nullptr, "CreateReportWithAttachments"}, 28 {10, nullptr, "CreateReportWithAttachments"},
29 {11, nullptr, "CreateReport"},
30 {20, nullptr, "RegisterRunningApplet"},
31 {21, nullptr, "UnregisterRunningApplet"},
32 {22, nullptr, "UpdateAppletSuspendedDuration"},
33 {30, nullptr, "InvalidateForcedShutdownDetection"},
29 }; 34 };
30 // clang-format on 35 // clang-format on
31 36
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index b15c737e1..72ad273b2 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -6,6 +6,7 @@
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/settings.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/file_sys/bis_factory.h" 11#include "core/file_sys/bis_factory.h"
11#include "core/file_sys/card_image.h" 12#include "core/file_sys/card_image.h"
@@ -26,7 +27,6 @@
26#include "core/hle/service/filesystem/fsp_pr.h" 27#include "core/hle/service/filesystem/fsp_pr.h"
27#include "core/hle/service/filesystem/fsp_srv.h" 28#include "core/hle/service/filesystem/fsp_srv.h"
28#include "core/loader/loader.h" 29#include "core/loader/loader.h"
29#include "core/settings.h"
30 30
31namespace Service::FileSystem { 31namespace Service::FileSystem {
32 32
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 9cc260515..a0215c4d7 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -118,9 +118,13 @@ public:
118 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) 118 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
119 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { 119 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
120 static const FunctionInfo functions[] = { 120 static const FunctionInfo functions[] = {
121 {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, 121 {0, &IFile::Read, "Read"},
122 {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, 122 {1, &IFile::Write, "Write"},
123 {4, &IFile::GetSize, "GetSize"}, {5, nullptr, "OperateRange"}, 123 {2, &IFile::Flush, "Flush"},
124 {3, &IFile::SetSize, "SetSize"},
125 {4, &IFile::GetSize, "GetSize"},
126 {5, nullptr, "OperateRange"},
127 {6, nullptr, "OperateRangeWithBuffer"},
124 }; 128 };
125 RegisterHandlers(functions); 129 RegisterHandlers(functions);
126 } 130 }
@@ -708,7 +712,10 @@ FSP_SRV::FSP_SRV(Core::System& system_)
708 {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"}, 712 {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
709 {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"}, 713 {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
710 {86, nullptr, "OpenSaveDataMover"}, 714 {86, nullptr, "OpenSaveDataMover"},
715 {87, nullptr, "OpenSaveDataTransferManagerForRepair"},
711 {100, nullptr, "OpenImageDirectoryFileSystem"}, 716 {100, nullptr, "OpenImageDirectoryFileSystem"},
717 {101, nullptr, "OpenBaseFileSystem"},
718 {102, nullptr, "FormatBaseFileSystem"},
712 {110, nullptr, "OpenContentStorageFileSystem"}, 719 {110, nullptr, "OpenContentStorageFileSystem"},
713 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, 720 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
714 {130, nullptr, "OpenCustomStorageFileSystem"}, 721 {130, nullptr, "OpenCustomStorageFileSystem"},
@@ -764,10 +771,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
764 {1008, nullptr, "OpenRegisteredUpdatePartition"}, 771 {1008, nullptr, "OpenRegisteredUpdatePartition"},
765 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 772 {1009, nullptr, "GetAndClearMemoryReportInfo"},
766 {1010, nullptr, "SetDataStorageRedirectTarget"}, 773 {1010, nullptr, "SetDataStorageRedirectTarget"},
767 {1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"}, 774 {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"},
768 {1012, nullptr, "GetFsStackUsage"}, 775 {1012, nullptr, "GetFsStackUsage"},
769 {1013, nullptr, "UnsetSaveDataRootPath"}, 776 {1013, nullptr, "UnsetSaveDataRootPath"},
770 {1014, nullptr, "OutputMultiProgramTagAccessLog"}, 777 {1014, nullptr, "OutputMultiProgramTagAccessLog"},
778 {1016, nullptr, "FlushAccessLogOnSdCard"},
779 {1017, nullptr, "OutputApplicationInfoAccessLog"},
771 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 780 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
772 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, 781 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
773 {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, 782 {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
@@ -1051,7 +1060,7 @@ void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
1051 rb.Push(RESULT_SUCCESS); 1060 rb.Push(RESULT_SUCCESS);
1052} 1061}
1053 1062
1054void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) { 1063void FSP_SRV::GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx) {
1055 LOG_DEBUG(Service_FS, "called"); 1064 LOG_DEBUG(Service_FS, "called");
1056 1065
1057 IPC::ResponseBuilder rb{ctx, 4}; 1066 IPC::ResponseBuilder rb{ctx, 4};
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 8ed933279..b01b924eb 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -53,7 +53,7 @@ private:
53 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 53 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
54 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 54 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
55 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); 55 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
56 void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); 56 void GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx);
57 void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); 57 void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
58 58
59 FileSystemController& fsc; 59 FileSystemController& fsc;
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 0a6621ef2..a35979053 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -38,7 +38,7 @@ public:
38 {10600, nullptr, "DeclareOpenOnlinePlaySession"}, 38 {10600, nullptr, "DeclareOpenOnlinePlaySession"},
39 {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, 39 {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
40 {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"}, 40 {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
41 {10700, nullptr, "GetPlayHistoryRegistrationKey"}, 41 {10700, &IFriendService::GetPlayHistoryRegistrationKey, "GetPlayHistoryRegistrationKey"},
42 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, 42 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
43 {10702, nullptr, "AddPlayHistory"}, 43 {10702, nullptr, "AddPlayHistory"},
44 {11000, nullptr, "GetProfileImageUrl"}, 44 {11000, nullptr, "GetProfileImageUrl"},
@@ -153,6 +153,18 @@ private:
153 rb.Push(RESULT_SUCCESS); 153 rb.Push(RESULT_SUCCESS);
154 } 154 }
155 155
156 void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) {
157 IPC::RequestParser rp{ctx};
158 const auto local_play = rp.Pop<bool>();
159 const auto uuid = rp.PopRaw<Common::UUID>();
160
161 LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play,
162 uuid.Format());
163
164 IPC::ResponseBuilder rb{ctx, 2};
165 rb.Push(RESULT_SUCCESS);
166 }
167
156 void GetFriendList(Kernel::HLERequestContext& ctx) { 168 void GetFriendList(Kernel::HLERequestContext& ctx) {
157 IPC::RequestParser rp{ctx}; 169 IPC::RequestParser rp{ctx};
158 const auto friend_offset = rp.Pop<u32>(); 170 const auto friend_offset = rp.Pop<u32>();
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index fc77e7286..322125135 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -41,6 +41,12 @@ ARP_R::ARP_R(Core::System& system_, const ARPManager& manager_)
41 {1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"}, 41 {1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"},
42 {2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"}, 42 {2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"},
43 {3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"}, 43 {3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"},
44 {4, nullptr, "GetApplicationInstanceUnregistrationNotifier"},
45 {5, nullptr, "ListApplicationInstanceId"},
46 {6, nullptr, "GetMicroApplicationInstanceId"},
47 {7, nullptr, "GetApplicationCertificate"},
48 {9998, nullptr, "GetPreomiaApplicationLaunchProperty"},
49 {9999, nullptr, "GetPreomiaApplicationControlProperty"},
44 }; 50 };
45 // clang-format on 51 // clang-format on
46 52
@@ -243,7 +249,8 @@ ARP_W::ARP_W(Core::System& system_, ARPManager& manager_)
243 // clang-format off 249 // clang-format off
244 static const FunctionInfo functions[] = { 250 static const FunctionInfo functions[] = {
245 {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"}, 251 {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
246 {1, &ARP_W::DeleteProperties, "DeleteProperties"}, 252 {1, &ARP_W::UnregisterApplicationInstance , "UnregisterApplicationInstance "},
253 {2, nullptr, "AcquireUpdater"},
247 }; 254 };
248 // clang-format on 255 // clang-format on
249 256
@@ -270,7 +277,7 @@ void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
270 rb.PushIpcInterface(registrar); 277 rb.PushIpcInterface(registrar);
271} 278}
272 279
273void ARP_W::DeleteProperties(Kernel::HLERequestContext& ctx) { 280void ARP_W::UnregisterApplicationInstance(Kernel::HLERequestContext& ctx) {
274 IPC::RequestParser rp{ctx}; 281 IPC::RequestParser rp{ctx};
275 const auto process_id = rp.PopRaw<u64>(); 282 const auto process_id = rp.PopRaw<u64>();
276 283
diff --git a/src/core/hle/service/glue/arp.h b/src/core/hle/service/glue/arp.h
index 34b412e26..0df3c5e1f 100644
--- a/src/core/hle/service/glue/arp.h
+++ b/src/core/hle/service/glue/arp.h
@@ -32,7 +32,7 @@ public:
32 32
33private: 33private:
34 void AcquireRegistrar(Kernel::HLERequestContext& ctx); 34 void AcquireRegistrar(Kernel::HLERequestContext& ctx);
35 void DeleteProperties(Kernel::HLERequestContext& ctx); 35 void UnregisterApplicationInstance(Kernel::HLERequestContext& ctx);
36 36
37 ARPManager& manager; 37 ARPManager& manager;
38 std::shared_ptr<IRegistrar> registrar; 38 std::shared_ptr<IRegistrar> registrar;
diff --git a/src/core/hle/service/glue/bgtc.cpp b/src/core/hle/service/glue/bgtc.cpp
index a478b68e1..daecfff15 100644
--- a/src/core/hle/service/glue/bgtc.cpp
+++ b/src/core/hle/service/glue/bgtc.cpp
@@ -2,6 +2,9 @@
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 "common/logging/log.h"
6#include "core/core.h"
7#include "core/hle/ipc_helpers.h"
5#include "core/hle/service/glue/bgtc.h" 8#include "core/hle/service/glue/bgtc.h"
6 9
7namespace Service::Glue { 10namespace Service::Glue {
@@ -9,6 +12,26 @@ namespace Service::Glue {
9BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} { 12BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
10 // clang-format off 13 // clang-format off
11 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
15 {100, &BGTC_T::OpenTaskService, "OpenTaskService"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22BGTC_T::~BGTC_T() = default;
23
24void BGTC_T::OpenTaskService(Kernel::HLERequestContext& ctx) {
25 LOG_DEBUG(Service_BGTC, "called");
26
27 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
28 rb.Push(RESULT_SUCCESS);
29 rb.PushIpcInterface<ITaskService>(system);
30}
31
32ITaskService::ITaskService(Core::System& system_) : ServiceFramework{system_, "ITaskService"} {
33 // clang-format off
34 static const FunctionInfo functions[] = {
12 {1, nullptr, "NotifyTaskStarting"}, 35 {1, nullptr, "NotifyTaskStarting"},
13 {2, nullptr, "NotifyTaskFinished"}, 36 {2, nullptr, "NotifyTaskFinished"},
14 {3, nullptr, "GetTriggerEvent"}, 37 {3, nullptr, "GetTriggerEvent"},
@@ -20,16 +43,18 @@ BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
20 {13, nullptr, "UnscheduleTask"}, 43 {13, nullptr, "UnscheduleTask"},
21 {14, nullptr, "GetScheduleEvent"}, 44 {14, nullptr, "GetScheduleEvent"},
22 {15, nullptr, "SchedulePeriodicTask"}, 45 {15, nullptr, "SchedulePeriodicTask"},
46 {16, nullptr, "Unknown16"},
23 {101, nullptr, "GetOperationMode"}, 47 {101, nullptr, "GetOperationMode"},
24 {102, nullptr, "WillDisconnectNetworkWhenEnteringSleep"}, 48 {102, nullptr, "WillDisconnectNetworkWhenEnteringSleep"},
25 {103, nullptr, "WillStayHalfAwakeInsteadSleep"}, 49 {103, nullptr, "WillStayHalfAwakeInsteadSleep"},
50 {200, nullptr, "Unknown200"},
26 }; 51 };
27 // clang-format on 52 // clang-format on
28 53
29 RegisterHandlers(functions); 54 RegisterHandlers(functions);
30} 55}
31 56
32BGTC_T::~BGTC_T() = default; 57ITaskService::~ITaskService() = default;
33 58
34BGTC_SC::BGTC_SC(Core::System& system_) : ServiceFramework{system_, "bgtc:sc"} { 59BGTC_SC::BGTC_SC(Core::System& system_) : ServiceFramework{system_, "bgtc:sc"} {
35 // clang-format off 60 // clang-format off
diff --git a/src/core/hle/service/glue/bgtc.h b/src/core/hle/service/glue/bgtc.h
index 906116ba6..4c0142fd5 100644
--- a/src/core/hle/service/glue/bgtc.h
+++ b/src/core/hle/service/glue/bgtc.h
@@ -16,6 +16,14 @@ class BGTC_T final : public ServiceFramework<BGTC_T> {
16public: 16public:
17 explicit BGTC_T(Core::System& system_); 17 explicit BGTC_T(Core::System& system_);
18 ~BGTC_T() override; 18 ~BGTC_T() override;
19
20 void OpenTaskService(Kernel::HLERequestContext& ctx);
21};
22
23class ITaskService final : public ServiceFramework<ITaskService> {
24public:
25 explicit ITaskService(Core::System& system_);
26 ~ITaskService() override;
19}; 27};
20 28
21class BGTC_SC final : public ServiceFramework<BGTC_SC> { 29class BGTC_SC final : public ServiceFramework<BGTC_SC> {
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index ad251ed4a..a460f2f79 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -4,9 +4,9 @@
4 4
5#include <cstring> 5#include <cstring>
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "common/settings.h"
7#include "core/core_timing.h" 8#include "core/core_timing.h"
8#include "core/hle/service/hid/controllers/debug_pad.h" 9#include "core/hle/service/hid/controllers/debug_pad.h"
9#include "core/settings.h"
10 10
11namespace Service::HID { 11namespace Service::HID {
12 12
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 555b29d76..0593d7d39 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -8,10 +8,10 @@
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/settings.h"
11#include "common/swap.h" 12#include "common/swap.h"
12#include "core/frontend/input.h" 13#include "core/frontend/input.h"
13#include "core/hle/service/hid/controllers/controller_base.h" 14#include "core/hle/service/hid/controllers/controller_base.h"
14#include "core/settings.h"
15 15
16namespace Service::HID { 16namespace Service::HID {
17class Controller_DebugPad final : public ControllerBase { 17class Controller_DebugPad final : public ControllerBase {
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 93c43a203..155808f6a 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -5,10 +5,10 @@
5#include <cstring> 5#include <cstring>
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/settings.h"
8#include "core/core_timing.h" 9#include "core/core_timing.h"
9#include "core/frontend/emu_window.h" 10#include "core/frontend/emu_window.h"
10#include "core/hle/service/hid/controllers/gesture.h" 11#include "core/hle/service/hid/controllers/gesture.h"
11#include "core/settings.h"
12 12
13namespace Service::HID { 13namespace Service::HID {
14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; 14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index c4a59147d..18b76038f 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -4,9 +4,9 @@
4 4
5#include <cstring> 5#include <cstring>
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "common/settings.h"
7#include "core/core_timing.h" 8#include "core/core_timing.h"
8#include "core/hle/service/hid/controllers/keyboard.h" 9#include "core/hle/service/hid/controllers/keyboard.h"
9#include "core/settings.h"
10 10
11namespace Service::HID { 11namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index b5b281752..e72948591 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -8,10 +8,10 @@
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/settings.h"
11#include "common/swap.h" 12#include "common/swap.h"
12#include "core/frontend/input.h" 13#include "core/frontend/input.h"
13#include "core/hle/service/hid/controllers/controller_base.h" 14#include "core/hle/service/hid/controllers/controller_base.h"
14#include "core/settings.h"
15 15
16namespace Service::HID { 16namespace Service::HID {
17class Controller_Keyboard final : public ControllerBase { 17class Controller_Keyboard final : public ControllerBase {
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 3b432a36e..0ec0c2b94 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -7,10 +7,10 @@
7#include <array> 7#include <array>
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/settings.h"
10#include "common/swap.h" 11#include "common/swap.h"
11#include "core/frontend/input.h" 12#include "core/frontend/input.h"
12#include "core/hle/service/hid/controllers/controller_base.h" 13#include "core/hle/service/hid/controllers/controller_base.h"
13#include "core/settings.h"
14 14
15namespace Service::HID { 15namespace Service::HID {
16class Controller_Mouse final : public ControllerBase { 16class Controller_Mouse final : public ControllerBase {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 70b9f3824..783386fcf 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -9,6 +9,7 @@
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/settings.h"
12#include "core/core.h" 13#include "core/core.h"
13#include "core/core_timing.h" 14#include "core/core_timing.h"
14#include "core/frontend/input.h" 15#include "core/frontend/input.h"
@@ -17,7 +18,6 @@
17#include "core/hle/kernel/k_writable_event.h" 18#include "core/hle/kernel/k_writable_event.h"
18#include "core/hle/kernel/kernel.h" 19#include "core/hle/kernel/kernel.h"
19#include "core/hle/service/hid/controllers/npad.h" 20#include "core/hle/service/hid/controllers/npad.h"
20#include "core/settings.h"
21 21
22namespace Service::HID { 22namespace Service::HID {
23constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 23constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
@@ -413,12 +413,16 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
413 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); 413 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
414 } 414 }
415 415
416 if (controller_type == NPadControllerType::JoyLeft || 416 if (controller_type == NPadControllerType::JoyLeft) {
417 controller_type == NPadControllerType::JoyRight) {
418 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); 417 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
419 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); 418 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
420 } 419 }
421 420
421 if (controller_type == NPadControllerType::JoyRight) {
422 pad_state.right_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
423 pad_state.right_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
424 }
425
422 if (controller_type == NPadControllerType::GameCube) { 426 if (controller_type == NPadControllerType::GameCube) {
423 trigger_entry.l_analog = static_cast<s32>( 427 trigger_entry.l_analog = static_cast<s32>(
424 button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0); 428 button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0);
@@ -1134,6 +1138,10 @@ void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_prot
1134 unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled; 1138 unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
1135} 1139}
1136 1140
1141void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
1142 analog_stick_use_center_clamp = use_center_clamp;
1143}
1144
1137void Controller_NPad::ClearAllConnectedControllers() { 1145void Controller_NPad::ClearAllConnectedControllers() {
1138 for (auto& controller : connected_controllers) { 1146 for (auto& controller : connected_controllers) {
1139 if (controller.is_connected && controller.type != NPadControllerType::None) { 1147 if (controller.is_connected && controller.type != NPadControllerType::None) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index bc2e6779d..14d0ac067 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -8,10 +8,10 @@
8#include <atomic> 8#include <atomic>
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/settings.h"
11#include "core/frontend/input.h" 12#include "core/frontend/input.h"
12#include "core/hle/kernel/object.h" 13#include "core/hle/kernel/object.h"
13#include "core/hle/service/hid/controllers/controller_base.h" 14#include "core/hle/service/hid/controllers/controller_base.h"
14#include "core/settings.h"
15 15
16namespace Kernel { 16namespace Kernel {
17class KEvent; 17class KEvent;
@@ -219,6 +219,7 @@ public:
219 LedPattern GetLedPattern(u32 npad_id); 219 LedPattern GetLedPattern(u32 npad_id);
220 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; 220 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
221 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); 221 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
222 void SetAnalogStickUseCenterClamp(bool use_center_clamp);
222 void ClearAllConnectedControllers(); 223 void ClearAllConnectedControllers();
223 void DisconnectAllConnectedControllers(); 224 void DisconnectAllConnectedControllers();
224 void ConnectAllDisconnectedControllers(); 225 void ConnectAllDisconnectedControllers();
@@ -577,6 +578,7 @@ private:
577 std::array<std::array<bool, 2>, 10> vibration_devices_mounted{}; 578 std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
578 std::array<ControllerHolder, 10> connected_controllers{}; 579 std::array<ControllerHolder, 10> connected_controllers{};
579 std::array<bool, 10> unintended_home_button_input_protection{}; 580 std::array<bool, 10> unintended_home_button_input_protection{};
581 bool analog_stick_use_center_clamp{};
580 GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; 582 GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
581 bool sixaxis_sensors_enabled{true}; 583 bool sixaxis_sensors_enabled{true};
582 f32 sixaxis_fusion_parameter1{}; 584 f32 sixaxis_fusion_parameter1{};
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index be60492a4..b5f8077be 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -6,11 +6,11 @@
6#include <cstring> 6#include <cstring>
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/settings.h"
9#include "core/core_timing.h" 10#include "core/core_timing.h"
10#include "core/frontend/emu_window.h" 11#include "core/frontend/emu_window.h"
11#include "core/frontend/input.h" 12#include "core/frontend/input.h"
12#include "core/hle/service/hid/controllers/touchscreen.h" 13#include "core/hle/service/hid/controllers/touchscreen.h"
13#include "core/settings.h"
14 14
15namespace Service::HID { 15namespace Service::HID {
16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; 16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index ba27bbb05..4c1c0ac68 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -5,6 +5,7 @@
5#include <array> 5#include <array>
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/settings.h"
8#include "core/core.h" 9#include "core/core.h"
9#include "core/core_timing.h" 10#include "core/core_timing.h"
10#include "core/core_timing_util.h" 11#include "core/core_timing_util.h"
@@ -23,7 +24,6 @@
23#include "core/hle/service/hid/irs.h" 24#include "core/hle/service/hid/irs.h"
24#include "core/hle/service/hid/xcd.h" 25#include "core/hle/service/hid/xcd.h"
25#include "core/hle/service/service.h" 26#include "core/hle/service/service.h"
26#include "core/settings.h"
27 27
28#include "core/hle/service/hid/controllers/controller_base.h" 28#include "core/hle/service/hid/controllers/controller_base.h"
29#include "core/hle/service/hid/controllers/debug_pad.h" 29#include "core/hle/service/hid/controllers/debug_pad.h"
@@ -263,7 +263,7 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
263 {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"}, 263 {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
264 {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, 264 {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
265 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, 265 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
266 {134, nullptr, "SetNpadAnalogStickUseCenterClamp"}, 266 {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
267 {135, nullptr, "SetNpadCaptureButtonAssignment"}, 267 {135, nullptr, "SetNpadCaptureButtonAssignment"},
268 {136, nullptr, "ClearNpadCaptureButtonAssignment"}, 268 {136, nullptr, "ClearNpadCaptureButtonAssignment"},
269 {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, 269 {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
@@ -278,6 +278,7 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
278 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, 278 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
279 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, 279 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
280 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"}, 280 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
281 {212, nullptr, "SendVibrationValueInBool"},
281 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, 282 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
282 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, 283 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
283 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, 284 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@@ -1087,6 +1088,27 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
1087 rb.Push(RESULT_SUCCESS); 1088 rb.Push(RESULT_SUCCESS);
1088} 1089}
1089 1090
1091void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
1092 IPC::RequestParser rp{ctx};
1093 struct Parameters {
1094 bool analog_stick_use_center_clamp;
1095 u64 applet_resource_user_id;
1096 };
1097 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1098
1099 const auto parameters{rp.PopRaw<Parameters>()};
1100
1101 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1102 .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
1103
1104 LOG_WARNING(Service_HID,
1105 "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
1106 parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id);
1107
1108 IPC::ResponseBuilder rb{ctx, 2};
1109 rb.Push(RESULT_SUCCESS);
1110}
1111
1090void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 1112void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
1091 IPC::RequestParser rp{ctx}; 1113 IPC::RequestParser rp{ctx};
1092 const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; 1114 const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
@@ -1553,6 +1575,7 @@ public:
1553 {11, nullptr, "SetTouchScreenAutoPilotState"}, 1575 {11, nullptr, "SetTouchScreenAutoPilotState"},
1554 {12, nullptr, "UnsetTouchScreenAutoPilotState"}, 1576 {12, nullptr, "UnsetTouchScreenAutoPilotState"},
1555 {13, nullptr, "GetTouchScreenConfiguration"}, 1577 {13, nullptr, "GetTouchScreenConfiguration"},
1578 {14, nullptr, "ProcessTouchScreenAutoTune"},
1556 {20, nullptr, "DeactivateMouse"}, 1579 {20, nullptr, "DeactivateMouse"},
1557 {21, nullptr, "SetMouseAutoPilotState"}, 1580 {21, nullptr, "SetMouseAutoPilotState"},
1558 {22, nullptr, "UnsetMouseAutoPilotState"}, 1581 {22, nullptr, "UnsetMouseAutoPilotState"},
@@ -1562,6 +1585,7 @@ public:
1562 {50, nullptr, "DeactivateXpad"}, 1585 {50, nullptr, "DeactivateXpad"},
1563 {51, nullptr, "SetXpadAutoPilotState"}, 1586 {51, nullptr, "SetXpadAutoPilotState"},
1564 {52, nullptr, "UnsetXpadAutoPilotState"}, 1587 {52, nullptr, "UnsetXpadAutoPilotState"},
1588 {53, nullptr, "DeactivateJoyXpad"},
1565 {60, nullptr, "ClearNpadSystemCommonPolicy"}, 1589 {60, nullptr, "ClearNpadSystemCommonPolicy"},
1566 {61, nullptr, "DeactivateNpad"}, 1590 {61, nullptr, "DeactivateNpad"},
1567 {62, nullptr, "ForceDisconnectNpad"}, 1591 {62, nullptr, "ForceDisconnectNpad"},
@@ -1632,6 +1656,11 @@ public:
1632 {244, nullptr, "RequestKuinaFirmwareVersion"}, 1656 {244, nullptr, "RequestKuinaFirmwareVersion"},
1633 {245, nullptr, "GetKuinaFirmwareVersion"}, 1657 {245, nullptr, "GetKuinaFirmwareVersion"},
1634 {246, nullptr, "GetVidPid"}, 1658 {246, nullptr, "GetVidPid"},
1659 {247, nullptr, "GetAnalogStickCalibrationValue"},
1660 {248, nullptr, "GetUniquePadIdsFull"},
1661 {249, nullptr, "ConnectUniquePad"},
1662 {250, nullptr, "IsVirtual"},
1663 {251, nullptr, "GetAnalogStickModuleParam"},
1635 {301, nullptr, "GetAbstractedPadHandles"}, 1664 {301, nullptr, "GetAbstractedPadHandles"},
1636 {302, nullptr, "GetAbstractedPadState"}, 1665 {302, nullptr, "GetAbstractedPadState"},
1637 {303, nullptr, "GetAbstractedPadsState"}, 1666 {303, nullptr, "GetAbstractedPadsState"},
@@ -1652,12 +1681,16 @@ public:
1652 {401, nullptr, "DisableRailDeviceFiltering"}, 1681 {401, nullptr, "DisableRailDeviceFiltering"},
1653 {402, nullptr, "EnableWiredPairing"}, 1682 {402, nullptr, "EnableWiredPairing"},
1654 {403, nullptr, "EnableShipmentModeAutoClear"}, 1683 {403, nullptr, "EnableShipmentModeAutoClear"},
1684 {404, nullptr, "SetRailEnabled"},
1655 {500, nullptr, "SetFactoryInt"}, 1685 {500, nullptr, "SetFactoryInt"},
1656 {501, nullptr, "IsFactoryBootEnabled"}, 1686 {501, nullptr, "IsFactoryBootEnabled"},
1657 {550, nullptr, "SetAnalogStickModelDataTemporarily"}, 1687 {550, nullptr, "SetAnalogStickModelDataTemporarily"},
1658 {551, nullptr, "GetAnalogStickModelData"}, 1688 {551, nullptr, "GetAnalogStickModelData"},
1659 {552, nullptr, "ResetAnalogStickModelData"}, 1689 {552, nullptr, "ResetAnalogStickModelData"},
1660 {600, nullptr, "ConvertPadState"}, 1690 {600, nullptr, "ConvertPadState"},
1691 {650, nullptr, "AddButtonPlayData"},
1692 {651, nullptr, "StartButtonPlayData"},
1693 {652, nullptr, "StopButtonPlayData"},
1661 {2000, nullptr, "DeactivateDigitizer"}, 1694 {2000, nullptr, "DeactivateDigitizer"},
1662 {2001, nullptr, "SetDigitizerAutoPilotState"}, 1695 {2001, nullptr, "SetDigitizerAutoPilotState"},
1663 {2002, nullptr, "UnsetDigitizerAutoPilotState"}, 1696 {2002, nullptr, "UnsetDigitizerAutoPilotState"},
@@ -1689,6 +1722,8 @@ public:
1689 {215, nullptr, "IsNfcActivated"}, 1722 {215, nullptr, "IsNfcActivated"},
1690 {230, nullptr, "AcquireIrSensorEventHandle"}, 1723 {230, nullptr, "AcquireIrSensorEventHandle"},
1691 {231, nullptr, "ActivateIrSensor"}, 1724 {231, nullptr, "ActivateIrSensor"},
1725 {232, nullptr, "GetIrSensorState"},
1726 {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
1692 {301, nullptr, "ActivateNpadSystem"}, 1727 {301, nullptr, "ActivateNpadSystem"},
1693 {303, nullptr, "ApplyNpadSystemCommonPolicy"}, 1728 {303, nullptr, "ApplyNpadSystemCommonPolicy"},
1694 {304, nullptr, "EnableAssigningSingleOnSlSrPress"}, 1729 {304, nullptr, "EnableAssigningSingleOnSlSrPress"},
@@ -1703,9 +1738,16 @@ public:
1703 {313, nullptr, "GetNpadCaptureButtonAssignment"}, 1738 {313, nullptr, "GetNpadCaptureButtonAssignment"},
1704 {314, nullptr, "GetAppletFooterUiType"}, 1739 {314, nullptr, "GetAppletFooterUiType"},
1705 {315, nullptr, "GetAppletDetailedUiType"}, 1740 {315, nullptr, "GetAppletDetailedUiType"},
1741 {316, nullptr, "GetNpadInterfaceType"},
1742 {317, nullptr, "GetNpadLeftRightInterfaceType"},
1743 {318, nullptr, "HasBattery"},
1744 {319, nullptr, "HasLeftRightBattery"},
1706 {321, nullptr, "GetUniquePadsFromNpad"}, 1745 {321, nullptr, "GetUniquePadsFromNpad"},
1707 {322, nullptr, "GetIrSensorState"}, 1746 {322, nullptr, "GetIrSensorState"},
1708 {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, 1747 {323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
1748 {324, nullptr, "GetUniquePadButtonSet"},
1749 {325, nullptr, "GetUniquePadColor"},
1750 {326, nullptr, "GetUniquePadAppletDetailedUiType"},
1709 {500, nullptr, "SetAppletResourceUserId"}, 1751 {500, nullptr, "SetAppletResourceUserId"},
1710 {501, nullptr, "RegisterAppletResourceUserId"}, 1752 {501, nullptr, "RegisterAppletResourceUserId"},
1711 {502, nullptr, "UnregisterAppletResourceUserId"}, 1753 {502, nullptr, "UnregisterAppletResourceUserId"},
@@ -1716,10 +1758,13 @@ public:
1716 {511, nullptr, "GetVibrationMasterVolume"}, 1758 {511, nullptr, "GetVibrationMasterVolume"},
1717 {512, nullptr, "BeginPermitVibrationSession"}, 1759 {512, nullptr, "BeginPermitVibrationSession"},
1718 {513, nullptr, "EndPermitVibrationSession"}, 1760 {513, nullptr, "EndPermitVibrationSession"},
1761 {514, nullptr, "Unknown514"},
1719 {520, nullptr, "EnableHandheldHids"}, 1762 {520, nullptr, "EnableHandheldHids"},
1720 {521, nullptr, "DisableHandheldHids"}, 1763 {521, nullptr, "DisableHandheldHids"},
1721 {522, nullptr, "SetJoyConRailEnabled"}, 1764 {522, nullptr, "SetJoyConRailEnabled"},
1722 {523, nullptr, "IsJoyConRailEnabled"}, 1765 {523, nullptr, "IsJoyConRailEnabled"},
1766 {524, nullptr, "IsHandheldHidsEnabled"},
1767 {525, nullptr, "IsJoyConAttachedOnAllRail"},
1723 {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, 1768 {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
1724 {541, nullptr, "GetPlayReportControllerUsages"}, 1769 {541, nullptr, "GetPlayReportControllerUsages"},
1725 {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, 1770 {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
@@ -1795,6 +1840,65 @@ public:
1795 {1154, nullptr, "IsFirmwareAvailableForNotification"}, 1840 {1154, nullptr, "IsFirmwareAvailableForNotification"},
1796 {1155, nullptr, "SetForceHandheldStyleVibration"}, 1841 {1155, nullptr, "SetForceHandheldStyleVibration"},
1797 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, 1842 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
1843 {1157, nullptr, "CancelConnectionTrigger"},
1844 {1200, nullptr, "IsButtonConfigSupported"},
1845 {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
1846 {1202, nullptr, "DeleteButtonConfig"},
1847 {1203, nullptr, "DeleteButtonConfigEmbedded"},
1848 {1204, nullptr, "SetButtonConfigEnabled"},
1849 {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
1850 {1206, nullptr, "IsButtonConfigEnabled"},
1851 {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
1852 {1208, nullptr, "SetButtonConfigEmbedded"},
1853 {1209, nullptr, "SetButtonConfigFull"},
1854 {1210, nullptr, "SetButtonConfigLeft"},
1855 {1211, nullptr, "SetButtonConfigRight"},
1856 {1212, nullptr, "GetButtonConfigEmbedded"},
1857 {1213, nullptr, "GetButtonConfigFull"},
1858 {1214, nullptr, "GetButtonConfigLeft"},
1859 {1215, nullptr, "GetButtonConfigRight"},
1860 {1250, nullptr, "IsCustomButtonConfigSupported"},
1861 {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
1862 {1252, nullptr, "IsDefaultButtonConfigFull"},
1863 {1253, nullptr, "IsDefaultButtonConfigLeft"},
1864 {1254, nullptr, "IsDefaultButtonConfigRight"},
1865 {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
1866 {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
1867 {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
1868 {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
1869 {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
1870 {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
1871 {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
1872 {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
1873 {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
1874 {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
1875 {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
1876 {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
1877 {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
1878 {1268, nullptr, "DeleteButtonConfigStorageFull"},
1879 {1269, nullptr, "DeleteButtonConfigStorageLeft"},
1880 {1270, nullptr, "DeleteButtonConfigStorageRight"},
1881 {1271, nullptr, "IsUsingCustomButtonConfig"},
1882 {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
1883 {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
1884 {1274, nullptr, "SetDefaultButtonConfig"},
1885 {1275, nullptr, "SetAllDefaultButtonConfig"},
1886 {1276, nullptr, "SetHidButtonConfigEmbedded"},
1887 {1277, nullptr, "SetHidButtonConfigFull"},
1888 {1278, nullptr, "SetHidButtonConfigLeft"},
1889 {1279, nullptr, "SetHidButtonConfigRight"},
1890 {1280, nullptr, "GetHidButtonConfigEmbedded"},
1891 {1281, nullptr, "GetHidButtonConfigFull"},
1892 {1282, nullptr, "GetHidButtonConfigLeft"},
1893 {1283, nullptr, "GetHidButtonConfigRight"},
1894 {1284, nullptr, "GetButtonConfigStorageEmbedded"},
1895 {1285, nullptr, "GetButtonConfigStorageFull"},
1896 {1286, nullptr, "GetButtonConfigStorageLeft"},
1897 {1287, nullptr, "GetButtonConfigStorageRight"},
1898 {1288, nullptr, "SetButtonConfigStorageEmbedded"},
1899 {1289, nullptr, "SetButtonConfigStorageFull"},
1900 {1290, nullptr, "DeleteButtonConfigStorageRight"},
1901 {1291, nullptr, "DeleteButtonConfigStorageRight"},
1798 }; 1902 };
1799 // clang-format on 1903 // clang-format on
1800 1904
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 36ed228c8..c2bdd39a3 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -129,6 +129,7 @@ private:
129 void SwapNpadAssignment(Kernel::HLERequestContext& ctx); 129 void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
130 void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx); 130 void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
131 void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); 131 void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
132 void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx);
132 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); 133 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
133 void SendVibrationValue(Kernel::HLERequestContext& ctx); 134 void SendVibrationValue(Kernel::HLERequestContext& ctx);
134 void GetActualVibrationValue(Kernel::HLERequestContext& ctx); 135 void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp
index 43a8840d0..b1efa3d05 100644
--- a/src/core/hle/service/hid/xcd.cpp
+++ b/src/core/hle/service/hid/xcd.cpp
@@ -28,6 +28,8 @@ XCD_SYS::XCD_SYS(Core::System& system_) : ServiceFramework{system_, "xcd:sys"} {
28 {20, nullptr, "StartMifareWrite"}, 28 {20, nullptr, "StartMifareWrite"},
29 {101, nullptr, "GetAwakeTriggerReasonForLeftRail"}, 29 {101, nullptr, "GetAwakeTriggerReasonForLeftRail"},
30 {102, nullptr, "GetAwakeTriggerReasonForRightRail"}, 30 {102, nullptr, "GetAwakeTriggerReasonForRightRail"},
31 {103, nullptr, "GetAwakeTriggerBatteryLevelTransitionForLeftRail"},
32 {104, nullptr, "GetAwakeTriggerBatteryLevelTransitionForRightRail"},
31 }; 33 };
32 // clang-format on 34 // clang-format on
33 35
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index d111c1357..c8bc60ad1 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -118,9 +118,9 @@ public:
118 explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} { 118 explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} {
119 // clang-format off 119 // clang-format off
120 static const FunctionInfo functions[] = { 120 static const FunctionInfo functions[] = {
121 {0, nullptr, "AddProcessToDebugLaunchQueue"}, 121 {0, nullptr, "SetProgramArgument"},
122 {1, nullptr, "ClearDebugLaunchQueue"}, 122 {1, nullptr, "FlushArguments"},
123 {2, nullptr, "GetNsoInfos"}, 123 {2, nullptr, "GetProcessModuleInfo"},
124 }; 124 };
125 // clang-format on 125 // clang-format on
126 126
@@ -135,8 +135,8 @@ public:
135 static const FunctionInfo functions[] = { 135 static const FunctionInfo functions[] = {
136 {0, nullptr, "CreateProcess"}, 136 {0, nullptr, "CreateProcess"},
137 {1, nullptr, "GetProgramInfo"}, 137 {1, nullptr, "GetProgramInfo"},
138 {2, nullptr, "RegisterTitle"}, 138 {2, nullptr, "PinProgram"},
139 {3, nullptr, "UnregisterTitle"}, 139 {3, nullptr, "UnpinProgram"},
140 {4, nullptr, "SetEnabledProgramVerification"}, 140 {4, nullptr, "SetEnabledProgramVerification"},
141 }; 141 };
142 // clang-format on 142 // clang-format on
@@ -150,8 +150,8 @@ public:
150 explicit Shell(Core::System& system_) : ServiceFramework{system_, "ldr:shel"} { 150 explicit Shell(Core::System& system_) : ServiceFramework{system_, "ldr:shel"} {
151 // clang-format off 151 // clang-format off
152 static const FunctionInfo functions[] = { 152 static const FunctionInfo functions[] = {
153 {0, nullptr, "AddProcessToLaunchQueue"}, 153 {0, nullptr, "SetProgramArgument"},
154 {1, nullptr, "ClearLaunchQueue"}, 154 {1, nullptr, "FlushArguments"},
155 }; 155 };
156 // clang-format on 156 // clang-format on
157 157
@@ -164,19 +164,19 @@ public:
164 explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} { 164 explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} {
165 // clang-format off 165 // clang-format off
166 static const FunctionInfo functions[] = { 166 static const FunctionInfo functions[] = {
167 {0, &RelocatableObject::LoadNro, "LoadNro"}, 167 {0, &RelocatableObject::LoadModule, "LoadModule"},
168 {1, &RelocatableObject::UnloadNro, "UnloadNro"}, 168 {1, &RelocatableObject::UnloadModule, "UnloadModule"},
169 {2, &RelocatableObject::LoadNrr, "LoadNrr"}, 169 {2, &RelocatableObject::RegisterModuleInfo, "RegisterModuleInfo"},
170 {3, &RelocatableObject::UnloadNrr, "UnloadNrr"}, 170 {3, &RelocatableObject::UnregisterModuleInfo, "UnregisterModuleInfo"},
171 {4, &RelocatableObject::Initialize, "Initialize"}, 171 {4, &RelocatableObject::Initialize, "Initialize"},
172 {10, nullptr, "LoadNrrEx"}, 172 {10, nullptr, "RegisterModuleInfo2"},
173 }; 173 };
174 // clang-format on 174 // clang-format on
175 175
176 RegisterHandlers(functions); 176 RegisterHandlers(functions);
177 } 177 }
178 178
179 void LoadNrr(Kernel::HLERequestContext& ctx) { 179 void RegisterModuleInfo(Kernel::HLERequestContext& ctx) {
180 struct Parameters { 180 struct Parameters {
181 u64_le process_id; 181 u64_le process_id;
182 u64_le nrr_address; 182 u64_le nrr_address;
@@ -273,7 +273,7 @@ public:
273 rb.Push(RESULT_SUCCESS); 273 rb.Push(RESULT_SUCCESS);
274 } 274 }
275 275
276 void UnloadNrr(Kernel::HLERequestContext& ctx) { 276 void UnregisterModuleInfo(Kernel::HLERequestContext& ctx) {
277 IPC::RequestParser rp{ctx}; 277 IPC::RequestParser rp{ctx};
278 const auto pid = rp.Pop<u64>(); 278 const auto pid = rp.Pop<u64>();
279 const auto nrr_address = rp.Pop<VAddr>(); 279 const auto nrr_address = rp.Pop<VAddr>();
@@ -408,7 +408,7 @@ public:
408 data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite); 408 data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite);
409 } 409 }
410 410
411 void LoadNro(Kernel::HLERequestContext& ctx) { 411 void LoadModule(Kernel::HLERequestContext& ctx) {
412 struct Parameters { 412 struct Parameters {
413 u64_le process_id; 413 u64_le process_id;
414 u64_le image_address; 414 u64_le image_address;
@@ -546,7 +546,7 @@ public:
546 return RESULT_SUCCESS; 546 return RESULT_SUCCESS;
547 } 547 }
548 548
549 void UnloadNro(Kernel::HLERequestContext& ctx) { 549 void UnloadModule(Kernel::HLERequestContext& ctx) {
550 if (!initialized) { 550 if (!initialized) {
551 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); 551 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
552 IPC::ResponseBuilder rb{ctx, 2}; 552 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 6ab35de47..44a5d5789 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -5,12 +5,12 @@
5#include <memory> 5#include <memory>
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/settings.h"
8#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h" 10#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/nfc/nfc.h" 11#include "core/hle/service/nfc/nfc.h"
11#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
13#include "core/settings.h"
14 14
15namespace Service::NFC { 15namespace Service::NFC {
16 16
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index afb3342d6..9f110df8e 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.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 "common/settings.h"
5#include "core/core.h" 6#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
@@ -10,7 +11,6 @@
10#include "core/hle/service/nifm/nifm.h" 11#include "core/hle/service/nifm/nifm.h"
11#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
12#include "core/network/network.h" 13#include "core/network/network.h"
13#include "core/settings.h"
14 14
15namespace Service::NIFM { 15namespace Service::NIFM {
16 16
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index f3be0b878..fee360ab9 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -125,51 +125,51 @@ public:
125 {39, nullptr, "PrepareShutdown"}, 125 {39, nullptr, "PrepareShutdown"},
126 {40, nullptr, "ListApplyDeltaTask"}, 126 {40, nullptr, "ListApplyDeltaTask"},
127 {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"}, 127 {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"},
128 {42, nullptr, "Unknown42"}, 128 {42, nullptr, "CreateApplyDeltaTaskFromDownloadTask"},
129 {43, nullptr, "Unknown43"}, 129 {43, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
130 {44, nullptr, "Unknown44"}, 130 {44, nullptr, "GetApplyDeltaTaskRequiredStorage"},
131 {45, nullptr, "Unknown45"}, 131 {45, nullptr, "CalculateNetworkInstallTaskContentsSize"},
132 {46, nullptr, "Unknown46"}, 132 {46, nullptr, "PrepareShutdownForSystemUpdate"},
133 {47, nullptr, "Unknown47"}, 133 {47, nullptr, "FindMaxRequiredApplicationVersionOfTask"},
134 {48, nullptr, "Unknown48"}, 134 {48, nullptr, "CommitNetworkInstallTaskPartially"},
135 {49, nullptr, "Unknown49"}, 135 {49, nullptr, "ListNetworkInstallTaskCommittedContentMeta"},
136 {50, nullptr, "Unknown50"}, 136 {50, nullptr, "ListNetworkInstallTaskNotCommittedContentMeta"},
137 {51, nullptr, "Unknown51"}, 137 {51, nullptr, "FindMaxRequiredSystemVersionOfTask"},
138 {52, nullptr, "Unknown52"}, 138 {52, nullptr, "GetNetworkInstallTaskErrorContext"},
139 {53, nullptr, "Unknown53"}, 139 {53, nullptr, "CreateLocalCommunicationReceiveApplicationTask"},
140 {54, nullptr, "Unknown54"}, 140 {54, nullptr, "DestroyLocalCommunicationReceiveApplicationTask"},
141 {55, nullptr, "Unknown55"}, 141 {55, nullptr, "ListLocalCommunicationReceiveApplicationTask"},
142 {56, nullptr, "Unknown56"}, 142 {56, nullptr, "RequestLocalCommunicationReceiveApplicationTaskRun"},
143 {57, nullptr, "Unknown57"}, 143 {57, nullptr, "GetLocalCommunicationReceiveApplicationTaskInfo"},
144 {58, nullptr, "Unknown58"}, 144 {58, nullptr, "CommitLocalCommunicationReceiveApplicationTask"},
145 {59, nullptr, "Unknown59"}, 145 {59, nullptr, "ListLocalCommunicationReceiveApplicationTaskContentMeta"},
146 {60, nullptr, "Unknown60"}, 146 {60, nullptr, "CreateLocalCommunicationSendApplicationTask"},
147 {61, nullptr, "Unknown61"}, 147 {61, nullptr, "RequestLocalCommunicationSendApplicationTaskRun"},
148 {62, nullptr, "Unknown62"}, 148 {62, nullptr, "GetLocalCommunicationReceiveApplicationTaskErrorContext"},
149 {63, nullptr, "Unknown63"}, 149 {63, nullptr, "GetLocalCommunicationSendApplicationTaskInfo"},
150 {64, nullptr, "Unknown64"}, 150 {64, nullptr, "DestroyLocalCommunicationSendApplicationTask"},
151 {65, nullptr, "Unknown65"}, 151 {65, nullptr, "GetLocalCommunicationSendApplicationTaskErrorContext"},
152 {66, nullptr, "Unknown66"}, 152 {66, nullptr, "CalculateLocalCommunicationReceiveApplicationTaskRequiredSize"},
153 {67, nullptr, "Unknown67"}, 153 {67, nullptr, "ListApplicationLocalCommunicationReceiveApplicationTask"},
154 {68, nullptr, "Unknown68"}, 154 {68, nullptr, "ListApplicationLocalCommunicationSendApplicationTask"},
155 {69, nullptr, "Unknown69"}, 155 {69, nullptr, "CreateLocalCommunicationReceiveSystemUpdateTask"},
156 {70, nullptr, "Unknown70"}, 156 {70, nullptr, "DestroyLocalCommunicationReceiveSystemUpdateTask"},
157 {71, nullptr, "Unknown71"}, 157 {71, nullptr, "ListLocalCommunicationReceiveSystemUpdateTask"},
158 {72, nullptr, "Unknown72"}, 158 {72, nullptr, "RequestLocalCommunicationReceiveSystemUpdateTaskRun"},
159 {73, nullptr, "Unknown73"}, 159 {73, nullptr, "GetLocalCommunicationReceiveSystemUpdateTaskInfo"},
160 {74, nullptr, "Unknown74"}, 160 {74, nullptr, "CommitLocalCommunicationReceiveSystemUpdateTask"},
161 {75, nullptr, "Unknown75"}, 161 {75, nullptr, "GetLocalCommunicationReceiveSystemUpdateTaskErrorContext"},
162 {76, nullptr, "Unknown76"}, 162 {76, nullptr, "CreateLocalCommunicationSendSystemUpdateTask"},
163 {77, nullptr, "Unknown77"}, 163 {77, nullptr, "RequestLocalCommunicationSendSystemUpdateTaskRun"},
164 {78, nullptr, "Unknown78"}, 164 {78, nullptr, "GetLocalCommunicationSendSystemUpdateTaskInfo"},
165 {79, nullptr, "Unknown79"}, 165 {79, nullptr, "DestroyLocalCommunicationSendSystemUpdateTask"},
166 {80, nullptr, "Unknown80"}, 166 {80, nullptr, "GetLocalCommunicationSendSystemUpdateTaskErrorContext"},
167 {81, nullptr, "Unknown81"}, 167 {81, nullptr, "ListLocalCommunicationSendSystemUpdateTask"},
168 {82, nullptr, "Unknown82"}, 168 {82, nullptr, "GetReceivedSystemDataPath"},
169 {83, nullptr, "Unknown83"}, 169 {83, nullptr, "CalculateApplyDeltaTaskOccupiedSize"},
170 {84, nullptr, "Unknown84"}, 170 {84, nullptr, "Unknown84"},
171 {85, nullptr, "Unknown85"}, 171 {85, nullptr, "ListNetworkInstallTaskContentMetaFromInstallMeta"},
172 {86, nullptr, "Unknown86"}, 172 {86, nullptr, "ListNetworkInstallTaskOccupiedSize"},
173 {87, nullptr, "Unknown87"}, 173 {87, nullptr, "Unknown87"},
174 {88, nullptr, "Unknown88"}, 174 {88, nullptr, "Unknown88"},
175 {89, nullptr, "Unknown89"}, 175 {89, nullptr, "Unknown89"},
@@ -202,6 +202,17 @@ public:
202 {116, nullptr, "Unknown116"}, 202 {116, nullptr, "Unknown116"},
203 {117, nullptr, "Unknown117"}, 203 {117, nullptr, "Unknown117"},
204 {118, nullptr, "Unknown118"}, 204 {118, nullptr, "Unknown118"},
205 {119, nullptr, "Unknown119"},
206 {120, nullptr, "Unknown120"},
207 {121, nullptr, "Unknown121"},
208 {122, nullptr, "Unknown122"},
209 {123, nullptr, "Unknown123"},
210 {124, nullptr, "Unknown124"},
211 {125, nullptr, "Unknown125"},
212 {126, nullptr, "Unknown126"},
213 {127, nullptr, "Unknown127"},
214 {128, nullptr, "Unknown128"},
215 {129, nullptr, "Unknown129"},
205 }; 216 };
206 // clang-format on 217 // clang-format on
207 218
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index f7a58f659..e4c703da4 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -49,6 +49,8 @@ public:
49 {151, nullptr, "GetStateWithHandover"}, 49 {151, nullptr, "GetStateWithHandover"},
50 {152, nullptr, "GetStateChangeEventWithHandover"}, 50 {152, nullptr, "GetStateChangeEventWithHandover"},
51 {153, nullptr, "GetDropEventWithHandover"}, 51 {153, nullptr, "GetDropEventWithHandover"},
52 {154, nullptr, "CreateTokenAsync"},
53 {155, nullptr, "CreateTokenAsyncWithApplicationId"},
52 {161, nullptr, "GetRequestChangeStateCancelEvent"}, 54 {161, nullptr, "GetRequestChangeStateCancelEvent"},
53 {162, nullptr, "RequestChangeStateForceTimedWithCancelEvent"}, 55 {162, nullptr, "RequestChangeStateForceTimedWithCancelEvent"},
54 {201, nullptr, "RequestChangeStateForceTimed"}, 56 {201, nullptr, "RequestChangeStateForceTimed"},
@@ -84,6 +86,7 @@ public:
84 {151, nullptr, "GetStateWithHandover"}, 86 {151, nullptr, "GetStateWithHandover"},
85 {152, nullptr, "GetStateChangeEventWithHandover"}, 87 {152, nullptr, "GetStateChangeEventWithHandover"},
86 {153, nullptr, "GetDropEventWithHandover"}, 88 {153, nullptr, "GetDropEventWithHandover"},
89 {154, nullptr, "CreateTokenAsync"},
87 }; 90 };
88 // clang-format on 91 // clang-format on
89 92
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 6ccf8995c..e373609a1 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.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 "common/logging/log.h" 5#include "common/logging/log.h"
6#include "common/settings.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/file_sys/control_metadata.h" 8#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/patch_manager.h" 9#include "core/file_sys/patch_manager.h"
@@ -14,7 +15,6 @@
14#include "core/hle/service/ns/ns.h" 15#include "core/hle/service/ns/ns.h"
15#include "core/hle/service/ns/pl_u.h" 16#include "core/hle/service/ns/pl_u.h"
16#include "core/hle/service/set/set.h" 17#include "core/hle/service/set/set.h"
17#include "core/settings.h"
18 18
19namespace Service::NS { 19namespace Service::NS {
20 20
@@ -55,6 +55,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
55 {26, nullptr, "BeginInstallApplication"}, 55 {26, nullptr, "BeginInstallApplication"},
56 {27, nullptr, "DeleteApplicationRecord"}, 56 {27, nullptr, "DeleteApplicationRecord"},
57 {30, nullptr, "RequestApplicationUpdateInfo"}, 57 {30, nullptr, "RequestApplicationUpdateInfo"},
58 {31, nullptr, "Unknown31"},
58 {32, nullptr, "CancelApplicationDownload"}, 59 {32, nullptr, "CancelApplicationDownload"},
59 {33, nullptr, "ResumeApplicationDownload"}, 60 {33, nullptr, "ResumeApplicationDownload"},
60 {35, nullptr, "UpdateVersionList"}, 61 {35, nullptr, "UpdateVersionList"},
@@ -182,6 +183,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
182 {913, nullptr, "ListAllApplicationRecord"}, 183 {913, nullptr, "ListAllApplicationRecord"},
183 {914, nullptr, "HideApplicationRecord"}, 184 {914, nullptr, "HideApplicationRecord"},
184 {915, nullptr, "ShowApplicationRecord"}, 185 {915, nullptr, "ShowApplicationRecord"},
186 {916, nullptr, "IsApplicationAutoDeleteDisabled"},
185 {1000, nullptr, "RequestVerifyApplicationDeprecated"}, 187 {1000, nullptr, "RequestVerifyApplicationDeprecated"},
186 {1001, nullptr, "CorruptApplicationForDebug"}, 188 {1001, nullptr, "CorruptApplicationForDebug"},
187 {1002, nullptr, "RequestVerifyAddOnContentsRights"}, 189 {1002, nullptr, "RequestVerifyAddOnContentsRights"},
@@ -201,6 +203,8 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
201 {1310, nullptr, "RequestMoveApplicationEntity"}, 203 {1310, nullptr, "RequestMoveApplicationEntity"},
202 {1311, nullptr, "EstimateSizeToMove"}, 204 {1311, nullptr, "EstimateSizeToMove"},
203 {1312, nullptr, "HasMovableEntity"}, 205 {1312, nullptr, "HasMovableEntity"},
206 {1313, nullptr, "CleanupOrphanContents"},
207 {1314, nullptr, "CheckPreconditionSatisfiedToMove"},
204 {1400, nullptr, "PrepareShutdown"}, 208 {1400, nullptr, "PrepareShutdown"},
205 {1500, nullptr, "FormatSdCard"}, 209 {1500, nullptr, "FormatSdCard"},
206 {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"}, 210 {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
@@ -215,6 +219,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
215 {1702, nullptr, "GetApplicationDownloadTaskStatus"}, 219 {1702, nullptr, "GetApplicationDownloadTaskStatus"},
216 {1703, nullptr, "GetApplicationViewDownloadErrorContext"}, 220 {1703, nullptr, "GetApplicationViewDownloadErrorContext"},
217 {1704, nullptr, "GetApplicationViewWithPromotionInfo"}, 221 {1704, nullptr, "GetApplicationViewWithPromotionInfo"},
222 {1705, nullptr, "IsPatchAutoDeletableApplication"},
218 {1800, nullptr, "IsNotificationSetupCompleted"}, 223 {1800, nullptr, "IsNotificationSetupCompleted"},
219 {1801, nullptr, "GetLastNotificationInfoCount"}, 224 {1801, nullptr, "GetLastNotificationInfoCount"},
220 {1802, nullptr, "ListLastNotificationInfo"}, 225 {1802, nullptr, "ListLastNotificationInfo"},
@@ -269,6 +274,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
269 {2351, nullptr, "RequestNoDownloadRightsErrorResolution"}, 274 {2351, nullptr, "RequestNoDownloadRightsErrorResolution"},
270 {2352, nullptr, "RequestResolveNoDownloadRightsError"}, 275 {2352, nullptr, "RequestResolveNoDownloadRightsError"},
271 {2353, nullptr, "GetApplicationDownloadTaskInfo"}, 276 {2353, nullptr, "GetApplicationDownloadTaskInfo"},
277 {2354, nullptr, "PrioritizeApplicationBackgroundTask"},
278 {2355, nullptr, "Unknown2355"},
279 {2356, nullptr, "Unknown2356"},
272 {2400, nullptr, "GetPromotionInfo"}, 280 {2400, nullptr, "GetPromotionInfo"},
273 {2401, nullptr, "CountPromotionInfo"}, 281 {2401, nullptr, "CountPromotionInfo"},
274 {2402, nullptr, "ListPromotionInfo"}, 282 {2402, nullptr, "ListPromotionInfo"},
@@ -282,6 +290,21 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
282 {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"}, 290 {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"},
283 {2516, nullptr, "EnsureApplicationCertificate"}, 291 {2516, nullptr, "EnsureApplicationCertificate"},
284 {2800, nullptr, "GetApplicationIdOfPreomia"}, 292 {2800, nullptr, "GetApplicationIdOfPreomia"},
293 {3000, nullptr, "RegisterDeviceLockKey"},
294 {3001, nullptr, "UnregisterDeviceLockKey"},
295 {3002, nullptr, "VerifyDeviceLockKey"},
296 {3003, nullptr, "HideApplicationIcon"},
297 {3004, nullptr, "ShowApplicationIcon"},
298 {3005, nullptr, "HideApplicationTitle"},
299 {3006, nullptr, "ShowApplicationTitle"},
300 {3007, nullptr, "EnableGameCard"},
301 {3008, nullptr, "DisableGameCard"},
302 {3009, nullptr, "EnableLocalContentShare"},
303 {3010, nullptr, "DisableLocalContentShare"},
304 {3011, nullptr, "IsApplicationIconHidden"},
305 {3012, nullptr, "IsApplicationTitleHidden"},
306 {3013, nullptr, "IsGameCardEnabled"},
307 {3014, nullptr, "IsLocalContentShareEnabled"},
285 {9999, nullptr, "GetApplicationCertificate"}, 308 {9999, nullptr, "GetApplicationCertificate"},
286 }; 309 };
287 // clang-format on 310 // clang-format on
@@ -441,7 +464,11 @@ IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_
441 {800, nullptr, "RequestVersionList"}, 464 {800, nullptr, "RequestVersionList"},
442 {801, nullptr, "ListVersionList"}, 465 {801, nullptr, "ListVersionList"},
443 {802, nullptr, "RequestVersionListData"}, 466 {802, nullptr, "RequestVersionListData"},
467 {900, nullptr, "ImportAutoUpdatePolicyJsonForDebug"},
468 {901, nullptr, "ListDefaultAutoUpdatePolicy"},
469 {902, nullptr, "ListAutoUpdatePolicyForSpecificApplication"},
444 {1000, nullptr, "PerformAutoUpdate"}, 470 {1000, nullptr, "PerformAutoUpdate"},
471 {1001, nullptr, "ListAutoUpdateSchedule"},
445 }; 472 };
446 // clang-format on 473 // clang-format on
447 474
@@ -547,6 +574,9 @@ IFactoryResetInterface::~IFactoryResetInterface() = default;
547NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { 574NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
548 // clang-format off 575 // clang-format off
549 static const FunctionInfo functions[] = { 576 static const FunctionInfo functions[] = {
577 {7988, nullptr, "GetDynamicRightsInterface"},
578 {7989, nullptr, "GetReadOnlyApplicationControlDataInterface"},
579 {7991, nullptr, "GetReadOnlyApplicationRecordInterface"},
550 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, 580 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
551 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, 581 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
552 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, 582 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
@@ -575,18 +605,22 @@ public:
575 {0, nullptr, "LaunchProgram"}, 605 {0, nullptr, "LaunchProgram"},
576 {1, nullptr, "TerminateProcess"}, 606 {1, nullptr, "TerminateProcess"},
577 {2, nullptr, "TerminateProgram"}, 607 {2, nullptr, "TerminateProgram"},
578 {4, nullptr, "GetShellEventHandle"}, 608 {4, nullptr, "GetShellEvent"},
579 {5, nullptr, "GetShellEventInfo"}, 609 {5, nullptr, "GetShellEventInfo"},
580 {6, nullptr, "TerminateApplication"}, 610 {6, nullptr, "TerminateApplication"},
581 {7, nullptr, "PrepareLaunchProgramFromHost"}, 611 {7, nullptr, "PrepareLaunchProgramFromHost"},
582 {8, nullptr, "LaunchApplication"}, 612 {8, nullptr, "LaunchApplicationFromHost"},
583 {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"}, 613 {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
584 {10, nullptr, "IsSystemMemoryResourceLimitBoosted"}, 614 {10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
585 {11, nullptr, "GetRunningApplicationProcessIdForDevelop"}, 615 {11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
586 {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"}, 616 {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop"},
587 {13, nullptr, "CreateApplicationResourceForDevelop"}, 617 {13, nullptr, "CreateApplicationResourceForDevelop"},
588 {14, nullptr, "IsPreomiaForDevelop"}, 618 {14, nullptr, "IsPreomiaForDevelop"},
589 {15, nullptr, "GetApplicationProgramIdFromHost"}, 619 {15, nullptr, "GetApplicationProgramIdFromHost"},
620 {16, nullptr, "RefreshCachedDebugValues"},
621 {17, nullptr, "PrepareLaunchApplicationFromHost"},
622 {18, nullptr, "GetLaunchEvent"},
623 {19, nullptr, "GetLaunchResult"},
590 }; 624 };
591 // clang-format on 625 // clang-format on
592 626
@@ -699,6 +733,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
699 std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager); 733 std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager);
700 std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager); 734 std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager);
701 std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager); 735 std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager);
736 std::make_shared<NS>("ns:ro", system)->InstallAsService(service_manager);
702 737
703 std::make_shared<NS_DEV>(system)->InstallAsService(service_manager); 738 std::make_shared<NS_DEV>(system)->InstallAsService(service_manager);
704 std::make_shared<NS_SU>(system)->InstallAsService(service_manager); 739 std::make_shared<NS_SU>(system)->InstallAsService(service_manager);
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index fcd15d81f..da139fdc4 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -154,6 +154,10 @@ PL_U::PL_U(Core::System& system_)
154 {100, nullptr, "RequestApplicationFunctionAuthorization"}, 154 {100, nullptr, "RequestApplicationFunctionAuthorization"},
155 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, 155 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
156 {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"}, 156 {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"},
157 {103, nullptr, "RefreshApplicationFunctionBlackListDebugRecord"},
158 {104, nullptr, "RequestApplicationFunctionAuthorizationByProgramId"},
159 {105, nullptr, "GetFunctionBlackListSystemVersionToAuthorize"},
160 {106, nullptr, "GetFunctionBlackListVersion"},
157 {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"}, 161 {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"},
158 {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"}, 162 {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"},
159 }; 163 };
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 933d42f3f..2edd803f3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -248,7 +248,13 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<
248 IoctlZbcSetTable params{}; 248 IoctlZbcSetTable params{};
249 std::memcpy(&params, input.data(), input.size()); 249 std::memcpy(&params, input.data(), input.size());
250 // TODO(ogniK): What does this even actually do? 250 // TODO(ogniK): What does this even actually do?
251 std::memcpy(output.data(), &params, output.size()); 251
252 // Prevent null pointer being passed as arg 1
253 if (output.empty()) {
254 LOG_WARNING(Service_NVDRV, "Avoiding passing null pointer to memcpy");
255 } else {
256 std::memcpy(output.data(), &params, output.size());
257 }
252 return NvResult::Success; 258 return NvResult::Success;
253} 259}
254 260
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 4898dc27a..c2f152190 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -23,17 +23,22 @@ namespace {
23template <typename T> 23template <typename T>
24std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count, 24std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
25 std::size_t offset) { 25 std::size_t offset) {
26 std::memcpy(dst.data(), input.data() + offset, count * sizeof(T)); 26 if (!dst.empty()) {
27 offset += count * sizeof(T); 27 std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
28 return offset; 28 }
29 return 0;
29} 30}
30 31
31// Write vectors will write data to the output buffer 32// Write vectors will write data to the output buffer
32template <typename T> 33template <typename T>
33std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) { 34std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
34 std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T)); 35 if (src.empty()) {
35 offset += src.size() * sizeof(T); 36 return 0;
36 return offset; 37 } else {
38 std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
39 offset += src.size() * sizeof(T);
40 return offset;
41 }
37} 42}
38} // Anonymous namespace 43} // Anonymous namespace
39 44
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index ac2906e5b..539b02bc4 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -9,6 +9,7 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/microprofile.h" 10#include "common/microprofile.h"
11#include "common/scope_exit.h" 11#include "common/scope_exit.h"
12#include "common/settings.h"
12#include "common/thread.h" 13#include "common/thread.h"
13#include "core/core.h" 14#include "core/core.h"
14#include "core/core_timing.h" 15#include "core/core_timing.h"
@@ -23,7 +24,6 @@
23#include "core/hle/service/vi/display/vi_display.h" 24#include "core/hle/service/vi/display/vi_display.h"
24#include "core/hle/service/vi/layer/vi_layer.h" 25#include "core/hle/service/vi/layer/vi_layer.h"
25#include "core/perf_stats.h" 26#include "core/perf_stats.h"
26#include "core/settings.h"
27#include "video_core/renderer_base.h" 27#include "video_core/renderer_base.h"
28 28
29namespace Service::NVFlinger { 29namespace Service::NVFlinger {
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index e2ac71fa1..b066c3417 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -26,6 +26,7 @@ public:
26 {22, nullptr, "DeleteSaveDataBackupAsync"}, 26 {22, nullptr, "DeleteSaveDataBackupAsync"},
27 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"}, 27 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
28 {26, nullptr, "DownloadSaveDataBackupAsync"}, 28 {26, nullptr, "DownloadSaveDataBackupAsync"},
29 {27, nullptr, "UploadSaveDataBackupAsync"},
29 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"}, 30 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
30 {9013, nullptr, "GetSaveDataBackupSettingForDebug"}, 31 {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
31 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"}, 32 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp
index f6686fc4d..9bc851591 100644
--- a/src/core/hle/service/pcie/pcie.cpp
+++ b/src/core/hle/service/pcie/pcie.cpp
@@ -37,7 +37,7 @@ public:
37 {19, nullptr, "SetIrqEnable"}, 37 {19, nullptr, "SetIrqEnable"},
38 {20, nullptr, "SetAspmEnable"}, 38 {20, nullptr, "SetAspmEnable"},
39 {21, nullptr, "SetResetUponResumeEnable"}, 39 {21, nullptr, "SetResetUponResumeEnable"},
40 {22, nullptr, "Unknown22"}, 40 {22, nullptr, "ResetFunction"},
41 {23, nullptr, "Unknown23"}, 41 {23, nullptr, "Unknown23"},
42 }; 42 };
43 // clang-format on 43 // clang-format on
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index f9089bf2f..dc59702f1 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -3,16 +3,30 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h"
7#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/patch_manager.h"
6#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/process.h"
7#include "core/hle/service/pctl/module.h" 11#include "core/hle/service/pctl/module.h"
8#include "core/hle/service/pctl/pctl.h" 12#include "core/hle/service/pctl/pctl.h"
9 13
10namespace Service::PCTL { 14namespace Service::PCTL {
11 15
16namespace Error {
17
18constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101};
19constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
20constexpr ResultCode ResultNoCapability{ErrorModule::PCTL, 131};
21constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
22
23} // namespace Error
24
12class IParentalControlService final : public ServiceFramework<IParentalControlService> { 25class IParentalControlService final : public ServiceFramework<IParentalControlService> {
13public: 26public:
14 explicit IParentalControlService(Core::System& system_) 27 explicit IParentalControlService(Core::System& system_, Capability capability)
15 : ServiceFramework{system_, "IParentalControlService"} { 28 : ServiceFramework{system_, "IParentalControlService"}, system(system_),
29 capability(capability) {
16 // clang-format off 30 // clang-format off
17 static const FunctionInfo functions[] = { 31 static const FunctionInfo functions[] = {
18 {1, &IParentalControlService::Initialize, "Initialize"}, 32 {1, &IParentalControlService::Initialize, "Initialize"},
@@ -28,13 +42,13 @@ public:
28 {1010, nullptr, "IsRestrictedSystemSettingsEntered"}, 42 {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
29 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, 43 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
30 {1012, nullptr, "GetRestrictedFeatures"}, 44 {1012, nullptr, "GetRestrictedFeatures"},
31 {1013, nullptr, "ConfirmStereoVisionPermission"}, 45 {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
32 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, 46 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
33 {1015, nullptr, "ConfirmPlayableApplicationVideo"}, 47 {1015, nullptr, "ConfirmPlayableApplicationVideo"},
34 {1016, nullptr, "ConfirmShowNewsPermission"}, 48 {1016, nullptr, "ConfirmShowNewsPermission"},
35 {1017, nullptr, "EndFreeCommunication"}, 49 {1017, nullptr, "EndFreeCommunication"},
36 {1018, nullptr, "IsFreeCommunicationAvailable"}, 50 {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
37 {1031, nullptr, "IsRestrictionEnabled"}, 51 {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
38 {1032, nullptr, "GetSafetyLevel"}, 52 {1032, nullptr, "GetSafetyLevel"},
39 {1033, nullptr, "SetSafetyLevel"}, 53 {1033, nullptr, "SetSafetyLevel"},
40 {1034, nullptr, "GetSafetyLevelSettings"}, 54 {1034, nullptr, "GetSafetyLevelSettings"},
@@ -50,6 +64,7 @@ public:
50 {1046, nullptr, "DisableFeaturesForReset"}, 64 {1046, nullptr, "DisableFeaturesForReset"},
51 {1047, nullptr, "NotifyApplicationDownloadStarted"}, 65 {1047, nullptr, "NotifyApplicationDownloadStarted"},
52 {1048, nullptr, "NotifyNetworkProfileCreated"}, 66 {1048, nullptr, "NotifyNetworkProfileCreated"},
67 {1049, nullptr, "ResetFreeCommunicationApplicationList"},
53 {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"}, 68 {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
54 {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"}, 69 {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
55 {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"}, 70 {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
@@ -69,6 +84,8 @@ public:
69 {1421, nullptr, "GetAccountNickname"}, 84 {1421, nullptr, "GetAccountNickname"},
70 {1424, nullptr, "GetAccountState"}, 85 {1424, nullptr, "GetAccountState"},
71 {1425, nullptr, "RequestPostEvents"}, 86 {1425, nullptr, "RequestPostEvents"},
87 {1426, nullptr, "GetPostEventInterval"},
88 {1427, nullptr, "SetPostEventInterval"},
72 {1432, nullptr, "GetSynchronizationEvent"}, 89 {1432, nullptr, "GetSynchronizationEvent"},
73 {1451, nullptr, "StartPlayTimer"}, 90 {1451, nullptr, "StartPlayTimer"},
74 {1452, nullptr, "StopPlayTimer"}, 91 {1452, nullptr, "StopPlayTimer"},
@@ -119,62 +136,235 @@ public:
119 } 136 }
120 137
121private: 138private:
139 bool CheckFreeCommunicationPermissionImpl() const {
140 if (states.temporary_unlocked) {
141 return true;
142 }
143 if ((states.application_info.parental_control_flag & 1) == 0) {
144 return true;
145 }
146 if (pin_code[0] == '\0') {
147 return true;
148 }
149 if (!settings.is_free_communication_default_on) {
150 return true;
151 }
152 // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
153 // but as we don't have multiproceses support yet, we can just assume our application is
154 // valid for the time being
155 return true;
156 }
157
158 bool ConfirmStereoVisionPermissionImpl() const {
159 if (states.temporary_unlocked) {
160 return true;
161 }
162 if (pin_code[0] == '\0') {
163 return true;
164 }
165 if (!settings.is_stero_vision_restricted) {
166 return false;
167 }
168 return true;
169 }
170
171 void SetStereoVisionRestrictionImpl(bool is_restricted) {
172 if (settings.disabled) {
173 return;
174 }
175
176 if (pin_code[0] == '\0') {
177 return;
178 }
179 settings.is_stero_vision_restricted = is_restricted;
180 }
181
122 void Initialize(Kernel::HLERequestContext& ctx) { 182 void Initialize(Kernel::HLERequestContext& ctx) {
123 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 183 LOG_DEBUG(Service_PCTL, "called");
184 IPC::ResponseBuilder rb{ctx, 2};
185
186 if (False(capability & (Capability::Application | Capability::System))) {
187 LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
188 return;
189 }
190
191 // TODO(ogniK): Recovery flag initialization for pctl:r
192
193 const auto tid = system.CurrentProcess()->GetTitleID();
194 if (tid != 0) {
195 const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
196 system.GetContentProvider()};
197 const auto control = pm.GetControlMetadata();
198 if (control.first) {
199 states.tid_from_event = 0;
200 states.launch_time_valid = false;
201 states.is_suspended = false;
202 states.free_communication = false;
203 states.stereo_vision = false;
204 states.application_info = ApplicationInfo{
205 .tid = tid,
206 .age_rating = control.first->GetRatingAge(),
207 .parental_control_flag = control.first->GetParentalControlFlag(),
208 .capability = capability,
209 };
210
211 if (False(capability & (Capability::System | Capability::Recovery))) {
212 // TODO(ogniK): Signal application launch event
213 }
214 }
215 }
124 216
125 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
126 rb.Push(RESULT_SUCCESS); 217 rb.Push(RESULT_SUCCESS);
127 } 218 }
128 219
129 void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { 220 void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
130 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 221 LOG_DEBUG(Service_PCTL, "called");
222
223 IPC::ResponseBuilder rb{ctx, 2};
224 if (!CheckFreeCommunicationPermissionImpl()) {
225 rb.Push(Error::ResultNoFreeCommunication);
226 } else {
227 rb.Push(RESULT_SUCCESS);
228 }
229
230 states.free_communication = true;
231 }
232
233 void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) {
234 LOG_DEBUG(Service_PCTL, "called");
235 states.stereo_vision = true;
131 236
132 IPC::ResponseBuilder rb{ctx, 2}; 237 IPC::ResponseBuilder rb{ctx, 2};
133 rb.Push(RESULT_SUCCESS); 238 rb.Push(RESULT_SUCCESS);
134 } 239 }
135 240
136 void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) { 241 void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
137 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 242 LOG_WARNING(Service_PCTL, "(STUBBED) called");
138 243
139 IPC::ResponseBuilder rb{ctx, 2}; 244 IPC::ResponseBuilder rb{ctx, 2};
245 if (!CheckFreeCommunicationPermissionImpl()) {
246 rb.Push(Error::ResultNoFreeCommunication);
247 } else {
248 rb.Push(RESULT_SUCCESS);
249 }
250 }
251
252 void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) {
253 LOG_DEBUG(Service_PCTL, "called");
254
255 IPC::ResponseBuilder rb{ctx, 3};
256 if (False(capability & (Capability::Status | Capability::Recovery))) {
257 LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
258 rb.Push(Error::ResultNoCapability);
259 rb.Push(false);
260 return;
261 }
262
263 rb.Push(pin_code[0] != '\0');
264 }
265
266 void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
267 LOG_DEBUG(Service_PCTL, "called");
268
269 IPC::ResponseBuilder rb{ctx, 2};
270
271 if (False(capability & Capability::StereoVision)) {
272 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
273 rb.Push(Error::ResultNoCapability);
274 return;
275 }
276
277 if (pin_code[0] == '\0') {
278 rb.Push(Error::ResultNoRestrictionEnabled);
279 return;
280 }
281
140 rb.Push(RESULT_SUCCESS); 282 rb.Push(RESULT_SUCCESS);
141 } 283 }
142 284
143 void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) { 285 void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) {
144 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 286 LOG_DEBUG(Service_PCTL, "called");
145 287
146 IPC::ResponseBuilder rb{ctx, 3}; 288 IPC::ResponseBuilder rb{ctx, 3};
147 rb.Push(RESULT_SUCCESS); 289 if (!ConfirmStereoVisionPermissionImpl()) {
148 rb.Push(true); 290 rb.Push(Error::ResultStereoVisionRestricted);
291 rb.Push(false);
292 } else {
293 rb.Push(RESULT_SUCCESS);
294 rb.Push(true);
295 }
149 } 296 }
150 297
151 void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { 298 void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
152 IPC::RequestParser rp{ctx}; 299 IPC::RequestParser rp{ctx};
153 const auto can_use = rp.Pop<bool>(); 300 const auto can_use = rp.Pop<bool>();
154 LOG_WARNING(Service_PCTL, "(STUBBED) called, can_use={}", can_use); 301 LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
155
156 can_use_stereo_vision = can_use;
157 302
158 IPC::ResponseBuilder rb{ctx, 2}; 303 IPC::ResponseBuilder rb{ctx, 2};
304 if (False(capability & Capability::StereoVision)) {
305 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
306 rb.Push(Error::ResultNoCapability);
307 return;
308 }
309
310 SetStereoVisionRestrictionImpl(can_use);
159 rb.Push(RESULT_SUCCESS); 311 rb.Push(RESULT_SUCCESS);
160 } 312 }
161 313
162 void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { 314 void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
163 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 315 LOG_DEBUG(Service_PCTL, "called");
164 316
165 IPC::ResponseBuilder rb{ctx, 3}; 317 IPC::ResponseBuilder rb{ctx, 3};
318 if (False(capability & Capability::StereoVision)) {
319 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
320 rb.Push(Error::ResultNoCapability);
321 rb.Push(false);
322 return;
323 }
324
166 rb.Push(RESULT_SUCCESS); 325 rb.Push(RESULT_SUCCESS);
167 rb.Push(can_use_stereo_vision); 326 rb.Push(settings.is_stero_vision_restricted);
168 } 327 }
169 328
170 void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) { 329 void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) {
171 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 330 LOG_DEBUG(Service_PCTL, "called");
331
332 states.stereo_vision = false;
172 333
173 IPC::ResponseBuilder rb{ctx, 2}; 334 IPC::ResponseBuilder rb{ctx, 2};
174 rb.Push(RESULT_SUCCESS); 335 rb.Push(RESULT_SUCCESS);
175 } 336 }
176 337
338 struct ApplicationInfo {
339 u64 tid{};
340 std::array<u8, 32> age_rating{};
341 u32 parental_control_flag{};
342 Capability capability{};
343 };
344
345 struct States {
346 u64 current_tid{};
347 ApplicationInfo application_info{};
348 u64 tid_from_event{};
349 bool launch_time_valid{};
350 bool is_suspended{};
351 bool temporary_unlocked{};
352 bool free_communication{};
353 bool stereo_vision{};
354 };
355
356 struct ParentalControlSettings {
357 bool is_stero_vision_restricted{};
358 bool is_free_communication_default_on{};
359 bool disabled{};
360 };
361
362 States states{};
363 ParentalControlSettings settings{};
364 std::array<char, 8> pin_code{};
177 bool can_use_stereo_vision = true; 365 bool can_use_stereo_vision = true;
366 Core::System& system;
367 Capability capability{};
178}; 368};
179 369
180void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { 370void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
@@ -182,7 +372,9 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
182 372
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 373 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(RESULT_SUCCESS); 374 rb.Push(RESULT_SUCCESS);
185 rb.PushIpcInterface<IParentalControlService>(system); 375 // TODO(ogniK): Get TID from process
376
377 rb.PushIpcInterface<IParentalControlService>(system, capability);
186} 378}
187 379
188void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { 380void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
@@ -190,21 +382,28 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
190 382
191 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 383 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
192 rb.Push(RESULT_SUCCESS); 384 rb.Push(RESULT_SUCCESS);
193 rb.PushIpcInterface<IParentalControlService>(system); 385 rb.PushIpcInterface<IParentalControlService>(system, capability);
194} 386}
195 387
196Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, 388Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
197 const char* name) 389 const char* name, Capability capability)
198 : ServiceFramework{system_, name}, module{std::move(module_)} {} 390 : ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {}
199 391
200Module::Interface::~Interface() = default; 392Module::Interface::~Interface() = default;
201 393
202void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 394void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
203 auto module = std::make_shared<Module>(); 395 auto module = std::make_shared<Module>();
204 std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager); 396 std::make_shared<PCTL>(system, module, "pctl",
205 std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager); 397 Capability::Application | Capability::SnsPost | Capability::Status |
206 std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager); 398 Capability::StereoVision)
207 std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager); 399 ->InstallAsService(service_manager);
400 // TODO(ogniK): Implement remaining capabilities
401 std::make_shared<PCTL>(system, module, "pctl:a", Capability::None)
402 ->InstallAsService(service_manager);
403 std::make_shared<PCTL>(system, module, "pctl:r", Capability::None)
404 ->InstallAsService(service_manager);
405 std::make_shared<PCTL>(system, module, "pctl:s", Capability::None)
406 ->InstallAsService(service_manager);
208} 407}
209 408
210} // namespace Service::PCTL 409} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h
index 4c7e09a3b..032481b00 100644
--- a/src/core/hle/service/pctl/module.h
+++ b/src/core/hle/service/pctl/module.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_funcs.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Core { 10namespace Core {
@@ -12,12 +13,23 @@ class System;
12 13
13namespace Service::PCTL { 14namespace Service::PCTL {
14 15
16enum class Capability : u32 {
17 None = 0,
18 Application = 1 << 0,
19 SnsPost = 1 << 1,
20 Recovery = 1 << 6,
21 Status = 1 << 8,
22 StereoVision = 1 << 9,
23 System = 1 << 15,
24};
25DECLARE_ENUM_FLAG_OPERATORS(Capability);
26
15class Module final { 27class Module final {
16public: 28public:
17 class Interface : public ServiceFramework<Interface> { 29 class Interface : public ServiceFramework<Interface> {
18 public: 30 public:
19 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, 31 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
20 const char* name); 32 Capability capability);
21 ~Interface() override; 33 ~Interface() override;
22 34
23 void CreateService(Kernel::HLERequestContext& ctx); 35 void CreateService(Kernel::HLERequestContext& ctx);
@@ -25,6 +37,9 @@ public:
25 37
26 protected: 38 protected:
27 std::shared_ptr<Module> module; 39 std::shared_ptr<Module> module;
40
41 private:
42 Capability capability{};
28 }; 43 };
29}; 44};
30 45
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index 16dd34f90..e4d155c86 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -6,8 +6,9 @@
6 6
7namespace Service::PCTL { 7namespace Service::PCTL {
8 8
9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name) 9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
10 : Interface{system_, std::move(module_), name} { 10 Capability capability)
11 : Interface{system_, std::move(module_), name, capability} {
11 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
12 {0, &PCTL::CreateService, "CreateService"}, 13 {0, &PCTL::CreateService, "CreateService"},
13 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, 14 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 275d23007..fd0a1e486 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -14,7 +14,8 @@ namespace Service::PCTL {
14 14
15class PCTL final : public Module::Interface { 15class PCTL final : public Module::Interface {
16public: 16public:
17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name); 17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
18 Capability capability);
18 ~PCTL() override; 19 ~PCTL() override;
19}; 20};
20 21
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 1da56bc27..41a502d8d 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -6,6 +6,7 @@
6#include <fmt/format.h> 6#include <fmt/format.h>
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/settings.h"
9#include "common/string_util.h" 10#include "common/string_util.h"
10#include "core/core.h" 11#include "core/core.h"
11#include "core/hle/ipc.h" 12#include "core/hle/ipc.h"
@@ -146,6 +147,11 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
146 system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name, 147 system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
147 service_name); 148 service_name);
148 UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf)); 149 UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
150 if (Settings::values.use_auto_stub) {
151 LOG_WARNING(Service, "Using auto stub fallback!");
152 IPC::ResponseBuilder rb{ctx, 2};
153 rb.Push(RESULT_SUCCESS);
154 }
149} 155}
150 156
151void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { 157void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index d953b4303..bc7dc776f 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -6,9 +6,9 @@
6#include <array> 6#include <array>
7#include <chrono> 7#include <chrono>
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/settings.h"
9#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
10#include "core/hle/service/set/set.h" 11#include "core/hle/service/set/set.h"
11#include "core/settings.h"
12 12
13namespace Service::Set { 13namespace Service::Set {
14namespace { 14namespace {
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index b58b2c8c5..5909fdd85 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -261,6 +261,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
261 {155, nullptr, "SetAccountOnlineStorageSettings"}, 261 {155, nullptr, "SetAccountOnlineStorageSettings"},
262 {156, nullptr, "GetPctlReadyFlag"}, 262 {156, nullptr, "GetPctlReadyFlag"},
263 {157, nullptr, "SetPctlReadyFlag"}, 263 {157, nullptr, "SetPctlReadyFlag"},
264 {158, nullptr, "GetAnalogStickUserCalibrationL"},
265 {159, nullptr, "SetAnalogStickUserCalibrationL"},
266 {160, nullptr, "GetAnalogStickUserCalibrationR"},
267 {161, nullptr, "SetAnalogStickUserCalibrationR"},
264 {162, nullptr, "GetPtmBatteryVersion"}, 268 {162, nullptr, "GetPtmBatteryVersion"},
265 {163, nullptr, "SetPtmBatteryVersion"}, 269 {163, nullptr, "SetPtmBatteryVersion"},
266 {164, nullptr, "GetUsb30HostEnableFlag"}, 270 {164, nullptr, "GetUsb30HostEnableFlag"},
@@ -302,6 +306,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
302 {200, nullptr, "SetButtonConfigRegisteredSettings"}, 306 {200, nullptr, "SetButtonConfigRegisteredSettings"},
303 {201, nullptr, "GetFieldTestingFlag"}, 307 {201, nullptr, "GetFieldTestingFlag"},
304 {202, nullptr, "SetFieldTestingFlag"}, 308 {202, nullptr, "SetFieldTestingFlag"},
309 {203, nullptr, "GetPanelCrcMode"},
310 {204, nullptr, "SetPanelCrcMode"},
305 }; 311 };
306 // clang-format on 312 // clang-format on
307 313
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 2b91a89d1..94608d529 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -190,10 +190,11 @@ SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_)
190 : ServiceFramework{system_, "sm:", 4}, 190 : ServiceFramework{system_, "sm:", 4},
191 service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { 191 service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} {
192 static const FunctionInfo functions[] = { 192 static const FunctionInfo functions[] = {
193 {0x00000000, &SM::Initialize, "Initialize"}, 193 {0, &SM::Initialize, "Initialize"},
194 {0x00000001, &SM::GetService, "GetService"}, 194 {1, &SM::GetService, "GetService"},
195 {0x00000002, &SM::RegisterService, "RegisterService"}, 195 {2, &SM::RegisterService, "RegisterService"},
196 {0x00000003, &SM::UnregisterService, "UnregisterService"}, 196 {3, &SM::UnregisterService, "UnregisterService"},
197 {4, nullptr, "DetachClient"},
197 }; 198 };
198 RegisterHandlers(functions); 199 RegisterHandlers(functions);
199} 200}
diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp
index 05681ca2d..899a64c2f 100644
--- a/src/core/hle/service/sockets/ethc.cpp
+++ b/src/core/hle/service/sockets/ethc.cpp
@@ -15,6 +15,7 @@ ETHC_C::ETHC_C(Core::System& system_) : ServiceFramework{system_, "ethc:c"} {
15 {3, nullptr, "GetMediaList"}, 15 {3, nullptr, "GetMediaList"},
16 {4, nullptr, "SetMediaType"}, 16 {4, nullptr, "SetMediaType"},
17 {5, nullptr, "GetMediaType"}, 17 {5, nullptr, "GetMediaType"},
18 {6, nullptr, "Unknown6"},
18 }; 19 };
19 // clang-format on 20 // clang-format on
20 21
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index 51c3739bb..1159debc5 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -9,6 +9,7 @@ namespace Service::Sockets {
9NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { 9NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {5, nullptr, "GetSettingUrl"},
12 {10, nullptr, "GetSettingName"}, 13 {10, nullptr, "GetSettingName"},
13 {11, nullptr, "GetEnvironmentIdentifier"}, 14 {11, nullptr, "GetEnvironmentIdentifier"},
14 {12, nullptr, "GetDeviceId"}, 15 {12, nullptr, "GetDeviceId"},
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 3a6329f56..5c71f423c 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -9,8 +9,8 @@ namespace Service::Sockets {
9 9
10SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} { 10SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} {
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "SetDnsAddressesPrivate"}, 12 {0, nullptr, "SetDnsAddressesPrivateRequest"},
13 {1, nullptr, "GetDnsAddressPrivate"}, 13 {1, nullptr, "GetDnsAddressPrivateRequest"},
14 {2, nullptr, "GetHostByNameRequest"}, 14 {2, nullptr, "GetHostByNameRequest"},
15 {3, nullptr, "GetHostByAddrRequest"}, 15 {3, nullptr, "GetHostByAddrRequest"},
16 {4, nullptr, "GetHostStringErrorRequest"}, 16 {4, nullptr, "GetHostStringErrorRequest"},
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 6903dd534..b1552c3f0 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -9,11 +9,11 @@
9#include <functional> 9#include <functional>
10#include <vector> 10#include <vector>
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/settings.h"
12#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
13#include "core/hle/service/spl/csrng.h" 14#include "core/hle/service/spl/csrng.h"
14#include "core/hle/service/spl/module.h" 15#include "core/hle/service/spl/module.h"
15#include "core/hle/service/spl/spl.h" 16#include "core/hle/service/spl/spl.h"
16#include "core/settings.h"
17 17
18namespace Service::SPL { 18namespace Service::SPL {
19 19
diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp
index 4e212610f..fff3f3c42 100644
--- a/src/core/hle/service/spl/spl.cpp
+++ b/src/core/hle/service/spl/spl.cpp
@@ -60,6 +60,8 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
60 {4, nullptr, "GenerateAesKey"}, 60 {4, nullptr, "GenerateAesKey"},
61 {5, nullptr, "SetConfig"}, 61 {5, nullptr, "SetConfig"},
62 {7, &SPL::GetRandomBytes, "GenerateRandomBytes"}, 62 {7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
63 {9, nullptr, "ImportLotusKey"},
64 {10, nullptr, "DecryptLotusMessage"},
63 {11, nullptr, "IsDevelopment"}, 65 {11, nullptr, "IsDevelopment"},
64 {12, nullptr, "GenerateSpecificAesKey"}, 66 {12, nullptr, "GenerateSpecificAesKey"},
65 {14, nullptr, "DecryptAesKey"}, 67 {14, nullptr, "DecryptAesKey"},
@@ -123,6 +125,7 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
123 {14, nullptr, "DecryptAesKey"}, 125 {14, nullptr, "DecryptAesKey"},
124 {15, nullptr, "CryptAesCtr"}, 126 {15, nullptr, "CryptAesCtr"},
125 {16, nullptr, "ComputeCmac"}, 127 {16, nullptr, "ComputeCmac"},
128 {17, nullptr, "ImportEsKey"},
126 {18, nullptr, "UnwrapTitleKey"}, 129 {18, nullptr, "UnwrapTitleKey"},
127 {20, nullptr, "PrepareEsCommonKey"}, 130 {20, nullptr, "PrepareEsCommonKey"},
128 {21, nullptr, "AllocateAesKeyslot"}, 131 {21, nullptr, "AllocateAesKeyslot"},
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h
index b78892223..a9cfe3eb0 100644
--- a/src/core/hle/service/time/clock_types.h
+++ b/src/core/hle/service/time/clock_types.h
@@ -12,6 +12,12 @@
12 12
13namespace Service::Time::Clock { 13namespace Service::Time::Clock {
14 14
15enum class TimeType : u8 {
16 UserSystemClock,
17 NetworkSystemClock,
18 LocalSystemClock,
19};
20
15/// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint 21/// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint
16struct SteadyClockTimePoint { 22struct SteadyClockTimePoint {
17 s64 time_point; 23 s64 time_point;
@@ -84,7 +90,7 @@ struct ClockSnapshot {
84 SteadyClockTimePoint steady_clock_time_point; 90 SteadyClockTimePoint steady_clock_time_point;
85 TimeZone::LocationName location_name; 91 TimeZone::LocationName location_name;
86 u8 is_automatic_correction_enabled; 92 u8 is_automatic_correction_enabled;
87 u8 type; 93 TimeType type;
88 INSERT_PADDING_BYTES_NOINIT(0x2); 94 INSERT_PADDING_BYTES_NOINIT(0x2);
89 95
90 static ResultCode GetCurrentTime(s64& current_time, 96 static ResultCode GetCurrentTime(s64& current_time,
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 78543688f..63e0247de 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -122,14 +122,16 @@ private:
122 122
123ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal( 123ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
124 Kernel::KThread* 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, Clock::TimeType type,
126 Clock::ClockSnapshot& clock_snapshot) {
126 127
127 auto& time_manager{system.GetTimeManager()}; 128 auto& time_manager{system.GetTimeManager()};
128 129
130 clock_snapshot.steady_clock_time_point =
131 time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system);
129 clock_snapshot.is_automatic_correction_enabled = 132 clock_snapshot.is_automatic_correction_enabled =
130 time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); 133 time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
131 clock_snapshot.user_context = user_context; 134 clock_snapshot.type = type;
132 clock_snapshot.network_context = network_context;
133 135
134 if (const ResultCode result{ 136 if (const ResultCode result{
135 time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName( 137 time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName(
@@ -138,12 +140,11 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
138 return result; 140 return result;
139 } 141 }
140 142
141 const auto current_time_point{ 143 clock_snapshot.user_context = user_context;
142 time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
143 clock_snapshot.steady_clock_time_point = current_time_point;
144 144
145 if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime( 145 if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime(
146 clock_snapshot.user_time, current_time_point, clock_snapshot.user_context)}; 146 clock_snapshot.user_time, clock_snapshot.steady_clock_time_point,
147 clock_snapshot.user_context)};
147 result != RESULT_SUCCESS) { 148 result != RESULT_SUCCESS) {
148 return result; 149 return result;
149 } 150 }
@@ -157,9 +158,12 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
157 } 158 }
158 159
159 clock_snapshot.user_calendar_time = userCalendarInfo.time; 160 clock_snapshot.user_calendar_time = userCalendarInfo.time;
160 clock_snapshot.user_calendar_additional_time = userCalendarInfo.additiona_info; 161 clock_snapshot.user_calendar_additional_time = userCalendarInfo.additional_info;
162
163 clock_snapshot.network_context = network_context;
161 164
162 if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time, current_time_point, 165 if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time,
166 clock_snapshot.steady_clock_time_point,
163 clock_snapshot.network_context) != RESULT_SUCCESS) { 167 clock_snapshot.network_context) != RESULT_SUCCESS) {
164 clock_snapshot.network_time = 0; 168 clock_snapshot.network_time = 0;
165 } 169 }
@@ -173,8 +177,7 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
173 } 177 }
174 178
175 clock_snapshot.network_calendar_time = networkCalendarInfo.time; 179 clock_snapshot.network_calendar_time = networkCalendarInfo.time;
176 clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additiona_info; 180 clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additional_info;
177 clock_snapshot.type = type;
178 181
179 return RESULT_SUCCESS; 182 return RESULT_SUCCESS;
180} 183}
@@ -257,9 +260,10 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe
257} 260}
258 261
259void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { 262void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
260 LOG_DEBUG(Service_Time, "called");
261 IPC::RequestParser rp{ctx}; 263 IPC::RequestParser rp{ctx};
262 const auto type{rp.PopRaw<u8>()}; 264 const auto type{rp.PopEnum<Clock::TimeType>()};
265
266 LOG_DEBUG(Service_Time, "called, type={}", type);
263 267
264 Clock::SystemClockContext user_context{}; 268 Clock::SystemClockContext user_context{};
265 if (const ResultCode result{ 269 if (const ResultCode result{
@@ -270,6 +274,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
270 rb.Push(result); 274 rb.Push(result);
271 return; 275 return;
272 } 276 }
277
273 Clock::SystemClockContext network_context{}; 278 Clock::SystemClockContext network_context{};
274 if (const ResultCode result{ 279 if (const ResultCode result{
275 system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( 280 system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
@@ -295,14 +300,16 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
295} 300}
296 301
297void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) { 302void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
298 LOG_DEBUG(Service_Time, "called");
299 IPC::RequestParser rp{ctx}; 303 IPC::RequestParser rp{ctx};
300 const auto type{rp.PopRaw<u8>()}; 304 const auto type{rp.PopEnum<Clock::TimeType>()};
305
301 rp.AlignWithPadding(); 306 rp.AlignWithPadding();
302 307
303 const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()}; 308 const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()};
304 const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()}; 309 const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()};
305 310
311 LOG_DEBUG(Service_Time, "called, type={}", type);
312
306 Clock::ClockSnapshot clock_snapshot{}; 313 Clock::ClockSnapshot clock_snapshot{};
307 if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal( 314 if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal(
308 &ctx.GetThread(), user_context, network_context, type, clock_snapshot)}; 315 &ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
@@ -321,9 +328,14 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
321 Kernel::HLERequestContext& ctx) { 328 Kernel::HLERequestContext& ctx) {
322 LOG_DEBUG(Service_Time, "called"); 329 LOG_DEBUG(Service_Time, "called");
323 330
324 IPC::RequestParser rp{ctx}; 331 Clock::ClockSnapshot snapshot_a;
325 const auto snapshot_a = rp.PopRaw<Clock::ClockSnapshot>(); 332 Clock::ClockSnapshot snapshot_b;
326 const auto snapshot_b = rp.PopRaw<Clock::ClockSnapshot>(); 333
334 const auto snapshot_a_data = ctx.ReadBuffer(0);
335 const auto snapshot_b_data = ctx.ReadBuffer(1);
336
337 std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot));
338 std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot));
327 339
328 auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset - 340 auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset -
329 snapshot_a.user_context.offset)}; 341 snapshot_a.user_context.offset)};
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 4154c7ee9..ce9c479c6 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -40,7 +40,7 @@ public:
40 private: 40 private:
41 ResultCode GetClockSnapshotFromSystemClockContextInternal( 41 ResultCode GetClockSnapshotFromSystemClockContextInternal(
42 Kernel::KThread* 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, Clock::TimeType type,
44 Clock::ClockSnapshot& cloc_snapshot); 44 Clock::ClockSnapshot& cloc_snapshot);
45 45
46 protected: 46 protected:
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index 1f7309f6b..f89c5aaad 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -5,12 +5,12 @@
5#include <chrono> 5#include <chrono>
6#include <ctime> 6#include <ctime>
7 7
8#include "common/settings.h"
8#include "common/time_zone.h" 9#include "common/time_zone.h"
9#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h" 10#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h"
10#include "core/hle/service/time/local_system_clock_context_writer.h" 11#include "core/hle/service/time/local_system_clock_context_writer.h"
11#include "core/hle/service/time/network_system_clock_context_writer.h" 12#include "core/hle/service/time/network_system_clock_context_writer.h"
12#include "core/hle/service/time/time_manager.h" 13#include "core/hle/service/time/time_manager.h"
13#include "core/settings.h"
14 14
15namespace Service::Time { 15namespace Service::Time {
16 16
@@ -44,7 +44,11 @@ struct TimeManager::Impl final {
44 const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())}; 44 const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
45 SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {}); 45 SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
46 SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); 46 SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
47 SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy); 47
48 Clock::SystemClockContext clock_context{};
49 standard_local_system_clock_core.GetClockContext(system, clock_context);
50
51 SetupStandardNetworkSystemClock(clock_context, standard_network_clock_accuracy);
48 SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom()); 52 SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
49 SetupEphemeralNetworkSystemClock(); 53 SetupEphemeralNetworkSystemClock();
50 } 54 }
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
index 4177d0a41..3c8e71a3c 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -5,6 +5,7 @@
5#include <sstream> 5#include <sstream>
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/settings.h"
8#include "common/time_zone.h" 9#include "common/time_zone.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
@@ -15,7 +16,6 @@
15#include "core/hle/service/filesystem/filesystem.h" 16#include "core/hle/service/filesystem/filesystem.h"
16#include "core/hle/service/time/time_manager.h" 17#include "core/hle/service/time/time_manager.h"
17#include "core/hle/service/time/time_zone_content_manager.h" 18#include "core/hle/service/time/time_zone_content_manager.h"
18#include "core/settings.h"
19 19
20namespace Service::Time::TimeZone { 20namespace Service::Time::TimeZone {
21 21
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index bdf0439f2..3032ca193 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -818,7 +818,7 @@ static ResultCode ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time,
818static ResultCode ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) { 818static ResultCode ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) {
819 CalendarTimeInternal calendar_time{}; 819 CalendarTimeInternal calendar_time{};
820 const ResultCode result{ 820 const ResultCode result{
821 ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)}; 821 ToCalendarTimeInternal(rules, time, calendar_time, calendar.additional_info)};
822 calendar.time.year = static_cast<s16>(calendar_time.year); 822 calendar.time.year = static_cast<s16>(calendar_time.year);
823 823
824 // Internal impl. uses 0-indexed month 824 // Internal impl. uses 0-indexed month
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
index 25cecbc83..3117627cf 100644
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -20,6 +20,7 @@ ITimeZoneService ::ITimeZoneService(Core::System& system_,
20 {3, nullptr, "LoadLocationNameList"}, 20 {3, nullptr, "LoadLocationNameList"},
21 {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, 21 {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
22 {5, nullptr, "GetTimeZoneRuleVersion"}, 22 {5, nullptr, "GetTimeZoneRuleVersion"},
23 {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
23 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, 24 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
24 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, 25 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
25 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, 26 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
diff --git a/src/core/hle/service/time/time_zone_types.h b/src/core/hle/service/time/time_zone_types.h
index 4a57e036d..d39103253 100644
--- a/src/core/hle/service/time/time_zone_types.h
+++ b/src/core/hle/service/time/time_zone_types.h
@@ -66,8 +66,8 @@ struct CalendarTime {
66static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size"); 66static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size");
67 67
68struct CalendarInfo { 68struct CalendarInfo {
69 CalendarTime time{}; 69 CalendarTime time;
70 CalendarAdditionalInfo additiona_info{}; 70 CalendarAdditionalInfo additional_info;
71}; 71};
72static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size"); 72static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size");
73 73
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index 579de83e4..b3b230a8c 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -69,15 +69,15 @@ public:
69 : ServiceFramework{system_, "IClientEpSession"} { 69 : ServiceFramework{system_, "IClientEpSession"} {
70 // clang-format off 70 // clang-format off
71 static const FunctionInfo functions[] = { 71 static const FunctionInfo functions[] = {
72 {0, nullptr, "Open"}, 72 {0, nullptr, "ReOpen"},
73 {1, nullptr, "Close"}, 73 {1, nullptr, "Close"},
74 {2, nullptr, "Unknown2"}, 74 {2, nullptr, "GetCompletionEvent"},
75 {3, nullptr, "Populate"}, 75 {3, nullptr, "PopulateRing"},
76 {4, nullptr, "PostBufferAsync"}, 76 {4, nullptr, "PostBufferAsync"},
77 {5, nullptr, "GetXferReport"}, 77 {5, nullptr, "GetXferReport"},
78 {6, nullptr, "PostBufferMultiAsync"}, 78 {6, nullptr, "PostBufferMultiAsync"},
79 {7, nullptr, "Unknown7"}, 79 {7, nullptr, "CreateSmmuSpace"},
80 {8, nullptr, "Unknown8"}, 80 {8, nullptr, "ShareReportRing"},
81 }; 81 };
82 // clang-format on 82 // clang-format on
83 83
@@ -91,7 +91,7 @@ public:
91 : ServiceFramework{system_, "IClientIfSession"} { 91 : ServiceFramework{system_, "IClientIfSession"} {
92 // clang-format off 92 // clang-format off
93 static const FunctionInfo functions[] = { 93 static const FunctionInfo functions[] = {
94 {0, nullptr, "Unknown0"}, 94 {0, nullptr, "GetStateChangeEvent"},
95 {1, nullptr, "SetInterface"}, 95 {1, nullptr, "SetInterface"},
96 {2, nullptr, "GetInterface"}, 96 {2, nullptr, "GetInterface"},
97 {3, nullptr, "GetAlternateInterface"}, 97 {3, nullptr, "GetAlternateInterface"},
@@ -176,15 +176,15 @@ public:
176 : ServiceFramework{system_, "IPdCradleSession"} { 176 : ServiceFramework{system_, "IPdCradleSession"} {
177 // clang-format off 177 // clang-format off
178 static const FunctionInfo functions[] = { 178 static const FunctionInfo functions[] = {
179 {0, nullptr, "VdmUserWrite"}, 179 {0, nullptr, "SetCradleVdo"},
180 {1, nullptr, "VdmUserRead"}, 180 {1, nullptr, "GetCradleVdo"},
181 {2, nullptr, "Vdm20Init"}, 181 {2, nullptr, "ResetCradleUsbHub"},
182 {3, nullptr, "GetFwType"}, 182 {3, nullptr, "GetHostPdcFirmwareType"},
183 {4, nullptr, "GetFwRevision"}, 183 {4, nullptr, "GetHostPdcFirmwareRevision"},
184 {5, nullptr, "GetManufacturerId"}, 184 {5, nullptr, "GetHostPdcManufactureId"},
185 {6, nullptr, "GetDeviceId"}, 185 {6, nullptr, "GetHostPdcDeviceId"},
186 {7, nullptr, "Unknown7"}, 186 {7, nullptr, "AwakeCradle"},
187 {8, nullptr, "Unknown8"}, 187 {8, nullptr, "SleepCradle"},
188 }; 188 };
189 // clang-format on 189 // clang-format on
190 190
@@ -219,12 +219,12 @@ public:
219 explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} { 219 explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} {
220 // clang-format off 220 // clang-format off
221 static const FunctionInfo functions[] = { 221 static const FunctionInfo functions[] = {
222 {0, nullptr, "Unknown0"}, 222 {0, nullptr, "GetPowerEvent"},
223 {1, nullptr, "Unknown1"}, 223 {1, nullptr, "GetPowerState"},
224 {2, nullptr, "Unknown2"}, 224 {2, nullptr, "GetDataEvent"},
225 {3, nullptr, "Unknown3"}, 225 {3, nullptr, "GetDataRole"},
226 {4, nullptr, "Unknown4"}, 226 {4, nullptr, "SetDiagData"},
227 {5, nullptr, "Unknown5"}, 227 {5, nullptr, "GetDiagData"},
228 }; 228 };
229 // clang-format on 229 // clang-format on
230 230
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 7423287ea..348360b51 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -15,6 +15,7 @@
15#include "common/common_funcs.h" 15#include "common/common_funcs.h"
16#include "common/logging/log.h" 16#include "common/logging/log.h"
17#include "common/math_util.h" 17#include "common/math_util.h"
18#include "common/settings.h"
18#include "common/swap.h" 19#include "common/swap.h"
19#include "core/core_timing.h" 20#include "core/core_timing.h"
20#include "core/hle/ipc_helpers.h" 21#include "core/hle/ipc_helpers.h"
@@ -30,7 +31,6 @@
30#include "core/hle/service/vi/vi_m.h" 31#include "core/hle/service/vi/vi_m.h"
31#include "core/hle/service/vi/vi_s.h" 32#include "core/hle/service/vi/vi_s.h"
32#include "core/hle/service/vi/vi_u.h" 33#include "core/hle/service/vi/vi_u.h"
33#include "core/settings.h"
34 34
35namespace Service::VI { 35namespace Service::VI {
36 36
@@ -695,6 +695,7 @@ public:
695 {2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"}, 695 {2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
696 {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"}, 696 {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"},
697 {2209, nullptr, "SetLayerAlpha"}, 697 {2209, nullptr, "SetLayerAlpha"},
698 {2210, nullptr, "SetLayerPositionAndSize"},
698 {2312, nullptr, "CreateStrayLayer"}, 699 {2312, nullptr, "CreateStrayLayer"},
699 {2400, nullptr, "OpenIndirectLayer"}, 700 {2400, nullptr, "OpenIndirectLayer"},
700 {2401, nullptr, "CloseIndirectLayer"}, 701 {2401, nullptr, "CloseIndirectLayer"},
@@ -718,6 +719,7 @@ public:
718 {3215, nullptr, "SetDisplayGamma"}, 719 {3215, nullptr, "SetDisplayGamma"},
719 {3216, nullptr, "GetDisplayCmuLuma"}, 720 {3216, nullptr, "GetDisplayCmuLuma"},
720 {3217, nullptr, "SetDisplayCmuLuma"}, 721 {3217, nullptr, "SetDisplayCmuLuma"},
722 {3218, nullptr, "SetDisplayCrcMode"},
721 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"}, 723 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
722 {8225, nullptr, "GetSharedBufferMemoryHandleId"}, 724 {8225, nullptr, "GetSharedBufferMemoryHandleId"},
723 {8250, nullptr, "OpenSharedLayer"}, 725 {8250, nullptr, "OpenSharedLayer"},
@@ -729,6 +731,7 @@ public:
729 {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"}, 731 {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
730 {8257, nullptr, "FillSharedFrameBufferColor"}, 732 {8257, nullptr, "FillSharedFrameBufferColor"},
731 {8258, nullptr, "CancelSharedFrameBuffer"}, 733 {8258, nullptr, "CancelSharedFrameBuffer"},
734 {9000, nullptr, "GetDp2hdmiController"},
732 }; 735 };
733 RegisterHandlers(functions); 736 RegisterHandlers(functions);
734 } 737 }
@@ -808,10 +811,15 @@ public:
808 {2402, nullptr, "GetDisplayHotplugState"}, 811 {2402, nullptr, "GetDisplayHotplugState"},
809 {2501, nullptr, "GetCompositorErrorInfo"}, 812 {2501, nullptr, "GetCompositorErrorInfo"},
810 {2601, nullptr, "GetDisplayErrorEvent"}, 813 {2601, nullptr, "GetDisplayErrorEvent"},
814 {2701, nullptr, "GetDisplayFatalErrorEvent"},
811 {4201, nullptr, "SetDisplayAlpha"}, 815 {4201, nullptr, "SetDisplayAlpha"},
812 {4203, nullptr, "SetDisplayLayerStack"}, 816 {4203, nullptr, "SetDisplayLayerStack"},
813 {4205, nullptr, "SetDisplayPowerState"}, 817 {4205, nullptr, "SetDisplayPowerState"},
814 {4206, nullptr, "SetDefaultDisplay"}, 818 {4206, nullptr, "SetDefaultDisplay"},
819 {4207, nullptr, "ResetDisplayPanel"},
820 {4208, nullptr, "SetDisplayFatalErrorEnabled"},
821 {4209, nullptr, "IsDisplayPanelOn"},
822 {4300, nullptr, "GetInternalPanelId"},
815 {6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"}, 823 {6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
816 {6001, nullptr, "RemoveFromLayerStack"}, 824 {6001, nullptr, "RemoveFromLayerStack"},
817 {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"}, 825 {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"},
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp
index ddbf04069..44957e01d 100644
--- a/src/core/hle/service/wlan/wlan.cpp
+++ b/src/core/hle/service/wlan/wlan.cpp
@@ -46,6 +46,13 @@ public:
46 {28, nullptr, "Unknown28"}, 46 {28, nullptr, "Unknown28"},
47 {29, nullptr, "Unknown29"}, 47 {29, nullptr, "Unknown29"},
48 {30, nullptr, "Unknown30"}, 48 {30, nullptr, "Unknown30"},
49 {31, nullptr, "Unknown31"},
50 {32, nullptr, "Unknown32"},
51 {33, nullptr, "Unknown33"},
52 {34, nullptr, "Unknown34"},
53 {35, nullptr, "Unknown35"},
54 {36, nullptr, "Unknown36"},
55 {37, nullptr, "Unknown37"},
49 }; 56 };
50 // clang-format on 57 // clang-format on
51 58
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 14618cb40..0115ed0c4 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -9,6 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/settings.h"
12#include "common/swap.h" 13#include "common/swap.h"
13#include "core/core.h" 14#include "core/core.h"
14#include "core/file_sys/control_metadata.h" 15#include "core/file_sys/control_metadata.h"
@@ -22,7 +23,6 @@
22#include "core/loader/nro.h" 23#include "core/loader/nro.h"
23#include "core/loader/nso.h" 24#include "core/loader/nso.h"
24#include "core/memory.h" 25#include "core/memory.h"
25#include "core/settings.h"
26 26
27namespace Loader { 27namespace Loader {
28 28
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index cbd048695..0c83dd666 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -11,6 +11,7 @@
11#include "common/hex_util.h" 11#include "common/hex_util.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/lz4_compression.h" 13#include "common/lz4_compression.h"
14#include "common/settings.h"
14#include "common/swap.h" 15#include "common/swap.h"
15#include "core/core.h" 16#include "core/core.h"
16#include "core/file_sys/patch_manager.h" 17#include "core/file_sys/patch_manager.h"
@@ -20,7 +21,6 @@
20#include "core/hle/kernel/process.h" 21#include "core/hle/kernel/process.h"
21#include "core/loader/nso.h" 22#include "core/loader/nso.h"
22#include "core/memory.h" 23#include "core/memory.h"
23#include "core/settings.h"
24 24
25namespace Loader { 25namespace Loader {
26namespace { 26namespace {
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index b93396a80..c92337079 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -13,8 +13,8 @@
13#include <fmt/format.h> 13#include <fmt/format.h>
14#include "common/file_util.h" 14#include "common/file_util.h"
15#include "common/math_util.h" 15#include "common/math_util.h"
16#include "common/settings.h"
16#include "core/perf_stats.h" 17#include "core/perf_stats.h"
17#include "core/settings.h"
18 18
19using namespace std::chrono_literals; 19using namespace std::chrono_literals;
20using DoubleSecs = std::chrono::duration<double, std::chrono::seconds::period>; 20using DoubleSecs = std::chrono::duration<double, std::chrono::seconds::period>;
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 74fb32814..311d4dda8 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -14,6 +14,7 @@
14#include "common/file_util.h" 14#include "common/file_util.h"
15#include "common/hex_util.h" 15#include "common/hex_util.h"
16#include "common/scm_rev.h" 16#include "common/scm_rev.h"
17#include "common/settings.h"
17#include "core/arm/arm_interface.h" 18#include "core/arm/arm_interface.h"
18#include "core/core.h" 19#include "core/core.h"
19#include "core/hle/kernel/hle_ipc.h" 20#include "core/hle/kernel/hle_ipc.h"
@@ -22,7 +23,6 @@
22#include "core/hle/result.h" 23#include "core/hle/result.h"
23#include "core/memory.h" 24#include "core/memory.h"
24#include "core/reporter.h" 25#include "core/reporter.h"
25#include "core/settings.h"
26 26
27namespace { 27namespace {
28 28
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index d11b15f38..6dcff5400 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -12,10 +12,10 @@
12#include "common/file_util.h" 12#include "common/file_util.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14 14
15#include "common/settings.h"
15#include "core/file_sys/control_metadata.h" 16#include "core/file_sys/control_metadata.h"
16#include "core/file_sys/patch_manager.h" 17#include "core/file_sys/patch_manager.h"
17#include "core/loader/loader.h" 18#include "core/loader/loader.h"
18#include "core/settings.h"
19#include "core/telemetry_session.h" 19#include "core/telemetry_session.h"
20 20
21#ifdef ENABLE_WEB_SERVICE 21#ifdef ENABLE_WEB_SERVICE
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 38ab31898..c3cfe7efc 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -9,8 +9,6 @@ add_library(input_common STATIC
9 motion_from_button.h 9 motion_from_button.h
10 motion_input.cpp 10 motion_input.cpp
11 motion_input.h 11 motion_input.h
12 settings.cpp
13 settings.h
14 touch_from_button.cpp 12 touch_from_button.cpp
15 touch_from_button.h 13 touch_from_button.h
16 gcadapter/gc_adapter.cpp 14 gcadapter/gc_adapter.cpp
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp
index 770893687..f8ec179d0 100755
--- a/src/input_common/analog_from_button.cpp
+++ b/src/input_common/analog_from_button.cpp
@@ -7,7 +7,7 @@
7#include <cmath> 7#include <cmath>
8#include <thread> 8#include <thread>
9#include "common/math_util.h" 9#include "common/math_util.h"
10#include "core/settings.h" 10#include "common/settings.h"
11#include "input_common/analog_from_button.h" 11#include "input_common/analog_from_button.h"
12 12
13namespace InputCommon { 13namespace InputCommon {
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index d80195c82..ec3167bea 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -16,8 +16,8 @@
16 16
17#include "common/logging/log.h" 17#include "common/logging/log.h"
18#include "common/param_package.h" 18#include "common/param_package.h"
19#include "common/settings_input.h"
19#include "input_common/gcadapter/gc_adapter.h" 20#include "input_common/gcadapter/gc_adapter.h"
20#include "input_common/settings.h"
21 21
22namespace GCAdapter { 22namespace GCAdapter {
23 23
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp
index 329e416c7..fff1c6b45 100644
--- a/src/input_common/mouse/mouse_input.cpp
+++ b/src/input_common/mouse/mouse_input.cpp
@@ -2,7 +2,7 @@
2// Licensed under GPLv2+ 2// Licensed under GPLv2+
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/settings.h" 5#include "common/settings.h"
6#include "input_common/mouse/mouse_input.h" 6#include "input_common/mouse/mouse_input.h"
7 7
8namespace MouseInput { 8namespace MouseInput {
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index 0e1db54fb..d96104a4e 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -5,8 +5,8 @@
5#include <mutex> 5#include <mutex>
6#include <utility> 6#include <utility>
7 7
8#include "common/settings.h"
8#include "common/threadsafe_queue.h" 9#include "common/threadsafe_queue.h"
9#include "core/settings.h"
10#include "input_common/mouse/mouse_input.h" 10#include "input_common/mouse/mouse_input.h"
11#include "input_common/mouse/mouse_poller.h" 11#include "input_common/mouse/mouse_poller.h"
12 12
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index f67de37e3..9418e78fa 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -20,11 +20,11 @@
20#include <SDL.h> 20#include <SDL.h>
21#include "common/logging/log.h" 21#include "common/logging/log.h"
22#include "common/param_package.h" 22#include "common/param_package.h"
23#include "common/settings_input.h"
23#include "common/threadsafe_queue.h" 24#include "common/threadsafe_queue.h"
24#include "core/frontend/input.h" 25#include "core/frontend/input.h"
25#include "input_common/motion_input.h" 26#include "input_common/motion_input.h"
26#include "input_common/sdl/sdl_impl.h" 27#include "input_common/sdl/sdl_impl.h"
27#include "input_common/settings.h"
28 28
29namespace InputCommon::SDL { 29namespace InputCommon::SDL {
30 30
@@ -761,7 +761,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
761 for (const auto& joystick : value) { 761 for (const auto& joystick : value) {
762 if (auto* const controller = joystick->GetSDLGameController()) { 762 if (auto* const controller = joystick->GetSDLGameController()) {
763 std::string name = 763 std::string name =
764 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort()); 764 fmt::format("{} {}", GetControllerName(controller), joystick->GetPort());
765 devices.emplace_back(Common::ParamPackage{ 765 devices.emplace_back(Common::ParamPackage{
766 {"class", "sdl"}, 766 {"class", "sdl"},
767 {"display", std::move(name)}, 767 {"display", std::move(name)},
@@ -782,6 +782,17 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
782 return devices; 782 return devices;
783} 783}
784 784
785std::string SDLState::GetControllerName(SDL_GameController* controller) const {
786 switch (SDL_GameControllerGetType(controller)) {
787 case SDL_CONTROLLER_TYPE_XBOX360:
788 return "XBox 360 Controller";
789 case SDL_CONTROLLER_TYPE_XBOXONE:
790 return "XBox One Controller";
791 default:
792 return SDL_GameControllerName(controller);
793 }
794}
795
785namespace { 796namespace {
786Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, 797Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
787 float value = 0.1f) { 798 float value = 0.1f) {
@@ -930,16 +941,19 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa
930 return {}; 941 return {};
931 } 942 }
932 943
944 const bool invert =
945 SDL_GameControllerGetType(controller) != SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
946
933 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. 947 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
934 // We will add those afterwards 948 // We will add those afterwards
935 // This list also excludes Screenshot since theres not really a mapping for that 949 // This list also excludes Screenshot since theres not really a mapping for that
936 using ButtonBindings = 950 using ButtonBindings =
937 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; 951 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
938 static constexpr ButtonBindings switch_to_sdl_button{{ 952 const ButtonBindings switch_to_sdl_button{{
939 {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, 953 {Settings::NativeButton::A, invert ? SDL_CONTROLLER_BUTTON_B : SDL_CONTROLLER_BUTTON_A},
940 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, 954 {Settings::NativeButton::B, invert ? SDL_CONTROLLER_BUTTON_A : SDL_CONTROLLER_BUTTON_B},
941 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, 955 {Settings::NativeButton::X, invert ? SDL_CONTROLLER_BUTTON_Y : SDL_CONTROLLER_BUTTON_X},
942 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, 956 {Settings::NativeButton::Y, invert ? SDL_CONTROLLER_BUTTON_X : SDL_CONTROLLER_BUTTON_Y},
943 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, 957 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
944 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, 958 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
945 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, 959 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index 08044b00d..8b7363f56 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -14,6 +14,7 @@
14#include "input_common/sdl/sdl.h" 14#include "input_common/sdl/sdl.h"
15 15
16union SDL_Event; 16union SDL_Event;
17using SDL_GameController = struct _SDL_GameController;
17using SDL_Joystick = struct _SDL_Joystick; 18using SDL_Joystick = struct _SDL_Joystick;
18using SDL_JoystickID = s32; 19using SDL_JoystickID = s32;
19 20
@@ -64,6 +65,9 @@ private:
64 /// Needs to be called before SDL_QuitSubSystem. 65 /// Needs to be called before SDL_QuitSubSystem.
65 void CloseJoysticks(); 66 void CloseJoysticks();
66 67
68 /// Returns a custom name for specific controllers because the default name is not correct
69 std::string GetControllerName(SDL_GameController* controller) const;
70
67 // Set to true if SDL supports game controller subsystem 71 // Set to true if SDL supports game controller subsystem
68 bool has_gamecontroller = false; 72 bool has_gamecontroller = false;
69 73
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp
index ffbe4f2ed..e94ba197b 100644
--- a/src/input_common/touch_from_button.cpp
+++ b/src/input_common/touch_from_button.cpp
@@ -2,8 +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#include "common/settings.h"
5#include "core/frontend/framebuffer_layout.h" 6#include "core/frontend/framebuffer_layout.h"
6#include "core/settings.h"
7#include "input_common/touch_from_button.h" 7#include "input_common/touch_from_button.h"
8 8
9namespace InputCommon { 9namespace InputCommon {
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index df73f9ff7..8a38a380d 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -9,7 +9,7 @@
9#include <thread> 9#include <thread>
10#include <boost/asio.hpp> 10#include <boost/asio.hpp>
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/settings.h" 12#include "common/settings.h"
13#include "input_common/udp/client.h" 13#include "input_common/udp/client.h"
14#include "input_common/udp/protocol.h" 14#include "input_common/udp/protocol.h"
15 15
@@ -27,11 +27,9 @@ class Socket {
27public: 27public:
28 using clock = std::chrono::system_clock; 28 using clock = std::chrono::system_clock;
29 29
30 explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, 30 explicit Socket(const std::string& host, u16 port, SocketCallback callback_)
31 SocketCallback callback_)
32 : callback(std::move(callback_)), timer(io_service), 31 : callback(std::move(callback_)), timer(io_service),
33 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()), 32 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) {
34 pad_index(pad_index_) {
35 boost::system::error_code ec{}; 33 boost::system::error_code ec{};
36 auto ipv4 = boost::asio::ip::make_address_v4(host, ec); 34 auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
37 if (ec.value() != boost::system::errc::success) { 35 if (ec.value() != boost::system::errc::success) {
@@ -99,15 +97,15 @@ private:
99 void HandleSend(const boost::system::error_code&) { 97 void HandleSend(const boost::system::error_code&) {
100 boost::system::error_code _ignored{}; 98 boost::system::error_code _ignored{};
101 // Send a request for getting port info for the pad 99 // Send a request for getting port info for the pad
102 const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}}; 100 const Request::PortInfo port_info{4, {0, 1, 2, 3}};
103 const auto port_message = Request::Create(port_info, client_id); 101 const auto port_message = Request::Create(port_info, client_id);
104 std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); 102 std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);
105 socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); 103 socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);
106 104
107 // Send a request for getting pad data for the pad 105 // Send a request for getting pad data for the pad
108 const Request::PadData pad_data{ 106 const Request::PadData pad_data{
109 Request::PadData::Flags::Id, 107 Request::PadData::Flags::AllPorts,
110 static_cast<u8>(pad_index), 108 0,
111 EMPTY_MAC_ADDRESS, 109 EMPTY_MAC_ADDRESS,
112 }; 110 };
113 const auto pad_message = Request::Create(pad_data, client_id); 111 const auto pad_message = Request::Create(pad_data, client_id);
@@ -122,7 +120,6 @@ private:
122 udp::socket socket; 120 udp::socket socket;
123 121
124 const u32 client_id; 122 const u32 client_id;
125 std::size_t pad_index{};
126 123
127 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); 124 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
128 static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>); 125 static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>);
@@ -150,34 +147,32 @@ Client::~Client() {
150 Reset(); 147 Reset();
151} 148}
152 149
153Client::ClientData::ClientData() = default; 150Client::ClientConnection::ClientConnection() = default;
154 151
155Client::ClientData::~ClientData() = default; 152Client::ClientConnection::~ClientConnection() = default;
156 153
157std::vector<Common::ParamPackage> Client::GetInputDevices() const { 154std::vector<Common::ParamPackage> Client::GetInputDevices() const {
158 std::vector<Common::ParamPackage> devices; 155 std::vector<Common::ParamPackage> devices;
159 for (std::size_t client = 0; client < clients.size(); client++) { 156 for (std::size_t pad = 0; pad < pads.size(); pad++) {
160 if (!DeviceConnected(client)) { 157 if (!DeviceConnected(pad)) {
161 continue; 158 continue;
162 } 159 }
163 std::string name = fmt::format("UDP Controller {}", client); 160 std::string name = fmt::format("UDP Controller {}", pad);
164 devices.emplace_back(Common::ParamPackage{ 161 devices.emplace_back(Common::ParamPackage{
165 {"class", "cemuhookudp"}, 162 {"class", "cemuhookudp"},
166 {"display", std::move(name)}, 163 {"display", std::move(name)},
167 {"port", std::to_string(client)}, 164 {"port", std::to_string(pad)},
168 }); 165 });
169 } 166 }
170 return devices; 167 return devices;
171} 168}
172 169
173bool Client::DeviceConnected(std::size_t client) const { 170bool Client::DeviceConnected(std::size_t pad) const {
174 // Use last timestamp to detect if the socket has stopped sending data 171 // Use last timestamp to detect if the socket has stopped sending data
175 const auto now = std::chrono::steady_clock::now(); 172 const auto now = std::chrono::steady_clock::now();
176 const auto time_difference = 173 const auto time_difference = static_cast<u64>(
177 static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>( 174 std::chrono::duration_cast<std::chrono::milliseconds>(now - pads[pad].last_update).count());
178 now - clients[client].last_motion_update) 175 return time_difference < 1000 && pads[pad].connected;
179 .count());
180 return time_difference < 1000 && clients[client].active == 1;
181} 176}
182 177
183void Client::ReloadSockets() { 178void Client::ReloadSockets() {
@@ -202,25 +197,21 @@ void Client::ReloadSockets() {
202 continue; 197 continue;
203 } 198 }
204 199
205 for (std::size_t pad = 0; pad < 4; ++pad) { 200 const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port);
206 const std::size_t client_number = 201 if (client_number != MAX_UDP_CLIENTS) {
207 GetClientNumber(udp_input_address, udp_input_port, pad); 202 LOG_ERROR(Input, "Duplicated UDP servers found");
208 if (client_number != MAX_UDP_CLIENTS) { 203 continue;
209 LOG_ERROR(Input, "Duplicated UDP servers found");
210 continue;
211 }
212 StartCommunication(client++, udp_input_address, udp_input_port, pad);
213 } 204 }
205 StartCommunication(client++, udp_input_address, udp_input_port);
214 } 206 }
215} 207}
216 208
217std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const { 209std::size_t Client::GetClientNumber(std::string_view host, u16 port) const {
218 for (std::size_t client = 0; client < clients.size(); client++) { 210 for (std::size_t client = 0; client < clients.size(); client++) {
219 if (clients[client].active == -1) { 211 if (clients[client].active == -1) {
220 continue; 212 continue;
221 } 213 }
222 if (clients[client].host == host && clients[client].port == port && 214 if (clients[client].host == host && clients[client].port == port) {
223 clients[client].pad_index == pad) {
224 return client; 215 return client;
225 } 216 }
226 } 217 }
@@ -236,69 +227,75 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) {
236} 227}
237 228
238void Client::OnPadData(Response::PadData data, std::size_t client) { 229void Client::OnPadData(Response::PadData data, std::size_t client) {
239 // Accept packets only for the correct pad 230 const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id;
240 if (static_cast<u8>(clients[client].pad_index) != data.info.id) { 231
232 if (pad_index >= pads.size()) {
233 LOG_ERROR(Input, "Invalid pad id {}", data.info.id);
241 return; 234 return;
242 } 235 }
243 236
244 LOG_TRACE(Input, "PadData packet received"); 237 LOG_TRACE(Input, "PadData packet received");
245 if (data.packet_counter == clients[client].packet_sequence) { 238 if (data.packet_counter == pads[pad_index].packet_sequence) {
246 LOG_WARNING( 239 LOG_WARNING(
247 Input, 240 Input,
248 "PadData packet dropped because its stale info. Current count: {} Packet count: {}", 241 "PadData packet dropped because its stale info. Current count: {} Packet count: {}",
249 clients[client].packet_sequence, data.packet_counter); 242 pads[pad_index].packet_sequence, data.packet_counter);
243 pads[pad_index].connected = false;
250 return; 244 return;
251 } 245 }
252 clients[client].active = static_cast<s8>(data.info.is_pad_active); 246
253 clients[client].packet_sequence = data.packet_counter; 247 clients[client].active = 1;
248 pads[pad_index].connected = true;
249 pads[pad_index].packet_sequence = data.packet_counter;
250
254 const auto now = std::chrono::steady_clock::now(); 251 const auto now = std::chrono::steady_clock::now();
255 const auto time_difference = 252 const auto time_difference = static_cast<u64>(
256 static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>( 253 std::chrono::duration_cast<std::chrono::microseconds>(now - pads[pad_index].last_update)
257 now - clients[client].last_motion_update) 254 .count());
258 .count()); 255 pads[pad_index].last_update = now;
259 clients[client].last_motion_update = now; 256
260 const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; 257 const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw};
261 clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); 258 pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
262 // Gyroscope values are not it the correct scale from better joy. 259 // Gyroscope values are not it the correct scale from better joy.
263 // Dividing by 312 allows us to make one full turn = 1 turn 260 // Dividing by 312 allows us to make one full turn = 1 turn
264 // This must be a configurable valued called sensitivity 261 // This must be a configurable valued called sensitivity
265 clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f); 262 pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f);
266 clients[client].motion.UpdateRotation(time_difference); 263 pads[pad_index].motion.UpdateRotation(time_difference);
267 clients[client].motion.UpdateOrientation(time_difference); 264 pads[pad_index].motion.UpdateOrientation(time_difference);
268 265
269 { 266 {
270 std::lock_guard guard(clients[client].status.update_mutex); 267 std::lock_guard guard(pads[pad_index].status.update_mutex);
271 clients[client].status.motion_status = clients[client].motion.GetMotion(); 268 pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion();
272 269
273 for (std::size_t id = 0; id < data.touch.size(); ++id) { 270 for (std::size_t id = 0; id < data.touch.size(); ++id) {
274 UpdateTouchInput(data.touch[id], client, id); 271 UpdateTouchInput(data.touch[id], client, id);
275 } 272 }
276 273
277 if (configuring) { 274 if (configuring) {
278 const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); 275 const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope();
279 const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); 276 const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration();
280 UpdateYuzuSettings(client, accelerometer, gyroscope); 277 UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope);
281 } 278 }
282 } 279 }
283} 280}
284 281
285void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, 282void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) {
286 std::size_t pad_index) {
287 SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, 283 SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
288 [this](Response::PortInfo info) { OnPortInfo(info); }, 284 [this](Response::PortInfo info) { OnPortInfo(info); },
289 [this, client](Response::PadData data) { OnPadData(data, client); }}; 285 [this, client](Response::PadData data) { OnPadData(data, client); }};
290 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port, 286 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
291 pad_index);
292 clients[client].host = host; 287 clients[client].host = host;
293 clients[client].port = port; 288 clients[client].port = port;
294 clients[client].pad_index = pad_index;
295 clients[client].active = 0; 289 clients[client].active = 0;
296 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback); 290 clients[client].socket = std::make_unique<Socket>(host, port, callback);
297 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; 291 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
292
298 // Set motion parameters 293 // Set motion parameters
299 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode 294 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
300 // Real HW values are unknown, 0.0001 is an approximate to Standard 295 // Real HW values are unknown, 0.0001 is an approximate to Standard
301 clients[client].motion.SetGyroThreshold(0.0001f); 296 for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) {
297 pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f);
298 }
302} 299}
303 300
304void Client::Reset() { 301void Client::Reset() {
@@ -311,8 +308,8 @@ void Client::Reset() {
311 } 308 }
312} 309}
313 310
314void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 311void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
315 const Common::Vec3<float>& gyro) { 312 const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro) {
316 if (gyro.Length() > 0.2f) { 313 if (gyro.Length() > 0.2f) {
317 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, 314 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client,
318 gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); 315 gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]);
@@ -320,7 +317,7 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a
320 UDPPadStatus pad{ 317 UDPPadStatus pad{
321 .host = clients[client].host, 318 .host = clients[client].host,
322 .port = clients[client].port, 319 .port = clients[client].port,
323 .pad_index = clients[client].pad_index, 320 .pad_index = pad_index,
324 }; 321 };
325 for (std::size_t i = 0; i < 3; ++i) { 322 for (std::size_t i = 0; i < 3; ++i) {
326 if (gyro[i] > 5.0f || gyro[i] < -5.0f) { 323 if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
@@ -391,19 +388,19 @@ void Client::EndConfiguration() {
391} 388}
392 389
393DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { 390DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) {
394 const std::size_t client_number = GetClientNumber(host, port, pad); 391 const std::size_t client_number = GetClientNumber(host, port);
395 if (client_number == MAX_UDP_CLIENTS) { 392 if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) {
396 return clients[0].status; 393 return pads[0].status;
397 } 394 }
398 return clients[client_number].status; 395 return pads[(client_number * PADS_PER_CLIENT) + pad].status;
399} 396}
400 397
401const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { 398const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const {
402 const std::size_t client_number = GetClientNumber(host, port, pad); 399 const std::size_t client_number = GetClientNumber(host, port);
403 if (client_number == MAX_UDP_CLIENTS) { 400 if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) {
404 return clients[0].status; 401 return pads[0].status;
405 } 402 }
406 return clients[client_number].status; 403 return pads[(client_number * PADS_PER_CLIENT) + pad].status;
407} 404}
408 405
409Input::TouchStatus& Client::GetTouchState() { 406Input::TouchStatus& Client::GetTouchState() {
@@ -422,7 +419,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
422 return pad_queue; 419 return pad_queue;
423} 420}
424 421
425void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, 422void TestCommunication(const std::string& host, u16 port,
426 const std::function<void()>& success_callback, 423 const std::function<void()>& success_callback,
427 const std::function<void()>& failure_callback) { 424 const std::function<void()>& failure_callback) {
428 std::thread([=] { 425 std::thread([=] {
@@ -432,9 +429,10 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
432 .port_info = [](Response::PortInfo) {}, 429 .port_info = [](Response::PortInfo) {},
433 .pad_data = [&](Response::PadData) { success_event.Set(); }, 430 .pad_data = [&](Response::PadData) { success_event.Set(); },
434 }; 431 };
435 Socket socket{host, port, pad_index, std::move(callback)}; 432 Socket socket{host, port, std::move(callback)};
436 std::thread worker_thread{SocketLoop, &socket}; 433 std::thread worker_thread{SocketLoop, &socket};
437 const bool result = success_event.WaitFor(std::chrono::seconds(5)); 434 const bool result =
435 success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10));
438 socket.Stop(); 436 socket.Stop();
439 worker_thread.join(); 437 worker_thread.join();
440 if (result) { 438 if (result) {
@@ -446,8 +444,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
446} 444}
447 445
448CalibrationConfigurationJob::CalibrationConfigurationJob( 446CalibrationConfigurationJob::CalibrationConfigurationJob(
449 const std::string& host, u16 port, std::size_t pad_index, 447 const std::string& host, u16 port, std::function<void(Status)> status_callback,
450 std::function<void(Status)> status_callback,
451 std::function<void(u16, u16, u16, u16)> data_callback) { 448 std::function<void(u16, u16, u16, u16)> data_callback) {
452 449
453 std::thread([=, this] { 450 std::thread([=, this] {
@@ -491,7 +488,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
491 complete_event.Set(); 488 complete_event.Set();
492 } 489 }
493 }}; 490 }};
494 Socket socket{host, port, pad_index, std::move(callback)}; 491 Socket socket{host, port, std::move(callback)};
495 std::thread worker_thread{SocketLoop, &socket}; 492 std::thread worker_thread{SocketLoop, &socket};
496 complete_event.Wait(); 493 complete_event.Wait();
497 socket.Stop(); 494 socket.Stop();
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index e9e438e88..a11ea3068 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -84,7 +84,7 @@ public:
84 84
85 std::vector<Common::ParamPackage> GetInputDevices() const; 85 std::vector<Common::ParamPackage> GetInputDevices() const;
86 86
87 bool DeviceConnected(std::size_t client) const; 87 bool DeviceConnected(std::size_t pad) const;
88 void ReloadSockets(); 88 void ReloadSockets();
89 89
90 Common::SPSCQueue<UDPPadStatus>& GetPadQueue(); 90 Common::SPSCQueue<UDPPadStatus>& GetPadQueue();
@@ -97,38 +97,40 @@ public:
97 const Input::TouchStatus& GetTouchState() const; 97 const Input::TouchStatus& GetTouchState() const;
98 98
99private: 99private:
100 struct ClientData { 100 struct PadData {
101 ClientData();
102 ~ClientData();
103
104 std::string host{"127.0.0.1"};
105 u16 port{26760};
106 std::size_t pad_index{}; 101 std::size_t pad_index{};
107 std::unique_ptr<Socket> socket; 102 bool connected{};
108 DeviceStatus status; 103 DeviceStatus status;
109 std::thread thread;
110 u64 packet_sequence{}; 104 u64 packet_sequence{};
111 s8 active{-1};
112 105
113 // Realtime values 106 // Realtime values
114 // motion is initalized with PID values for drift correction on joycons 107 // motion is initalized with PID values for drift correction on joycons
115 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; 108 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f};
116 std::chrono::time_point<std::chrono::steady_clock> last_motion_update; 109 std::chrono::time_point<std::chrono::steady_clock> last_update;
110 };
111
112 struct ClientConnection {
113 ClientConnection();
114 ~ClientConnection();
115 std::string host{"127.0.0.1"};
116 u16 port{26760};
117 s8 active{-1};
118 std::unique_ptr<Socket> socket;
119 std::thread thread;
117 }; 120 };
118 121
119 // For shutting down, clear all data, join all threads, release usb 122 // For shutting down, clear all data, join all threads, release usb
120 void Reset(); 123 void Reset();
121 124
122 // Translates configuration to client number 125 // Translates configuration to client number
123 std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const; 126 std::size_t GetClientNumber(std::string_view host, u16 port) const;
124 127
125 void OnVersion(Response::Version); 128 void OnVersion(Response::Version);
126 void OnPortInfo(Response::PortInfo); 129 void OnPortInfo(Response::PortInfo);
127 void OnPadData(Response::PadData, std::size_t client); 130 void OnPadData(Response::PadData, std::size_t client);
128 void StartCommunication(std::size_t client, const std::string& host, u16 port, 131 void StartCommunication(std::size_t client, const std::string& host, u16 port);
129 std::size_t pad_index); 132 void UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
130 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 133 const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro);
131 const Common::Vec3<float>& gyro);
132 134
133 // Returns an unused finger id, if there is no fingers available std::nullopt will be 135 // Returns an unused finger id, if there is no fingers available std::nullopt will be
134 // returned 136 // returned
@@ -140,10 +142,12 @@ private:
140 bool configuring = false; 142 bool configuring = false;
141 143
142 // Allocate clients for 8 udp servers 144 // Allocate clients for 8 udp servers
143 static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8; 145 static constexpr std::size_t MAX_UDP_CLIENTS = 8;
146 static constexpr std::size_t PADS_PER_CLIENT = 4;
144 // Each client can have up 2 touch inputs 147 // Each client can have up 2 touch inputs
145 static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; 148 static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2;
146 std::array<ClientData, MAX_UDP_CLIENTS> clients{}; 149 std::array<PadData, MAX_UDP_CLIENTS * PADS_PER_CLIENT> pads{};
150 std::array<ClientConnection, MAX_UDP_CLIENTS> clients{};
147 Common::SPSCQueue<UDPPadStatus> pad_queue{}; 151 Common::SPSCQueue<UDPPadStatus> pad_queue{};
148 Input::TouchStatus touch_status{}; 152 Input::TouchStatus touch_status{};
149 std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{}; 153 std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{};
@@ -164,7 +168,7 @@ public:
164 * @param status_callback Callback for job status updates 168 * @param status_callback Callback for job status updates
165 * @param data_callback Called when calibration data is ready 169 * @param data_callback Called when calibration data is ready
166 */ 170 */
167 explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, 171 explicit CalibrationConfigurationJob(const std::string& host, u16 port,
168 std::function<void(Status)> status_callback, 172 std::function<void(Status)> status_callback,
169 std::function<void(u16, u16, u16, u16)> data_callback); 173 std::function<void(u16, u16, u16, u16)> data_callback);
170 ~CalibrationConfigurationJob(); 174 ~CalibrationConfigurationJob();
@@ -174,7 +178,7 @@ private:
174 Common::Event complete_event; 178 Common::Event complete_event;
175}; 179};
176 180
177void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, 181void TestCommunication(const std::string& host, u16 port,
178 const std::function<void()>& success_callback, 182 const std::function<void()>& success_callback,
179 const std::function<void()>& failure_callback); 183 const std::function<void()>& failure_callback);
180 184
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 9b931976a..47190c464 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -236,7 +236,6 @@ add_library(video_core STATIC
236 texture_cache/types.h 236 texture_cache/types.h
237 texture_cache/util.cpp 237 texture_cache/util.cpp
238 texture_cache/util.h 238 texture_cache/util.h
239 textures/astc.cpp
240 textures/astc.h 239 textures/astc.h
241 textures/decoders.cpp 240 textures/decoders.cpp
242 textures/decoders.h 241 textures/decoders.h
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 4de1e37e5..32dcbd693 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -20,8 +20,8 @@
20#include "common/div_ceil.h" 20#include "common/div_ceil.h"
21#include "common/microprofile.h" 21#include "common/microprofile.h"
22#include "common/scope_exit.h" 22#include "common/scope_exit.h"
23#include "common/settings.h"
23#include "core/memory.h" 24#include "core/memory.h"
24#include "core/settings.h"
25#include "video_core/buffer_cache/buffer_base.h" 25#include "video_core/buffer_cache/buffer_base.h"
26#include "video_core/delayed_destruction_ring.h" 26#include "video_core/delayed_destruction_ring.h"
27#include "video_core/dirty_flags.h" 27#include "video_core/dirty_flags.h"
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index 59e586695..29bb31418 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -2,8 +2,9 @@
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 <cstring> // for std::memcpy 5#include <algorithm> // for std::copy
6#include <numeric> 6#include <numeric>
7#include "common/assert.h"
7#include "video_core/command_classes/codecs/vp9.h" 8#include "video_core/command_classes/codecs/vp9.h"
8#include "video_core/gpu.h" 9#include "video_core/gpu.h"
9#include "video_core/memory_manager.h" 10#include "video_core/memory_manager.h"
@@ -362,7 +363,8 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state)
362 // surface_luma_offset[0:3] contains the address of the reference frame offsets in the following 363 // surface_luma_offset[0:3] contains the address of the reference frame offsets in the following
363 // order: last, golden, altref, current. It may be worthwhile to track the updates done here 364 // order: last, golden, altref, current. It may be worthwhile to track the updates done here
364 // to avoid buffering frame data needed for reference frame updating in the header composition. 365 // to avoid buffering frame data needed for reference frame updating in the header composition.
365 std::memcpy(vp9_info.frame_offsets.data(), state.surface_luma_offset.data(), 4 * sizeof(u64)); 366 std::copy(state.surface_luma_offset.begin(), state.surface_luma_offset.begin() + 4,
367 vp9_info.frame_offsets.begin());
366 368
367 return vp9_info; 369 return vp9_info;
368} 370}
@@ -821,11 +823,11 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
821 823
822 // Write headers and frame to buffer 824 // Write headers and frame to buffer
823 frame.resize(uncompressed_header.size() + compressed_header.size() + bitstream.size()); 825 frame.resize(uncompressed_header.size() + compressed_header.size() + bitstream.size());
824 std::memcpy(frame.data(), uncompressed_header.data(), uncompressed_header.size()); 826 std::copy(uncompressed_header.begin(), uncompressed_header.end(), frame.begin());
825 std::memcpy(frame.data() + uncompressed_header.size(), compressed_header.data(), 827 std::copy(compressed_header.begin(), compressed_header.end(),
826 compressed_header.size()); 828 frame.begin() + uncompressed_header.size());
827 std::memcpy(frame.data() + uncompressed_header.size() + compressed_header.size(), 829 std::copy(bitstream.begin(), bitstream.end(),
828 bitstream.data(), bitstream.size()); 830 frame.begin() + uncompressed_header.size() + compressed_header.size());
829 831
830 // keep track of frame number 832 // keep track of frame number
831 current_frame_number++; 833 current_frame_number++;
diff --git a/src/video_core/engines/engine_interface.h b/src/video_core/engines/engine_interface.h
index 18a9db7e6..c7ffd68c5 100644
--- a/src/video_core/engines/engine_interface.h
+++ b/src/video_core/engines/engine_interface.h
@@ -4,13 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <type_traits>
8#include "common/common_types.h" 7#include "common/common_types.h"
9 8
10namespace Tegra::Engines { 9namespace Tegra::Engines {
11 10
12class EngineInterface { 11class EngineInterface {
13public: 12public:
13 virtual ~EngineInterface() = default;
14
14 /// Write the value to the register identified by method. 15 /// Write the value to the register identified by method.
15 virtual void CallMethod(u32 method, u32 method_argument, bool is_last_call) = 0; 16 virtual void CallMethod(u32 method, u32 method_argument, bool is_last_call) = 0;
16 17
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index c808a577d..a4170ffff 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -35,7 +35,7 @@ namespace Tegra::Engines {
35class Fermi2D final : public EngineInterface { 35class Fermi2D final : public EngineInterface {
36public: 36public:
37 explicit Fermi2D(); 37 explicit Fermi2D();
38 ~Fermi2D(); 38 ~Fermi2D() override;
39 39
40 /// Binds a rasterizer to this engine. 40 /// Binds a rasterizer to this engine.
41 void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); 41 void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
index 19808a5c6..0d8ea09a9 100644
--- a/src/video_core/engines/kepler_memory.h
+++ b/src/video_core/engines/kepler_memory.h
@@ -36,7 +36,7 @@ namespace Tegra::Engines {
36class KeplerMemory final : public EngineInterface { 36class KeplerMemory final : public EngineInterface {
37public: 37public:
38 explicit KeplerMemory(Core::System& system_, MemoryManager& memory_manager); 38 explicit KeplerMemory(Core::System& system_, MemoryManager& memory_manager);
39 ~KeplerMemory(); 39 ~KeplerMemory() override;
40 40
41 /// Write the value to the register identified by method. 41 /// Write the value to the register identified by method.
42 void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; 42 void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index a2f19559f..2ee980bab 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -4,8 +4,8 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "common/settings.h"
7#include "core/core.h" 8#include "core/core.h"
8#include "core/settings.h"
9#include "video_core/engines/maxwell_3d.h" 9#include "video_core/engines/maxwell_3d.h"
10#include "video_core/engines/maxwell_dma.h" 10#include "video_core/engines/maxwell_dma.h"
11#include "video_core/memory_manager.h" 11#include "video_core/memory_manager.h"
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index 3c59eeb13..c77f02a22 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -188,7 +188,7 @@ public:
188 static_assert(sizeof(RemapConst) == 12); 188 static_assert(sizeof(RemapConst) == 12);
189 189
190 explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_); 190 explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_);
191 ~MaxwellDMA(); 191 ~MaxwellDMA() override;
192 192
193 /// Write the value to the register identified by method. 193 /// Write the value to the register identified by method.
194 void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; 194 void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 36c31fec2..7c42f1177 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -6,13 +6,13 @@
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/microprofile.h" 8#include "common/microprofile.h"
9#include "common/settings.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/core_timing.h" 11#include "core/core_timing.h"
11#include "core/core_timing_util.h" 12#include "core/core_timing_util.h"
12#include "core/frontend/emu_window.h" 13#include "core/frontend/emu_window.h"
13#include "core/hardware_interrupt_manager.h" 14#include "core/hardware_interrupt_manager.h"
14#include "core/memory.h" 15#include "core/memory.h"
15#include "core/settings.h"
16#include "video_core/engines/fermi_2d.h" 16#include "video_core/engines/fermi_2d.h"
17#include "video_core/engines/kepler_compute.h" 17#include "video_core/engines/kepler_compute.h"
18#include "video_core/engines/kepler_memory.h" 18#include "video_core/engines/kepler_memory.h"
@@ -519,8 +519,8 @@ void GPU::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const {
519 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value); 519 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
520} 520}
521 521
522void GPU::WaitIdle() const { 522void GPU::ShutDown() {
523 gpu_thread.WaitIdle(); 523 gpu_thread.ShutDown();
524} 524}
525 525
526void GPU::OnCommandListEnd() { 526void GPU::OnCommandListEnd() {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index d40982a54..b1960ea86 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -219,8 +219,8 @@ public:
219 return *shader_notify; 219 return *shader_notify;
220 } 220 }
221 221
222 // Waits for the GPU to finish working 222 // Stops the GPU execution and waits for the GPU to finish working
223 void WaitIdle() const; 223 void ShutDown();
224 224
225 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame. 225 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame.
226 void WaitFence(u32 syncpoint_id, u32 value); 226 void WaitFence(u32 syncpoint_id, u32 value);
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 99353f15f..cd1fbb9bf 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -5,10 +5,10 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/microprofile.h" 6#include "common/microprofile.h"
7#include "common/scope_exit.h" 7#include "common/scope_exit.h"
8#include "common/settings.h"
8#include "common/thread.h" 9#include "common/thread.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/frontend/emu_window.h" 11#include "core/frontend/emu_window.h"
11#include "core/settings.h"
12#include "video_core/dma_pusher.h" 12#include "video_core/dma_pusher.h"
13#include "video_core/gpu.h" 13#include "video_core/gpu.h"
14#include "video_core/gpu_thread.h" 14#include "video_core/gpu_thread.h"
@@ -29,8 +29,7 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
29 system.RegisterHostThread(); 29 system.RegisterHostThread();
30 30
31 // Wait for first GPU command before acquiring the window context 31 // Wait for first GPU command before acquiring the window context
32 while (state.queue.Empty()) 32 state.queue.Wait();
33 ;
34 33
35 // If emulation was stopped during disk shader loading, abort before trying to acquire context 34 // If emulation was stopped during disk shader loading, abort before trying to acquire context
36 if (!state.is_running) { 35 if (!state.is_running) {
@@ -57,11 +56,17 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
57 } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) { 56 } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
58 rasterizer->OnCPUWrite(invalidate->addr, invalidate->size); 57 rasterizer->OnCPUWrite(invalidate->addr, invalidate->size);
59 } else if (std::holds_alternative<EndProcessingCommand>(next.data)) { 58 } else if (std::holds_alternative<EndProcessingCommand>(next.data)) {
60 return; 59 ASSERT(state.is_running == false);
61 } else { 60 } else {
62 UNREACHABLE(); 61 UNREACHABLE();
63 } 62 }
64 state.signaled_fence.store(next.fence); 63 state.signaled_fence.store(next.fence);
64 if (next.block) {
65 // We have to lock the write_lock to ensure that the condition_variable wait not get a
66 // race between the check and the lock itself.
67 std::lock_guard lk(state.write_lock);
68 state.cv.notify_all();
69 }
65 } 70 }
66} 71}
67 72
@@ -69,13 +74,7 @@ ThreadManager::ThreadManager(Core::System& system_, bool is_async_)
69 : system{system_}, is_async{is_async_} {} 74 : system{system_}, is_async{is_async_} {}
70 75
71ThreadManager::~ThreadManager() { 76ThreadManager::~ThreadManager() {
72 if (!thread.joinable()) { 77 ShutDown();
73 return;
74 }
75
76 // Notify GPU thread that a shutdown is pending
77 PushCommand(EndProcessingCommand());
78 thread.join();
79} 78}
80 79
81void ThreadManager::StartThread(VideoCore::RendererBase& renderer, 80void ThreadManager::StartThread(VideoCore::RendererBase& renderer,
@@ -112,9 +111,8 @@ void ThreadManager::FlushRegion(VAddr addr, u64 size) {
112 case Settings::GPUAccuracy::Extreme: { 111 case Settings::GPUAccuracy::Extreme: {
113 auto& gpu = system.GPU(); 112 auto& gpu = system.GPU();
114 u64 fence = gpu.RequestFlush(addr, size); 113 u64 fence = gpu.RequestFlush(addr, size);
115 PushCommand(GPUTickCommand()); 114 PushCommand(GPUTickCommand(), true);
116 while (fence > gpu.CurrentFlushRequestFence()) { 115 ASSERT(fence <= gpu.CurrentFlushRequestFence());
117 }
118 break; 116 break;
119 } 117 }
120 default: 118 default:
@@ -131,23 +129,45 @@ void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) {
131 rasterizer->OnCPUWrite(addr, size); 129 rasterizer->OnCPUWrite(addr, size);
132} 130}
133 131
134void ThreadManager::WaitIdle() const { 132void ThreadManager::ShutDown() {
135 while (state.last_fence > state.signaled_fence.load(std::memory_order_relaxed) && 133 if (!state.is_running) {
136 system.IsPoweredOn()) { 134 return;
137 } 135 }
136
137 {
138 std::lock_guard lk(state.write_lock);
139 state.is_running = false;
140 state.cv.notify_all();
141 }
142
143 if (!thread.joinable()) {
144 return;
145 }
146
147 // Notify GPU thread that a shutdown is pending
148 PushCommand(EndProcessingCommand());
149 thread.join();
138} 150}
139 151
140void ThreadManager::OnCommandListEnd() { 152void ThreadManager::OnCommandListEnd() {
141 PushCommand(OnCommandListEndCommand()); 153 PushCommand(OnCommandListEndCommand());
142} 154}
143 155
144u64 ThreadManager::PushCommand(CommandData&& command_data) { 156u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
145 const u64 fence{++state.last_fence};
146 state.queue.Push(CommandDataContainer(std::move(command_data), fence));
147
148 if (!is_async) { 157 if (!is_async) {
149 // In synchronous GPU mode, block the caller until the command has executed 158 // In synchronous GPU mode, block the caller until the command has executed
150 WaitIdle(); 159 block = true;
160 }
161
162 std::unique_lock lk(state.write_lock);
163 const u64 fence{++state.last_fence};
164 state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));
165
166 if (block) {
167 state.cv.wait(lk, [this, fence] {
168 return fence <= state.signaled_fence.load(std::memory_order_relaxed) ||
169 !state.is_running;
170 });
151 } 171 }
152 172
153 return fence; 173 return fence;
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 18269e51c..11a648f38 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -90,21 +90,24 @@ using CommandData =
90struct CommandDataContainer { 90struct CommandDataContainer {
91 CommandDataContainer() = default; 91 CommandDataContainer() = default;
92 92
93 explicit CommandDataContainer(CommandData&& data_, u64 next_fence_) 93 explicit CommandDataContainer(CommandData&& data_, u64 next_fence_, bool block_)
94 : data{std::move(data_)}, fence{next_fence_} {} 94 : data{std::move(data_)}, fence{next_fence_}, block(block_) {}
95 95
96 CommandData data; 96 CommandData data;
97 u64 fence{}; 97 u64 fence{};
98 bool block{};
98}; 99};
99 100
100/// Struct used to synchronize the GPU thread 101/// Struct used to synchronize the GPU thread
101struct SynchState final { 102struct SynchState final {
102 std::atomic_bool is_running{true}; 103 std::atomic_bool is_running{true};
103 104
104 using CommandQueue = Common::MPSCQueue<CommandDataContainer>; 105 using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
106 std::mutex write_lock;
105 CommandQueue queue; 107 CommandQueue queue;
106 u64 last_fence{}; 108 u64 last_fence{};
107 std::atomic<u64> signaled_fence{}; 109 std::atomic<u64> signaled_fence{};
110 std::condition_variable cv;
108}; 111};
109 112
110/// Class used to manage the GPU thread 113/// Class used to manage the GPU thread
@@ -132,14 +135,14 @@ public:
132 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 135 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
133 void FlushAndInvalidateRegion(VAddr addr, u64 size); 136 void FlushAndInvalidateRegion(VAddr addr, u64 size);
134 137
135 // Wait until the gpu thread is idle. 138 // Stops the GPU execution and waits for the GPU to finish working
136 void WaitIdle() const; 139 void ShutDown();
137 140
138 void OnCommandListEnd(); 141 void OnCommandListEnd();
139 142
140private: 143private:
141 /// Pushes a command to be executed by the GPU thread 144 /// Pushes a command to be executed by the GPU thread
142 u64 PushCommand(CommandData&& command_data); 145 u64 PushCommand(CommandData&& command_data, bool block = false);
143 146
144 Core::System& system; 147 Core::System& system;
145 const bool is_async; 148 const bool is_async;
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index 3494318ca..2208e1922 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -1,4 +1,5 @@
1set(SHADER_FILES 1set(SHADER_FILES
2 astc_decoder.comp
2 block_linear_unswizzle_2d.comp 3 block_linear_unswizzle_2d.comp
3 block_linear_unswizzle_3d.comp 4 block_linear_unswizzle_3d.comp
4 convert_depth_to_float.frag 5 convert_depth_to_float.frag
diff --git a/src/video_core/host_shaders/StringShaderHeader.cmake b/src/video_core/host_shaders/StringShaderHeader.cmake
index c0fc49768..1b4bc6103 100644
--- a/src/video_core/host_shaders/StringShaderHeader.cmake
+++ b/src/video_core/host_shaders/StringShaderHeader.cmake
@@ -6,7 +6,27 @@ get_filename_component(CONTENTS_NAME ${SOURCE_FILE} NAME)
6string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME}) 6string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME})
7string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME) 7string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
8 8
9file(READ ${SOURCE_FILE} CONTENTS) 9FILE(READ ${SOURCE_FILE} line_contents)
10
11# Replace double quotes with single quotes,
12# as double quotes will be used to wrap the lines
13STRING(REGEX REPLACE "\"" "'" line_contents "${line_contents}")
14
15# CMake separates list elements with semicolons, but semicolons
16# are used extensively in the shader code.
17# Replace with a temporary marker, to be reverted later.
18STRING(REGEX REPLACE ";" "{{SEMICOLON}}" line_contents "${line_contents}")
19
20# Make every line an individual element in the CMake list.
21STRING(REGEX REPLACE "\n" ";" line_contents "${line_contents}")
22
23# Build the shader string, wrapping each line in double quotes.
24foreach(line IN LISTS line_contents)
25 string(CONCAT CONTENTS "${CONTENTS}" \"${line}\\n\"\n)
26endforeach()
27
28# Revert the original semicolons in the source.
29STRING(REGEX REPLACE "{{SEMICOLON}}" ";" CONTENTS "${CONTENTS}")
10 30
11get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY) 31get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY)
12make_directory(${OUTPUT_DIR}) 32make_directory(${OUTPUT_DIR})
diff --git a/src/video_core/host_shaders/astc_decoder.comp b/src/video_core/host_shaders/astc_decoder.comp
new file mode 100644
index 000000000..703e34587
--- /dev/null
+++ b/src/video_core/host_shaders/astc_decoder.comp
@@ -0,0 +1,1339 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 450
6
7#ifdef VULKAN
8
9#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
10#define END_PUSH_CONSTANTS };
11#define UNIFORM(n)
12#define BINDING_INPUT_BUFFER 0
13#define BINDING_ENC_BUFFER 1
14#define BINDING_6_TO_8_BUFFER 2
15#define BINDING_7_TO_8_BUFFER 3
16#define BINDING_8_TO_8_BUFFER 4
17#define BINDING_BYTE_TO_16_BUFFER 5
18#define BINDING_SWIZZLE_BUFFER 6
19#define BINDING_OUTPUT_IMAGE 7
20
21#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
22
23#define BEGIN_PUSH_CONSTANTS
24#define END_PUSH_CONSTANTS
25#define UNIFORM(n) layout(location = n) uniform
26#define BINDING_SWIZZLE_BUFFER 0
27#define BINDING_INPUT_BUFFER 1
28#define BINDING_ENC_BUFFER 2
29#define BINDING_6_TO_8_BUFFER 3
30#define BINDING_7_TO_8_BUFFER 4
31#define BINDING_8_TO_8_BUFFER 5
32#define BINDING_BYTE_TO_16_BUFFER 6
33#define BINDING_OUTPUT_IMAGE 0
34
35#endif
36
37layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
38
39BEGIN_PUSH_CONSTANTS
40UNIFORM(1) uvec2 block_dims;
41
42UNIFORM(2) uint bytes_per_block_log2;
43UNIFORM(3) uint layer_stride;
44UNIFORM(4) uint block_size;
45UNIFORM(5) uint x_shift;
46UNIFORM(6) uint block_height;
47UNIFORM(7) uint block_height_mask;
48END_PUSH_CONSTANTS
49
50struct EncodingData {
51 uint encoding;
52 uint num_bits;
53 uint bit_value;
54 uint quint_trit_value;
55};
56
57struct TexelWeightParams {
58 uvec2 size;
59 uint max_weight;
60 bool dual_plane;
61 bool error_state;
62 bool void_extent_ldr;
63 bool void_extent_hdr;
64};
65
66// Swizzle data
67layout(binding = BINDING_SWIZZLE_BUFFER, std430) readonly buffer SwizzleTable {
68 uint swizzle_table[];
69};
70
71layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 {
72 uint astc_data[];
73};
74
75// ASTC Encodings data
76layout(binding = BINDING_ENC_BUFFER, std430) readonly buffer EncodingsValues {
77 EncodingData encoding_values[];
78};
79// ASTC Precompiled tables
80layout(binding = BINDING_6_TO_8_BUFFER, std430) readonly buffer REPLICATE_6_BIT_TO_8 {
81 uint REPLICATE_6_BIT_TO_8_TABLE[];
82};
83layout(binding = BINDING_7_TO_8_BUFFER, std430) readonly buffer REPLICATE_7_BIT_TO_8 {
84 uint REPLICATE_7_BIT_TO_8_TABLE[];
85};
86layout(binding = BINDING_8_TO_8_BUFFER, std430) readonly buffer REPLICATE_8_BIT_TO_8 {
87 uint REPLICATE_8_BIT_TO_8_TABLE[];
88};
89layout(binding = BINDING_BYTE_TO_16_BUFFER, std430) readonly buffer REPLICATE_BYTE_TO_16 {
90 uint REPLICATE_BYTE_TO_16_TABLE[];
91};
92
93layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image;
94
95const uint GOB_SIZE_X = 64;
96const uint GOB_SIZE_Y = 8;
97const uint GOB_SIZE_Z = 1;
98const uint GOB_SIZE = GOB_SIZE_X * GOB_SIZE_Y * GOB_SIZE_Z;
99
100const uint GOB_SIZE_X_SHIFT = 6;
101const uint GOB_SIZE_Y_SHIFT = 3;
102const uint GOB_SIZE_Z_SHIFT = 0;
103const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT;
104
105const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1, GOB_SIZE_Y - 1);
106
107const int BLOCK_SIZE_IN_BYTES = 16;
108
109const int BLOCK_INFO_ERROR = 0;
110const int BLOCK_INFO_VOID_EXTENT_HDR = 1;
111const int BLOCK_INFO_VOID_EXTENT_LDR = 2;
112const int BLOCK_INFO_NORMAL = 3;
113
114const int JUST_BITS = 0;
115const int QUINT = 1;
116const int TRIT = 2;
117
118// The following constants are expanded variants of the Replicate()
119// function calls corresponding to the following arguments:
120// value: index into the generated table
121// num_bits: the after "REPLICATE" in the table name. i.e. 4 is num_bits in REPLICATE_4.
122// to_bit: the integer after "TO_"
123const uint REPLICATE_BIT_TO_7_TABLE[2] = uint[](0, 127);
124const uint REPLICATE_1_BIT_TO_9_TABLE[2] = uint[](0, 511);
125
126const uint REPLICATE_1_BIT_TO_8_TABLE[2] = uint[](0, 255);
127const uint REPLICATE_2_BIT_TO_8_TABLE[4] = uint[](0, 85, 170, 255);
128const uint REPLICATE_3_BIT_TO_8_TABLE[8] = uint[](0, 36, 73, 109, 146, 182, 219, 255);
129const uint REPLICATE_4_BIT_TO_8_TABLE[16] =
130 uint[](0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255);
131const uint REPLICATE_5_BIT_TO_8_TABLE[32] =
132 uint[](0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165,
133 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255);
134const uint REPLICATE_1_BIT_TO_6_TABLE[2] = uint[](0, 63);
135const uint REPLICATE_2_BIT_TO_6_TABLE[4] = uint[](0, 21, 42, 63);
136const uint REPLICATE_3_BIT_TO_6_TABLE[8] = uint[](0, 9, 18, 27, 36, 45, 54, 63);
137const uint REPLICATE_4_BIT_TO_6_TABLE[16] =
138 uint[](0, 4, 8, 12, 17, 21, 25, 29, 34, 38, 42, 46, 51, 55, 59, 63);
139const uint REPLICATE_5_BIT_TO_6_TABLE[32] =
140 uint[](0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 33, 35, 37, 39, 41, 43, 45,
141 47, 49, 51, 53, 55, 57, 59, 61, 63);
142
143// Input ASTC texture globals
144uint current_index = 0;
145int bitsread = 0;
146uint total_bitsread = 0;
147uint local_buff[16];
148
149// Color data globals
150uint color_endpoint_data[16];
151int color_bitsread = 0;
152uint total_color_bitsread = 0;
153int color_index = 0;
154
155// Four values, two endpoints, four maximum paritions
156uint color_values[32];
157int colvals_index = 0;
158
159// Weight data globals
160uint texel_weight_data[16];
161int texel_bitsread = 0;
162uint total_texel_bitsread = 0;
163int texel_index = 0;
164
165bool texel_flag = false;
166
167// Global "vectors" to be pushed into when decoding
168EncodingData result_vector[100];
169int result_index = 0;
170
171EncodingData texel_vector[100];
172int texel_vector_index = 0;
173
174uint unquantized_texel_weights[2][144];
175
176uint SwizzleOffset(uvec2 pos) {
177 pos = pos & SWIZZLE_MASK;
178 return swizzle_table[pos.y * 64 + pos.x];
179}
180
181uint ReadTexel(uint offset) {
182 // extract the 8-bit value from the 32-bit packed data.
183 return bitfieldExtract(astc_data[offset / 4], int((offset * 8) & 24), 8);
184}
185
186// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
187// is the same as [(num_bits - 1):0] and repeats all the way down.
188uint Replicate(uint val, uint num_bits, uint to_bit) {
189 if (num_bits == 0 || to_bit == 0) {
190 return 0;
191 }
192 const uint v = val & uint((1 << num_bits) - 1);
193 uint res = v;
194 uint reslen = num_bits;
195 while (reslen < to_bit) {
196 uint comp = 0;
197 if (num_bits > to_bit - reslen) {
198 uint newshift = to_bit - reslen;
199 comp = num_bits - newshift;
200 num_bits = newshift;
201 }
202 res = uint(res << num_bits);
203 res = uint(res | (v >> comp));
204 reslen += num_bits;
205 }
206 return res;
207}
208
209uvec4 ReplicateByteTo16(uvec4 value) {
210 return uvec4(REPLICATE_BYTE_TO_16_TABLE[value.x], REPLICATE_BYTE_TO_16_TABLE[value.y],
211 REPLICATE_BYTE_TO_16_TABLE[value.z], REPLICATE_BYTE_TO_16_TABLE[value.w]);
212}
213
214uint ReplicateBitTo7(uint value) {
215 return REPLICATE_BIT_TO_7_TABLE[value];
216}
217
218uint ReplicateBitTo9(uint value) {
219 return REPLICATE_1_BIT_TO_9_TABLE[value];
220}
221
222uint FastReplicateTo8(uint value, uint num_bits) {
223 switch (num_bits) {
224 case 1:
225 return REPLICATE_1_BIT_TO_8_TABLE[value];
226 case 2:
227 return REPLICATE_2_BIT_TO_8_TABLE[value];
228 case 3:
229 return REPLICATE_3_BIT_TO_8_TABLE[value];
230 case 4:
231 return REPLICATE_4_BIT_TO_8_TABLE[value];
232 case 5:
233 return REPLICATE_5_BIT_TO_8_TABLE[value];
234 case 6:
235 return REPLICATE_6_BIT_TO_8_TABLE[value];
236 case 7:
237 return REPLICATE_7_BIT_TO_8_TABLE[value];
238 case 8:
239 return REPLICATE_8_BIT_TO_8_TABLE[value];
240 }
241 return Replicate(value, num_bits, 8);
242}
243
244uint FastReplicateTo6(uint value, uint num_bits) {
245 switch (num_bits) {
246 case 1:
247 return REPLICATE_1_BIT_TO_6_TABLE[value];
248 case 2:
249 return REPLICATE_2_BIT_TO_6_TABLE[value];
250 case 3:
251 return REPLICATE_3_BIT_TO_6_TABLE[value];
252 case 4:
253 return REPLICATE_4_BIT_TO_6_TABLE[value];
254 case 5:
255 return REPLICATE_5_BIT_TO_6_TABLE[value];
256 }
257 return Replicate(value, num_bits, 6);
258}
259
260uint Div3Floor(uint v) {
261 return (v * 0x5556) >> 16;
262}
263
264uint Div3Ceil(uint v) {
265 return Div3Floor(v + 2);
266}
267
268uint Div5Floor(uint v) {
269 return (v * 0x3334) >> 16;
270}
271
272uint Div5Ceil(uint v) {
273 return Div5Floor(v + 4);
274}
275
276uint Hash52(uint p) {
277 p ^= p >> 15;
278 p -= p << 17;
279 p += p << 7;
280 p += p << 4;
281 p ^= p >> 5;
282 p += p << 16;
283 p ^= p >> 7;
284 p ^= p >> 3;
285 p ^= p << 6;
286 p ^= p >> 17;
287 return p;
288}
289
290uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bool small_block) {
291 if (partition_count == 1) {
292 return 0;
293 }
294 if (small_block) {
295 x <<= 1;
296 y <<= 1;
297 z <<= 1;
298 }
299
300 seed += (partition_count - 1) * 1024;
301
302 uint rnum = Hash52(uint(seed));
303 uint seed1 = uint(rnum & 0xF);
304 uint seed2 = uint((rnum >> 4) & 0xF);
305 uint seed3 = uint((rnum >> 8) & 0xF);
306 uint seed4 = uint((rnum >> 12) & 0xF);
307 uint seed5 = uint((rnum >> 16) & 0xF);
308 uint seed6 = uint((rnum >> 20) & 0xF);
309 uint seed7 = uint((rnum >> 24) & 0xF);
310 uint seed8 = uint((rnum >> 28) & 0xF);
311 uint seed9 = uint((rnum >> 18) & 0xF);
312 uint seed10 = uint((rnum >> 22) & 0xF);
313 uint seed11 = uint((rnum >> 26) & 0xF);
314 uint seed12 = uint(((rnum >> 30) | (rnum << 2)) & 0xF);
315
316 seed1 = (seed1 * seed1);
317 seed2 = (seed2 * seed2);
318 seed3 = (seed3 * seed3);
319 seed4 = (seed4 * seed4);
320 seed5 = (seed5 * seed5);
321 seed6 = (seed6 * seed6);
322 seed7 = (seed7 * seed7);
323 seed8 = (seed8 * seed8);
324 seed9 = (seed9 * seed9);
325 seed10 = (seed10 * seed10);
326 seed11 = (seed11 * seed11);
327 seed12 = (seed12 * seed12);
328
329 int sh1, sh2, sh3;
330 if ((seed & 1) > 0) {
331 sh1 = (seed & 2) > 0 ? 4 : 5;
332 sh2 = (partition_count == 3) ? 6 : 5;
333 } else {
334 sh1 = (partition_count == 3) ? 6 : 5;
335 sh2 = (seed & 2) > 0 ? 4 : 5;
336 }
337 sh3 = (seed & 0x10) > 0 ? sh1 : sh2;
338
339 seed1 = (seed1 >> sh1);
340 seed2 = (seed2 >> sh2);
341 seed3 = (seed3 >> sh1);
342 seed4 = (seed4 >> sh2);
343 seed5 = (seed5 >> sh1);
344 seed6 = (seed6 >> sh2);
345 seed7 = (seed7 >> sh1);
346 seed8 = (seed8 >> sh2);
347 seed9 = (seed9 >> sh3);
348 seed10 = (seed10 >> sh3);
349 seed11 = (seed11 >> sh3);
350 seed12 = (seed12 >> sh3);
351
352 uint a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
353 uint b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
354 uint c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
355 uint d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
356
357 a &= 0x3F;
358 b &= 0x3F;
359 c &= 0x3F;
360 d &= 0x3F;
361
362 if (partition_count < 4) {
363 d = 0;
364 }
365 if (partition_count < 3) {
366 c = 0;
367 }
368
369 if (a >= b && a >= c && a >= d) {
370 return 0;
371 } else if (b >= c && b >= d) {
372 return 1;
373 } else if (c >= d) {
374 return 2;
375 } else {
376 return 3;
377 }
378}
379
380uint Select2DPartition(uint seed, uint x, uint y, uint partition_count, bool small_block) {
381 return SelectPartition(seed, x, y, 0, partition_count, small_block);
382}
383
384uint ReadBit() {
385 if (current_index >= local_buff.length()) {
386 return 0;
387 }
388 uint bit = bitfieldExtract(local_buff[current_index], bitsread, 1);
389 ++bitsread;
390 ++total_bitsread;
391 if (bitsread == 8) {
392 ++current_index;
393 bitsread = 0;
394 }
395 return bit;
396}
397
398uint StreamBits(uint num_bits) {
399 uint ret = 0;
400 for (uint i = 0; i < num_bits; i++) {
401 ret |= ((ReadBit() & 1) << i);
402 }
403 return ret;
404}
405
406uint ReadColorBit() {
407 uint bit = 0;
408 if (texel_flag) {
409 bit = bitfieldExtract(texel_weight_data[texel_index], texel_bitsread, 1);
410 ++texel_bitsread;
411 ++total_texel_bitsread;
412 if (texel_bitsread == 8) {
413 ++texel_index;
414 texel_bitsread = 0;
415 }
416 } else {
417 bit = bitfieldExtract(color_endpoint_data[color_index], color_bitsread, 1);
418 ++color_bitsread;
419 ++total_color_bitsread;
420 if (color_bitsread == 8) {
421 ++color_index;
422 color_bitsread = 0;
423 }
424 }
425 return bit;
426}
427
428uint StreamColorBits(uint num_bits) {
429 uint ret = 0;
430 for (uint i = 0; i < num_bits; i++) {
431 ret |= ((ReadColorBit() & 1) << i);
432 }
433 return ret;
434}
435
436void ResultEmplaceBack(EncodingData val) {
437 if (texel_flag) {
438 texel_vector[texel_vector_index] = val;
439 ++texel_vector_index;
440 } else {
441 result_vector[result_index] = val;
442 ++result_index;
443 }
444}
445
446// Returns the number of bits required to encode n_vals values.
447uint GetBitLength(uint n_vals, uint encoding_index) {
448 uint total_bits = encoding_values[encoding_index].num_bits * n_vals;
449 if (encoding_values[encoding_index].encoding == TRIT) {
450 total_bits += Div5Ceil(n_vals * 8);
451 } else if (encoding_values[encoding_index].encoding == QUINT) {
452 total_bits += Div3Ceil(n_vals * 7);
453 }
454 return total_bits;
455}
456
457uint GetNumWeightValues(uvec2 size, bool dual_plane) {
458 uint n_vals = size.x * size.y;
459 if (dual_plane) {
460 n_vals *= 2;
461 }
462 return n_vals;
463}
464
465uint GetPackedBitSize(uvec2 size, bool dual_plane, uint max_weight) {
466 uint n_vals = GetNumWeightValues(size, dual_plane);
467 return GetBitLength(n_vals, max_weight);
468}
469
470uint BitsBracket(uint bits, uint pos) {
471 return ((bits >> pos) & 1);
472}
473
474uint BitsOp(uint bits, uint start, uint end) {
475 if (start == end) {
476 return BitsBracket(bits, start);
477 } else if (start > end) {
478 uint t = start;
479 start = end;
480 end = t;
481 }
482
483 uint mask = (1 << (end - start + 1)) - 1;
484 return ((bits >> start) & mask);
485}
486
487void DecodeQuintBlock(uint num_bits) {
488 uint m[3];
489 uint q[3];
490 uint Q;
491 m[0] = StreamColorBits(num_bits);
492 Q = StreamColorBits(3);
493 m[1] = StreamColorBits(num_bits);
494 Q |= StreamColorBits(2) << 3;
495 m[2] = StreamColorBits(num_bits);
496 Q |= StreamColorBits(2) << 5;
497 if (BitsOp(Q, 1, 2) == 3 && BitsOp(Q, 5, 6) == 0) {
498 q[0] = 4;
499 q[1] = 4;
500 q[2] = (BitsBracket(Q, 0) << 2) | ((BitsBracket(Q, 4) & ~BitsBracket(Q, 0)) << 1) |
501 (BitsBracket(Q, 3) & ~BitsBracket(Q, 0));
502 } else {
503 uint C = 0;
504 if (BitsOp(Q, 1, 2) == 3) {
505 q[2] = 4;
506 C = (BitsOp(Q, 3, 4) << 3) | ((~BitsOp(Q, 5, 6) & 3) << 1) | BitsBracket(Q, 0);
507 } else {
508 q[2] = BitsOp(Q, 5, 6);
509 C = BitsOp(Q, 0, 4);
510 }
511 if (BitsOp(C, 0, 2) == 5) {
512 q[1] = 4;
513 q[0] = BitsOp(C, 3, 4);
514 } else {
515 q[1] = BitsOp(C, 3, 4);
516 q[0] = BitsOp(C, 0, 2);
517 }
518 }
519 for (uint i = 0; i < 3; i++) {
520 EncodingData val;
521 val.encoding = QUINT;
522 val.num_bits = num_bits;
523 val.bit_value = m[i];
524 val.quint_trit_value = q[i];
525 ResultEmplaceBack(val);
526 }
527}
528
529void DecodeTritBlock(uint num_bits) {
530 uint m[5];
531 uint t[5];
532 uint T;
533 m[0] = StreamColorBits(num_bits);
534 T = StreamColorBits(2);
535 m[1] = StreamColorBits(num_bits);
536 T |= StreamColorBits(2) << 2;
537 m[2] = StreamColorBits(num_bits);
538 T |= StreamColorBits(1) << 4;
539 m[3] = StreamColorBits(num_bits);
540 T |= StreamColorBits(2) << 5;
541 m[4] = StreamColorBits(num_bits);
542 T |= StreamColorBits(1) << 7;
543 uint C = 0;
544 if (BitsOp(T, 2, 4) == 7) {
545 C = (BitsOp(T, 5, 7) << 2) | BitsOp(T, 0, 1);
546 t[4] = 2;
547 t[3] = 2;
548 } else {
549 C = BitsOp(T, 0, 4);
550 if (BitsOp(T, 5, 6) == 3) {
551 t[4] = 2;
552 t[3] = BitsBracket(T, 7);
553 } else {
554 t[4] = BitsBracket(T, 7);
555 t[3] = BitsOp(T, 5, 6);
556 }
557 }
558 if (BitsOp(C, 0, 1) == 3) {
559 t[2] = 2;
560 t[1] = BitsBracket(C, 4);
561 t[0] = (BitsBracket(C, 3) << 1) | (BitsBracket(C, 2) & ~BitsBracket(C, 3));
562 } else if (BitsOp(C, 2, 3) == 3) {
563 t[2] = 2;
564 t[1] = 2;
565 t[0] = BitsOp(C, 0, 1);
566 } else {
567 t[2] = BitsBracket(C, 4);
568 t[1] = BitsOp(C, 2, 3);
569 t[0] = (BitsBracket(C, 1) << 1) | (BitsBracket(C, 0) & ~BitsBracket(C, 1));
570 }
571 for (uint i = 0; i < 5; i++) {
572 EncodingData val;
573 val.encoding = TRIT;
574 val.num_bits = num_bits;
575 val.bit_value = m[i];
576 val.quint_trit_value = t[i];
577 ResultEmplaceBack(val);
578 }
579}
580
581void DecodeIntegerSequence(uint max_range, uint num_values) {
582 EncodingData val = encoding_values[max_range];
583 uint vals_decoded = 0;
584 while (vals_decoded < num_values) {
585 switch (val.encoding) {
586 case QUINT:
587 DecodeQuintBlock(val.num_bits);
588 vals_decoded += 3;
589 break;
590 case TRIT:
591 DecodeTritBlock(val.num_bits);
592 vals_decoded += 5;
593 break;
594 case JUST_BITS:
595 val.bit_value = StreamColorBits(val.num_bits);
596 ResultEmplaceBack(val);
597 vals_decoded++;
598 break;
599 }
600 }
601}
602
603void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits) {
604 uint num_values = 0;
605 for (uint i = 0; i < num_partitions; i++) {
606 num_values += ((modes[i] >> 2) + 1) << 1;
607 }
608 int range = 256;
609 while (--range > 0) {
610 EncodingData val = encoding_values[range];
611 uint bit_length = GetBitLength(num_values, range);
612 if (bit_length <= color_data_bits) {
613 while (--range > 0) {
614 EncodingData newval = encoding_values[range];
615 if (newval.encoding != val.encoding && newval.num_bits != val.num_bits) {
616 break;
617 }
618 }
619 ++range;
620 break;
621 }
622 }
623 DecodeIntegerSequence(range, num_values);
624 uint out_index = 0;
625 for (int itr = 0; itr < result_index; ++itr) {
626 if (out_index >= num_values) {
627 break;
628 }
629 EncodingData val = result_vector[itr];
630 uint bitlen = val.num_bits;
631 uint bitval = val.bit_value;
632 uint A = 0, B = 0, C = 0, D = 0;
633 A = ReplicateBitTo9((bitval & 1));
634 switch (val.encoding) {
635 case JUST_BITS:
636 color_values[out_index++] = FastReplicateTo8(bitval, bitlen);
637 break;
638 case TRIT: {
639 D = val.quint_trit_value;
640 switch (bitlen) {
641 case 1:
642 C = 204;
643 break;
644 case 2: {
645 C = 93;
646 uint b = (bitval >> 1) & 1;
647 B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
648 break;
649 }
650 case 3: {
651 C = 44;
652 uint cb = (bitval >> 1) & 3;
653 B = (cb << 7) | (cb << 2) | cb;
654 break;
655 }
656 case 4: {
657 C = 22;
658 uint dcb = (bitval >> 1) & 7;
659 B = (dcb << 6) | dcb;
660 break;
661 }
662 case 5: {
663 C = 11;
664 uint edcb = (bitval >> 1) & 0xF;
665 B = (edcb << 5) | (edcb >> 2);
666 break;
667 }
668 case 6: {
669 C = 5;
670 uint fedcb = (bitval >> 1) & 0x1F;
671 B = (fedcb << 4) | (fedcb >> 4);
672 break;
673 }
674 }
675 break;
676 }
677 case QUINT: {
678 D = val.quint_trit_value;
679 switch (bitlen) {
680 case 1:
681 C = 113;
682 break;
683 case 2: {
684 C = 54;
685 uint b = (bitval >> 1) & 1;
686 B = (b << 8) | (b << 3) | (b << 2);
687 break;
688 }
689 case 3: {
690 C = 26;
691 uint cb = (bitval >> 1) & 3;
692 B = (cb << 7) | (cb << 1) | (cb >> 1);
693 break;
694 }
695 case 4: {
696 C = 13;
697 uint dcb = (bitval >> 1) & 7;
698 B = (dcb << 6) | (dcb >> 1);
699 break;
700 }
701 case 5: {
702 C = 6;
703 uint edcb = (bitval >> 1) & 0xF;
704 B = (edcb << 5) | (edcb >> 3);
705 break;
706 }
707 }
708 break;
709 }
710 }
711 if (val.encoding != JUST_BITS) {
712 uint T = (D * C) + B;
713 T ^= A;
714 T = (A & 0x80) | (T >> 2);
715 color_values[out_index++] = T;
716 }
717 }
718}
719
720ivec2 BitTransferSigned(int a, int b) {
721 ivec2 transferred;
722 transferred.y = b >> 1;
723 transferred.y |= a & 0x80;
724 transferred.x = a >> 1;
725 transferred.x &= 0x3F;
726 if ((transferred.x & 0x20) > 0) {
727 transferred.x -= 0x40;
728 }
729 return transferred;
730}
731
732uvec4 ClampByte(ivec4 color) {
733 for (uint i = 0; i < 4; ++i) {
734 color[i] = (color[i] < 0) ? 0 : ((color[i] > 255) ? 255 : color[i]);
735 }
736 return uvec4(color);
737}
738
739ivec4 BlueContract(int a, int r, int g, int b) {
740 return ivec4(a, (r + b) >> 1, (g + b) >> 1, b);
741}
742
743void ComputeEndpoints(out uvec4 ep1, out uvec4 ep2, uint color_endpoint_mode) {
744#define READ_UINT_VALUES(N) \
745 uint v[N]; \
746 for (uint i = 0; i < N; i++) { \
747 v[i] = color_values[colvals_index++]; \
748 }
749
750#define READ_INT_VALUES(N) \
751 int v[N]; \
752 for (uint i = 0; i < N; i++) { \
753 v[i] = int(color_values[colvals_index++]); \
754 }
755
756 switch (color_endpoint_mode) {
757 case 0: {
758 READ_UINT_VALUES(2)
759 ep1 = uvec4(0xFF, v[0], v[0], v[0]);
760 ep2 = uvec4(0xFF, v[1], v[1], v[1]);
761 break;
762 }
763 case 1: {
764 READ_UINT_VALUES(2)
765 uint L0 = (v[0] >> 2) | (v[1] & 0xC0);
766 uint L1 = max(L0 + (v[1] & 0x3F), 0xFFU);
767 ep1 = uvec4(0xFF, L0, L0, L0);
768 ep2 = uvec4(0xFF, L1, L1, L1);
769 break;
770 }
771 case 4: {
772 READ_UINT_VALUES(4)
773 ep1 = uvec4(v[2], v[0], v[0], v[0]);
774 ep2 = uvec4(v[3], v[1], v[1], v[1]);
775 break;
776 }
777 case 5: {
778 READ_INT_VALUES(4)
779 ivec2 transferred = BitTransferSigned(v[1], v[0]);
780 v[1] = transferred.x;
781 v[0] = transferred.y;
782 transferred = BitTransferSigned(v[3], v[2]);
783 v[3] = transferred.x;
784 v[2] = transferred.y;
785 ep1 = ClampByte(ivec4(v[2], v[0], v[0], v[0]));
786 ep2 = ClampByte(ivec4(v[2] + v[3], v[0] + v[1], v[0] + v[1], v[0] + v[1]));
787 break;
788 }
789 case 6: {
790 READ_UINT_VALUES(4)
791 ep1 = uvec4(0xFF, (v[0] * v[3]) >> 8, (v[1] * v[3]) >> 8, (v[2] * v[3]) >> 8);
792 ep2 = uvec4(0xFF, v[0], v[1], v[2]);
793 break;
794 }
795 case 8: {
796 READ_UINT_VALUES(6)
797 if ((v[1] + v[3] + v[5]) >= (v[0] + v[2] + v[4])) {
798 ep1 = uvec4(0xFF, v[0], v[2], v[4]);
799 ep2 = uvec4(0xFF, v[1], v[3], v[5]);
800 } else {
801 ep1 = uvec4(BlueContract(0xFF, int(v[1]), int(v[3]), int(v[5])));
802 ep2 = uvec4(BlueContract(0xFF, int(v[0]), int(v[2]), int(v[4])));
803 }
804 break;
805 }
806 case 9: {
807 READ_INT_VALUES(6)
808 ivec2 transferred = BitTransferSigned(v[1], v[0]);
809 v[1] = transferred.x;
810 v[0] = transferred.y;
811 transferred = BitTransferSigned(v[3], v[2]);
812 v[3] = transferred.x;
813 v[2] = transferred.y;
814 transferred = BitTransferSigned(v[5], v[4]);
815 v[5] = transferred.x;
816 v[4] = transferred.y;
817 if ((v[1] + v[3] + v[5]) >= 0) {
818 ep1 = ClampByte(ivec4(0xFF, v[0], v[2], v[4]));
819 ep2 = ClampByte(ivec4(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]));
820 } else {
821 ep1 = ClampByte(BlueContract(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]));
822 ep2 = ClampByte(BlueContract(0xFF, v[0], v[2], v[4]));
823 }
824 break;
825 }
826 case 10: {
827 READ_UINT_VALUES(6)
828 ep1 = uvec4(v[4], (v[0] * v[3]) >> 8, (v[1] * v[3]) >> 8, (v[2] * v[3]) >> 8);
829 ep2 = uvec4(v[5], v[0], v[1], v[2]);
830 break;
831 }
832 case 12: {
833 READ_UINT_VALUES(8)
834 if ((v[1] + v[3] + v[5]) >= (v[0] + v[2] + v[4])) {
835 ep1 = uvec4(v[6], v[0], v[2], v[4]);
836 ep2 = uvec4(v[7], v[1], v[3], v[5]);
837 } else {
838 ep1 = uvec4(BlueContract(int(v[7]), int(v[1]), int(v[3]), int(v[5])));
839 ep2 = uvec4(BlueContract(int(v[6]), int(v[0]), int(v[2]), int(v[4])));
840 }
841 break;
842 }
843 case 13: {
844 READ_INT_VALUES(8)
845 ivec2 transferred = BitTransferSigned(v[1], v[0]);
846 v[1] = transferred.x;
847 v[0] = transferred.y;
848 transferred = BitTransferSigned(v[3], v[2]);
849 v[3] = transferred.x;
850 v[2] = transferred.y;
851
852 transferred = BitTransferSigned(v[5], v[4]);
853 v[5] = transferred.x;
854 v[4] = transferred.y;
855
856 transferred = BitTransferSigned(v[7], v[6]);
857 v[7] = transferred.x;
858 v[6] = transferred.y;
859
860 if ((v[1] + v[3] + v[5]) >= 0) {
861 ep1 = ClampByte(ivec4(v[6], v[0], v[2], v[4]));
862 ep2 = ClampByte(ivec4(v[7] + v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5]));
863 } else {
864 ep1 = ClampByte(BlueContract(v[6] + v[7], v[0] + v[1], v[2] + v[3], v[4] + v[5]));
865 ep2 = ClampByte(BlueContract(v[6], v[0], v[2], v[4]));
866 }
867 break;
868 }
869 default: {
870 // HDR mode, or more likely a bug computing the color_endpoint_mode
871 ep1 = uvec4(0xFF, 0xFF, 0, 0);
872 ep2 = uvec4(0xFF, 0xFF, 0, 0);
873 break;
874 }
875 }
876#undef READ_UINT_VALUES
877#undef READ_INT_VALUES
878}
879
880uint UnquantizeTexelWeight(EncodingData val) {
881 uint bitval = val.bit_value;
882 uint bitlen = val.num_bits;
883 uint A = ReplicateBitTo7((bitval & 1));
884 uint B = 0, C = 0, D = 0;
885 uint result = 0;
886 switch (val.encoding) {
887 case JUST_BITS:
888 result = FastReplicateTo6(bitval, bitlen);
889 break;
890 case TRIT: {
891 D = val.quint_trit_value;
892 switch (bitlen) {
893 case 0: {
894 uint results[3] = {0, 32, 63};
895 result = results[D];
896 break;
897 }
898 case 1: {
899 C = 50;
900 break;
901 }
902 case 2: {
903 C = 23;
904 uint b = (bitval >> 1) & 1;
905 B = (b << 6) | (b << 2) | b;
906 break;
907 }
908 case 3: {
909 C = 11;
910 uint cb = (bitval >> 1) & 3;
911 B = (cb << 5) | cb;
912 break;
913 }
914 default:
915 break;
916 }
917 break;
918 }
919 case QUINT: {
920 D = val.quint_trit_value;
921 switch (bitlen) {
922 case 0: {
923 uint results[5] = {0, 16, 32, 47, 63};
924 result = results[D];
925 break;
926 }
927 case 1: {
928 C = 28;
929 break;
930 }
931 case 2: {
932 C = 13;
933 uint b = (bitval >> 1) & 1;
934 B = (b << 6) | (b << 1);
935 break;
936 }
937 }
938 break;
939 }
940 }
941 if (val.encoding != JUST_BITS && bitlen > 0) {
942 result = D * C + B;
943 result ^= A;
944 result = (A & 0x20) | (result >> 2);
945 }
946 if (result > 32) {
947 result += 1;
948 }
949 return result;
950}
951
952void UnquantizeTexelWeights(bool dual_plane, uvec2 size) {
953 uint weight_idx = 0;
954 uint unquantized[2][144];
955 uint area = size.x * size.y;
956 for (uint itr = 0; itr < texel_vector_index; itr++) {
957 unquantized[0][weight_idx] = UnquantizeTexelWeight(texel_vector[itr]);
958 if (dual_plane) {
959 ++itr;
960 unquantized[1][weight_idx] = UnquantizeTexelWeight(texel_vector[itr]);
961 if (itr == texel_vector_index) {
962 break;
963 }
964 }
965 if (++weight_idx >= (area))
966 break;
967 }
968
969 const uint Ds = uint((block_dims.x * 0.5f + 1024) / (block_dims.x - 1));
970 const uint Dt = uint((block_dims.y * 0.5f + 1024) / (block_dims.y - 1));
971 const uint k_plane_scale = dual_plane ? 2 : 1;
972 for (uint plane = 0; plane < k_plane_scale; plane++) {
973 for (uint t = 0; t < block_dims.y; t++) {
974 for (uint s = 0; s < block_dims.x; s++) {
975 uint cs = Ds * s;
976 uint ct = Dt * t;
977 uint gs = (cs * (size.x - 1) + 32) >> 6;
978 uint gt = (ct * (size.y - 1) + 32) >> 6;
979 uint js = gs >> 4;
980 uint fs = gs & 0xF;
981 uint jt = gt >> 4;
982 uint ft = gt & 0x0F;
983 uint w11 = (fs * ft + 8) >> 4;
984 uint w10 = ft - w11;
985 uint w01 = fs - w11;
986 uint w00 = 16 - fs - ft + w11;
987 uvec4 w = uvec4(w00, w01, w10, w11);
988 uint v0 = jt * size.x + js;
989
990 uvec4 p = uvec4(0);
991 if (v0 < area) {
992 p.x = unquantized[plane][v0];
993 }
994 if ((v0 + 1) < (area)) {
995 p.y = unquantized[plane][v0 + 1];
996 }
997 if ((v0 + size.x) < (area)) {
998 p.z = unquantized[plane][(v0 + size.x)];
999 }
1000 if ((v0 + size.x + 1) < (area)) {
1001 p.w = unquantized[plane][(v0 + size.x + 1)];
1002 }
1003 unquantized_texel_weights[plane][t * block_dims.x + s] = (uint(dot(p, w)) + 8) >> 4;
1004 }
1005 }
1006 }
1007}
1008
1009int FindLayout(uint mode) {
1010 if ((mode & 3) != 0) {
1011 if ((mode & 8) != 0) {
1012 if ((mode & 4) != 0) {
1013 if ((mode & 0x100) != 0) {
1014 return 4;
1015 }
1016 return 3;
1017 }
1018 return 2;
1019 }
1020 if ((mode & 4) != 0) {
1021 return 1;
1022 }
1023 return 0;
1024 }
1025 if ((mode & 0x100) != 0) {
1026 if ((mode & 0x80) != 0) {
1027 if ((mode & 0x20) != 0) {
1028 return 8;
1029 }
1030 return 7;
1031 }
1032 return 9;
1033 }
1034 if ((mode & 0x80) != 0) {
1035 return 6;
1036 }
1037 return 5;
1038}
1039
1040TexelWeightParams DecodeBlockInfo(uint block_index) {
1041 TexelWeightParams params = TexelWeightParams(uvec2(0), 0, false, false, false, false);
1042 uint mode = StreamBits(11);
1043 if ((mode & 0x1ff) == 0x1fc) {
1044 if ((mode & 0x200) != 0) {
1045 params.void_extent_hdr = true;
1046 } else {
1047 params.void_extent_ldr = true;
1048 }
1049 if ((mode & 0x400) == 0 || StreamBits(1) == 0) {
1050 params.error_state = true;
1051 }
1052 return params;
1053 }
1054 if ((mode & 0xf) == 0) {
1055 params.error_state = true;
1056 return params;
1057 }
1058 if ((mode & 3) == 0 && (mode & 0x1c0) == 0x1c0) {
1059 params.error_state = true;
1060 return params;
1061 }
1062 uint A, B;
1063 uint mode_layout = FindLayout(mode);
1064 switch (mode_layout) {
1065 case 0:
1066 A = (mode >> 5) & 0x3;
1067 B = (mode >> 7) & 0x3;
1068 params.size = uvec2(B + 4, A + 2);
1069 break;
1070 case 1:
1071 A = (mode >> 5) & 0x3;
1072 B = (mode >> 7) & 0x3;
1073 params.size = uvec2(B + 8, A + 2);
1074 break;
1075 case 2:
1076 A = (mode >> 5) & 0x3;
1077 B = (mode >> 7) & 0x3;
1078 params.size = uvec2(A + 2, B + 8);
1079 break;
1080 case 3:
1081 A = (mode >> 5) & 0x3;
1082 B = (mode >> 7) & 0x1;
1083 params.size = uvec2(A + 2, B + 6);
1084 break;
1085 case 4:
1086 A = (mode >> 5) & 0x3;
1087 B = (mode >> 7) & 0x1;
1088 params.size = uvec2(B + 2, A + 2);
1089 break;
1090 case 5:
1091 A = (mode >> 5) & 0x3;
1092 params.size = uvec2(12, A + 2);
1093 break;
1094 case 6:
1095 A = (mode >> 5) & 0x3;
1096 params.size = uvec2(A + 2, 12);
1097 break;
1098 case 7:
1099 params.size = uvec2(6, 10);
1100 break;
1101 case 8:
1102 params.size = uvec2(10, 6);
1103 break;
1104 case 9:
1105 A = (mode >> 5) & 0x3;
1106 B = (mode >> 9) & 0x3;
1107 params.size = uvec2(A + 6, B + 6);
1108 break;
1109 default:
1110 params.error_state = true;
1111 break;
1112 }
1113 params.dual_plane = (mode_layout != 9) && ((mode & 0x400) != 0);
1114 uint weight_index = (mode & 0x10) != 0 ? 1 : 0;
1115 if (mode_layout < 5) {
1116 weight_index |= (mode & 0x3) << 1;
1117 } else {
1118 weight_index |= (mode & 0xc) >> 1;
1119 }
1120 weight_index -= 2;
1121 if ((mode_layout != 9) && ((mode & 0x200) != 0)) {
1122 const int max_weights[6] = int[6](9, 11, 15, 19, 23, 31);
1123 params.max_weight = max_weights[weight_index];
1124 } else {
1125 const int max_weights[6] = int[6](1, 2, 3, 4, 5, 7);
1126 params.max_weight = max_weights[weight_index];
1127 }
1128 return params;
1129}
1130
1131void FillError(ivec3 coord) {
1132 for (uint j = 0; j < block_dims.y; j++) {
1133 for (uint i = 0; i < block_dims.x; i++) {
1134 imageStore(dest_image, coord + ivec3(i, j, 0), vec4(1.0, 1.0, 0.0, 1.0));
1135 }
1136 }
1137}
1138
1139void FillVoidExtentLDR(ivec3 coord) {
1140 StreamBits(52);
1141 uint r_u = StreamBits(16);
1142 uint g_u = StreamBits(16);
1143 uint b_u = StreamBits(16);
1144 uint a_u = StreamBits(16);
1145 float a = float(a_u) / 65535.0f;
1146 float r = float(r_u) / 65535.0f;
1147 float g = float(g_u) / 65535.0f;
1148 float b = float(b_u) / 65535.0f;
1149 for (uint j = 0; j < block_dims.y; j++) {
1150 for (uint i = 0; i < block_dims.x; i++) {
1151 imageStore(dest_image, coord + ivec3(i, j, 0), vec4(r, g, b, a));
1152 }
1153 }
1154}
1155
1156void DecompressBlock(ivec3 coord, uint block_index) {
1157 TexelWeightParams params = DecodeBlockInfo(block_index);
1158 if (params.error_state) {
1159 FillError(coord);
1160 return;
1161 }
1162 if (params.void_extent_hdr) {
1163 FillError(coord);
1164 return;
1165 }
1166 if (params.void_extent_ldr) {
1167 FillVoidExtentLDR(coord);
1168 return;
1169 }
1170 if ((params.size.x > block_dims.x) || (params.size.y > block_dims.y)) {
1171 FillError(coord);
1172 return;
1173 }
1174 uint num_partitions = StreamBits(2) + 1;
1175 if (num_partitions > 4 || (num_partitions == 4 && params.dual_plane)) {
1176 FillError(coord);
1177 return;
1178 }
1179 int plane_index = -1;
1180 uint partition_index = 1;
1181 uvec4 color_endpoint_mode = uvec4(0);
1182 uint ced_pointer = 0;
1183 uint base_cem = 0;
1184 if (num_partitions == 1) {
1185 color_endpoint_mode.x = StreamBits(4);
1186 partition_index = 0;
1187 } else {
1188 partition_index = StreamBits(10);
1189 base_cem = StreamBits(6);
1190 }
1191 uint base_mode = base_cem & 3;
1192 uint weight_bits = GetPackedBitSize(params.size, params.dual_plane, params.max_weight);
1193 uint remaining_bits = 128 - weight_bits - total_bitsread;
1194 uint extra_cem_bits = 0;
1195 if (base_mode > 0) {
1196 switch (num_partitions) {
1197 case 2:
1198 extra_cem_bits += 2;
1199 break;
1200 case 3:
1201 extra_cem_bits += 5;
1202 break;
1203 case 4:
1204 extra_cem_bits += 8;
1205 break;
1206 default:
1207 return;
1208 }
1209 }
1210 remaining_bits -= extra_cem_bits;
1211 uint plane_selector_bits = 0;
1212 if (params.dual_plane) {
1213 plane_selector_bits = 2;
1214 }
1215 remaining_bits -= plane_selector_bits;
1216 if (remaining_bits > 128) {
1217 // Bad data, more remaining bits than 4 bytes
1218 // return early
1219 return;
1220 }
1221 // Read color data...
1222 uint color_data_bits = remaining_bits;
1223 while (remaining_bits > 0) {
1224 int nb = int(min(remaining_bits, 8U));
1225 uint b = StreamBits(nb);
1226 color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb));
1227 ++ced_pointer;
1228 remaining_bits -= nb;
1229 }
1230 plane_index = int(StreamBits(plane_selector_bits));
1231 if (base_mode > 0) {
1232 uint extra_cem = StreamBits(extra_cem_bits);
1233 uint cem = (extra_cem << 6) | base_cem;
1234 cem >>= 2;
1235 uvec4 C = uvec4(0);
1236 for (uint i = 0; i < num_partitions; i++) {
1237 C[i] = (cem & 1);
1238 cem >>= 1;
1239 }
1240 uvec4 M = uvec4(0);
1241 for (uint i = 0; i < num_partitions; i++) {
1242 M[i] = cem & 3;
1243 cem >>= 2;
1244 }
1245 for (uint i = 0; i < num_partitions; i++) {
1246 color_endpoint_mode[i] = base_mode;
1247 if (C[i] == 0) {
1248 --color_endpoint_mode[i];
1249 }
1250 color_endpoint_mode[i] <<= 2;
1251 color_endpoint_mode[i] |= M[i];
1252 }
1253 } else if (num_partitions > 1) {
1254 uint cem = base_cem >> 2;
1255 for (uint i = 0; i < num_partitions; i++) {
1256 color_endpoint_mode[i] = cem;
1257 }
1258 }
1259 DecodeColorValues(color_endpoint_mode, num_partitions, color_data_bits);
1260
1261 uvec4 endpoints[4][2];
1262 for (uint i = 0; i < num_partitions; i++) {
1263 ComputeEndpoints(endpoints[i][0], endpoints[i][1], color_endpoint_mode[i]);
1264 }
1265
1266 for (uint i = 0; i < 16; i++) {
1267 texel_weight_data[i] = local_buff[i];
1268 }
1269 for (uint i = 0; i < 8; i++) {
1270#define REVERSE_BYTE(b) ((b * 0x0802U & 0x22110U) | (b * 0x8020U & 0x88440U)) * 0x10101U >> 16
1271 uint a = REVERSE_BYTE(texel_weight_data[i]);
1272 uint b = REVERSE_BYTE(texel_weight_data[15 - i]);
1273#undef REVERSE_BYTE
1274 texel_weight_data[i] = uint(bitfieldExtract(b, 0, 8));
1275 texel_weight_data[15 - i] = uint(bitfieldExtract(a, 0, 8));
1276 }
1277 uint clear_byte_start =
1278 (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) >> 3) + 1;
1279 texel_weight_data[clear_byte_start - 1] =
1280 texel_weight_data[clear_byte_start - 1] &
1281 uint(
1282 ((1 << (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) % 8)) - 1));
1283 for (uint i = 0; i < 16 - clear_byte_start; i++) {
1284 texel_weight_data[clear_byte_start + i] = 0U;
1285 }
1286 texel_flag = true; // use texel "vector" and bit stream in integer decoding
1287 DecodeIntegerSequence(params.max_weight, GetNumWeightValues(params.size, params.dual_plane));
1288
1289 UnquantizeTexelWeights(params.dual_plane, params.size);
1290
1291 for (uint j = 0; j < block_dims.y; j++) {
1292 for (uint i = 0; i < block_dims.x; i++) {
1293 uint local_partition = Select2DPartition(partition_index, i, j, num_partitions,
1294 (block_dims.y * block_dims.x) < 32);
1295 vec4 p;
1296 uvec4 C0 = ReplicateByteTo16(endpoints[local_partition][0]);
1297 uvec4 C1 = ReplicateByteTo16(endpoints[local_partition][1]);
1298 uvec4 plane_vec = uvec4(0);
1299 uvec4 weight_vec = uvec4(0);
1300 for (uint c = 0; c < 4; c++) {
1301 if (params.dual_plane && (((plane_index + 1) & 3) == c)) {
1302 plane_vec[c] = 1;
1303 }
1304 weight_vec[c] = unquantized_texel_weights[plane_vec[c]][j * block_dims.x + i];
1305 }
1306 vec4 Cf = vec4((C0 * (uvec4(64) - weight_vec) + C1 * weight_vec + uvec4(32)) / 64);
1307 p = (Cf / 65535.0);
1308 imageStore(dest_image, coord + ivec3(i, j, 0), p.gbar);
1309 }
1310 }
1311}
1312
1313void main() {
1314 uvec3 pos = gl_GlobalInvocationID;
1315 pos.x <<= bytes_per_block_log2;
1316
1317 // Read as soon as possible due to its latency
1318 const uint swizzle = SwizzleOffset(pos.xy);
1319
1320 const uint block_y = pos.y >> GOB_SIZE_Y_SHIFT;
1321
1322 uint offset = 0;
1323 offset += pos.z * layer_stride;
1324 offset += (block_y >> block_height) * block_size;
1325 offset += (block_y & block_height_mask) << GOB_SIZE_SHIFT;
1326 offset += (pos.x >> GOB_SIZE_X_SHIFT) << x_shift;
1327 offset += swizzle;
1328
1329 const ivec3 coord = ivec3(gl_GlobalInvocationID * uvec3(block_dims, 1));
1330 uint block_index =
1331 pos.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + pos.y * gl_WorkGroupSize.x + pos.x;
1332
1333 current_index = 0;
1334 bitsread = 0;
1335 for (int i = 0; i < 16; i++) {
1336 local_buff[i] = ReadTexel(offset + i);
1337 }
1338 DecompressBlock(coord, block_index);
1339}
diff --git a/src/video_core/host_shaders/source_shader.h.in b/src/video_core/host_shaders/source_shader.h.in
index ccdb0d2a9..929dec39b 100644
--- a/src/video_core/host_shaders/source_shader.h.in
+++ b/src/video_core/host_shaders/source_shader.h.in
@@ -4,6 +4,8 @@
4 4
5namespace HostShaders { 5namespace HostShaders {
6 6
7constexpr std::string_view @CONTENTS_NAME@ = R"(@CONTENTS@)"; 7constexpr std::string_view @CONTENTS_NAME@ = {
8@CONTENTS@
9};
8 10
9} // namespace HostShaders 11} // namespace HostShaders
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp
index cd21a2112..d7fabe605 100644
--- a/src/video_core/macro/macro.cpp
+++ b/src/video_core/macro/macro.cpp
@@ -6,7 +6,7 @@
6#include <boost/container_hash/hash.hpp> 6#include <boost/container_hash/hash.hpp>
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/settings.h" 9#include "common/settings.h"
10#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/macro/macro.h" 11#include "video_core/macro/macro.h"
12#include "video_core/macro/macro_hle.h" 12#include "video_core/macro/macro_hle.h"
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index 203f2af05..aac851253 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -16,8 +16,8 @@
16#include <vector> 16#include <vector>
17 17
18#include "common/assert.h" 18#include "common/assert.h"
19#include "common/settings.h"
19#include "core/core.h" 20#include "core/core.h"
20#include "core/settings.h"
21#include "video_core/engines/maxwell_3d.h" 21#include "video_core/engines/maxwell_3d.h"
22#include "video_core/gpu.h" 22#include "video_core/gpu.h"
23#include "video_core/memory_manager.h" 23#include "video_core/memory_manager.h"
@@ -208,9 +208,9 @@ public:
208private: 208private:
209 /// Flushes a memory range to guest memory and removes it from the cache. 209 /// Flushes a memory range to guest memory and removes it from the cache.
210 void FlushAndRemoveRegion(VAddr addr, std::size_t size) { 210 void FlushAndRemoveRegion(VAddr addr, std::size_t size) {
211 const u64 addr_begin = static_cast<u64>(addr); 211 const u64 addr_begin = addr;
212 const u64 addr_end = addr_begin + static_cast<u64>(size); 212 const u64 addr_end = addr_begin + size;
213 const auto in_range = [addr_begin, addr_end](CachedQuery& query) { 213 const auto in_range = [addr_begin, addr_end](const CachedQuery& query) {
214 const u64 cache_begin = query.GetCpuAddr(); 214 const u64 cache_begin = query.GetCpuAddr();
215 const u64 cache_end = cache_begin + query.SizeInBytes(); 215 const u64 cache_end = cache_begin + query.SizeInBytes();
216 return cache_begin < addr_end && addr_begin < cache_end; 216 return cache_begin < addr_end && addr_begin < cache_end;
@@ -230,8 +230,7 @@ private:
230 rasterizer.UpdatePagesCachedCount(query.GetCpuAddr(), query.SizeInBytes(), -1); 230 rasterizer.UpdatePagesCachedCount(query.GetCpuAddr(), query.SizeInBytes(), -1);
231 query.Flush(); 231 query.Flush();
232 } 232 }
233 contents.erase(std::remove_if(std::begin(contents), std::end(contents), in_range), 233 std::erase_if(contents, in_range);
234 std::end(contents));
235 } 234 }
236 } 235 }
237 236
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index a93a1732c..c9a360aaf 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -3,8 +3,8 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "common/settings.h"
6#include "core/frontend/emu_window.h" 7#include "core/frontend/emu_window.h"
7#include "core/settings.h"
8#include "video_core/renderer_base.h" 8#include "video_core/renderer_base.h"
9 9
10namespace VideoCore { 10namespace VideoCore {
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 5776fccdc..b113f54db 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -16,7 +16,7 @@
16 16
17#include "common/logging/log.h" 17#include "common/logging/log.h"
18#include "common/scope_exit.h" 18#include "common/scope_exit.h"
19#include "core/settings.h" 19#include "common/settings.h"
20#include "video_core/renderer_opengl/gl_device.h" 20#include "video_core/renderer_opengl/gl_device.h"
21#include "video_core/renderer_opengl/gl_resource_manager.h" 21#include "video_core/renderer_opengl/gl_resource_manager.h"
22 22
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4610fd160..0863904e9 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -17,10 +17,10 @@
17#include "common/math_util.h" 17#include "common/math_util.h"
18#include "common/microprofile.h" 18#include "common/microprofile.h"
19#include "common/scope_exit.h" 19#include "common/scope_exit.h"
20#include "common/settings.h"
20#include "core/core.h" 21#include "core/core.h"
21#include "core/hle/kernel/process.h" 22#include "core/hle/kernel/process.h"
22#include "core/memory.h" 23#include "core/memory.h"
23#include "core/settings.h"
24#include "video_core/engines/kepler_compute.h" 24#include "video_core/engines/kepler_compute.h"
25#include "video_core/engines/maxwell_3d.h" 25#include "video_core/engines/maxwell_3d.h"
26#include "video_core/engines/shader_type.h" 26#include "video_core/engines/shader_type.h"
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 955b2abc4..97fb11ac6 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -12,10 +12,10 @@
12#include "common/file_util.h" 12#include "common/file_util.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/scm_rev.h" 14#include "common/scm_rev.h"
15#include "common/settings.h"
15#include "common/zstd_compression.h" 16#include "common/zstd_compression.h"
16#include "core/core.h" 17#include "core/core.h"
17#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
18#include "core/settings.h"
19#include "video_core/engines/shader_type.h" 19#include "video_core/engines/shader_type.h"
20#include "video_core/renderer_opengl/gl_shader_cache.h" 20#include "video_core/renderer_opengl/gl_shader_cache.h"
21#include "video_core/renderer_opengl/gl_shader_disk_cache.h" 21#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index e028677e9..623b43d8a 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -307,7 +307,8 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
307 307
308[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime, 308[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
309 const VideoCommon::ImageInfo& info) { 309 const VideoCommon::ImageInfo& info) {
310 // Disable accelerated uploads for now as they don't implement swizzled uploads 310 return !runtime.HasNativeASTC() && IsPixelFormatASTC(info.format);
311 // Disable other accelerated uploads for now as they don't implement swizzled uploads
311 return false; 312 return false;
312 switch (info.type) { 313 switch (info.type) {
313 case ImageType::e2D: 314 case ImageType::e2D:
@@ -569,7 +570,11 @@ void TextureCacheRuntime::AccelerateImageUpload(Image& image, const ImageBufferM
569 std::span<const SwizzleParameters> swizzles) { 570 std::span<const SwizzleParameters> swizzles) {
570 switch (image.info.type) { 571 switch (image.info.type) {
571 case ImageType::e2D: 572 case ImageType::e2D:
572 return util_shaders.BlockLinearUpload2D(image, map, swizzles); 573 if (IsPixelFormatASTC(image.info.format)) {
574 return util_shaders.ASTCDecode(image, map, swizzles);
575 } else {
576 return util_shaders.BlockLinearUpload2D(image, map, swizzles);
577 }
573 case ImageType::e3D: 578 case ImageType::e3D:
574 return util_shaders.BlockLinearUpload3D(image, map, swizzles); 579 return util_shaders.BlockLinearUpload3D(image, map, swizzles);
575 case ImageType::Linear: 580 case ImageType::Linear:
@@ -599,6 +604,10 @@ FormatProperties TextureCacheRuntime::FormatInfo(ImageType type, GLenum internal
599 } 604 }
600} 605}
601 606
607bool TextureCacheRuntime::HasNativeASTC() const noexcept {
608 return device.HasASTC();
609}
610
602TextureCacheRuntime::StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_) 611TextureCacheRuntime::StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_)
603 : storage_flags{storage_flags_}, map_flags{map_flags_} {} 612 : storage_flags{storage_flags_}, map_flags{map_flags_} {}
604 613
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 3fbaa102f..3c871541b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -95,6 +95,8 @@ public:
95 return has_broken_texture_view_formats; 95 return has_broken_texture_view_formats;
96 } 96 }
97 97
98 bool HasNativeASTC() const noexcept;
99
98private: 100private:
99 struct StagingBuffers { 101 struct StagingBuffers {
100 explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_); 102 explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_);
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 9d2acd4d9..cc2e499f9 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -13,13 +13,13 @@
13#include "common/assert.h" 13#include "common/assert.h"
14#include "common/logging/log.h" 14#include "common/logging/log.h"
15#include "common/microprofile.h" 15#include "common/microprofile.h"
16#include "common/settings.h"
16#include "common/telemetry.h" 17#include "common/telemetry.h"
17#include "core/core.h" 18#include "core/core.h"
18#include "core/core_timing.h" 19#include "core/core_timing.h"
19#include "core/frontend/emu_window.h" 20#include "core/frontend/emu_window.h"
20#include "core/memory.h" 21#include "core/memory.h"
21#include "core/perf_stats.h" 22#include "core/perf_stats.h"
22#include "core/settings.h"
23#include "core/telemetry_session.h" 23#include "core/telemetry_session.h"
24#include "video_core/host_shaders/opengl_present_frag.h" 24#include "video_core/host_shaders/opengl_present_frag.h"
25#include "video_core/host_shaders/opengl_present_vert.h" 25#include "video_core/host_shaders/opengl_present_vert.h"
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp
index 2fe4799bc..47fddcb6e 100644
--- a/src/video_core/renderer_opengl/util_shaders.cpp
+++ b/src/video_core/renderer_opengl/util_shaders.cpp
@@ -2,7 +2,6 @@
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 <bit>
6#include <span> 5#include <span>
7#include <string_view> 6#include <string_view>
8 7
@@ -11,6 +10,7 @@
11#include "common/assert.h" 10#include "common/assert.h"
12#include "common/common_types.h" 11#include "common/common_types.h"
13#include "common/div_ceil.h" 12#include "common/div_ceil.h"
13#include "video_core/host_shaders/astc_decoder_comp.h"
14#include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" 14#include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h"
15#include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" 15#include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h"
16#include "video_core/host_shaders/opengl_copy_bc4_comp.h" 16#include "video_core/host_shaders/opengl_copy_bc4_comp.h"
@@ -20,16 +20,18 @@
20#include "video_core/renderer_opengl/gl_shader_manager.h" 20#include "video_core/renderer_opengl/gl_shader_manager.h"
21#include "video_core/renderer_opengl/gl_texture_cache.h" 21#include "video_core/renderer_opengl/gl_texture_cache.h"
22#include "video_core/renderer_opengl/util_shaders.h" 22#include "video_core/renderer_opengl/util_shaders.h"
23#include "video_core/surface.h"
24#include "video_core/texture_cache/accelerated_swizzle.h" 23#include "video_core/texture_cache/accelerated_swizzle.h"
25#include "video_core/texture_cache/types.h" 24#include "video_core/texture_cache/types.h"
26#include "video_core/texture_cache/util.h" 25#include "video_core/texture_cache/util.h"
26#include "video_core/textures/astc.h"
27#include "video_core/textures/decoders.h" 27#include "video_core/textures/decoders.h"
28 28
29namespace OpenGL { 29namespace OpenGL {
30 30
31using namespace HostShaders; 31using namespace HostShaders;
32using namespace Tegra::Texture::ASTC;
32 33
34using VideoCommon::Extent2D;
33using VideoCommon::Extent3D; 35using VideoCommon::Extent3D;
34using VideoCommon::ImageCopy; 36using VideoCommon::ImageCopy;
35using VideoCommon::ImageType; 37using VideoCommon::ImageType;
@@ -57,7 +59,7 @@ size_t NumPixelsInCopy(const VideoCommon::ImageCopy& copy) {
57} // Anonymous namespace 59} // Anonymous namespace
58 60
59UtilShaders::UtilShaders(ProgramManager& program_manager_) 61UtilShaders::UtilShaders(ProgramManager& program_manager_)
60 : program_manager{program_manager_}, 62 : program_manager{program_manager_}, astc_decoder_program(MakeProgram(ASTC_DECODER_COMP)),
61 block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)), 63 block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)),
62 block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), 64 block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)),
63 pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), 65 pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)),
@@ -65,11 +67,79 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
65 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { 67 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) {
66 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); 68 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
67 swizzle_table_buffer.Create(); 69 swizzle_table_buffer.Create();
70 astc_buffer.Create();
68 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); 71 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
72 glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_BUFFER_DATA), &ASTC_BUFFER_DATA, 0);
69} 73}
70 74
71UtilShaders::~UtilShaders() = default; 75UtilShaders::~UtilShaders() = default;
72 76
77void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
78 std::span<const VideoCommon::SwizzleParameters> swizzles) {
79 static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
80 static constexpr GLuint BINDING_INPUT_BUFFER = 1;
81 static constexpr GLuint BINDING_ENC_BUFFER = 2;
82
83 static constexpr GLuint BINDING_6_TO_8_BUFFER = 3;
84 static constexpr GLuint BINDING_7_TO_8_BUFFER = 4;
85 static constexpr GLuint BINDING_8_TO_8_BUFFER = 5;
86 static constexpr GLuint BINDING_BYTE_TO_16_BUFFER = 6;
87
88 static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
89
90 const Extent2D tile_size{
91 .width = VideoCore::Surface::DefaultBlockWidth(image.info.format),
92 .height = VideoCore::Surface::DefaultBlockHeight(image.info.format),
93 };
94 program_manager.BindHostCompute(astc_decoder_program.handle);
95 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
96 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle,
97 offsetof(AstcBufferData, encoding_values),
98 sizeof(AstcBufferData::encoding_values));
99 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_6_TO_8_BUFFER, astc_buffer.handle,
100 offsetof(AstcBufferData, replicate_6_to_8),
101 sizeof(AstcBufferData::replicate_6_to_8));
102 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_7_TO_8_BUFFER, astc_buffer.handle,
103 offsetof(AstcBufferData, replicate_7_to_8),
104 sizeof(AstcBufferData::replicate_7_to_8));
105 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_8_TO_8_BUFFER, astc_buffer.handle,
106 offsetof(AstcBufferData, replicate_8_to_8),
107 sizeof(AstcBufferData::replicate_8_to_8));
108 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_BYTE_TO_16_BUFFER, astc_buffer.handle,
109 offsetof(AstcBufferData, replicate_byte_to_16),
110 sizeof(AstcBufferData::replicate_byte_to_16));
111
112 glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
113 glUniform2ui(1, tile_size.width, tile_size.height);
114 // Ensure buffer data is valid before dispatching
115 glFlush();
116 for (const SwizzleParameters& swizzle : swizzles) {
117 const size_t input_offset = swizzle.buffer_offset + map.offset;
118 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
119 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
120
121 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
122 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
123 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
124
125 glUniform1ui(2, params.bytes_per_block_log2);
126 glUniform1ui(3, params.layer_stride);
127 glUniform1ui(4, params.block_size);
128 glUniform1ui(5, params.x_shift);
129 glUniform1ui(6, params.block_height);
130 glUniform1ui(7, params.block_height_mask);
131
132 glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
133 GL_WRITE_ONLY, GL_RGBA8);
134 // ASTC texture data
135 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset,
136 image.guest_size_bytes - swizzle.buffer_offset);
137
138 glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
139 }
140 program_manager.RestoreGuestCompute();
141}
142
73void UtilShaders::BlockLinearUpload2D(Image& image, const ImageBufferMap& map, 143void UtilShaders::BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
74 std::span<const SwizzleParameters> swizzles) { 144 std::span<const SwizzleParameters> swizzles) {
75 static constexpr Extent3D WORKGROUP_SIZE{32, 32, 1}; 145 static constexpr Extent3D WORKGROUP_SIZE{32, 32, 1};
diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h
index 93b009743..53d65f368 100644
--- a/src/video_core/renderer_opengl/util_shaders.h
+++ b/src/video_core/renderer_opengl/util_shaders.h
@@ -40,6 +40,9 @@ public:
40 explicit UtilShaders(ProgramManager& program_manager); 40 explicit UtilShaders(ProgramManager& program_manager);
41 ~UtilShaders(); 41 ~UtilShaders();
42 42
43 void ASTCDecode(Image& image, const ImageBufferMap& map,
44 std::span<const VideoCommon::SwizzleParameters> swizzles);
45
43 void BlockLinearUpload2D(Image& image, const ImageBufferMap& map, 46 void BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
44 std::span<const VideoCommon::SwizzleParameters> swizzles); 47 std::span<const VideoCommon::SwizzleParameters> swizzles);
45 48
@@ -59,7 +62,9 @@ private:
59 ProgramManager& program_manager; 62 ProgramManager& program_manager;
60 63
61 OGLBuffer swizzle_table_buffer; 64 OGLBuffer swizzle_table_buffer;
65 OGLBuffer astc_buffer;
62 66
67 OGLProgram astc_decoder_program;
63 OGLProgram block_linear_unswizzle_2d_program; 68 OGLProgram block_linear_unswizzle_2d_program;
64 OGLProgram block_linear_unswizzle_3d_program; 69 OGLProgram block_linear_unswizzle_3d_program;
65 OGLProgram pitch_unswizzle_program; 70 OGLProgram pitch_unswizzle_program;
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 19aaf034f..f088447e9 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -166,7 +166,7 @@ struct FormatTuple {
166 {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT 166 {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT
167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM 167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM
168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT 168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT
169 {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB 169 {VK_FORMAT_A8B8G8R8_SRGB_PACK32, Attachable}, // A8B8G8R8_SRGB
170 {VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // R8G8_UNORM 170 {VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // R8G8_UNORM
171 {VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // R8G8_SNORM 171 {VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // R8G8_SNORM
172 {VK_FORMAT_R8G8_SINT, Attachable | Storage}, // R8G8_SINT 172 {VK_FORMAT_R8G8_SINT, Attachable | Storage}, // R8G8_SINT
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 1cc720ddd..2e0cf4232 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -13,11 +13,11 @@
13#include <fmt/format.h> 13#include <fmt/format.h>
14 14
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/settings.h"
16#include "common/telemetry.h" 17#include "common/telemetry.h"
17#include "core/core.h" 18#include "core/core.h"
18#include "core/core_timing.h" 19#include "core/core_timing.h"
19#include "core/frontend/emu_window.h" 20#include "core/frontend/emu_window.h"
20#include "core/settings.h"
21#include "core/telemetry_session.h" 21#include "core/telemetry_session.h"
22#include "video_core/gpu.h" 22#include "video_core/gpu.h"
23#include "video_core/renderer_vulkan/renderer_vulkan.h" 23#include "video_core/renderer_vulkan/renderer_vulkan.h"
@@ -143,7 +143,10 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
143 143
144 scheduler.WaitWorker(); 144 scheduler.WaitWorker();
145 145
146 swapchain.AcquireNextImage(); 146 while (!swapchain.AcquireNextImage()) {
147 swapchain.Create(layout.width, layout.height, is_srgb);
148 blit_screen.Recreate();
149 }
147 const VkSemaphore render_semaphore = blit_screen.Draw(*framebuffer, use_accelerated); 150 const VkSemaphore render_semaphore = blit_screen.Draw(*framebuffer, use_accelerated);
148 151
149 scheduler.Flush(render_semaphore); 152 scheduler.Flush(render_semaphore);
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 668633e7b..8cb65e588 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -176,7 +176,7 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset
176 u32 stride) { 176 u32 stride) {
177 if (device.IsExtExtendedDynamicStateSupported()) { 177 if (device.IsExtExtendedDynamicStateSupported()) {
178 scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) { 178 scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
179 const VkDeviceSize vk_offset = offset; 179 const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
180 const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE; 180 const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
181 const VkDeviceSize vk_stride = stride; 181 const VkDeviceSize vk_stride = stride;
182 cmdbuf.BindVertexBuffers2EXT(index, 1, &buffer, &vk_offset, &vk_size, &vk_stride); 182 cmdbuf.BindVertexBuffers2EXT(index, 1, &buffer, &vk_offset, &vk_size, &vk_stride);
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 2f9a7b028..e11406e58 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -11,18 +11,39 @@
11#include "common/assert.h" 11#include "common/assert.h"
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/div_ceil.h" 13#include "common/div_ceil.h"
14#include "video_core/host_shaders/astc_decoder_comp_spv.h"
14#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h" 15#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
15#include "video_core/host_shaders/vulkan_uint8_comp_spv.h" 16#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
16#include "video_core/renderer_vulkan/vk_compute_pass.h" 17#include "video_core/renderer_vulkan/vk_compute_pass.h"
17#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 18#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
18#include "video_core/renderer_vulkan/vk_scheduler.h" 19#include "video_core/renderer_vulkan/vk_scheduler.h"
19#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 20#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
21#include "video_core/renderer_vulkan/vk_texture_cache.h"
20#include "video_core/renderer_vulkan/vk_update_descriptor.h" 22#include "video_core/renderer_vulkan/vk_update_descriptor.h"
23#include "video_core/texture_cache/accelerated_swizzle.h"
24#include "video_core/texture_cache/types.h"
25#include "video_core/textures/astc.h"
26#include "video_core/textures/decoders.h"
21#include "video_core/vulkan_common/vulkan_device.h" 27#include "video_core/vulkan_common/vulkan_device.h"
22#include "video_core/vulkan_common/vulkan_wrapper.h" 28#include "video_core/vulkan_common/vulkan_wrapper.h"
23 29
24namespace Vulkan { 30namespace Vulkan {
31
32using Tegra::Texture::SWIZZLE_TABLE;
33using Tegra::Texture::ASTC::EncodingsValues;
34using namespace Tegra::Texture::ASTC;
35
25namespace { 36namespace {
37
38constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
39constexpr u32 ASTC_BINDING_ENC_BUFFER = 1;
40constexpr u32 ASTC_BINDING_6_TO_8_BUFFER = 2;
41constexpr u32 ASTC_BINDING_7_TO_8_BUFFER = 3;
42constexpr u32 ASTC_BINDING_8_TO_8_BUFFER = 4;
43constexpr u32 ASTC_BINDING_BYTE_TO_16_BUFFER = 5;
44constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 6;
45constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 7;
46
26VkPushConstantRange BuildComputePushConstantRange(std::size_t size) { 47VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
27 return { 48 return {
28 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, 49 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
@@ -50,6 +71,67 @@ std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBinding
50 }}; 71 }};
51} 72}
52 73
74std::array<VkDescriptorSetLayoutBinding, 8> BuildASTCDescriptorSetBindings() {
75 return {{
76 {
77 .binding = ASTC_BINDING_INPUT_BUFFER,
78 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
79 .descriptorCount = 1,
80 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
81 .pImmutableSamplers = nullptr,
82 },
83 {
84 .binding = ASTC_BINDING_ENC_BUFFER,
85 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
86 .descriptorCount = 1,
87 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
88 .pImmutableSamplers = nullptr,
89 },
90 {
91 .binding = ASTC_BINDING_6_TO_8_BUFFER,
92 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
93 .descriptorCount = 1,
94 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
95 .pImmutableSamplers = nullptr,
96 },
97 {
98 .binding = ASTC_BINDING_7_TO_8_BUFFER,
99 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
100 .descriptorCount = 1,
101 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
102 .pImmutableSamplers = nullptr,
103 },
104 {
105 .binding = ASTC_BINDING_8_TO_8_BUFFER,
106 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
107 .descriptorCount = 1,
108 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
109 .pImmutableSamplers = nullptr,
110 },
111 {
112 .binding = ASTC_BINDING_BYTE_TO_16_BUFFER,
113 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
114 .descriptorCount = 1,
115 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
116 .pImmutableSamplers = nullptr,
117 },
118 {
119 .binding = ASTC_BINDING_SWIZZLE_BUFFER,
120 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
121 .descriptorCount = 1,
122 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
123 .pImmutableSamplers = nullptr,
124 },
125 {
126 .binding = ASTC_BINDING_OUTPUT_IMAGE,
127 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
128 .descriptorCount = 1,
129 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
130 .pImmutableSamplers = nullptr,
131 },
132 }};
133}
134
53VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() { 135VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
54 return { 136 return {
55 .dstBinding = 0, 137 .dstBinding = 0,
@@ -61,6 +143,94 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
61 }; 143 };
62} 144}
63 145
146std::array<VkDescriptorUpdateTemplateEntryKHR, 8> BuildASTCPassDescriptorUpdateTemplateEntry() {
147 return {{
148 {
149 .dstBinding = ASTC_BINDING_INPUT_BUFFER,
150 .dstArrayElement = 0,
151 .descriptorCount = 1,
152 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
153 .offset = ASTC_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry),
154 .stride = sizeof(DescriptorUpdateEntry),
155 },
156 {
157 .dstBinding = ASTC_BINDING_ENC_BUFFER,
158 .dstArrayElement = 0,
159 .descriptorCount = 1,
160 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
161 .offset = ASTC_BINDING_ENC_BUFFER * sizeof(DescriptorUpdateEntry),
162 .stride = sizeof(DescriptorUpdateEntry),
163 },
164 {
165 .dstBinding = ASTC_BINDING_6_TO_8_BUFFER,
166 .dstArrayElement = 0,
167 .descriptorCount = 1,
168 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
169 .offset = ASTC_BINDING_6_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
170 .stride = sizeof(DescriptorUpdateEntry),
171 },
172 {
173 .dstBinding = ASTC_BINDING_7_TO_8_BUFFER,
174 .dstArrayElement = 0,
175 .descriptorCount = 1,
176 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
177 .offset = ASTC_BINDING_7_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
178 .stride = sizeof(DescriptorUpdateEntry),
179 },
180 {
181 .dstBinding = ASTC_BINDING_8_TO_8_BUFFER,
182 .dstArrayElement = 0,
183 .descriptorCount = 1,
184 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
185 .offset = ASTC_BINDING_8_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
186 .stride = sizeof(DescriptorUpdateEntry),
187 },
188 {
189 .dstBinding = ASTC_BINDING_BYTE_TO_16_BUFFER,
190 .dstArrayElement = 0,
191 .descriptorCount = 1,
192 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
193 .offset = ASTC_BINDING_BYTE_TO_16_BUFFER * sizeof(DescriptorUpdateEntry),
194 .stride = sizeof(DescriptorUpdateEntry),
195 },
196 {
197 .dstBinding = ASTC_BINDING_SWIZZLE_BUFFER,
198 .dstArrayElement = 0,
199 .descriptorCount = 1,
200 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
201 .offset = ASTC_BINDING_SWIZZLE_BUFFER * sizeof(DescriptorUpdateEntry),
202 .stride = sizeof(DescriptorUpdateEntry),
203 },
204 {
205 .dstBinding = ASTC_BINDING_OUTPUT_IMAGE,
206 .dstArrayElement = 0,
207 .descriptorCount = 1,
208 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
209 .offset = ASTC_BINDING_OUTPUT_IMAGE * sizeof(DescriptorUpdateEntry),
210 .stride = sizeof(DescriptorUpdateEntry),
211 },
212 }};
213}
214
215struct AstcPushConstants {
216 std::array<u32, 2> blocks_dims;
217 u32 bytes_per_block_log2;
218 u32 layer_stride;
219 u32 block_size;
220 u32 x_shift;
221 u32 block_height;
222 u32 block_height_mask;
223};
224
225struct AstcBufferData {
226 decltype(SWIZZLE_TABLE) swizzle_table_buffer = SWIZZLE_TABLE;
227 decltype(EncodingsValues) encoding_values = EncodingsValues;
228 decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
229 decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
230 decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
231 decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
232} constexpr ASTC_BUFFER_DATA;
233
64} // Anonymous namespace 234} // Anonymous namespace
65 235
66VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool, 236VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool,
@@ -238,4 +408,167 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
238 return {staging.buffer, staging.offset}; 408 return {staging.buffer, staging.offset};
239} 409}
240 410
411ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
412 VKDescriptorPool& descriptor_pool_,
413 StagingBufferPool& staging_buffer_pool_,
414 VKUpdateDescriptorQueue& update_descriptor_queue_,
415 MemoryAllocator& memory_allocator_)
416 : VKComputePass(device_, descriptor_pool_, BuildASTCDescriptorSetBindings(),
417 BuildASTCPassDescriptorUpdateTemplateEntry(),
418 BuildComputePushConstantRange(sizeof(AstcPushConstants)),
419 ASTC_DECODER_COMP_SPV),
420 device{device_}, scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
421 update_descriptor_queue{update_descriptor_queue_}, memory_allocator{memory_allocator_} {}
422
423ASTCDecoderPass::~ASTCDecoderPass() = default;
424
425void ASTCDecoderPass::MakeDataBuffer() {
426 constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_BUFFER_DATA) + sizeof(SWIZZLE_TABLE);
427 data_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
428 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
429 .pNext = nullptr,
430 .flags = 0,
431 .size = TOTAL_BUFFER_SIZE,
432 .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
433 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
434 .queueFamilyIndexCount = 0,
435 .pQueueFamilyIndices = nullptr,
436 });
437 data_buffer_commit = memory_allocator.Commit(data_buffer, MemoryUsage::Upload);
438
439 const auto staging_ref = staging_buffer_pool.Request(TOTAL_BUFFER_SIZE, MemoryUsage::Upload);
440 std::memcpy(staging_ref.mapped_span.data(), &ASTC_BUFFER_DATA, sizeof(ASTC_BUFFER_DATA));
441 // Tack on the swizzle table at the end of the buffer
442 std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_BUFFER_DATA), &SWIZZLE_TABLE,
443 sizeof(SWIZZLE_TABLE));
444
445 scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
446 TOTAL_BUFFER_SIZE](vk::CommandBuffer cmdbuf) {
447 cmdbuf.CopyBuffer(src, dst,
448 VkBufferCopy{
449 .srcOffset = offset,
450 .dstOffset = 0,
451 .size = TOTAL_BUFFER_SIZE,
452 });
453 cmdbuf.PipelineBarrier(
454 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
455 VkMemoryBarrier{
456 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
457 .pNext = nullptr,
458 .srcAccessMask = 0,
459 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
460 });
461 });
462}
463
464void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
465 std::span<const VideoCommon::SwizzleParameters> swizzles) {
466 using namespace VideoCommon::Accelerated;
467 const std::array<u32, 2> block_dims{
468 VideoCore::Surface::DefaultBlockWidth(image.info.format),
469 VideoCore::Surface::DefaultBlockHeight(image.info.format),
470 };
471 scheduler.RequestOutsideRenderPassOperationContext();
472 if (!data_buffer) {
473 MakeDataBuffer();
474 }
475 const VkPipeline vk_pipeline = *pipeline;
476 const VkImageAspectFlags aspect_mask = image.AspectMask();
477 const VkImage vk_image = image.Handle();
478 const bool is_initialized = image.ExchangeInitialization();
479 scheduler.Record(
480 [vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
481 const VkImageMemoryBarrier image_barrier{
482 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
483 .pNext = nullptr,
484 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
485 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
486 .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
487 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
488 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
489 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
490 .image = vk_image,
491 .subresourceRange{
492 .aspectMask = aspect_mask,
493 .baseMipLevel = 0,
494 .levelCount = VK_REMAINING_MIP_LEVELS,
495 .baseArrayLayer = 0,
496 .layerCount = VK_REMAINING_ARRAY_LAYERS,
497 },
498 };
499 cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : 0,
500 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
501 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
502 });
503 for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
504 const size_t input_offset = swizzle.buffer_offset + map.offset;
505 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
506 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
507 const u32 num_dispatches_z = image.info.resources.layers;
508
509 update_descriptor_queue.Acquire();
510 update_descriptor_queue.AddBuffer(map.buffer, input_offset,
511 image.guest_size_bytes - swizzle.buffer_offset);
512 update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, encoding_values),
513 sizeof(AstcBufferData::encoding_values));
514 update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_6_to_8),
515 sizeof(AstcBufferData::replicate_6_to_8));
516 update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_7_to_8),
517 sizeof(AstcBufferData::replicate_7_to_8));
518 update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_8_to_8),
519 sizeof(AstcBufferData::replicate_8_to_8));
520 update_descriptor_queue.AddBuffer(*data_buffer,
521 offsetof(AstcBufferData, replicate_byte_to_16),
522 sizeof(AstcBufferData::replicate_byte_to_16));
523 update_descriptor_queue.AddBuffer(*data_buffer, sizeof(AstcBufferData),
524 sizeof(SWIZZLE_TABLE));
525 update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
526
527 const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
528 const VkPipelineLayout vk_layout = *layout;
529
530 // To unswizzle the ASTC data
531 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
532 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
533 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
534 scheduler.Record([vk_layout, num_dispatches_x, num_dispatches_y, num_dispatches_z,
535 block_dims, params, set](vk::CommandBuffer cmdbuf) {
536 const AstcPushConstants uniforms{
537 .blocks_dims = block_dims,
538 .bytes_per_block_log2 = params.bytes_per_block_log2,
539 .layer_stride = params.layer_stride,
540 .block_size = params.block_size,
541 .x_shift = params.x_shift,
542 .block_height = params.block_height,
543 .block_height_mask = params.block_height_mask,
544 };
545 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, vk_layout, 0, set, {});
546 cmdbuf.PushConstants(vk_layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
547 cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, num_dispatches_z);
548 });
549 }
550 scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
551 const VkImageMemoryBarrier image_barrier{
552 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
553 .pNext = nullptr,
554 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
555 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
556 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
557 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
558 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
559 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
560 .image = vk_image,
561 .subresourceRange{
562 .aspectMask = aspect_mask,
563 .baseMipLevel = 0,
564 .levelCount = VK_REMAINING_MIP_LEVELS,
565 .baseArrayLayer = 0,
566 .layerCount = VK_REMAINING_ARRAY_LAYERS,
567 },
568 };
569 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
570 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, image_barrier);
571 });
572}
573
241} // namespace Vulkan 574} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index 17d781d99..5ea187c30 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -11,14 +11,21 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/engines/maxwell_3d.h" 12#include "video_core/engines/maxwell_3d.h"
13#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 13#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
14#include "video_core/vulkan_common/vulkan_memory_allocator.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
15 16
17namespace VideoCommon {
18struct SwizzleParameters;
19}
20
16namespace Vulkan { 21namespace Vulkan {
17 22
18class Device; 23class Device;
19class StagingBufferPool; 24class StagingBufferPool;
20class VKScheduler; 25class VKScheduler;
21class VKUpdateDescriptorQueue; 26class VKUpdateDescriptorQueue;
27class Image;
28struct StagingBufferRef;
22 29
23class VKComputePass { 30class VKComputePass {
24public: 31public:
@@ -77,4 +84,29 @@ private:
77 VKUpdateDescriptorQueue& update_descriptor_queue; 84 VKUpdateDescriptorQueue& update_descriptor_queue;
78}; 85};
79 86
87class ASTCDecoderPass final : public VKComputePass {
88public:
89 explicit ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
90 VKDescriptorPool& descriptor_pool_,
91 StagingBufferPool& staging_buffer_pool_,
92 VKUpdateDescriptorQueue& update_descriptor_queue_,
93 MemoryAllocator& memory_allocator_);
94 ~ASTCDecoderPass();
95
96 void Assemble(Image& image, const StagingBufferRef& map,
97 std::span<const VideoCommon::SwizzleParameters> swizzles);
98
99private:
100 void MakeDataBuffer();
101
102 const Device& device;
103 VKScheduler& scheduler;
104 StagingBufferPool& staging_buffer_pool;
105 VKUpdateDescriptorQueue& update_descriptor_queue;
106 MemoryAllocator& memory_allocator;
107
108 vk::Buffer data_buffer;
109 MemoryCommit data_buffer_commit;
110};
111
80} // namespace Vulkan 112} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
index 56ec5e380..db78ce3d9 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
@@ -5,7 +5,7 @@
5#include <atomic> 5#include <atomic>
6#include <chrono> 6#include <chrono>
7 7
8#include "core/settings.h" 8#include "common/settings.h"
9#include "video_core/renderer_vulkan/vk_master_semaphore.h" 9#include "video_core/renderer_vulkan/vk_master_semaphore.h"
10#include "video_core/vulkan_common/vulkan_device.h" 10#include "video_core/vulkan_common/vulkan_device.h"
11#include "video_core/vulkan_common/vulkan_wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h
index 2c7ed654d..4b6d64daa 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.h
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h
@@ -35,8 +35,8 @@ public:
35 } 35 }
36 36
37 /// Returns true when a tick has been hit by the GPU. 37 /// Returns true when a tick has been hit by the GPU.
38 [[nodiscard]] bool IsFree(u64 tick) { 38 [[nodiscard]] bool IsFree(u64 tick) const noexcept {
39 return gpu_tick.load(std::memory_order_relaxed) >= tick; 39 return KnownGpuTick() >= tick;
40 } 40 }
41 41
42 /// Advance to the logical tick. 42 /// Advance to the logical tick.
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index dfd38f575..e9a0e7811 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -13,8 +13,8 @@
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/microprofile.h" 14#include "common/microprofile.h"
15#include "common/scope_exit.h" 15#include "common/scope_exit.h"
16#include "common/settings.h"
16#include "core/core.h" 17#include "core/core.h"
17#include "core/settings.h"
18#include "video_core/engines/kepler_compute.h" 18#include "video_core/engines/kepler_compute.h"
19#include "video_core/engines/maxwell_3d.h" 19#include "video_core/engines/maxwell_3d.h"
20#include "video_core/renderer_vulkan/blit_image.h" 20#include "video_core/renderer_vulkan/blit_image.h"
@@ -241,7 +241,10 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
241 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), 241 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
242 update_descriptor_queue(device, scheduler), 242 update_descriptor_queue(device, scheduler),
243 blit_image(device, scheduler, state_tracker, descriptor_pool), 243 blit_image(device, scheduler, state_tracker, descriptor_pool),
244 texture_cache_runtime{device, scheduler, memory_allocator, staging_pool, blit_image}, 244 astc_decoder_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue,
245 memory_allocator),
246 texture_cache_runtime{device, scheduler, memory_allocator,
247 staging_pool, blit_image, astc_decoder_pass},
245 texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), 248 texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory),
246 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool, 249 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
247 update_descriptor_queue, descriptor_pool), 250 update_descriptor_queue, descriptor_pool),
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index acea1ba2d..235afc6f3 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -173,6 +173,7 @@ private:
173 VKDescriptorPool descriptor_pool; 173 VKDescriptorPool descriptor_pool;
174 VKUpdateDescriptorQueue update_descriptor_queue; 174 VKUpdateDescriptorQueue update_descriptor_queue;
175 BlitImageHelper blit_image; 175 BlitImageHelper blit_image;
176 ASTCDecoderPass astc_decoder_pass;
176 177
177 GraphicsPipelineCacheKey graphics_key; 178 GraphicsPipelineCacheKey graphics_key;
178 179
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 0b63bd6c8..dfd5c65ba 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -82,11 +82,13 @@ void VKSwapchain::Create(u32 width, u32 height, bool srgb) {
82 resource_ticks.resize(image_count); 82 resource_ticks.resize(image_count);
83} 83}
84 84
85void VKSwapchain::AcquireNextImage() { 85bool VKSwapchain::AcquireNextImage() {
86 device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(), 86 const VkResult result =
87 *present_semaphores[frame_index], {}, &image_index); 87 device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(),
88 *present_semaphores[frame_index], {}, &image_index);
88 89
89 scheduler.Wait(resource_ticks[image_index]); 90 scheduler.Wait(resource_ticks[image_index]);
91 return result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR;
90} 92}
91 93
92bool VKSwapchain::Present(VkSemaphore render_semaphore) { 94bool VKSwapchain::Present(VkSemaphore render_semaphore) {
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index a728511e0..adc8d27cf 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -28,7 +28,7 @@ public:
28 void Create(u32 width, u32 height, bool srgb); 28 void Create(u32 width, u32 height, bool srgb);
29 29
30 /// Acquires the next image in the swapchain, waits as needed. 30 /// Acquires the next image in the swapchain, waits as needed.
31 void AcquireNextImage(); 31 bool AcquireNextImage();
32 32
33 /// Presents the rendered image to the swapchain. Returns true when the swapchains had to be 33 /// Presents the rendered image to the swapchain. Returns true when the swapchains had to be
34 /// recreated. Takes responsability for the ownership of fence. 34 /// recreated. Takes responsability for the ownership of fence.
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 22a1014a9..bc2a53841 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -7,9 +7,12 @@
7#include <span> 7#include <span>
8#include <vector> 8#include <vector>
9 9
10#include "common/bit_cast.h"
11
10#include "video_core/engines/fermi_2d.h" 12#include "video_core/engines/fermi_2d.h"
11#include "video_core/renderer_vulkan/blit_image.h" 13#include "video_core/renderer_vulkan/blit_image.h"
12#include "video_core/renderer_vulkan/maxwell_to_vk.h" 14#include "video_core/renderer_vulkan/maxwell_to_vk.h"
15#include "video_core/renderer_vulkan/vk_compute_pass.h"
13#include "video_core/renderer_vulkan/vk_rasterizer.h" 16#include "video_core/renderer_vulkan/vk_rasterizer.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h" 17#include "video_core/renderer_vulkan/vk_scheduler.h"
15#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 18#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -807,7 +810,7 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
807 commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); 810 commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
808 } 811 }
809 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { 812 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
810 flags |= VideoCommon::ImageFlagBits::Converted; 813 flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
811 } 814 }
812 if (runtime.device.HasDebuggingToolAttached()) { 815 if (runtime.device.HasDebuggingToolAttached()) {
813 if (image) { 816 if (image) {
@@ -816,6 +819,38 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
816 buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); 819 buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
817 } 820 }
818 } 821 }
822 static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
823 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
824 .pNext = nullptr,
825 .usage = VK_IMAGE_USAGE_STORAGE_BIT,
826 };
827 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
828 const auto& device = runtime.device.GetLogical();
829 storage_image_views.reserve(info.resources.levels);
830 for (s32 level = 0; level < info.resources.levels; ++level) {
831 storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{
832 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
833 .pNext = &storage_image_view_usage_create_info,
834 .flags = 0,
835 .image = *image,
836 .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
837 .format = VK_FORMAT_A8B8G8R8_UNORM_PACK32,
838 .components{
839 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
840 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
841 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
842 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
843 },
844 .subresourceRange{
845 .aspectMask = aspect_mask,
846 .baseMipLevel = static_cast<u32>(level),
847 .levelCount = 1,
848 .baseArrayLayer = 0,
849 .layerCount = VK_REMAINING_ARRAY_LAYERS,
850 },
851 }));
852 }
853 }
819} 854}
820 855
821void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) { 856void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
@@ -918,7 +953,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
918 } 953 }
919 } 954 }
920 const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format); 955 const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
921 const VkFormat vk_format = format_info.format;
922 const VkImageViewUsageCreateInfo image_view_usage{ 956 const VkImageViewUsageCreateInfo image_view_usage{
923 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, 957 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
924 .pNext = nullptr, 958 .pNext = nullptr,
@@ -930,7 +964,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
930 .flags = 0, 964 .flags = 0,
931 .image = image.Handle(), 965 .image = image.Handle(),
932 .viewType = VkImageViewType{}, 966 .viewType = VkImageViewType{},
933 .format = vk_format, 967 .format = format_info.format,
934 .components{ 968 .components{
935 .r = ComponentSwizzle(swizzle[0]), 969 .r = ComponentSwizzle(swizzle[0]),
936 .g = ComponentSwizzle(swizzle[1]), 970 .g = ComponentSwizzle(swizzle[1]),
@@ -982,7 +1016,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
982 .pNext = nullptr, 1016 .pNext = nullptr,
983 .flags = 0, 1017 .flags = 0,
984 .buffer = image.Buffer(), 1018 .buffer = image.Buffer(),
985 .format = vk_format, 1019 .format = format_info.format,
986 .offset = 0, // TODO: Redesign buffer cache to support this 1020 .offset = 0, // TODO: Redesign buffer cache to support this
987 .range = image.guest_size_bytes, 1021 .range = image.guest_size_bytes,
988 }); 1022 });
@@ -1030,14 +1064,13 @@ vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) {
1030Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) { 1064Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) {
1031 const auto& device = runtime.device; 1065 const auto& device = runtime.device;
1032 const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported(); 1066 const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported();
1033 const std::array<float, 4> color = tsc.BorderColor(); 1067 const auto color = tsc.BorderColor();
1034 // C++20 bit_cast 1068
1035 VkClearColorValue border_color;
1036 std::memcpy(&border_color, &color, sizeof(color));
1037 const VkSamplerCustomBorderColorCreateInfoEXT border_ci{ 1069 const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
1038 .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT, 1070 .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
1039 .pNext = nullptr, 1071 .pNext = nullptr,
1040 .customBorderColor = border_color, 1072 // TODO: Make use of std::bit_cast once libc++ supports it.
1073 .customBorderColor = Common::BitCast<VkClearColorValue>(color),
1041 .format = VK_FORMAT_UNDEFINED, 1074 .format = VK_FORMAT_UNDEFINED,
1042 }; 1075 };
1043 const void* pnext = nullptr; 1076 const void* pnext = nullptr;
@@ -1167,4 +1200,13 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1167 } 1200 }
1168} 1201}
1169 1202
1203void TextureCacheRuntime::AccelerateImageUpload(
1204 Image& image, const StagingBufferRef& map,
1205 std::span<const VideoCommon::SwizzleParameters> swizzles) {
1206 if (IsPixelFormatASTC(image.info.format)) {
1207 return astc_decoder_pass.Assemble(image, map, swizzles);
1208 }
1209 UNREACHABLE();
1210}
1211
1170} // namespace Vulkan 1212} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 3aee27ce0..628785d5e 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -20,6 +20,7 @@ using VideoCommon::Offset2D;
20using VideoCommon::RenderTargets; 20using VideoCommon::RenderTargets;
21using VideoCore::Surface::PixelFormat; 21using VideoCore::Surface::PixelFormat;
22 22
23class ASTCDecoderPass;
23class BlitImageHelper; 24class BlitImageHelper;
24class Device; 25class Device;
25class Image; 26class Image;
@@ -60,6 +61,7 @@ struct TextureCacheRuntime {
60 MemoryAllocator& memory_allocator; 61 MemoryAllocator& memory_allocator;
61 StagingBufferPool& staging_buffer_pool; 62 StagingBufferPool& staging_buffer_pool;
62 BlitImageHelper& blit_image_helper; 63 BlitImageHelper& blit_image_helper;
64 ASTCDecoderPass& astc_decoder_pass;
63 std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache{}; 65 std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache{};
64 66
65 void Finish(); 67 void Finish();
@@ -83,9 +85,7 @@ struct TextureCacheRuntime {
83 } 85 }
84 86
85 void AccelerateImageUpload(Image&, const StagingBufferRef&, 87 void AccelerateImageUpload(Image&, const StagingBufferRef&,
86 std::span<const VideoCommon::SwizzleParameters>) { 88 std::span<const VideoCommon::SwizzleParameters>);
87 UNREACHABLE();
88 }
89 89
90 void InsertUploadMemoryBarrier() {} 90 void InsertUploadMemoryBarrier() {}
91 91
@@ -121,15 +121,26 @@ public:
121 return *buffer; 121 return *buffer;
122 } 122 }
123 123
124 [[nodiscard]] VkImageCreateFlags AspectMask() const noexcept { 124 [[nodiscard]] VkImageAspectFlags AspectMask() const noexcept {
125 return aspect_mask; 125 return aspect_mask;
126 } 126 }
127 127
128 [[nodiscard]] VkImageView StorageImageView(s32 level) const noexcept {
129 return *storage_image_views[level];
130 }
131
132 /// Returns true when the image is already initialized and mark it as initialized
133 [[nodiscard]] bool ExchangeInitialization() noexcept {
134 return std::exchange(initialized, true);
135 }
136
128private: 137private:
129 VKScheduler* scheduler; 138 VKScheduler* scheduler;
130 vk::Image image; 139 vk::Image image;
131 vk::Buffer buffer; 140 vk::Buffer buffer;
132 MemoryCommit commit; 141 MemoryCommit commit;
142 vk::ImageView image_view;
143 std::vector<vk::ImageView> storage_image_views;
133 VkImageAspectFlags aspect_mask = 0; 144 VkImageAspectFlags aspect_mask = 0;
134 bool initialized = false; 145 bool initialized = false;
135}; 146};
diff --git a/src/video_core/texture_cache/accelerated_swizzle.h b/src/video_core/texture_cache/accelerated_swizzle.h
index 6ec5c78c4..a11c924e1 100644
--- a/src/video_core/texture_cache/accelerated_swizzle.h
+++ b/src/video_core/texture_cache/accelerated_swizzle.h
@@ -13,8 +13,8 @@
13namespace VideoCommon::Accelerated { 13namespace VideoCommon::Accelerated {
14 14
15struct BlockLinearSwizzle2DParams { 15struct BlockLinearSwizzle2DParams {
16 std::array<u32, 3> origin; 16 alignas(16) std::array<u32, 3> origin;
17 std::array<s32, 3> destination; 17 alignas(16) std::array<s32, 3> destination;
18 u32 bytes_per_block_log2; 18 u32 bytes_per_block_log2;
19 u32 layer_stride; 19 u32 layer_stride;
20 u32 block_size; 20 u32 block_size;
diff --git a/src/video_core/texture_cache/image_view_base.cpp b/src/video_core/texture_cache/image_view_base.cpp
index f89a40b4c..e8d632f9e 100644
--- a/src/video_core/texture_cache/image_view_base.cpp
+++ b/src/video_core/texture_cache/image_view_base.cpp
@@ -5,7 +5,7 @@
5#include <algorithm> 5#include <algorithm>
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "core/settings.h" 8#include "common/settings.h"
9#include "video_core/compatible_formats.h" 9#include "video_core/compatible_formats.h"
10#include "video_core/surface.h" 10#include "video_core/surface.h"
11#include "video_core/texture_cache/formatter.h" 11#include "video_core/texture_cache/formatter.h"
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index 2c42d1449..0ab297413 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -47,7 +47,6 @@
47#include "video_core/texture_cache/formatter.h" 47#include "video_core/texture_cache/formatter.h"
48#include "video_core/texture_cache/samples_helper.h" 48#include "video_core/texture_cache/samples_helper.h"
49#include "video_core/texture_cache/util.h" 49#include "video_core/texture_cache/util.h"
50#include "video_core/textures/astc.h"
51#include "video_core/textures/decoders.h" 50#include "video_core/textures/decoders.h"
52 51
53namespace VideoCommon { 52namespace VideoCommon {
@@ -269,16 +268,19 @@ template <u32 GOB_EXTENT>
269 return num_tiles << shift; 268 return num_tiles << shift;
270} 269}
271 270
272[[nodiscard]] constexpr std::array<u32, MAX_MIP_LEVELS> CalculateLevelSizes(const LevelInfo& info, 271[[nodiscard]] constexpr LevelArray CalculateLevelSizes(const LevelInfo& info, u32 num_levels) {
273 u32 num_levels) {
274 ASSERT(num_levels <= MAX_MIP_LEVELS); 272 ASSERT(num_levels <= MAX_MIP_LEVELS);
275 std::array<u32, MAX_MIP_LEVELS> sizes{}; 273 LevelArray sizes{};
276 for (u32 level = 0; level < num_levels; ++level) { 274 for (u32 level = 0; level < num_levels; ++level) {
277 sizes[level] = CalculateLevelSize(info, level); 275 sizes[level] = CalculateLevelSize(info, level);
278 } 276 }
279 return sizes; 277 return sizes;
280} 278}
281 279
280[[nodiscard]] u32 CalculateLevelBytes(const LevelArray& sizes, u32 num_levels) {
281 return std::reduce(sizes.begin(), sizes.begin() + num_levels, 0U);
282}
283
282[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block, 284[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block,
283 u32 num_samples, u32 tile_width_spacing) { 285 u32 num_samples, u32 tile_width_spacing) {
284 const auto [samples_x, samples_y] = Samples(num_samples); 286 const auto [samples_x, samples_y] = Samples(num_samples);
@@ -567,10 +569,10 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr
567 569
568 const u32 num_levels = info.resources.levels; 570 const u32 num_levels = info.resources.levels;
569 const std::array sizes = CalculateLevelSizes(level_info, num_levels); 571 const std::array sizes = CalculateLevelSizes(level_info, num_levels);
570 size_t guest_offset = std::reduce(sizes.begin(), sizes.begin() + level, 0); 572 size_t guest_offset = CalculateLevelBytes(sizes, level);
571 const size_t layer_stride = 573 const size_t layer_stride =
572 AlignLayerSize(std::reduce(sizes.begin(), sizes.begin() + num_levels, 0), size, 574 AlignLayerSize(CalculateLevelBytes(sizes, num_levels), size, level_info.block,
573 level_info.block, tile_size.height, info.tile_width_spacing); 575 tile_size.height, info.tile_width_spacing);
574 const size_t subresource_size = sizes[level]; 576 const size_t subresource_size = sizes[level];
575 577
576 const auto dst_data = std::make_unique<u8[]>(subresource_size); 578 const auto dst_data = std::make_unique<u8[]>(subresource_size);
@@ -644,10 +646,10 @@ u32 CalculateLayerSize(const ImageInfo& info) noexcept {
644 info.tile_width_spacing, info.resources.levels); 646 info.tile_width_spacing, info.resources.levels);
645} 647}
646 648
647std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets(const ImageInfo& info) noexcept { 649LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept {
648 ASSERT(info.resources.levels <= static_cast<s32>(MAX_MIP_LEVELS)); 650 ASSERT(info.resources.levels <= static_cast<s32>(MAX_MIP_LEVELS));
649 const LevelInfo level_info = MakeLevelInfo(info); 651 const LevelInfo level_info = MakeLevelInfo(info);
650 std::array<u32, MAX_MIP_LEVELS> offsets{}; 652 LevelArray offsets{};
651 u32 offset = 0; 653 u32 offset = 0;
652 for (s32 level = 0; level < info.resources.levels; ++level) { 654 for (s32 level = 0; level < info.resources.levels; ++level) {
653 offsets[level] = offset; 655 offsets[level] = offset;
@@ -813,7 +815,7 @@ std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, GP
813 const Extent2D tile_size = DefaultBlockSize(info.format); 815 const Extent2D tile_size = DefaultBlockSize(info.format);
814 const std::array level_sizes = CalculateLevelSizes(level_info, num_levels); 816 const std::array level_sizes = CalculateLevelSizes(level_info, num_levels);
815 const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing); 817 const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing);
816 const u32 layer_size = std::reduce(level_sizes.begin(), level_sizes.begin() + num_levels, 0); 818 const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels);
817 const u32 layer_stride = AlignLayerSize(layer_size, size, level_info.block, tile_size.height, 819 const u32 layer_stride = AlignLayerSize(layer_size, size, level_info.block, tile_size.height,
818 info.tile_width_spacing); 820 info.tile_width_spacing);
819 size_t guest_offset = 0; 821 size_t guest_offset = 0;
@@ -879,17 +881,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
879 ASSERT(copy.image_extent == mip_size); 881 ASSERT(copy.image_extent == mip_size);
880 ASSERT(copy.buffer_row_length == Common::AlignUp(mip_size.width, tile_size.width)); 882 ASSERT(copy.buffer_row_length == Common::AlignUp(mip_size.width, tile_size.width));
881 ASSERT(copy.buffer_image_height == Common::AlignUp(mip_size.height, tile_size.height)); 883 ASSERT(copy.buffer_image_height == Common::AlignUp(mip_size.height, tile_size.height));
882 884 DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
883 if (IsPixelFormatASTC(info.format)) { 885 output.subspan(output_offset));
884 ASSERT(copy.image_extent.depth == 1);
885 Tegra::Texture::ASTC::Decompress(input.subspan(copy.buffer_offset),
886 copy.image_extent.width, copy.image_extent.height,
887 copy.image_subresource.num_layers, tile_size.width,
888 tile_size.height, output.subspan(output_offset));
889 } else {
890 DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
891 output.subspan(output_offset));
892 }
893 copy.buffer_offset = output_offset; 886 copy.buffer_offset = output_offset;
894 copy.buffer_row_length = mip_size.width; 887 copy.buffer_row_length = mip_size.width;
895 copy.buffer_image_height = mip_size.height; 888 copy.buffer_image_height = mip_size.height;
diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h
index 4d0072867..cdc5cbc75 100644
--- a/src/video_core/texture_cache/util.h
+++ b/src/video_core/texture_cache/util.h
@@ -20,6 +20,8 @@ namespace VideoCommon {
20 20
21using Tegra::Texture::TICEntry; 21using Tegra::Texture::TICEntry;
22 22
23using LevelArray = std::array<u32, MAX_MIP_LEVELS>;
24
23struct OverlapResult { 25struct OverlapResult {
24 GPUVAddr gpu_addr; 26 GPUVAddr gpu_addr;
25 VAddr cpu_addr; 27 VAddr cpu_addr;
@@ -36,8 +38,7 @@ struct OverlapResult {
36 38
37[[nodiscard]] u32 CalculateLayerSize(const ImageInfo& info) noexcept; 39[[nodiscard]] u32 CalculateLayerSize(const ImageInfo& info) noexcept;
38 40
39[[nodiscard]] std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets( 41[[nodiscard]] LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept;
40 const ImageInfo& info) noexcept;
41 42
42[[nodiscard]] std::vector<u32> CalculateSliceOffsets(const ImageInfo& info); 43[[nodiscard]] std::vector<u32> CalculateSliceOffsets(const ImageInfo& info);
43 44
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
deleted file mode 100644
index 3625b666c..000000000
--- a/src/video_core/textures/astc.cpp
+++ /dev/null
@@ -1,1710 +0,0 @@
1// Copyright 2016 The University of North Carolina at Chapel Hill
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
16// <http://gamma.cs.unc.edu/FasTC/>
17
18#include <algorithm>
19#include <cassert>
20#include <cstring>
21#include <span>
22#include <vector>
23
24#include <boost/container/static_vector.hpp>
25
26#include "common/common_types.h"
27
28#include "video_core/textures/astc.h"
29
30namespace {
31
32/// Count the number of bits set in a number.
33constexpr u32 Popcnt(u32 n) {
34 u32 c = 0;
35 for (; n; c++) {
36 n &= n - 1;
37 }
38 return c;
39}
40
41} // Anonymous namespace
42
43class InputBitStream {
44public:
45 constexpr explicit InputBitStream(std::span<const u8> data, size_t start_offset = 0)
46 : cur_byte{data.data()}, total_bits{data.size()}, next_bit{start_offset % 8} {}
47
48 constexpr size_t GetBitsRead() const {
49 return bits_read;
50 }
51
52 constexpr bool ReadBit() {
53 if (bits_read >= total_bits * 8) {
54 return 0;
55 }
56 const bool bit = ((*cur_byte >> next_bit) & 1) != 0;
57 ++next_bit;
58 while (next_bit >= 8) {
59 next_bit -= 8;
60 ++cur_byte;
61 }
62 ++bits_read;
63 return bit;
64 }
65
66 constexpr u32 ReadBits(std::size_t nBits) {
67 u32 ret = 0;
68 for (std::size_t i = 0; i < nBits; ++i) {
69 ret |= (ReadBit() & 1) << i;
70 }
71 return ret;
72 }
73
74 template <std::size_t nBits>
75 constexpr u32 ReadBits() {
76 u32 ret = 0;
77 for (std::size_t i = 0; i < nBits; ++i) {
78 ret |= (ReadBit() & 1) << i;
79 }
80 return ret;
81 }
82
83private:
84 const u8* cur_byte;
85 size_t total_bits = 0;
86 size_t next_bit = 0;
87 size_t bits_read = 0;
88};
89
90class OutputBitStream {
91public:
92 constexpr explicit OutputBitStream(u8* ptr, std::size_t bits = 0, std::size_t start_offset = 0)
93 : cur_byte{ptr}, num_bits{bits}, next_bit{start_offset % 8} {}
94
95 constexpr std::size_t GetBitsWritten() const {
96 return bits_written;
97 }
98
99 constexpr void WriteBitsR(u32 val, u32 nBits) {
100 for (u32 i = 0; i < nBits; i++) {
101 WriteBit((val >> (nBits - i - 1)) & 1);
102 }
103 }
104
105 constexpr void WriteBits(u32 val, u32 nBits) {
106 for (u32 i = 0; i < nBits; i++) {
107 WriteBit((val >> i) & 1);
108 }
109 }
110
111private:
112 constexpr void WriteBit(bool b) {
113 if (bits_written >= num_bits) {
114 return;
115 }
116
117 const u32 mask = 1 << next_bit++;
118
119 // clear the bit
120 *cur_byte &= static_cast<u8>(~mask);
121
122 // Write the bit, if necessary
123 if (b)
124 *cur_byte |= static_cast<u8>(mask);
125
126 // Next byte?
127 if (next_bit >= 8) {
128 cur_byte += 1;
129 next_bit = 0;
130 }
131 }
132
133 u8* cur_byte;
134 std::size_t num_bits;
135 std::size_t bits_written = 0;
136 std::size_t next_bit = 0;
137};
138
139template <typename IntType>
140class Bits {
141public:
142 explicit Bits(const IntType& v) : m_Bits(v) {}
143
144 Bits(const Bits&) = delete;
145 Bits& operator=(const Bits&) = delete;
146
147 u8 operator[](u32 bitPos) const {
148 return static_cast<u8>((m_Bits >> bitPos) & 1);
149 }
150
151 IntType operator()(u32 start, u32 end) const {
152 if (start == end) {
153 return (*this)[start];
154 } else if (start > end) {
155 u32 t = start;
156 start = end;
157 end = t;
158 }
159
160 u64 mask = (1 << (end - start + 1)) - 1;
161 return (m_Bits >> start) & static_cast<IntType>(mask);
162 }
163
164private:
165 const IntType& m_Bits;
166};
167
168enum class IntegerEncoding { JustBits, Qus32, Trit };
169
170struct IntegerEncodedValue {
171 constexpr IntegerEncodedValue() = default;
172
173 constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
174 : encoding{encoding_}, num_bits{num_bits_} {}
175
176 constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
177 return encoding == other.encoding && num_bits == other.num_bits;
178 }
179
180 // Returns the number of bits required to encode nVals values.
181 u32 GetBitLength(u32 nVals) const {
182 u32 totalBits = num_bits * nVals;
183 if (encoding == IntegerEncoding::Trit) {
184 totalBits += (nVals * 8 + 4) / 5;
185 } else if (encoding == IntegerEncoding::Qus32) {
186 totalBits += (nVals * 7 + 2) / 3;
187 }
188 return totalBits;
189 }
190
191 IntegerEncoding encoding{};
192 u32 num_bits = 0;
193 u32 bit_value = 0;
194 union {
195 u32 qus32_value = 0;
196 u32 trit_value;
197 };
198};
199using IntegerEncodedVector = boost::container::static_vector<
200 IntegerEncodedValue, 256,
201 boost::container::static_vector_options<
202 boost::container::inplace_alignment<alignof(IntegerEncodedValue)>,
203 boost::container::throw_on_overflow<false>>::type>;
204
205static void DecodeTritBlock(InputBitStream& bits, IntegerEncodedVector& result, u32 nBitsPerValue) {
206 // Implement the algorithm in section C.2.12
207 std::array<u32, 5> m;
208 std::array<u32, 5> t;
209 u32 T;
210
211 // Read the trit encoded block according to
212 // table C.2.14
213 m[0] = bits.ReadBits(nBitsPerValue);
214 T = bits.ReadBits<2>();
215 m[1] = bits.ReadBits(nBitsPerValue);
216 T |= bits.ReadBits<2>() << 2;
217 m[2] = bits.ReadBits(nBitsPerValue);
218 T |= bits.ReadBit() << 4;
219 m[3] = bits.ReadBits(nBitsPerValue);
220 T |= bits.ReadBits<2>() << 5;
221 m[4] = bits.ReadBits(nBitsPerValue);
222 T |= bits.ReadBit() << 7;
223
224 u32 C = 0;
225
226 Bits<u32> Tb(T);
227 if (Tb(2, 4) == 7) {
228 C = (Tb(5, 7) << 2) | Tb(0, 1);
229 t[4] = t[3] = 2;
230 } else {
231 C = Tb(0, 4);
232 if (Tb(5, 6) == 3) {
233 t[4] = 2;
234 t[3] = Tb[7];
235 } else {
236 t[4] = Tb[7];
237 t[3] = Tb(5, 6);
238 }
239 }
240
241 Bits<u32> Cb(C);
242 if (Cb(0, 1) == 3) {
243 t[2] = 2;
244 t[1] = Cb[4];
245 t[0] = (Cb[3] << 1) | (Cb[2] & ~Cb[3]);
246 } else if (Cb(2, 3) == 3) {
247 t[2] = 2;
248 t[1] = 2;
249 t[0] = Cb(0, 1);
250 } else {
251 t[2] = Cb[4];
252 t[1] = Cb(2, 3);
253 t[0] = (Cb[1] << 1) | (Cb[0] & ~Cb[1]);
254 }
255
256 for (std::size_t i = 0; i < 5; ++i) {
257 IntegerEncodedValue& val = result.emplace_back(IntegerEncoding::Trit, nBitsPerValue);
258 val.bit_value = m[i];
259 val.trit_value = t[i];
260 }
261}
262
263static void DecodeQus32Block(InputBitStream& bits, IntegerEncodedVector& result,
264 u32 nBitsPerValue) {
265 // Implement the algorithm in section C.2.12
266 u32 m[3];
267 u32 q[3];
268 u32 Q;
269
270 // Read the trit encoded block according to
271 // table C.2.15
272 m[0] = bits.ReadBits(nBitsPerValue);
273 Q = bits.ReadBits<3>();
274 m[1] = bits.ReadBits(nBitsPerValue);
275 Q |= bits.ReadBits<2>() << 3;
276 m[2] = bits.ReadBits(nBitsPerValue);
277 Q |= bits.ReadBits<2>() << 5;
278
279 Bits<u32> Qb(Q);
280 if (Qb(1, 2) == 3 && Qb(5, 6) == 0) {
281 q[0] = q[1] = 4;
282 q[2] = (Qb[0] << 2) | ((Qb[4] & ~Qb[0]) << 1) | (Qb[3] & ~Qb[0]);
283 } else {
284 u32 C = 0;
285 if (Qb(1, 2) == 3) {
286 q[2] = 4;
287 C = (Qb(3, 4) << 3) | ((~Qb(5, 6) & 3) << 1) | Qb[0];
288 } else {
289 q[2] = Qb(5, 6);
290 C = Qb(0, 4);
291 }
292
293 Bits<u32> Cb(C);
294 if (Cb(0, 2) == 5) {
295 q[1] = 4;
296 q[0] = Cb(3, 4);
297 } else {
298 q[1] = Cb(3, 4);
299 q[0] = Cb(0, 2);
300 }
301 }
302
303 for (std::size_t i = 0; i < 3; ++i) {
304 IntegerEncodedValue& val = result.emplace_back(IntegerEncoding::Qus32, nBitsPerValue);
305 val.bit_value = m[i];
306 val.qus32_value = q[i];
307 }
308}
309
310// Returns a new instance of this struct that corresponds to the
311// can take no more than maxval values
312static constexpr IntegerEncodedValue CreateEncoding(u32 maxVal) {
313 while (maxVal > 0) {
314 u32 check = maxVal + 1;
315
316 // Is maxVal a power of two?
317 if (!(check & (check - 1))) {
318 return IntegerEncodedValue(IntegerEncoding::JustBits, Popcnt(maxVal));
319 }
320
321 // Is maxVal of the type 3*2^n - 1?
322 if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
323 return IntegerEncodedValue(IntegerEncoding::Trit, Popcnt(check / 3 - 1));
324 }
325
326 // Is maxVal of the type 5*2^n - 1?
327 if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
328 return IntegerEncodedValue(IntegerEncoding::Qus32, Popcnt(check / 5 - 1));
329 }
330
331 // Apparently it can't be represented with a bounded integer sequence...
332 // just iterate.
333 maxVal--;
334 }
335 return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
336}
337
338static constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
339 std::array<IntegerEncodedValue, 256> encodings{};
340 for (std::size_t i = 0; i < encodings.size(); ++i) {
341 encodings[i] = CreateEncoding(static_cast<u32>(i));
342 }
343 return encodings;
344}
345
346static constexpr std::array EncodingsValues = MakeEncodedValues();
347
348// Fills result with the values that are encoded in the given
349// bitstream. We must know beforehand what the maximum possible
350// value is, and how many values we're decoding.
351static void DecodeIntegerSequence(IntegerEncodedVector& result, InputBitStream& bits, u32 maxRange,
352 u32 nValues) {
353 // Determine encoding parameters
354 IntegerEncodedValue val = EncodingsValues[maxRange];
355
356 // Start decoding
357 u32 nValsDecoded = 0;
358 while (nValsDecoded < nValues) {
359 switch (val.encoding) {
360 case IntegerEncoding::Qus32:
361 DecodeQus32Block(bits, result, val.num_bits);
362 nValsDecoded += 3;
363 break;
364
365 case IntegerEncoding::Trit:
366 DecodeTritBlock(bits, result, val.num_bits);
367 nValsDecoded += 5;
368 break;
369
370 case IntegerEncoding::JustBits:
371 val.bit_value = bits.ReadBits(val.num_bits);
372 result.push_back(val);
373 nValsDecoded++;
374 break;
375 }
376 }
377}
378
379namespace ASTCC {
380
381struct TexelWeightParams {
382 u32 m_Width = 0;
383 u32 m_Height = 0;
384 bool m_bDualPlane = false;
385 u32 m_MaxWeight = 0;
386 bool m_bError = false;
387 bool m_bVoidExtentLDR = false;
388 bool m_bVoidExtentHDR = false;
389
390 u32 GetPackedBitSize() const {
391 // How many indices do we have?
392 u32 nIdxs = m_Height * m_Width;
393 if (m_bDualPlane) {
394 nIdxs *= 2;
395 }
396
397 return EncodingsValues[m_MaxWeight].GetBitLength(nIdxs);
398 }
399
400 u32 GetNumWeightValues() const {
401 u32 ret = m_Width * m_Height;
402 if (m_bDualPlane) {
403 ret *= 2;
404 }
405 return ret;
406 }
407};
408
409static TexelWeightParams DecodeBlockInfo(InputBitStream& strm) {
410 TexelWeightParams params;
411
412 // Read the entire block mode all at once
413 u16 modeBits = static_cast<u16>(strm.ReadBits<11>());
414
415 // Does this match the void extent block mode?
416 if ((modeBits & 0x01FF) == 0x1FC) {
417 if (modeBits & 0x200) {
418 params.m_bVoidExtentHDR = true;
419 } else {
420 params.m_bVoidExtentLDR = true;
421 }
422
423 // Next two bits must be one.
424 if (!(modeBits & 0x400) || !strm.ReadBit()) {
425 params.m_bError = true;
426 }
427
428 return params;
429 }
430
431 // First check if the last four bits are zero
432 if ((modeBits & 0xF) == 0) {
433 params.m_bError = true;
434 return params;
435 }
436
437 // If the last two bits are zero, then if bits
438 // [6-8] are all ones, this is also reserved.
439 if ((modeBits & 0x3) == 0 && (modeBits & 0x1C0) == 0x1C0) {
440 params.m_bError = true;
441 return params;
442 }
443
444 // Otherwise, there is no error... Figure out the layout
445 // of the block mode. Layout is determined by a number
446 // between 0 and 9 corresponding to table C.2.8 of the
447 // ASTC spec.
448 u32 layout = 0;
449
450 if ((modeBits & 0x1) || (modeBits & 0x2)) {
451 // layout is in [0-4]
452 if (modeBits & 0x8) {
453 // layout is in [2-4]
454 if (modeBits & 0x4) {
455 // layout is in [3-4]
456 if (modeBits & 0x100) {
457 layout = 4;
458 } else {
459 layout = 3;
460 }
461 } else {
462 layout = 2;
463 }
464 } else {
465 // layout is in [0-1]
466 if (modeBits & 0x4) {
467 layout = 1;
468 } else {
469 layout = 0;
470 }
471 }
472 } else {
473 // layout is in [5-9]
474 if (modeBits & 0x100) {
475 // layout is in [7-9]
476 if (modeBits & 0x80) {
477 // layout is in [7-8]
478 assert((modeBits & 0x40) == 0U);
479 if (modeBits & 0x20) {
480 layout = 8;
481 } else {
482 layout = 7;
483 }
484 } else {
485 layout = 9;
486 }
487 } else {
488 // layout is in [5-6]
489 if (modeBits & 0x80) {
490 layout = 6;
491 } else {
492 layout = 5;
493 }
494 }
495 }
496
497 assert(layout < 10);
498
499 // Determine R
500 u32 R = !!(modeBits & 0x10);
501 if (layout < 5) {
502 R |= (modeBits & 0x3) << 1;
503 } else {
504 R |= (modeBits & 0xC) >> 1;
505 }
506 assert(2 <= R && R <= 7);
507
508 // Determine width & height
509 switch (layout) {
510 case 0: {
511 u32 A = (modeBits >> 5) & 0x3;
512 u32 B = (modeBits >> 7) & 0x3;
513 params.m_Width = B + 4;
514 params.m_Height = A + 2;
515 break;
516 }
517
518 case 1: {
519 u32 A = (modeBits >> 5) & 0x3;
520 u32 B = (modeBits >> 7) & 0x3;
521 params.m_Width = B + 8;
522 params.m_Height = A + 2;
523 break;
524 }
525
526 case 2: {
527 u32 A = (modeBits >> 5) & 0x3;
528 u32 B = (modeBits >> 7) & 0x3;
529 params.m_Width = A + 2;
530 params.m_Height = B + 8;
531 break;
532 }
533
534 case 3: {
535 u32 A = (modeBits >> 5) & 0x3;
536 u32 B = (modeBits >> 7) & 0x1;
537 params.m_Width = A + 2;
538 params.m_Height = B + 6;
539 break;
540 }
541
542 case 4: {
543 u32 A = (modeBits >> 5) & 0x3;
544 u32 B = (modeBits >> 7) & 0x1;
545 params.m_Width = B + 2;
546 params.m_Height = A + 2;
547 break;
548 }
549
550 case 5: {
551 u32 A = (modeBits >> 5) & 0x3;
552 params.m_Width = 12;
553 params.m_Height = A + 2;
554 break;
555 }
556
557 case 6: {
558 u32 A = (modeBits >> 5) & 0x3;
559 params.m_Width = A + 2;
560 params.m_Height = 12;
561 break;
562 }
563
564 case 7: {
565 params.m_Width = 6;
566 params.m_Height = 10;
567 break;
568 }
569
570 case 8: {
571 params.m_Width = 10;
572 params.m_Height = 6;
573 break;
574 }
575
576 case 9: {
577 u32 A = (modeBits >> 5) & 0x3;
578 u32 B = (modeBits >> 9) & 0x3;
579 params.m_Width = A + 6;
580 params.m_Height = B + 6;
581 break;
582 }
583
584 default:
585 assert(false && "Don't know this layout...");
586 params.m_bError = true;
587 break;
588 }
589
590 // Determine whether or not we're using dual planes
591 // and/or high precision layouts.
592 bool D = (layout != 9) && (modeBits & 0x400);
593 bool H = (layout != 9) && (modeBits & 0x200);
594
595 if (H) {
596 const u32 maxWeights[6] = {9, 11, 15, 19, 23, 31};
597 params.m_MaxWeight = maxWeights[R - 2];
598 } else {
599 const u32 maxWeights[6] = {1, 2, 3, 4, 5, 7};
600 params.m_MaxWeight = maxWeights[R - 2];
601 }
602
603 params.m_bDualPlane = D;
604
605 return params;
606}
607
608static void FillVoidExtentLDR(InputBitStream& strm, std::span<u32> outBuf, u32 blockWidth,
609 u32 blockHeight) {
610 // Don't actually care about the void extent, just read the bits...
611 for (s32 i = 0; i < 4; ++i) {
612 strm.ReadBits<13>();
613 }
614
615 // Decode the RGBA components and renormalize them to the range [0, 255]
616 u16 r = static_cast<u16>(strm.ReadBits<16>());
617 u16 g = static_cast<u16>(strm.ReadBits<16>());
618 u16 b = static_cast<u16>(strm.ReadBits<16>());
619 u16 a = static_cast<u16>(strm.ReadBits<16>());
620
621 u32 rgba = (r >> 8) | (g & 0xFF00) | (static_cast<u32>(b) & 0xFF00) << 8 |
622 (static_cast<u32>(a) & 0xFF00) << 16;
623
624 for (u32 j = 0; j < blockHeight; j++) {
625 for (u32 i = 0; i < blockWidth; i++) {
626 outBuf[j * blockWidth + i] = rgba;
627 }
628 }
629}
630
631static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) {
632 for (u32 j = 0; j < blockHeight; j++) {
633 for (u32 i = 0; i < blockWidth; i++) {
634 outBuf[j * blockWidth + i] = 0xFFFF00FF;
635 }
636 }
637}
638
639// Replicates low numBits such that [(toBit - 1):(toBit - 1 - fromBit)]
640// is the same as [(numBits - 1):0] and repeats all the way down.
641template <typename IntType>
642static constexpr IntType Replicate(IntType val, u32 numBits, u32 toBit) {
643 if (numBits == 0) {
644 return 0;
645 }
646 if (toBit == 0) {
647 return 0;
648 }
649 const IntType v = val & static_cast<IntType>((1 << numBits) - 1);
650 IntType res = v;
651 u32 reslen = numBits;
652 while (reslen < toBit) {
653 u32 comp = 0;
654 if (numBits > toBit - reslen) {
655 u32 newshift = toBit - reslen;
656 comp = numBits - newshift;
657 numBits = newshift;
658 }
659 res = static_cast<IntType>(res << numBits);
660 res = static_cast<IntType>(res | (v >> comp));
661 reslen += numBits;
662 }
663 return res;
664}
665
666static constexpr std::size_t NumReplicateEntries(u32 num_bits) {
667 return std::size_t(1) << num_bits;
668}
669
670template <typename IntType, u32 num_bits, u32 to_bit>
671static constexpr auto MakeReplicateTable() {
672 std::array<IntType, NumReplicateEntries(num_bits)> table{};
673 for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
674 table[value] = Replicate(value, num_bits, to_bit);
675 }
676 return table;
677}
678
679static constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
680static constexpr u32 ReplicateByteTo16(std::size_t value) {
681 return REPLICATE_BYTE_TO_16_TABLE[value];
682}
683
684static constexpr auto REPLICATE_BIT_TO_7_TABLE = MakeReplicateTable<u32, 1, 7>();
685static constexpr u32 ReplicateBitTo7(std::size_t value) {
686 return REPLICATE_BIT_TO_7_TABLE[value];
687}
688
689static constexpr auto REPLICATE_BIT_TO_9_TABLE = MakeReplicateTable<u32, 1, 9>();
690static constexpr u32 ReplicateBitTo9(std::size_t value) {
691 return REPLICATE_BIT_TO_9_TABLE[value];
692}
693
694static constexpr auto REPLICATE_1_BIT_TO_8_TABLE = MakeReplicateTable<u32, 1, 8>();
695static constexpr auto REPLICATE_2_BIT_TO_8_TABLE = MakeReplicateTable<u32, 2, 8>();
696static constexpr auto REPLICATE_3_BIT_TO_8_TABLE = MakeReplicateTable<u32, 3, 8>();
697static constexpr auto REPLICATE_4_BIT_TO_8_TABLE = MakeReplicateTable<u32, 4, 8>();
698static constexpr auto REPLICATE_5_BIT_TO_8_TABLE = MakeReplicateTable<u32, 5, 8>();
699static constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
700static constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
701static constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
702/// Use a precompiled table with the most common usages, if it's not in the expected range, fallback
703/// to the runtime implementation
704static constexpr u32 FastReplicateTo8(u32 value, u32 num_bits) {
705 switch (num_bits) {
706 case 1:
707 return REPLICATE_1_BIT_TO_8_TABLE[value];
708 case 2:
709 return REPLICATE_2_BIT_TO_8_TABLE[value];
710 case 3:
711 return REPLICATE_3_BIT_TO_8_TABLE[value];
712 case 4:
713 return REPLICATE_4_BIT_TO_8_TABLE[value];
714 case 5:
715 return REPLICATE_5_BIT_TO_8_TABLE[value];
716 case 6:
717 return REPLICATE_6_BIT_TO_8_TABLE[value];
718 case 7:
719 return REPLICATE_7_BIT_TO_8_TABLE[value];
720 case 8:
721 return REPLICATE_8_BIT_TO_8_TABLE[value];
722 default:
723 return Replicate(value, num_bits, 8);
724 }
725}
726
727static constexpr auto REPLICATE_1_BIT_TO_6_TABLE = MakeReplicateTable<u32, 1, 6>();
728static constexpr auto REPLICATE_2_BIT_TO_6_TABLE = MakeReplicateTable<u32, 2, 6>();
729static constexpr auto REPLICATE_3_BIT_TO_6_TABLE = MakeReplicateTable<u32, 3, 6>();
730static constexpr auto REPLICATE_4_BIT_TO_6_TABLE = MakeReplicateTable<u32, 4, 6>();
731static constexpr auto REPLICATE_5_BIT_TO_6_TABLE = MakeReplicateTable<u32, 5, 6>();
732static constexpr u32 FastReplicateTo6(u32 value, u32 num_bits) {
733 switch (num_bits) {
734 case 1:
735 return REPLICATE_1_BIT_TO_6_TABLE[value];
736 case 2:
737 return REPLICATE_2_BIT_TO_6_TABLE[value];
738 case 3:
739 return REPLICATE_3_BIT_TO_6_TABLE[value];
740 case 4:
741 return REPLICATE_4_BIT_TO_6_TABLE[value];
742 case 5:
743 return REPLICATE_5_BIT_TO_6_TABLE[value];
744 default:
745 return Replicate(value, num_bits, 6);
746 }
747}
748
749class Pixel {
750protected:
751 using ChannelType = s16;
752 u8 m_BitDepth[4] = {8, 8, 8, 8};
753 s16 color[4] = {};
754
755public:
756 Pixel() = default;
757 Pixel(u32 a, u32 r, u32 g, u32 b, u32 bitDepth = 8)
758 : m_BitDepth{u8(bitDepth), u8(bitDepth), u8(bitDepth), u8(bitDepth)},
759 color{static_cast<ChannelType>(a), static_cast<ChannelType>(r),
760 static_cast<ChannelType>(g), static_cast<ChannelType>(b)} {}
761
762 // Changes the depth of each pixel. This scales the values to
763 // the appropriate bit depth by either truncating the least
764 // significant bits when going from larger to smaller bit depth
765 // or by repeating the most significant bits when going from
766 // smaller to larger bit depths.
767 void ChangeBitDepth() {
768 for (u32 i = 0; i < 4; i++) {
769 Component(i) = ChangeBitDepth(Component(i), m_BitDepth[i]);
770 m_BitDepth[i] = 8;
771 }
772 }
773
774 template <typename IntType>
775 static float ConvertChannelToFloat(IntType channel, u8 bitDepth) {
776 float denominator = static_cast<float>((1 << bitDepth) - 1);
777 return static_cast<float>(channel) / denominator;
778 }
779
780 // Changes the bit depth of a single component. See the comment
781 // above for how we do this.
782 static ChannelType ChangeBitDepth(Pixel::ChannelType val, u8 oldDepth) {
783 assert(oldDepth <= 8);
784
785 if (oldDepth == 8) {
786 // Do nothing
787 return val;
788 } else if (oldDepth == 0) {
789 return static_cast<ChannelType>((1 << 8) - 1);
790 } else if (8 > oldDepth) {
791 return static_cast<ChannelType>(FastReplicateTo8(static_cast<u32>(val), oldDepth));
792 } else {
793 // oldDepth > newDepth
794 const u8 bitsWasted = static_cast<u8>(oldDepth - 8);
795 u16 v = static_cast<u16>(val);
796 v = static_cast<u16>((v + (1 << (bitsWasted - 1))) >> bitsWasted);
797 v = ::std::min<u16>(::std::max<u16>(0, v), static_cast<u16>((1 << 8) - 1));
798 return static_cast<u8>(v);
799 }
800
801 assert(false && "We shouldn't get here.");
802 return 0;
803 }
804
805 const ChannelType& A() const {
806 return color[0];
807 }
808 ChannelType& A() {
809 return color[0];
810 }
811 const ChannelType& R() const {
812 return color[1];
813 }
814 ChannelType& R() {
815 return color[1];
816 }
817 const ChannelType& G() const {
818 return color[2];
819 }
820 ChannelType& G() {
821 return color[2];
822 }
823 const ChannelType& B() const {
824 return color[3];
825 }
826 ChannelType& B() {
827 return color[3];
828 }
829 const ChannelType& Component(u32 idx) const {
830 return color[idx];
831 }
832 ChannelType& Component(u32 idx) {
833 return color[idx];
834 }
835
836 void GetBitDepth(u8 (&outDepth)[4]) const {
837 for (s32 i = 0; i < 4; i++) {
838 outDepth[i] = m_BitDepth[i];
839 }
840 }
841
842 // Take all of the components, transform them to their 8-bit variants,
843 // and then pack each channel into an R8G8B8A8 32-bit integer. We assume
844 // that the architecture is little-endian, so the alpha channel will end
845 // up in the most-significant byte.
846 u32 Pack() const {
847 Pixel eightBit(*this);
848 eightBit.ChangeBitDepth();
849
850 u32 r = 0;
851 r |= eightBit.A();
852 r <<= 8;
853 r |= eightBit.B();
854 r <<= 8;
855 r |= eightBit.G();
856 r <<= 8;
857 r |= eightBit.R();
858 return r;
859 }
860
861 // Clamps the pixel to the range [0,255]
862 void ClampByte() {
863 for (u32 i = 0; i < 4; i++) {
864 color[i] = (color[i] < 0) ? 0 : ((color[i] > 255) ? 255 : color[i]);
865 }
866 }
867
868 void MakeOpaque() {
869 A() = 255;
870 }
871};
872
873static void DecodeColorValues(u32* out, std::span<u8> data, const u32* modes, const u32 nPartitions,
874 const u32 nBitsForColorData) {
875 // First figure out how many color values we have
876 u32 nValues = 0;
877 for (u32 i = 0; i < nPartitions; i++) {
878 nValues += ((modes[i] >> 2) + 1) << 1;
879 }
880
881 // Then based on the number of values and the remaining number of bits,
882 // figure out the max value for each of them...
883 u32 range = 256;
884 while (--range > 0) {
885 IntegerEncodedValue val = EncodingsValues[range];
886 u32 bitLength = val.GetBitLength(nValues);
887 if (bitLength <= nBitsForColorData) {
888 // Find the smallest possible range that matches the given encoding
889 while (--range > 0) {
890 IntegerEncodedValue newval = EncodingsValues[range];
891 if (!newval.MatchesEncoding(val)) {
892 break;
893 }
894 }
895
896 // Return to last matching range.
897 range++;
898 break;
899 }
900 }
901
902 // We now have enough to decode our integer sequence.
903 IntegerEncodedVector decodedColorValues;
904
905 InputBitStream colorStream(data, 0);
906 DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues);
907
908 // Once we have the decoded values, we need to dequantize them to the 0-255 range
909 // This procedure is outlined in ASTC spec C.2.13
910 u32 outIdx = 0;
911 for (auto itr = decodedColorValues.begin(); itr != decodedColorValues.end(); ++itr) {
912 // Have we already decoded all that we need?
913 if (outIdx >= nValues) {
914 break;
915 }
916
917 const IntegerEncodedValue& val = *itr;
918 u32 bitlen = val.num_bits;
919 u32 bitval = val.bit_value;
920
921 assert(bitlen >= 1);
922
923 u32 A = 0, B = 0, C = 0, D = 0;
924 // A is just the lsb replicated 9 times.
925 A = ReplicateBitTo9(bitval & 1);
926
927 switch (val.encoding) {
928 // Replicate bits
929 case IntegerEncoding::JustBits:
930 out[outIdx++] = FastReplicateTo8(bitval, bitlen);
931 break;
932
933 // Use algorithm in C.2.13
934 case IntegerEncoding::Trit: {
935
936 D = val.trit_value;
937
938 switch (bitlen) {
939 case 1: {
940 C = 204;
941 } break;
942
943 case 2: {
944 C = 93;
945 // B = b000b0bb0
946 u32 b = (bitval >> 1) & 1;
947 B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
948 } break;
949
950 case 3: {
951 C = 44;
952 // B = cb000cbcb
953 u32 cb = (bitval >> 1) & 3;
954 B = (cb << 7) | (cb << 2) | cb;
955 } break;
956
957 case 4: {
958 C = 22;
959 // B = dcb000dcb
960 u32 dcb = (bitval >> 1) & 7;
961 B = (dcb << 6) | dcb;
962 } break;
963
964 case 5: {
965 C = 11;
966 // B = edcb000ed
967 u32 edcb = (bitval >> 1) & 0xF;
968 B = (edcb << 5) | (edcb >> 2);
969 } break;
970
971 case 6: {
972 C = 5;
973 // B = fedcb000f
974 u32 fedcb = (bitval >> 1) & 0x1F;
975 B = (fedcb << 4) | (fedcb >> 4);
976 } break;
977
978 default:
979 assert(false && "Unsupported trit encoding for color values!");
980 break;
981 } // switch(bitlen)
982 } // case IntegerEncoding::Trit
983 break;
984
985 case IntegerEncoding::Qus32: {
986
987 D = val.qus32_value;
988
989 switch (bitlen) {
990 case 1: {
991 C = 113;
992 } break;
993
994 case 2: {
995 C = 54;
996 // B = b0000bb00
997 u32 b = (bitval >> 1) & 1;
998 B = (b << 8) | (b << 3) | (b << 2);
999 } break;
1000
1001 case 3: {
1002 C = 26;
1003 // B = cb0000cbc
1004 u32 cb = (bitval >> 1) & 3;
1005 B = (cb << 7) | (cb << 1) | (cb >> 1);
1006 } break;
1007
1008 case 4: {
1009 C = 13;
1010 // B = dcb0000dc
1011 u32 dcb = (bitval >> 1) & 7;
1012 B = (dcb << 6) | (dcb >> 1);
1013 } break;
1014
1015 case 5: {
1016 C = 6;
1017 // B = edcb0000e
1018 u32 edcb = (bitval >> 1) & 0xF;
1019 B = (edcb << 5) | (edcb >> 3);
1020 } break;
1021
1022 default:
1023 assert(false && "Unsupported quint encoding for color values!");
1024 break;
1025 } // switch(bitlen)
1026 } // case IntegerEncoding::Qus32
1027 break;
1028 } // switch(val.encoding)
1029
1030 if (val.encoding != IntegerEncoding::JustBits) {
1031 u32 T = D * C + B;
1032 T ^= A;
1033 T = (A & 0x80) | (T >> 2);
1034 out[outIdx++] = T;
1035 }
1036 }
1037
1038 // Make sure that each of our values is in the proper range...
1039 for (u32 i = 0; i < nValues; i++) {
1040 assert(out[i] <= 255);
1041 }
1042}
1043
1044static u32 UnquantizeTexelWeight(const IntegerEncodedValue& val) {
1045 u32 bitval = val.bit_value;
1046 u32 bitlen = val.num_bits;
1047
1048 u32 A = ReplicateBitTo7(bitval & 1);
1049 u32 B = 0, C = 0, D = 0;
1050
1051 u32 result = 0;
1052 switch (val.encoding) {
1053 case IntegerEncoding::JustBits:
1054 result = FastReplicateTo6(bitval, bitlen);
1055 break;
1056
1057 case IntegerEncoding::Trit: {
1058 D = val.trit_value;
1059 assert(D < 3);
1060
1061 switch (bitlen) {
1062 case 0: {
1063 u32 results[3] = {0, 32, 63};
1064 result = results[D];
1065 } break;
1066
1067 case 1: {
1068 C = 50;
1069 } break;
1070
1071 case 2: {
1072 C = 23;
1073 u32 b = (bitval >> 1) & 1;
1074 B = (b << 6) | (b << 2) | b;
1075 } break;
1076
1077 case 3: {
1078 C = 11;
1079 u32 cb = (bitval >> 1) & 3;
1080 B = (cb << 5) | cb;
1081 } break;
1082
1083 default:
1084 assert(false && "Invalid trit encoding for texel weight");
1085 break;
1086 }
1087 } break;
1088
1089 case IntegerEncoding::Qus32: {
1090 D = val.qus32_value;
1091 assert(D < 5);
1092
1093 switch (bitlen) {
1094 case 0: {
1095 u32 results[5] = {0, 16, 32, 47, 63};
1096 result = results[D];
1097 } break;
1098
1099 case 1: {
1100 C = 28;
1101 } break;
1102
1103 case 2: {
1104 C = 13;
1105 u32 b = (bitval >> 1) & 1;
1106 B = (b << 6) | (b << 1);
1107 } break;
1108
1109 default:
1110 assert(false && "Invalid quint encoding for texel weight");
1111 break;
1112 }
1113 } break;
1114 }
1115
1116 if (val.encoding != IntegerEncoding::JustBits && bitlen > 0) {
1117 // Decode the value...
1118 result = D * C + B;
1119 result ^= A;
1120 result = (A & 0x20) | (result >> 2);
1121 }
1122
1123 assert(result < 64);
1124
1125 // Change from [0,63] to [0,64]
1126 if (result > 32) {
1127 result += 1;
1128 }
1129
1130 return result;
1131}
1132
1133static void UnquantizeTexelWeights(u32 out[2][144], const IntegerEncodedVector& weights,
1134 const TexelWeightParams& params, const u32 blockWidth,
1135 const u32 blockHeight) {
1136 u32 weightIdx = 0;
1137 u32 unquantized[2][144];
1138
1139 for (auto itr = weights.begin(); itr != weights.end(); ++itr) {
1140 unquantized[0][weightIdx] = UnquantizeTexelWeight(*itr);
1141
1142 if (params.m_bDualPlane) {
1143 ++itr;
1144 unquantized[1][weightIdx] = UnquantizeTexelWeight(*itr);
1145 if (itr == weights.end()) {
1146 break;
1147 }
1148 }
1149
1150 if (++weightIdx >= (params.m_Width * params.m_Height))
1151 break;
1152 }
1153
1154 // Do infill if necessary (Section C.2.18) ...
1155 u32 Ds = (1024 + (blockWidth / 2)) / (blockWidth - 1);
1156 u32 Dt = (1024 + (blockHeight / 2)) / (blockHeight - 1);
1157
1158 const u32 kPlaneScale = params.m_bDualPlane ? 2U : 1U;
1159 for (u32 plane = 0; plane < kPlaneScale; plane++)
1160 for (u32 t = 0; t < blockHeight; t++)
1161 for (u32 s = 0; s < blockWidth; s++) {
1162 u32 cs = Ds * s;
1163 u32 ct = Dt * t;
1164
1165 u32 gs = (cs * (params.m_Width - 1) + 32) >> 6;
1166 u32 gt = (ct * (params.m_Height - 1) + 32) >> 6;
1167
1168 u32 js = gs >> 4;
1169 u32 fs = gs & 0xF;
1170
1171 u32 jt = gt >> 4;
1172 u32 ft = gt & 0x0F;
1173
1174 u32 w11 = (fs * ft + 8) >> 4;
1175 u32 w10 = ft - w11;
1176 u32 w01 = fs - w11;
1177 u32 w00 = 16 - fs - ft + w11;
1178
1179 u32 v0 = js + jt * params.m_Width;
1180
1181#define FIND_TEXEL(tidx, bidx) \
1182 u32 p##bidx = 0; \
1183 do { \
1184 if ((tidx) < (params.m_Width * params.m_Height)) { \
1185 p##bidx = unquantized[plane][(tidx)]; \
1186 } \
1187 } while (0)
1188
1189 FIND_TEXEL(v0, 00);
1190 FIND_TEXEL(v0 + 1, 01);
1191 FIND_TEXEL(v0 + params.m_Width, 10);
1192 FIND_TEXEL(v0 + params.m_Width + 1, 11);
1193
1194#undef FIND_TEXEL
1195
1196 out[plane][t * blockWidth + s] =
1197 (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4;
1198 }
1199}
1200
1201// Transfers a bit as described in C.2.14
1202static inline void BitTransferSigned(s32& a, s32& b) {
1203 b >>= 1;
1204 b |= a & 0x80;
1205 a >>= 1;
1206 a &= 0x3F;
1207 if (a & 0x20)
1208 a -= 0x40;
1209}
1210
1211// Adds more precision to the blue channel as described
1212// in C.2.14
1213static inline Pixel BlueContract(s32 a, s32 r, s32 g, s32 b) {
1214 return Pixel(static_cast<s16>(a), static_cast<s16>((r + b) >> 1),
1215 static_cast<s16>((g + b) >> 1), static_cast<s16>(b));
1216}
1217
1218// Partition selection functions as specified in
1219// C.2.21
1220static inline u32 hash52(u32 p) {
1221 p ^= p >> 15;
1222 p -= p << 17;
1223 p += p << 7;
1224 p += p << 4;
1225 p ^= p >> 5;
1226 p += p << 16;
1227 p ^= p >> 7;
1228 p ^= p >> 3;
1229 p ^= p << 6;
1230 p ^= p >> 17;
1231 return p;
1232}
1233
1234static u32 SelectPartition(s32 seed, s32 x, s32 y, s32 z, s32 partitionCount, s32 smallBlock) {
1235 if (1 == partitionCount)
1236 return 0;
1237
1238 if (smallBlock) {
1239 x <<= 1;
1240 y <<= 1;
1241 z <<= 1;
1242 }
1243
1244 seed += (partitionCount - 1) * 1024;
1245
1246 u32 rnum = hash52(static_cast<u32>(seed));
1247 u8 seed1 = static_cast<u8>(rnum & 0xF);
1248 u8 seed2 = static_cast<u8>((rnum >> 4) & 0xF);
1249 u8 seed3 = static_cast<u8>((rnum >> 8) & 0xF);
1250 u8 seed4 = static_cast<u8>((rnum >> 12) & 0xF);
1251 u8 seed5 = static_cast<u8>((rnum >> 16) & 0xF);
1252 u8 seed6 = static_cast<u8>((rnum >> 20) & 0xF);
1253 u8 seed7 = static_cast<u8>((rnum >> 24) & 0xF);
1254 u8 seed8 = static_cast<u8>((rnum >> 28) & 0xF);
1255 u8 seed9 = static_cast<u8>((rnum >> 18) & 0xF);
1256 u8 seed10 = static_cast<u8>((rnum >> 22) & 0xF);
1257 u8 seed11 = static_cast<u8>((rnum >> 26) & 0xF);
1258 u8 seed12 = static_cast<u8>(((rnum >> 30) | (rnum << 2)) & 0xF);
1259
1260 seed1 = static_cast<u8>(seed1 * seed1);
1261 seed2 = static_cast<u8>(seed2 * seed2);
1262 seed3 = static_cast<u8>(seed3 * seed3);
1263 seed4 = static_cast<u8>(seed4 * seed4);
1264 seed5 = static_cast<u8>(seed5 * seed5);
1265 seed6 = static_cast<u8>(seed6 * seed6);
1266 seed7 = static_cast<u8>(seed7 * seed7);
1267 seed8 = static_cast<u8>(seed8 * seed8);
1268 seed9 = static_cast<u8>(seed9 * seed9);
1269 seed10 = static_cast<u8>(seed10 * seed10);
1270 seed11 = static_cast<u8>(seed11 * seed11);
1271 seed12 = static_cast<u8>(seed12 * seed12);
1272
1273 s32 sh1, sh2, sh3;
1274 if (seed & 1) {
1275 sh1 = (seed & 2) ? 4 : 5;
1276 sh2 = (partitionCount == 3) ? 6 : 5;
1277 } else {
1278 sh1 = (partitionCount == 3) ? 6 : 5;
1279 sh2 = (seed & 2) ? 4 : 5;
1280 }
1281 sh3 = (seed & 0x10) ? sh1 : sh2;
1282
1283 seed1 = static_cast<u8>(seed1 >> sh1);
1284 seed2 = static_cast<u8>(seed2 >> sh2);
1285 seed3 = static_cast<u8>(seed3 >> sh1);
1286 seed4 = static_cast<u8>(seed4 >> sh2);
1287 seed5 = static_cast<u8>(seed5 >> sh1);
1288 seed6 = static_cast<u8>(seed6 >> sh2);
1289 seed7 = static_cast<u8>(seed7 >> sh1);
1290 seed8 = static_cast<u8>(seed8 >> sh2);
1291 seed9 = static_cast<u8>(seed9 >> sh3);
1292 seed10 = static_cast<u8>(seed10 >> sh3);
1293 seed11 = static_cast<u8>(seed11 >> sh3);
1294 seed12 = static_cast<u8>(seed12 >> sh3);
1295
1296 s32 a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
1297 s32 b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
1298 s32 c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
1299 s32 d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
1300
1301 a &= 0x3F;
1302 b &= 0x3F;
1303 c &= 0x3F;
1304 d &= 0x3F;
1305
1306 if (partitionCount < 4)
1307 d = 0;
1308 if (partitionCount < 3)
1309 c = 0;
1310
1311 if (a >= b && a >= c && a >= d)
1312 return 0;
1313 else if (b >= c && b >= d)
1314 return 1;
1315 else if (c >= d)
1316 return 2;
1317 return 3;
1318}
1319
1320static inline u32 Select2DPartition(s32 seed, s32 x, s32 y, s32 partitionCount, s32 smallBlock) {
1321 return SelectPartition(seed, x, y, 0, partitionCount, smallBlock);
1322}
1323
1324// Section C.2.14
1325static void ComputeEndpos32s(Pixel& ep1, Pixel& ep2, const u32*& colorValues,
1326 u32 colorEndpos32Mode) {
1327#define READ_UINT_VALUES(N) \
1328 u32 v[N]; \
1329 for (u32 i = 0; i < N; i++) { \
1330 v[i] = *(colorValues++); \
1331 }
1332
1333#define READ_INT_VALUES(N) \
1334 s32 v[N]; \
1335 for (u32 i = 0; i < N; i++) { \
1336 v[i] = static_cast<s32>(*(colorValues++)); \
1337 }
1338
1339 switch (colorEndpos32Mode) {
1340 case 0: {
1341 READ_UINT_VALUES(2)
1342 ep1 = Pixel(0xFF, v[0], v[0], v[0]);
1343 ep2 = Pixel(0xFF, v[1], v[1], v[1]);
1344 } break;
1345
1346 case 1: {
1347 READ_UINT_VALUES(2)
1348 u32 L0 = (v[0] >> 2) | (v[1] & 0xC0);
1349 u32 L1 = std::max(L0 + (v[1] & 0x3F), 0xFFU);
1350 ep1 = Pixel(0xFF, L0, L0, L0);
1351 ep2 = Pixel(0xFF, L1, L1, L1);
1352 } break;
1353
1354 case 4: {
1355 READ_UINT_VALUES(4)
1356 ep1 = Pixel(v[2], v[0], v[0], v[0]);
1357 ep2 = Pixel(v[3], v[1], v[1], v[1]);
1358 } break;
1359
1360 case 5: {
1361 READ_INT_VALUES(4)
1362 BitTransferSigned(v[1], v[0]);
1363 BitTransferSigned(v[3], v[2]);
1364 ep1 = Pixel(v[2], v[0], v[0], v[0]);
1365 ep2 = Pixel(v[2] + v[3], v[0] + v[1], v[0] + v[1], v[0] + v[1]);
1366 ep1.ClampByte();
1367 ep2.ClampByte();
1368 } break;
1369
1370 case 6: {
1371 READ_UINT_VALUES(4)
1372 ep1 = Pixel(0xFF, v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8);
1373 ep2 = Pixel(0xFF, v[0], v[1], v[2]);
1374 } break;
1375
1376 case 8: {
1377 READ_UINT_VALUES(6)
1378 if (v[1] + v[3] + v[5] >= v[0] + v[2] + v[4]) {
1379 ep1 = Pixel(0xFF, v[0], v[2], v[4]);
1380 ep2 = Pixel(0xFF, v[1], v[3], v[5]);
1381 } else {
1382 ep1 = BlueContract(0xFF, v[1], v[3], v[5]);
1383 ep2 = BlueContract(0xFF, v[0], v[2], v[4]);
1384 }
1385 } break;
1386
1387 case 9: {
1388 READ_INT_VALUES(6)
1389 BitTransferSigned(v[1], v[0]);
1390 BitTransferSigned(v[3], v[2]);
1391 BitTransferSigned(v[5], v[4]);
1392 if (v[1] + v[3] + v[5] >= 0) {
1393 ep1 = Pixel(0xFF, v[0], v[2], v[4]);
1394 ep2 = Pixel(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]);
1395 } else {
1396 ep1 = BlueContract(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]);
1397 ep2 = BlueContract(0xFF, v[0], v[2], v[4]);
1398 }
1399 ep1.ClampByte();
1400 ep2.ClampByte();
1401 } break;
1402
1403 case 10: {
1404 READ_UINT_VALUES(6)
1405 ep1 = Pixel(v[4], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8);
1406 ep2 = Pixel(v[5], v[0], v[1], v[2]);
1407 } break;
1408
1409 case 12: {
1410 READ_UINT_VALUES(8)
1411 if (v[1] + v[3] + v[5] >= v[0] + v[2] + v[4]) {
1412 ep1 = Pixel(v[6], v[0], v[2], v[4]);
1413 ep2 = Pixel(v[7], v[1], v[3], v[5]);
1414 } else {
1415 ep1 = BlueContract(v[7], v[1], v[3], v[5]);
1416 ep2 = BlueContract(v[6], v[0], v[2], v[4]);
1417 }
1418 } break;
1419
1420 case 13: {
1421 READ_INT_VALUES(8)
1422 BitTransferSigned(v[1], v[0]);
1423 BitTransferSigned(v[3], v[2]);
1424 BitTransferSigned(v[5], v[4]);
1425 BitTransferSigned(v[7], v[6]);
1426 if (v[1] + v[3] + v[5] >= 0) {
1427 ep1 = Pixel(v[6], v[0], v[2], v[4]);
1428 ep2 = Pixel(v[7] + v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5]);
1429 } else {
1430 ep1 = BlueContract(v[6] + v[7], v[0] + v[1], v[2] + v[3], v[4] + v[5]);
1431 ep2 = BlueContract(v[6], v[0], v[2], v[4]);
1432 }
1433 ep1.ClampByte();
1434 ep2.ClampByte();
1435 } break;
1436
1437 default:
1438 assert(false && "Unsupported color endpoint mode (is it HDR?)");
1439 break;
1440 }
1441
1442#undef READ_UINT_VALUES
1443#undef READ_INT_VALUES
1444}
1445
1446static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
1447 const u32 blockHeight, std::span<u32, 12 * 12> outBuf) {
1448 InputBitStream strm(inBuf);
1449 TexelWeightParams weightParams = DecodeBlockInfo(strm);
1450
1451 // Was there an error?
1452 if (weightParams.m_bError) {
1453 assert(false && "Invalid block mode");
1454 FillError(outBuf, blockWidth, blockHeight);
1455 return;
1456 }
1457
1458 if (weightParams.m_bVoidExtentLDR) {
1459 FillVoidExtentLDR(strm, outBuf, blockWidth, blockHeight);
1460 return;
1461 }
1462
1463 if (weightParams.m_bVoidExtentHDR) {
1464 assert(false && "HDR void extent blocks are unsupported!");
1465 FillError(outBuf, blockWidth, blockHeight);
1466 return;
1467 }
1468
1469 if (weightParams.m_Width > blockWidth) {
1470 assert(false && "Texel weight grid width should be smaller than block width");
1471 FillError(outBuf, blockWidth, blockHeight);
1472 return;
1473 }
1474
1475 if (weightParams.m_Height > blockHeight) {
1476 assert(false && "Texel weight grid height should be smaller than block height");
1477 FillError(outBuf, blockWidth, blockHeight);
1478 return;
1479 }
1480
1481 // Read num partitions
1482 u32 nPartitions = strm.ReadBits<2>() + 1;
1483 assert(nPartitions <= 4);
1484
1485 if (nPartitions == 4 && weightParams.m_bDualPlane) {
1486 assert(false && "Dual plane mode is incompatible with four partition blocks");
1487 FillError(outBuf, blockWidth, blockHeight);
1488 return;
1489 }
1490
1491 // Based on the number of partitions, read the color endpos32 mode for
1492 // each partition.
1493
1494 // Determine partitions, partition index, and color endpos32 modes
1495 s32 planeIdx = -1;
1496 u32 partitionIndex;
1497 u32 colorEndpos32Mode[4] = {0, 0, 0, 0};
1498
1499 // Define color data.
1500 u8 colorEndpos32Data[16];
1501 memset(colorEndpos32Data, 0, sizeof(colorEndpos32Data));
1502 OutputBitStream colorEndpos32Stream(colorEndpos32Data, 16 * 8, 0);
1503
1504 // Read extra config data...
1505 u32 baseCEM = 0;
1506 if (nPartitions == 1) {
1507 colorEndpos32Mode[0] = strm.ReadBits<4>();
1508 partitionIndex = 0;
1509 } else {
1510 partitionIndex = strm.ReadBits<10>();
1511 baseCEM = strm.ReadBits<6>();
1512 }
1513 u32 baseMode = (baseCEM & 3);
1514
1515 // Remaining bits are color endpos32 data...
1516 u32 nWeightBits = weightParams.GetPackedBitSize();
1517 s32 remainingBits = 128 - nWeightBits - static_cast<s32>(strm.GetBitsRead());
1518
1519 // Consider extra bits prior to texel data...
1520 u32 extraCEMbits = 0;
1521 if (baseMode) {
1522 switch (nPartitions) {
1523 case 2:
1524 extraCEMbits += 2;
1525 break;
1526 case 3:
1527 extraCEMbits += 5;
1528 break;
1529 case 4:
1530 extraCEMbits += 8;
1531 break;
1532 default:
1533 assert(false);
1534 break;
1535 }
1536 }
1537 remainingBits -= extraCEMbits;
1538
1539 // Do we have a dual plane situation?
1540 u32 planeSelectorBits = 0;
1541 if (weightParams.m_bDualPlane) {
1542 planeSelectorBits = 2;
1543 }
1544 remainingBits -= planeSelectorBits;
1545
1546 // Read color data...
1547 u32 colorDataBits = remainingBits;
1548 while (remainingBits > 0) {
1549 u32 nb = std::min(remainingBits, 8);
1550 u32 b = strm.ReadBits(nb);
1551 colorEndpos32Stream.WriteBits(b, nb);
1552 remainingBits -= 8;
1553 }
1554
1555 // Read the plane selection bits
1556 planeIdx = strm.ReadBits(planeSelectorBits);
1557
1558 // Read the rest of the CEM
1559 if (baseMode) {
1560 u32 extraCEM = strm.ReadBits(extraCEMbits);
1561 u32 CEM = (extraCEM << 6) | baseCEM;
1562 CEM >>= 2;
1563
1564 bool C[4] = {0};
1565 for (u32 i = 0; i < nPartitions; i++) {
1566 C[i] = CEM & 1;
1567 CEM >>= 1;
1568 }
1569
1570 u8 M[4] = {0};
1571 for (u32 i = 0; i < nPartitions; i++) {
1572 M[i] = CEM & 3;
1573 CEM >>= 2;
1574 assert(M[i] <= 3);
1575 }
1576
1577 for (u32 i = 0; i < nPartitions; i++) {
1578 colorEndpos32Mode[i] = baseMode;
1579 if (!(C[i]))
1580 colorEndpos32Mode[i] -= 1;
1581 colorEndpos32Mode[i] <<= 2;
1582 colorEndpos32Mode[i] |= M[i];
1583 }
1584 } else if (nPartitions > 1) {
1585 u32 CEM = baseCEM >> 2;
1586 for (u32 i = 0; i < nPartitions; i++) {
1587 colorEndpos32Mode[i] = CEM;
1588 }
1589 }
1590
1591 // Make sure everything up till here is sane.
1592 for (u32 i = 0; i < nPartitions; i++) {
1593 assert(colorEndpos32Mode[i] < 16);
1594 }
1595 assert(strm.GetBitsRead() + weightParams.GetPackedBitSize() == 128);
1596
1597 // Decode both color data and texel weight data
1598 u32 colorValues[32]; // Four values, two endpos32s, four maximum paritions
1599 DecodeColorValues(colorValues, colorEndpos32Data, colorEndpos32Mode, nPartitions,
1600 colorDataBits);
1601
1602 Pixel endpos32s[4][2];
1603 const u32* colorValuesPtr = colorValues;
1604 for (u32 i = 0; i < nPartitions; i++) {
1605 ComputeEndpos32s(endpos32s[i][0], endpos32s[i][1], colorValuesPtr, colorEndpos32Mode[i]);
1606 }
1607
1608 // Read the texel weight data..
1609 std::array<u8, 16> texelWeightData;
1610 std::ranges::copy(inBuf, texelWeightData.begin());
1611
1612 // Reverse everything
1613 for (u32 i = 0; i < 8; i++) {
1614// Taken from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
1615#define REVERSE_BYTE(b) (((b)*0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32
1616 u8 a = static_cast<u8>(REVERSE_BYTE(texelWeightData[i]));
1617 u8 b = static_cast<u8>(REVERSE_BYTE(texelWeightData[15 - i]));
1618#undef REVERSE_BYTE
1619
1620 texelWeightData[i] = b;
1621 texelWeightData[15 - i] = a;
1622 }
1623
1624 // Make sure that higher non-texel bits are set to zero
1625 const u32 clearByteStart = (weightParams.GetPackedBitSize() >> 3) + 1;
1626 if (clearByteStart > 0 && clearByteStart <= texelWeightData.size()) {
1627 texelWeightData[clearByteStart - 1] &=
1628 static_cast<u8>((1 << (weightParams.GetPackedBitSize() % 8)) - 1);
1629 std::memset(texelWeightData.data() + clearByteStart, 0,
1630 std::min(16U - clearByteStart, 16U));
1631 }
1632
1633 IntegerEncodedVector texelWeightValues;
1634
1635 InputBitStream weightStream(texelWeightData);
1636
1637 DecodeIntegerSequence(texelWeightValues, weightStream, weightParams.m_MaxWeight,
1638 weightParams.GetNumWeightValues());
1639
1640 // Blocks can be at most 12x12, so we can have as many as 144 weights
1641 u32 weights[2][144];
1642 UnquantizeTexelWeights(weights, texelWeightValues, weightParams, blockWidth, blockHeight);
1643
1644 // Now that we have endpos32s and weights, we can s32erpolate and generate
1645 // the proper decoding...
1646 for (u32 j = 0; j < blockHeight; j++)
1647 for (u32 i = 0; i < blockWidth; i++) {
1648 u32 partition = Select2DPartition(partitionIndex, i, j, nPartitions,
1649 (blockHeight * blockWidth) < 32);
1650 assert(partition < nPartitions);
1651
1652 Pixel p;
1653 for (u32 c = 0; c < 4; c++) {
1654 u32 C0 = endpos32s[partition][0].Component(c);
1655 C0 = ReplicateByteTo16(C0);
1656 u32 C1 = endpos32s[partition][1].Component(c);
1657 C1 = ReplicateByteTo16(C1);
1658
1659 u32 plane = 0;
1660 if (weightParams.m_bDualPlane && (((planeIdx + 1) & 3) == c)) {
1661 plane = 1;
1662 }
1663
1664 u32 weight = weights[plane][j * blockWidth + i];
1665 u32 C = (C0 * (64 - weight) + C1 * weight + 32) / 64;
1666 if (C == 65535) {
1667 p.Component(c) = 255;
1668 } else {
1669 double Cf = static_cast<double>(C);
1670 p.Component(c) = static_cast<u16>(255.0 * (Cf / 65536.0) + 0.5);
1671 }
1672 }
1673
1674 outBuf[j * blockWidth + i] = p.Pack();
1675 }
1676}
1677
1678} // namespace ASTCC
1679
1680namespace Tegra::Texture::ASTC {
1681
1682void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
1683 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output) {
1684 u32 block_index = 0;
1685 std::size_t depth_offset = 0;
1686 for (u32 z = 0; z < depth; z++) {
1687 for (u32 y = 0; y < height; y += block_height) {
1688 for (u32 x = 0; x < width; x += block_width) {
1689 const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)};
1690
1691 // Blocks can be at most 12x12
1692 std::array<u32, 12 * 12> uncompData;
1693 ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData);
1694
1695 u32 decompWidth = std::min(block_width, width - x);
1696 u32 decompHeight = std::min(block_height, height - y);
1697
1698 const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4);
1699 for (u32 jj = 0; jj < decompHeight; jj++) {
1700 std::memcpy(outRow.data() + jj * width * 4,
1701 uncompData.data() + jj * block_width, decompWidth * 4);
1702 }
1703 ++block_index;
1704 }
1705 }
1706 depth_offset += height * width * 4;
1707 }
1708}
1709
1710} // namespace Tegra::Texture::ASTC
diff --git a/src/video_core/textures/astc.h b/src/video_core/textures/astc.h
index 9105119bc..c1c73fda5 100644
--- a/src/video_core/textures/astc.h
+++ b/src/video_core/textures/astc.h
@@ -4,11 +4,129 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstdint> 7#include <bit>
8#include "common/common_types.h"
8 9
9namespace Tegra::Texture::ASTC { 10namespace Tegra::Texture::ASTC {
10 11
11void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 12enum class IntegerEncoding { JustBits, Quint, Trit };
12 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output); 13
14struct IntegerEncodedValue {
15 constexpr IntegerEncodedValue() = default;
16
17 constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
18 : encoding{encoding_}, num_bits{num_bits_} {}
19
20 constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
21 return encoding == other.encoding && num_bits == other.num_bits;
22 }
23
24 // Returns the number of bits required to encode num_vals values.
25 u32 GetBitLength(u32 num_vals) const {
26 u32 total_bits = num_bits * num_vals;
27 if (encoding == IntegerEncoding::Trit) {
28 total_bits += (num_vals * 8 + 4) / 5;
29 } else if (encoding == IntegerEncoding::Quint) {
30 total_bits += (num_vals * 7 + 2) / 3;
31 }
32 return total_bits;
33 }
34
35 IntegerEncoding encoding{};
36 u32 num_bits = 0;
37 u32 bit_value = 0;
38 union {
39 u32 quint_value = 0;
40 u32 trit_value;
41 };
42};
43
44// Returns a new instance of this struct that corresponds to the
45// can take no more than mav_value values
46constexpr IntegerEncodedValue CreateEncoding(u32 mav_value) {
47 while (mav_value > 0) {
48 u32 check = mav_value + 1;
49
50 // Is mav_value a power of two?
51 if (!(check & (check - 1))) {
52 return IntegerEncodedValue(IntegerEncoding::JustBits, std::popcount(mav_value));
53 }
54
55 // Is mav_value of the type 3*2^n - 1?
56 if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
57 return IntegerEncodedValue(IntegerEncoding::Trit, std::popcount(check / 3 - 1));
58 }
59
60 // Is mav_value of the type 5*2^n - 1?
61 if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
62 return IntegerEncodedValue(IntegerEncoding::Quint, std::popcount(check / 5 - 1));
63 }
64
65 // Apparently it can't be represented with a bounded integer sequence...
66 // just iterate.
67 mav_value--;
68 }
69 return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
70}
71
72constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
73 std::array<IntegerEncodedValue, 256> encodings{};
74 for (std::size_t i = 0; i < encodings.size(); ++i) {
75 encodings[i] = CreateEncoding(static_cast<u32>(i));
76 }
77 return encodings;
78}
79
80constexpr std::array<IntegerEncodedValue, 256> EncodingsValues = MakeEncodedValues();
81
82// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
83// is the same as [(num_bits - 1):0] and repeats all the way down.
84template <typename IntType>
85constexpr IntType Replicate(IntType val, u32 num_bits, u32 to_bit) {
86 if (num_bits == 0 || to_bit == 0) {
87 return 0;
88 }
89 const IntType v = val & static_cast<IntType>((1 << num_bits) - 1);
90 IntType res = v;
91 u32 reslen = num_bits;
92 while (reslen < to_bit) {
93 u32 comp = 0;
94 if (num_bits > to_bit - reslen) {
95 u32 newshift = to_bit - reslen;
96 comp = num_bits - newshift;
97 num_bits = newshift;
98 }
99 res = static_cast<IntType>(res << num_bits);
100 res = static_cast<IntType>(res | (v >> comp));
101 reslen += num_bits;
102 }
103 return res;
104}
105
106constexpr std::size_t NumReplicateEntries(u32 num_bits) {
107 return std::size_t(1) << num_bits;
108}
109
110template <typename IntType, u32 num_bits, u32 to_bit>
111constexpr auto MakeReplicateTable() {
112 std::array<IntType, NumReplicateEntries(num_bits)> table{};
113 for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
114 table[value] = Replicate(value, num_bits, to_bit);
115 }
116 return table;
117}
118
119constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
120constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
121constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
122constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
123
124struct AstcBufferData {
125 decltype(EncodingsValues) encoding_values = EncodingsValues;
126 decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
127 decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
128 decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
129 decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
130} constexpr ASTC_BUFFER_DATA;
13 131
14} // namespace Tegra::Texture::ASTC 132} // namespace Tegra::Texture::ASTC
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 62685a183..3a463d5db 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -17,26 +17,7 @@
17#include "video_core/textures/texture.h" 17#include "video_core/textures/texture.h"
18 18
19namespace Tegra::Texture { 19namespace Tegra::Texture {
20
21namespace { 20namespace {
22/**
23 * This table represents the internal swizzle of a gob, in format 16 bytes x 2 sector packing.
24 * Calculates the offset of an (x, y) position within a swizzled texture.
25 * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
26 */
27constexpr SwizzleTable MakeSwizzleTableConst() {
28 SwizzleTable table{};
29 for (u32 y = 0; y < table.size(); ++y) {
30 for (u32 x = 0; x < table[0].size(); ++x) {
31 table[y][x] = ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
32 (y % 2) * 16 + (x % 16);
33 }
34 }
35 return table;
36}
37
38constexpr SwizzleTable SWIZZLE_TABLE = MakeSwizzleTableConst();
39
40template <bool TO_LINEAR> 21template <bool TO_LINEAR>
41void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width, 22void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width,
42 u32 height, u32 depth, u32 block_height, u32 block_depth, u32 stride_alignment) { 23 u32 height, u32 depth, u32 block_height, u32 block_depth, u32 stride_alignment) {
@@ -91,10 +72,6 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe
91} 72}
92} // Anonymous namespace 73} // Anonymous namespace
93 74
94SwizzleTable MakeSwizzleTable() {
95 return SWIZZLE_TABLE;
96}
97
98void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, 75void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
99 u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth, 76 u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth,
100 u32 stride_alignment) { 77 u32 stride_alignment) {
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index d7cdc81e8..4c14cefbf 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -23,8 +23,22 @@ constexpr u32 GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_
23 23
24using SwizzleTable = std::array<std::array<u32, GOB_SIZE_X>, GOB_SIZE_Y>; 24using SwizzleTable = std::array<std::array<u32, GOB_SIZE_X>, GOB_SIZE_Y>;
25 25
26/// Returns a z-order swizzle table 26/**
27SwizzleTable MakeSwizzleTable(); 27 * This table represents the internal swizzle of a gob, in format 16 bytes x 2 sector packing.
28 * Calculates the offset of an (x, y) position within a swizzled texture.
29 * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
30 */
31constexpr SwizzleTable MakeSwizzleTable() {
32 SwizzleTable table{};
33 for (u32 y = 0; y < table.size(); ++y) {
34 for (u32 x = 0; x < table[0].size(); ++x) {
35 table[y][x] = ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
36 (y % 2) * 16 + (x % 16);
37 }
38 }
39 return table;
40}
41constexpr SwizzleTable SWIZZLE_TABLE = MakeSwizzleTable();
28 42
29/// Unswizzles a block linear texture into linear memory. 43/// Unswizzles a block linear texture into linear memory.
30void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, 44void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
diff --git a/src/video_core/textures/texture.cpp b/src/video_core/textures/texture.cpp
index ae5621a7d..a552543ed 100644
--- a/src/video_core/textures/texture.cpp
+++ b/src/video_core/textures/texture.cpp
@@ -6,7 +6,7 @@
6#include <array> 6#include <array>
7 7
8#include "common/cityhash.h" 8#include "common/cityhash.h"
9#include "core/settings.h" 9#include "common/settings.h"
10#include "video_core/textures/texture.h" 10#include "video_core/textures/texture.h"
11 11
12using Tegra::Texture::TICEntry; 12using Tegra::Texture::TICEntry;
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index e1b38c6ac..3b575db4d 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -5,8 +5,8 @@
5#include <memory> 5#include <memory>
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/settings.h"
8#include "core/core.h" 9#include "core/core.h"
9#include "core/settings.h"
10#include "video_core/renderer_base.h" 10#include "video_core/renderer_base.h"
11#include "video_core/renderer_opengl/renderer_opengl.h" 11#include "video_core/renderer_opengl/renderer_opengl.h"
12#include "video_core/renderer_vulkan/renderer_vulkan.h" 12#include "video_core/renderer_vulkan/renderer_vulkan.h"
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 34d396434..64206b3d2 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -12,7 +12,7 @@
12#include <vector> 12#include <vector>
13 13
14#include "common/assert.h" 14#include "common/assert.h"
15#include "core/settings.h" 15#include "common/settings.h"
16#include "video_core/vulkan_common/nsight_aftermath_tracker.h" 16#include "video_core/vulkan_common/nsight_aftermath_tracker.h"
17#include "video_core/vulkan_common/vulkan_device.h" 17#include "video_core/vulkan_common/vulkan_device.h"
18#include "video_core/vulkan_common/vulkan_wrapper.h" 18#include "video_core/vulkan_common/vulkan_wrapper.h"
@@ -51,7 +51,7 @@ constexpr std::array REQUIRED_EXTENSIONS{
51#ifdef _WIN32 51#ifdef _WIN32
52 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, 52 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
53#endif 53#endif
54#ifdef __linux__ 54#ifdef __unix__
55 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, 55 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
56#endif 56#endif
57}; 57};
@@ -294,6 +294,15 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
294 }; 294 };
295 SetNext(next, bit8_storage); 295 SetNext(next, bit8_storage);
296 296
297 VkPhysicalDeviceRobustness2FeaturesEXT robustness2{
298 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT,
299 .pNext = nullptr,
300 .robustBufferAccess2 = true,
301 .robustImageAccess2 = true,
302 .nullDescriptor = true,
303 };
304 SetNext(next, robustness2);
305
297 VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ 306 VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{
298 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, 307 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT,
299 .pNext = nullptr, 308 .pNext = nullptr,
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 2a8b7a907..fa37aa79a 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -62,7 +62,7 @@ public:
62 : memory{std::move(memory_)}, allocation_size{allocation_size_}, property_flags{properties}, 62 : memory{std::move(memory_)}, allocation_size{allocation_size_}, property_flags{properties},
63 shifted_memory_type{1U << type} {} 63 shifted_memory_type{1U << type} {}
64 64
65#if defined(_WIN32) || defined(__linux__) 65#if defined(_WIN32) || defined(__unix__)
66 ~MemoryAllocation() { 66 ~MemoryAllocation() {
67 if (owning_opengl_handle != 0) { 67 if (owning_opengl_handle != 0) {
68 glDeleteMemoryObjectsEXT(1, &owning_opengl_handle); 68 glDeleteMemoryObjectsEXT(1, &owning_opengl_handle);
@@ -114,7 +114,7 @@ public:
114 } 114 }
115 return owning_opengl_handle; 115 return owning_opengl_handle;
116 } 116 }
117#elif __linux__ 117#elif __unix__
118 [[nodiscard]] u32 ExportOpenGLHandle() { 118 [[nodiscard]] u32 ExportOpenGLHandle() {
119 if (!owning_opengl_handle) { 119 if (!owning_opengl_handle) {
120 glCreateMemoryObjectsEXT(1, &owning_opengl_handle); 120 glCreateMemoryObjectsEXT(1, &owning_opengl_handle);
@@ -165,7 +165,7 @@ private:
165 const u32 shifted_memory_type; ///< Shifted Vulkan memory type. 165 const u32 shifted_memory_type; ///< Shifted Vulkan memory type.
166 std::vector<Range> commits; ///< All commit ranges done from this allocation. 166 std::vector<Range> commits; ///< All commit ranges done from this allocation.
167 std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. 167 std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before.
168#if defined(_WIN32) || defined(__linux__) 168#if defined(_WIN32) || defined(__unix__)
169 u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle. 169 u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle.
170#endif 170#endif
171}; 171};
@@ -249,7 +249,7 @@ void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u6
249 .pNext = nullptr, 249 .pNext = nullptr,
250#ifdef _WIN32 250#ifdef _WIN32
251 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, 251 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
252#elif __linux__ 252#elif __unix__
253 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, 253 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
254#else 254#else
255 .handleTypes = 0, 255 .handleTypes = 0,
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index b025ced1c..cc0790e07 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -18,6 +18,7 @@ add_executable(yuzu
18 applets/profile_select.h 18 applets/profile_select.h
19 applets/software_keyboard.cpp 19 applets/software_keyboard.cpp
20 applets/software_keyboard.h 20 applets/software_keyboard.h
21 applets/software_keyboard.ui
21 applets/web_browser.cpp 22 applets/web_browser.cpp
22 applets/web_browser.h 23 applets/web_browser.h
23 bootmanager.cpp 24 bootmanager.cpp
@@ -143,6 +144,9 @@ add_executable(yuzu
143 uisettings.h 144 uisettings.h
144 util/limitable_input_dialog.cpp 145 util/limitable_input_dialog.cpp
145 util/limitable_input_dialog.h 146 util/limitable_input_dialog.h
147 util/overlay_dialog.cpp
148 util/overlay_dialog.h
149 util/overlay_dialog.ui
146 util/sequence_dialog/sequence_dialog.cpp 150 util/sequence_dialog/sequence_dialog.cpp
147 util/sequence_dialog/sequence_dialog.h 151 util/sequence_dialog/sequence_dialog.h
148 util/url_request_interceptor.cpp 152 util/url_request_interceptor.cpp
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
index b92cd6886..836d90fda 100644
--- a/src/yuzu/applets/controller.cpp
+++ b/src/yuzu/applets/controller.cpp
@@ -16,6 +16,7 @@
16#include "yuzu/applets/controller.h" 16#include "yuzu/applets/controller.h"
17#include "yuzu/configuration/configure_input.h" 17#include "yuzu/configuration/configure_input.h"
18#include "yuzu/configuration/configure_input_profile_dialog.h" 18#include "yuzu/configuration/configure_input_profile_dialog.h"
19#include "yuzu/configuration/configure_motion_touch.h"
19#include "yuzu/configuration/configure_vibration.h" 20#include "yuzu/configuration/configure_vibration.h"
20#include "yuzu/configuration/input_profiles.h" 21#include "yuzu/configuration/input_profiles.h"
21#include "yuzu/main.h" 22#include "yuzu/main.h"
@@ -206,6 +207,9 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
206 connect(ui->vibrationButton, &QPushButton::clicked, this, 207 connect(ui->vibrationButton, &QPushButton::clicked, this,
207 &QtControllerSelectorDialog::CallConfigureVibrationDialog); 208 &QtControllerSelectorDialog::CallConfigureVibrationDialog);
208 209
210 connect(ui->motionButton, &QPushButton::clicked, this,
211 &QtControllerSelectorDialog::CallConfigureMotionTouchDialog);
212
209 connect(ui->inputConfigButton, &QPushButton::clicked, this, 213 connect(ui->inputConfigButton, &QPushButton::clicked, this,
210 &QtControllerSelectorDialog::CallConfigureInputProfileDialog); 214 &QtControllerSelectorDialog::CallConfigureInputProfileDialog);
211 215
@@ -276,6 +280,18 @@ void QtControllerSelectorDialog::CallConfigureVibrationDialog() {
276 } 280 }
277} 281}
278 282
283void QtControllerSelectorDialog::CallConfigureMotionTouchDialog() {
284 ConfigureMotionTouch dialog(this, input_subsystem);
285
286 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
287 Qt::WindowSystemMenuHint);
288 dialog.setWindowModality(Qt::WindowModal);
289
290 if (dialog.exec() == QDialog::Accepted) {
291 dialog.ApplyConfiguration();
292 }
293}
294
279void QtControllerSelectorDialog::CallConfigureInputProfileDialog() { 295void QtControllerSelectorDialog::CallConfigureInputProfileDialog() {
280 ConfigureInputProfileDialog dialog(this, input_subsystem, input_profiles.get()); 296 ConfigureInputProfileDialog dialog(this, input_subsystem, input_profiles.get());
281 297
diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h
index 3518eed56..9b57aea1a 100644
--- a/src/yuzu/applets/controller.h
+++ b/src/yuzu/applets/controller.h
@@ -51,6 +51,9 @@ private:
51 // Initializes the "Configure Vibration" Dialog. 51 // Initializes the "Configure Vibration" Dialog.
52 void CallConfigureVibrationDialog(); 52 void CallConfigureVibrationDialog();
53 53
54 // Initializes the "Configure Motion / Touch" Dialog.
55 void CallConfigureMotionTouchDialog();
56
54 // Initializes the "Create Input Profile" Dialog. 57 // Initializes the "Create Input Profile" Dialog.
55 void CallConfigureInputProfileDialog(); 58 void CallConfigureInputProfileDialog();
56 59
diff --git a/src/yuzu/applets/error.cpp b/src/yuzu/applets/error.cpp
index 8ee03ddb3..085688cd4 100644
--- a/src/yuzu/applets/error.cpp
+++ b/src/yuzu/applets/error.cpp
@@ -19,11 +19,11 @@ QtErrorDisplay::~QtErrorDisplay() = default;
19void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const { 19void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const {
20 callback = std::move(finished); 20 callback = std::move(finished);
21 emit MainWindowDisplayError( 21 emit MainWindowDisplayError(
22 tr("An error has occurred.\nPlease try again or contact the developer of the " 22 tr("Error Code: %1-%2 (0x%3)")
23 "software.\n\nError Code: %1-%2 (0x%3)")
24 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) 23 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
25 .arg(error.description, 4, 10, QChar::fromLatin1('0')) 24 .arg(error.description, 4, 10, QChar::fromLatin1('0'))
26 .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); 25 .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
26 tr("An error has occurred.\nPlease try again or contact the developer of the software."));
27} 27}
28 28
29void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, 29void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
@@ -32,13 +32,14 @@ void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::secon
32 32
33 const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); 33 const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count());
34 emit MainWindowDisplayError( 34 emit MainWindowDisplayError(
35 tr("An error occurred on %1 at %2.\nPlease try again or contact the " 35 tr("Error Code: %1-%2 (0x%3)")
36 "developer of the software.\n\nError Code: %3-%4 (0x%5)")
37 .arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy")))
38 .arg(date_time.toString(QStringLiteral("h:mm:ss A")))
39 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) 36 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
40 .arg(error.description, 4, 10, QChar::fromLatin1('0')) 37 .arg(error.description, 4, 10, QChar::fromLatin1('0'))
41 .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); 38 .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
39 tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the "
40 "software.")
41 .arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy")))
42 .arg(date_time.toString(QStringLiteral("h:mm:ss A"))));
42} 43}
43 44
44void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text, 45void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text,
@@ -46,10 +47,11 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te
46 std::function<void()> finished) const { 47 std::function<void()> finished) const {
47 callback = std::move(finished); 48 callback = std::move(finished);
48 emit MainWindowDisplayError( 49 emit MainWindowDisplayError(
49 tr("An error has occurred.\nError Code: %1-%2 (0x%3)\n\n%4\n\n%5") 50 tr("Error Code: %1-%2 (0x%3)")
50 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) 51 .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
51 .arg(error.description, 4, 10, QChar::fromLatin1('0')) 52 .arg(error.description, 4, 10, QChar::fromLatin1('0'))
52 .arg(error.raw, 8, 16, QChar::fromLatin1('0')) 53 .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
54 tr("An error has occurred.\n\n%1\n\n%2")
53 .arg(QString::fromStdString(dialog_text)) 55 .arg(QString::fromStdString(dialog_text))
54 .arg(QString::fromStdString(fullscreen_text))); 56 .arg(QString::fromStdString(fullscreen_text)));
55} 57}
diff --git a/src/yuzu/applets/error.h b/src/yuzu/applets/error.h
index b0932d895..8bd895a32 100644
--- a/src/yuzu/applets/error.h
+++ b/src/yuzu/applets/error.h
@@ -24,7 +24,7 @@ public:
24 std::function<void()> finished) const override; 24 std::function<void()> finished) const override;
25 25
26signals: 26signals:
27 void MainWindowDisplayError(QString error) const; 27 void MainWindowDisplayError(QString error_code, QString error_text) const;
28 28
29private: 29private:
30 void MainWindowFinishedError(); 30 void MainWindowFinishedError();
diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp
index ab8cfd8ee..fd3368479 100644
--- a/src/yuzu/applets/software_keyboard.cpp
+++ b/src/yuzu/applets/software_keyboard.cpp
@@ -1,153 +1,1641 @@
1// Copyright 2018 yuzu Emulator Project 1// Copyright 2021 yuzu Emulator Project
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 <QCursor>
6#include <mutex> 6#include <QKeyEvent>
7#include <QDialogButtonBox> 7#include <QScreen>
8#include <QFont> 8
9#include <QLabel> 9#include "common/logging/log.h"
10#include <QLineEdit> 10#include "common/settings.h"
11#include <QVBoxLayout> 11#include "common/string_util.h"
12#include "core/hle/lock.h" 12#include "core/core.h"
13#include "core/frontend/input_interpreter.h"
14#include "ui_software_keyboard.h"
13#include "yuzu/applets/software_keyboard.h" 15#include "yuzu/applets/software_keyboard.h"
14#include "yuzu/main.h" 16#include "yuzu/main.h"
17#include "yuzu/util/overlay_dialog.h"
18
19namespace {
20
21using namespace Service::AM::Applets;
22
23constexpr float BASE_HEADER_FONT_SIZE = 23.0f;
24constexpr float BASE_SUB_FONT_SIZE = 17.0f;
25constexpr float BASE_EDITOR_FONT_SIZE = 26.0f;
26constexpr float BASE_CHAR_BUTTON_FONT_SIZE = 28.0f;
27constexpr float BASE_LABEL_BUTTON_FONT_SIZE = 18.0f;
28constexpr float BASE_ICON_BUTTON_SIZE = 36.0f;
29[[maybe_unused]] constexpr float BASE_WIDTH = 1280.0f;
30constexpr float BASE_HEIGHT = 720.0f;
31
32} // Anonymous namespace
33
34QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
35 QWidget* parent, Core::System& system_, bool is_inline_,
36 Core::Frontend::KeyboardInitializeParameters initialize_parameters_)
37 : QDialog(parent), ui{std::make_unique<Ui::QtSoftwareKeyboardDialog>()}, system{system_},
38 is_inline{is_inline_}, initialize_parameters{std::move(initialize_parameters_)} {
39 ui->setupUi(this);
40
41 setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint |
42 Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint);
43 setWindowModality(Qt::WindowModal);
44 setAttribute(Qt::WA_DeleteOnClose);
45 setAttribute(Qt::WA_TranslucentBackground);
46
47 keyboard_buttons = {{
48 {{
49 {
50 ui->button_1,
51 ui->button_2,
52 ui->button_3,
53 ui->button_4,
54 ui->button_5,
55 ui->button_6,
56 ui->button_7,
57 ui->button_8,
58 ui->button_9,
59 ui->button_0,
60 ui->button_minus,
61 ui->button_backspace,
62 },
63 {
64 ui->button_q,
65 ui->button_w,
66 ui->button_e,
67 ui->button_r,
68 ui->button_t,
69 ui->button_y,
70 ui->button_u,
71 ui->button_i,
72 ui->button_o,
73 ui->button_p,
74 ui->button_slash,
75 ui->button_return,
76 },
77 {
78 ui->button_a,
79 ui->button_s,
80 ui->button_d,
81 ui->button_f,
82 ui->button_g,
83 ui->button_h,
84 ui->button_j,
85 ui->button_k,
86 ui->button_l,
87 ui->button_colon,
88 ui->button_apostrophe,
89 ui->button_return,
90 },
91 {
92 ui->button_z,
93 ui->button_x,
94 ui->button_c,
95 ui->button_v,
96 ui->button_b,
97 ui->button_n,
98 ui->button_m,
99 ui->button_comma,
100 ui->button_dot,
101 ui->button_question,
102 ui->button_exclamation,
103 ui->button_ok,
104 },
105 {
106 ui->button_shift,
107 ui->button_shift,
108 ui->button_space,
109 ui->button_space,
110 ui->button_space,
111 ui->button_space,
112 ui->button_space,
113 ui->button_space,
114 ui->button_space,
115 ui->button_space,
116 ui->button_space,
117 ui->button_ok,
118 },
119 }},
120 {{
121 {
122 ui->button_hash,
123 ui->button_left_bracket,
124 ui->button_right_bracket,
125 ui->button_dollar,
126 ui->button_percent,
127 ui->button_circumflex,
128 ui->button_ampersand,
129 ui->button_asterisk,
130 ui->button_left_parenthesis,
131 ui->button_right_parenthesis,
132 ui->button_underscore,
133 ui->button_backspace_shift,
134 },
135 {
136 ui->button_q_shift,
137 ui->button_w_shift,
138 ui->button_e_shift,
139 ui->button_r_shift,
140 ui->button_t_shift,
141 ui->button_y_shift,
142 ui->button_u_shift,
143 ui->button_i_shift,
144 ui->button_o_shift,
145 ui->button_p_shift,
146 ui->button_at,
147 ui->button_return_shift,
148 },
149 {
150 ui->button_a_shift,
151 ui->button_s_shift,
152 ui->button_d_shift,
153 ui->button_f_shift,
154 ui->button_g_shift,
155 ui->button_h_shift,
156 ui->button_j_shift,
157 ui->button_k_shift,
158 ui->button_l_shift,
159 ui->button_semicolon,
160 ui->button_quotation,
161 ui->button_return_shift,
162 },
163 {
164 ui->button_z_shift,
165 ui->button_x_shift,
166 ui->button_c_shift,
167 ui->button_v_shift,
168 ui->button_b_shift,
169 ui->button_n_shift,
170 ui->button_m_shift,
171 ui->button_less_than,
172 ui->button_greater_than,
173 ui->button_plus,
174 ui->button_equal,
175 ui->button_ok_shift,
176 },
177 {
178 ui->button_shift_shift,
179 ui->button_shift_shift,
180 ui->button_space_shift,
181 ui->button_space_shift,
182 ui->button_space_shift,
183 ui->button_space_shift,
184 ui->button_space_shift,
185 ui->button_space_shift,
186 ui->button_space_shift,
187 ui->button_space_shift,
188 ui->button_space_shift,
189 ui->button_ok_shift,
190 },
191 }},
192 }};
15 193
16QtSoftwareKeyboardValidator::QtSoftwareKeyboardValidator( 194 numberpad_buttons = {{
17 Core::Frontend::SoftwareKeyboardParameters parameters) 195 {
18 : parameters(std::move(parameters)) {} 196 ui->button_1_num,
197 ui->button_2_num,
198 ui->button_3_num,
199 ui->button_backspace_num,
200 },
201 {
202 ui->button_4_num,
203 ui->button_5_num,
204 ui->button_6_num,
205 ui->button_ok_num,
206 },
207 {
208 ui->button_7_num,
209 ui->button_8_num,
210 ui->button_9_num,
211 ui->button_ok_num,
212 },
213 {
214 nullptr,
215 ui->button_0_num,
216 nullptr,
217 ui->button_ok_num,
218 },
219 }};
19 220
20QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int& pos) const { 221 all_buttons = {
21 if (input.size() > static_cast<s64>(parameters.max_length)) { 222 ui->button_1,
22 return Invalid; 223 ui->button_2,
224 ui->button_3,
225 ui->button_4,
226 ui->button_5,
227 ui->button_6,
228 ui->button_7,
229 ui->button_8,
230 ui->button_9,
231 ui->button_0,
232 ui->button_minus,
233 ui->button_backspace,
234 ui->button_q,
235 ui->button_w,
236 ui->button_e,
237 ui->button_r,
238 ui->button_t,
239 ui->button_y,
240 ui->button_u,
241 ui->button_i,
242 ui->button_o,
243 ui->button_p,
244 ui->button_slash,
245 ui->button_return,
246 ui->button_a,
247 ui->button_s,
248 ui->button_d,
249 ui->button_f,
250 ui->button_g,
251 ui->button_h,
252 ui->button_j,
253 ui->button_k,
254 ui->button_l,
255 ui->button_colon,
256 ui->button_apostrophe,
257 ui->button_z,
258 ui->button_x,
259 ui->button_c,
260 ui->button_v,
261 ui->button_b,
262 ui->button_n,
263 ui->button_m,
264 ui->button_comma,
265 ui->button_dot,
266 ui->button_question,
267 ui->button_exclamation,
268 ui->button_ok,
269 ui->button_shift,
270 ui->button_space,
271 ui->button_hash,
272 ui->button_left_bracket,
273 ui->button_right_bracket,
274 ui->button_dollar,
275 ui->button_percent,
276 ui->button_circumflex,
277 ui->button_ampersand,
278 ui->button_asterisk,
279 ui->button_left_parenthesis,
280 ui->button_right_parenthesis,
281 ui->button_underscore,
282 ui->button_backspace_shift,
283 ui->button_q_shift,
284 ui->button_w_shift,
285 ui->button_e_shift,
286 ui->button_r_shift,
287 ui->button_t_shift,
288 ui->button_y_shift,
289 ui->button_u_shift,
290 ui->button_i_shift,
291 ui->button_o_shift,
292 ui->button_p_shift,
293 ui->button_at,
294 ui->button_return_shift,
295 ui->button_a_shift,
296 ui->button_s_shift,
297 ui->button_d_shift,
298 ui->button_f_shift,
299 ui->button_g_shift,
300 ui->button_h_shift,
301 ui->button_j_shift,
302 ui->button_k_shift,
303 ui->button_l_shift,
304 ui->button_semicolon,
305 ui->button_quotation,
306 ui->button_z_shift,
307 ui->button_x_shift,
308 ui->button_c_shift,
309 ui->button_v_shift,
310 ui->button_b_shift,
311 ui->button_n_shift,
312 ui->button_m_shift,
313 ui->button_less_than,
314 ui->button_greater_than,
315 ui->button_plus,
316 ui->button_equal,
317 ui->button_ok_shift,
318 ui->button_shift_shift,
319 ui->button_space_shift,
320 ui->button_1_num,
321 ui->button_2_num,
322 ui->button_3_num,
323 ui->button_backspace_num,
324 ui->button_4_num,
325 ui->button_5_num,
326 ui->button_6_num,
327 ui->button_ok_num,
328 ui->button_7_num,
329 ui->button_8_num,
330 ui->button_9_num,
331 ui->button_0_num,
332 };
333
334 SetupMouseHover();
335
336 if (!initialize_parameters.ok_text.empty()) {
337 ui->button_ok->setText(QString::fromStdU16String(initialize_parameters.ok_text));
23 } 338 }
24 if (parameters.disable_space && input.contains(QLatin1Char{' '})) { 339
25 return Invalid; 340 ui->label_header->setText(QString::fromStdU16String(initialize_parameters.header_text));
341 ui->label_sub->setText(QString::fromStdU16String(initialize_parameters.sub_text));
342
343 current_text = initialize_parameters.initial_text;
344 cursor_position = initialize_parameters.initial_cursor_position;
345
346 SetTextDrawType();
347
348 for (auto* button : all_buttons) {
349 connect(button, &QPushButton::clicked, this, [this, button](bool) {
350 if (is_inline) {
351 InlineKeyboardButtonClicked(button);
352 } else {
353 NormalKeyboardButtonClicked(button);
354 }
355 });
26 } 356 }
27 if (parameters.disable_address && input.contains(QLatin1Char{'@'})) { 357
28 return Invalid; 358 // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend
359 if (system.IsPoweredOn()) {
360 input_interpreter = std::make_unique<InputInterpreter>(system);
29 } 361 }
30 if (parameters.disable_percent && input.contains(QLatin1Char{'%'})) { 362}
31 return Invalid; 363
364QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() {
365 StopInputThread();
366}
367
368void QtSoftwareKeyboardDialog::ShowNormalKeyboard(QPoint pos, QSize size) {
369 if (isVisible()) {
370 return;
32 } 371 }
33 if (parameters.disable_slash && 372
34 (input.contains(QLatin1Char{'/'}) || input.contains(QLatin1Char{'\\'}))) { 373 MoveAndResizeWindow(pos, size);
35 return Invalid; 374
375 SetKeyboardType();
376 SetPasswordMode();
377 SetControllerImage();
378 DisableKeyboardButtons();
379 SetBackspaceOkEnabled();
380
381 open();
382}
383
384void QtSoftwareKeyboardDialog::ShowTextCheckDialog(
385 Service::AM::Applets::SwkbdTextCheckResult text_check_result,
386 std::u16string text_check_message) {
387 switch (text_check_result) {
388 case SwkbdTextCheckResult::Success:
389 case SwkbdTextCheckResult::Silent:
390 default:
391 break;
392 case SwkbdTextCheckResult::Failure: {
393 StopInputThread();
394
395 OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message),
396 QString{}, tr("OK"), Qt::AlignCenter);
397 dialog.exec();
398
399 StartInputThread();
400 break;
36 } 401 }
37 if (parameters.disable_number && 402 case SwkbdTextCheckResult::Confirm: {
38 std::any_of(input.begin(), input.end(), [](QChar c) { return c.isDigit(); })) { 403 StopInputThread();
39 return Invalid; 404
405 OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message),
406 tr("Cancel"), tr("OK"), Qt::AlignCenter);
407 if (dialog.exec() == QDialog::Accepted) {
408 emit SubmitNormalText(SwkbdResult::Ok, current_text);
409 break;
410 }
411
412 StartInputThread();
413 break;
40 } 414 }
415 }
416}
417
418void QtSoftwareKeyboardDialog::ShowInlineKeyboard(
419 Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, QSize size) {
420 MoveAndResizeWindow(pos, size);
421
422 ui->topOSK->setStyleSheet(QStringLiteral("background: rgba(0, 0, 0, 0);"));
423
424 ui->headerOSK->hide();
425 ui->subOSK->hide();
426 ui->inputOSK->hide();
427 ui->charactersOSK->hide();
428 ui->inputBoxOSK->hide();
429 ui->charactersBoxOSK->hide();
430
431 initialize_parameters.max_text_length = appear_parameters.max_text_length;
432 initialize_parameters.min_text_length = appear_parameters.min_text_length;
433 initialize_parameters.type = appear_parameters.type;
434 initialize_parameters.key_disable_flags = appear_parameters.key_disable_flags;
435 initialize_parameters.enable_backspace_button = appear_parameters.enable_backspace_button;
436 initialize_parameters.enable_return_button = appear_parameters.enable_return_button;
437 initialize_parameters.disable_cancel_button = initialize_parameters.disable_cancel_button;
41 438
42 if (parameters.disable_download_code && std::any_of(input.begin(), input.end(), [](QChar c) { 439 SetKeyboardType();
43 return c == QLatin1Char{'O'} || c == QLatin1Char{'I'}; 440 SetControllerImage();
44 })) { 441 DisableKeyboardButtons();
45 return Invalid; 442 SetBackspaceOkEnabled();
443
444 open();
445}
446
447void QtSoftwareKeyboardDialog::HideInlineKeyboard() {
448 StopInputThread();
449 QDialog::hide();
450}
451
452void QtSoftwareKeyboardDialog::InlineTextChanged(
453 Core::Frontend::InlineTextParameters text_parameters) {
454 current_text = text_parameters.input_text;
455 cursor_position = text_parameters.cursor_position;
456
457 SetBackspaceOkEnabled();
458}
459
460void QtSoftwareKeyboardDialog::ExitKeyboard() {
461 StopInputThread();
462 QDialog::done(QDialog::Accepted);
463}
464
465void QtSoftwareKeyboardDialog::open() {
466 QDialog::open();
467
468 row = 0;
469 column = 0;
470
471 const auto* const curr_button =
472 keyboard_buttons[static_cast<int>(bottom_osk_index)][row][column];
473
474 // This is a workaround for setFocus() randomly not showing focus in the UI
475 QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center()));
476
477 StartInputThread();
478}
479
480void QtSoftwareKeyboardDialog::reject() {
481 // Pressing the ESC key in a dialog calls QDialog::reject().
482 // We will override this behavior to the "Cancel" action on the software keyboard.
483 if (is_inline) {
484 emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
485 } else {
486 emit SubmitNormalText(SwkbdResult::Cancel, current_text);
46 } 487 }
488}
489
490void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) {
491 if (!is_inline) {
492 QDialog::keyPressEvent(event);
493 return;
494 }
495
496 const auto entered_key = event->key();
47 497
48 return Acceptable; 498 switch (entered_key) {
499 case Qt::Key_Escape:
500 QDialog::keyPressEvent(event);
501 return;
502 case Qt::Key_Backspace:
503 switch (bottom_osk_index) {
504 case BottomOSKIndex::LowerCase:
505 ui->button_backspace->click();
506 break;
507 case BottomOSKIndex::UpperCase:
508 ui->button_backspace_shift->click();
509 break;
510 case BottomOSKIndex::NumberPad:
511 ui->button_backspace_num->click();
512 break;
513 default:
514 break;
515 }
516 return;
517 case Qt::Key_Return:
518 switch (bottom_osk_index) {
519 case BottomOSKIndex::LowerCase:
520 ui->button_ok->click();
521 break;
522 case BottomOSKIndex::UpperCase:
523 ui->button_ok_shift->click();
524 break;
525 case BottomOSKIndex::NumberPad:
526 ui->button_ok_num->click();
527 break;
528 default:
529 break;
530 }
531 return;
532 case Qt::Key_Left:
533 MoveTextCursorDirection(Direction::Left);
534 return;
535 case Qt::Key_Right:
536 MoveTextCursorDirection(Direction::Right);
537 return;
538 default:
539 break;
540 }
541
542 const auto entered_text = event->text();
543
544 if (entered_text.isEmpty()) {
545 return;
546 }
547
548 InlineTextInsertString(entered_text.toStdU16String());
49} 549}
50 550
51QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( 551void QtSoftwareKeyboardDialog::MoveAndResizeWindow(QPoint pos, QSize size) {
52 QWidget* parent, Core::Frontend::SoftwareKeyboardParameters parameters_) 552 QDialog::move(pos);
53 : QDialog(parent), parameters(std::move(parameters_)) { 553 QDialog::resize(size);
54 layout = new QVBoxLayout; 554
55 555 // High DPI
56 header_label = new QLabel(QString::fromStdU16String(parameters.header_text)); 556 const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f;
57 header_label->setFont({header_label->font().family(), 11, QFont::Bold}); 557
58 if (header_label->text().isEmpty()) 558 RescaleKeyboardElements(size.width(), size.height(), dpi_scale);
59 header_label->setText(tr("Enter text:")); 559}
60 560
61 sub_label = new QLabel(QString::fromStdU16String(parameters.sub_text)); 561void QtSoftwareKeyboardDialog::RescaleKeyboardElements(float width, float height, float dpi_scale) {
62 sub_label->setFont({sub_label->font().family(), sub_label->font().pointSize(), 562 const auto header_font_size = BASE_HEADER_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
63 sub_label->font().weight(), true}); 563 const auto sub_font_size = BASE_SUB_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
64 sub_label->setHidden(parameters.sub_text.empty()); 564 const auto editor_font_size = BASE_EDITOR_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
65 565 const auto char_button_font_size =
66 guide_label = new QLabel(QString::fromStdU16String(parameters.guide_text)); 566 BASE_CHAR_BUTTON_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
67 guide_label->setHidden(parameters.guide_text.empty()); 567 const auto label_button_font_size =
68 568 BASE_LABEL_BUTTON_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
69 length_label = new QLabel(QStringLiteral("0/%1").arg(parameters.max_length)); 569
70 length_label->setAlignment(Qt::AlignRight); 570 QFont header_font(QStringLiteral("MS Shell Dlg 2"), header_font_size, QFont::Normal);
71 length_label->setFont({length_label->font().family(), 8}); 571 QFont sub_font(QStringLiteral("MS Shell Dlg 2"), sub_font_size, QFont::Normal);
72 572 QFont editor_font(QStringLiteral("MS Shell Dlg 2"), editor_font_size, QFont::Normal);
73 line_edit = new QLineEdit; 573 QFont char_button_font(QStringLiteral("MS Shell Dlg 2"), char_button_font_size, QFont::Normal);
74 line_edit->setValidator(new QtSoftwareKeyboardValidator(parameters)); 574 QFont label_button_font(QStringLiteral("MS Shell Dlg 2"), label_button_font_size,
75 line_edit->setMaxLength(static_cast<int>(parameters.max_length)); 575 QFont::Normal);
76 line_edit->setText(QString::fromStdU16String(parameters.initial_text)); 576
77 line_edit->setCursorPosition( 577 ui->label_header->setFont(header_font);
78 parameters.cursor_at_beginning ? 0 : static_cast<int>(parameters.initial_text.size())); 578 ui->label_sub->setFont(sub_font);
79 line_edit->setEchoMode(parameters.password ? QLineEdit::Password : QLineEdit::Normal); 579 ui->line_edit_osk->setFont(editor_font);
80 580 ui->text_edit_osk->setFont(editor_font);
81 connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) { 581 ui->label_characters->setFont(sub_font);
82 length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length)); 582 ui->label_characters_box->setFont(sub_font);
83 }); 583
84 584 ui->label_shift->setFont(label_button_font);
85 buttons = new QDialogButtonBox(QDialogButtonBox::Cancel); 585 ui->label_shift_shift->setFont(label_button_font);
86 if (parameters.submit_text.empty()) { 586 ui->label_cancel->setFont(label_button_font);
87 buttons->addButton(QDialogButtonBox::Ok); 587 ui->label_cancel_shift->setFont(label_button_font);
588 ui->label_cancel_num->setFont(label_button_font);
589 ui->label_enter->setFont(label_button_font);
590 ui->label_enter_shift->setFont(label_button_font);
591 ui->label_enter_num->setFont(label_button_font);
592
593 for (auto* button : all_buttons) {
594 if (button == ui->button_return || button == ui->button_return_shift) {
595 button->setFont(label_button_font);
596 continue;
597 }
598
599 if (button == ui->button_space || button == ui->button_space_shift) {
600 button->setFont(label_button_font);
601 continue;
602 }
603
604 if (button == ui->button_shift || button == ui->button_shift_shift) {
605 button->setFont(label_button_font);
606 button->setIconSize(QSize(BASE_ICON_BUTTON_SIZE, BASE_ICON_BUTTON_SIZE) *
607 (height / BASE_HEIGHT));
608 continue;
609 }
610
611 if (button == ui->button_backspace || button == ui->button_backspace_shift ||
612 button == ui->button_backspace_num) {
613 button->setFont(label_button_font);
614 button->setIconSize(QSize(BASE_ICON_BUTTON_SIZE, BASE_ICON_BUTTON_SIZE) *
615 (height / BASE_HEIGHT));
616 continue;
617 }
618
619 if (button == ui->button_ok || button == ui->button_ok_shift ||
620 button == ui->button_ok_num) {
621 button->setFont(label_button_font);
622 continue;
623 }
624
625 button->setFont(char_button_font);
626 }
627}
628
629void QtSoftwareKeyboardDialog::SetKeyboardType() {
630 switch (initialize_parameters.type) {
631 case SwkbdType::Normal:
632 case SwkbdType::Qwerty:
633 case SwkbdType::Unknown3:
634 case SwkbdType::Latin:
635 case SwkbdType::SimplifiedChinese:
636 case SwkbdType::TraditionalChinese:
637 case SwkbdType::Korean:
638 default: {
639 bottom_osk_index = BottomOSKIndex::LowerCase;
640 ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
641
642 ui->verticalLayout_2->setStretch(0, 320);
643 ui->verticalLayout_2->setStretch(1, 400);
644
645 ui->gridLineOSK->setRowStretch(5, 94);
646 ui->gridBoxOSK->setRowStretch(2, 81);
647 break;
648 }
649 case SwkbdType::NumberPad: {
650 bottom_osk_index = BottomOSKIndex::NumberPad;
651 ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
652
653 ui->verticalLayout_2->setStretch(0, 370);
654 ui->verticalLayout_2->setStretch(1, 350);
655
656 ui->gridLineOSK->setRowStretch(5, 144);
657 ui->gridBoxOSK->setRowStretch(2, 131);
658 break;
659 }
660 }
661}
662
663void QtSoftwareKeyboardDialog::SetPasswordMode() {
664 switch (initialize_parameters.password_mode) {
665 case SwkbdPasswordMode::Disabled:
666 default:
667 ui->line_edit_osk->setEchoMode(QLineEdit::Normal);
668 break;
669 case SwkbdPasswordMode::Enabled:
670 ui->line_edit_osk->setEchoMode(QLineEdit::Password);
671 break;
672 }
673}
674
675void QtSoftwareKeyboardDialog::SetTextDrawType() {
676 switch (initialize_parameters.text_draw_type) {
677 case SwkbdTextDrawType::Line:
678 case SwkbdTextDrawType::DownloadCode: {
679 ui->topOSK->setCurrentIndex(0);
680
681 if (initialize_parameters.max_text_length <= 10) {
682 ui->gridLineOSK->setColumnStretch(0, 390);
683 ui->gridLineOSK->setColumnStretch(1, 500);
684 ui->gridLineOSK->setColumnStretch(2, 390);
685 } else {
686 ui->gridLineOSK->setColumnStretch(0, 130);
687 ui->gridLineOSK->setColumnStretch(1, 1020);
688 ui->gridLineOSK->setColumnStretch(2, 130);
689 }
690
691 if (is_inline) {
692 return;
693 }
694
695 connect(ui->line_edit_osk, &QLineEdit::textChanged, [this](const QString& changed_string) {
696 const auto is_valid = ValidateInputText(changed_string);
697
698 const auto text_length = static_cast<u32>(changed_string.length());
699
700 ui->label_characters->setText(QStringLiteral("%1/%2")
701 .arg(text_length)
702 .arg(initialize_parameters.max_text_length));
703
704 ui->button_ok->setEnabled(is_valid);
705 ui->button_ok_shift->setEnabled(is_valid);
706 ui->button_ok_num->setEnabled(is_valid);
707
708 ui->line_edit_osk->setFocus();
709 });
710
711 connect(ui->line_edit_osk, &QLineEdit::cursorPositionChanged,
712 [this](int old_cursor_position, int new_cursor_position) {
713 ui->button_backspace->setEnabled(
714 initialize_parameters.enable_backspace_button && new_cursor_position > 0);
715 ui->button_backspace_shift->setEnabled(
716 initialize_parameters.enable_backspace_button && new_cursor_position > 0);
717 ui->button_backspace_num->setEnabled(
718 initialize_parameters.enable_backspace_button && new_cursor_position > 0);
719
720 ui->line_edit_osk->setFocus();
721 });
722
723 connect(ui->line_edit_osk, &QLineEdit::returnPressed, [this] {
724 switch (bottom_osk_index) {
725 case BottomOSKIndex::LowerCase:
726 ui->button_ok->click();
727 break;
728 case BottomOSKIndex::UpperCase:
729 ui->button_ok_shift->click();
730 break;
731 case BottomOSKIndex::NumberPad:
732 ui->button_ok_num->click();
733 break;
734 default:
735 break;
736 }
737 });
738
739 ui->line_edit_osk->setPlaceholderText(
740 QString::fromStdU16String(initialize_parameters.guide_text));
741 ui->line_edit_osk->setText(QString::fromStdU16String(initialize_parameters.initial_text));
742 ui->line_edit_osk->setMaxLength(initialize_parameters.max_text_length);
743 ui->line_edit_osk->setCursorPosition(initialize_parameters.initial_cursor_position);
744
745 ui->label_characters->setText(QStringLiteral("%1/%2")
746 .arg(initialize_parameters.initial_text.size())
747 .arg(initialize_parameters.max_text_length));
748 break;
749 }
750 case SwkbdTextDrawType::Box:
751 default: {
752 ui->topOSK->setCurrentIndex(1);
753
754 if (is_inline) {
755 return;
756 }
757
758 connect(ui->text_edit_osk, &QTextEdit::textChanged, [this] {
759 if (static_cast<u32>(ui->text_edit_osk->toPlainText().length()) >
760 initialize_parameters.max_text_length) {
761 auto text_cursor = ui->text_edit_osk->textCursor();
762 ui->text_edit_osk->setTextCursor(text_cursor);
763 text_cursor.deletePreviousChar();
764 }
765
766 const auto is_valid = ValidateInputText(ui->text_edit_osk->toPlainText());
767
768 const auto text_length = static_cast<u32>(ui->text_edit_osk->toPlainText().length());
769
770 ui->label_characters_box->setText(QStringLiteral("%1/%2")
771 .arg(text_length)
772 .arg(initialize_parameters.max_text_length));
773
774 ui->button_ok->setEnabled(is_valid);
775 ui->button_ok_shift->setEnabled(is_valid);
776 ui->button_ok_num->setEnabled(is_valid);
777
778 ui->text_edit_osk->setFocus();
779 });
780
781 connect(ui->text_edit_osk, &QTextEdit::cursorPositionChanged, [this] {
782 const auto new_cursor_position = ui->text_edit_osk->textCursor().position();
783
784 ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button &&
785 new_cursor_position > 0);
786 ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button &&
787 new_cursor_position > 0);
788 ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button &&
789 new_cursor_position > 0);
790
791 ui->text_edit_osk->setFocus();
792 });
793
794 ui->text_edit_osk->setPlaceholderText(
795 QString::fromStdU16String(initialize_parameters.guide_text));
796 ui->text_edit_osk->setText(QString::fromStdU16String(initialize_parameters.initial_text));
797 ui->text_edit_osk->moveCursor(initialize_parameters.initial_cursor_position == 0
798 ? QTextCursor::Start
799 : QTextCursor::End);
800
801 ui->label_characters_box->setText(QStringLiteral("%1/%2")
802 .arg(initialize_parameters.initial_text.size())
803 .arg(initialize_parameters.max_text_length));
804 break;
805 }
806 }
807}
808
809void QtSoftwareKeyboardDialog::SetControllerImage() {
810 const auto controller_type = Settings::values.players.GetValue()[8].connected
811 ? Settings::values.players.GetValue()[8].controller_type
812 : Settings::values.players.GetValue()[0].controller_type;
813
814 const QString theme = [] {
815 if (QIcon::themeName().contains(QStringLiteral("dark")) ||
816 QIcon::themeName().contains(QStringLiteral("midnight"))) {
817 return QStringLiteral("_dark");
818 } else {
819 return QString{};
820 }
821 }();
822
823 switch (controller_type) {
824 case Settings::ControllerType::ProController:
825 case Settings::ControllerType::GameCube:
826 ui->icon_controller->setStyleSheet(
827 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
828 ui->icon_controller_shift->setStyleSheet(
829 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
830 ui->icon_controller_num->setStyleSheet(
831 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
832 break;
833 case Settings::ControllerType::DualJoyconDetached:
834 ui->icon_controller->setStyleSheet(
835 QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
836 ui->icon_controller_shift->setStyleSheet(
837 QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
838 ui->icon_controller_num->setStyleSheet(
839 QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
840 break;
841 case Settings::ControllerType::LeftJoycon:
842 ui->icon_controller->setStyleSheet(
843 QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
844 .arg(theme));
845 ui->icon_controller_shift->setStyleSheet(
846 QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
847 .arg(theme));
848 ui->icon_controller_num->setStyleSheet(
849 QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
850 .arg(theme));
851 break;
852 case Settings::ControllerType::RightJoycon:
853 ui->icon_controller->setStyleSheet(
854 QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
855 .arg(theme));
856 ui->icon_controller_shift->setStyleSheet(
857 QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
858 .arg(theme));
859 ui->icon_controller_num->setStyleSheet(
860 QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
861 .arg(theme));
862 break;
863 case Settings::ControllerType::Handheld:
864 ui->icon_controller->setStyleSheet(
865 QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
866 ui->icon_controller_shift->setStyleSheet(
867 QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
868 ui->icon_controller_num->setStyleSheet(
869 QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
870 break;
871 default:
872 break;
873 }
874}
875
876void QtSoftwareKeyboardDialog::DisableKeyboardButtons() {
877 switch (bottom_osk_index) {
878 case BottomOSKIndex::LowerCase:
879 case BottomOSKIndex::UpperCase:
880 default: {
881 for (const auto& keys : keyboard_buttons) {
882 for (const auto& rows : keys) {
883 for (auto* button : rows) {
884 if (!button) {
885 continue;
886 }
887
888 button->setEnabled(true);
889 }
890 }
891 }
892
893 const auto& key_disable_flags = initialize_parameters.key_disable_flags;
894
895 ui->button_space->setDisabled(key_disable_flags.space);
896 ui->button_space_shift->setDisabled(key_disable_flags.space);
897
898 ui->button_at->setDisabled(key_disable_flags.at || key_disable_flags.username);
899
900 ui->button_percent->setDisabled(key_disable_flags.percent || key_disable_flags.username);
901
902 ui->button_slash->setDisabled(key_disable_flags.slash);
903
904 ui->button_1->setDisabled(key_disable_flags.numbers);
905 ui->button_2->setDisabled(key_disable_flags.numbers);
906 ui->button_3->setDisabled(key_disable_flags.numbers);
907 ui->button_4->setDisabled(key_disable_flags.numbers);
908 ui->button_5->setDisabled(key_disable_flags.numbers);
909 ui->button_6->setDisabled(key_disable_flags.numbers);
910 ui->button_7->setDisabled(key_disable_flags.numbers);
911 ui->button_8->setDisabled(key_disable_flags.numbers);
912 ui->button_9->setDisabled(key_disable_flags.numbers);
913 ui->button_0->setDisabled(key_disable_flags.numbers);
914
915 ui->button_return->setEnabled(initialize_parameters.enable_return_button);
916 ui->button_return_shift->setEnabled(initialize_parameters.enable_return_button);
917 break;
918 }
919 case BottomOSKIndex::NumberPad: {
920 for (const auto& rows : numberpad_buttons) {
921 for (auto* button : rows) {
922 if (!button) {
923 continue;
924 }
925
926 button->setEnabled(true);
927 }
928 }
929 break;
930 }
931 }
932}
933
934void QtSoftwareKeyboardDialog::SetBackspaceOkEnabled() {
935 if (is_inline) {
936 ui->button_ok->setEnabled(current_text.size() >= initialize_parameters.min_text_length);
937 ui->button_ok_shift->setEnabled(current_text.size() >=
938 initialize_parameters.min_text_length);
939 ui->button_ok_num->setEnabled(current_text.size() >= initialize_parameters.min_text_length);
940
941 ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button &&
942 cursor_position > 0);
943 ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button &&
944 cursor_position > 0);
945 ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button &&
946 cursor_position > 0);
88 } else { 947 } else {
89 buttons->addButton(QString::fromStdU16String(parameters.submit_text), 948 const auto text_length = [this] {
90 QDialogButtonBox::AcceptRole); 949 if (ui->topOSK->currentIndex() == 1) {
950 return static_cast<u32>(ui->text_edit_osk->toPlainText().length());
951 } else {
952 return static_cast<u32>(ui->line_edit_osk->text().length());
953 }
954 }();
955
956 const auto normal_cursor_position = [this] {
957 if (ui->topOSK->currentIndex() == 1) {
958 return ui->text_edit_osk->textCursor().position();
959 } else {
960 return ui->line_edit_osk->cursorPosition();
961 }
962 }();
963
964 ui->button_ok->setEnabled(text_length >= initialize_parameters.min_text_length);
965 ui->button_ok_shift->setEnabled(text_length >= initialize_parameters.min_text_length);
966 ui->button_ok_num->setEnabled(text_length >= initialize_parameters.min_text_length);
967
968 ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button &&
969 normal_cursor_position > 0);
970 ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button &&
971 normal_cursor_position > 0);
972 ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button &&
973 normal_cursor_position > 0);
91 } 974 }
92 connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept);
93 connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject);
94 layout->addWidget(header_label);
95 layout->addWidget(sub_label);
96 layout->addWidget(guide_label);
97 layout->addWidget(length_label);
98 layout->addWidget(line_edit);
99 layout->addWidget(buttons);
100 setLayout(layout);
101 setWindowTitle(tr("Software Keyboard"));
102} 975}
103 976
104QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; 977bool QtSoftwareKeyboardDialog::ValidateInputText(const QString& input_text) {
978 const auto& key_disable_flags = initialize_parameters.key_disable_flags;
979
980 const auto input_text_length = static_cast<u32>(input_text.length());
981
982 if (input_text_length < initialize_parameters.min_text_length ||
983 input_text_length > initialize_parameters.max_text_length) {
984 return false;
985 }
986
987 if (key_disable_flags.space && input_text.contains(QLatin1Char{' '})) {
988 return false;
989 }
990
991 if ((key_disable_flags.at || key_disable_flags.username) &&
992 input_text.contains(QLatin1Char{'@'})) {
993 return false;
994 }
995
996 if ((key_disable_flags.percent || key_disable_flags.username) &&
997 input_text.contains(QLatin1Char{'%'})) {
998 return false;
999 }
1000
1001 if (key_disable_flags.slash && input_text.contains(QLatin1Char{'/'})) {
1002 return false;
1003 }
1004
1005 if ((key_disable_flags.backslash || key_disable_flags.username) &&
1006 input_text.contains(QLatin1Char('\\'))) {
1007 return false;
1008 }
105 1009
106void QtSoftwareKeyboardDialog::accept() { 1010 if (key_disable_flags.numbers &&
107 text = line_edit->text().toStdU16String(); 1011 std::any_of(input_text.begin(), input_text.end(), [](QChar c) { return c.isDigit(); })) {
108 QDialog::accept(); 1012 return false;
1013 }
1014
1015 if (bottom_osk_index == BottomOSKIndex::NumberPad &&
1016 std::any_of(input_text.begin(), input_text.end(), [](QChar c) { return !c.isDigit(); })) {
1017 return false;
1018 }
1019
1020 return true;
109} 1021}
110 1022
111void QtSoftwareKeyboardDialog::reject() { 1023void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() {
112 text.clear(); 1024 switch (bottom_osk_index) {
113 QDialog::reject(); 1025 case BottomOSKIndex::LowerCase:
1026 bottom_osk_index = BottomOSKIndex::UpperCase;
1027 ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
1028
1029 ui->button_shift_shift->setStyleSheet(
1030 QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);"
1031 "\nbackground-position: left top;"
1032 "\nbackground-repeat: no-repeat;"
1033 "\nbackground-origin: content;"));
1034
1035 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
1036 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
1037 break;
1038 case BottomOSKIndex::UpperCase:
1039 if (caps_lock_enabled) {
1040 caps_lock_enabled = false;
1041
1042 ui->button_shift_shift->setStyleSheet(
1043 QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);"
1044 "\nbackground-position: left top;"
1045 "\nbackground-repeat: no-repeat;"
1046 "\nbackground-origin: content;"));
1047
1048 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
1049 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
1050
1051 ui->label_shift_shift->setText(QStringLiteral("Caps Lock"));
1052
1053 bottom_osk_index = BottomOSKIndex::LowerCase;
1054 ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
1055 } else {
1056 caps_lock_enabled = true;
1057
1058 ui->button_shift_shift->setStyleSheet(
1059 QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_on.png);"
1060 "\nbackground-position: left top;"
1061 "\nbackground-repeat: no-repeat;"
1062 "\nbackground-origin: content;"));
1063
1064 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
1065 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
1066
1067 ui->label_shift_shift->setText(QStringLiteral("Caps Lock Off"));
1068 }
1069 break;
1070 case BottomOSKIndex::NumberPad:
1071 default:
1072 break;
1073 }
114} 1074}
115 1075
116std::u16string QtSoftwareKeyboardDialog::GetText() const { 1076void QtSoftwareKeyboardDialog::NormalKeyboardButtonClicked(QPushButton* button) {
117 return text; 1077 if (button == ui->button_ampersand) {
1078 if (ui->topOSK->currentIndex() == 1) {
1079 ui->text_edit_osk->insertPlainText(QStringLiteral("&"));
1080 } else {
1081 ui->line_edit_osk->insert(QStringLiteral("&"));
1082 }
1083 return;
1084 }
1085
1086 if (button == ui->button_return || button == ui->button_return_shift) {
1087 if (ui->topOSK->currentIndex() == 1) {
1088 ui->text_edit_osk->insertPlainText(QStringLiteral("\n"));
1089 } else {
1090 ui->line_edit_osk->insert(QStringLiteral("\n"));
1091 }
1092 return;
1093 }
1094
1095 if (button == ui->button_space || button == ui->button_space_shift) {
1096 if (ui->topOSK->currentIndex() == 1) {
1097 ui->text_edit_osk->insertPlainText(QStringLiteral(" "));
1098 } else {
1099 ui->line_edit_osk->insert(QStringLiteral(" "));
1100 }
1101 return;
1102 }
1103
1104 if (button == ui->button_shift || button == ui->button_shift_shift) {
1105 ChangeBottomOSKIndex();
1106 return;
1107 }
1108
1109 if (button == ui->button_backspace || button == ui->button_backspace_shift ||
1110 button == ui->button_backspace_num) {
1111 if (ui->topOSK->currentIndex() == 1) {
1112 auto text_cursor = ui->text_edit_osk->textCursor();
1113 ui->text_edit_osk->setTextCursor(text_cursor);
1114 text_cursor.deletePreviousChar();
1115 } else {
1116 ui->line_edit_osk->backspace();
1117 }
1118 return;
1119 }
1120
1121 if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) {
1122 if (ui->topOSK->currentIndex() == 1) {
1123 emit SubmitNormalText(SwkbdResult::Ok,
1124 ui->text_edit_osk->toPlainText().toStdU16String());
1125 } else {
1126 emit SubmitNormalText(SwkbdResult::Ok, ui->line_edit_osk->text().toStdU16String());
1127 }
1128 return;
1129 }
1130
1131 if (ui->topOSK->currentIndex() == 1) {
1132 ui->text_edit_osk->insertPlainText(button->text());
1133 } else {
1134 ui->line_edit_osk->insert(button->text());
1135 }
1136
1137 // Revert the keyboard to lowercase if the shift key is active.
1138 if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) {
1139 // This is set to true since ChangeBottomOSKIndex will change bottom_osk_index to LowerCase
1140 // if bottom_osk_index is UpperCase and caps_lock_enabled is true.
1141 caps_lock_enabled = true;
1142 ChangeBottomOSKIndex();
1143 }
1144}
1145
1146void QtSoftwareKeyboardDialog::InlineKeyboardButtonClicked(QPushButton* button) {
1147 if (!button->isEnabled()) {
1148 return;
1149 }
1150
1151 if (button == ui->button_ampersand) {
1152 InlineTextInsertString(u"&");
1153 return;
1154 }
1155
1156 if (button == ui->button_return || button == ui->button_return_shift) {
1157 InlineTextInsertString(u"\n");
1158 return;
1159 }
1160
1161 if (button == ui->button_space || button == ui->button_space_shift) {
1162 InlineTextInsertString(u" ");
1163 return;
1164 }
1165
1166 if (button == ui->button_shift || button == ui->button_shift_shift) {
1167 ChangeBottomOSKIndex();
1168 return;
1169 }
1170
1171 if (button == ui->button_backspace || button == ui->button_backspace_shift ||
1172 button == ui->button_backspace_num) {
1173 if (cursor_position <= 0 || current_text.empty()) {
1174 cursor_position = 0;
1175 return;
1176 }
1177
1178 --cursor_position;
1179
1180 current_text.erase(cursor_position, 1);
1181
1182 SetBackspaceOkEnabled();
1183
1184 emit SubmitInlineText(SwkbdReplyType::ChangedString, current_text, cursor_position);
1185 return;
1186 }
1187
1188 if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) {
1189 emit SubmitInlineText(SwkbdReplyType::DecidedEnter, current_text, cursor_position);
1190 return;
1191 }
1192
1193 InlineTextInsertString(button->text().toStdU16String());
1194
1195 // Revert the keyboard to lowercase if the shift key is active.
1196 if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) {
1197 // This is set to true since ChangeBottomOSKIndex will change bottom_osk_index to LowerCase
1198 // if bottom_osk_index is UpperCase and caps_lock_enabled is true.
1199 caps_lock_enabled = true;
1200 ChangeBottomOSKIndex();
1201 }
1202}
1203
1204void QtSoftwareKeyboardDialog::InlineTextInsertString(std::u16string_view string) {
1205 if ((current_text.size() + string.size()) > initialize_parameters.max_text_length) {
1206 return;
1207 }
1208
1209 current_text.insert(cursor_position, string);
1210
1211 cursor_position += static_cast<s32>(string.size());
1212
1213 SetBackspaceOkEnabled();
1214
1215 emit SubmitInlineText(SwkbdReplyType::ChangedString, current_text, cursor_position);
1216}
1217
1218void QtSoftwareKeyboardDialog::SetupMouseHover() {
1219 // setFocus() has a bug where continuously changing focus will cause the focus UI to
1220 // mysteriously disappear. A workaround we have found is using the mouse to hover over
1221 // the buttons to act in place of the button focus. As a result, we will have to set
1222 // a blank cursor when hovering over all the buttons and set a no focus policy so the
1223 // buttons do not stay in focus in addition to the mouse hover.
1224 for (auto* button : all_buttons) {
1225 button->setCursor(QCursor(Qt::BlankCursor));
1226 button->setFocusPolicy(Qt::NoFocus);
1227 }
1228}
1229
1230template <HIDButton... T>
1231void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() {
1232 const auto f = [this](HIDButton button) {
1233 if (input_interpreter->IsButtonPressedOnce(button)) {
1234 TranslateButtonPress(button);
1235 }
1236 };
1237
1238 (f(T), ...);
1239}
1240
1241template <HIDButton... T>
1242void QtSoftwareKeyboardDialog::HandleButtonHold() {
1243 const auto f = [this](HIDButton button) {
1244 if (input_interpreter->IsButtonHeld(button)) {
1245 TranslateButtonPress(button);
1246 }
1247 };
1248
1249 (f(T), ...);
1250}
1251
1252void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
1253 switch (button) {
1254 case HIDButton::A:
1255 switch (bottom_osk_index) {
1256 case BottomOSKIndex::LowerCase:
1257 case BottomOSKIndex::UpperCase:
1258 keyboard_buttons[static_cast<std::size_t>(bottom_osk_index)][row][column]->click();
1259 break;
1260 case BottomOSKIndex::NumberPad:
1261 numberpad_buttons[row][column]->click();
1262 break;
1263 default:
1264 break;
1265 }
1266 break;
1267 case HIDButton::B:
1268 switch (bottom_osk_index) {
1269 case BottomOSKIndex::LowerCase:
1270 ui->button_backspace->click();
1271 break;
1272 case BottomOSKIndex::UpperCase:
1273 ui->button_backspace_shift->click();
1274 break;
1275 case BottomOSKIndex::NumberPad:
1276 ui->button_backspace_num->click();
1277 break;
1278 default:
1279 break;
1280 }
1281 break;
1282 case HIDButton::X:
1283 if (is_inline) {
1284 emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
1285 } else {
1286 if (ui->topOSK->currentIndex() == 1) {
1287 emit SubmitNormalText(SwkbdResult::Cancel,
1288 ui->text_edit_osk->toPlainText().toStdU16String());
1289 } else {
1290 emit SubmitNormalText(SwkbdResult::Cancel,
1291 ui->line_edit_osk->text().toStdU16String());
1292 }
1293 }
1294 break;
1295 case HIDButton::Y:
1296 switch (bottom_osk_index) {
1297 case BottomOSKIndex::LowerCase:
1298 ui->button_space->click();
1299 break;
1300 case BottomOSKIndex::UpperCase:
1301 ui->button_space_shift->click();
1302 break;
1303 case BottomOSKIndex::NumberPad:
1304 default:
1305 break;
1306 }
1307 break;
1308 case HIDButton::LStick:
1309 case HIDButton::RStick:
1310 switch (bottom_osk_index) {
1311 case BottomOSKIndex::LowerCase:
1312 ui->button_shift->click();
1313 break;
1314 case BottomOSKIndex::UpperCase:
1315 ui->button_shift_shift->click();
1316 break;
1317 case BottomOSKIndex::NumberPad:
1318 default:
1319 break;
1320 }
1321 break;
1322 case HIDButton::L:
1323 MoveTextCursorDirection(Direction::Left);
1324 break;
1325 case HIDButton::R:
1326 MoveTextCursorDirection(Direction::Right);
1327 break;
1328 case HIDButton::Plus:
1329 switch (bottom_osk_index) {
1330 case BottomOSKIndex::LowerCase:
1331 ui->button_ok->click();
1332 break;
1333 case BottomOSKIndex::UpperCase:
1334 ui->button_ok_shift->click();
1335 break;
1336 case BottomOSKIndex::NumberPad:
1337 ui->button_ok_num->click();
1338 break;
1339 default:
1340 break;
1341 }
1342 break;
1343 case HIDButton::DLeft:
1344 case HIDButton::LStickLeft:
1345 case HIDButton::RStickLeft:
1346 MoveButtonDirection(Direction::Left);
1347 break;
1348 case HIDButton::DUp:
1349 case HIDButton::LStickUp:
1350 case HIDButton::RStickUp:
1351 MoveButtonDirection(Direction::Up);
1352 break;
1353 case HIDButton::DRight:
1354 case HIDButton::LStickRight:
1355 case HIDButton::RStickRight:
1356 MoveButtonDirection(Direction::Right);
1357 break;
1358 case HIDButton::DDown:
1359 case HIDButton::LStickDown:
1360 case HIDButton::RStickDown:
1361 MoveButtonDirection(Direction::Down);
1362 break;
1363 default:
1364 break;
1365 }
1366}
1367
1368void QtSoftwareKeyboardDialog::MoveButtonDirection(Direction direction) {
1369 // Changes the row or column index depending on the direction.
1370 auto move_direction = [this, direction](std::size_t max_rows, std::size_t max_columns) {
1371 switch (direction) {
1372 case Direction::Left:
1373 column = (column + max_columns - 1) % max_columns;
1374 break;
1375 case Direction::Up:
1376 row = (row + max_rows - 1) % max_rows;
1377 break;
1378 case Direction::Right:
1379 column = (column + 1) % max_columns;
1380 break;
1381 case Direction::Down:
1382 row = (row + 1) % max_rows;
1383 break;
1384 default:
1385 break;
1386 }
1387 };
1388
1389 switch (bottom_osk_index) {
1390 case BottomOSKIndex::LowerCase:
1391 case BottomOSKIndex::UpperCase: {
1392 const auto index = static_cast<std::size_t>(bottom_osk_index);
1393
1394 const auto* const prev_button = keyboard_buttons[index][row][column];
1395 move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL);
1396 auto* curr_button = keyboard_buttons[index][row][column];
1397
1398 while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) {
1399 move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL);
1400 curr_button = keyboard_buttons[index][row][column];
1401 }
1402
1403 // This is a workaround for setFocus() randomly not showing focus in the UI
1404 QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center()));
1405 break;
1406 }
1407 case BottomOSKIndex::NumberPad: {
1408 const auto* const prev_button = numberpad_buttons[row][column];
1409 move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD);
1410 auto* curr_button = numberpad_buttons[row][column];
1411
1412 while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) {
1413 move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD);
1414 curr_button = numberpad_buttons[row][column];
1415 }
1416
1417 // This is a workaround for setFocus() randomly not showing focus in the UI
1418 QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center()));
1419 break;
1420 }
1421 default:
1422 break;
1423 }
1424}
1425
1426void QtSoftwareKeyboardDialog::MoveTextCursorDirection(Direction direction) {
1427 switch (direction) {
1428 case Direction::Left:
1429 if (is_inline) {
1430 if (cursor_position <= 0) {
1431 cursor_position = 0;
1432 } else {
1433 --cursor_position;
1434 emit SubmitInlineText(SwkbdReplyType::MovedCursor, current_text, cursor_position);
1435 }
1436 } else {
1437 if (ui->topOSK->currentIndex() == 1) {
1438 ui->text_edit_osk->moveCursor(QTextCursor::Left);
1439 } else {
1440 ui->line_edit_osk->setCursorPosition(ui->line_edit_osk->cursorPosition() - 1);
1441 }
1442 }
1443 break;
1444 case Direction::Right:
1445 if (is_inline) {
1446 if (cursor_position >= static_cast<s32>(current_text.size())) {
1447 cursor_position = static_cast<s32>(current_text.size());
1448 } else {
1449 ++cursor_position;
1450 emit SubmitInlineText(SwkbdReplyType::MovedCursor, current_text, cursor_position);
1451 }
1452 } else {
1453 if (ui->topOSK->currentIndex() == 1) {
1454 ui->text_edit_osk->moveCursor(QTextCursor::Right);
1455 } else {
1456 ui->line_edit_osk->setCursorPosition(ui->line_edit_osk->cursorPosition() + 1);
1457 }
1458 }
1459 break;
1460 default:
1461 break;
1462 }
1463}
1464
1465void QtSoftwareKeyboardDialog::StartInputThread() {
1466 if (input_thread_running) {
1467 return;
1468 }
1469
1470 input_thread_running = true;
1471
1472 input_thread = std::thread(&QtSoftwareKeyboardDialog::InputThread, this);
1473}
1474
1475void QtSoftwareKeyboardDialog::StopInputThread() {
1476 input_thread_running = false;
1477
1478 if (input_thread.joinable()) {
1479 input_thread.join();
1480 }
1481
1482 if (input_interpreter) {
1483 input_interpreter->ResetButtonStates();
1484 }
1485}
1486
1487void QtSoftwareKeyboardDialog::InputThread() {
1488 while (input_thread_running) {
1489 input_interpreter->PollInput();
1490
1491 HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::X, HIDButton::Y,
1492 HIDButton::LStick, HIDButton::RStick, HIDButton::L, HIDButton::R,
1493 HIDButton::Plus, HIDButton::DLeft, HIDButton::DUp,
1494 HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft,
1495 HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown,
1496 HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight,
1497 HIDButton::RStickDown>();
1498
1499 HandleButtonHold<HIDButton::B, HIDButton::L, HIDButton::R, HIDButton::DLeft, HIDButton::DUp,
1500 HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft,
1501 HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown,
1502 HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight,
1503 HIDButton::RStickDown>();
1504
1505 std::this_thread::sleep_for(std::chrono::milliseconds(50));
1506 }
118} 1507}
119 1508
120QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) { 1509QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) {
121 connect(this, &QtSoftwareKeyboard::MainWindowGetText, &main_window, 1510 connect(this, &QtSoftwareKeyboard::MainWindowInitializeKeyboard, &main_window,
122 &GMainWindow::SoftwareKeyboardGetText, Qt::QueuedConnection); 1511 &GMainWindow::SoftwareKeyboardInitialize, Qt::QueuedConnection);
123 connect(this, &QtSoftwareKeyboard::MainWindowTextCheckDialog, &main_window, 1512 connect(this, &QtSoftwareKeyboard::MainWindowShowNormalKeyboard, &main_window,
124 &GMainWindow::SoftwareKeyboardInvokeCheckDialog, Qt::BlockingQueuedConnection); 1513 &GMainWindow::SoftwareKeyboardShowNormal, Qt::QueuedConnection);
125 connect(&main_window, &GMainWindow::SoftwareKeyboardFinishedText, this, 1514 connect(this, &QtSoftwareKeyboard::MainWindowShowTextCheckDialog, &main_window,
126 &QtSoftwareKeyboard::MainWindowFinishedText, Qt::QueuedConnection); 1515 &GMainWindow::SoftwareKeyboardShowTextCheck, Qt::QueuedConnection);
1516 connect(this, &QtSoftwareKeyboard::MainWindowShowInlineKeyboard, &main_window,
1517 &GMainWindow::SoftwareKeyboardShowInline, Qt::QueuedConnection);
1518 connect(this, &QtSoftwareKeyboard::MainWindowHideInlineKeyboard, &main_window,
1519 &GMainWindow::SoftwareKeyboardHideInline, Qt::QueuedConnection);
1520 connect(this, &QtSoftwareKeyboard::MainWindowInlineTextChanged, &main_window,
1521 &GMainWindow::SoftwareKeyboardInlineTextChanged, Qt::QueuedConnection);
1522 connect(this, &QtSoftwareKeyboard::MainWindowExitKeyboard, &main_window,
1523 &GMainWindow::SoftwareKeyboardExit, Qt::QueuedConnection);
1524 connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitNormalText, this,
1525 &QtSoftwareKeyboard::SubmitNormalText, Qt::QueuedConnection);
1526 connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitInlineText, this,
1527 &QtSoftwareKeyboard::SubmitInlineText, Qt::QueuedConnection);
127} 1528}
128 1529
129QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; 1530QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
130 1531
131void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, 1532void QtSoftwareKeyboard::InitializeKeyboard(
132 Core::Frontend::SoftwareKeyboardParameters parameters) const { 1533 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
133 text_output = std::move(out); 1534 std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
134 emit MainWindowGetText(parameters); 1535 std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
1536 submit_inline_callback_) {
1537 if (is_inline) {
1538 submit_inline_callback = std::move(submit_inline_callback_);
1539 } else {
1540 submit_normal_callback = std::move(submit_normal_callback_);
1541 }
1542
1543 LOG_INFO(Service_AM,
1544 "\nKeyboardInitializeParameters:"
1545 "\nok_text={}"
1546 "\nheader_text={}"
1547 "\nsub_text={}"
1548 "\nguide_text={}"
1549 "\ninitial_text={}"
1550 "\nmax_text_length={}"
1551 "\nmin_text_length={}"
1552 "\ninitial_cursor_position={}"
1553 "\ntype={}"
1554 "\npassword_mode={}"
1555 "\ntext_draw_type={}"
1556 "\nkey_disable_flags={}"
1557 "\nuse_blur_background={}"
1558 "\nenable_backspace_button={}"
1559 "\nenable_return_button={}"
1560 "\ndisable_cancel_button={}",
1561 Common::UTF16ToUTF8(initialize_parameters.ok_text),
1562 Common::UTF16ToUTF8(initialize_parameters.header_text),
1563 Common::UTF16ToUTF8(initialize_parameters.sub_text),
1564 Common::UTF16ToUTF8(initialize_parameters.guide_text),
1565 Common::UTF16ToUTF8(initialize_parameters.initial_text),
1566 initialize_parameters.max_text_length, initialize_parameters.min_text_length,
1567 initialize_parameters.initial_cursor_position, initialize_parameters.type,
1568 initialize_parameters.password_mode, initialize_parameters.text_draw_type,
1569 initialize_parameters.key_disable_flags.raw, initialize_parameters.use_blur_background,
1570 initialize_parameters.enable_backspace_button,
1571 initialize_parameters.enable_return_button,
1572 initialize_parameters.disable_cancel_button);
1573
1574 emit MainWindowInitializeKeyboard(is_inline, std::move(initialize_parameters));
1575}
1576
1577void QtSoftwareKeyboard::ShowNormalKeyboard() const {
1578 emit MainWindowShowNormalKeyboard();
1579}
1580
1581void QtSoftwareKeyboard::ShowTextCheckDialog(
1582 Service::AM::Applets::SwkbdTextCheckResult text_check_result,
1583 std::u16string text_check_message) const {
1584 emit MainWindowShowTextCheckDialog(text_check_result, text_check_message);
1585}
1586
1587void QtSoftwareKeyboard::ShowInlineKeyboard(
1588 Core::Frontend::InlineAppearParameters appear_parameters) const {
1589 LOG_INFO(Service_AM,
1590 "\nInlineAppearParameters:"
1591 "\nmax_text_length={}"
1592 "\nmin_text_length={}"
1593 "\nkey_top_scale_x={}"
1594 "\nkey_top_scale_y={}"
1595 "\nkey_top_translate_x={}"
1596 "\nkey_top_translate_y={}"
1597 "\ntype={}"
1598 "\nkey_disable_flags={}"
1599 "\nkey_top_as_floating={}"
1600 "\nenable_backspace_button={}"
1601 "\nenable_return_button={}"
1602 "\ndisable_cancel_button={}",
1603 appear_parameters.max_text_length, appear_parameters.min_text_length,
1604 appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y,
1605 appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y,
1606 appear_parameters.type, appear_parameters.key_disable_flags.raw,
1607 appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button,
1608 appear_parameters.enable_return_button, appear_parameters.disable_cancel_button);
1609
1610 emit MainWindowShowInlineKeyboard(std::move(appear_parameters));
1611}
1612
1613void QtSoftwareKeyboard::HideInlineKeyboard() const {
1614 emit MainWindowHideInlineKeyboard();
1615}
1616
1617void QtSoftwareKeyboard::InlineTextChanged(
1618 Core::Frontend::InlineTextParameters text_parameters) const {
1619 LOG_INFO(Service_AM,
1620 "\nInlineTextParameters:"
1621 "\ninput_text={}"
1622 "\ncursor_position={}",
1623 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
1624
1625 emit MainWindowInlineTextChanged(std::move(text_parameters));
135} 1626}
136 1627
137void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, 1628void QtSoftwareKeyboard::ExitKeyboard() const {
138 std::function<void()> finished_check_) const { 1629 emit MainWindowExitKeyboard();
139 finished_check = std::move(finished_check_);
140 emit MainWindowTextCheckDialog(error_message);
141} 1630}
142 1631
143void QtSoftwareKeyboard::MainWindowFinishedText(std::optional<std::u16string> text) { 1632void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Applets::SwkbdResult result,
144 // Acquire the HLE mutex 1633 std::u16string submitted_text) const {
145 std::lock_guard lock{HLE::g_hle_lock}; 1634 submit_normal_callback(result, submitted_text);
146 text_output(std::move(text));
147} 1635}
148 1636
149void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() { 1637void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
150 // Acquire the HLE mutex 1638 std::u16string submitted_text,
151 std::lock_guard lock{HLE::g_hle_lock}; 1639 s32 cursor_position) const {
152 finished_check(); 1640 submit_inline_callback(reply_type, submitted_text, cursor_position);
153} 1641}
diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/software_keyboard.h
index 9e1094cce..1a03c098c 100644
--- a/src/yuzu/applets/software_keyboard.h
+++ b/src/yuzu/applets/software_keyboard.h
@@ -1,54 +1,228 @@
1// Copyright 2018 yuzu Emulator Project 1// Copyright 2021 yuzu Emulator Project
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 5#pragma once
6 6
7#include <array>
8#include <atomic>
9#include <memory>
10#include <thread>
11
7#include <QDialog> 12#include <QDialog>
8#include <QValidator> 13#include <QValidator>
14
9#include "core/frontend/applets/software_keyboard.h" 15#include "core/frontend/applets/software_keyboard.h"
10 16
11class GMainWindow; 17enum class HIDButton : u8;
12class QDialogButtonBox;
13class QLabel;
14class QLineEdit;
15class QVBoxLayout;
16class QtSoftwareKeyboard;
17 18
18class QtSoftwareKeyboardValidator final : public QValidator { 19class InputInterpreter;
19public:
20 explicit QtSoftwareKeyboardValidator(Core::Frontend::SoftwareKeyboardParameters parameters);
21 State validate(QString& input, int& pos) const override;
22 20
23private: 21namespace Core {
24 Core::Frontend::SoftwareKeyboardParameters parameters; 22class System;
25}; 23}
24
25namespace Ui {
26class QtSoftwareKeyboardDialog;
27}
28
29class GMainWindow;
26 30
27class QtSoftwareKeyboardDialog final : public QDialog { 31class QtSoftwareKeyboardDialog final : public QDialog {
28 Q_OBJECT 32 Q_OBJECT
29 33
30public: 34public:
31 QtSoftwareKeyboardDialog(QWidget* parent, 35 QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_,
32 Core::Frontend::SoftwareKeyboardParameters parameters); 36 Core::Frontend::KeyboardInitializeParameters initialize_parameters_);
33 ~QtSoftwareKeyboardDialog() override; 37 ~QtSoftwareKeyboardDialog() override;
34 38
35 void accept() override; 39 void ShowNormalKeyboard(QPoint pos, QSize size);
40
41 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
42 std::u16string text_check_message);
43
44 void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos,
45 QSize size);
46
47 void HideInlineKeyboard();
48
49 void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
50
51 void ExitKeyboard();
52
53signals:
54 void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
55 std::u16string submitted_text) const;
56
57 void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
58 std::u16string submitted_text, s32 cursor_position) const;
59
60public slots:
61 void open() override;
36 void reject() override; 62 void reject() override;
37 63
38 std::u16string GetText() const; 64protected:
65 /// We override the keyPressEvent for inputting text into the inline software keyboard.
66 void keyPressEvent(QKeyEvent* event) override;
39 67
40private: 68private:
41 std::u16string text; 69 enum class Direction {
70 Left,
71 Up,
72 Right,
73 Down,
74 };
75
76 enum class BottomOSKIndex {
77 LowerCase,
78 UpperCase,
79 NumberPad,
80 };
81
82 /**
83 * Moves and resizes the window to a specified position and size.
84 *
85 * @param pos Top-left window position
86 * @param size Window size
87 */
88 void MoveAndResizeWindow(QPoint pos, QSize size);
89
90 /**
91 * Rescales all keyboard elements to account for High DPI displays.
92 *
93 * @param width Window width
94 * @param height Window height
95 * @param dpi_scale Display scaling factor
96 */
97 void RescaleKeyboardElements(float width, float height, float dpi_scale);
98
99 /// Sets the keyboard type based on initialize_parameters.
100 void SetKeyboardType();
101
102 /// Sets the password mode based on initialize_parameters.
103 void SetPasswordMode();
104
105 /// Sets the text draw type based on initialize_parameters.
106 void SetTextDrawType();
107
108 /// Sets the controller image at the bottom left of the software keyboard.
109 void SetControllerImage();
110
111 /// Disables buttons based on initialize_parameters.
112 void DisableKeyboardButtons();
113
114 /// Changes whether the backspace or/and ok buttons should be enabled or disabled.
115 void SetBackspaceOkEnabled();
116
117 /**
118 * Validates the input text sent in based on the parameters in initialize_parameters.
119 *
120 * @param input_text Input text
121 *
122 * @returns True if the input text is valid, false otherwise.
123 */
124 bool ValidateInputText(const QString& input_text);
125
126 /// Switches between LowerCase and UpperCase (Shift and Caps Lock)
127 void ChangeBottomOSKIndex();
128
129 /// Processes a keyboard button click from the UI as normal keyboard input.
130 void NormalKeyboardButtonClicked(QPushButton* button);
131
132 /// Processes a keyboard button click from the UI as inline keyboard input.
133 void InlineKeyboardButtonClicked(QPushButton* button);
134
135 /**
136 * Inserts a string of arbitrary length into the current_text at the current cursor position.
137 * This is only used for the inline software keyboard.
138 */
139 void InlineTextInsertString(std::u16string_view string);
42 140
43 QDialogButtonBox* buttons; 141 /// Setup the mouse hover workaround for "focusing" buttons. This should only be called once.
44 QLabel* header_label; 142 void SetupMouseHover();
45 QLabel* sub_label;
46 QLabel* guide_label;
47 QLabel* length_label;
48 QLineEdit* line_edit;
49 QVBoxLayout* layout;
50 143
51 Core::Frontend::SoftwareKeyboardParameters parameters; 144 /**
145 * Handles button presses and converts them into keyboard input.
146 *
147 * @tparam HIDButton The list of buttons that can be converted into keyboard input.
148 */
149 template <HIDButton... T>
150 void HandleButtonPressedOnce();
151
152 /**
153 * Handles button holds and converts them into keyboard input.
154 *
155 * @tparam HIDButton The list of buttons that can be converted into keyboard input.
156 */
157 template <HIDButton... T>
158 void HandleButtonHold();
159
160 /**
161 * Translates a button press to focus or click a keyboard button.
162 *
163 * @param button The button press to process.
164 */
165 void TranslateButtonPress(HIDButton button);
166
167 /**
168 * Moves the focus of a button in a certain direction.
169 *
170 * @param direction The direction to move.
171 */
172 void MoveButtonDirection(Direction direction);
173
174 /**
175 * Moves the text cursor in a certain direction.
176 *
177 * @param direction The direction to move.
178 */
179 void MoveTextCursorDirection(Direction direction);
180
181 void StartInputThread();
182 void StopInputThread();
183
184 /// The thread where input is being polled and processed.
185 void InputThread();
186
187 std::unique_ptr<Ui::QtSoftwareKeyboardDialog> ui;
188
189 Core::System& system;
190
191 // True if it is the inline software keyboard.
192 bool is_inline;
193
194 // Common software keyboard initialize parameters.
195 Core::Frontend::KeyboardInitializeParameters initialize_parameters;
196
197 // Used only by the inline software keyboard since the QLineEdit or QTextEdit is hidden.
198 std::u16string current_text;
199 s32 cursor_position{0};
200
201 static constexpr std::size_t NUM_ROWS_NORMAL = 5;
202 static constexpr std::size_t NUM_COLUMNS_NORMAL = 12;
203 static constexpr std::size_t NUM_ROWS_NUMPAD = 4;
204 static constexpr std::size_t NUM_COLUMNS_NUMPAD = 4;
205
206 // Stores the normal keyboard layout.
207 std::array<std::array<std::array<QPushButton*, NUM_COLUMNS_NORMAL>, NUM_ROWS_NORMAL>, 2>
208 keyboard_buttons;
209 // Stores the numberpad keyboard layout.
210 std::array<std::array<QPushButton*, NUM_COLUMNS_NUMPAD>, NUM_ROWS_NUMPAD> numberpad_buttons;
211
212 // Contains a set of all buttons used in keyboard_buttons and numberpad_buttons.
213 std::array<QPushButton*, 110> all_buttons;
214
215 std::size_t row{0};
216 std::size_t column{0};
217
218 BottomOSKIndex bottom_osk_index{BottomOSKIndex::LowerCase};
219 std::atomic<bool> caps_lock_enabled{false};
220
221 std::unique_ptr<InputInterpreter> input_interpreter;
222
223 std::thread input_thread;
224
225 std::atomic<bool> input_thread_running{};
52}; 226};
53 227
54class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet { 228class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet {
@@ -58,19 +232,54 @@ public:
58 explicit QtSoftwareKeyboard(GMainWindow& parent); 232 explicit QtSoftwareKeyboard(GMainWindow& parent);
59 ~QtSoftwareKeyboard() override; 233 ~QtSoftwareKeyboard() override;
60 234
61 void RequestText(std::function<void(std::optional<std::u16string>)> out, 235 void InitializeKeyboard(
62 Core::Frontend::SoftwareKeyboardParameters parameters) const override; 236 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
63 void SendTextCheckDialog(std::u16string error_message, 237 std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
64 std::function<void()> finished_check_) const override; 238 submit_normal_callback_,
239 std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
240 submit_inline_callback_) override;
241
242 void ShowNormalKeyboard() const override;
243
244 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
245 std::u16string text_check_message) const override;
246
247 void ShowInlineKeyboard(
248 Core::Frontend::InlineAppearParameters appear_parameters) const override;
249
250 void HideInlineKeyboard() const override;
251
252 void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override;
253
254 void ExitKeyboard() const override;
65 255
66signals: 256signals:
67 void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const; 257 void MainWindowInitializeKeyboard(
68 void MainWindowTextCheckDialog(std::u16string error_message) const; 258 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) const;
259
260 void MainWindowShowNormalKeyboard() const;
261
262 void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
263 std::u16string text_check_message) const;
264
265 void MainWindowShowInlineKeyboard(
266 Core::Frontend::InlineAppearParameters appear_parameters) const;
267
268 void MainWindowHideInlineKeyboard() const;
269
270 void MainWindowInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const;
271
272 void MainWindowExitKeyboard() const;
69 273
70private: 274private:
71 void MainWindowFinishedText(std::optional<std::u16string> text); 275 void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
72 void MainWindowFinishedCheckDialog(); 276 std::u16string submitted_text) const;
277
278 void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
279 std::u16string submitted_text, s32 cursor_position) const;
73 280
74 mutable std::function<void(std::optional<std::u16string>)> text_output; 281 mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
75 mutable std::function<void()> finished_check; 282 submit_normal_callback;
283 mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
284 submit_inline_callback;
76}; 285};
diff --git a/src/yuzu/applets/software_keyboard.ui b/src/yuzu/applets/software_keyboard.ui
new file mode 100644
index 000000000..b0a1fcde9
--- /dev/null
+++ b/src/yuzu/applets/software_keyboard.ui
@@ -0,0 +1,3503 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>QtSoftwareKeyboardDialog</class>
4 <widget class="QDialog" name="QtSoftwareKeyboardDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>1280</width>
10 <height>720</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Software Keyboard</string>
15 </property>
16 <property name="styleSheet">
17 <string notr="true"/>
18 </property>
19 <layout class="QVBoxLayout" name="verticalLayout">
20 <property name="spacing">
21 <number>0</number>
22 </property>
23 <property name="leftMargin">
24 <number>0</number>
25 </property>
26 <property name="topMargin">
27 <number>0</number>
28 </property>
29 <property name="rightMargin">
30 <number>0</number>
31 </property>
32 <property name="bottomMargin">
33 <number>0</number>
34 </property>
35 <item>
36 <widget class="QWidget" name="mainOSK" native="true">
37 <layout class="QVBoxLayout" name="verticalLayout_2" stretch="320,400">
38 <property name="spacing">
39 <number>0</number>
40 </property>
41 <property name="leftMargin">
42 <number>0</number>
43 </property>
44 <property name="topMargin">
45 <number>0</number>
46 </property>
47 <property name="rightMargin">
48 <number>0</number>
49 </property>
50 <property name="bottomMargin">
51 <number>0</number>
52 </property>
53 <item>
54 <widget class="QStackedWidget" name="topOSK">
55 <property name="currentIndex">
56 <number>0</number>
57 </property>
58 <widget class="QWidget" name="lineOSK">
59 <property name="minimumSize">
60 <size>
61 <width>0</width>
62 <height>100</height>
63 </size>
64 </property>
65 <layout class="QVBoxLayout" name="lineOSKVerticalLayout">
66 <property name="spacing">
67 <number>0</number>
68 </property>
69 <property name="leftMargin">
70 <number>0</number>
71 </property>
72 <property name="topMargin">
73 <number>0</number>
74 </property>
75 <property name="rightMargin">
76 <number>0</number>
77 </property>
78 <property name="bottomMargin">
79 <number>0</number>
80 </property>
81 <item>
82 <layout class="QGridLayout" name="gridLineOSK" rowstretch="40,50,23,48,65,94" columnstretch="130,1020,130">
83 <property name="topMargin">
84 <number>0</number>
85 </property>
86 <property name="spacing">
87 <number>0</number>
88 </property>
89 <item row="4" column="2">
90 <spacer name="horizontalSpacer_3">
91 <property name="orientation">
92 <enum>Qt::Horizontal</enum>
93 </property>
94 <property name="sizeHint" stdset="0">
95 <size>
96 <width>40</width>
97 <height>20</height>
98 </size>
99 </property>
100 </spacer>
101 </item>
102 <item row="4" column="0">
103 <spacer name="horizontalSpacer_4">
104 <property name="orientation">
105 <enum>Qt::Horizontal</enum>
106 </property>
107 <property name="sizeHint" stdset="0">
108 <size>
109 <width>40</width>
110 <height>20</height>
111 </size>
112 </property>
113 </spacer>
114 </item>
115 <item row="5" column="1">
116 <widget class="QWidget" name="charactersOSK" native="true">
117 <layout class="QVBoxLayout" name="verticalLayout_5">
118 <property name="spacing">
119 <number>0</number>
120 </property>
121 <property name="leftMargin">
122 <number>0</number>
123 </property>
124 <property name="topMargin">
125 <number>0</number>
126 </property>
127 <property name="rightMargin">
128 <number>0</number>
129 </property>
130 <property name="bottomMargin">
131 <number>0</number>
132 </property>
133 <item alignment="Qt::AlignRight|Qt::AlignTop">
134 <widget class="QLabel" name="label_characters">
135 <property name="font">
136 <font>
137 <pointsize>17</pointsize>
138 </font>
139 </property>
140 <property name="text">
141 <string notr="true">0/32</string>
142 </property>
143 <property name="alignment">
144 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
145 </property>
146 </widget>
147 </item>
148 </layout>
149 </widget>
150 </item>
151 <item row="3" column="1">
152 <spacer name="verticalSpacer_2">
153 <property name="orientation">
154 <enum>Qt::Vertical</enum>
155 </property>
156 <property name="sizeHint" stdset="0">
157 <size>
158 <width>20</width>
159 <height>40</height>
160 </size>
161 </property>
162 </spacer>
163 </item>
164 <item row="5" column="0">
165 <spacer name="verticalSpacer_3">
166 <property name="orientation">
167 <enum>Qt::Vertical</enum>
168 </property>
169 <property name="sizeHint" stdset="0">
170 <size>
171 <width>20</width>
172 <height>40</height>
173 </size>
174 </property>
175 </spacer>
176 </item>
177 <item row="4" column="1">
178 <widget class="QWidget" name="inputOSK" native="true">
179 <layout class="QVBoxLayout" name="verticalLayout_3">
180 <item>
181 <widget class="QLineEdit" name="line_edit_osk">
182 <property name="font">
183 <font>
184 <pointsize>26</pointsize>
185 <weight>50</weight>
186 <bold>false</bold>
187 </font>
188 </property>
189 <property name="focusPolicy">
190 <enum>Qt::StrongFocus</enum>
191 </property>
192 <property name="text">
193 <string/>
194 </property>
195 <property name="maxLength">
196 <number>32</number>
197 </property>
198 <property name="placeholderText">
199 <string>Enter Text</string>
200 </property>
201 </widget>
202 </item>
203 </layout>
204 </widget>
205 </item>
206 <item row="0" column="1">
207 <spacer name="verticalSpacer_4">
208 <property name="orientation">
209 <enum>Qt::Vertical</enum>
210 </property>
211 <property name="sizeHint" stdset="0">
212 <size>
213 <width>20</width>
214 <height>40</height>
215 </size>
216 </property>
217 </spacer>
218 </item>
219 <item row="1" column="0" colspan="3">
220 <widget class="QWidget" name="headerOSK" native="true">
221 <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="130,1020,130">
222 <property name="spacing">
223 <number>0</number>
224 </property>
225 <property name="leftMargin">
226 <number>0</number>
227 </property>
228 <property name="topMargin">
229 <number>0</number>
230 </property>
231 <property name="rightMargin">
232 <number>0</number>
233 </property>
234 <property name="bottomMargin">
235 <number>0</number>
236 </property>
237 <item>
238 <spacer name="horizontalSpacer_18">
239 <property name="orientation">
240 <enum>Qt::Horizontal</enum>
241 </property>
242 <property name="sizeHint" stdset="0">
243 <size>
244 <width>127</width>
245 <height>20</height>
246 </size>
247 </property>
248 </spacer>
249 </item>
250 <item>
251 <widget class="QLabel" name="label_header">
252 <property name="font">
253 <font>
254 <pointsize>23</pointsize>
255 </font>
256 </property>
257 <property name="text">
258 <string/>
259 </property>
260 </widget>
261 </item>
262 <item>
263 <spacer name="horizontalSpacer_19">
264 <property name="orientation">
265 <enum>Qt::Horizontal</enum>
266 </property>
267 <property name="sizeHint" stdset="0">
268 <size>
269 <width>127</width>
270 <height>20</height>
271 </size>
272 </property>
273 </spacer>
274 </item>
275 </layout>
276 </widget>
277 </item>
278 <item row="2" column="0" colspan="3">
279 <widget class="QWidget" name="subOSK" native="true">
280 <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="130,1020,130">
281 <property name="spacing">
282 <number>0</number>
283 </property>
284 <property name="leftMargin">
285 <number>0</number>
286 </property>
287 <property name="topMargin">
288 <number>0</number>
289 </property>
290 <property name="rightMargin">
291 <number>0</number>
292 </property>
293 <property name="bottomMargin">
294 <number>0</number>
295 </property>
296 <item>
297 <spacer name="horizontalSpacer_16">
298 <property name="orientation">
299 <enum>Qt::Horizontal</enum>
300 </property>
301 <property name="sizeHint" stdset="0">
302 <size>
303 <width>127</width>
304 <height>20</height>
305 </size>
306 </property>
307 </spacer>
308 </item>
309 <item>
310 <widget class="QLabel" name="label_sub">
311 <property name="font">
312 <font>
313 <pointsize>17</pointsize>
314 </font>
315 </property>
316 <property name="text">
317 <string/>
318 </property>
319 </widget>
320 </item>
321 <item>
322 <spacer name="horizontalSpacer_17">
323 <property name="orientation">
324 <enum>Qt::Horizontal</enum>
325 </property>
326 <property name="sizeHint" stdset="0">
327 <size>
328 <width>127</width>
329 <height>20</height>
330 </size>
331 </property>
332 </spacer>
333 </item>
334 </layout>
335 </widget>
336 </item>
337 </layout>
338 </item>
339 </layout>
340 </widget>
341 <widget class="QWidget" name="boxOSK">
342 <layout class="QVBoxLayout" name="boxOSKVerticalLayout">
343 <property name="spacing">
344 <number>0</number>
345 </property>
346 <property name="leftMargin">
347 <number>0</number>
348 </property>
349 <property name="topMargin">
350 <number>0</number>
351 </property>
352 <property name="rightMargin">
353 <number>0</number>
354 </property>
355 <property name="bottomMargin">
356 <number>0</number>
357 </property>
358 <item>
359 <layout class="QGridLayout" name="gridBoxOSK" rowstretch="61,178,81" columnstretch="120,1040,120">
360 <property name="leftMargin">
361 <number>0</number>
362 </property>
363 <property name="topMargin">
364 <number>0</number>
365 </property>
366 <property name="rightMargin">
367 <number>0</number>
368 </property>
369 <property name="bottomMargin">
370 <number>0</number>
371 </property>
372 <property name="spacing">
373 <number>0</number>
374 </property>
375 <item row="0" column="1">
376 <spacer name="verticalSpacer_5">
377 <property name="orientation">
378 <enum>Qt::Vertical</enum>
379 </property>
380 <property name="sizeHint" stdset="0">
381 <size>
382 <width>20</width>
383 <height>40</height>
384 </size>
385 </property>
386 </spacer>
387 </item>
388 <item row="1" column="0">
389 <spacer name="horizontalSpacer_20">
390 <property name="orientation">
391 <enum>Qt::Horizontal</enum>
392 </property>
393 <property name="sizeHint" stdset="0">
394 <size>
395 <width>40</width>
396 <height>20</height>
397 </size>
398 </property>
399 </spacer>
400 </item>
401 <item row="1" column="2">
402 <spacer name="horizontalSpacer_21">
403 <property name="orientation">
404 <enum>Qt::Horizontal</enum>
405 </property>
406 <property name="sizeHint" stdset="0">
407 <size>
408 <width>40</width>
409 <height>20</height>
410 </size>
411 </property>
412 </spacer>
413 </item>
414 <item row="2" column="1" alignment="Qt::AlignRight|Qt::AlignTop">
415 <widget class="QWidget" name="charactersBoxOSK" native="true">
416 <layout class="QVBoxLayout" name="verticalLayout_4">
417 <property name="spacing">
418 <number>0</number>
419 </property>
420 <property name="leftMargin">
421 <number>0</number>
422 </property>
423 <property name="topMargin">
424 <number>0</number>
425 </property>
426 <property name="rightMargin">
427 <number>0</number>
428 </property>
429 <property name="bottomMargin">
430 <number>0</number>
431 </property>
432 <item>
433 <widget class="QLabel" name="label_characters_box">
434 <property name="enabled">
435 <bool>true</bool>
436 </property>
437 <property name="font">
438 <font>
439 <pointsize>17</pointsize>
440 </font>
441 </property>
442 <property name="text">
443 <string notr="true">0/500</string>
444 </property>
445 </widget>
446 </item>
447 </layout>
448 </widget>
449 </item>
450 <item row="1" column="1">
451 <widget class="QWidget" name="inputBoxOSK" native="true">
452 <layout class="QVBoxLayout" name="verticalLayout_6">
453 <property name="spacing">
454 <number>0</number>
455 </property>
456 <property name="leftMargin">
457 <number>14</number>
458 </property>
459 <property name="topMargin">
460 <number>9</number>
461 </property>
462 <property name="rightMargin">
463 <number>14</number>
464 </property>
465 <property name="bottomMargin">
466 <number>9</number>
467 </property>
468 <item>
469 <widget class="QTextEdit" name="text_edit_osk">
470 <property name="font">
471 <font>
472 <pointsize>26</pointsize>
473 </font>
474 </property>
475 <property name="focusPolicy">
476 <enum>Qt::StrongFocus</enum>
477 </property>
478 <property name="html">
479 <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
480&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
481p, li { white-space: pre-wrap; }
482&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;&quot;&gt;
483&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
484 </property>
485 </widget>
486 </item>
487 </layout>
488 </widget>
489 </item>
490 </layout>
491 </item>
492 </layout>
493 </widget>
494 </widget>
495 </item>
496 <item>
497 <widget class="QStackedWidget" name="bottomOSK">
498 <property name="currentIndex">
499 <number>0</number>
500 </property>
501 <widget class="QWidget" name="normalOSK">
502 <layout class="QVBoxLayout" name="normalPageVerticalLayout">
503 <property name="leftMargin">
504 <number>0</number>
505 </property>
506 <property name="topMargin">
507 <number>0</number>
508 </property>
509 <property name="rightMargin">
510 <number>0</number>
511 </property>
512 <property name="bottomMargin">
513 <number>0</number>
514 </property>
515 <item>
516 <layout class="QGridLayout" name="kbOSKnormal" rowstretch="15,63,63,63,63,63,70" columnstretch="54,96,96,96,96,96,96,96,96,96,96,96,116,54">
517 <property name="spacing">
518 <number>0</number>
519 </property>
520 <item row="6" column="1" colspan="12">
521 <widget class="QWidget" name="legendOSK" native="true">
522 <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="70,525,25,12,22,41,25,12,22,41,25,12,47,37,29,12,69,37,29,12,56,8">
523 <property name="spacing">
524 <number>0</number>
525 </property>
526 <property name="leftMargin">
527 <number>2</number>
528 </property>
529 <property name="topMargin">
530 <number>0</number>
531 </property>
532 <property name="rightMargin">
533 <number>0</number>
534 </property>
535 <property name="bottomMargin">
536 <number>0</number>
537 </property>
538 <item>
539 <widget class="QWidget" name="icon_controller" native="true">
540 <property name="styleSheet">
541 <string notr="true"/>
542 </property>
543 </widget>
544 </item>
545 <item>
546 <spacer name="horizontalSpacer_5">
547 <property name="orientation">
548 <enum>Qt::Horizontal</enum>
549 </property>
550 <property name="sizeHint" stdset="0">
551 <size>
552 <width>0</width>
553 <height>20</height>
554 </size>
555 </property>
556 </spacer>
557 </item>
558 <item>
559 <widget class="QWidget" name="button_L" native="true"/>
560 </item>
561 <item>
562 <spacer name="horizontalSpacer_14">
563 <property name="orientation">
564 <enum>Qt::Horizontal</enum>
565 </property>
566 <property name="sizeHint" stdset="0">
567 <size>
568 <width>0</width>
569 <height>20</height>
570 </size>
571 </property>
572 </spacer>
573 </item>
574 <item>
575 <widget class="QWidget" name="arrow_left" native="true"/>
576 </item>
577 <item>
578 <spacer name="horizontalSpacer_13">
579 <property name="orientation">
580 <enum>Qt::Horizontal</enum>
581 </property>
582 <property name="sizeHint" stdset="0">
583 <size>
584 <width>0</width>
585 <height>20</height>
586 </size>
587 </property>
588 </spacer>
589 </item>
590 <item>
591 <widget class="QWidget" name="button_R" native="true"/>
592 </item>
593 <item>
594 <spacer name="horizontalSpacer_12">
595 <property name="orientation">
596 <enum>Qt::Horizontal</enum>
597 </property>
598 <property name="sizeHint" stdset="0">
599 <size>
600 <width>0</width>
601 <height>20</height>
602 </size>
603 </property>
604 </spacer>
605 </item>
606 <item>
607 <widget class="QWidget" name="arrow_right" native="true"/>
608 </item>
609 <item>
610 <spacer name="horizontalSpacer_11">
611 <property name="orientation">
612 <enum>Qt::Horizontal</enum>
613 </property>
614 <property name="sizeHint" stdset="0">
615 <size>
616 <width>0</width>
617 <height>20</height>
618 </size>
619 </property>
620 </spacer>
621 </item>
622 <item>
623 <widget class="QWidget" name="button_press_stick" native="true"/>
624 </item>
625 <item>
626 <spacer name="horizontalSpacer_10">
627 <property name="orientation">
628 <enum>Qt::Horizontal</enum>
629 </property>
630 <property name="sizeHint" stdset="0">
631 <size>
632 <width>0</width>
633 <height>20</height>
634 </size>
635 </property>
636 </spacer>
637 </item>
638 <item>
639 <widget class="QLabel" name="label_shift">
640 <property name="font">
641 <font>
642 <pointsize>18</pointsize>
643 </font>
644 </property>
645 <property name="text">
646 <string notr="true">Shift</string>
647 </property>
648 </widget>
649 </item>
650 <item>
651 <spacer name="horizontalSpacer_15">
652 <property name="orientation">
653 <enum>Qt::Horizontal</enum>
654 </property>
655 <property name="sizeHint" stdset="0">
656 <size>
657 <width>0</width>
658 <height>20</height>
659 </size>
660 </property>
661 </spacer>
662 </item>
663 <item>
664 <widget class="QWidget" name="button_X" native="true"/>
665 </item>
666 <item>
667 <spacer name="horizontalSpacer_9">
668 <property name="orientation">
669 <enum>Qt::Horizontal</enum>
670 </property>
671 <property name="sizeHint" stdset="0">
672 <size>
673 <width>0</width>
674 <height>20</height>
675 </size>
676 </property>
677 </spacer>
678 </item>
679 <item>
680 <widget class="QLabel" name="label_cancel">
681 <property name="font">
682 <font>
683 <pointsize>18</pointsize>
684 </font>
685 </property>
686 <property name="text">
687 <string notr="true">Cancel</string>
688 </property>
689 </widget>
690 </item>
691 <item>
692 <spacer name="horizontalSpacer_8">
693 <property name="orientation">
694 <enum>Qt::Horizontal</enum>
695 </property>
696 <property name="sizeHint" stdset="0">
697 <size>
698 <width>0</width>
699 <height>20</height>
700 </size>
701 </property>
702 </spacer>
703 </item>
704 <item>
705 <widget class="QWidget" name="button_A" native="true"/>
706 </item>
707 <item>
708 <spacer name="horizontalSpacer_7">
709 <property name="orientation">
710 <enum>Qt::Horizontal</enum>
711 </property>
712 <property name="sizeHint" stdset="0">
713 <size>
714 <width>0</width>
715 <height>20</height>
716 </size>
717 </property>
718 </spacer>
719 </item>
720 <item>
721 <widget class="QLabel" name="label_enter">
722 <property name="font">
723 <font>
724 <pointsize>18</pointsize>
725 </font>
726 </property>
727 <property name="text">
728 <string notr="true">Enter</string>
729 </property>
730 </widget>
731 </item>
732 <item>
733 <spacer name="horizontalSpacer_6">
734 <property name="orientation">
735 <enum>Qt::Horizontal</enum>
736 </property>
737 <property name="sizeHint" stdset="0">
738 <size>
739 <width>0</width>
740 <height>20</height>
741 </size>
742 </property>
743 </spacer>
744 </item>
745 </layout>
746 </widget>
747 </item>
748 <item row="1" column="11">
749 <widget class="QPushButton" name="button_minus">
750 <property name="sizePolicy">
751 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
752 <horstretch>1</horstretch>
753 <verstretch>1</verstretch>
754 </sizepolicy>
755 </property>
756 <property name="font">
757 <font>
758 <pointsize>28</pointsize>
759 </font>
760 </property>
761 <property name="text">
762 <string notr="true">-</string>
763 </property>
764 </widget>
765 </item>
766 <item row="3" column="11">
767 <widget class="QPushButton" name="button_apostrophe">
768 <property name="sizePolicy">
769 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
770 <horstretch>1</horstretch>
771 <verstretch>1</verstretch>
772 </sizepolicy>
773 </property>
774 <property name="font">
775 <font>
776 <pointsize>28</pointsize>
777 </font>
778 </property>
779 <property name="text">
780 <string notr="true">'</string>
781 </property>
782 </widget>
783 </item>
784 <item row="2" column="11">
785 <widget class="QPushButton" name="button_slash">
786 <property name="sizePolicy">
787 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
788 <horstretch>1</horstretch>
789 <verstretch>1</verstretch>
790 </sizepolicy>
791 </property>
792 <property name="font">
793 <font>
794 <pointsize>28</pointsize>
795 </font>
796 </property>
797 <property name="text">
798 <string notr="true">/</string>
799 </property>
800 </widget>
801 </item>
802 <item row="4" column="11">
803 <widget class="QPushButton" name="button_exclamation">
804 <property name="sizePolicy">
805 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
806 <horstretch>1</horstretch>
807 <verstretch>1</verstretch>
808 </sizepolicy>
809 </property>
810 <property name="font">
811 <font>
812 <pointsize>28</pointsize>
813 </font>
814 </property>
815 <property name="text">
816 <string notr="true">!</string>
817 </property>
818 </widget>
819 </item>
820 <item row="1" column="7">
821 <widget class="QPushButton" name="button_7">
822 <property name="sizePolicy">
823 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
824 <horstretch>1</horstretch>
825 <verstretch>1</verstretch>
826 </sizepolicy>
827 </property>
828 <property name="font">
829 <font>
830 <pointsize>28</pointsize>
831 </font>
832 </property>
833 <property name="text">
834 <string notr="true">7</string>
835 </property>
836 </widget>
837 </item>
838 <item row="1" column="8">
839 <widget class="QPushButton" name="button_8">
840 <property name="sizePolicy">
841 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
842 <horstretch>1</horstretch>
843 <verstretch>1</verstretch>
844 </sizepolicy>
845 </property>
846 <property name="font">
847 <font>
848 <pointsize>28</pointsize>
849 </font>
850 </property>
851 <property name="text">
852 <string notr="true">8</string>
853 </property>
854 </widget>
855 </item>
856 <item row="1" column="10">
857 <widget class="QPushButton" name="button_0">
858 <property name="sizePolicy">
859 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
860 <horstretch>1</horstretch>
861 <verstretch>1</verstretch>
862 </sizepolicy>
863 </property>
864 <property name="font">
865 <font>
866 <pointsize>28</pointsize>
867 </font>
868 </property>
869 <property name="text">
870 <string notr="true">0</string>
871 </property>
872 </widget>
873 </item>
874 <item row="1" column="9">
875 <widget class="QPushButton" name="button_9">
876 <property name="sizePolicy">
877 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
878 <horstretch>1</horstretch>
879 <verstretch>1</verstretch>
880 </sizepolicy>
881 </property>
882 <property name="font">
883 <font>
884 <pointsize>28</pointsize>
885 </font>
886 </property>
887 <property name="text">
888 <string notr="true">9</string>
889 </property>
890 </widget>
891 </item>
892 <item row="2" column="2">
893 <widget class="QPushButton" name="button_w">
894 <property name="sizePolicy">
895 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
896 <horstretch>1</horstretch>
897 <verstretch>1</verstretch>
898 </sizepolicy>
899 </property>
900 <property name="font">
901 <font>
902 <pointsize>28</pointsize>
903 </font>
904 </property>
905 <property name="text">
906 <string notr="true">w</string>
907 </property>
908 </widget>
909 </item>
910 <item row="2" column="4">
911 <widget class="QPushButton" name="button_r">
912 <property name="sizePolicy">
913 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
914 <horstretch>1</horstretch>
915 <verstretch>1</verstretch>
916 </sizepolicy>
917 </property>
918 <property name="font">
919 <font>
920 <pointsize>28</pointsize>
921 </font>
922 </property>
923 <property name="text">
924 <string notr="true">r</string>
925 </property>
926 </widget>
927 </item>
928 <item row="2" column="3">
929 <widget class="QPushButton" name="button_e">
930 <property name="sizePolicy">
931 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
932 <horstretch>1</horstretch>
933 <verstretch>1</verstretch>
934 </sizepolicy>
935 </property>
936 <property name="font">
937 <font>
938 <pointsize>28</pointsize>
939 </font>
940 </property>
941 <property name="text">
942 <string notr="true">e</string>
943 </property>
944 </widget>
945 </item>
946 <item row="2" column="1">
947 <widget class="QPushButton" name="button_q">
948 <property name="sizePolicy">
949 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
950 <horstretch>1</horstretch>
951 <verstretch>1</verstretch>
952 </sizepolicy>
953 </property>
954 <property name="font">
955 <font>
956 <pointsize>28</pointsize>
957 </font>
958 </property>
959 <property name="text">
960 <string notr="true">q</string>
961 </property>
962 </widget>
963 </item>
964 <item row="2" column="7">
965 <widget class="QPushButton" name="button_u">
966 <property name="sizePolicy">
967 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
968 <horstretch>1</horstretch>
969 <verstretch>1</verstretch>
970 </sizepolicy>
971 </property>
972 <property name="font">
973 <font>
974 <pointsize>28</pointsize>
975 </font>
976 </property>
977 <property name="text">
978 <string notr="true">u</string>
979 </property>
980 </widget>
981 </item>
982 <item row="2" column="6">
983 <widget class="QPushButton" name="button_y">
984 <property name="sizePolicy">
985 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
986 <horstretch>1</horstretch>
987 <verstretch>1</verstretch>
988 </sizepolicy>
989 </property>
990 <property name="font">
991 <font>
992 <pointsize>28</pointsize>
993 </font>
994 </property>
995 <property name="text">
996 <string notr="true">y</string>
997 </property>
998 </widget>
999 </item>
1000 <item row="2" column="5">
1001 <widget class="QPushButton" name="button_t">
1002 <property name="sizePolicy">
1003 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1004 <horstretch>1</horstretch>
1005 <verstretch>1</verstretch>
1006 </sizepolicy>
1007 </property>
1008 <property name="font">
1009 <font>
1010 <pointsize>28</pointsize>
1011 </font>
1012 </property>
1013 <property name="text">
1014 <string notr="true">t</string>
1015 </property>
1016 </widget>
1017 </item>
1018 <item row="2" column="9">
1019 <widget class="QPushButton" name="button_o">
1020 <property name="sizePolicy">
1021 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1022 <horstretch>1</horstretch>
1023 <verstretch>1</verstretch>
1024 </sizepolicy>
1025 </property>
1026 <property name="font">
1027 <font>
1028 <pointsize>28</pointsize>
1029 </font>
1030 </property>
1031 <property name="text">
1032 <string notr="true">o</string>
1033 </property>
1034 </widget>
1035 </item>
1036 <item row="2" column="10">
1037 <widget class="QPushButton" name="button_p">
1038 <property name="sizePolicy">
1039 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1040 <horstretch>1</horstretch>
1041 <verstretch>1</verstretch>
1042 </sizepolicy>
1043 </property>
1044 <property name="font">
1045 <font>
1046 <pointsize>28</pointsize>
1047 </font>
1048 </property>
1049 <property name="text">
1050 <string notr="true">p</string>
1051 </property>
1052 </widget>
1053 </item>
1054 <item row="2" column="8">
1055 <widget class="QPushButton" name="button_i">
1056 <property name="sizePolicy">
1057 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1058 <horstretch>1</horstretch>
1059 <verstretch>1</verstretch>
1060 </sizepolicy>
1061 </property>
1062 <property name="font">
1063 <font>
1064 <pointsize>28</pointsize>
1065 </font>
1066 </property>
1067 <property name="text">
1068 <string notr="true">i</string>
1069 </property>
1070 </widget>
1071 </item>
1072 <item row="3" column="1">
1073 <widget class="QPushButton" name="button_a">
1074 <property name="sizePolicy">
1075 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1076 <horstretch>1</horstretch>
1077 <verstretch>1</verstretch>
1078 </sizepolicy>
1079 </property>
1080 <property name="font">
1081 <font>
1082 <pointsize>28</pointsize>
1083 </font>
1084 </property>
1085 <property name="text">
1086 <string notr="true">a</string>
1087 </property>
1088 </widget>
1089 </item>
1090 <item row="3" column="2">
1091 <widget class="QPushButton" name="button_s">
1092 <property name="sizePolicy">
1093 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1094 <horstretch>1</horstretch>
1095 <verstretch>1</verstretch>
1096 </sizepolicy>
1097 </property>
1098 <property name="font">
1099 <font>
1100 <pointsize>28</pointsize>
1101 </font>
1102 </property>
1103 <property name="text">
1104 <string notr="true">s</string>
1105 </property>
1106 </widget>
1107 </item>
1108 <item row="3" column="3">
1109 <widget class="QPushButton" name="button_d">
1110 <property name="sizePolicy">
1111 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1112 <horstretch>1</horstretch>
1113 <verstretch>1</verstretch>
1114 </sizepolicy>
1115 </property>
1116 <property name="font">
1117 <font>
1118 <pointsize>28</pointsize>
1119 </font>
1120 </property>
1121 <property name="text">
1122 <string notr="true">d</string>
1123 </property>
1124 </widget>
1125 </item>
1126 <item row="3" column="4">
1127 <widget class="QPushButton" name="button_f">
1128 <property name="sizePolicy">
1129 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1130 <horstretch>1</horstretch>
1131 <verstretch>1</verstretch>
1132 </sizepolicy>
1133 </property>
1134 <property name="font">
1135 <font>
1136 <pointsize>28</pointsize>
1137 </font>
1138 </property>
1139 <property name="text">
1140 <string notr="true">f</string>
1141 </property>
1142 </widget>
1143 </item>
1144 <item row="3" column="6">
1145 <widget class="QPushButton" name="button_h">
1146 <property name="sizePolicy">
1147 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1148 <horstretch>1</horstretch>
1149 <verstretch>1</verstretch>
1150 </sizepolicy>
1151 </property>
1152 <property name="font">
1153 <font>
1154 <pointsize>28</pointsize>
1155 </font>
1156 </property>
1157 <property name="text">
1158 <string notr="true">h</string>
1159 </property>
1160 </widget>
1161 </item>
1162 <item row="3" column="7">
1163 <widget class="QPushButton" name="button_j">
1164 <property name="sizePolicy">
1165 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1166 <horstretch>1</horstretch>
1167 <verstretch>1</verstretch>
1168 </sizepolicy>
1169 </property>
1170 <property name="font">
1171 <font>
1172 <pointsize>28</pointsize>
1173 </font>
1174 </property>
1175 <property name="text">
1176 <string notr="true">j</string>
1177 </property>
1178 </widget>
1179 </item>
1180 <item row="3" column="5">
1181 <widget class="QPushButton" name="button_g">
1182 <property name="sizePolicy">
1183 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1184 <horstretch>1</horstretch>
1185 <verstretch>1</verstretch>
1186 </sizepolicy>
1187 </property>
1188 <property name="font">
1189 <font>
1190 <pointsize>28</pointsize>
1191 </font>
1192 </property>
1193 <property name="text">
1194 <string notr="true">g</string>
1195 </property>
1196 </widget>
1197 </item>
1198 <item row="3" column="8">
1199 <widget class="QPushButton" name="button_k">
1200 <property name="sizePolicy">
1201 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1202 <horstretch>1</horstretch>
1203 <verstretch>1</verstretch>
1204 </sizepolicy>
1205 </property>
1206 <property name="font">
1207 <font>
1208 <pointsize>28</pointsize>
1209 </font>
1210 </property>
1211 <property name="text">
1212 <string notr="true">k</string>
1213 </property>
1214 </widget>
1215 </item>
1216 <item row="3" column="9">
1217 <widget class="QPushButton" name="button_l">
1218 <property name="sizePolicy">
1219 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1220 <horstretch>1</horstretch>
1221 <verstretch>1</verstretch>
1222 </sizepolicy>
1223 </property>
1224 <property name="font">
1225 <font>
1226 <pointsize>28</pointsize>
1227 </font>
1228 </property>
1229 <property name="text">
1230 <string notr="true">l</string>
1231 </property>
1232 </widget>
1233 </item>
1234 <item row="3" column="10">
1235 <widget class="QPushButton" name="button_colon">
1236 <property name="sizePolicy">
1237 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1238 <horstretch>1</horstretch>
1239 <verstretch>1</verstretch>
1240 </sizepolicy>
1241 </property>
1242 <property name="font">
1243 <font>
1244 <pointsize>28</pointsize>
1245 </font>
1246 </property>
1247 <property name="text">
1248 <string notr="true">:</string>
1249 </property>
1250 </widget>
1251 </item>
1252 <item row="2" column="12" rowspan="2">
1253 <widget class="QPushButton" name="button_return">
1254 <property name="sizePolicy">
1255 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1256 <horstretch>1</horstretch>
1257 <verstretch>1</verstretch>
1258 </sizepolicy>
1259 </property>
1260 <property name="font">
1261 <font>
1262 <pointsize>18</pointsize>
1263 </font>
1264 </property>
1265 <property name="text">
1266 <string notr="true">Return</string>
1267 </property>
1268 </widget>
1269 </item>
1270 <item row="4" column="12" rowspan="2">
1271 <widget class="QPushButton" name="button_ok">
1272 <property name="sizePolicy">
1273 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1274 <horstretch>1</horstretch>
1275 <verstretch>1</verstretch>
1276 </sizepolicy>
1277 </property>
1278 <property name="font">
1279 <font>
1280 <pointsize>18</pointsize>
1281 </font>
1282 </property>
1283 <property name="text">
1284 <string notr="true">OK</string>
1285 </property>
1286 </widget>
1287 </item>
1288 <item row="4" column="1">
1289 <widget class="QPushButton" name="button_z">
1290 <property name="sizePolicy">
1291 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1292 <horstretch>1</horstretch>
1293 <verstretch>1</verstretch>
1294 </sizepolicy>
1295 </property>
1296 <property name="font">
1297 <font>
1298 <pointsize>28</pointsize>
1299 </font>
1300 </property>
1301 <property name="text">
1302 <string notr="true">z</string>
1303 </property>
1304 </widget>
1305 </item>
1306 <item row="4" column="3">
1307 <widget class="QPushButton" name="button_c">
1308 <property name="sizePolicy">
1309 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1310 <horstretch>1</horstretch>
1311 <verstretch>1</verstretch>
1312 </sizepolicy>
1313 </property>
1314 <property name="font">
1315 <font>
1316 <pointsize>28</pointsize>
1317 </font>
1318 </property>
1319 <property name="text">
1320 <string notr="true">c</string>
1321 </property>
1322 </widget>
1323 </item>
1324 <item row="4" column="2">
1325 <widget class="QPushButton" name="button_x">
1326 <property name="sizePolicy">
1327 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1328 <horstretch>1</horstretch>
1329 <verstretch>1</verstretch>
1330 </sizepolicy>
1331 </property>
1332 <property name="font">
1333 <font>
1334 <pointsize>28</pointsize>
1335 </font>
1336 </property>
1337 <property name="text">
1338 <string notr="true">x</string>
1339 </property>
1340 </widget>
1341 </item>
1342 <item row="4" column="4">
1343 <widget class="QPushButton" name="button_v">
1344 <property name="sizePolicy">
1345 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1346 <horstretch>1</horstretch>
1347 <verstretch>1</verstretch>
1348 </sizepolicy>
1349 </property>
1350 <property name="font">
1351 <font>
1352 <pointsize>28</pointsize>
1353 </font>
1354 </property>
1355 <property name="text">
1356 <string notr="true">v</string>
1357 </property>
1358 </widget>
1359 </item>
1360 <item row="4" column="7">
1361 <widget class="QPushButton" name="button_m">
1362 <property name="sizePolicy">
1363 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1364 <horstretch>1</horstretch>
1365 <verstretch>1</verstretch>
1366 </sizepolicy>
1367 </property>
1368 <property name="font">
1369 <font>
1370 <pointsize>28</pointsize>
1371 </font>
1372 </property>
1373 <property name="text">
1374 <string notr="true">m</string>
1375 </property>
1376 </widget>
1377 </item>
1378 <item row="4" column="8">
1379 <widget class="QPushButton" name="button_comma">
1380 <property name="sizePolicy">
1381 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1382 <horstretch>1</horstretch>
1383 <verstretch>1</verstretch>
1384 </sizepolicy>
1385 </property>
1386 <property name="font">
1387 <font>
1388 <pointsize>28</pointsize>
1389 </font>
1390 </property>
1391 <property name="text">
1392 <string notr="true">,</string>
1393 </property>
1394 </widget>
1395 </item>
1396 <item row="4" column="6">
1397 <widget class="QPushButton" name="button_n">
1398 <property name="sizePolicy">
1399 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1400 <horstretch>1</horstretch>
1401 <verstretch>1</verstretch>
1402 </sizepolicy>
1403 </property>
1404 <property name="font">
1405 <font>
1406 <pointsize>28</pointsize>
1407 </font>
1408 </property>
1409 <property name="text">
1410 <string notr="true">n</string>
1411 </property>
1412 </widget>
1413 </item>
1414 <item row="4" column="5">
1415 <widget class="QPushButton" name="button_b">
1416 <property name="sizePolicy">
1417 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1418 <horstretch>1</horstretch>
1419 <verstretch>1</verstretch>
1420 </sizepolicy>
1421 </property>
1422 <property name="font">
1423 <font>
1424 <pointsize>28</pointsize>
1425 </font>
1426 </property>
1427 <property name="text">
1428 <string notr="true">b</string>
1429 </property>
1430 </widget>
1431 </item>
1432 <item row="5" column="1" colspan="2">
1433 <widget class="QPushButton" name="button_shift">
1434 <property name="sizePolicy">
1435 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1436 <horstretch>1</horstretch>
1437 <verstretch>1</verstretch>
1438 </sizepolicy>
1439 </property>
1440 <property name="font">
1441 <font>
1442 <pointsize>18</pointsize>
1443 </font>
1444 </property>
1445 <property name="text">
1446 <string notr="true"/>
1447 </property>
1448 <property name="checkable">
1449 <bool>true</bool>
1450 </property>
1451 <property name="checked">
1452 <bool>false</bool>
1453 </property>
1454 </widget>
1455 </item>
1456 <item row="4" column="10">
1457 <widget class="QPushButton" name="button_question">
1458 <property name="sizePolicy">
1459 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1460 <horstretch>1</horstretch>
1461 <verstretch>1</verstretch>
1462 </sizepolicy>
1463 </property>
1464 <property name="font">
1465 <font>
1466 <pointsize>28</pointsize>
1467 </font>
1468 </property>
1469 <property name="text">
1470 <string notr="true">?</string>
1471 </property>
1472 </widget>
1473 </item>
1474 <item row="4" column="9">
1475 <widget class="QPushButton" name="button_dot">
1476 <property name="sizePolicy">
1477 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1478 <horstretch>1</horstretch>
1479 <verstretch>1</verstretch>
1480 </sizepolicy>
1481 </property>
1482 <property name="font">
1483 <font>
1484 <pointsize>28</pointsize>
1485 </font>
1486 </property>
1487 <property name="text">
1488 <string notr="true">.</string>
1489 </property>
1490 </widget>
1491 </item>
1492 <item row="1" column="1">
1493 <widget class="QPushButton" name="button_1">
1494 <property name="sizePolicy">
1495 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1496 <horstretch>1</horstretch>
1497 <verstretch>1</verstretch>
1498 </sizepolicy>
1499 </property>
1500 <property name="font">
1501 <font>
1502 <pointsize>28</pointsize>
1503 </font>
1504 </property>
1505 <property name="text">
1506 <string notr="true">1</string>
1507 </property>
1508 </widget>
1509 </item>
1510 <item row="1" column="3">
1511 <widget class="QPushButton" name="button_3">
1512 <property name="sizePolicy">
1513 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1514 <horstretch>1</horstretch>
1515 <verstretch>1</verstretch>
1516 </sizepolicy>
1517 </property>
1518 <property name="font">
1519 <font>
1520 <pointsize>28</pointsize>
1521 </font>
1522 </property>
1523 <property name="text">
1524 <string notr="true">3</string>
1525 </property>
1526 </widget>
1527 </item>
1528 <item row="1" column="4">
1529 <widget class="QPushButton" name="button_4">
1530 <property name="sizePolicy">
1531 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1532 <horstretch>1</horstretch>
1533 <verstretch>1</verstretch>
1534 </sizepolicy>
1535 </property>
1536 <property name="font">
1537 <font>
1538 <pointsize>28</pointsize>
1539 </font>
1540 </property>
1541 <property name="text">
1542 <string notr="true">4</string>
1543 </property>
1544 </widget>
1545 </item>
1546 <item row="1" column="2">
1547 <widget class="QPushButton" name="button_2">
1548 <property name="sizePolicy">
1549 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1550 <horstretch>1</horstretch>
1551 <verstretch>1</verstretch>
1552 </sizepolicy>
1553 </property>
1554 <property name="font">
1555 <font>
1556 <pointsize>28</pointsize>
1557 </font>
1558 </property>
1559 <property name="text">
1560 <string notr="true">2</string>
1561 </property>
1562 </widget>
1563 </item>
1564 <item row="1" column="6">
1565 <widget class="QPushButton" name="button_6">
1566 <property name="sizePolicy">
1567 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1568 <horstretch>1</horstretch>
1569 <verstretch>1</verstretch>
1570 </sizepolicy>
1571 </property>
1572 <property name="font">
1573 <font>
1574 <pointsize>28</pointsize>
1575 </font>
1576 </property>
1577 <property name="text">
1578 <string notr="true">6</string>
1579 </property>
1580 </widget>
1581 </item>
1582 <item row="1" column="5">
1583 <widget class="QPushButton" name="button_5">
1584 <property name="sizePolicy">
1585 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1586 <horstretch>1</horstretch>
1587 <verstretch>1</verstretch>
1588 </sizepolicy>
1589 </property>
1590 <property name="font">
1591 <font>
1592 <pointsize>28</pointsize>
1593 </font>
1594 </property>
1595 <property name="text">
1596 <string notr="true">5</string>
1597 </property>
1598 </widget>
1599 </item>
1600 <item row="5" column="3" colspan="9">
1601 <widget class="QPushButton" name="button_space">
1602 <property name="sizePolicy">
1603 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1604 <horstretch>1</horstretch>
1605 <verstretch>1</verstretch>
1606 </sizepolicy>
1607 </property>
1608 <property name="font">
1609 <font>
1610 <pointsize>18</pointsize>
1611 </font>
1612 </property>
1613 <property name="text">
1614 <string notr="true">Space</string>
1615 </property>
1616 </widget>
1617 </item>
1618 <item row="1" column="12">
1619 <widget class="QPushButton" name="button_backspace">
1620 <property name="sizePolicy">
1621 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1622 <horstretch>1</horstretch>
1623 <verstretch>1</verstretch>
1624 </sizepolicy>
1625 </property>
1626 <property name="font">
1627 <font>
1628 <pointsize>18</pointsize>
1629 </font>
1630 </property>
1631 <property name="text">
1632 <string notr="true"/>
1633 </property>
1634 </widget>
1635 </item>
1636 <item row="1" column="0">
1637 <spacer name="horizontalSpacer">
1638 <property name="orientation">
1639 <enum>Qt::Horizontal</enum>
1640 </property>
1641 <property name="sizeHint" stdset="0">
1642 <size>
1643 <width>40</width>
1644 <height>20</height>
1645 </size>
1646 </property>
1647 </spacer>
1648 </item>
1649 <item row="0" column="1">
1650 <spacer name="verticalSpacer">
1651 <property name="orientation">
1652 <enum>Qt::Vertical</enum>
1653 </property>
1654 <property name="sizeHint" stdset="0">
1655 <size>
1656 <width>20</width>
1657 <height>0</height>
1658 </size>
1659 </property>
1660 </spacer>
1661 </item>
1662 <item row="1" column="13">
1663 <spacer name="horizontalSpacer_2">
1664 <property name="orientation">
1665 <enum>Qt::Horizontal</enum>
1666 </property>
1667 <property name="sizeHint" stdset="0">
1668 <size>
1669 <width>40</width>
1670 <height>20</height>
1671 </size>
1672 </property>
1673 </spacer>
1674 </item>
1675 </layout>
1676 </item>
1677 </layout>
1678 </widget>
1679 <widget class="QWidget" name="shiftOSK">
1680 <layout class="QVBoxLayout" name="shiftPageVerticalLayout">
1681 <property name="leftMargin">
1682 <number>0</number>
1683 </property>
1684 <property name="topMargin">
1685 <number>0</number>
1686 </property>
1687 <property name="rightMargin">
1688 <number>0</number>
1689 </property>
1690 <property name="bottomMargin">
1691 <number>0</number>
1692 </property>
1693 <item>
1694 <layout class="QGridLayout" name="kbOSKshift" rowstretch="15,63,63,63,63,63,70" columnstretch="54,96,96,96,96,96,96,96,96,96,96,96,116,54">
1695 <property name="spacing">
1696 <number>0</number>
1697 </property>
1698 <item row="6" column="1" colspan="12">
1699 <widget class="QWidget" name="legendOSKshift" native="true">
1700 <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="70,464,25,12,22,41,25,12,22,41,25,12,95,37,29,12,69,37,29,12,56,8">
1701 <property name="spacing">
1702 <number>0</number>
1703 </property>
1704 <property name="leftMargin">
1705 <number>2</number>
1706 </property>
1707 <property name="topMargin">
1708 <number>0</number>
1709 </property>
1710 <property name="rightMargin">
1711 <number>0</number>
1712 </property>
1713 <property name="bottomMargin">
1714 <number>0</number>
1715 </property>
1716 <item>
1717 <widget class="QWidget" name="icon_controller_shift" native="true">
1718 <property name="styleSheet">
1719 <string notr="true"/>
1720 </property>
1721 </widget>
1722 </item>
1723 <item>
1724 <spacer name="horizontalSpacer_22">
1725 <property name="orientation">
1726 <enum>Qt::Horizontal</enum>
1727 </property>
1728 <property name="sizeHint" stdset="0">
1729 <size>
1730 <width>0</width>
1731 <height>20</height>
1732 </size>
1733 </property>
1734 </spacer>
1735 </item>
1736 <item>
1737 <widget class="QWidget" name="button_L_shift" native="true"/>
1738 </item>
1739 <item>
1740 <spacer name="horizontalSpacer_23">
1741 <property name="orientation">
1742 <enum>Qt::Horizontal</enum>
1743 </property>
1744 <property name="sizeHint" stdset="0">
1745 <size>
1746 <width>0</width>
1747 <height>20</height>
1748 </size>
1749 </property>
1750 </spacer>
1751 </item>
1752 <item>
1753 <widget class="QWidget" name="arrow_left_shift" native="true"/>
1754 </item>
1755 <item>
1756 <spacer name="horizontalSpacer_24">
1757 <property name="orientation">
1758 <enum>Qt::Horizontal</enum>
1759 </property>
1760 <property name="sizeHint" stdset="0">
1761 <size>
1762 <width>0</width>
1763 <height>20</height>
1764 </size>
1765 </property>
1766 </spacer>
1767 </item>
1768 <item>
1769 <widget class="QWidget" name="button_R_shift" native="true"/>
1770 </item>
1771 <item>
1772 <spacer name="horizontalSpacer_25">
1773 <property name="orientation">
1774 <enum>Qt::Horizontal</enum>
1775 </property>
1776 <property name="sizeHint" stdset="0">
1777 <size>
1778 <width>0</width>
1779 <height>20</height>
1780 </size>
1781 </property>
1782 </spacer>
1783 </item>
1784 <item>
1785 <widget class="QWidget" name="arrow_right_shift" native="true"/>
1786 </item>
1787 <item>
1788 <spacer name="horizontalSpacer_26">
1789 <property name="orientation">
1790 <enum>Qt::Horizontal</enum>
1791 </property>
1792 <property name="sizeHint" stdset="0">
1793 <size>
1794 <width>0</width>
1795 <height>20</height>
1796 </size>
1797 </property>
1798 </spacer>
1799 </item>
1800 <item>
1801 <widget class="QWidget" name="button_press_stick_shift" native="true"/>
1802 </item>
1803 <item>
1804 <spacer name="horizontalSpacer_27">
1805 <property name="orientation">
1806 <enum>Qt::Horizontal</enum>
1807 </property>
1808 <property name="sizeHint" stdset="0">
1809 <size>
1810 <width>0</width>
1811 <height>20</height>
1812 </size>
1813 </property>
1814 </spacer>
1815 </item>
1816 <item>
1817 <widget class="QLabel" name="label_shift_shift">
1818 <property name="font">
1819 <font>
1820 <pointsize>18</pointsize>
1821 </font>
1822 </property>
1823 <property name="text">
1824 <string notr="true">Caps Lock</string>
1825 </property>
1826 </widget>
1827 </item>
1828 <item>
1829 <spacer name="horizontalSpacer_28">
1830 <property name="orientation">
1831 <enum>Qt::Horizontal</enum>
1832 </property>
1833 <property name="sizeHint" stdset="0">
1834 <size>
1835 <width>0</width>
1836 <height>20</height>
1837 </size>
1838 </property>
1839 </spacer>
1840 </item>
1841 <item>
1842 <widget class="QWidget" name="button_X_shift" native="true"/>
1843 </item>
1844 <item>
1845 <spacer name="horizontalSpacer_29">
1846 <property name="orientation">
1847 <enum>Qt::Horizontal</enum>
1848 </property>
1849 <property name="sizeHint" stdset="0">
1850 <size>
1851 <width>0</width>
1852 <height>20</height>
1853 </size>
1854 </property>
1855 </spacer>
1856 </item>
1857 <item>
1858 <widget class="QLabel" name="label_cancel_shift">
1859 <property name="font">
1860 <font>
1861 <pointsize>18</pointsize>
1862 </font>
1863 </property>
1864 <property name="text">
1865 <string notr="true">Cancel</string>
1866 </property>
1867 </widget>
1868 </item>
1869 <item>
1870 <spacer name="horizontalSpacer_30">
1871 <property name="orientation">
1872 <enum>Qt::Horizontal</enum>
1873 </property>
1874 <property name="sizeHint" stdset="0">
1875 <size>
1876 <width>0</width>
1877 <height>20</height>
1878 </size>
1879 </property>
1880 </spacer>
1881 </item>
1882 <item>
1883 <widget class="QWidget" name="button_A_shift" native="true"/>
1884 </item>
1885 <item>
1886 <spacer name="horizontalSpacer_31">
1887 <property name="orientation">
1888 <enum>Qt::Horizontal</enum>
1889 </property>
1890 <property name="sizeHint" stdset="0">
1891 <size>
1892 <width>0</width>
1893 <height>20</height>
1894 </size>
1895 </property>
1896 </spacer>
1897 </item>
1898 <item>
1899 <widget class="QLabel" name="label_enter_shift">
1900 <property name="font">
1901 <font>
1902 <pointsize>18</pointsize>
1903 </font>
1904 </property>
1905 <property name="text">
1906 <string notr="true">Enter</string>
1907 </property>
1908 </widget>
1909 </item>
1910 <item>
1911 <spacer name="horizontalSpacer_32">
1912 <property name="orientation">
1913 <enum>Qt::Horizontal</enum>
1914 </property>
1915 <property name="sizeHint" stdset="0">
1916 <size>
1917 <width>0</width>
1918 <height>20</height>
1919 </size>
1920 </property>
1921 </spacer>
1922 </item>
1923 </layout>
1924 </widget>
1925 </item>
1926 <item row="1" column="11">
1927 <widget class="QPushButton" name="button_underscore">
1928 <property name="sizePolicy">
1929 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1930 <horstretch>1</horstretch>
1931 <verstretch>1</verstretch>
1932 </sizepolicy>
1933 </property>
1934 <property name="font">
1935 <font>
1936 <pointsize>28</pointsize>
1937 </font>
1938 </property>
1939 <property name="text">
1940 <string notr="true">_</string>
1941 </property>
1942 </widget>
1943 </item>
1944 <item row="3" column="11">
1945 <widget class="QPushButton" name="button_quotation">
1946 <property name="sizePolicy">
1947 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1948 <horstretch>1</horstretch>
1949 <verstretch>1</verstretch>
1950 </sizepolicy>
1951 </property>
1952 <property name="font">
1953 <font>
1954 <pointsize>28</pointsize>
1955 </font>
1956 </property>
1957 <property name="text">
1958 <string notr="true">&quot;</string>
1959 </property>
1960 </widget>
1961 </item>
1962 <item row="2" column="11">
1963 <widget class="QPushButton" name="button_at">
1964 <property name="sizePolicy">
1965 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1966 <horstretch>1</horstretch>
1967 <verstretch>1</verstretch>
1968 </sizepolicy>
1969 </property>
1970 <property name="font">
1971 <font>
1972 <pointsize>28</pointsize>
1973 </font>
1974 </property>
1975 <property name="text">
1976 <string notr="true">@</string>
1977 </property>
1978 </widget>
1979 </item>
1980 <item row="4" column="11">
1981 <widget class="QPushButton" name="button_equal">
1982 <property name="sizePolicy">
1983 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1984 <horstretch>1</horstretch>
1985 <verstretch>1</verstretch>
1986 </sizepolicy>
1987 </property>
1988 <property name="font">
1989 <font>
1990 <pointsize>28</pointsize>
1991 </font>
1992 </property>
1993 <property name="text">
1994 <string notr="true">=</string>
1995 </property>
1996 </widget>
1997 </item>
1998 <item row="1" column="7">
1999 <widget class="QPushButton" name="button_ampersand">
2000 <property name="sizePolicy">
2001 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2002 <horstretch>1</horstretch>
2003 <verstretch>1</verstretch>
2004 </sizepolicy>
2005 </property>
2006 <property name="font">
2007 <font>
2008 <pointsize>28</pointsize>
2009 </font>
2010 </property>
2011 <property name="text">
2012 <string notr="true">&amp;&amp;</string>
2013 </property>
2014 </widget>
2015 </item>
2016 <item row="1" column="8">
2017 <widget class="QPushButton" name="button_asterisk">
2018 <property name="sizePolicy">
2019 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2020 <horstretch>1</horstretch>
2021 <verstretch>1</verstretch>
2022 </sizepolicy>
2023 </property>
2024 <property name="font">
2025 <font>
2026 <pointsize>28</pointsize>
2027 </font>
2028 </property>
2029 <property name="text">
2030 <string notr="true">*</string>
2031 </property>
2032 </widget>
2033 </item>
2034 <item row="1" column="10">
2035 <widget class="QPushButton" name="button_right_parenthesis">
2036 <property name="sizePolicy">
2037 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2038 <horstretch>1</horstretch>
2039 <verstretch>1</verstretch>
2040 </sizepolicy>
2041 </property>
2042 <property name="font">
2043 <font>
2044 <pointsize>28</pointsize>
2045 </font>
2046 </property>
2047 <property name="text">
2048 <string notr="true">)</string>
2049 </property>
2050 </widget>
2051 </item>
2052 <item row="1" column="9">
2053 <widget class="QPushButton" name="button_left_parenthesis">
2054 <property name="sizePolicy">
2055 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2056 <horstretch>1</horstretch>
2057 <verstretch>1</verstretch>
2058 </sizepolicy>
2059 </property>
2060 <property name="font">
2061 <font>
2062 <pointsize>28</pointsize>
2063 </font>
2064 </property>
2065 <property name="text">
2066 <string notr="true">(</string>
2067 </property>
2068 </widget>
2069 </item>
2070 <item row="2" column="2">
2071 <widget class="QPushButton" name="button_w_shift">
2072 <property name="sizePolicy">
2073 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2074 <horstretch>1</horstretch>
2075 <verstretch>1</verstretch>
2076 </sizepolicy>
2077 </property>
2078 <property name="font">
2079 <font>
2080 <pointsize>28</pointsize>
2081 </font>
2082 </property>
2083 <property name="text">
2084 <string notr="true">W</string>
2085 </property>
2086 </widget>
2087 </item>
2088 <item row="2" column="4">
2089 <widget class="QPushButton" name="button_r_shift">
2090 <property name="sizePolicy">
2091 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2092 <horstretch>1</horstretch>
2093 <verstretch>1</verstretch>
2094 </sizepolicy>
2095 </property>
2096 <property name="font">
2097 <font>
2098 <pointsize>28</pointsize>
2099 </font>
2100 </property>
2101 <property name="text">
2102 <string notr="true">R</string>
2103 </property>
2104 </widget>
2105 </item>
2106 <item row="2" column="3">
2107 <widget class="QPushButton" name="button_e_shift">
2108 <property name="sizePolicy">
2109 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2110 <horstretch>1</horstretch>
2111 <verstretch>1</verstretch>
2112 </sizepolicy>
2113 </property>
2114 <property name="font">
2115 <font>
2116 <pointsize>28</pointsize>
2117 </font>
2118 </property>
2119 <property name="text">
2120 <string notr="true">E</string>
2121 </property>
2122 </widget>
2123 </item>
2124 <item row="2" column="1">
2125 <widget class="QPushButton" name="button_q_shift">
2126 <property name="sizePolicy">
2127 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2128 <horstretch>1</horstretch>
2129 <verstretch>1</verstretch>
2130 </sizepolicy>
2131 </property>
2132 <property name="font">
2133 <font>
2134 <pointsize>28</pointsize>
2135 </font>
2136 </property>
2137 <property name="text">
2138 <string notr="true">Q</string>
2139 </property>
2140 </widget>
2141 </item>
2142 <item row="2" column="7">
2143 <widget class="QPushButton" name="button_u_shift">
2144 <property name="sizePolicy">
2145 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2146 <horstretch>1</horstretch>
2147 <verstretch>1</verstretch>
2148 </sizepolicy>
2149 </property>
2150 <property name="font">
2151 <font>
2152 <pointsize>28</pointsize>
2153 </font>
2154 </property>
2155 <property name="text">
2156 <string notr="true">U</string>
2157 </property>
2158 </widget>
2159 </item>
2160 <item row="2" column="6">
2161 <widget class="QPushButton" name="button_y_shift">
2162 <property name="sizePolicy">
2163 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2164 <horstretch>1</horstretch>
2165 <verstretch>1</verstretch>
2166 </sizepolicy>
2167 </property>
2168 <property name="font">
2169 <font>
2170 <pointsize>28</pointsize>
2171 </font>
2172 </property>
2173 <property name="text">
2174 <string notr="true">Y</string>
2175 </property>
2176 </widget>
2177 </item>
2178 <item row="2" column="5">
2179 <widget class="QPushButton" name="button_t_shift">
2180 <property name="sizePolicy">
2181 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2182 <horstretch>1</horstretch>
2183 <verstretch>1</verstretch>
2184 </sizepolicy>
2185 </property>
2186 <property name="font">
2187 <font>
2188 <pointsize>28</pointsize>
2189 </font>
2190 </property>
2191 <property name="text">
2192 <string notr="true">T</string>
2193 </property>
2194 </widget>
2195 </item>
2196 <item row="2" column="9">
2197 <widget class="QPushButton" name="button_o_shift">
2198 <property name="sizePolicy">
2199 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2200 <horstretch>1</horstretch>
2201 <verstretch>1</verstretch>
2202 </sizepolicy>
2203 </property>
2204 <property name="font">
2205 <font>
2206 <pointsize>28</pointsize>
2207 </font>
2208 </property>
2209 <property name="text">
2210 <string notr="true">O</string>
2211 </property>
2212 </widget>
2213 </item>
2214 <item row="2" column="10">
2215 <widget class="QPushButton" name="button_p_shift">
2216 <property name="sizePolicy">
2217 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2218 <horstretch>1</horstretch>
2219 <verstretch>1</verstretch>
2220 </sizepolicy>
2221 </property>
2222 <property name="font">
2223 <font>
2224 <pointsize>28</pointsize>
2225 </font>
2226 </property>
2227 <property name="text">
2228 <string notr="true">P</string>
2229 </property>
2230 </widget>
2231 </item>
2232 <item row="2" column="8">
2233 <widget class="QPushButton" name="button_i_shift">
2234 <property name="sizePolicy">
2235 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2236 <horstretch>1</horstretch>
2237 <verstretch>1</verstretch>
2238 </sizepolicy>
2239 </property>
2240 <property name="font">
2241 <font>
2242 <pointsize>28</pointsize>
2243 </font>
2244 </property>
2245 <property name="text">
2246 <string notr="true">I</string>
2247 </property>
2248 </widget>
2249 </item>
2250 <item row="3" column="1">
2251 <widget class="QPushButton" name="button_a_shift">
2252 <property name="sizePolicy">
2253 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2254 <horstretch>1</horstretch>
2255 <verstretch>1</verstretch>
2256 </sizepolicy>
2257 </property>
2258 <property name="font">
2259 <font>
2260 <pointsize>28</pointsize>
2261 </font>
2262 </property>
2263 <property name="text">
2264 <string notr="true">A</string>
2265 </property>
2266 </widget>
2267 </item>
2268 <item row="3" column="2">
2269 <widget class="QPushButton" name="button_s_shift">
2270 <property name="sizePolicy">
2271 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2272 <horstretch>1</horstretch>
2273 <verstretch>1</verstretch>
2274 </sizepolicy>
2275 </property>
2276 <property name="font">
2277 <font>
2278 <pointsize>28</pointsize>
2279 </font>
2280 </property>
2281 <property name="text">
2282 <string notr="true">S</string>
2283 </property>
2284 </widget>
2285 </item>
2286 <item row="3" column="3">
2287 <widget class="QPushButton" name="button_d_shift">
2288 <property name="sizePolicy">
2289 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2290 <horstretch>1</horstretch>
2291 <verstretch>1</verstretch>
2292 </sizepolicy>
2293 </property>
2294 <property name="font">
2295 <font>
2296 <pointsize>28</pointsize>
2297 </font>
2298 </property>
2299 <property name="text">
2300 <string notr="true">D</string>
2301 </property>
2302 </widget>
2303 </item>
2304 <item row="3" column="4">
2305 <widget class="QPushButton" name="button_f_shift">
2306 <property name="sizePolicy">
2307 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2308 <horstretch>1</horstretch>
2309 <verstretch>1</verstretch>
2310 </sizepolicy>
2311 </property>
2312 <property name="font">
2313 <font>
2314 <pointsize>28</pointsize>
2315 </font>
2316 </property>
2317 <property name="text">
2318 <string notr="true">F</string>
2319 </property>
2320 </widget>
2321 </item>
2322 <item row="3" column="6">
2323 <widget class="QPushButton" name="button_h_shift">
2324 <property name="sizePolicy">
2325 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2326 <horstretch>1</horstretch>
2327 <verstretch>1</verstretch>
2328 </sizepolicy>
2329 </property>
2330 <property name="font">
2331 <font>
2332 <pointsize>28</pointsize>
2333 </font>
2334 </property>
2335 <property name="text">
2336 <string notr="true">H</string>
2337 </property>
2338 </widget>
2339 </item>
2340 <item row="3" column="7">
2341 <widget class="QPushButton" name="button_j_shift">
2342 <property name="sizePolicy">
2343 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2344 <horstretch>1</horstretch>
2345 <verstretch>1</verstretch>
2346 </sizepolicy>
2347 </property>
2348 <property name="font">
2349 <font>
2350 <pointsize>28</pointsize>
2351 </font>
2352 </property>
2353 <property name="text">
2354 <string notr="true">J</string>
2355 </property>
2356 </widget>
2357 </item>
2358 <item row="3" column="5">
2359 <widget class="QPushButton" name="button_g_shift">
2360 <property name="sizePolicy">
2361 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2362 <horstretch>1</horstretch>
2363 <verstretch>1</verstretch>
2364 </sizepolicy>
2365 </property>
2366 <property name="font">
2367 <font>
2368 <pointsize>28</pointsize>
2369 </font>
2370 </property>
2371 <property name="text">
2372 <string notr="true">G</string>
2373 </property>
2374 </widget>
2375 </item>
2376 <item row="3" column="8">
2377 <widget class="QPushButton" name="button_k_shift">
2378 <property name="sizePolicy">
2379 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2380 <horstretch>1</horstretch>
2381 <verstretch>1</verstretch>
2382 </sizepolicy>
2383 </property>
2384 <property name="font">
2385 <font>
2386 <pointsize>28</pointsize>
2387 </font>
2388 </property>
2389 <property name="text">
2390 <string notr="true">K</string>
2391 </property>
2392 </widget>
2393 </item>
2394 <item row="3" column="9">
2395 <widget class="QPushButton" name="button_l_shift">
2396 <property name="sizePolicy">
2397 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2398 <horstretch>1</horstretch>
2399 <verstretch>1</verstretch>
2400 </sizepolicy>
2401 </property>
2402 <property name="font">
2403 <font>
2404 <pointsize>28</pointsize>
2405 </font>
2406 </property>
2407 <property name="text">
2408 <string notr="true">L</string>
2409 </property>
2410 </widget>
2411 </item>
2412 <item row="3" column="10">
2413 <widget class="QPushButton" name="button_semicolon">
2414 <property name="sizePolicy">
2415 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2416 <horstretch>1</horstretch>
2417 <verstretch>1</verstretch>
2418 </sizepolicy>
2419 </property>
2420 <property name="font">
2421 <font>
2422 <pointsize>28</pointsize>
2423 </font>
2424 </property>
2425 <property name="text">
2426 <string notr="true">;</string>
2427 </property>
2428 </widget>
2429 </item>
2430 <item row="2" column="12" rowspan="2">
2431 <widget class="QPushButton" name="button_return_shift">
2432 <property name="sizePolicy">
2433 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2434 <horstretch>1</horstretch>
2435 <verstretch>1</verstretch>
2436 </sizepolicy>
2437 </property>
2438 <property name="font">
2439 <font>
2440 <pointsize>18</pointsize>
2441 </font>
2442 </property>
2443 <property name="text">
2444 <string notr="true">Return</string>
2445 </property>
2446 </widget>
2447 </item>
2448 <item row="4" column="12" rowspan="2">
2449 <widget class="QPushButton" name="button_ok_shift">
2450 <property name="sizePolicy">
2451 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2452 <horstretch>1</horstretch>
2453 <verstretch>1</verstretch>
2454 </sizepolicy>
2455 </property>
2456 <property name="font">
2457 <font>
2458 <pointsize>18</pointsize>
2459 </font>
2460 </property>
2461 <property name="text">
2462 <string notr="true">OK</string>
2463 </property>
2464 </widget>
2465 </item>
2466 <item row="4" column="1">
2467 <widget class="QPushButton" name="button_z_shift">
2468 <property name="sizePolicy">
2469 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2470 <horstretch>1</horstretch>
2471 <verstretch>1</verstretch>
2472 </sizepolicy>
2473 </property>
2474 <property name="font">
2475 <font>
2476 <pointsize>28</pointsize>
2477 </font>
2478 </property>
2479 <property name="text">
2480 <string notr="true">Z</string>
2481 </property>
2482 </widget>
2483 </item>
2484 <item row="4" column="3">
2485 <widget class="QPushButton" name="button_c_shift">
2486 <property name="sizePolicy">
2487 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2488 <horstretch>1</horstretch>
2489 <verstretch>1</verstretch>
2490 </sizepolicy>
2491 </property>
2492 <property name="font">
2493 <font>
2494 <pointsize>28</pointsize>
2495 </font>
2496 </property>
2497 <property name="text">
2498 <string notr="true">C</string>
2499 </property>
2500 </widget>
2501 </item>
2502 <item row="4" column="2">
2503 <widget class="QPushButton" name="button_x_shift">
2504 <property name="sizePolicy">
2505 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2506 <horstretch>1</horstretch>
2507 <verstretch>1</verstretch>
2508 </sizepolicy>
2509 </property>
2510 <property name="font">
2511 <font>
2512 <pointsize>28</pointsize>
2513 </font>
2514 </property>
2515 <property name="text">
2516 <string notr="true">X</string>
2517 </property>
2518 </widget>
2519 </item>
2520 <item row="4" column="4">
2521 <widget class="QPushButton" name="button_v_shift">
2522 <property name="sizePolicy">
2523 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2524 <horstretch>1</horstretch>
2525 <verstretch>1</verstretch>
2526 </sizepolicy>
2527 </property>
2528 <property name="font">
2529 <font>
2530 <pointsize>28</pointsize>
2531 </font>
2532 </property>
2533 <property name="text">
2534 <string notr="true">V</string>
2535 </property>
2536 </widget>
2537 </item>
2538 <item row="4" column="7">
2539 <widget class="QPushButton" name="button_m_shift">
2540 <property name="sizePolicy">
2541 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2542 <horstretch>1</horstretch>
2543 <verstretch>1</verstretch>
2544 </sizepolicy>
2545 </property>
2546 <property name="font">
2547 <font>
2548 <pointsize>28</pointsize>
2549 </font>
2550 </property>
2551 <property name="text">
2552 <string notr="true">M</string>
2553 </property>
2554 </widget>
2555 </item>
2556 <item row="4" column="8">
2557 <widget class="QPushButton" name="button_less_than">
2558 <property name="sizePolicy">
2559 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2560 <horstretch>1</horstretch>
2561 <verstretch>1</verstretch>
2562 </sizepolicy>
2563 </property>
2564 <property name="font">
2565 <font>
2566 <pointsize>28</pointsize>
2567 </font>
2568 </property>
2569 <property name="text">
2570 <string notr="true">&lt;</string>
2571 </property>
2572 </widget>
2573 </item>
2574 <item row="4" column="6">
2575 <widget class="QPushButton" name="button_n_shift">
2576 <property name="sizePolicy">
2577 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2578 <horstretch>1</horstretch>
2579 <verstretch>1</verstretch>
2580 </sizepolicy>
2581 </property>
2582 <property name="font">
2583 <font>
2584 <pointsize>28</pointsize>
2585 </font>
2586 </property>
2587 <property name="text">
2588 <string notr="true">N</string>
2589 </property>
2590 </widget>
2591 </item>
2592 <item row="4" column="5">
2593 <widget class="QPushButton" name="button_b_shift">
2594 <property name="sizePolicy">
2595 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2596 <horstretch>1</horstretch>
2597 <verstretch>1</verstretch>
2598 </sizepolicy>
2599 </property>
2600 <property name="font">
2601 <font>
2602 <pointsize>28</pointsize>
2603 </font>
2604 </property>
2605 <property name="text">
2606 <string notr="true">B</string>
2607 </property>
2608 </widget>
2609 </item>
2610 <item row="5" column="1" colspan="2">
2611 <widget class="QPushButton" name="button_shift_shift">
2612 <property name="sizePolicy">
2613 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2614 <horstretch>1</horstretch>
2615 <verstretch>1</verstretch>
2616 </sizepolicy>
2617 </property>
2618 <property name="font">
2619 <font>
2620 <pointsize>18</pointsize>
2621 </font>
2622 </property>
2623 <property name="text">
2624 <string notr="true"/>
2625 </property>
2626 <property name="checkable">
2627 <bool>true</bool>
2628 </property>
2629 <property name="checked">
2630 <bool>false</bool>
2631 </property>
2632 </widget>
2633 </item>
2634 <item row="4" column="10">
2635 <widget class="QPushButton" name="button_plus">
2636 <property name="sizePolicy">
2637 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2638 <horstretch>1</horstretch>
2639 <verstretch>1</verstretch>
2640 </sizepolicy>
2641 </property>
2642 <property name="font">
2643 <font>
2644 <pointsize>28</pointsize>
2645 </font>
2646 </property>
2647 <property name="text">
2648 <string notr="true">+</string>
2649 </property>
2650 </widget>
2651 </item>
2652 <item row="4" column="9">
2653 <widget class="QPushButton" name="button_greater_than">
2654 <property name="sizePolicy">
2655 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2656 <horstretch>1</horstretch>
2657 <verstretch>1</verstretch>
2658 </sizepolicy>
2659 </property>
2660 <property name="font">
2661 <font>
2662 <pointsize>28</pointsize>
2663 </font>
2664 </property>
2665 <property name="text">
2666 <string notr="true">&gt;</string>
2667 </property>
2668 </widget>
2669 </item>
2670 <item row="1" column="1">
2671 <widget class="QPushButton" name="button_hash">
2672 <property name="sizePolicy">
2673 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2674 <horstretch>1</horstretch>
2675 <verstretch>1</verstretch>
2676 </sizepolicy>
2677 </property>
2678 <property name="font">
2679 <font>
2680 <pointsize>28</pointsize>
2681 </font>
2682 </property>
2683 <property name="text">
2684 <string notr="true">#</string>
2685 </property>
2686 </widget>
2687 </item>
2688 <item row="1" column="3">
2689 <widget class="QPushButton" name="button_right_bracket">
2690 <property name="sizePolicy">
2691 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2692 <horstretch>1</horstretch>
2693 <verstretch>1</verstretch>
2694 </sizepolicy>
2695 </property>
2696 <property name="font">
2697 <font>
2698 <pointsize>28</pointsize>
2699 </font>
2700 </property>
2701 <property name="text">
2702 <string notr="true">]</string>
2703 </property>
2704 </widget>
2705 </item>
2706 <item row="1" column="4">
2707 <widget class="QPushButton" name="button_dollar">
2708 <property name="sizePolicy">
2709 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2710 <horstretch>1</horstretch>
2711 <verstretch>1</verstretch>
2712 </sizepolicy>
2713 </property>
2714 <property name="font">
2715 <font>
2716 <pointsize>28</pointsize>
2717 </font>
2718 </property>
2719 <property name="text">
2720 <string notr="true">$</string>
2721 </property>
2722 </widget>
2723 </item>
2724 <item row="1" column="2">
2725 <widget class="QPushButton" name="button_left_bracket">
2726 <property name="sizePolicy">
2727 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2728 <horstretch>1</horstretch>
2729 <verstretch>1</verstretch>
2730 </sizepolicy>
2731 </property>
2732 <property name="font">
2733 <font>
2734 <pointsize>28</pointsize>
2735 </font>
2736 </property>
2737 <property name="text">
2738 <string notr="true">[</string>
2739 </property>
2740 </widget>
2741 </item>
2742 <item row="1" column="6">
2743 <widget class="QPushButton" name="button_circumflex">
2744 <property name="sizePolicy">
2745 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2746 <horstretch>1</horstretch>
2747 <verstretch>1</verstretch>
2748 </sizepolicy>
2749 </property>
2750 <property name="font">
2751 <font>
2752 <pointsize>28</pointsize>
2753 </font>
2754 </property>
2755 <property name="text">
2756 <string notr="true">^</string>
2757 </property>
2758 </widget>
2759 </item>
2760 <item row="1" column="5">
2761 <widget class="QPushButton" name="button_percent">
2762 <property name="sizePolicy">
2763 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2764 <horstretch>1</horstretch>
2765 <verstretch>1</verstretch>
2766 </sizepolicy>
2767 </property>
2768 <property name="font">
2769 <font>
2770 <pointsize>28</pointsize>
2771 </font>
2772 </property>
2773 <property name="text">
2774 <string notr="true">%</string>
2775 </property>
2776 </widget>
2777 </item>
2778 <item row="5" column="3" colspan="9">
2779 <widget class="QPushButton" name="button_space_shift">
2780 <property name="sizePolicy">
2781 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2782 <horstretch>1</horstretch>
2783 <verstretch>1</verstretch>
2784 </sizepolicy>
2785 </property>
2786 <property name="font">
2787 <font>
2788 <pointsize>18</pointsize>
2789 </font>
2790 </property>
2791 <property name="text">
2792 <string notr="true">Space</string>
2793 </property>
2794 </widget>
2795 </item>
2796 <item row="1" column="12">
2797 <widget class="QPushButton" name="button_backspace_shift">
2798 <property name="sizePolicy">
2799 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2800 <horstretch>1</horstretch>
2801 <verstretch>1</verstretch>
2802 </sizepolicy>
2803 </property>
2804 <property name="font">
2805 <font>
2806 <pointsize>18</pointsize>
2807 </font>
2808 </property>
2809 <property name="text">
2810 <string notr="true"/>
2811 </property>
2812 </widget>
2813 </item>
2814 <item row="1" column="0">
2815 <spacer name="horizontalSpacer_33">
2816 <property name="orientation">
2817 <enum>Qt::Horizontal</enum>
2818 </property>
2819 <property name="sizeHint" stdset="0">
2820 <size>
2821 <width>40</width>
2822 <height>20</height>
2823 </size>
2824 </property>
2825 </spacer>
2826 </item>
2827 <item row="0" column="1">
2828 <spacer name="verticalSpacer_6">
2829 <property name="orientation">
2830 <enum>Qt::Vertical</enum>
2831 </property>
2832 <property name="sizeHint" stdset="0">
2833 <size>
2834 <width>20</width>
2835 <height>0</height>
2836 </size>
2837 </property>
2838 </spacer>
2839 </item>
2840 <item row="1" column="13">
2841 <spacer name="horizontalSpacer_34">
2842 <property name="orientation">
2843 <enum>Qt::Horizontal</enum>
2844 </property>
2845 <property name="sizeHint" stdset="0">
2846 <size>
2847 <width>40</width>
2848 <height>20</height>
2849 </size>
2850 </property>
2851 </spacer>
2852 </item>
2853 </layout>
2854 </item>
2855 </layout>
2856 </widget>
2857 <widget class="QWidget" name="numOSK">
2858 <layout class="QVBoxLayout" name="graphicsTabVerticalLayout">
2859 <property name="leftMargin">
2860 <number>0</number>
2861 </property>
2862 <property name="topMargin">
2863 <number>0</number>
2864 </property>
2865 <property name="rightMargin">
2866 <number>0</number>
2867 </property>
2868 <property name="bottomMargin">
2869 <number>0</number>
2870 </property>
2871 <item>
2872 <layout class="QGridLayout" name="kbOSKnum" rowstretch="18,63,63,63,63,10,70" columnstretch="54,307,186,186,186,120,187,54">
2873 <property name="leftMargin">
2874 <number>0</number>
2875 </property>
2876 <property name="rightMargin">
2877 <number>0</number>
2878 </property>
2879 <property name="spacing">
2880 <number>0</number>
2881 </property>
2882 <item row="1" column="5">
2883 <widget class="QPushButton" name="button_backspace_num">
2884 <property name="sizePolicy">
2885 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
2886 <horstretch>1</horstretch>
2887 <verstretch>1</verstretch>
2888 </sizepolicy>
2889 </property>
2890 <property name="font">
2891 <font>
2892 <pointsize>18</pointsize>
2893 </font>
2894 </property>
2895 <property name="text">
2896 <string notr="true"/>
2897 </property>
2898 </widget>
2899 </item>
2900 <item row="1" column="6">
2901 <spacer name="horizontalSpacer_35">
2902 <property name="orientation">
2903 <enum>Qt::Horizontal</enum>
2904 </property>
2905 <property name="sizeHint" stdset="0">
2906 <size>
2907 <width>40</width>
2908 <height>20</height>
2909 </size>
2910 </property>
2911 </spacer>
2912 </item>
2913 <item row="1" column="1">
2914 <spacer name="horizontalSpacer_36">
2915 <property name="orientation">
2916 <enum>Qt::Horizontal</enum>
2917 </property>
2918 <property name="sizeHint" stdset="0">
2919 <size>
2920 <width>40</width>
2921 <height>20</height>
2922 </size>
2923 </property>
2924 </spacer>
2925 </item>
2926 <item row="0" column="2">
2927 <spacer name="verticalSpacer_7">
2928 <property name="orientation">
2929 <enum>Qt::Vertical</enum>
2930 </property>
2931 <property name="sizeHint" stdset="0">
2932 <size>
2933 <width>20</width>
2934 <height>0</height>
2935 </size>
2936 </property>
2937 </spacer>
2938 </item>
2939 <item row="6" column="1" colspan="6">
2940 <widget class="QWidget" name="legendOSKnum" native="true">
2941 <layout class="QHBoxLayout" name="horizontalLayout_6" stretch="25,70,601,25,12,22,41,25,12,22,41,29,12,69,37,29,12,56,30">
2942 <property name="spacing">
2943 <number>0</number>
2944 </property>
2945 <property name="leftMargin">
2946 <number>0</number>
2947 </property>
2948 <property name="topMargin">
2949 <number>0</number>
2950 </property>
2951 <property name="rightMargin">
2952 <number>0</number>
2953 </property>
2954 <property name="bottomMargin">
2955 <number>0</number>
2956 </property>
2957 <item>
2958 <spacer name="horizontalSpacer_48">
2959 <property name="orientation">
2960 <enum>Qt::Horizontal</enum>
2961 </property>
2962 <property name="sizeHint" stdset="0">
2963 <size>
2964 <width>40</width>
2965 <height>20</height>
2966 </size>
2967 </property>
2968 </spacer>
2969 </item>
2970 <item>
2971 <widget class="QWidget" name="icon_controller_num" native="true">
2972 <property name="styleSheet">
2973 <string notr="true"/>
2974 </property>
2975 </widget>
2976 </item>
2977 <item>
2978 <spacer name="horizontalSpacer_38">
2979 <property name="orientation">
2980 <enum>Qt::Horizontal</enum>
2981 </property>
2982 <property name="sizeHint" stdset="0">
2983 <size>
2984 <width>0</width>
2985 <height>20</height>
2986 </size>
2987 </property>
2988 </spacer>
2989 </item>
2990 <item>
2991 <widget class="QWidget" name="button_L_num" native="true"/>
2992 </item>
2993 <item>
2994 <spacer name="horizontalSpacer_39">
2995 <property name="orientation">
2996 <enum>Qt::Horizontal</enum>
2997 </property>
2998 <property name="sizeHint" stdset="0">
2999 <size>
3000 <width>0</width>
3001 <height>20</height>
3002 </size>
3003 </property>
3004 </spacer>
3005 </item>
3006 <item>
3007 <widget class="QWidget" name="arrow_left_num" native="true"/>
3008 </item>
3009 <item>
3010 <spacer name="horizontalSpacer_40">
3011 <property name="orientation">
3012 <enum>Qt::Horizontal</enum>
3013 </property>
3014 <property name="sizeHint" stdset="0">
3015 <size>
3016 <width>0</width>
3017 <height>20</height>
3018 </size>
3019 </property>
3020 </spacer>
3021 </item>
3022 <item>
3023 <widget class="QWidget" name="button_R_num" native="true"/>
3024 </item>
3025 <item>
3026 <spacer name="horizontalSpacer_41">
3027 <property name="orientation">
3028 <enum>Qt::Horizontal</enum>
3029 </property>
3030 <property name="sizeHint" stdset="0">
3031 <size>
3032 <width>0</width>
3033 <height>20</height>
3034 </size>
3035 </property>
3036 </spacer>
3037 </item>
3038 <item>
3039 <widget class="QWidget" name="arrow_right_num" native="true"/>
3040 </item>
3041 <item>
3042 <spacer name="horizontalSpacer_42">
3043 <property name="orientation">
3044 <enum>Qt::Horizontal</enum>
3045 </property>
3046 <property name="sizeHint" stdset="0">
3047 <size>
3048 <width>0</width>
3049 <height>20</height>
3050 </size>
3051 </property>
3052 </spacer>
3053 </item>
3054 <item>
3055 <widget class="QWidget" name="button_X_num" native="true"/>
3056 </item>
3057 <item>
3058 <spacer name="horizontalSpacer_43">
3059 <property name="orientation">
3060 <enum>Qt::Horizontal</enum>
3061 </property>
3062 <property name="sizeHint" stdset="0">
3063 <size>
3064 <width>0</width>
3065 <height>20</height>
3066 </size>
3067 </property>
3068 </spacer>
3069 </item>
3070 <item>
3071 <widget class="QLabel" name="label_cancel_num">
3072 <property name="font">
3073 <font>
3074 <pointsize>18</pointsize>
3075 </font>
3076 </property>
3077 <property name="text">
3078 <string notr="true">Cancel</string>
3079 </property>
3080 </widget>
3081 </item>
3082 <item>
3083 <spacer name="horizontalSpacer_44">
3084 <property name="orientation">
3085 <enum>Qt::Horizontal</enum>
3086 </property>
3087 <property name="sizeHint" stdset="0">
3088 <size>
3089 <width>0</width>
3090 <height>20</height>
3091 </size>
3092 </property>
3093 </spacer>
3094 </item>
3095 <item>
3096 <widget class="QWidget" name="button_A_num" native="true"/>
3097 </item>
3098 <item>
3099 <spacer name="horizontalSpacer_45">
3100 <property name="orientation">
3101 <enum>Qt::Horizontal</enum>
3102 </property>
3103 <property name="sizeHint" stdset="0">
3104 <size>
3105 <width>0</width>
3106 <height>20</height>
3107 </size>
3108 </property>
3109 </spacer>
3110 </item>
3111 <item>
3112 <widget class="QLabel" name="label_enter_num">
3113 <property name="font">
3114 <font>
3115 <pointsize>18</pointsize>
3116 </font>
3117 </property>
3118 <property name="text">
3119 <string notr="true">Enter</string>
3120 </property>
3121 </widget>
3122 </item>
3123 <item>
3124 <spacer name="horizontalSpacer_46">
3125 <property name="orientation">
3126 <enum>Qt::Horizontal</enum>
3127 </property>
3128 <property name="sizeHint" stdset="0">
3129 <size>
3130 <width>0</width>
3131 <height>20</height>
3132 </size>
3133 </property>
3134 </spacer>
3135 </item>
3136 </layout>
3137 </widget>
3138 </item>
3139 <item row="2" column="4">
3140 <widget class="QPushButton" name="button_6_num">
3141 <property name="sizePolicy">
3142 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3143 <horstretch>1</horstretch>
3144 <verstretch>1</verstretch>
3145 </sizepolicy>
3146 </property>
3147 <property name="font">
3148 <font>
3149 <pointsize>28</pointsize>
3150 </font>
3151 </property>
3152 <property name="text">
3153 <string notr="true">6</string>
3154 </property>
3155 </widget>
3156 </item>
3157 <item row="2" column="2">
3158 <widget class="QPushButton" name="button_4_num">
3159 <property name="sizePolicy">
3160 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3161 <horstretch>1</horstretch>
3162 <verstretch>1</verstretch>
3163 </sizepolicy>
3164 </property>
3165 <property name="font">
3166 <font>
3167 <pointsize>28</pointsize>
3168 </font>
3169 </property>
3170 <property name="text">
3171 <string notr="true">4</string>
3172 </property>
3173 </widget>
3174 </item>
3175 <item row="3" column="4">
3176 <widget class="QPushButton" name="button_9_num">
3177 <property name="sizePolicy">
3178 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3179 <horstretch>1</horstretch>
3180 <verstretch>1</verstretch>
3181 </sizepolicy>
3182 </property>
3183 <property name="font">
3184 <font>
3185 <pointsize>28</pointsize>
3186 </font>
3187 </property>
3188 <property name="text">
3189 <string notr="true">9</string>
3190 </property>
3191 </widget>
3192 </item>
3193 <item row="2" column="3">
3194 <widget class="QPushButton" name="button_5_num">
3195 <property name="sizePolicy">
3196 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3197 <horstretch>1</horstretch>
3198 <verstretch>1</verstretch>
3199 </sizepolicy>
3200 </property>
3201 <property name="font">
3202 <font>
3203 <pointsize>28</pointsize>
3204 </font>
3205 </property>
3206 <property name="text">
3207 <string notr="true">5</string>
3208 </property>
3209 </widget>
3210 </item>
3211 <item row="2" column="5" rowspan="3">
3212 <widget class="QPushButton" name="button_ok_num">
3213 <property name="sizePolicy">
3214 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3215 <horstretch>1</horstretch>
3216 <verstretch>1</verstretch>
3217 </sizepolicy>
3218 </property>
3219 <property name="font">
3220 <font>
3221 <pointsize>18</pointsize>
3222 </font>
3223 </property>
3224 <property name="text">
3225 <string notr="true">OK</string>
3226 </property>
3227 </widget>
3228 </item>
3229 <item row="3" column="2">
3230 <widget class="QPushButton" name="button_7_num">
3231 <property name="sizePolicy">
3232 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3233 <horstretch>1</horstretch>
3234 <verstretch>1</verstretch>
3235 </sizepolicy>
3236 </property>
3237 <property name="font">
3238 <font>
3239 <pointsize>28</pointsize>
3240 </font>
3241 </property>
3242 <property name="text">
3243 <string notr="true">7</string>
3244 </property>
3245 </widget>
3246 </item>
3247 <item row="3" column="3">
3248 <widget class="QPushButton" name="button_8_num">
3249 <property name="sizePolicy">
3250 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3251 <horstretch>1</horstretch>
3252 <verstretch>1</verstretch>
3253 </sizepolicy>
3254 </property>
3255 <property name="font">
3256 <font>
3257 <pointsize>28</pointsize>
3258 </font>
3259 </property>
3260 <property name="text">
3261 <string notr="true">8</string>
3262 </property>
3263 </widget>
3264 </item>
3265 <item row="1" column="3">
3266 <widget class="QPushButton" name="button_2_num">
3267 <property name="sizePolicy">
3268 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3269 <horstretch>1</horstretch>
3270 <verstretch>1</verstretch>
3271 </sizepolicy>
3272 </property>
3273 <property name="font">
3274 <font>
3275 <pointsize>28</pointsize>
3276 </font>
3277 </property>
3278 <property name="text">
3279 <string notr="true">2</string>
3280 </property>
3281 </widget>
3282 </item>
3283 <item row="1" column="2">
3284 <widget class="QPushButton" name="button_1_num">
3285 <property name="sizePolicy">
3286 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3287 <horstretch>1</horstretch>
3288 <verstretch>1</verstretch>
3289 </sizepolicy>
3290 </property>
3291 <property name="font">
3292 <font>
3293 <pointsize>28</pointsize>
3294 </font>
3295 </property>
3296 <property name="text">
3297 <string notr="true">1</string>
3298 </property>
3299 </widget>
3300 </item>
3301 <item row="4" column="3">
3302 <widget class="QPushButton" name="button_0_num">
3303 <property name="sizePolicy">
3304 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3305 <horstretch>1</horstretch>
3306 <verstretch>1</verstretch>
3307 </sizepolicy>
3308 </property>
3309 <property name="font">
3310 <font>
3311 <pointsize>28</pointsize>
3312 </font>
3313 </property>
3314 <property name="text">
3315 <string notr="true">0</string>
3316 </property>
3317 </widget>
3318 </item>
3319 <item row="1" column="4">
3320 <widget class="QPushButton" name="button_3_num">
3321 <property name="sizePolicy">
3322 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
3323 <horstretch>1</horstretch>
3324 <verstretch>1</verstretch>
3325 </sizepolicy>
3326 </property>
3327 <property name="font">
3328 <font>
3329 <pointsize>28</pointsize>
3330 </font>
3331 </property>
3332 <property name="text">
3333 <string notr="true">3</string>
3334 </property>
3335 </widget>
3336 </item>
3337 <item row="1" column="0">
3338 <spacer name="horizontalSpacer_37">
3339 <property name="orientation">
3340 <enum>Qt::Horizontal</enum>
3341 </property>
3342 <property name="sizeHint" stdset="0">
3343 <size>
3344 <width>40</width>
3345 <height>20</height>
3346 </size>
3347 </property>
3348 </spacer>
3349 </item>
3350 <item row="1" column="7">
3351 <spacer name="horizontalSpacer_47">
3352 <property name="orientation">
3353 <enum>Qt::Horizontal</enum>
3354 </property>
3355 <property name="sizeHint" stdset="0">
3356 <size>
3357 <width>40</width>
3358 <height>20</height>
3359 </size>
3360 </property>
3361 </spacer>
3362 </item>
3363 <item row="5" column="3">
3364 <spacer name="verticalSpacer_8">
3365 <property name="orientation">
3366 <enum>Qt::Vertical</enum>
3367 </property>
3368 <property name="sizeHint" stdset="0">
3369 <size>
3370 <width>20</width>
3371 <height>0</height>
3372 </size>
3373 </property>
3374 </spacer>
3375 </item>
3376 </layout>
3377 </item>
3378 </layout>
3379 </widget>
3380 </widget>
3381 </item>
3382 </layout>
3383 </widget>
3384 </item>
3385 </layout>
3386 </widget>
3387 <tabstops>
3388 <tabstop>button_1</tabstop>
3389 <tabstop>button_2</tabstop>
3390 <tabstop>button_3</tabstop>
3391 <tabstop>button_4</tabstop>
3392 <tabstop>button_5</tabstop>
3393 <tabstop>button_6</tabstop>
3394 <tabstop>button_7</tabstop>
3395 <tabstop>button_8</tabstop>
3396 <tabstop>button_9</tabstop>
3397 <tabstop>button_0</tabstop>
3398 <tabstop>button_minus</tabstop>
3399 <tabstop>button_backspace</tabstop>
3400 <tabstop>button_q</tabstop>
3401 <tabstop>button_w</tabstop>
3402 <tabstop>button_e</tabstop>
3403 <tabstop>button_r</tabstop>
3404 <tabstop>button_t</tabstop>
3405 <tabstop>button_y</tabstop>
3406 <tabstop>button_u</tabstop>
3407 <tabstop>button_i</tabstop>
3408 <tabstop>button_o</tabstop>
3409 <tabstop>button_p</tabstop>
3410 <tabstop>button_slash</tabstop>
3411 <tabstop>button_return</tabstop>
3412 <tabstop>button_a</tabstop>
3413 <tabstop>button_s</tabstop>
3414 <tabstop>button_d</tabstop>
3415 <tabstop>button_f</tabstop>
3416 <tabstop>button_g</tabstop>
3417 <tabstop>button_h</tabstop>
3418 <tabstop>button_j</tabstop>
3419 <tabstop>button_k</tabstop>
3420 <tabstop>button_l</tabstop>
3421 <tabstop>button_colon</tabstop>
3422 <tabstop>button_apostrophe</tabstop>
3423 <tabstop>button_z</tabstop>
3424 <tabstop>button_x</tabstop>
3425 <tabstop>button_c</tabstop>
3426 <tabstop>button_v</tabstop>
3427 <tabstop>button_b</tabstop>
3428 <tabstop>button_n</tabstop>
3429 <tabstop>button_m</tabstop>
3430 <tabstop>button_comma</tabstop>
3431 <tabstop>button_dot</tabstop>
3432 <tabstop>button_question</tabstop>
3433 <tabstop>button_exclamation</tabstop>
3434 <tabstop>button_ok</tabstop>
3435 <tabstop>button_shift</tabstop>
3436 <tabstop>button_space</tabstop>
3437 <tabstop>button_hash</tabstop>
3438 <tabstop>button_left_bracket</tabstop>
3439 <tabstop>button_right_bracket</tabstop>
3440 <tabstop>button_dollar</tabstop>
3441 <tabstop>button_percent</tabstop>
3442 <tabstop>button_circumflex</tabstop>
3443 <tabstop>button_ampersand</tabstop>
3444 <tabstop>button_asterisk</tabstop>
3445 <tabstop>button_left_parenthesis</tabstop>
3446 <tabstop>button_right_parenthesis</tabstop>
3447 <tabstop>button_underscore</tabstop>
3448 <tabstop>button_backspace_shift</tabstop>
3449 <tabstop>button_q_shift</tabstop>
3450 <tabstop>button_w_shift</tabstop>
3451 <tabstop>button_e_shift</tabstop>
3452 <tabstop>button_r_shift</tabstop>
3453 <tabstop>button_t_shift</tabstop>
3454 <tabstop>button_y_shift</tabstop>
3455 <tabstop>button_u_shift</tabstop>
3456 <tabstop>button_i_shift</tabstop>
3457 <tabstop>button_o_shift</tabstop>
3458 <tabstop>button_p_shift</tabstop>
3459 <tabstop>button_at</tabstop>
3460 <tabstop>button_return_shift</tabstop>
3461 <tabstop>button_a_shift</tabstop>
3462 <tabstop>button_s_shift</tabstop>
3463 <tabstop>button_d_shift</tabstop>
3464 <tabstop>button_f_shift</tabstop>
3465 <tabstop>button_g_shift</tabstop>
3466 <tabstop>button_h_shift</tabstop>
3467 <tabstop>button_j_shift</tabstop>
3468 <tabstop>button_k_shift</tabstop>
3469 <tabstop>button_l_shift</tabstop>
3470 <tabstop>button_semicolon</tabstop>
3471 <tabstop>button_quotation</tabstop>
3472 <tabstop>button_z_shift</tabstop>
3473 <tabstop>button_x_shift</tabstop>
3474 <tabstop>button_c_shift</tabstop>
3475 <tabstop>button_v_shift</tabstop>
3476 <tabstop>button_b_shift</tabstop>
3477 <tabstop>button_n_shift</tabstop>
3478 <tabstop>button_m_shift</tabstop>
3479 <tabstop>button_less_than</tabstop>
3480 <tabstop>button_greater_than</tabstop>
3481 <tabstop>button_plus</tabstop>
3482 <tabstop>button_equal</tabstop>
3483 <tabstop>button_ok_shift</tabstop>
3484 <tabstop>button_shift_shift</tabstop>
3485 <tabstop>button_space_shift</tabstop>
3486 <tabstop>button_1_num</tabstop>
3487 <tabstop>button_2_num</tabstop>
3488 <tabstop>button_3_num</tabstop>
3489 <tabstop>button_backspace_num</tabstop>
3490 <tabstop>button_4_num</tabstop>
3491 <tabstop>button_5_num</tabstop>
3492 <tabstop>button_6_num</tabstop>
3493 <tabstop>button_ok_num</tabstop>
3494 <tabstop>button_7_num</tabstop>
3495 <tabstop>button_8_num</tabstop>
3496 <tabstop>button_9_num</tabstop>
3497 <tabstop>button_0_num</tabstop>
3498 </tabstops>
3499 <resources>
3500 <include location="../../../dist/icons/overlay/overlay.qrc"/>
3501 </resources>
3502 <connections/>
3503</ui>
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 15c09e0ad..9c7daeac7 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -29,10 +29,10 @@
29#include "common/microprofile.h" 29#include "common/microprofile.h"
30#include "common/scm_rev.h" 30#include "common/scm_rev.h"
31#include "common/scope_exit.h" 31#include "common/scope_exit.h"
32#include "common/settings.h"
32#include "core/core.h" 33#include "core/core.h"
33#include "core/frontend/framebuffer_layout.h" 34#include "core/frontend/framebuffer_layout.h"
34#include "core/hle/kernel/process.h" 35#include "core/hle/kernel/process.h"
35#include "core/settings.h"
36#include "input_common/keyboard.h" 36#include "input_common/keyboard.h"
37#include "input_common/main.h" 37#include "input_common/main.h"
38#include "input_common/mouse/mouse_input.h" 38#include "input_common/mouse/mouse_input.h"
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 1bac57bb2..851246233 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -641,6 +641,9 @@ void Config::ReadDebuggingValues() {
641 ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); 641 ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
642 Settings::values.extended_logging = 642 Settings::values.extended_logging =
643 ReadSetting(QStringLiteral("extended_logging"), false).toBool(); 643 ReadSetting(QStringLiteral("extended_logging"), false).toBool();
644 Settings::values.use_debug_asserts =
645 ReadSetting(QStringLiteral("use_debug_asserts"), false).toBool();
646 Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
644 647
645 qt_config->endGroup(); 648 qt_config->endGroup();
646} 649}
@@ -770,6 +773,13 @@ void Config::ReadRendererValues() {
770 ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0); 773 ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
771 ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false); 774 ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
772 ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0); 775 ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
776#ifdef _WIN32
777 ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 0);
778#else
779 // *nix platforms may have issues with the borderless windowed fullscreen mode.
780 // Default to exclusive fullscreen on these platforms for now.
781 ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 1);
782#endif
773 ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0); 783 ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
774 ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0); 784 ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
775 ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true); 785 ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
@@ -1230,6 +1240,7 @@ void Config::SaveDebuggingValues() {
1230 WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false); 1240 WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
1231 WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false); 1241 WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
1232 WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false); 1242 WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
1243 WriteSetting(QStringLiteral("use_debug_asserts"), Settings::values.use_debug_asserts, false);
1233 WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false); 1244 WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false);
1234 1245
1235 qt_config->endGroup(); 1246 qt_config->endGroup();
@@ -1333,6 +1344,13 @@ void Config::SaveRendererValues() {
1333 Settings::values.renderer_backend.UsingGlobal(), 0); 1344 Settings::values.renderer_backend.UsingGlobal(), 0);
1334 WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false); 1345 WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
1335 WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0); 1346 WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
1347#ifdef _WIN32
1348 WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 0);
1349#else
1350 // *nix platforms may have issues with the borderless windowed fullscreen mode.
1351 // Default to exclusive fullscreen on these platforms for now.
1352 WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 1);
1353#endif
1336 WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0); 1354 WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
1337 WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0); 1355 WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
1338 WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true); 1356 WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
@@ -1584,7 +1602,7 @@ void Config::Reload() {
1584 ReadValues(); 1602 ReadValues();
1585 // To apply default value changes 1603 // To apply default value changes
1586 SaveValues(); 1604 SaveValues();
1587 Settings::Apply(Core::System::GetInstance()); 1605 Core::System::GetInstance().ApplySettings();
1588} 1606}
1589 1607
1590void Config::Save() { 1608void Config::Save() {
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 949c4eb13..5a2c026b3 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -9,7 +9,7 @@
9#include <string> 9#include <string>
10#include <QMetaType> 10#include <QMetaType>
11#include <QVariant> 11#include <QVariant>
12#include "core/settings.h" 12#include "common/settings.h"
13#include "yuzu/uisettings.h" 13#include "yuzu/uisettings.h"
14 14
15class QSettings; 15class QSettings;
@@ -131,6 +131,6 @@ private:
131 bool global; 131 bool global;
132}; 132};
133 133
134// These metatype declarations cannot be in core/settings.h because core is devoid of QT 134// These metatype declarations cannot be in common/settings.h because core is devoid of QT
135Q_DECLARE_METATYPE(Settings::RendererBackend); 135Q_DECLARE_METATYPE(Settings::RendererBackend);
136Q_DECLARE_METATYPE(Settings::GPUAccuracy); 136Q_DECLARE_METATYPE(Settings::GPUAccuracy);
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp
index 18482795c..89be4a62d 100644
--- a/src/yuzu/configuration/configuration_shared.cpp
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -6,7 +6,7 @@
6#include <QComboBox> 6#include <QComboBox>
7#include <QObject> 7#include <QObject>
8#include <QString> 8#include <QString>
9#include "core/settings.h" 9#include "common/settings.h"
10#include "yuzu/configuration/configuration_shared.h" 10#include "yuzu/configuration/configuration_shared.h"
11#include "yuzu/configuration/configure_per_game.h" 11#include "yuzu/configuration/configure_per_game.h"
12 12
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
index 312b9e549..5b344cdbd 100644
--- a/src/yuzu/configuration/configuration_shared.h
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -7,7 +7,7 @@
7#include <QCheckBox> 7#include <QCheckBox>
8#include <QComboBox> 8#include <QComboBox>
9#include <QString> 9#include <QString>
10#include "core/settings.h" 10#include "common/settings.h"
11 11
12namespace ConfigurationShared { 12namespace ConfigurationShared {
13 13
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index db9518798..f9507e228 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -8,8 +8,8 @@
8 8
9#include "audio_core/sink.h" 9#include "audio_core/sink.h"
10#include "audio_core/sink_details.h" 10#include "audio_core/sink_details.h"
11#include "common/settings.h"
11#include "core/core.h" 12#include "core/core.h"
12#include "core/settings.h"
13#include "ui_configure_audio.h" 13#include "ui_configure_audio.h"
14#include "yuzu/configuration/configuration_shared.h" 14#include "yuzu/configuration/configuration_shared.h"
15#include "yuzu/configuration/configure_audio.h" 15#include "yuzu/configuration/configure_audio.h"
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index d055cbd60..4f99bc80f 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -7,8 +7,8 @@
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/settings.h"
10#include "core/core.h" 11#include "core/core.h"
11#include "core/settings.h"
12#include "ui_configure_cpu.h" 12#include "ui_configure_cpu.h"
13#include "yuzu/configuration/configure_cpu.h" 13#include "yuzu/configuration/configure_cpu.h"
14 14
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index 3c5683d81..ef77b2e7e 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -6,7 +6,7 @@
6 6
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9#include "core/settings.h" 9#include "common/settings.h"
10 10
11namespace Ui { 11namespace Ui {
12class ConfigureCpu; 12class ConfigureCpu;
diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp
index 3385b2cf6..c925c023c 100644
--- a/src/yuzu/configuration/configure_cpu_debug.cpp
+++ b/src/yuzu/configuration/configure_cpu_debug.cpp
@@ -6,8 +6,8 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/settings.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/settings.h"
11#include "ui_configure_cpu_debug.h" 11#include "ui_configure_cpu_debug.h"
12#include "yuzu/configuration/configure_cpu_debug.h" 12#include "yuzu/configuration/configure_cpu_debug.h"
13 13
diff --git a/src/yuzu/configuration/configure_cpu_debug.h b/src/yuzu/configuration/configure_cpu_debug.h
index c9941ef3b..10de55099 100644
--- a/src/yuzu/configuration/configure_cpu_debug.h
+++ b/src/yuzu/configuration/configure_cpu_debug.h
@@ -6,7 +6,7 @@
6 6
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9#include "core/settings.h" 9#include "common/settings.h"
10 10
11namespace Ui { 11namespace Ui {
12class ConfigureCpuDebug; 12class ConfigureCpuDebug;
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 121873f95..6730eb356 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -7,8 +7,8 @@
7#include "common/file_util.h" 7#include "common/file_util.h"
8#include "common/logging/backend.h" 8#include "common/logging/backend.h"
9#include "common/logging/filter.h" 9#include "common/logging/filter.h"
10#include "common/settings.h"
10#include "core/core.h" 11#include "core/core.h"
11#include "core/settings.h"
12#include "ui_configure_debug.h" 12#include "ui_configure_debug.h"
13#include "yuzu/configuration/configure_debug.h" 13#include "yuzu/configuration/configure_debug.h"
14#include "yuzu/debugger/console.h" 14#include "yuzu/debugger/console.h"
@@ -34,6 +34,8 @@ void ConfigureDebug::SetConfiguration() {
34 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); 34 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
35 ui->reporting_services->setChecked(Settings::values.reporting_services); 35 ui->reporting_services->setChecked(Settings::values.reporting_services);
36 ui->quest_flag->setChecked(Settings::values.quest_flag); 36 ui->quest_flag->setChecked(Settings::values.quest_flag);
37 ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts);
38 ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
37 ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 39 ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
38 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); 40 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
39 ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 41 ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
@@ -47,13 +49,15 @@ void ConfigureDebug::ApplyConfiguration() {
47 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); 49 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
48 Settings::values.reporting_services = ui->reporting_services->isChecked(); 50 Settings::values.reporting_services = ui->reporting_services->isChecked();
49 Settings::values.quest_flag = ui->quest_flag->isChecked(); 51 Settings::values.quest_flag = ui->quest_flag->isChecked();
52 Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
53 Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
50 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); 54 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
51 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); 55 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
52 Settings::values.extended_logging = ui->extended_logging->isChecked(); 56 Settings::values.extended_logging = ui->extended_logging->isChecked();
53 Debugger::ToggleConsole(); 57 Debugger::ToggleConsole();
54 Log::Filter filter; 58 Common::Log::Filter filter;
55 filter.ParseFilterString(Settings::values.log_filter); 59 filter.ParseFilterString(Settings::values.log_filter);
56 Log::SetGlobalFilter(filter); 60 Common::Log::SetGlobalFilter(filter);
57} 61}
58 62
59void ConfigureDebug::changeEvent(QEvent* event) { 63void ConfigureDebug::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 9186aa732..d812858b6 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -185,6 +185,35 @@
185 </property> 185 </property>
186 </widget> 186 </widget>
187 </item> 187 </item>
188 <item>
189 <widget class="QCheckBox" name="use_debug_asserts">
190 <property name="text">
191 <string>Enable Debug Asserts</string>
192 </property>
193 </widget>
194 </item>
195 <item>
196 <widget class="QCheckBox" name="use_auto_stub">
197 <property name="text">
198 <string>Enable Auto-Stub</string>
199 </property>
200 </widget>
201 </item>
202 <item>
203 <widget class="QLabel" name="label_3">
204 <property name="font">
205 <font>
206 <italic>true</italic>
207 </font>
208 </property>
209 <property name="text">
210 <string>This will be reset automatically when yuzu closes.</string>
211 </property>
212 <property name="indent">
213 <number>20</number>
214 </property>
215 </widget>
216 </item>
188 </layout> 217 </layout>
189 </widget> 218 </widget>
190 </item> 219 </item>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index d6b17a28d..3ad40d2b3 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -5,8 +5,8 @@
5#include <QHash> 5#include <QHash>
6#include <QListWidgetItem> 6#include <QListWidgetItem>
7#include <QSignalBlocker> 7#include <QSignalBlocker>
8#include "common/settings.h"
8#include "core/core.h" 9#include "core/core.h"
9#include "core/settings.h"
10#include "ui_configure.h" 10#include "ui_configure.h"
11#include "yuzu/configuration/config.h" 11#include "yuzu/configuration/config.h"
12#include "yuzu/configuration/configure_dialog.h" 12#include "yuzu/configuration/configure_dialog.h"
@@ -55,7 +55,7 @@ void ConfigureDialog::ApplyConfiguration() {
55 ui->debugTab->ApplyConfiguration(); 55 ui->debugTab->ApplyConfiguration();
56 ui->webTab->ApplyConfiguration(); 56 ui->webTab->ApplyConfiguration();
57 ui->serviceTab->ApplyConfiguration(); 57 ui->serviceTab->ApplyConfiguration();
58 Settings::Apply(Core::System::GetInstance()); 58 Core::System::GetInstance().ApplySettings();
59 Settings::LogSettings(); 59 Settings::LogSettings();
60} 60}
61 61
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index 58f644af4..006eda4b0 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -6,7 +6,7 @@
6#include <QMessageBox> 6#include <QMessageBox>
7#include "common/common_paths.h" 7#include "common/common_paths.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "core/settings.h" 9#include "common/settings.h"
10#include "ui_configure_filesystem.h" 10#include "ui_configure_filesystem.h"
11#include "yuzu/configuration/configure_filesystem.h" 11#include "yuzu/configuration/configure_filesystem.h"
12#include "yuzu/uisettings.h" 12#include "yuzu/uisettings.h"
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index d4d29d422..2fa88dcec 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -4,8 +4,8 @@
4 4
5#include <QCheckBox> 5#include <QCheckBox>
6#include <QSpinBox> 6#include <QSpinBox>
7#include "common/settings.h"
7#include "core/core.h" 8#include "core/core.h"
8#include "core/settings.h"
9#include "ui_configure_general.h" 9#include "ui_configure_general.h"
10#include "yuzu/configuration/configuration_shared.h" 10#include "yuzu/configuration/configuration_shared.h"
11#include "yuzu/configuration/configure_general.h" 11#include "yuzu/configuration/configure_general.h"
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 9ff32aec4..0a7536617 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -11,8 +11,8 @@
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/settings.h"
14#include "core/core.h" 15#include "core/core.h"
15#include "core/settings.h"
16#include "ui_configure_graphics.h" 16#include "ui_configure_graphics.h"
17#include "video_core/vulkan_common/vulkan_instance.h" 17#include "video_core/vulkan_common/vulkan_instance.h"
18#include "video_core/vulkan_common/vulkan_library.h" 18#include "video_core/vulkan_common/vulkan_library.h"
@@ -77,18 +77,25 @@ void ConfigureGraphics::SetConfiguration() {
77 77
78 if (Settings::IsConfiguringGlobal()) { 78 if (Settings::IsConfiguringGlobal()) {
79 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); 79 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
80 ui->fullscreen_mode_combobox->setCurrentIndex(Settings::values.fullscreen_mode.GetValue());
80 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); 81 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
81 } else { 82 } else {
82 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); 83 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
83 ConfigurationShared::SetHighlight(ui->api_layout, 84 ConfigurationShared::SetHighlight(ui->api_layout,
84 !Settings::values.renderer_backend.UsingGlobal()); 85 !Settings::values.renderer_backend.UsingGlobal());
86
87 ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox,
88 &Settings::values.fullscreen_mode);
89 ConfigurationShared::SetHighlight(ui->fullscreen_mode_label,
90 !Settings::values.fullscreen_mode.UsingGlobal());
91
85 ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox, 92 ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
86 &Settings::values.aspect_ratio); 93 &Settings::values.aspect_ratio);
94 ConfigurationShared::SetHighlight(ui->ar_label,
95 !Settings::values.aspect_ratio.UsingGlobal());
87 96
88 ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1); 97 ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
89 ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal()); 98 ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
90 ConfigurationShared::SetHighlight(ui->ar_label,
91 !Settings::values.aspect_ratio.UsingGlobal());
92 ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal()); 99 ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
93 } 100 }
94 101
@@ -107,6 +114,9 @@ void ConfigureGraphics::ApplyConfiguration() {
107 if (Settings::values.vulkan_device.UsingGlobal()) { 114 if (Settings::values.vulkan_device.UsingGlobal()) {
108 Settings::values.vulkan_device.SetValue(vulkan_device); 115 Settings::values.vulkan_device.SetValue(vulkan_device);
109 } 116 }
117 if (Settings::values.fullscreen_mode.UsingGlobal()) {
118 Settings::values.fullscreen_mode.SetValue(ui->fullscreen_mode_combobox->currentIndex());
119 }
110 if (Settings::values.aspect_ratio.UsingGlobal()) { 120 if (Settings::values.aspect_ratio.UsingGlobal()) {
111 Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex()); 121 Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
112 } 122 }
@@ -140,6 +150,8 @@ void ConfigureGraphics::ApplyConfiguration() {
140 } 150 }
141 } 151 }
142 152
153 ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
154 ui->fullscreen_mode_combobox);
143 ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio, 155 ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
144 ui->aspect_ratio_combobox); 156 ui->aspect_ratio_combobox);
145 157
@@ -227,7 +239,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
227 vulkan_devices.clear(); 239 vulkan_devices.clear();
228 vulkan_devices.reserve(physical_devices.size()); 240 vulkan_devices.reserve(physical_devices.size());
229 for (const VkPhysicalDevice device : physical_devices) { 241 for (const VkPhysicalDevice device : physical_devices) {
230 const char* const name = vk::PhysicalDevice(device, dld).GetProperties().deviceName; 242 const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
231 vulkan_devices.push_back(QString::fromStdString(name)); 243 vulkan_devices.push_back(QString::fromStdString(name));
232 } 244 }
233 245
@@ -253,6 +265,7 @@ void ConfigureGraphics::SetupPerGameUI() {
253 if (Settings::IsConfiguringGlobal()) { 265 if (Settings::IsConfiguringGlobal()) {
254 ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal()); 266 ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
255 ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal()); 267 ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
268 ui->fullscreen_mode_combobox->setEnabled(Settings::values.fullscreen_mode.UsingGlobal());
256 ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal()); 269 ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
257 ui->use_asynchronous_gpu_emulation->setEnabled( 270 ui->use_asynchronous_gpu_emulation->setEnabled(
258 Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()); 271 Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
@@ -278,6 +291,8 @@ void ConfigureGraphics::SetupPerGameUI() {
278 291
279 ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label, 292 ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
280 Settings::values.aspect_ratio.GetValue(true)); 293 Settings::values.aspect_ratio.GetValue(true));
294 ConfigurationShared::SetColoredComboBox(ui->fullscreen_mode_combobox, ui->fullscreen_mode_label,
295 Settings::values.fullscreen_mode.GetValue(true));
281 ConfigurationShared::InsertGlobalItem( 296 ConfigurationShared::InsertGlobalItem(
282 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); 297 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
283} 298}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 1fefc88eb..c162048a2 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -8,7 +8,7 @@
8#include <vector> 8#include <vector>
9#include <QString> 9#include <QString>
10#include <QWidget> 10#include <QWidget>
11#include "core/settings.h" 11#include "common/settings.h"
12 12
13namespace ConfigurationShared { 13namespace ConfigurationShared {
14enum class CheckState; 14enum class CheckState;
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 58486eb1e..ab0bd4d77 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -105,8 +105,47 @@
105 </widget> 105 </widget>
106 </item> 106 </item>
107 <item> 107 <item>
108 <widget class="QWidget" name="fullscreen_mode_layout" native="true">
109 <layout class="QHBoxLayout" name="horizontalLayout_1">
110 <property name="leftMargin">
111 <number>0</number>
112 </property>
113 <property name="topMargin">
114 <number>0</number>
115 </property>
116 <property name="rightMargin">
117 <number>0</number>
118 </property>
119 <property name="bottomMargin">
120 <number>0</number>
121 </property>
122 <item>
123 <widget class="QLabel" name="fullscreen_mode_label">
124 <property name="text">
125 <string>Fullscreen Mode:</string>
126 </property>
127 </widget>
128 </item>
129 <item>
130 <widget class="QComboBox" name="fullscreen_mode_combobox">
131 <item>
132 <property name="text">
133 <string>Borderless Windowed</string>
134 </property>
135 </item>
136 <item>
137 <property name="text">
138 <string>Exclusive Fullscreen</string>
139 </property>
140 </item>
141 </widget>
142 </item>
143 </layout>
144 </widget>
145 </item>
146 <item>
108 <widget class="QWidget" name="aspect_ratio_layout" native="true"> 147 <widget class="QWidget" name="aspect_ratio_layout" native="true">
109 <layout class="QHBoxLayout" name="horizontalLayout_6"> 148 <layout class="QHBoxLayout" name="horizontalLayout_2">
110 <property name="leftMargin"> 149 <property name="leftMargin">
111 <number>0</number> 150 <number>0</number>
112 </property> 151 </property>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 383c7bac8..c67609b0e 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -2,8 +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#include "common/settings.h"
5#include "core/core.h" 6#include "core/core.h"
6#include "core/settings.h"
7#include "ui_configure_graphics_advanced.h" 7#include "ui_configure_graphics_advanced.h"
8#include "yuzu/configuration/configuration_shared.h" 8#include "yuzu/configuration/configuration_shared.h"
9#include "yuzu/configuration/configure_graphics_advanced.h" 9#include "yuzu/configuration/configure_graphics_advanced.h"
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp
index cbee51a5e..ed76fe18e 100644
--- a/src/yuzu/configuration/configure_hotkeys.cpp
+++ b/src/yuzu/configuration/configure_hotkeys.cpp
@@ -5,7 +5,7 @@
5#include <QMenu> 5#include <QMenu>
6#include <QMessageBox> 6#include <QMessageBox>
7#include <QStandardItemModel> 7#include <QStandardItemModel>
8#include "core/settings.h" 8#include "common/settings.h"
9#include "ui_configure_hotkeys.h" 9#include "ui_configure_hotkeys.h"
10#include "yuzu/configuration/config.h" 10#include "yuzu/configuration/config.h"
11#include "yuzu/configuration/configure_hotkeys.h" 11#include "yuzu/configuration/configure_hotkeys.h"
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index a1a0eb676..d8d3b83dc 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -3,8 +3,8 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QColorDialog> 5#include <QColorDialog>
6#include "common/settings.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/settings.h"
8#include "ui_configure_input_advanced.h" 8#include "ui_configure_input_advanced.h"
9#include "yuzu/configuration/configure_input_advanced.h" 9#include "yuzu/configuration/configure_input_advanced.h"
10 10
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index efe953fbc..c7d101682 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -14,7 +14,7 @@
14#include <QWidget> 14#include <QWidget>
15 15
16#include "common/param_package.h" 16#include "common/param_package.h"
17#include "core/settings.h" 17#include "common/settings.h"
18#include "ui_configure_input.h" 18#include "ui_configure_input.h"
19 19
20class QCheckBox; 20class QCheckBox;
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index 91c3343f1..51bb84eb6 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -7,8 +7,8 @@
7#include <array> 7#include <array>
8#include <QFrame> 8#include <QFrame>
9#include <QPointer> 9#include <QPointer>
10#include "common/settings.h"
10#include "core/frontend/input.h" 11#include "core/frontend/input.h"
11#include "core/settings.h"
12 12
13class QLabel; 13class QLabel;
14 14
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index 52fdf7265..6a5d625df 100644
--- a/src/yuzu/configuration/configure_motion_touch.cpp
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -14,7 +14,7 @@
14#include <QVBoxLayout> 14#include <QVBoxLayout>
15 15
16#include "common/logging/log.h" 16#include "common/logging/log.h"
17#include "core/settings.h" 17#include "common/settings.h"
18#include "input_common/main.h" 18#include "input_common/main.h"
19#include "input_common/udp/client.h" 19#include "input_common/udp/client.h"
20#include "input_common/udp/udp.h" 20#include "input_common/udp/udp.h"
@@ -23,8 +23,7 @@
23#include "yuzu/configuration/configure_touch_from_button.h" 23#include "yuzu/configuration/configure_touch_from_button.h"
24 24
25CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, 25CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
26 const std::string& host, u16 port, 26 const std::string& host, u16 port)
27 u8 pad_index)
28 : QDialog(parent) { 27 : QDialog(parent) {
29 layout = new QVBoxLayout; 28 layout = new QVBoxLayout;
30 status_label = new QLabel(tr("Communicating with the server...")); 29 status_label = new QLabel(tr("Communicating with the server..."));
@@ -41,7 +40,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
41 40
42 using namespace InputCommon::CemuhookUDP; 41 using namespace InputCommon::CemuhookUDP;
43 job = std::make_unique<CalibrationConfigurationJob>( 42 job = std::make_unique<CalibrationConfigurationJob>(
44 host, port, pad_index, 43 host, port,
45 [this](CalibrationConfigurationJob::Status status) { 44 [this](CalibrationConfigurationJob::Status status) {
46 QString text; 45 QString text;
47 switch (status) { 46 switch (status) {
@@ -217,7 +216,7 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
217 ui->udp_test->setText(tr("Testing")); 216 ui->udp_test->setText(tr("Testing"));
218 udp_test_in_progress = true; 217 udp_test_in_progress = true;
219 InputCommon::CemuhookUDP::TestCommunication( 218 InputCommon::CemuhookUDP::TestCommunication(
220 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0, 219 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()),
221 [this] { 220 [this] {
222 LOG_INFO(Frontend, "UDP input test success"); 221 LOG_INFO(Frontend, "UDP input test success");
223 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); 222 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
@@ -232,7 +231,7 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() {
232 ui->touch_calibration_config->setEnabled(false); 231 ui->touch_calibration_config->setEnabled(false);
233 ui->touch_calibration_config->setText(tr("Configuring")); 232 ui->touch_calibration_config->setText(tr("Configuring"));
234 CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(), 233 CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(),
235 static_cast<u16>(ui->udp_port->text().toUInt()), 0); 234 static_cast<u16>(ui->udp_port->text().toUInt()));
236 dialog.exec(); 235 dialog.exec();
237 if (dialog.completed) { 236 if (dialog.completed) {
238 min_x = dialog.min_x; 237 min_x = dialog.min_x;
diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h
index d76bc8154..8b707d2ff 100644
--- a/src/yuzu/configuration/configure_motion_touch.h
+++ b/src/yuzu/configuration/configure_motion_touch.h
@@ -29,8 +29,7 @@ class ConfigureMotionTouch;
29class CalibrationConfigurationDialog : public QDialog { 29class CalibrationConfigurationDialog : public QDialog {
30 Q_OBJECT 30 Q_OBJECT
31public: 31public:
32 explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, 32 explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port);
33 u8 pad_index);
34 ~CalibrationConfigurationDialog() override; 33 ~CalibrationConfigurationDialog() override;
35 34
36private: 35private:
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index f598513df..bd91ebc42 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -57,7 +57,7 @@ void ConfigurePerGame::ApplyConfiguration() {
57 ui->graphicsAdvancedTab->ApplyConfiguration(); 57 ui->graphicsAdvancedTab->ApplyConfiguration();
58 ui->audioTab->ApplyConfiguration(); 58 ui->audioTab->ApplyConfiguration();
59 59
60 Settings::Apply(Core::System::GetInstance()); 60 Core::System::GetInstance().ApplySettings();
61 Settings::LogSettings(); 61 Settings::LogSettings();
62 62
63 game_config->Save(); 63 game_config->Save();
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index 51647a028..d61b5e29b 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -13,10 +13,10 @@
13#include <QVBoxLayout> 13#include <QVBoxLayout>
14#include "common/assert.h" 14#include "common/assert.h"
15#include "common/file_util.h" 15#include "common/file_util.h"
16#include "common/settings.h"
16#include "common/string_util.h" 17#include "common/string_util.h"
17#include "core/core.h" 18#include "core/core.h"
18#include "core/hle/service/acc/profile_manager.h" 19#include "core/hle/service/acc/profile_manager.h"
19#include "core/settings.h"
20#include "ui_configure_profile_manager.h" 20#include "ui_configure_profile_manager.h"
21#include "yuzu/configuration/configure_profile_manager.h" 21#include "yuzu/configuration/configure_profile_manager.h"
22#include "yuzu/util/limitable_input_dialog.h" 22#include "yuzu/util/limitable_input_dialog.h"
@@ -180,7 +180,7 @@ void ConfigureProfileManager::ApplyConfiguration() {
180 return; 180 return;
181 } 181 }
182 182
183 Settings::Apply(Core::System::GetInstance()); 183 Core::System::GetInstance().ApplySettings();
184} 184}
185 185
186void ConfigureProfileManager::SelectUser(const QModelIndex& index) { 186void ConfigureProfileManager::SelectUser(const QModelIndex& index) {
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_service.cpp
index b580cfff2..6d954a67f 100644
--- a/src/yuzu/configuration/configure_service.cpp
+++ b/src/yuzu/configuration/configure_service.cpp
@@ -4,8 +4,8 @@
4 4
5#include <QGraphicsItem> 5#include <QGraphicsItem>
6#include <QtConcurrent/QtConcurrent> 6#include <QtConcurrent/QtConcurrent>
7#include "common/settings.h"
7#include "core/hle/service/bcat/backend/boxcat.h" 8#include "core/hle/service/bcat/backend/boxcat.h"
8#include "core/settings.h"
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
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 6cf2032da..268ed44c3 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -11,9 +11,9 @@
11#include <QMessageBox> 11#include <QMessageBox>
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/file_util.h" 13#include "common/file_util.h"
14#include "common/settings.h"
14#include "core/core.h" 15#include "core/core.h"
15#include "core/hle/service/time/time.h" 16#include "core/hle/service/time/time.h"
16#include "core/settings.h"
17#include "ui_configure_system.h" 17#include "ui_configure_system.h"
18#include "yuzu/configuration/configuration_shared.h" 18#include "yuzu/configuration/configuration_shared.h"
19#include "yuzu/configuration/configure_system.h" 19#include "yuzu/configuration/configure_system.h"
@@ -199,7 +199,7 @@ void ConfigureSystem::ApplyConfiguration() {
199 } 199 }
200 } 200 }
201 201
202 Settings::Apply(system); 202 system.ApplySettings();
203} 203}
204 204
205void ConfigureSystem::RefreshConsoleID() { 205void ConfigureSystem::RefreshConsoleID() {
diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp
index 15557e4b8..40129f228 100644
--- a/src/yuzu/configuration/configure_touch_from_button.cpp
+++ b/src/yuzu/configuration/configure_touch_from_button.cpp
@@ -10,8 +10,8 @@
10#include <QStandardItemModel> 10#include <QStandardItemModel>
11#include <QTimer> 11#include <QTimer>
12#include "common/param_package.h" 12#include "common/param_package.h"
13#include "common/settings.h"
13#include "core/frontend/framebuffer_layout.h" 14#include "core/frontend/framebuffer_layout.h"
14#include "core/settings.h"
15#include "input_common/main.h" 15#include "input_common/main.h"
16#include "ui_configure_touch_from_button.h" 16#include "ui_configure_touch_from_button.h"
17#include "yuzu/configuration/configure_touch_from_button.h" 17#include "yuzu/configuration/configure_touch_from_button.h"
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index aed876008..f35c89e04 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -9,8 +9,8 @@
9#include <QDirIterator> 9#include <QDirIterator>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/file_util.h" 11#include "common/file_util.h"
12#include "common/settings.h"
12#include "core/core.h" 13#include "core/core.h"
13#include "core/settings.h"
14#include "ui_configure_ui.h" 14#include "ui_configure_ui.h"
15#include "yuzu/configuration/configure_ui.h" 15#include "yuzu/configuration/configure_ui.h"
16#include "yuzu/uisettings.h" 16#include "yuzu/uisettings.h"
@@ -85,7 +85,7 @@ void ConfigureUi::ApplyConfiguration() {
85 UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked(); 85 UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked();
86 Common::FS::GetUserPath(Common::FS::UserPath::ScreenshotsDir, 86 Common::FS::GetUserPath(Common::FS::UserPath::ScreenshotsDir,
87 ui->screenshot_path_edit->text().toStdString()); 87 ui->screenshot_path_edit->text().toStdString());
88 Settings::Apply(Core::System::GetInstance()); 88 Core::System::GetInstance().ApplySettings();
89} 89}
90 90
91void ConfigureUi::RequestGameListUpdate() { 91void ConfigureUi::RequestGameListUpdate() {
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp
index 7dcb2c5b9..9d92c4949 100644
--- a/src/yuzu/configuration/configure_vibration.cpp
+++ b/src/yuzu/configuration/configure_vibration.cpp
@@ -8,7 +8,7 @@
8#include <fmt/format.h> 8#include <fmt/format.h>
9 9
10#include "common/param_package.h" 10#include "common/param_package.h"
11#include "core/settings.h" 11#include "common/settings.h"
12#include "ui_configure_vibration.h" 12#include "ui_configure_vibration.h"
13#include "yuzu/configuration/configure_vibration.h" 13#include "yuzu/configuration/configure_vibration.h"
14 14
diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp
index 8637f5b3c..f3f3b54d6 100644
--- a/src/yuzu/configuration/configure_web.cpp
+++ b/src/yuzu/configuration/configure_web.cpp
@@ -5,7 +5,7 @@
5#include <QIcon> 5#include <QIcon>
6#include <QMessageBox> 6#include <QMessageBox>
7#include <QtConcurrent/QtConcurrentRun> 7#include <QtConcurrent/QtConcurrentRun>
8#include "core/settings.h" 8#include "common/settings.h"
9#include "core/telemetry_session.h" 9#include "core/telemetry_session.h"
10#include "ui_configure_web.h" 10#include "ui_configure_web.h"
11#include "yuzu/configuration/configure_web.h" 11#include "yuzu/configuration/configure_web.h"
diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp
index 207ff4d58..c11a326ac 100644
--- a/src/yuzu/debugger/console.cpp
+++ b/src/yuzu/debugger/console.cpp
@@ -29,13 +29,13 @@ void ToggleConsole() {
29 freopen_s(&temp, "CONIN$", "r", stdin); 29 freopen_s(&temp, "CONIN$", "r", stdin);
30 freopen_s(&temp, "CONOUT$", "w", stdout); 30 freopen_s(&temp, "CONOUT$", "w", stdout);
31 freopen_s(&temp, "CONOUT$", "w", stderr); 31 freopen_s(&temp, "CONOUT$", "w", stderr);
32 Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); 32 Common::Log::AddBackend(std::make_unique<Common::Log::ColorConsoleBackend>());
33 } 33 }
34 } else { 34 } else {
35 if (FreeConsole()) { 35 if (FreeConsole()) {
36 // In order to close the console, we have to also detach the streams on it. 36 // In order to close the console, we have to also detach the streams on it.
37 // Just redirect them to NUL if there is no console window 37 // Just redirect them to NUL if there is no console window
38 Log::RemoveBackend(Log::ColorConsoleBackend::Name()); 38 Common::Log::RemoveBackend(Common::Log::ColorConsoleBackend::Name());
39 freopen_s(&temp, "NUL", "r", stdin); 39 freopen_s(&temp, "NUL", "r", stdin);
40 freopen_s(&temp, "NUL", "w", stdout); 40 freopen_s(&temp, "NUL", "w", stdout);
41 freopen_s(&temp, "NUL", "w", stderr); 41 freopen_s(&temp, "NUL", "w", stderr);
@@ -43,9 +43,9 @@ void ToggleConsole() {
43 } 43 }
44#else 44#else
45 if (UISettings::values.show_console) { 45 if (UISettings::values.show_console) {
46 Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); 46 Common::Log::AddBackend(std::make_unique<Common::Log::ColorConsoleBackend>());
47 } else { 47 } else {
48 Log::RemoveBackend(Log::ColorConsoleBackend::Name()); 48 Common::Log::RemoveBackend(Common::Log::ColorConsoleBackend::Name());
49 } 49 }
50#endif 50#endif
51} 51}
diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp
index 2731d948d..7186eac76 100644
--- a/src/yuzu/debugger/controller.cpp
+++ b/src/yuzu/debugger/controller.cpp
@@ -5,7 +5,7 @@
5#include <QAction> 5#include <QAction>
6#include <QLayout> 6#include <QLayout>
7#include <QString> 7#include <QString>
8#include "core/settings.h" 8#include "common/settings.h"
9#include "yuzu/configuration/configure_input_player_widget.h" 9#include "yuzu/configuration/configure_input_player_widget.h"
10#include "yuzu/debugger/controller.h" 10#include "yuzu/debugger/controller.h"
11 11
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 24bfa4d34..5f6cdc0c6 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -79,6 +79,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
79#ifdef ARCHITECTURE_x86_64 79#ifdef ARCHITECTURE_x86_64
80#include "common/x64/cpu_detect.h" 80#include "common/x64/cpu_detect.h"
81#endif 81#endif
82#include "common/settings.h"
82#include "common/telemetry.h" 83#include "common/telemetry.h"
83#include "core/core.h" 84#include "core/core.h"
84#include "core/crypto/key_manager.h" 85#include "core/crypto/key_manager.h"
@@ -98,9 +99,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
98#include "core/hle/service/sm/sm.h" 99#include "core/hle/service/sm/sm.h"
99#include "core/loader/loader.h" 100#include "core/loader/loader.h"
100#include "core/perf_stats.h" 101#include "core/perf_stats.h"
101#include "core/settings.h"
102#include "core/telemetry_session.h" 102#include "core/telemetry_session.h"
103#include "input_common/main.h" 103#include "input_common/main.h"
104#include "util/overlay_dialog.h"
104#include "video_core/gpu.h" 105#include "video_core/gpu.h"
105#include "video_core/shader_notify.h" 106#include "video_core/shader_notify.h"
106#include "yuzu/about_dialog.h" 107#include "yuzu/about_dialog.h"
@@ -164,19 +165,21 @@ void GMainWindow::ShowTelemetryCallout() {
164 "<br/><br/>Would you like to share your usage data with us?"); 165 "<br/><br/>Would you like to share your usage data with us?");
165 if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) { 166 if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) {
166 Settings::values.enable_telemetry = false; 167 Settings::values.enable_telemetry = false;
167 Settings::Apply(Core::System::GetInstance()); 168 Core::System::GetInstance().ApplySettings();
168 } 169 }
169} 170}
170 171
171const int GMainWindow::max_recent_files_item; 172const int GMainWindow::max_recent_files_item;
172 173
173static void InitializeLogging() { 174static void InitializeLogging() {
175 using namespace Common;
176
174 Log::Filter log_filter; 177 Log::Filter log_filter;
175 log_filter.ParseFilterString(Settings::values.log_filter); 178 log_filter.ParseFilterString(Settings::values.log_filter);
176 Log::SetGlobalFilter(log_filter); 179 Log::SetGlobalFilter(log_filter);
177 180
178 const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir); 181 const std::string& log_dir = FS::GetUserPath(FS::UserPath::LogDir);
179 Common::FS::CreateFullPath(log_dir); 182 FS::CreateFullPath(log_dir);
180 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE)); 183 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
181#ifdef _WIN32 184#ifdef _WIN32
182 Log::AddBackend(std::make_unique<Log::DebuggerBackend>()); 185 Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
@@ -225,6 +228,8 @@ GMainWindow::GMainWindow()
225 SetDiscordEnabled(UISettings::values.enable_discord_presence); 228 SetDiscordEnabled(UISettings::values.enable_discord_presence);
226 discord_rpc->Update(); 229 discord_rpc->Update();
227 230
231 RegisterMetaTypes();
232
228 InitializeWidgets(); 233 InitializeWidgets();
229 InitializeDebugWidgets(); 234 InitializeDebugWidgets();
230 InitializeRecentFileMenuActions(); 235 InitializeRecentFileMenuActions();
@@ -320,6 +325,34 @@ GMainWindow::GMainWindow()
320 continue; 325 continue;
321 } 326 }
322 327
328 // Launch game with a specific user
329 if (args[i] == QStringLiteral("-u")) {
330 if (i >= args.size() - 1) {
331 continue;
332 }
333
334 if (args[i + 1].startsWith(QChar::fromLatin1('-'))) {
335 continue;
336 }
337
338 bool argument_ok;
339 const std::size_t selected_user = args[++i].toUInt(&argument_ok);
340
341 if (!argument_ok) {
342 LOG_ERROR(Frontend, "Invalid user argument");
343 continue;
344 }
345
346 const Service::Account::ProfileManager manager;
347 if (!manager.UserExistsIndex(selected_user)) {
348 LOG_ERROR(Frontend, "Selected user doesn't exist");
349 continue;
350 }
351
352 Settings::values.current_user = selected_user;
353 continue;
354 }
355
323 // Launch game at path 356 // Launch game at path
324 if (args[i] == QStringLiteral("-g")) { 357 if (args[i] == QStringLiteral("-g")) {
325 if (i >= args.size() - 1) { 358 if (i >= args.size() - 1) {
@@ -345,6 +378,55 @@ GMainWindow::~GMainWindow() {
345 delete render_window; 378 delete render_window;
346} 379}
347 380
381void GMainWindow::RegisterMetaTypes() {
382 // Register integral and floating point types
383 qRegisterMetaType<u8>("u8");
384 qRegisterMetaType<u16>("u16");
385 qRegisterMetaType<u32>("u32");
386 qRegisterMetaType<u64>("u64");
387 qRegisterMetaType<u128>("u128");
388 qRegisterMetaType<s8>("s8");
389 qRegisterMetaType<s16>("s16");
390 qRegisterMetaType<s32>("s32");
391 qRegisterMetaType<s64>("s64");
392 qRegisterMetaType<f32>("f32");
393 qRegisterMetaType<f64>("f64");
394
395 // Register string types
396 qRegisterMetaType<std::string>("std::string");
397 qRegisterMetaType<std::wstring>("std::wstring");
398 qRegisterMetaType<std::u8string>("std::u8string");
399 qRegisterMetaType<std::u16string>("std::u16string");
400 qRegisterMetaType<std::u32string>("std::u32string");
401 qRegisterMetaType<std::string_view>("std::string_view");
402 qRegisterMetaType<std::wstring_view>("std::wstring_view");
403 qRegisterMetaType<std::u8string_view>("std::u8string_view");
404 qRegisterMetaType<std::u16string_view>("std::u16string_view");
405 qRegisterMetaType<std::u32string_view>("std::u32string_view");
406
407 // Register applet types
408
409 // Controller Applet
410 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
411
412 // Software Keyboard Applet
413 qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>(
414 "Core::Frontend::KeyboardInitializeParameters");
415 qRegisterMetaType<Core::Frontend::InlineAppearParameters>(
416 "Core::Frontend::InlineAppearParameters");
417 qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters");
418 qRegisterMetaType<Service::AM::Applets::SwkbdResult>("Service::AM::Applets::SwkbdResult");
419 qRegisterMetaType<Service::AM::Applets::SwkbdTextCheckResult>(
420 "Service::AM::Applets::SwkbdTextCheckResult");
421 qRegisterMetaType<Service::AM::Applets::SwkbdReplyType>("Service::AM::Applets::SwkbdReplyType");
422
423 // Web Browser Applet
424 qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
425
426 // Register loader types
427 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
428}
429
348void GMainWindow::ControllerSelectorReconfigureControllers( 430void GMainWindow::ControllerSelectorReconfigureControllers(
349 const Core::Frontend::ControllerParameters& parameters) { 431 const Core::Frontend::ControllerParameters& parameters) {
350 QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get()); 432 QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
@@ -357,7 +439,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
357 emit ControllerSelectorReconfigureFinished(); 439 emit ControllerSelectorReconfigureFinished();
358 440
359 // Don't forget to apply settings. 441 // Don't forget to apply settings.
360 Settings::Apply(Core::System::GetInstance()); 442 Core::System::GetInstance().ApplySettings();
361 config->Save(); 443 config->Save();
362 444
363 UpdateStatusButtons(); 445 UpdateStatusButtons();
@@ -384,25 +466,112 @@ void GMainWindow::ProfileSelectorSelectProfile() {
384 emit ProfileSelectorFinishedSelection(uuid); 466 emit ProfileSelectorFinishedSelection(uuid);
385} 467}
386 468
387void GMainWindow::SoftwareKeyboardGetText( 469void GMainWindow::SoftwareKeyboardInitialize(
388 const Core::Frontend::SoftwareKeyboardParameters& parameters) { 470 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) {
389 QtSoftwareKeyboardDialog dialog(this, parameters); 471 if (software_keyboard) {
390 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | 472 LOG_ERROR(Frontend, "The software keyboard is already initialized!");
391 Qt::WindowTitleHint | Qt::WindowSystemMenuHint | 473 return;
392 Qt::WindowCloseButtonHint); 474 }
393 dialog.setWindowModality(Qt::WindowModal);
394 475
395 if (dialog.exec() == QDialog::Rejected) { 476 software_keyboard = new QtSoftwareKeyboardDialog(render_window, Core::System::GetInstance(),
396 emit SoftwareKeyboardFinishedText(std::nullopt); 477 is_inline, std::move(initialize_parameters));
478
479 if (is_inline) {
480 connect(
481 software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this,
482 [this](Service::AM::Applets::SwkbdReplyType reply_type, std::u16string submitted_text,
483 s32 cursor_position) {
484 emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position);
485 },
486 Qt::QueuedConnection);
487 } else {
488 connect(
489 software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this,
490 [this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text) {
491 emit SoftwareKeyboardSubmitNormalText(result, submitted_text);
492 },
493 Qt::QueuedConnection);
494 }
495}
496
497void GMainWindow::SoftwareKeyboardShowNormal() {
498 if (!software_keyboard) {
499 LOG_ERROR(Frontend, "The software keyboard is not initialized!");
500 return;
501 }
502
503 const auto& layout = render_window->GetFramebufferLayout();
504
505 const auto x = layout.screen.left;
506 const auto y = layout.screen.top;
507 const auto w = layout.screen.GetWidth();
508 const auto h = layout.screen.GetHeight();
509
510 software_keyboard->ShowNormalKeyboard(render_window->mapToGlobal(QPoint(x, y)), QSize(w, h));
511}
512
513void GMainWindow::SoftwareKeyboardShowTextCheck(
514 Service::AM::Applets::SwkbdTextCheckResult text_check_result,
515 std::u16string text_check_message) {
516 if (!software_keyboard) {
517 LOG_ERROR(Frontend, "The software keyboard is not initialized!");
397 return; 518 return;
398 } 519 }
399 520
400 emit SoftwareKeyboardFinishedText(dialog.GetText()); 521 software_keyboard->ShowTextCheckDialog(text_check_result, text_check_message);
401} 522}
402 523
403void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) { 524void GMainWindow::SoftwareKeyboardShowInline(
404 QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message)); 525 Core::Frontend::InlineAppearParameters appear_parameters) {
405 emit SoftwareKeyboardFinishedCheckDialog(); 526 if (!software_keyboard) {
527 LOG_ERROR(Frontend, "The software keyboard is not initialized!");
528 return;
529 }
530
531 const auto& layout = render_window->GetFramebufferLayout();
532
533 const auto x =
534 static_cast<int>(layout.screen.left + (0.5f * layout.screen.GetWidth() *
535 ((2.0f * appear_parameters.key_top_translate_x) +
536 (1.0f - appear_parameters.key_top_scale_x))));
537 const auto y =
538 static_cast<int>(layout.screen.top + (layout.screen.GetHeight() *
539 ((2.0f * appear_parameters.key_top_translate_y) +
540 (1.0f - appear_parameters.key_top_scale_y))));
541 const auto w = static_cast<int>(layout.screen.GetWidth() * appear_parameters.key_top_scale_x);
542 const auto h = static_cast<int>(layout.screen.GetHeight() * appear_parameters.key_top_scale_y);
543
544 software_keyboard->ShowInlineKeyboard(std::move(appear_parameters),
545 render_window->mapToGlobal(QPoint(x, y)), QSize(w, h));
546}
547
548void GMainWindow::SoftwareKeyboardHideInline() {
549 if (!software_keyboard) {
550 LOG_ERROR(Frontend, "The software keyboard is not initialized!");
551 return;
552 }
553
554 software_keyboard->HideInlineKeyboard();
555}
556
557void GMainWindow::SoftwareKeyboardInlineTextChanged(
558 Core::Frontend::InlineTextParameters text_parameters) {
559 if (!software_keyboard) {
560 LOG_ERROR(Frontend, "The software keyboard is not initialized!");
561 return;
562 }
563
564 software_keyboard->InlineTextChanged(std::move(text_parameters));
565}
566
567void GMainWindow::SoftwareKeyboardExit() {
568 if (!software_keyboard) {
569 return;
570 }
571
572 software_keyboard->ExitKeyboard();
573
574 software_keyboard = nullptr;
406} 575}
407 576
408void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, 577void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
@@ -622,7 +791,7 @@ void GMainWindow::InitializeWidgets() {
622 Settings::values.use_asynchronous_gpu_emulation.SetValue( 791 Settings::values.use_asynchronous_gpu_emulation.SetValue(
623 !Settings::values.use_asynchronous_gpu_emulation.GetValue()); 792 !Settings::values.use_asynchronous_gpu_emulation.GetValue());
624 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); 793 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
625 Settings::Apply(Core::System::GetInstance()); 794 Core::System::GetInstance().ApplySettings();
626 }); 795 });
627 async_status_button->setText(tr("ASYNC")); 796 async_status_button->setText(tr("ASYNC"));
628 async_status_button->setCheckable(true); 797 async_status_button->setCheckable(true);
@@ -638,7 +807,7 @@ void GMainWindow::InitializeWidgets() {
638 } 807 }
639 Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue()); 808 Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue());
640 multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue()); 809 multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
641 Settings::Apply(Core::System::GetInstance()); 810 Core::System::GetInstance().ApplySettings();
642 }); 811 });
643 multicore_status_button->setText(tr("MULTICORE")); 812 multicore_status_button->setText(tr("MULTICORE"));
644 multicore_status_button->setCheckable(true); 813 multicore_status_button->setCheckable(true);
@@ -669,7 +838,7 @@ void GMainWindow::InitializeWidgets() {
669 Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL); 838 Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL);
670 } 839 }
671 840
672 Settings::Apply(Core::System::GetInstance()); 841 Core::System::GetInstance().ApplySettings();
673 }); 842 });
674 statusBar()->insertPermanentWidget(0, renderer_status_button); 843 statusBar()->insertPermanentWidget(0, renderer_status_button);
675 844
@@ -948,6 +1117,10 @@ void GMainWindow::ConnectWidgetEvents() {
948 connect(this, &GMainWindow::EmulationStopping, render_window, 1117 connect(this, &GMainWindow::EmulationStopping, render_window,
949 &GRenderWindow::OnEmulationStopping); 1118 &GRenderWindow::OnEmulationStopping);
950 1119
1120 // Software Keyboard Applet
1121 connect(this, &GMainWindow::EmulationStarting, this, &GMainWindow::SoftwareKeyboardExit);
1122 connect(this, &GMainWindow::EmulationStopping, this, &GMainWindow::SoftwareKeyboardExit);
1123
951 connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar); 1124 connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
952} 1125}
953 1126
@@ -2157,15 +2330,6 @@ void GMainWindow::OnStartGame() {
2157 2330
2158 emu_thread->SetRunning(true); 2331 emu_thread->SetRunning(true);
2159 2332
2160 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
2161 qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
2162 "Core::Frontend::SoftwareKeyboardParameters");
2163 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
2164 qRegisterMetaType<std::string>("std::string");
2165 qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
2166 qRegisterMetaType<std::string_view>("std::string_view");
2167 qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
2168
2169 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); 2333 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
2170 2334
2171 ui.action_Start->setEnabled(false); 2335 ui.action_Start->setEnabled(false);
@@ -2214,8 +2378,11 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) {
2214 BootGame(last_filename_booted, program_index); 2378 BootGame(last_filename_booted, program_index);
2215} 2379}
2216 2380
2217void GMainWindow::ErrorDisplayDisplayError(QString body) { 2381void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
2218 QMessageBox::critical(this, tr("Error Display"), body); 2382 OverlayDialog dialog(render_window, Core::System::GetInstance(), error_code, error_text,
2383 QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter);
2384 dialog.exec();
2385
2219 emit ErrorDisplayFinished(); 2386 emit ErrorDisplayFinished();
2220} 2387}
2221 2388
@@ -2267,24 +2434,66 @@ void GMainWindow::ToggleFullscreen() {
2267void GMainWindow::ShowFullscreen() { 2434void GMainWindow::ShowFullscreen() {
2268 if (ui.action_Single_Window_Mode->isChecked()) { 2435 if (ui.action_Single_Window_Mode->isChecked()) {
2269 UISettings::values.geometry = saveGeometry(); 2436 UISettings::values.geometry = saveGeometry();
2437
2270 ui.menubar->hide(); 2438 ui.menubar->hide();
2271 statusBar()->hide(); 2439 statusBar()->hide();
2272 showFullScreen(); 2440
2441 if (Settings::values.fullscreen_mode.GetValue() == 1) {
2442 showFullScreen();
2443 return;
2444 }
2445
2446 hide();
2447 setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
2448 const auto screen_geometry = QApplication::desktop()->screenGeometry(this);
2449 setGeometry(screen_geometry.x(), screen_geometry.y(), screen_geometry.width(),
2450 screen_geometry.height() + 1);
2451 raise();
2452 showNormal();
2273 } else { 2453 } else {
2274 UISettings::values.renderwindow_geometry = render_window->saveGeometry(); 2454 UISettings::values.renderwindow_geometry = render_window->saveGeometry();
2275 render_window->showFullScreen(); 2455
2456 if (Settings::values.fullscreen_mode.GetValue() == 1) {
2457 render_window->showFullScreen();
2458 return;
2459 }
2460
2461 render_window->hide();
2462 render_window->setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
2463 const auto screen_geometry = QApplication::desktop()->screenGeometry(this);
2464 render_window->setGeometry(screen_geometry.x(), screen_geometry.y(),
2465 screen_geometry.width(), screen_geometry.height() + 1);
2466 render_window->raise();
2467 render_window->showNormal();
2276 } 2468 }
2277} 2469}
2278 2470
2279void GMainWindow::HideFullscreen() { 2471void GMainWindow::HideFullscreen() {
2280 if (ui.action_Single_Window_Mode->isChecked()) { 2472 if (ui.action_Single_Window_Mode->isChecked()) {
2473 if (Settings::values.fullscreen_mode.GetValue() == 1) {
2474 showNormal();
2475 restoreGeometry(UISettings::values.geometry);
2476 } else {
2477 hide();
2478 setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
2479 restoreGeometry(UISettings::values.geometry);
2480 raise();
2481 show();
2482 }
2483
2281 statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); 2484 statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
2282 ui.menubar->show(); 2485 ui.menubar->show();
2283 showNormal();
2284 restoreGeometry(UISettings::values.geometry);
2285 } else { 2486 } else {
2286 render_window->showNormal(); 2487 if (Settings::values.fullscreen_mode.GetValue() == 1) {
2287 render_window->restoreGeometry(UISettings::values.renderwindow_geometry); 2488 render_window->showNormal();
2489 render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
2490 } else {
2491 render_window->hide();
2492 render_window->setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
2493 render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
2494 render_window->raise();
2495 render_window->show();
2496 }
2288 } 2497 }
2289} 2498}
2290 2499
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 04d37d4ae..7f1e50a5b 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -37,9 +37,13 @@ enum class GameListRemoveTarget;
37enum class InstalledEntryType; 37enum class InstalledEntryType;
38class GameListPlaceholder; 38class GameListPlaceholder;
39 39
40class QtSoftwareKeyboardDialog;
41
40namespace Core::Frontend { 42namespace Core::Frontend {
41struct ControllerParameters; 43struct ControllerParameters;
42struct SoftwareKeyboardParameters; 44struct InlineAppearParameters;
45struct InlineTextParameters;
46struct KeyboardInitializeParameters;
43} // namespace Core::Frontend 47} // namespace Core::Frontend
44 48
45namespace DiscordRPC { 49namespace DiscordRPC {
@@ -57,8 +61,11 @@ class InputSubsystem;
57} 61}
58 62
59namespace Service::AM::Applets { 63namespace Service::AM::Applets {
64enum class SwkbdResult : u32;
65enum class SwkbdTextCheckResult : u32;
66enum class SwkbdReplyType : u32;
60enum class WebExitReason : u32; 67enum class WebExitReason : u32;
61} 68} // namespace Service::AM::Applets
62 69
63enum class EmulatedDirectoryTarget { 70enum class EmulatedDirectoryTarget {
64 NAND, 71 NAND,
@@ -128,8 +135,10 @@ signals:
128 135
129 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); 136 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
130 137
131 void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); 138 void SoftwareKeyboardSubmitNormalText(Service::AM::Applets::SwkbdResult result,
132 void SoftwareKeyboardFinishedCheckDialog(); 139 std::u16string submitted_text);
140 void SoftwareKeyboardSubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
141 std::u16string submitted_text, s32 cursor_position);
133 142
134 void WebBrowserExtractOfflineRomFS(); 143 void WebBrowserExtractOfflineRomFS();
135 void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); 144 void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url);
@@ -139,15 +148,24 @@ public slots:
139 void OnExecuteProgram(std::size_t program_index); 148 void OnExecuteProgram(std::size_t program_index);
140 void ControllerSelectorReconfigureControllers( 149 void ControllerSelectorReconfigureControllers(
141 const Core::Frontend::ControllerParameters& parameters); 150 const Core::Frontend::ControllerParameters& parameters);
142 void ErrorDisplayDisplayError(QString body); 151 void SoftwareKeyboardInitialize(
152 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters);
153 void SoftwareKeyboardShowNormal();
154 void SoftwareKeyboardShowTextCheck(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
155 std::u16string text_check_message);
156 void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters);
157 void SoftwareKeyboardHideInline();
158 void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
159 void SoftwareKeyboardExit();
160 void ErrorDisplayDisplayError(QString error_code, QString error_text);
143 void ProfileSelectorSelectProfile(); 161 void ProfileSelectorSelectProfile();
144 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
145 void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
146 void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, 162 void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
147 bool is_local); 163 bool is_local);
148 void OnAppFocusStateChanged(Qt::ApplicationState state); 164 void OnAppFocusStateChanged(Qt::ApplicationState state);
149 165
150private: 166private:
167 void RegisterMetaTypes();
168
151 void InitializeWidgets(); 169 void InitializeWidgets();
152 void InitializeDebugWidgets(); 170 void InitializeDebugWidgets();
153 void InitializeRecentFileMenuActions(); 171 void InitializeRecentFileMenuActions();
@@ -334,6 +352,9 @@ private:
334 // Disables the web applet for the rest of the emulated session 352 // Disables the web applet for the rest of the emulated session
335 bool disable_web_applet{}; 353 bool disable_web_applet{};
336 354
355 // Applets
356 QtSoftwareKeyboardDialog* software_keyboard = nullptr;
357
337protected: 358protected:
338 void dropEvent(QDropEvent* event) override; 359 void dropEvent(QDropEvent* event) override;
339 void dragEnterEvent(QDragEnterEvent* event) override; 360 void dragEnterEvent(QDragEnterEvent* event) override;
diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp
new file mode 100644
index 000000000..95b148545
--- /dev/null
+++ b/src/yuzu/util/overlay_dialog.cpp
@@ -0,0 +1,249 @@
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 <QKeyEvent>
6#include <QScreen>
7
8#include "core/core.h"
9#include "core/frontend/input_interpreter.h"
10#include "ui_overlay_dialog.h"
11#include "yuzu/util/overlay_dialog.h"
12
13namespace {
14
15constexpr float BASE_TITLE_FONT_SIZE = 14.0f;
16constexpr float BASE_FONT_SIZE = 18.0f;
17constexpr float BASE_WIDTH = 1280.0f;
18constexpr float BASE_HEIGHT = 720.0f;
19
20} // Anonymous namespace
21
22OverlayDialog::OverlayDialog(QWidget* parent, Core::System& system, const QString& title_text,
23 const QString& body_text, const QString& left_button_text,
24 const QString& right_button_text, Qt::Alignment alignment,
25 bool use_rich_text_)
26 : QDialog(parent), ui{std::make_unique<Ui::OverlayDialog>()}, use_rich_text{use_rich_text_} {
27 ui->setupUi(this);
28
29 setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint |
30 Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint);
31 setWindowModality(Qt::WindowModal);
32 setAttribute(Qt::WA_TranslucentBackground);
33
34 if (use_rich_text) {
35 InitializeRichTextDialog(title_text, body_text, left_button_text, right_button_text,
36 alignment);
37 } else {
38 InitializeRegularTextDialog(title_text, body_text, left_button_text, right_button_text,
39 alignment);
40 }
41
42 MoveAndResizeWindow();
43
44 // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend
45 if (system.IsPoweredOn()) {
46 input_interpreter = std::make_unique<InputInterpreter>(system);
47
48 StartInputThread();
49 }
50}
51
52OverlayDialog::~OverlayDialog() {
53 StopInputThread();
54}
55
56void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const QString& body_text,
57 const QString& left_button_text,
58 const QString& right_button_text,
59 Qt::Alignment alignment) {
60 ui->stackedDialog->setCurrentIndex(0);
61
62 ui->label_title->setText(title_text);
63 ui->label_dialog->setText(body_text);
64 ui->button_cancel->setText(left_button_text);
65 ui->button_ok_label->setText(right_button_text);
66
67 ui->label_dialog->setAlignment(alignment);
68
69 if (title_text.isEmpty()) {
70 ui->label_title->hide();
71 ui->verticalLayout_2->setStretch(0, 0);
72 ui->verticalLayout_2->setStretch(1, 219);
73 ui->verticalLayout_2->setStretch(2, 82);
74 }
75
76 if (left_button_text.isEmpty()) {
77 ui->button_cancel->hide();
78 ui->button_cancel->setEnabled(false);
79 }
80
81 if (right_button_text.isEmpty()) {
82 ui->button_ok_label->hide();
83 ui->button_ok_label->setEnabled(false);
84 }
85
86 connect(
87 ui->button_cancel, &QPushButton::clicked, this,
88 [this](bool) {
89 StopInputThread();
90 QDialog::reject();
91 },
92 Qt::QueuedConnection);
93 connect(
94 ui->button_ok_label, &QPushButton::clicked, this,
95 [this](bool) {
96 StopInputThread();
97 QDialog::accept();
98 },
99 Qt::QueuedConnection);
100}
101
102void OverlayDialog::InitializeRichTextDialog(const QString& title_text, const QString& body_text,
103 const QString& left_button_text,
104 const QString& right_button_text,
105 Qt::Alignment alignment) {
106 ui->stackedDialog->setCurrentIndex(1);
107
108 ui->label_title_rich->setText(title_text);
109 ui->text_browser_dialog->setText(body_text);
110 ui->button_cancel_rich->setText(left_button_text);
111 ui->button_ok_rich->setText(right_button_text);
112
113 // TODO (Morph/Rei): Replace this with something that works better
114 ui->text_browser_dialog->setAlignment(alignment);
115
116 if (title_text.isEmpty()) {
117 ui->label_title_rich->hide();
118 ui->verticalLayout_3->setStretch(0, 0);
119 ui->verticalLayout_3->setStretch(1, 438);
120 ui->verticalLayout_3->setStretch(2, 82);
121 }
122
123 if (left_button_text.isEmpty()) {
124 ui->button_cancel_rich->hide();
125 ui->button_cancel_rich->setEnabled(false);
126 }
127
128 if (right_button_text.isEmpty()) {
129 ui->button_ok_rich->hide();
130 ui->button_ok_rich->setEnabled(false);
131 }
132
133 connect(
134 ui->button_cancel_rich, &QPushButton::clicked, this,
135 [this](bool) {
136 StopInputThread();
137 QDialog::reject();
138 },
139 Qt::QueuedConnection);
140 connect(
141 ui->button_ok_rich, &QPushButton::clicked, this,
142 [this](bool) {
143 StopInputThread();
144 QDialog::accept();
145 },
146 Qt::QueuedConnection);
147}
148
149void OverlayDialog::MoveAndResizeWindow() {
150 const auto pos = parentWidget()->mapToGlobal(parentWidget()->rect().topLeft());
151 const auto width = static_cast<float>(parentWidget()->width());
152 const auto height = static_cast<float>(parentWidget()->height());
153
154 // High DPI
155 const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f;
156
157 const auto title_text_font_size = BASE_TITLE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
158 const auto body_text_font_size =
159 BASE_FONT_SIZE * (((width / BASE_WIDTH) + (height / BASE_HEIGHT)) / 2.0f) / dpi_scale;
160 const auto button_text_font_size = BASE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
161
162 QFont title_text_font(QStringLiteral("MS Shell Dlg 2"), title_text_font_size, QFont::Normal);
163 QFont body_text_font(QStringLiteral("MS Shell Dlg 2"), body_text_font_size, QFont::Normal);
164 QFont button_text_font(QStringLiteral("MS Shell Dlg 2"), button_text_font_size, QFont::Normal);
165
166 if (use_rich_text) {
167 ui->label_title_rich->setFont(title_text_font);
168 ui->text_browser_dialog->setFont(body_text_font);
169 ui->button_cancel_rich->setFont(button_text_font);
170 ui->button_ok_rich->setFont(button_text_font);
171 } else {
172 ui->label_title->setFont(title_text_font);
173 ui->label_dialog->setFont(body_text_font);
174 ui->button_cancel->setFont(button_text_font);
175 ui->button_ok_label->setFont(button_text_font);
176 }
177
178 QDialog::move(pos);
179 QDialog::resize(width, height);
180}
181
182template <HIDButton... T>
183void OverlayDialog::HandleButtonPressedOnce() {
184 const auto f = [this](HIDButton button) {
185 if (input_interpreter->IsButtonPressedOnce(button)) {
186 TranslateButtonPress(button);
187 }
188 };
189
190 (f(T), ...);
191}
192
193void OverlayDialog::TranslateButtonPress(HIDButton button) {
194 QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel;
195 QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label;
196
197 // TODO (Morph): Handle QTextBrowser text scrolling
198 // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it
199
200 switch (button) {
201 case HIDButton::A:
202 case HIDButton::B:
203 if (left_button->hasFocus()) {
204 left_button->click();
205 } else if (right_button->hasFocus()) {
206 right_button->click();
207 }
208 break;
209 case HIDButton::DLeft:
210 case HIDButton::LStickLeft:
211 focusPreviousChild();
212 break;
213 case HIDButton::DRight:
214 case HIDButton::LStickRight:
215 focusNextChild();
216 break;
217 default:
218 break;
219 }
220}
221
222void OverlayDialog::StartInputThread() {
223 if (input_thread_running) {
224 return;
225 }
226
227 input_thread_running = true;
228
229 input_thread = std::thread(&OverlayDialog::InputThread, this);
230}
231
232void OverlayDialog::StopInputThread() {
233 input_thread_running = false;
234
235 if (input_thread.joinable()) {
236 input_thread.join();
237 }
238}
239
240void OverlayDialog::InputThread() {
241 while (input_thread_running) {
242 input_interpreter->PollInput();
243
244 HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::DLeft, HIDButton::DRight,
245 HIDButton::LStickLeft, HIDButton::LStickRight>();
246
247 std::this_thread::sleep_for(std::chrono::milliseconds(50));
248 }
249}
diff --git a/src/yuzu/util/overlay_dialog.h b/src/yuzu/util/overlay_dialog.h
new file mode 100644
index 000000000..e8c388bd0
--- /dev/null
+++ b/src/yuzu/util/overlay_dialog.h
@@ -0,0 +1,107 @@
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 <atomic>
9#include <memory>
10#include <thread>
11
12#include <QDialog>
13
14#include "common/common_types.h"
15
16enum class HIDButton : u8;
17
18class InputInterpreter;
19
20namespace Core {
21class System;
22}
23
24namespace Ui {
25class OverlayDialog;
26}
27
28/**
29 * An OverlayDialog is an interactive dialog that accepts controller input (while a game is running)
30 * This dialog attempts to replicate the look and feel of the Nintendo Switch's overlay dialogs and
31 * provide some extra features such as embedding HTML/Rich Text content in a QTextBrowser.
32 * The OverlayDialog provides 2 modes: one to embed regular text into a QLabel and another to embed
33 * HTML/Rich Text content into a QTextBrowser.
34 */
35class OverlayDialog final : public QDialog {
36 Q_OBJECT
37
38public:
39 explicit OverlayDialog(QWidget* parent, Core::System& system, const QString& title_text,
40 const QString& body_text, const QString& left_button_text,
41 const QString& right_button_text,
42 Qt::Alignment alignment = Qt::AlignCenter, bool use_rich_text_ = false);
43 ~OverlayDialog() override;
44
45private:
46 /**
47 * Initializes a text dialog with a QLabel storing text.
48 * Only use this for short text as the dialog buttons would be squashed with longer text.
49 *
50 * @param title_text Title text to be displayed
51 * @param body_text Main text to be displayed
52 * @param left_button_text Left button text. If empty, the button is hidden and disabled
53 * @param right_button_text Right button text. If empty, the button is hidden and disabled
54 * @param alignment Main text alignment
55 */
56 void InitializeRegularTextDialog(const QString& title_text, const QString& body_text,
57 const QString& left_button_text,
58 const QString& right_button_text, Qt::Alignment alignment);
59
60 /**
61 * Initializes a text dialog with a QTextBrowser storing text.
62 * This is ideal for longer text or rich text content. A scrollbar is shown for longer text.
63 *
64 * @param title_text Title text to be displayed
65 * @param body_text Main text to be displayed
66 * @param left_button_text Left button text. If empty, the button is hidden and disabled
67 * @param right_button_text Right button text. If empty, the button is hidden and disabled
68 * @param alignment Main text alignment
69 */
70 void InitializeRichTextDialog(const QString& title_text, const QString& body_text,
71 const QString& left_button_text, const QString& right_button_text,
72 Qt::Alignment alignment);
73
74 /// Moves and resizes the dialog to be fully overlayed on top of the parent window.
75 void MoveAndResizeWindow();
76
77 /**
78 * Handles button presses and converts them into keyboard input.
79 *
80 * @tparam HIDButton The list of buttons that can be converted into keyboard input.
81 */
82 template <HIDButton... T>
83 void HandleButtonPressedOnce();
84
85 /**
86 * Translates a button press to focus or click either the left or right buttons.
87 *
88 * @param button The button press to process.
89 */
90 void TranslateButtonPress(HIDButton button);
91
92 void StartInputThread();
93 void StopInputThread();
94
95 /// The thread where input is being polled and processed.
96 void InputThread();
97
98 std::unique_ptr<Ui::OverlayDialog> ui;
99
100 bool use_rich_text;
101
102 std::unique_ptr<InputInterpreter> input_interpreter;
103
104 std::thread input_thread;
105
106 std::atomic<bool> input_thread_running{};
107};
diff --git a/src/yuzu/util/overlay_dialog.ui b/src/yuzu/util/overlay_dialog.ui
new file mode 100644
index 000000000..278e2f219
--- /dev/null
+++ b/src/yuzu/util/overlay_dialog.ui
@@ -0,0 +1,404 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>OverlayDialog</class>
4 <widget class="QDialog" name="OverlayDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>1280</width>
10 <height>720</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Dialog</string>
15 </property>
16 <property name="styleSheet">
17 <string notr="true"/>
18 </property>
19 <layout class="QVBoxLayout" name="verticalLayout">
20 <property name="spacing">
21 <number>0</number>
22 </property>
23 <property name="leftMargin">
24 <number>0</number>
25 </property>
26 <property name="topMargin">
27 <number>0</number>
28 </property>
29 <property name="rightMargin">
30 <number>0</number>
31 </property>
32 <property name="bottomMargin">
33 <number>0</number>
34 </property>
35 <item>
36 <widget class="QStackedWidget" name="stackedDialog">
37 <property name="currentIndex">
38 <number>0</number>
39 </property>
40 <widget class="QWidget" name="lineDialog">
41 <layout class="QGridLayout" name="lineDialogGridLayout" rowstretch="210,300,210" columnstretch="250,780,250">
42 <property name="leftMargin">
43 <number>0</number>
44 </property>
45 <property name="topMargin">
46 <number>0</number>
47 </property>
48 <property name="rightMargin">
49 <number>0</number>
50 </property>
51 <property name="bottomMargin">
52 <number>0</number>
53 </property>
54 <property name="spacing">
55 <number>0</number>
56 </property>
57 <item row="1" column="1">
58 <widget class="QWidget" name="contentDialog" native="true">
59 <layout class="QVBoxLayout" name="verticalLayout_2" stretch="70,149,82">
60 <property name="spacing">
61 <number>0</number>
62 </property>
63 <property name="leftMargin">
64 <number>0</number>
65 </property>
66 <property name="topMargin">
67 <number>0</number>
68 </property>
69 <property name="rightMargin">
70 <number>0</number>
71 </property>
72 <property name="bottomMargin">
73 <number>0</number>
74 </property>
75 <item>
76 <widget class="QLabel" name="label_title">
77 <property name="font">
78 <font>
79 <pointsize>14</pointsize>
80 </font>
81 </property>
82 <property name="alignment">
83 <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
84 </property>
85 </widget>
86 </item>
87 <item>
88 <widget class="QLabel" name="label_dialog">
89 <property name="font">
90 <font>
91 <pointsize>18</pointsize>
92 </font>
93 </property>
94 <property name="alignment">
95 <set>Qt::AlignCenter</set>
96 </property>
97 <property name="wordWrap">
98 <bool>true</bool>
99 </property>
100 </widget>
101 </item>
102 <item>
103 <widget class="QWidget" name="buttonsDialog" native="true">
104 <layout class="QHBoxLayout" name="horizontalLayout">
105 <property name="spacing">
106 <number>0</number>
107 </property>
108 <property name="leftMargin">
109 <number>0</number>
110 </property>
111 <property name="topMargin">
112 <number>0</number>
113 </property>
114 <property name="rightMargin">
115 <number>0</number>
116 </property>
117 <property name="bottomMargin">
118 <number>0</number>
119 </property>
120 <item>
121 <widget class="QPushButton" name="button_cancel">
122 <property name="sizePolicy">
123 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
124 <horstretch>0</horstretch>
125 <verstretch>0</verstretch>
126 </sizepolicy>
127 </property>
128 <property name="font">
129 <font>
130 <pointsize>18</pointsize>
131 </font>
132 </property>
133 <property name="text">
134 <string>Cancel</string>
135 </property>
136 </widget>
137 </item>
138 <item>
139 <widget class="QPushButton" name="button_ok_label">
140 <property name="sizePolicy">
141 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
142 <horstretch>0</horstretch>
143 <verstretch>0</verstretch>
144 </sizepolicy>
145 </property>
146 <property name="font">
147 <font>
148 <pointsize>18</pointsize>
149 </font>
150 </property>
151 <property name="text">
152 <string>OK</string>
153 </property>
154 </widget>
155 </item>
156 </layout>
157 </widget>
158 </item>
159 </layout>
160 </widget>
161 </item>
162 <item row="0" column="1">
163 <spacer name="verticalSpacer">
164 <property name="orientation">
165 <enum>Qt::Vertical</enum>
166 </property>
167 <property name="sizeHint" stdset="0">
168 <size>
169 <width>20</width>
170 <height>40</height>
171 </size>
172 </property>
173 </spacer>
174 </item>
175 <item row="1" column="0">
176 <spacer name="horizontalSpacer">
177 <property name="orientation">
178 <enum>Qt::Horizontal</enum>
179 </property>
180 <property name="sizeHint" stdset="0">
181 <size>
182 <width>40</width>
183 <height>20</height>
184 </size>
185 </property>
186 </spacer>
187 </item>
188 <item row="2" column="1">
189 <spacer name="verticalSpacer_2">
190 <property name="orientation">
191 <enum>Qt::Vertical</enum>
192 </property>
193 <property name="sizeHint" stdset="0">
194 <size>
195 <width>20</width>
196 <height>40</height>
197 </size>
198 </property>
199 </spacer>
200 </item>
201 <item row="1" column="2">
202 <spacer name="horizontalSpacer_2">
203 <property name="orientation">
204 <enum>Qt::Horizontal</enum>
205 </property>
206 <property name="sizeHint" stdset="0">
207 <size>
208 <width>40</width>
209 <height>20</height>
210 </size>
211 </property>
212 </spacer>
213 </item>
214 </layout>
215 </widget>
216 <widget class="QWidget" name="richDialog">
217 <layout class="QGridLayout" name="richDialogGridLayout" rowstretch="100,520,100" columnstretch="165,950,165">
218 <property name="leftMargin">
219 <number>0</number>
220 </property>
221 <property name="topMargin">
222 <number>0</number>
223 </property>
224 <property name="rightMargin">
225 <number>0</number>
226 </property>
227 <property name="bottomMargin">
228 <number>0</number>
229 </property>
230 <property name="spacing">
231 <number>0</number>
232 </property>
233 <item row="1" column="0">
234 <spacer name="horizontalSpacer_3">
235 <property name="orientation">
236 <enum>Qt::Horizontal</enum>
237 </property>
238 <property name="sizeHint" stdset="0">
239 <size>
240 <width>40</width>
241 <height>20</height>
242 </size>
243 </property>
244 </spacer>
245 </item>
246 <item row="2" column="1">
247 <spacer name="verticalSpacer_4">
248 <property name="orientation">
249 <enum>Qt::Vertical</enum>
250 </property>
251 <property name="sizeHint" stdset="0">
252 <size>
253 <width>20</width>
254 <height>40</height>
255 </size>
256 </property>
257 </spacer>
258 </item>
259 <item row="0" column="1">
260 <spacer name="verticalSpacer_3">
261 <property name="orientation">
262 <enum>Qt::Vertical</enum>
263 </property>
264 <property name="sizeHint" stdset="0">
265 <size>
266 <width>20</width>
267 <height>40</height>
268 </size>
269 </property>
270 </spacer>
271 </item>
272 <item row="1" column="1">
273 <widget class="QWidget" name="contentRichDialog" native="true">
274 <layout class="QVBoxLayout" name="verticalLayout_3" stretch="70,368,82">
275 <property name="spacing">
276 <number>0</number>
277 </property>
278 <property name="leftMargin">
279 <number>0</number>
280 </property>
281 <property name="topMargin">
282 <number>0</number>
283 </property>
284 <property name="rightMargin">
285 <number>0</number>
286 </property>
287 <property name="bottomMargin">
288 <number>0</number>
289 </property>
290 <item>
291 <widget class="QLabel" name="label_title_rich">
292 <property name="font">
293 <font>
294 <pointsize>14</pointsize>
295 </font>
296 </property>
297 <property name="text">
298 <string/>
299 </property>
300 <property name="alignment">
301 <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
302 </property>
303 </widget>
304 </item>
305 <item>
306 <widget class="QTextBrowser" name="text_browser_dialog">
307 <property name="font">
308 <font>
309 <pointsize>18</pointsize>
310 </font>
311 </property>
312 <property name="html">
313 <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
314&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
315p, li { white-space: pre-wrap; }
316&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;&quot;&gt;
317&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
318 </property>
319 </widget>
320 </item>
321 <item>
322 <widget class="QWidget" name="buttonsRichDialog" native="true">
323 <layout class="QHBoxLayout" name="horizontalLayout_2">
324 <property name="spacing">
325 <number>0</number>
326 </property>
327 <property name="leftMargin">
328 <number>0</number>
329 </property>
330 <property name="topMargin">
331 <number>0</number>
332 </property>
333 <property name="rightMargin">
334 <number>0</number>
335 </property>
336 <property name="bottomMargin">
337 <number>0</number>
338 </property>
339 <item>
340 <widget class="QPushButton" name="button_cancel_rich">
341 <property name="sizePolicy">
342 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
343 <horstretch>0</horstretch>
344 <verstretch>0</verstretch>
345 </sizepolicy>
346 </property>
347 <property name="font">
348 <font>
349 <pointsize>18</pointsize>
350 </font>
351 </property>
352 <property name="text">
353 <string>Cancel</string>
354 </property>
355 </widget>
356 </item>
357 <item>
358 <widget class="QPushButton" name="button_ok_rich">
359 <property name="sizePolicy">
360 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
361 <horstretch>0</horstretch>
362 <verstretch>0</verstretch>
363 </sizepolicy>
364 </property>
365 <property name="font">
366 <font>
367 <pointsize>18</pointsize>
368 </font>
369 </property>
370 <property name="text">
371 <string>OK</string>
372 </property>
373 </widget>
374 </item>
375 </layout>
376 </widget>
377 </item>
378 </layout>
379 </widget>
380 </item>
381 <item row="1" column="2">
382 <spacer name="horizontalSpacer_4">
383 <property name="orientation">
384 <enum>Qt::Horizontal</enum>
385 </property>
386 <property name="sizeHint" stdset="0">
387 <size>
388 <width>40</width>
389 <height>20</height>
390 </size>
391 </property>
392 </spacer>
393 </item>
394 </layout>
395 </widget>
396 </widget>
397 </item>
398 </layout>
399 </widget>
400 <resources>
401 <include location="../../../dist/icons/overlay/overlay.qrc"/>
402 </resources>
403 <connections/>
404</ui>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 43877fc98..2f984d1b8 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -9,8 +9,8 @@
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/param_package.h" 11#include "common/param_package.h"
12#include "common/settings.h"
12#include "core/hle/service/acc/profile_manager.h" 13#include "core/hle/service/acc/profile_manager.h"
13#include "core/settings.h"
14#include "input_common/main.h" 14#include "input_common/main.h"
15#include "input_common/udp/client.h" 15#include "input_common/udp/client.h"
16#include "yuzu_cmd/config.h" 16#include "yuzu_cmd/config.h"
@@ -428,6 +428,10 @@ void Config::ReadValues() {
428 Settings::values.reporting_services = 428 Settings::values.reporting_services =
429 sdl2_config->GetBoolean("Debugging", "reporting_services", false); 429 sdl2_config->GetBoolean("Debugging", "reporting_services", false);
430 Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false); 430 Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false);
431 Settings::values.use_debug_asserts =
432 sdl2_config->GetBoolean("Debugging", "use_debug_asserts", false);
433 Settings::values.use_auto_stub = sdl2_config->GetBoolean("Debugging", "use_auto_stub", false);
434
431 Settings::values.disable_macro_jit = 435 Settings::values.disable_macro_jit =
432 sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false); 436 sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
433 437
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 3ee0e037d..4ce8e08e4 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -325,6 +325,12 @@ dump_nso=false
325# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode 325# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
326# false: Retail/Normal Mode (default), true: Kiosk Mode 326# false: Retail/Normal Mode (default), true: Kiosk Mode
327quest_flag = 327quest_flag =
328# Determines whether debug asserts should be enabled, which will throw an exception on asserts.
329# false: Disabled (default), true: Enabled
330use_debug_asserts =
331# Determines whether unimplemented HLE service calls should be automatically stubbed.
332# false: Disabled (default), true: Enabled
333use_auto_stub =
328# Enables/Disables the macro JIT compiler 334# Enables/Disables the macro JIT compiler
329disable_macro_jit=false 335disable_macro_jit=false
330 336
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 a02485c14..a765fa7b3 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -12,9 +12,9 @@
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/scm_rev.h" 14#include "common/scm_rev.h"
15#include "common/settings.h"
15#include "common/string_util.h" 16#include "common/string_util.h"
16#include "core/core.h" 17#include "core/core.h"
17#include "core/settings.h"
18#include "input_common/keyboard.h" 18#include "input_common/keyboard.h"
19#include "input_common/main.h" 19#include "input_common/main.h"
20#include "video_core/renderer_base.h" 20#include "video_core/renderer_base.h"
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
index 6f9b00461..dfd53e285 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
@@ -11,7 +11,7 @@
11#include "common/assert.h" 11#include "common/assert.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/scm_rev.h" 13#include "common/scm_rev.h"
14#include "core/settings.h" 14#include "common/settings.h"
15#include "video_core/renderer_vulkan/renderer_vulkan.h" 15#include "video_core/renderer_vulkan/renderer_vulkan.h"
16#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h" 16#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
17 17
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 982c41785..4871ac3bb 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -20,6 +20,7 @@
20#include "common/nvidia_flags.h" 20#include "common/nvidia_flags.h"
21#include "common/scm_rev.h" 21#include "common/scm_rev.h"
22#include "common/scope_exit.h" 22#include "common/scope_exit.h"
23#include "common/settings.h"
23#include "common/string_util.h" 24#include "common/string_util.h"
24#include "common/telemetry.h" 25#include "common/telemetry.h"
25#include "core/core.h" 26#include "core/core.h"
@@ -29,7 +30,6 @@
29#include "core/hle/kernel/process.h" 30#include "core/hle/kernel/process.h"
30#include "core/hle/service/filesystem/filesystem.h" 31#include "core/hle/service/filesystem/filesystem.h"
31#include "core/loader/loader.h" 32#include "core/loader/loader.h"
32#include "core/settings.h"
33#include "core/telemetry_session.h" 33#include "core/telemetry_session.h"
34#include "input_common/main.h" 34#include "input_common/main.h"
35#include "video_core/renderer_base.h" 35#include "video_core/renderer_base.h"
@@ -74,14 +74,16 @@ static void PrintVersion() {
74} 74}
75 75
76static void InitializeLogging() { 76static void InitializeLogging() {
77 using namespace Common;
78
77 Log::Filter log_filter(Log::Level::Debug); 79 Log::Filter log_filter(Log::Level::Debug);
78 log_filter.ParseFilterString(Settings::values.log_filter); 80 log_filter.ParseFilterString(Settings::values.log_filter);
79 Log::SetGlobalFilter(log_filter); 81 Log::SetGlobalFilter(log_filter);
80 82
81 Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); 83 Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
82 84
83 const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir); 85 const std::string& log_dir = FS::GetUserPath(FS::UserPath::LogDir);
84 Common::FS::CreateFullPath(log_dir); 86 FS::CreateFullPath(log_dir);
85 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE)); 87 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
86#ifdef _WIN32 88#ifdef _WIN32
87 Log::AddBackend(std::make_unique<Log::DebuggerBackend>()); 89 Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
@@ -164,7 +166,7 @@ int main(int argc, char** argv) {
164 InputCommon::InputSubsystem input_subsystem; 166 InputCommon::InputSubsystem input_subsystem;
165 167
166 // Apply the command line arguments 168 // Apply the command line arguments
167 Settings::Apply(system); 169 system.ApplySettings();
168 170
169 std::unique_ptr<EmuWindow_SDL2> emu_window; 171 std::unique_ptr<EmuWindow_SDL2> emu_window;
170 switch (Settings::values.renderer_backend.GetValue()) { 172 switch (Settings::values.renderer_backend.GetValue()) {