summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.ci/templates/build-msvc.yml2
-rw-r--r--CMakeLists.txt78
-rw-r--r--dist/icons/overlay/arrow_left.pngbin0 -> 1490 bytes
-rw-r--r--dist/icons/overlay/arrow_left_dark.pngbin0 -> 712 bytes
-rw-r--r--dist/icons/overlay/arrow_right.pngbin0 -> 1394 bytes
-rw-r--r--dist/icons/overlay/arrow_right_dark.pngbin0 -> 683 bytes
-rw-r--r--dist/icons/overlay/button_A.pngbin0 -> 3494 bytes
-rw-r--r--dist/icons/overlay/button_A_dark.pngbin0 -> 3167 bytes
-rw-r--r--dist/icons/overlay/button_B.pngbin0 -> 3375 bytes
-rw-r--r--dist/icons/overlay/button_B_dark.pngbin0 -> 2975 bytes
-rw-r--r--dist/icons/overlay/button_L.pngbin0 -> 796 bytes
-rw-r--r--dist/icons/overlay/button_L_dark.pngbin0 -> 745 bytes
-rw-r--r--dist/icons/overlay/button_R.pngbin0 -> 1841 bytes
-rw-r--r--dist/icons/overlay/button_R_dark.pngbin0 -> 1835 bytes
-rw-r--r--dist/icons/overlay/button_X.pngbin0 -> 3968 bytes
-rw-r--r--dist/icons/overlay/button_X_dark.pngbin0 -> 3530 bytes
-rw-r--r--dist/icons/overlay/button_Y.pngbin0 -> 3337 bytes
-rw-r--r--dist/icons/overlay/button_Y_dark.pngbin0 -> 2883 bytes
-rw-r--r--dist/icons/overlay/button_minus.pngbin0 -> 2401 bytes
-rw-r--r--dist/icons/overlay/button_minus_dark.pngbin0 -> 1969 bytes
-rw-r--r--dist/icons/overlay/button_plus.pngbin0 -> 2497 bytes
-rw-r--r--dist/icons/overlay/button_plus_dark.pngbin0 -> 2066 bytes
-rw-r--r--dist/icons/overlay/button_press_stick.pngbin0 -> 5225 bytes
-rw-r--r--dist/icons/overlay/button_press_stick_dark.pngbin0 -> 3636 bytes
-rw-r--r--dist/icons/overlay/controller_dual_joycon.pngbin0 -> 7312 bytes
-rw-r--r--dist/icons/overlay/controller_dual_joycon_dark.pngbin0 -> 5889 bytes
-rw-r--r--dist/icons/overlay/controller_handheld.pngbin0 -> 4645 bytes
-rw-r--r--dist/icons/overlay/controller_handheld_dark.pngbin0 -> 3745 bytes
-rw-r--r--dist/icons/overlay/controller_pro.pngbin0 -> 9493 bytes
-rw-r--r--dist/icons/overlay/controller_pro_dark.pngbin0 -> 7488 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left.pngbin0 -> 7489 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_a.pngbin0 -> 2609 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_a_dark.pngbin0 -> 2564 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_b.pngbin0 -> 2559 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_b_dark.pngbin0 -> 2383 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_dark.pngbin0 -> 6768 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_x.pngbin0 -> 2541 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_x_dark.pngbin0 -> 2392 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_y.pngbin0 -> 2641 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_y_dark.pngbin0 -> 2639 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_right.pngbin0 -> 7497 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_right_dark.pngbin0 -> 6729 bytes
-rw-r--r--dist/icons/overlay/osk_button_B.pngbin0 -> 741 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_dark.pngbin0 -> 767 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_dark_disabled.pngbin0 -> 781 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_disabled.pngbin0 -> 791 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y.pngbin0 -> 726 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_dark.pngbin0 -> 502 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_dark_disabled.pngbin0 -> 694 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_disabled.pngbin0 -> 699 bytes
-rw-r--r--dist/icons/overlay/osk_button_backspace.pngbin0 -> 2919 bytes
-rw-r--r--dist/icons/overlay/osk_button_backspace_dark.pngbin0 -> 2958 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus.pngbin0 -> 626 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_dark.pngbin0 -> 676 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_dark_disabled.pngbin0 -> 645 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_disabled.pngbin0 -> 664 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift.pngbin0 -> 1876 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_dark.pngbin0 -> 2003 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_lock_off.pngbin0 -> 281 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_lock_on.pngbin0 -> 274 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_on.pngbin0 -> 1573 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_on_dark.pngbin0 -> 1937 bytes
-rw-r--r--dist/icons/overlay/overlay.qrc64
-rw-r--r--dist/qt_themes/default/style.qss377
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss399
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qss439
-rw-r--r--externals/CMakeLists.txt10
m---------externals/dynarmic0
-rw-r--r--externals/find-modules/FindLibzip.cmake72
-rw-r--r--externals/find-modules/Findlibzip.cmake72
-rw-r--r--externals/find-modules/Findopus.cmake2
-rw-r--r--externals/opus/CMakeLists.txt2
-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
362 files changed, 15464 insertions, 3321 deletions
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml
index 721179550..74e688c12 100644
--- a/.ci/templates/build-msvc.yml
+++ b/.ci/templates/build-msvc.yml
@@ -8,7 +8,7 @@ steps:
displayName: 'Install vulkan-sdk'
- script: python -m pip install --upgrade pip conan
displayName: 'Install conan'
-- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd ..
+- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cmake --install . --config Release && cd ..
displayName: 'Configure CMake'
- task: MSBuild@1
displayName: 'Build'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac7c3ce90..a4a6da2e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,7 @@ project(yuzu)
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
+CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
@@ -166,12 +167,12 @@ macro(yuzu_find_packages)
# Cmake Pkg Prefix Version Conan Pkg
"Catch2 2.13 catch2/2.13.0"
"fmt 7.1 fmt/7.1.2"
- # can't use until https://github.com/bincrafters/community/issues/1173
- #"libzip 1.5 libzip/1.5.2@bincrafters/stable"
"lz4 1.8 lz4/1.9.2"
"nlohmann_json 3.8 nlohmann_json/3.8.0"
"ZLIB 1.2 zlib/1.2.11"
"zstd 1.4 zstd/1.4.8"
+ # can't use opus until AVX check is fixed: https://github.com/yuzu-emu/yuzu/pull/4068
+ #"opus 1.3 opus/1.3.1"
)
foreach(PACKAGE ${REQUIRED_LIBS})
@@ -249,22 +250,44 @@ if(ENABLE_QT)
if (ENABLE_QT_TRANSLATION)
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
endif()
- if (NOT Qt5_FOUND)
- list(APPEND CONAN_REQUIRED_LIBS "qt/5.14.1@bincrafters/stable")
- endif()
endif()
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the yuzu_find_package
-if(ENABLE_SDL2)
- if(EXISTS ${CMAKE_BINARY_DIR}/sdl2Config.cmake)
- include(${CMAKE_BINARY_DIR}/sdl2Config.cmake)
- list(APPEND CMAKE_MODULE_PATH "${CONAN_SDL2_ROOT_RELEASE}")
- list(APPEND CMAKE_PREFIX_PATH "${CONAN_SDL2_ROOT_RELEASE}")
- endif()
- find_package(SDL2)
- if (NOT SDL2_FOUND)
- # otherwise add this to the list of libraries to install
- list(APPEND CONAN_REQUIRED_LIBS "sdl2/2.0.14@bincrafters/stable")
+if (ENABLE_SDL2)
+ if (YUZU_USE_BUNDLED_SDL2)
+ # Detect toolchain and platform
+ if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
+ set(SDL2_VER "SDL2-2.0.14")
+ else()
+ message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
+ endif()
+
+ if (DEFINED SDL2_VER)
+ download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
+ endif()
+
+ set(SDL2_FOUND YES)
+ set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
+ set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
+ set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
+
+ add_library(SDL2 INTERFACE)
+ target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
+ target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
+ else()
+ find_package(SDL2 REQUIRED)
+
+ # Some installations don't set SDL2_LIBRARIES
+ if("${SDL2_LIBRARIES}" STREQUAL "")
+ message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
+ set(SDL2_LIBRARIES "SDL2::SDL2")
+ endif()
+
+ include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
+ add_library(SDL2 INTERFACE)
+ target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
endif()
+else()
+ set(SDL2_FOUND NO)
endif()
# Install any missing dependencies with conan install
@@ -285,9 +308,6 @@ if (CONAN_REQUIRED_LIBS)
)
conan_check(VERSION 1.24.0 REQUIRED)
- # Add the bincrafters remote
- conan_add_remote(NAME bincrafters
- URL https://api.bintray.com/conan/bincrafters/public-conan)
# Manually add iconv to fix a dep conflict between qt and sdl2
# We don't need to add it through find_package or anything since the other two can find it just fine
@@ -338,11 +358,6 @@ if (CONAN_REQUIRED_LIBS)
find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets)
endif()
endif()
- if(ENABLE_SDL2)
- list(APPEND CMAKE_MODULE_PATH "${CONAN_SDL2_ROOT_RELEASE}")
- list(APPEND CMAKE_PREFIX_PATH "${CONAN_SDL2_ROOT_RELEASE}")
- find_package(SDL2 REQUIRED)
- endif()
endif()
@@ -358,23 +373,6 @@ elseif (TARGET Boost::boost)
add_library(boost ALIAS Boost::boost)
endif()
-if (TARGET sdl2::sdl2)
- # imported from the conan generated sdl2Config.cmake
- set_target_properties(sdl2::sdl2 PROPERTIES IMPORTED_GLOBAL TRUE)
- add_library(SDL2 ALIAS sdl2::sdl2)
-elseif(SDL2_FOUND)
- # found through the system package manager
- # Some installations don't set SDL2_LIBRARIES
- if("${SDL2_LIBRARIES}" STREQUAL "")
- message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
- set(SDL2_LIBRARIES "SDL2::SDL2")
- endif()
-
- include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
- add_library(SDL2 INTERFACE)
- target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
-endif()
-
# Ensure libusb is properly configured (based on dolphin libusb include)
if(NOT APPLE)
include(FindPkgConfig)
diff --git a/dist/icons/overlay/arrow_left.png b/dist/icons/overlay/arrow_left.png
new file mode 100644
index 000000000..a5d4fecfe
--- /dev/null
+++ b/dist/icons/overlay/arrow_left.png
Binary files differ
diff --git a/dist/icons/overlay/arrow_left_dark.png b/dist/icons/overlay/arrow_left_dark.png
new file mode 100644
index 000000000..f73672a59
--- /dev/null
+++ b/dist/icons/overlay/arrow_left_dark.png
Binary files differ
diff --git a/dist/icons/overlay/arrow_right.png b/dist/icons/overlay/arrow_right.png
new file mode 100644
index 000000000..e47ee94bd
--- /dev/null
+++ b/dist/icons/overlay/arrow_right.png
Binary files differ
diff --git a/dist/icons/overlay/arrow_right_dark.png b/dist/icons/overlay/arrow_right_dark.png
new file mode 100644
index 000000000..91cf83d2c
--- /dev/null
+++ b/dist/icons/overlay/arrow_right_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_A.png b/dist/icons/overlay/button_A.png
new file mode 100644
index 000000000..fd90f8b42
--- /dev/null
+++ b/dist/icons/overlay/button_A.png
Binary files differ
diff --git a/dist/icons/overlay/button_A_dark.png b/dist/icons/overlay/button_A_dark.png
new file mode 100644
index 000000000..d6b5514fa
--- /dev/null
+++ b/dist/icons/overlay/button_A_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_B.png b/dist/icons/overlay/button_B.png
new file mode 100644
index 000000000..e8927addc
--- /dev/null
+++ b/dist/icons/overlay/button_B.png
Binary files differ
diff --git a/dist/icons/overlay/button_B_dark.png b/dist/icons/overlay/button_B_dark.png
new file mode 100644
index 000000000..3acbeddcd
--- /dev/null
+++ b/dist/icons/overlay/button_B_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_L.png b/dist/icons/overlay/button_L.png
new file mode 100644
index 000000000..77838369e
--- /dev/null
+++ b/dist/icons/overlay/button_L.png
Binary files differ
diff --git a/dist/icons/overlay/button_L_dark.png b/dist/icons/overlay/button_L_dark.png
new file mode 100644
index 000000000..c96a5e868
--- /dev/null
+++ b/dist/icons/overlay/button_L_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_R.png b/dist/icons/overlay/button_R.png
new file mode 100644
index 000000000..4e5553954
--- /dev/null
+++ b/dist/icons/overlay/button_R.png
Binary files differ
diff --git a/dist/icons/overlay/button_R_dark.png b/dist/icons/overlay/button_R_dark.png
new file mode 100644
index 000000000..ed13199c4
--- /dev/null
+++ b/dist/icons/overlay/button_R_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_X.png b/dist/icons/overlay/button_X.png
new file mode 100644
index 000000000..fe70fb685
--- /dev/null
+++ b/dist/icons/overlay/button_X.png
Binary files differ
diff --git a/dist/icons/overlay/button_X_dark.png b/dist/icons/overlay/button_X_dark.png
new file mode 100644
index 000000000..b2c83d0c1
--- /dev/null
+++ b/dist/icons/overlay/button_X_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_Y.png b/dist/icons/overlay/button_Y.png
new file mode 100644
index 000000000..ca0de569d
--- /dev/null
+++ b/dist/icons/overlay/button_Y.png
Binary files differ
diff --git a/dist/icons/overlay/button_Y_dark.png b/dist/icons/overlay/button_Y_dark.png
new file mode 100644
index 000000000..0f3e4df25
--- /dev/null
+++ b/dist/icons/overlay/button_Y_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_minus.png b/dist/icons/overlay/button_minus.png
new file mode 100644
index 000000000..7b315fe79
--- /dev/null
+++ b/dist/icons/overlay/button_minus.png
Binary files differ
diff --git a/dist/icons/overlay/button_minus_dark.png b/dist/icons/overlay/button_minus_dark.png
new file mode 100644
index 000000000..6dfcdc1b5
--- /dev/null
+++ b/dist/icons/overlay/button_minus_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_plus.png b/dist/icons/overlay/button_plus.png
new file mode 100644
index 000000000..4d8090d7d
--- /dev/null
+++ b/dist/icons/overlay/button_plus.png
Binary files differ
diff --git a/dist/icons/overlay/button_plus_dark.png b/dist/icons/overlay/button_plus_dark.png
new file mode 100644
index 000000000..abe8b9c95
--- /dev/null
+++ b/dist/icons/overlay/button_plus_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_press_stick.png b/dist/icons/overlay/button_press_stick.png
new file mode 100644
index 000000000..6d0254d50
--- /dev/null
+++ b/dist/icons/overlay/button_press_stick.png
Binary files differ
diff --git a/dist/icons/overlay/button_press_stick_dark.png b/dist/icons/overlay/button_press_stick_dark.png
new file mode 100644
index 000000000..757d0ab29
--- /dev/null
+++ b/dist/icons/overlay/button_press_stick_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_dual_joycon.png b/dist/icons/overlay/controller_dual_joycon.png
new file mode 100644
index 000000000..8e8b5ad41
--- /dev/null
+++ b/dist/icons/overlay/controller_dual_joycon.png
Binary files differ
diff --git a/dist/icons/overlay/controller_dual_joycon_dark.png b/dist/icons/overlay/controller_dual_joycon_dark.png
new file mode 100644
index 000000000..63e03eb4e
--- /dev/null
+++ b/dist/icons/overlay/controller_dual_joycon_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_handheld.png b/dist/icons/overlay/controller_handheld.png
new file mode 100644
index 000000000..deb375011
--- /dev/null
+++ b/dist/icons/overlay/controller_handheld.png
Binary files differ
diff --git a/dist/icons/overlay/controller_handheld_dark.png b/dist/icons/overlay/controller_handheld_dark.png
new file mode 100644
index 000000000..1f5317aa0
--- /dev/null
+++ b/dist/icons/overlay/controller_handheld_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_pro.png b/dist/icons/overlay/controller_pro.png
new file mode 100644
index 000000000..67cf86d5c
--- /dev/null
+++ b/dist/icons/overlay/controller_pro.png
Binary files differ
diff --git a/dist/icons/overlay/controller_pro_dark.png b/dist/icons/overlay/controller_pro_dark.png
new file mode 100644
index 000000000..7be655b96
--- /dev/null
+++ b/dist/icons/overlay/controller_pro_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left.png b/dist/icons/overlay/controller_single_joycon_left.png
new file mode 100644
index 000000000..340ddc71b
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_a.png b/dist/icons/overlay/controller_single_joycon_left_a.png
new file mode 100644
index 000000000..e0f5c2ad4
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_a.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_a_dark.png b/dist/icons/overlay/controller_single_joycon_left_a_dark.png
new file mode 100644
index 000000000..53e04781e
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_a_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_b.png b/dist/icons/overlay/controller_single_joycon_left_b.png
new file mode 100644
index 000000000..7429450a3
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_b.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_b_dark.png b/dist/icons/overlay/controller_single_joycon_left_b_dark.png
new file mode 100644
index 000000000..3bd97a8eb
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_b_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_dark.png b/dist/icons/overlay/controller_single_joycon_left_dark.png
new file mode 100644
index 000000000..24ed2c44c
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_x.png b/dist/icons/overlay/controller_single_joycon_left_x.png
new file mode 100644
index 000000000..4615172a3
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_x.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_x_dark.png b/dist/icons/overlay/controller_single_joycon_left_x_dark.png
new file mode 100644
index 000000000..119e3091a
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_x_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_y.png b/dist/icons/overlay/controller_single_joycon_left_y.png
new file mode 100644
index 000000000..24421d8b9
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_y.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_y_dark.png b/dist/icons/overlay/controller_single_joycon_left_y_dark.png
new file mode 100644
index 000000000..fdf177c12
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_y_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_right.png b/dist/icons/overlay/controller_single_joycon_right.png
new file mode 100644
index 000000000..5b8fc0eff
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_right.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_right_dark.png b/dist/icons/overlay/controller_single_joycon_right_dark.png
new file mode 100644
index 000000000..afa80e6ef
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_right_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B.png b/dist/icons/overlay/osk_button_B.png
new file mode 100644
index 000000000..f4a041178
--- /dev/null
+++ b/dist/icons/overlay/osk_button_B.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_dark.png b/dist/icons/overlay/osk_button_B_dark.png
new file mode 100644
index 000000000..2d2bffcca
--- /dev/null
+++ b/dist/icons/overlay/osk_button_B_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_dark_disabled.png b/dist/icons/overlay/osk_button_B_dark_disabled.png
new file mode 100644
index 000000000..93c102b1b
--- /dev/null
+++ b/dist/icons/overlay/osk_button_B_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_disabled.png b/dist/icons/overlay/osk_button_B_disabled.png
new file mode 100644
index 000000000..5900982f6
--- /dev/null
+++ b/dist/icons/overlay/osk_button_B_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y.png b/dist/icons/overlay/osk_button_Y.png
new file mode 100644
index 000000000..b08b4e26b
--- /dev/null
+++ b/dist/icons/overlay/osk_button_Y.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_dark.png b/dist/icons/overlay/osk_button_Y_dark.png
new file mode 100644
index 000000000..1fba9ca93
--- /dev/null
+++ b/dist/icons/overlay/osk_button_Y_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_dark_disabled.png b/dist/icons/overlay/osk_button_Y_dark_disabled.png
new file mode 100644
index 000000000..6ce53f9e4
--- /dev/null
+++ b/dist/icons/overlay/osk_button_Y_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_disabled.png b/dist/icons/overlay/osk_button_Y_disabled.png
new file mode 100644
index 000000000..25db07f66
--- /dev/null
+++ b/dist/icons/overlay/osk_button_Y_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_backspace.png b/dist/icons/overlay/osk_button_backspace.png
new file mode 100644
index 000000000..4ad284720
--- /dev/null
+++ b/dist/icons/overlay/osk_button_backspace.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_backspace_dark.png b/dist/icons/overlay/osk_button_backspace_dark.png
new file mode 100644
index 000000000..19ac8847e
--- /dev/null
+++ b/dist/icons/overlay/osk_button_backspace_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus.png b/dist/icons/overlay/osk_button_plus.png
new file mode 100644
index 000000000..5baa5201e
--- /dev/null
+++ b/dist/icons/overlay/osk_button_plus.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_dark.png b/dist/icons/overlay/osk_button_plus_dark.png
new file mode 100644
index 000000000..4cadb438b
--- /dev/null
+++ b/dist/icons/overlay/osk_button_plus_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_dark_disabled.png b/dist/icons/overlay/osk_button_plus_dark_disabled.png
new file mode 100644
index 000000000..b8eb8dc3d
--- /dev/null
+++ b/dist/icons/overlay/osk_button_plus_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_disabled.png b/dist/icons/overlay/osk_button_plus_disabled.png
new file mode 100644
index 000000000..c23e9d95d
--- /dev/null
+++ b/dist/icons/overlay/osk_button_plus_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift.png b/dist/icons/overlay/osk_button_shift.png
new file mode 100644
index 000000000..f03e30697
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_dark.png b/dist/icons/overlay/osk_button_shift_dark.png
new file mode 100644
index 000000000..c9cc5cd9a
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_lock_off.png b/dist/icons/overlay/osk_button_shift_lock_off.png
new file mode 100644
index 000000000..585500b3a
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_lock_off.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_lock_on.png b/dist/icons/overlay/osk_button_shift_lock_on.png
new file mode 100644
index 000000000..09077ab01
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_lock_on.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_on.png b/dist/icons/overlay/osk_button_shift_on.png
new file mode 100644
index 000000000..e7c1187f9
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_on.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_on_dark.png b/dist/icons/overlay/osk_button_shift_on_dark.png
new file mode 100644
index 000000000..58e0d9cf4
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_on_dark.png
Binary files differ
diff --git a/dist/icons/overlay/overlay.qrc b/dist/icons/overlay/overlay.qrc
new file mode 100644
index 000000000..d5a21ce10
--- /dev/null
+++ b/dist/icons/overlay/overlay.qrc
@@ -0,0 +1,64 @@
+<RCC>
+ <qresource prefix="overlay">
+ <file>arrow_left.png</file>
+ <file>arrow_left_dark.png</file>
+ <file>arrow_right.png</file>
+ <file>arrow_right_dark.png</file>
+ <file>button_minus.png</file>
+ <file>button_minus_dark.png</file>
+ <file>button_plus.png</file>
+ <file>button_plus_dark.png</file>
+ <file>button_A.png</file>
+ <file>button_A_dark.png</file>
+ <file>button_B.png</file>
+ <file>button_B_dark.png</file>
+ <file>button_X.png</file>
+ <file>button_X_dark.png</file>
+ <file>button_Y.png</file>
+ <file>button_Y_dark.png</file>
+ <file>button_L.png</file>
+ <file>button_L_dark.png</file>
+ <file>button_R.png</file>
+ <file>button_R_dark.png</file>
+ <file>button_press_stick.png</file>
+ <file>button_press_stick_dark.png</file>
+ <file>osk_button_B.png</file>
+ <file>osk_button_B_disabled.png</file>
+ <file>osk_button_B_dark.png</file>
+ <file>osk_button_B_dark_disabled.png</file>
+ <file>osk_button_Y.png</file>
+ <file>osk_button_Y_disabled.png</file>
+ <file>osk_button_Y_dark.png</file>
+ <file>osk_button_Y_dark_disabled.png</file>
+ <file>osk_button_backspace.png</file>
+ <file>osk_button_backspace_dark.png</file>
+ <file>osk_button_plus.png</file>
+ <file>osk_button_plus_disabled.png</file>
+ <file>osk_button_plus_dark.png</file>
+ <file>osk_button_plus_dark_disabled.png</file>
+ <file>osk_button_shift.png</file>
+ <file>osk_button_shift_dark.png</file>
+ <file>osk_button_shift_on.png</file>
+ <file>osk_button_shift_on_dark.png</file>
+ <file>osk_button_shift_lock_on.png</file>
+ <file>osk_button_shift_lock_off.png</file>
+ <file>controller_dual_joycon.png</file>
+ <file>controller_dual_joycon_dark.png</file>
+ <file>controller_pro.png</file>
+ <file>controller_pro_dark.png</file>
+ <file>controller_handheld.png</file>
+ <file>controller_handheld_dark.png</file>
+ <file>controller_single_joycon_left.png</file>
+ <file>controller_single_joycon_left_dark.png</file>
+ <file>controller_single_joycon_right.png</file>
+ <file>controller_single_joycon_right_dark.png</file>
+ <file>controller_single_joycon_left_a.png</file>
+ <file>controller_single_joycon_left_a_dark.png</file>
+ <file>controller_single_joycon_left_b.png</file>
+ <file>controller_single_joycon_left_b_dark.png</file>
+ <file>controller_single_joycon_left_x.png</file>
+ <file>controller_single_joycon_left_x_dark.png</file>
+ <file>controller_single_joycon_left_y.png</file>
+ <file>controller_single_joycon_left_y_dark.png</file>
+ </qresource>
+</RCC>
diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss
index 836dd25ca..3bc92b69d 100644
--- a/dist/qt_themes/default/style.qss
+++ b/dist/qt_themes/default/style.qss
@@ -281,3 +281,380 @@ QWidget#controllerPlayer7,
QWidget#controllerPlayer8 {
background: transparent;
}
+
+QDialog#QtSoftwareKeyboardDialog,
+QStackedWidget#topOSK {
+ background: rgba(51, 51, 51, .9);
+}
+
+
+QDialog#OverlayDialog,
+QStackedWidget#stackedDialog {
+ background: rgba(51, 51, 51, .7);
+}
+
+QWidget#boxOSK,
+QWidget#lineOSK,
+QWidget#richDialog,
+QWidget#lineDialog {
+ background: transparent;
+}
+
+QStackedWidget#bottomOSK,
+QWidget#contentDialog,
+QWidget#contentRichDialog {
+ background: rgba(240, 240, 240, 1);
+}
+
+QWidget#contentDialog,
+QWidget#contentRichDialog {
+ margin: 5px;
+ border-radius: 6px;
+}
+
+QWidget#buttonsDialog,
+QWidget#buttonsRichDialog {
+ margin: 5px;
+ border-top: 2px solid rgba(44, 44, 44, 1);
+}
+
+QWidget#legendOSKnum {
+ border-top: 1px solid rgba(44, 44, 44, 1);
+}
+
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::vertical {
+ background: #cdcdcd;
+ width: 15px;
+ margin: 15px 3px 15px 3px;
+ border: 1px transparent;
+ border-radius: 4px;
+}
+
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::horizoncal {
+ background: #cdcdcd;
+ height: 15px;
+ margin: 3px 15px 3px 15px;
+ border: 1px transparent;
+ border-radius: 4px;
+}
+
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::handle {
+ background: #fff;
+ border-radius: 4px;
+ min-height: 5px;
+ min-width: 5px;
+}
+
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line,
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-page,
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-page {
+ background: none;
+}
+
+QWidget#inputOSK {
+ border-bottom: 3px solid rgba(255, 255, 255, .9);
+}
+
+QWidget#inputOSK QLineEdit {
+ background: transparent;
+ border: none;
+ color: #ccc;
+}
+
+QWidget#inputBoxOSK {
+ border: 2px solid rgba(255, 255, 255, .9);
+}
+
+QWidget#inputBoxOSK QTextEdit {
+ background: transparent;
+ border: none;
+ color: #ccc;
+}
+
+QWidget#richDialog QTextBrowser {
+ background: transparent;
+ border: none;
+ padding: 35px 65px;
+}
+
+
+QWidget#lineOSK QLabel#label_header {
+ color: #f0f0f0;
+}
+
+QWidget#lineOSK QLabel#label_sub,
+QWidget#lineOSK QLabel#label_characters,
+QWidget#boxOSK QLabel#label_characters_box {
+ color: #ccc;
+}
+
+QWidget#contentDialog QLabel#label_title,
+QWidget#contentRichDialog QLabel#label_title_rich {
+ color: #888;
+}
+
+QWidget#contentDialog QLabel#label_dialog {
+ padding: 20px 65px;
+}
+
+QWidget#contentDialog QLabel#label_title,
+QWidget#contentRichDialog QLabel#label_title_rich {
+ padding: 0px 65px;
+}
+
+QDialog#OverlayDialog QPushButton {
+ color: rgba(49, 79, 239, 1);
+ background: transparent;
+ border: none;
+ padding: 0px;
+ min-width: 0px;
+}
+
+QDialog#OverlayDialog QPushButton:focus,
+QDialog#OverlayDialog QPushButton:hover {
+ color: rgba(49, 79, 239, 1);
+ background: rgba(255, 255, 255, 1);
+ border: 5px solid rgba(148, 250, 202, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#OverlayDialog QPushButton:pressed {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(150, 150, 150, 1);
+ border: 5px solid rgba(148, 250, 202, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton {
+ background: rgba(232, 232, 232, 1);
+ border: 2px solid rgba(240, 240, 240, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
+ background: rgba(218, 218, 218, 1);
+ border: 2px solid rgba(240, 240, 240, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(44, 44, 44, 1);
+ border: 2px solid rgba(240, 240, 240, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(49, 79, 239, 1);
+ border: 2px solid rgba(240, 240, 240, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
+ color: rgba(0, 0, 0, 1);
+ background: rgba(255, 255, 255, 1);
+ border: 5px solid rgba(148, 250, 202, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(150, 150, 150, 1);
+ border: 5px solid rgba(148, 250, 202, 1);
+ border-radius: 6px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_B.png);
+ qproperty-icon: url(:/overlay/osk_button_backspace.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_Y.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_plus.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
+ background-position: left top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ qproperty-icon: url(:/overlay/osk_button_shift.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
+ background-position: left top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ qproperty-icon: url(:/overlay/osk_button_shift_on.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
+ padding-bottom: 7px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
+ background: transparent;
+ color: #ccc;
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
+ image: url(:/overlay/button_L.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
+ image: url(:/overlay/arrow_left.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
+ image: url(:/overlay/button_R.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
+ image: url(:/overlay/arrow_right.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
+ image: url(:/overlay/button_press_stick.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
+ image: url(:/overlay/button_X.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
+ image: url(:/overlay/button_A.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
+ color: rgba(164, 164, 164, 1);
+ background-color: rgba(218, 218, 218, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
+ color: rgba(164, 164, 164, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
+ background-image: url(:/overlay/osk_button_plus_disabled.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
+ background-image: url(:/overlay/osk_button_B_disabled.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
+ background-image: url(:/overlay/osk_button_Y_disabled.png);
+}
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 2a1e8ddeb..8ce6d75f7 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -1560,7 +1560,400 @@ QWidget#controllerPlayer8 {
background: transparent;
}
-/* touchscreen mapping widget */
-TouchScreenPreview {
- qproperty-dotHighlightColor: #3daee9;
+QDialog#QtSoftwareKeyboardDialog,
+QStackedWidget#topOSK {
+ background: rgba(41, 41, 41, .9);
+}
+
+
+QDialog#OverlayDialog,
+QStackedWidget#stackedDialog {
+ background: rgba(41, 41, 41, .7);
+}
+
+QWidget#boxOSK,
+QWidget#lineOSK,
+QWidget#richDialog,
+QWidget#lineDialog {
+ background: transparent;
+}
+
+QStackedWidget#bottomOSK,
+QWidget#contentDialog,
+QWidget#contentRichDialog {
+ background: rgba(71, 69, 71, 1);
+}
+
+QWidget#contentDialog,
+QWidget#contentRichDialog {
+ margin: 5px;
+ border-radius: 6px;
+}
+
+QWidget#buttonsDialog,
+QWidget#buttonsRichDialog {
+ margin: 5px;
+ border-top: 2px solid rgba(255, 255, 255, .9);
+}
+
+QWidget#legendOSKnum {
+ border-top: 1px solid rgba(255, 255, 255, 1);
+}
+
+QStackedWidget#stackedDialog QTextBrowser QWidget {
+ background: transparent;
+}
+
+QStackedWidget#stackedDialog QTextBrowser QScrollBar {
+ background: #2a2929;
+}
+
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line {
+ border-image: none;
+}
+
+QWidget#inputOSK {
+ border-bottom: 3px solid rgba(255, 255, 255, .9);
+}
+
+QWidget#inputOSK QLineEdit {
+ background: transparent;
+ border: none;
+ color: #ccc;
+ padding: 0px;
+}
+
+QWidget#inputBoxOSK {
+ border: 2px solid rgba(255, 255, 255, .9);
+}
+
+QWidget#inputBoxOSK QTextEdit {
+ background: transparent;
+ border: none;
+ color: #ccc;
+}
+
+QWidget#richDialog QTextBrowser {
+ background: transparent;
+ border: none;
+ color: #fff;
+ padding: 35px 65px;
+}
+
+QWidget#lineOSK QLabel#label_header {
+ color: #f0f0f0;
+}
+
+QWidget#lineOSK QLabel#label_sub,
+QWidget#lineOSK QLabel#label_characters,
+QWidget#contentDialog QLabel#label_title,
+QWidget#contentRichDialog QLabel#label_title_rich,
+QWidget#boxOSK QLabel#label_characters_box {
+ color: #ccc;
+}
+
+QWidget#buttonsDialog,
+QWidget#buttonsRichDialog,
+QWidget#mainOSK,
+QWidget#headerOSK,
+QWidget#normalOSK,
+QWidget#shiftOSK,
+QWidget#numOSK,
+QWidget#subOSK,
+QWidget#inputOSK,
+QWidget#inputBoxOSK,
+QWidget#charactersOSK,
+QWidget#charactersBoxOSK,
+QWidget#legendOSK,
+QWidget#legendOSK QWidget,
+QWidget#legendOSKshift,
+QWidget#legendOSKshift QWidget,
+QWidget#legendOSKnum,
+QWidget#legendOSKnum QWidget {
+ background: transparent;
+}
+
+QWidget#contentDialog QLabel,
+QWidget#legendOSK QLabel,
+QWidget#legendOSKshift QLabel,
+QWidget#legendOSKnum QLabel {
+ color: rgba(255, 255, 255, 1);
+}
+
+QWidget#contentDialog QLabel#label_dialog {
+ padding: 20px 65px;
+}
+
+QWidget#contentDialog QLabel#label_title,
+QWidget#contentRichDialog QLabel#label_title_rich {
+ padding: 0px 65px;
+}
+
+QDialog#OverlayDialog QPushButton {
+ color: rgba(1, 253, 201, 1);
+ background: transparent;
+ border: none;
+ padding: 0px;
+ min-width: 0px;
+}
+
+QDialog#OverlayDialog QPushButton:focus,
+QDialog#OverlayDialog QPushButton:hover {
+ color: rgba(1, 253, 201, 1);
+ background: rgba(58, 61, 66, 1);
+ border: 5px solid rgba(56, 189, 225, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#OverlayDialog QPushButton:pressed {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(150, 150, 150, 1);
+ border: 5px solid rgba(56, 189, 225, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton {
+ color: rgba(255, 255, 255, 1);
+ background: rgba(80, 79, 80, 1);
+ border: 2px solid rgba(71, 69, 71, 1);
+ padding: 0px;
+ min-width: 0px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
+ background: rgba(95, 94, 95, 1);
+ border: 2px solid rgba(71, 69, 71, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(255, 255, 255, 1);
+ border: 2px solid rgba(71, 69, 71, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
+ color: rgba(0, 0, 0, 1);
+ background: rgba(1, 253, 201, 1);
+ border: 2px solid rgba(71, 69, 71, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
+ color: rgba(255, 255, 255, 1);
+ background: rgba(58, 61, 66, 1);
+ border: 5px solid rgba(56, 189, 225, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(150, 150, 150, 1);
+ border: 5px solid rgba(56, 189, 225, 1);
+ border-radius: 6px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_B_dark.png);
+ qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_Y_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
+ color: rgba(44, 44, 44, 1);
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_plus_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
+ background-position: left top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
+ background-position: left top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
+ padding-bottom: 7px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
+ background: transparent;
+ color: #ccc;
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
+ image: url(:/overlay/button_L_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
+ image: url(:/overlay/arrow_left_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
+ image: url(:/overlay/button_R_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
+ image: url(:/overlay/arrow_right_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
+ image: url(:/overlay/button_press_stick_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
+ image: url(:/overlay/button_X_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
+ image: url(:/overlay/button_A_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
+ color: rgba(144, 144, 144, 1);
+ background-color: rgba(95, 94, 95, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
+ color: rgba(144, 144, 144, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
+ background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
+ background-image: url(:/overlay/osk_button_B_dark_disabled.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
+ background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QFrame,
+QDialog#QtSoftwareKeyboardDialog QFrame[frameShape="0"],
+QDialog#OverlayDialog QFrame,
+QDialog#OverlayDialog QFrame[frameShape="0"] {
+ border-radius: 0px;
+ border: none;
}
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index a64037455..64e1ecbcc 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -1,10 +1,10 @@
/* ---------------------------------------------------------------------------
- Created by the qtsass compiler v0.1.1
+ Created by the qtsass compiler v0.1.1
- The definitions are in the "qdarkstyle.qss._styles.scss" module
+ The definitions are in the "qdarkstyle.qss._styles.scss" module
- WARNING! All changes made in this file will be lost!
+ WARNING! All changes made in this file will be lost!
--------------------------------------------------------------------------- */
/* QDarkStyleSheet -----------------------------------------------------------
@@ -15,34 +15,34 @@ It is based on three selecting colors, three greyish (background) colors
plus three whitish (foreground) colors. Each set of widgets of the same
type have a header like this:
- ------------------
- GroupName --------
- ------------------
+ ------------------
+ GroupName --------
+ ------------------
And each widget is separated with a header like this:
- QWidgetName ------
+ QWidgetName ------
This makes more easy to find and change some css field. The basic
configuration is described bellow.
- BACKGROUND -----------
+ BACKGROUND -----------
- Light (unpressed)
- Normal (border, disabled, pressed, checked, toolbars, menus)
- Dark (background)
+ Light (unpressed)
+ Normal (border, disabled, pressed, checked, toolbars, menus)
+ Dark (background)
- FOREGROUND -----------
+ FOREGROUND -----------
- Light (texts/labels)
- Normal (not used yet)
- Dark (disabled texts)
+ Light (texts/labels)
+ Normal (not used yet)
+ Dark (disabled texts)
- SELECTION ------------
+ SELECTION ------------
- Light (selection/hover/active)
- Normal (selected)
- Dark (selected disabled)
+ Light (selection/hover/active)
+ Normal (selected)
+ Dark (selected disabled)
If a stranger configuration is required because of a bugfix or anything
else, keep the comment on the line above so nobody changes it, including the
@@ -2483,3 +2483,404 @@ QWidget#controllerPlayer7,
QWidget#controllerPlayer8 {
background: transparent;
}
+
+QDialog#QtSoftwareKeyboardDialog,
+QStackedWidget#topOSK {
+ background: rgba(15, 25, 34, .9);
+}
+
+QDialog#OverlayDialog,
+QStackedWidget#stackedDialog {
+ background: rgba(15, 25, 34, .7);
+}
+
+QWidget#boxOSK,
+QWidget#lineOSK,
+QWidget#richDialog,
+QWidget#lineDialog {
+ background: transparent;
+}
+
+QStackedWidget#bottomOSK,
+QWidget#contentDialog,
+QWidget#contentRichDialog {
+ background: rgba(31, 41, 51, 1);
+}
+
+QWidget#contentDialog,
+QWidget#contentRichDialog {
+ margin: 5px;
+ border-radius: 6px;
+}
+
+QWidget#buttonsDialog,
+QWidget#buttonsRichDialog {
+ margin: 5px;
+ border-top: 2px solid rgba(255, 255, 255, .9);
+}
+
+QWidget#legendOSKnum {
+ border-top: 1px solid rgba(255, 255, 255, 1);
+}
+
+QStackedWidget#stackedDialog QTextBrowser QWidget {
+ background: transparent;
+}
+
+QStackedWidget#stackedDialog QTextBrowser QScrollBar {
+ background: #19232d;
+ border: none;
+}
+
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
+QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line {
+ border-image: none;
+}
+
+QWidget#mainOSK QStackedWidget,
+QDialog#OverlayDialog QStackedWidget {
+ border: none;
+ padding: 0px;
+}
+
+QWidget#inputOSK {
+ border-bottom: 3px solid rgba(255, 255, 255, .9);
+}
+
+QWidget#inputOSK QLineEdit {
+ background: transparent;
+ border: none;
+ color: #ccc;
+ padding: 0px;
+}
+
+QWidget#inputBoxOSK {
+ border: 2px solid rgba(255, 255, 255, .9);
+}
+
+QWidget#inputBoxOSK QTextEdit {
+ background: transparent;
+ border: none;
+ color: #ccc;
+}
+
+QWidget#richDialog QTextBrowser {
+ background: transparent;
+ border: none;
+ color: #fff;
+ padding: 35px 65px;
+}
+
+QWidget#lineOSK QLabel#label_header {
+ color: #f0f0f0;
+}
+
+QWidget#lineOSK QLabel#label_sub,
+QWidget#lineOSK QLabel#label_characters,
+QWidget#contentDialog QLabel#label_title,
+QWidget#contentRichDialog QLabel#label_title_rich,
+QWidget#boxOSK QLabel#label_characters_box {
+ color: #ccc;
+}
+
+QWidget#buttonsDialog,
+QWidget#buttonsRichDialog,
+QWidget#mainOSK,
+QWidget#headerOSK,
+QWidget#normalOSK,
+QWidget#shiftOSK,
+QWidget#numOSK,
+QWidget#subOSK,
+QWidget#inputOSK,
+QWidget#inputBoxOSK,
+QWidget#charactersOSK,
+QWidget#charactersBoxOSK,
+QWidget#legendOSK,
+QWidget#legendOSK QWidget,
+QWidget#legendOSKshift,
+QWidget#legendOSKshift QWidget,
+QWidget#legendOSKnum,
+QWidget#legendOSKnum QWidget {
+ background: transparent;
+}
+
+QWidget#contentDialog QLabel,
+QWidget#legendOSK QLabel,
+QWidget#legendOSKshift QLabel,
+QWidget#legendOSKnum QLabel {
+ color: rgba(255, 255, 255, 1);
+}
+
+QWidget#contentDialog QLabel#label_dialog {
+ padding: 20px 65px;
+}
+
+QWidget#contentDialog QLabel#label_title,
+QWidget#contentRichDialog QLabel#label_title_rich {
+ padding: 0px 65px;
+}
+
+QDialog#OverlayDialog QPushButton {
+ color: rgba(1, 253, 201, 1);
+ background: transparent;
+ border: none;
+ padding: 0px;
+ min-width: 0px;
+}
+
+QDialog#OverlayDialog QPushButton:focus,
+QDialog#OverlayDialog QPushButton:hover {
+ color: rgba(1, 253, 201, 1);
+ background: rgba(18, 33, 46, 1);
+ border: 5px solid rgba(56, 189, 225, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#OverlayDialog QPushButton:pressed {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(110, 122, 130, 1);
+ border: 5px solid rgba(56, 189, 225, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#QtSoftwareKeyboardDialog QLabel {
+ padding: 0px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton {
+ color: rgba(255, 255, 255, 1);
+ background: rgba(40, 51, 60, 1);
+ border: 2px solid rgba(31, 41, 51, 1);
+ border-radius: 0px;
+ padding: 0px;
+ min-width: 0px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
+ background: rgba(55, 66, 75, 1);
+ border: 2px solid rgba(31, 41, 51, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(255, 255, 255, 1);
+ border: 2px solid rgba(31, 41, 51, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
+ color: rgba(0, 0, 0, 1);
+ background: rgba(1, 253, 201, 1);
+ border: 2px solid rgba(31, 41, 51, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
+ color: rgba(255, 255, 255, 1);
+ background: rgba(18, 33, 46, 1);
+ border: 5px solid rgba(56, 189, 225, 1);
+ border-radius: 6px;
+ outline: none;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
+ color: rgba(240, 240, 240, 1);
+ background: rgba(110, 122, 130, 1);
+ border: 5px solid rgba(56, 189, 225, 1);
+ border-radius: 6px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_B_dark.png);
+ qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_Y_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
+ color: rgba(44, 44, 44, 1);
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_plus_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
+ background-position: left top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
+ background-position: left top;
+ background-repeat: no-repeat;
+ background-origin: content;
+ background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
+ qproperty-iconSize: 36px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
+ padding-bottom: 7px;
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
+ background: transparent;
+ color: #ccc;
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
+ image: url(:/overlay/button_L_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
+ image: url(:/overlay/arrow_left_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
+ image: url(:/overlay/button_R_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
+ image: url(:/overlay/arrow_right_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
+ image: url(:/overlay/button_press_stick_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
+ image: url(:/overlay/button_X_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
+QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
+ image: url(:/overlay/button_A_dark.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
+ color: rgba(144, 144, 144, 1);
+ background-color: rgba(55, 66, 75, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
+ color: rgba(144, 144, 144, 1);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
+ background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
+ background-image: url(:/overlay/osk_button_B_dark_disabled.png);
+}
+
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
+QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
+ background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
+}
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index c629bbc5c..891a47c3c 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -64,8 +64,8 @@ endif()
add_subdirectory(sirit)
# libzip
-find_package(Libzip 1.5)
-if (NOT LIBZIP_FOUND)
+find_package(libzip 1.5)
+if (NOT libzip_FOUND)
message(STATUS "libzip 1.5 or newer not found, falling back to externals")
add_subdirectory(libzip EXCLUDE_FROM_ALL)
endif()
@@ -97,4 +97,8 @@ if (ENABLE_WEB_SERVICE)
endif()
# Opus
-add_subdirectory(opus)
+find_package(opus 1.3)
+if (NOT opus_FOUND)
+ message(STATUS "opus 1.3 or newer not found, falling back to externals")
+ add_subdirectory(opus EXCLUDE_FROM_ALL)
+endif()
diff --git a/externals/dynarmic b/externals/dynarmic
-Subproject c28f13af9797c0319d9a38b5b5c8470ff906e2c
+Subproject b2a4da5e65985e6b0a20ac8ac37d14425a2a39d
diff --git a/externals/find-modules/FindLibzip.cmake b/externals/find-modules/FindLibzip.cmake
deleted file mode 100644
index f36b1687a..000000000
--- a/externals/find-modules/FindLibzip.cmake
+++ /dev/null
@@ -1,72 +0,0 @@
-
-find_package(PkgConfig QUIET)
-pkg_check_modules(PC_LIBZIP QUIET libzip)
-
-find_path(LIBZIP_INCLUDE_DIR
- NAMES zip.h
- PATHS ${PC_LIBZIP_INCLUDE_DIRS}
- "$ENV{LIB_DIR}/include"
- "$ENV{INCLUDE}"
- /usr/local/include
- /usr/include
-)
-find_path(LIBZIP_INCLUDE_DIR_ZIPCONF
- NAMES zipconf.h
- HINTS ${PC_LIBZIP_INCLUDE_DIRS}
- "$ENV{LIB_DIR}/include"
- "$ENV{LIB_DIR}/lib/libzip/include"
- "$ENV{LIB}/lib/libzip/include"
- /usr/local/lib/libzip/include
- /usr/lib/libzip/include
- /usr/local/include
- /usr/include
- "$ENV{INCLUDE}"
-)
-find_library(LIBZIP_LIBRARY
- NAMES zip
- PATHS ${PC_LIBZIP_LIBRARY_DIRS}
- "$ENV{LIB_DIR}/lib" "$ENV{LIB}" /usr/local/lib /usr/lib
-)
-
-if (LIBZIP_INCLUDE_DIR_ZIPCONF)
- FILE(READ "${LIBZIP_INCLUDE_DIR_ZIPCONF}/zipconf.h" _LIBZIP_VERSION_CONTENTS)
- if (_LIBZIP_VERSION_CONTENTS)
- STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9.]+)\".*" "\\1" LIBZIP_VERSION "${_LIBZIP_VERSION_CONTENTS}")
- endif()
- unset(_LIBZIP_VERSION_CONTENTS)
-endif()
-
-set(LIBZIP_VERSION ${LIBZIP_VERSION} CACHE STRING "Version number of libzip")
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Libzip
- FOUND_VAR LIBZIP_FOUND
- REQUIRED_VARS
- LIBZIP_LIBRARY
- LIBZIP_INCLUDE_DIR
- LIBZIP_INCLUDE_DIR_ZIPCONF
- LIBZIP_VERSION
- VERSION_VAR LIBZIP_VERSION
-)
-
-if(LIBZIP_FOUND)
- set(LIBZIP_LIBRARIES ${LIBZIP_LIBRARY})
- set(LIBZIP_INCLUDE_DIRS ${LIBZIP_INCLUDE_DIR})
- set(LIBZIP_DEFINITIONS ${PC_LIBZIP_CFLAGS_OTHER})
-endif()
-
-if(LIBZIP_FOUND AND NOT TARGET libzip::libzip)
- add_library(libzip::libzip UNKNOWN IMPORTED)
- set_target_properties(libzip::libzip PROPERTIES
- IMPORTED_LOCATION "${LIBZIP_LIBRARY}"
- INTERFACE_COMPILE_OPTIONS "${PC_LIBZIP_CFLAGS_OTHER}"
- INTERFACE_INCLUDE_DIRECTORIES "${LIBZIP_INCLUDE_DIR}"
- )
-endif()
-
-mark_as_advanced(
- LIBZIP_INCLUDE_DIR
- LIBZIP_INCLUDE_DIR_ZIPCONF
- LIBZIP_LIBRARY
- LIBZIP_VERSION
-)
diff --git a/externals/find-modules/Findlibzip.cmake b/externals/find-modules/Findlibzip.cmake
new file mode 100644
index 000000000..8934de3b8
--- /dev/null
+++ b/externals/find-modules/Findlibzip.cmake
@@ -0,0 +1,72 @@
+
+find_package(PkgConfig QUIET)
+pkg_check_modules(PC_libzip QUIET libzip)
+
+find_path(libzip_INCLUDE_DIR
+ NAMES zip.h
+ PATHS ${PC_libzip_INCLUDE_DIRS}
+ "$ENV{LIB_DIR}/include"
+ "$ENV{INCLUDE}"
+ /usr/local/include
+ /usr/include
+)
+find_path(libzip_INCLUDE_DIR_ZIPCONF
+ NAMES zipconf.h
+ HINTS ${PC_libzip_INCLUDE_DIRS}
+ "$ENV{LIB_DIR}/include"
+ "$ENV{LIB_DIR}/lib/libzip/include"
+ "$ENV{LIB}/lib/libzip/include"
+ /usr/local/lib/libzip/include
+ /usr/lib/libzip/include
+ /usr/local/include
+ /usr/include
+ "$ENV{INCLUDE}"
+)
+find_library(libzip_LIBRARY
+ NAMES zip
+ PATHS ${PC_libzip_LIBRARY_DIRS}
+ "$ENV{LIB_DIR}/lib" "$ENV{LIB}" /usr/local/lib /usr/lib
+)
+
+if (libzip_INCLUDE_DIR_ZIPCONF)
+ FILE(READ "${libzip_INCLUDE_DIR_ZIPCONF}/zipconf.h" _libzip_VERSION_CONTENTS)
+ if (_libzip_VERSION_CONTENTS)
+ STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9.]+)\".*" "\\1" libzip_VERSION "${_libzip_VERSION_CONTENTS}")
+ endif()
+ unset(_libzip_VERSION_CONTENTS)
+endif()
+
+set(libzip_VERSION ${libzip_VERSION} CACHE STRING "Version number of libzip")
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(libzip
+ FOUND_VAR libzip_FOUND
+ REQUIRED_VARS
+ libzip_LIBRARY
+ libzip_INCLUDE_DIR
+ libzip_INCLUDE_DIR_ZIPCONF
+ libzip_VERSION
+ VERSION_VAR libzip_VERSION
+)
+
+if(libzip_FOUND)
+ set(libzip_LIBRARIES ${libzip_LIBRARY})
+ set(libzip_INCLUDE_DIRS ${libzip_INCLUDE_DIR})
+ set(libzip_DEFINITIONS ${PC_libzip_CFLAGS_OTHER})
+endif()
+
+if(libzip_FOUND AND NOT TARGET libzip::libzip)
+ add_library(libzip::libzip UNKNOWN IMPORTED)
+ set_target_properties(libzip::libzip PROPERTIES
+ IMPORTED_LOCATION "${libzip_LIBRARY}"
+ INTERFACE_COMPILE_OPTIONS "${PC_libzip_CFLAGS_OTHER}"
+ INTERFACE_INCLUDE_DIRECTORIES "${libzip_INCLUDE_DIR}"
+ )
+endif()
+
+mark_as_advanced(
+ libzip_INCLUDE_DIR
+ libzip_INCLUDE_DIR_ZIPCONF
+ libzip_LIBRARY
+ libzip_VERSION
+)
diff --git a/externals/find-modules/Findopus.cmake b/externals/find-modules/Findopus.cmake
index de84bd995..2bce56122 100644
--- a/externals/find-modules/Findopus.cmake
+++ b/externals/find-modules/Findopus.cmake
@@ -28,7 +28,7 @@ if(opus_FOUND)
endif()
if(opus_FOUND AND NOT TARGET Opus::Opus)
- add_library(Opus::Opus UNKNOWN IMPORTED)
+ add_library(Opus::Opus UNKNOWN IMPORTED GLOBAL)
set_target_properties(Opus::Opus PROPERTIES
IMPORTED_LOCATION "${opus_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_opus_CFLAGS_OTHER}"
diff --git a/externals/opus/CMakeLists.txt b/externals/opus/CMakeLists.txt
index 94a86551f..16f5af9f2 100644
--- a/externals/opus/CMakeLists.txt
+++ b/externals/opus/CMakeLists.txt
@@ -252,3 +252,5 @@ PRIVATE
opus/silk/float
opus/src
)
+
+add_library(Opus::Opus ALIAS opus)
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 @@
#include "audio_core/sink_details.h"
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/settings.h"
+#include "common/settings.h"
namespace AudioCore {
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 @@
#include "audio_core/info_updater.h"
#include "audio_core/voice_context.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/memory.h"
-#include "core/settings.h"
namespace {
[[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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/ring_buffer.h"
-#include "core/settings.h"
+#include "common/settings.h"
#ifdef _WIN32
#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 @@
#include "audio_core/stream.h"
#include "common/assert.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core_timing.h"
-#include "core/settings.h"
namespace AudioCore {
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
add_library(common STATIC
algorithm.h
alignment.h
+ assert.cpp
assert.h
atomic_ops.h
detached_tasks.cpp
@@ -109,6 +110,7 @@ add_library(common STATIC
cityhash.h
common_funcs.h
common_paths.h
+ common_sizes.h
common_types.h
concepts.h
div_ceil.h
@@ -150,6 +152,10 @@ add_library(common STATIC
scm_rev.cpp
scm_rev.h
scope_exit.h
+ settings.cpp
+ settings.h
+ settings_input.cpp
+ settings_input.h
spin_lock.cpp
spin_lock.h
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/common_funcs.h"
+
+#include "common/settings.h"
+
+void assert_handle_failure() {
+ if (Settings::values.use_debug_asserts) {
+ Crash();
+ }
+}
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 @@
#pragma once
-#include <cstdlib>
-#include "common/common_funcs.h"
#include "common/logging/log.h"
+// Sometimes we want to try to continue even after hitting an assert.
+// However touching this file yields a global recompilation as this header is included almost
+// everywhere. So let's just move the handling of the failed assert to a single cpp file.
+void assert_handle_failure();
+
// For asserts we'd like to keep all the junk executed when an assert happens away from the
// important code in the function. One way of doing this is to put all the relevant code inside a
// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to
@@ -17,15 +20,14 @@
// enough for our purposes.
template <typename Fn>
#if defined(_MSC_VER)
-[[msvc::noinline, noreturn]]
+[[msvc::noinline]]
#elif defined(__GNUC__)
-[[gnu::cold, gnu::noinline, noreturn]]
+[[gnu::cold, gnu::noinline]]
#endif
static void
assert_noinline_call(const Fn& fn) {
fn();
- Crash();
- exit(1); // Keeps GCC's mouth shut about this actually returning
+ assert_handle_failure();
}
#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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <limits>
+
+#include "common/common_types.h"
+
+namespace Common {
+
+enum : u64 {
+ Size_1_KB = 0x400ULL,
+ Size_64_KB = 64ULL * Size_1_KB,
+ Size_128_KB = 128ULL * Size_1_KB,
+ Size_1_MB = 0x100000ULL,
+ Size_2_MB = 2ULL * Size_1_MB,
+ Size_4_MB = 4ULL * Size_1_MB,
+ Size_5_MB = 5ULL * Size_1_MB,
+ Size_14_MB = 14ULL * Size_1_MB,
+ Size_32_MB = 32ULL * Size_1_MB,
+ Size_33_MB = 33ULL * Size_1_MB,
+ Size_128_MB = 128ULL * Size_1_MB,
+ Size_448_MB = 448ULL * Size_1_MB,
+ Size_507_MB = 507ULL * Size_1_MB,
+ Size_562_MB = 562ULL * Size_1_MB,
+ Size_1554_MB = 1554ULL * Size_1_MB,
+ Size_2048_MB = 2048ULL * Size_1_MB,
+ Size_2193_MB = 2193ULL * Size_1_MB,
+ Size_3285_MB = 3285ULL * Size_1_MB,
+ Size_4916_MB = 4916ULL * Size_1_MB,
+ Size_1_GB = 0x40000000ULL,
+ Size_2_GB = 2ULL * Size_1_GB,
+ Size_4_GB = 4ULL * Size_1_GB,
+ Size_6_GB = 6ULL * Size_1_GB,
+ Size_8_GB = 8ULL * Size_1_GB,
+ Size_64_GB = 64ULL * Size_1_GB,
+ Size_512_GB = 512ULL * Size_1_GB,
+ Size_Invalid = std::numeric_limits<u64>::max(),
+};
+
+} // 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 @@
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "common/threadsafe_queue.h"
-#include "core/settings.h"
-namespace Log {
+namespace Common::Log {
/**
* Static state as a singleton.
@@ -37,8 +37,11 @@ public:
return backend;
}
- Impl(Impl const&) = delete;
- const Impl& operator=(Impl const&) = delete;
+ Impl(const Impl&) = delete;
+ Impl& operator=(const Impl&) = delete;
+
+ Impl(Impl&&) = delete;
+ Impl& operator=(Impl&&) = delete;
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, std::string message) {
@@ -132,7 +135,7 @@ private:
std::mutex writing_mutex;
std::thread backend_thread;
std::vector<std::unique_ptr<Backend>> backends;
- Common::MPSCQueue<Log::Entry> message_queue;
+ MPSCQueue<Entry> message_queue;
Filter filter;
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
};
@@ -146,16 +149,16 @@ void ColorConsoleBackend::Write(const Entry& entry) {
}
FileBackend::FileBackend(const std::string& filename) : bytes_written(0) {
- if (Common::FS::Exists(filename + ".old.txt")) {
- Common::FS::Delete(filename + ".old.txt");
+ if (FS::Exists(filename + ".old.txt")) {
+ FS::Delete(filename + ".old.txt");
}
- if (Common::FS::Exists(filename)) {
- Common::FS::Rename(filename, filename + ".old.txt");
+ if (FS::Exists(filename)) {
+ FS::Rename(filename, filename + ".old.txt");
}
// _SH_DENYWR allows read only access to the file for other programs.
// It is #defined to 0 on other platforms
- file = Common::FS::IOFile(filename, "w", _SH_DENYWR);
+ file = FS::IOFile(filename, "w", _SH_DENYWR);
}
void FileBackend::Write(const Entry& entry) {
@@ -182,7 +185,7 @@ void FileBackend::Write(const Entry& entry) {
void DebuggerBackend::Write(const Entry& entry) {
#ifdef _WIN32
- ::OutputDebugStringW(Common::UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
+ ::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
#endif
}
@@ -212,6 +215,7 @@ void DebuggerBackend::Write(const Entry& entry) {
SUB(Service, ARP) \
SUB(Service, BCAT) \
SUB(Service, BPC) \
+ SUB(Service, BGTC) \
SUB(Service, BTDRV) \
SUB(Service, BTM) \
SUB(Service, Capture) \
@@ -341,4 +345,4 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
instance.PushEntry(log_class, log_level, filename, line_num, function,
fmt::vformat(format, args));
}
-} // namespace Log
+} // 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 @@
#include "common/logging/filter.h"
#include "common/logging/log.h"
-namespace Log {
+namespace Common::Log {
class Filter;
@@ -135,4 +135,4 @@ const char* GetLevelName(Level log_level);
* never get the message
*/
void SetGlobalFilter(const Filter& filter);
-} // namespace Log \ No newline at end of file
+} // 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 @@
#include "common/logging/filter.h"
#include "common/string_util.h"
-namespace Log {
+namespace Common::Log {
namespace {
template <typename It>
Level GetLevelByName(const It begin, const It end) {
@@ -103,4 +103,4 @@ bool Filter::IsDebug() const {
});
}
-} // namespace Log
+} // 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 @@
#include <string_view>
#include "common/logging/log.h"
-namespace Log {
+namespace Common::Log {
/**
* Implements a log message filter which allows different log classes to have different minimum
@@ -51,4 +51,4 @@ public:
private:
std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels;
};
-} // namespace Log
+} // 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 @@
#include <fmt/format.h>
#include "common/common_types.h"
-namespace Log {
+namespace Common::Log {
// trims up to and including the last of ../, ..\, src/, src\ in a string
constexpr const char* TrimSourcePath(std::string_view source) {
@@ -66,6 +66,7 @@ enum class Class : ClassType {
Service_ARP, ///< The ARP service
Service_Audio, ///< The Audio (Audio control) service
Service_BCAT, ///< The BCAT service
+ Service_BGTC, ///< The BGTC (Background Task Controller) service
Service_BPC, ///< The BPC service
Service_BTDRV, ///< The Bluetooth driver service
Service_BTM, ///< The BTM service
@@ -147,28 +148,34 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig
fmt::make_format_args(args...));
}
-} // namespace Log
+} // namespace Common::Log
#ifdef _DEBUG
#define LOG_TRACE(log_class, ...) \
- ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, \
- ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
+ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Trace, \
+ Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
+ __VA_ARGS__)
#else
#define LOG_TRACE(log_class, fmt, ...) (void(0))
#endif
#define LOG_DEBUG(log_class, ...) \
- ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, \
- ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
+ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Debug, \
+ Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
+ __VA_ARGS__)
#define LOG_INFO(log_class, ...) \
- ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, \
- ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
+ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Info, \
+ Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
+ __VA_ARGS__)
#define LOG_WARNING(log_class, ...) \
- ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, \
- ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
+ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Warning, \
+ Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
+ __VA_ARGS__)
#define LOG_ERROR(log_class, ...) \
- ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, \
- ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
+ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Error, \
+ Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
+ __VA_ARGS__)
#define LOG_CRITICAL(log_class, ...) \
- ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, \
- ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__)
+ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Critical, \
+ Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \
+ __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 @@
#include "common/logging/text_formatter.h"
#include "common/string_util.h"
-namespace Log {
+namespace Common::Log {
std::string FormatLogMessage(const Entry& entry) {
unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
@@ -108,4 +108,4 @@ void PrintColoredMessage(const Entry& entry) {
#undef ESC
#endif
}
-} // namespace Log
+} // 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 @@
#include <cstddef>
#include <string>
-namespace Log {
+namespace Common::Log {
struct Entry;
@@ -17,4 +17,4 @@ std::string FormatLogMessage(const Entry& entry);
void PrintMessage(const Entry& entry);
/// Prints the same message as `PrintMessage`, but colored according to the severity level.
void PrintColoredMessage(const Entry& entry);
-} // namespace Log
+} // 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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
namespace Common {
/// 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 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,10 +7,7 @@
#include "common/assert.h"
#include "common/file_util.h"
#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hle/service/hid/hid.h"
-#include "core/settings.h"
-#include "video_core/renderer_base.h"
+#include "common/settings.h"
namespace Settings {
@@ -32,14 +29,6 @@ std::string GetTimeZoneString() {
return timezones[time_zone_index];
}
-void Apply(Core::System& system) {
- if (system.IsPoweredOn()) {
- system.Renderer().RefreshBaseSettings();
- }
-
- Service::HID::ReloadInputDevices();
-}
-
void LogSettings() {
const auto log_setting = [](std::string_view name, const auto& value) {
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 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -11,16 +11,13 @@
#include <optional>
#include <string>
#include <vector>
-#include "common/common_types.h"
-#include "input_common/settings.h"
-namespace Core {
-class System;
-}
+#include "common/common_types.h"
+#include "common/settings_input.h"
namespace Settings {
-enum class RendererBackend {
+enum class RendererBackend : u32 {
OpenGL = 0,
Vulkan = 1,
};
@@ -31,7 +28,7 @@ enum class GPUAccuracy : u32 {
Extreme = 2,
};
-enum class CPUAccuracy {
+enum class CPUAccuracy : u32 {
Accurate = 0,
Unsafe = 1,
DebugMode = 2,
@@ -139,6 +136,7 @@ struct Values {
Setting<int> vulkan_device;
Setting<u16> resolution_factor{1};
+ Setting<int> fullscreen_mode;
Setting<int> aspect_ratio;
Setting<int> max_anisotropy;
Setting<bool> use_frame_limit;
@@ -222,6 +220,8 @@ struct Values {
bool quest_flag;
bool disable_macro_jit;
bool extended_logging;
+ bool use_debug_asserts;
+ bool use_auto_stub;
// Miscellaneous
std::string log_filter;
@@ -253,7 +253,6 @@ float Volume();
std::string GetTimeZoneString();
-void Apply(Core::System& system);
void LogSettings();
// 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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "input_common/settings.h"
+#include "common/settings_input.h"
namespace Settings {
namespace 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 @@
#include <array>
#include <string>
+
#include "common/common_types.h"
namespace 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:
return true;
}
- T PopWait() {
+ void Wait() {
if (Empty()) {
std::unique_lock lock{cv_mutex};
cv.wait(lock, [this]() { return !Empty(); });
}
+ }
+
+ T PopWait() {
+ Wait();
T t;
Pop(t);
return t;
@@ -156,6 +160,10 @@ public:
return spsc_queue.Pop(t);
}
+ void Wait() {
+ spsc_queue.Wait();
+ }
+
T PopWait() {
return spsc_queue.PopWait();
}
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
hardware_interrupt_manager.h
hle/ipc.h
hle/ipc_helpers.h
+ hle/kernel/board/nintendo/nx/k_system_control.cpp
+ hle/kernel/board/nintendo/nx/k_system_control.h
+ hle/kernel/board/nintendo/nx/secure_monitor.h
hle/kernel/client_port.cpp
hle/kernel/client_port.h
hle/kernel/client_session.cpp
@@ -169,9 +172,13 @@ add_library(core STATIC
hle/kernel/k_memory_block.h
hle/kernel/k_memory_block_manager.cpp
hle/kernel/k_memory_block_manager.h
+ hle/kernel/k_memory_layout.cpp
+ hle/kernel/k_memory_layout.board.nintendo_nx.cpp
hle/kernel/k_memory_layout.h
hle/kernel/k_memory_manager.cpp
hle/kernel/k_memory_manager.h
+ hle/kernel/k_memory_region.h
+ hle/kernel/k_memory_region_type.h
hle/kernel/k_page_bitmap.h
hle/kernel/k_page_heap.cpp
hle/kernel/k_page_heap.h
@@ -196,11 +203,11 @@ add_library(core STATIC
hle/kernel/k_spin_lock.h
hle/kernel/k_synchronization_object.cpp
hle/kernel/k_synchronization_object.h
- hle/kernel/k_system_control.cpp
hle/kernel/k_system_control.h
hle/kernel/k_thread.cpp
hle/kernel/k_thread.h
hle/kernel/k_thread_queue.h
+ hle/kernel/k_trace.h
hle/kernel/k_writable_event.cpp
hle/kernel/k_writable_event.h
hle/kernel/kernel.cpp
@@ -266,6 +273,7 @@ add_library(core STATIC
hle/service/am/applets/profile_select.h
hle/service/am/applets/software_keyboard.cpp
hle/service/am/applets/software_keyboard.h
+ hle/service/am/applets/software_keyboard_types.h
hle/service/am/applets/web_browser.cpp
hle/service/am/applets/web_browser.h
hle/service/am/applets/web_types.h
@@ -614,8 +622,6 @@ add_library(core STATIC
perf_stats.h
reporter.cpp
reporter.h
- settings.cpp
- settings.h
telemetry_session.cpp
telemetry_session.h
tools/freezer.cpp
@@ -666,7 +672,7 @@ endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
-target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip)
+target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus zip)
if (YUZU_ENABLE_BOXCAT)
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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
+#include "common/settings.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
@@ -18,7 +19,6 @@
#include "core/core_timing.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
-#include "core/settings.h"
namespace Core {
@@ -114,18 +114,17 @@ public:
static constexpr u64 minimum_run_cycles = 1000U;
};
-std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table,
- std::size_t address_space_bits) const {
+std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
Dynarmic::A32::UserConfig config;
config.callbacks = cb.get();
- // TODO(bunnei): Implement page table for 32-bit
- // config.page_table = &page_table.pointers;
config.coprocessors[15] = cp15;
config.define_unpredictable_behaviour = true;
static constexpr std::size_t PAGE_BITS = 12;
static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
- config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
- page_table.pointers.data());
+ if (page_table) {
+ config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
+ page_table->pointers.data());
+ }
config.absolute_offset_page_table = true;
config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
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&
// Timing
config.wall_clock_cntpct = uses_wall_clock;
+ // Code cache size
+ config.code_cache_size = 512 * 1024 * 1024;
+ config.far_code_offset = 256 * 1024 * 1024;
+
// Safe optimizations
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
@@ -201,7 +204,8 @@ ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handle
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
cb(std::make_unique<DynarmicCallbacks32>(*this)),
cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index},
- exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
+ exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
+ jit(MakeJit(nullptr)) {}
ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
@@ -256,9 +260,6 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
- if (!jit) {
- return;
- }
Dynarmic::A32::Context context;
jit->SaveContext(context);
ctx.cpu_registers = context.Regs();
@@ -268,9 +269,6 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
}
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
- if (!jit) {
- return;
- }
Dynarmic::A32::Context context;
context.Regs() = ctx.cpu_registers;
context.ExtRegs() = ctx.extension_registers;
@@ -284,23 +282,14 @@ void ARM_Dynarmic_32::PrepareReschedule() {
}
void ARM_Dynarmic_32::ClearInstructionCache() {
- if (!jit) {
- return;
- }
jit->ClearCache();
}
void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
- if (!jit) {
- return;
- }
jit->InvalidateCacheRange(static_cast<u32>(addr), size);
}
void ARM_Dynarmic_32::ClearExclusiveState() {
- if (!jit) {
- return;
- }
jit->ClearExclusiveState();
}
@@ -316,7 +305,7 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
LoadContext(ctx);
return;
}
- jit = MakeJit(page_table, new_address_space_size_in_bits);
+ jit = MakeJit(&page_table);
LoadContext(ctx);
jit_cache.emplace(key, jit);
}
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:
std::size_t new_address_space_size_in_bits) override;
private:
- std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable& page_table,
- std::size_t address_space_bits) const;
+ std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =
@@ -80,10 +79,10 @@ private:
std::unique_ptr<DynarmicCallbacks32> cb;
JitCacheType jit_cache;
- std::shared_ptr<Dynarmic::A32::Jit> jit;
std::shared_ptr<DynarmicCP15> cp15;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
+ std::shared_ptr<Dynarmic::A32::Jit> jit;
};
} // 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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
+#include "common/settings.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
@@ -19,7 +20,6 @@
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
-#include "core/settings.h"
namespace Core {
@@ -142,7 +142,7 @@ public:
static constexpr u64 minimum_run_cycles = 1000U;
};
-std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table,
+std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const {
Dynarmic::A64::UserConfig config;
@@ -150,13 +150,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
config.callbacks = cb.get();
// Memory
- config.page_table = reinterpret_cast<void**>(page_table.pointers.data());
- config.page_table_address_space_bits = address_space_bits;
- config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
- config.silently_mirror_page_table = false;
- config.absolute_offset_page_table = true;
- config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
- config.only_detect_misalignment_via_page_table_on_page_boundary = true;
+ if (page_table) {
+ config.page_table = reinterpret_cast<void**>(page_table->pointers.data());
+ config.page_table_address_space_bits = address_space_bits;
+ config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
+ config.silently_mirror_page_table = false;
+ config.absolute_offset_page_table = true;
+ config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
+ config.only_detect_misalignment_via_page_table_on_page_boundary = true;
+ }
// Multi-process state
config.processor_id = core_index;
@@ -175,6 +177,10 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
// Timing
config.wall_clock_cntpct = uses_wall_clock;
+ // Code cache size
+ config.code_cache_size = 512 * 1024 * 1024;
+ config.far_code_offset = 256 * 1024 * 1024;
+
// Safe optimizations
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
@@ -237,7 +243,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
std::size_t core_index)
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
- exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
+ exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
+ jit(MakeJit(nullptr, 48)) {}
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
@@ -294,9 +301,6 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
- if (!jit) {
- return;
- }
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
@@ -308,9 +312,6 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
}
void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
- if (!jit) {
- return;
- }
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
@@ -326,23 +327,14 @@ void ARM_Dynarmic_64::PrepareReschedule() {
}
void ARM_Dynarmic_64::ClearInstructionCache() {
- if (!jit) {
- return;
- }
jit->ClearCache();
}
void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
- if (!jit) {
- return;
- }
jit->InvalidateCacheRange(addr, size);
}
void ARM_Dynarmic_64::ClearExclusiveState() {
- if (!jit) {
- return;
- }
jit->ClearExclusiveState();
}
@@ -358,7 +350,7 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
LoadContext(ctx);
return;
}
- jit = MakeJit(page_table, new_address_space_size_in_bits);
+ jit = MakeJit(&page_table, new_address_space_size_in_bits);
LoadContext(ctx);
jit_cache.emplace(key, jit);
}
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:
std::size_t new_address_space_size_in_bits) override;
private:
- std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table,
+ std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const;
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
@@ -71,10 +71,11 @@ private:
friend class DynarmicCallbacks64;
std::unique_ptr<DynarmicCallbacks64> cb;
JitCacheType jit_cache;
- std::shared_ptr<Dynarmic::A64::Jit> jit;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
+
+ std::shared_ptr<Dynarmic::A64::Jit> jit;
};
} // 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 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
@@ -36,6 +37,7 @@
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/manager.h"
+#include "core/hle/service/hid/hid.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/time/time_manager.h"
@@ -45,7 +47,6 @@
#include "core/network/network.h"
#include "core/perf_stats.h"
#include "core/reporter.h"
-#include "core/settings.h"
#include "core/telemetry_session.h"
#include "core/tools/freezer.h"
#include "video_core/renderer_base.h"
@@ -296,7 +297,7 @@ struct System::Impl {
exit_lock = false;
if (gpu_core) {
- gpu_core->WaitIdle();
+ gpu_core->ShutDown();
}
services.reset();
@@ -774,4 +775,12 @@ void System::ExecuteProgram(std::size_t program_index) {
}
}
+void System::ApplySettings() {
+ if (IsPoweredOn()) {
+ Renderer().RefreshBaseSettings();
+ }
+
+ Service::HID::ReloadInputDevices();
+}
+
} // 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:
*/
void ExecuteProgram(std::size_t program_index);
+ /// Applies any changes to settings to this core instance.
+ void ApplySettings();
+
private:
System();
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 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/key_manager.h"
@@ -32,7 +33,6 @@
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
-#include "core/settings.h"
namespace Core::Crypto {
namespace {
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 {
return raw.device_save_data_size;
}
+u32 NACP::GetParentalControlFlag() const {
+ return raw.parental_control;
+}
+
+const std::array<u8, 0x20>& NACP::GetRatingAge() const {
+ return raw.rating_age;
+}
+
std::vector<u8> NACP::GetRawBytes() const {
std::vector<u8> out(sizeof(RawNACP));
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:
std::vector<u8> GetRawBytes() const;
bool GetUserAccountSwitchLock() const;
u64 GetDeviceSaveDataSize() const;
+ u32 GetParentalControlFlag() const;
+ const std::array<u8, 0x20>& GetRatingAge() const;
private:
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 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
@@ -25,7 +26,6 @@
#include "core/loader/loader.h"
#include "core/loader/nso.h"
#include "core/memory/cheat_engine.h"
-#include "core/settings.h"
namespace FileSys {
namespace {
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/settings.h"
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/acc/profile_manager.h"
-#include "core/settings.h"
namespace Core::Frontend {
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 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/logging/backend.h"
+#include <thread>
+
+#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/frontend/applets/software_keyboard.h"
namespace Core::Frontend {
+
SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
-void DefaultSoftwareKeyboardApplet::RequestText(
- std::function<void(std::optional<std::u16string>)> out,
- SoftwareKeyboardParameters parameters) const {
- if (parameters.initial_text.empty())
- out(u"yuzu");
+DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
+
+void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
+ bool is_inline, KeyboardInitializeParameters initialize_parameters,
+ std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
+ std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+ submit_inline_callback_) {
+ if (is_inline) {
+ LOG_WARNING(
+ Service_AM,
+ "(STUBBED) called, backend requested to initialize the inline software keyboard.");
+
+ submit_inline_callback = std::move(submit_inline_callback_);
+ } else {
+ LOG_WARNING(
+ Service_AM,
+ "(STUBBED) called, backend requested to initialize the normal software keyboard.");
+
+ submit_normal_callback = std::move(submit_normal_callback_);
+ }
+
+ parameters = std::move(initialize_parameters);
+
+ LOG_INFO(Service_AM,
+ "\nKeyboardInitializeParameters:"
+ "\nok_text={}"
+ "\nheader_text={}"
+ "\nsub_text={}"
+ "\nguide_text={}"
+ "\ninitial_text={}"
+ "\nmax_text_length={}"
+ "\nmin_text_length={}"
+ "\ninitial_cursor_position={}"
+ "\ntype={}"
+ "\npassword_mode={}"
+ "\ntext_draw_type={}"
+ "\nkey_disable_flags={}"
+ "\nuse_blur_background={}"
+ "\nenable_backspace_button={}"
+ "\nenable_return_button={}"
+ "\ndisable_cancel_button={}",
+ Common::UTF16ToUTF8(parameters.ok_text), Common::UTF16ToUTF8(parameters.header_text),
+ Common::UTF16ToUTF8(parameters.sub_text), Common::UTF16ToUTF8(parameters.guide_text),
+ Common::UTF16ToUTF8(parameters.initial_text), parameters.max_text_length,
+ parameters.min_text_length, parameters.initial_cursor_position, parameters.type,
+ parameters.password_mode, parameters.text_draw_type, parameters.key_disable_flags.raw,
+ parameters.use_blur_background, parameters.enable_backspace_button,
+ parameters.enable_return_button, parameters.disable_cancel_button);
+}
+
+void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
+ LOG_WARNING(Service_AM,
+ "(STUBBED) called, backend requested to show the normal software keyboard.");
+
+ SubmitNormalText(u"yuzu");
+}
+
+void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
+ Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) const {
+ LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
+}
+
+void DefaultSoftwareKeyboardApplet::ShowInlineKeyboard(
+ InlineAppearParameters appear_parameters) const {
+ LOG_WARNING(Service_AM,
+ "(STUBBED) called, backend requested to show the inline software keyboard.");
+
+ LOG_INFO(Service_AM,
+ "\nInlineAppearParameters:"
+ "\nmax_text_length={}"
+ "\nmin_text_length={}"
+ "\nkey_top_scale_x={}"
+ "\nkey_top_scale_y={}"
+ "\nkey_top_translate_x={}"
+ "\nkey_top_translate_y={}"
+ "\ntype={}"
+ "\nkey_disable_flags={}"
+ "\nkey_top_as_floating={}"
+ "\nenable_backspace_button={}"
+ "\nenable_return_button={}"
+ "\ndisable_cancel_button={}",
+ appear_parameters.max_text_length, appear_parameters.min_text_length,
+ appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y,
+ appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y,
+ appear_parameters.type, appear_parameters.key_disable_flags.raw,
+ appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button,
+ appear_parameters.enable_return_button, appear_parameters.disable_cancel_button);
+
+ std::thread([this] { SubmitInlineText(u"yuzu"); }).detach();
+}
- out(parameters.initial_text);
+void DefaultSoftwareKeyboardApplet::HideInlineKeyboard() const {
+ LOG_WARNING(Service_AM,
+ "(STUBBED) called, backend requested to hide the inline software keyboard.");
}
-void DefaultSoftwareKeyboardApplet::SendTextCheckDialog(
- std::u16string error_message, std::function<void()> finished_check) const {
+void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_parameters) const {
LOG_WARNING(Service_AM,
- "(STUBBED) called - Default fallback software keyboard does not support text "
- "check! (error_message={})",
- Common::UTF16ToUTF8(error_message));
- finished_check();
+ "(STUBBED) called, backend requested to change the inline keyboard text.");
+
+ LOG_INFO(Service_AM,
+ "\nInlineTextParameters:"
+ "\ninput_text={}"
+ "\ncursor_position={}",
+ Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
+
+ submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
+ text_parameters.input_text, text_parameters.cursor_position);
+}
+
+void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
+ LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to exit the software keyboard.");
}
+
+void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
+ submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text);
+}
+
+void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+ for (std::size_t index = 0; index < text.size(); ++index) {
+ submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
+ std::u16string(text.data(), text.data() + index + 1),
+ static_cast<s32>(index) + 1);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(250));
+ }
+
+ submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text),
+ static_cast<s32>(text.size()));
+}
+
} // 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 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <functional>
-#include <optional>
-#include <string>
-#include "common/bit_field.h"
+#include <thread>
+
#include "common/common_types.h"
+#include "core/hle/service/am/applets/software_keyboard_types.h"
+
namespace Core::Frontend {
-struct SoftwareKeyboardParameters {
- std::u16string submit_text;
+
+struct KeyboardInitializeParameters {
+ std::u16string ok_text;
std::u16string header_text;
std::u16string sub_text;
std::u16string guide_text;
std::u16string initial_text;
- std::size_t max_length;
- bool password;
- bool cursor_at_beginning;
-
- union {
- u8 value;
-
- BitField<1, 1, u8> disable_space;
- BitField<2, 1, u8> disable_address;
- BitField<3, 1, u8> disable_percent;
- BitField<4, 1, u8> disable_slash;
- BitField<6, 1, u8> disable_number;
- BitField<7, 1, u8> disable_download_code;
- };
+ u32 max_text_length;
+ u32 min_text_length;
+ s32 initial_cursor_position;
+ Service::AM::Applets::SwkbdType type;
+ Service::AM::Applets::SwkbdPasswordMode password_mode;
+ Service::AM::Applets::SwkbdTextDrawType text_draw_type;
+ Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
+ bool use_blur_background;
+ bool enable_backspace_button;
+ bool enable_return_button;
+ bool disable_cancel_button;
+};
+
+struct InlineAppearParameters {
+ u32 max_text_length;
+ u32 min_text_length;
+ f32 key_top_scale_x;
+ f32 key_top_scale_y;
+ f32 key_top_translate_x;
+ f32 key_top_translate_y;
+ Service::AM::Applets::SwkbdType type;
+ Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
+ bool key_top_as_floating;
+ bool enable_backspace_button;
+ bool enable_return_button;
+ bool disable_cancel_button;
+};
+
+struct InlineTextParameters {
+ std::u16string input_text;
+ s32 cursor_position;
};
class SoftwareKeyboardApplet {
public:
virtual ~SoftwareKeyboardApplet();
- virtual void RequestText(std::function<void(std::optional<std::u16string>)> out,
- SoftwareKeyboardParameters parameters) const = 0;
- virtual void SendTextCheckDialog(std::u16string error_message,
- std::function<void()> finished_check) const = 0;
+ virtual void InitializeKeyboard(
+ bool is_inline, KeyboardInitializeParameters initialize_parameters,
+ std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
+ submit_normal_callback_,
+ std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+ submit_inline_callback_) = 0;
+
+ virtual void ShowNormalKeyboard() const = 0;
+
+ virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) const = 0;
+
+ virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;
+
+ virtual void HideInlineKeyboard() const = 0;
+
+ virtual void InlineTextChanged(InlineTextParameters text_parameters) const = 0;
+
+ virtual void ExitKeyboard() const = 0;
};
class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
public:
- void RequestText(std::function<void(std::optional<std::u16string>)> out,
- SoftwareKeyboardParameters parameters) const override;
- void SendTextCheckDialog(std::u16string error_message,
- std::function<void()> finished_check) const override;
+ ~DefaultSoftwareKeyboardApplet() override;
+
+ void InitializeKeyboard(
+ bool is_inline, KeyboardInitializeParameters initialize_parameters,
+ std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
+ submit_normal_callback_,
+ std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+ submit_inline_callback_) override;
+
+ void ShowNormalKeyboard() const override;
+
+ void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) const override;
+
+ void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override;
+
+ void HideInlineKeyboard() const override;
+
+ void InlineTextChanged(InlineTextParameters text_parameters) const override;
+
+ void ExitKeyboard() const override;
+
+private:
+ void SubmitNormalText(std::u16string text) const;
+ void SubmitInlineText(std::u16string_view text) const;
+
+ KeyboardInitializeParameters parameters;
+
+ mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
+ submit_normal_callback;
+ mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+ submit_inline_callback;
};
} // 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 @@
#include <cmath>
#include <mutex>
+#include "common/settings.h"
#include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
-#include "core/settings.h"
namespace Core::Frontend {
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 @@
#include <cmath>
#include "common/assert.h"
+#include "common/settings.h"
#include "core/frontend/framebuffer_layout.h"
-#include "core/settings.h"
namespace Layout {
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)
: npad{system.ServiceManager()
.GetService<Service::HID::Hid>("hid")
->GetAppletResource()
- ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {}
+ ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
+ ResetButtonStates();
+}
InputInterpreter::~InputInterpreter() = default;
@@ -25,6 +27,17 @@ void InputInterpreter::PollInput() {
button_states[current_index] = button_state;
}
+void InputInterpreter::ResetButtonStates() {
+ previous_index = 0;
+ current_index = 0;
+
+ button_states[0] = 0xFFFFFFFF;
+
+ for (std::size_t i = 1; i < button_states.size(); ++i) {
+ button_states[i] = 0;
+ }
+}
+
bool InputInterpreter::IsButtonPressed(HIDButton button) const {
return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0;
}
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:
/// Gets a button state from HID and inserts it into the array of button states.
void PollInput();
+ /// Resets all the button states to their defaults.
+ void ResetButtonStates();
+
/**
* Checks whether the button is pressed.
*
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// All architectures must define NumArchitectureDeviceRegions.
+constexpr inline const auto NumArchitectureDeviceRegions = 3;
+
+constexpr inline const auto KMemoryRegionType_Uart =
+ KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0);
+constexpr inline const auto KMemoryRegionType_InterruptCpuInterface =
+ KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+constexpr inline const auto KMemoryRegionType_InterruptDistributor =
+ KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+static_assert(KMemoryRegionType_Uart.GetValue() == (0x1D));
+static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() ==
+ (0x2D | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_InterruptDistributor.GetValue() ==
+ (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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// All architectures must define NumBoardDeviceRegions.
+constexpr inline const auto NumBoardDeviceRegions = 6;
+// UNUSED: .Derive(NumBoardDeviceRegions, 0);
+constexpr inline const auto KMemoryRegionType_MemoryController =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 1)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+constexpr inline const auto KMemoryRegionType_MemoryController1 =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 2)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+constexpr inline const auto KMemoryRegionType_MemoryController0 =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 3)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+constexpr inline const auto KMemoryRegionType_PowerManagementController =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 4).DeriveTransition();
+constexpr inline const auto KMemoryRegionType_LegacyLpsDevices =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 5);
+static_assert(KMemoryRegionType_MemoryController.GetValue() ==
+ (0x55 | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_MemoryController1.GetValue() ==
+ (0x65 | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_MemoryController0.GetValue() ==
+ (0x95 | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_PowerManagementController.GetValue() == (0x1A5));
+
+static_assert(KMemoryRegionType_LegacyLpsDevices.GetValue() == 0xC5);
+
+constexpr inline const auto NumLegacyLpsDevices = 7;
+constexpr inline const auto KMemoryRegionType_LegacyLpsExceptionVectors =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 0);
+constexpr inline const auto KMemoryRegionType_LegacyLpsIram =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 1);
+constexpr inline const auto KMemoryRegionType_LegacyLpsFlowController =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 2);
+constexpr inline const auto KMemoryRegionType_LegacyLpsPrimaryICtlr =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 3);
+constexpr inline const auto KMemoryRegionType_LegacyLpsSemaphore =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 4);
+constexpr inline const auto KMemoryRegionType_LegacyLpsAtomics =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 5);
+constexpr inline const auto KMemoryRegionType_LegacyLpsClkRst =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 6);
+static_assert(KMemoryRegionType_LegacyLpsExceptionVectors.GetValue() == 0x3C5);
+static_assert(KMemoryRegionType_LegacyLpsIram.GetValue() == 0x5C5);
+static_assert(KMemoryRegionType_LegacyLpsFlowController.GetValue() == 0x6C5);
+static_assert(KMemoryRegionType_LegacyLpsPrimaryICtlr.GetValue() == 0x9C5);
+static_assert(KMemoryRegionType_LegacyLpsSemaphore.GetValue() == 0xAC5);
+static_assert(KMemoryRegionType_LegacyLpsAtomics.GetValue() == 0xCC5);
+static_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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <random>
+
+#include "common/common_sizes.h"
+#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
+#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
+#include "core/hle/kernel/k_trace.h"
+
+namespace Kernel::Board::Nintendo::Nx {
+
+namespace impl {
+
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2238 * 4 * 1024;
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x710 * 4 * 1024;
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4 * 1024;
+
+} // namespace impl
+
+constexpr const std::size_t RequiredNonSecureSystemMemorySize =
+ impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices +
+ impl::RequiredNonSecureSystemMemorySizeMisc;
+
+namespace {
+
+u32 GetMemoryModeForInit() {
+ return 0x01;
+}
+
+u32 GetMemorySizeForInit() {
+ return 0;
+}
+
+Smc::MemoryArrangement GetMemoryArrangeForInit() {
+ switch (GetMemoryModeForInit() & 0x3F) {
+ case 0x01:
+ default:
+ return Smc::MemoryArrangement_4GB;
+ case 0x02:
+ return Smc::MemoryArrangement_4GBForAppletDev;
+ case 0x03:
+ return Smc::MemoryArrangement_4GBForSystemDev;
+ case 0x11:
+ return Smc::MemoryArrangement_6GB;
+ case 0x12:
+ return Smc::MemoryArrangement_6GBForAppletDev;
+ case 0x21:
+ return Smc::MemoryArrangement_8GB;
+ }
+}
+} // namespace
+
+// Initialization.
+size_t KSystemControl::Init::GetIntendedMemorySize() {
+ switch (GetMemorySizeForInit()) {
+ case Smc::MemorySize_4GB:
+ default: // All invalid modes should go to 4GB.
+ return Common::Size_4_GB;
+ case Smc::MemorySize_6GB:
+ return Common::Size_6_GB;
+ case Smc::MemorySize_8GB:
+ return Common::Size_8_GB;
+ }
+}
+
+PAddr KSystemControl::Init::GetKernelPhysicalBaseAddress(u64 base_address) {
+ return base_address;
+}
+
+bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
+ return true;
+}
+
+std::size_t KSystemControl::Init::GetApplicationPoolSize() {
+ // Get the base pool size.
+ const size_t base_pool_size = []() -> size_t {
+ switch (GetMemoryArrangeForInit()) {
+ case Smc::MemoryArrangement_4GB:
+ default:
+ return Common::Size_3285_MB;
+ case Smc::MemoryArrangement_4GBForAppletDev:
+ return Common::Size_2048_MB;
+ case Smc::MemoryArrangement_4GBForSystemDev:
+ return Common::Size_3285_MB;
+ case Smc::MemoryArrangement_6GB:
+ return Common::Size_4916_MB;
+ case Smc::MemoryArrangement_6GBForAppletDev:
+ return Common::Size_3285_MB;
+ case Smc::MemoryArrangement_8GB:
+ return Common::Size_4916_MB;
+ }
+ }();
+
+ // Return (possibly) adjusted size.
+ return base_pool_size;
+}
+
+size_t KSystemControl::Init::GetAppletPoolSize() {
+ // Get the base pool size.
+ const size_t base_pool_size = []() -> size_t {
+ switch (GetMemoryArrangeForInit()) {
+ case Smc::MemoryArrangement_4GB:
+ default:
+ return Common::Size_507_MB;
+ case Smc::MemoryArrangement_4GBForAppletDev:
+ return Common::Size_1554_MB;
+ case Smc::MemoryArrangement_4GBForSystemDev:
+ return Common::Size_448_MB;
+ case Smc::MemoryArrangement_6GB:
+ return Common::Size_562_MB;
+ case Smc::MemoryArrangement_6GBForAppletDev:
+ return Common::Size_2193_MB;
+ case Smc::MemoryArrangement_8GB:
+ return Common::Size_2193_MB;
+ }
+ }();
+
+ // Return (possibly) adjusted size.
+ constexpr size_t ExtraSystemMemoryForAtmosphere = Common::Size_33_MB;
+ return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
+}
+
+size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
+ // Verify that our minimum is at least as large as Nintendo's.
+ constexpr size_t MinimumSize = RequiredNonSecureSystemMemorySize;
+ static_assert(MinimumSize >= 0x29C8000);
+
+ return MinimumSize;
+}
+
+namespace {
+template <typename F>
+u64 GenerateUniformRange(u64 min, u64 max, F f) {
+ // Handle the case where the difference is too large to represent.
+ if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
+ return f();
+ }
+
+ // Iterate until we get a value in range.
+ const u64 range_size = ((max + 1) - min);
+ const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
+ while (true) {
+ if (const u64 rnd = f(); rnd < effective_max) {
+ return min + (rnd % range_size);
+ }
+ }
+}
+
+} // Anonymous namespace
+
+u64 KSystemControl::GenerateRandomU64() {
+ static std::random_device device;
+ static std::mt19937 gen(device());
+ static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
+ return distribution(gen);
+}
+
+u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
+ return GenerateUniformRange(min, max, GenerateRandomU64);
+}
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Kernel::Board::Nintendo::Nx {
+
+class KSystemControl {
+public:
+ class Init {
+ public:
+ // Initialization.
+ static std::size_t GetIntendedMemorySize();
+ static PAddr GetKernelPhysicalBaseAddress(u64 base_address);
+ static bool ShouldIncreaseThreadResourceLimit();
+ static std::size_t GetApplicationPoolSize();
+ static std::size_t GetAppletPoolSize();
+ static std::size_t GetMinimumNonSecureSystemPoolSize();
+ };
+
+ static u64 GenerateRandomRange(u64 min, u64 max);
+ static u64 GenerateRandomU64();
+};
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Kernel::Board::Nintendo::Nx::Smc {
+
+enum MemorySize {
+ MemorySize_4GB = 0,
+ MemorySize_6GB = 1,
+ MemorySize_8GB = 2,
+};
+
+enum MemoryArrangement {
+ MemoryArrangement_4GB = 0,
+ MemoryArrangement_4GBForAppletDev = 1,
+ MemoryArrangement_4GBForSystemDev = 2,
+ MemoryArrangement_6GB = 3,
+ MemoryArrangement_6GBForAppletDev = 4,
+ MemoryArrangement_8GB = 5,
+};
+
+} // 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_
if (incoming) {
// Populate the object lists with the data in the IPC request.
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
- copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
+ const u32 copy_handle{rp.Pop<Handle>()};
+ copy_handles.push_back(copy_handle);
+ copy_objects.push_back(handle_table.GetGeneric(copy_handle));
}
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
- move_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
+ const u32 move_handle{rp.Pop<Handle>()};
+ move_handles.push_back(move_handle);
+ move_objects.push_back(handle_table.GetGeneric(move_handle));
}
} else {
// 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:
/// Helper function to test whether the output buffer at buffer_index can be written
bool CanWriteBuffer(std::size_t buffer_index = 0) const;
+ Handle GetCopyHandle(std::size_t index) const {
+ return copy_handles.at(index);
+ }
+
+ Handle GetMoveHandle(std::size_t index) const {
+ return move_handles.at(index);
+ }
+
template <typename T>
std::shared_ptr<T> GetCopyObject(std::size_t index) {
return DynamicObjectCast<T>(copy_objects.at(index));
@@ -285,6 +293,8 @@ private:
std::shared_ptr<Kernel::ServerSession> server_session;
std::shared_ptr<KThread> thread;
// TODO(yuriks): Check common usage of this and optimize size accordingly
+ boost::container::small_vector<Handle, 8> move_handles;
+ boost::container::small_vector<Handle, 8> copy_handles;
boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
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 @@
#include <array>
#include "common/assert.h"
+#include "common/common_sizes.h"
#include "core/hle/kernel/k_address_space_info.h"
namespace Kernel {
namespace {
-enum : u64 {
- Size_1_MB = 0x100000,
- Size_2_MB = 2 * Size_1_MB,
- Size_128_MB = 128 * Size_1_MB,
- Size_1_GB = 0x40000000,
- Size_2_GB = 2 * Size_1_GB,
- Size_4_GB = 4 * Size_1_GB,
- Size_6_GB = 6 * Size_1_GB,
- Size_64_GB = 64 * Size_1_GB,
- Size_512_GB = 512 * Size_1_GB,
- Invalid = std::numeric_limits<u64>::max(),
-};
-
// clang-format off
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
- { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
- { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
- { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
- { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
- { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
- { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
- { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
- { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
- { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
- { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
- { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
- { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
- { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
+ { .bit_width = 32, .address = Common::Size_2_MB , .size = Common::Size_1_GB - Common::Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
+ { .bit_width = 32, .address = Common::Size_1_GB , .size = Common::Size_4_GB - Common::Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
+ { .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
+ { .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
+ { .bit_width = 36, .address = Common::Size_128_MB , .size = Common::Size_2_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
+ { .bit_width = 36, .address = Common::Size_2_GB , .size = Common::Size_64_GB - Common::Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
+ { .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
+ { .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
+ { .bit_width = 39, .address = Common::Size_128_MB , .size = Common::Size_512_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
+ { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
+ { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
+ { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
+ { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
}};
// clang-format on
constexpr bool IsAllowedIndexForAddress(std::size_t index) {
- return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid;
+ return index < AddressSpaceInfos.size() &&
+ AddressSpaceInfos[index].address != Common::Size_Invalid;
}
using 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/alignment.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_system_control.h"
+#include "core/hle/kernel/k_trace.h"
+
+namespace Kernel {
+
+namespace {
+
+constexpr size_t CarveoutAlignment = 0x20000;
+constexpr size_t CarveoutSizeMax = (512ULL * 1024 * 1024) - CarveoutAlignment;
+
+bool SetupPowerManagementControllerMemoryRegion(KMemoryLayout& memory_layout) {
+ // Above firmware 2.0.0, the PMC is not mappable.
+ return memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x7000E000, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap) &&
+ memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x7000E400, 0xC00,
+ KMemoryRegionType_PowerManagementController | KMemoryRegionAttr_NoUserMap);
+}
+
+void InsertPoolPartitionRegionIntoBothTrees(KMemoryLayout& memory_layout, size_t start, size_t size,
+ KMemoryRegionType phys_type,
+ KMemoryRegionType virt_type, u32& cur_attr) {
+ const u32 attr = cur_attr++;
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(start, size,
+ static_cast<u32>(phys_type), attr));
+ const KMemoryRegion* phys = memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
+ static_cast<u32>(phys_type), attr);
+ ASSERT(phys != nullptr);
+ ASSERT(phys->GetEndAddress() != 0);
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size,
+ static_cast<u32>(virt_type), attr));
+}
+
+} // namespace
+
+namespace Init {
+
+void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout) {
+ ASSERT(SetupPowerManagementControllerMemoryRegion(memory_layout));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x50041000, 0x1000,
+ KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x50042000, 0x1000,
+ KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
+
+ // Map IRAM unconditionally, to support debug-logging-to-iram build config.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x40000000, 0x40000, KMemoryRegionType_LegacyLpsIram | KMemoryRegionAttr_ShouldKernelMap));
+
+ // Above firmware 2.0.0, prevent mapping the bpmp exception vectors or the ipatch region.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
+}
+
+void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout) {
+ const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize();
+ const PAddr physical_memory_base_address =
+ KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress);
+
+ // Insert blocks into the tree.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ physical_memory_base_address, intended_memory_size, KMemoryRegionType_Dram));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ physical_memory_base_address, ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly));
+
+ // Insert the KTrace block at the end of Dram, if KTrace is enabled.
+ static_assert(!IsKTraceEnabled || KTraceBufferSize > 0);
+ if constexpr (IsKTraceEnabled) {
+ const PAddr ktrace_buffer_phys_addr =
+ physical_memory_base_address + intended_memory_size - KTraceBufferSize;
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ ktrace_buffer_phys_addr, KTraceBufferSize, KMemoryRegionType_KernelTraceBuffer));
+ }
+}
+
+void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout) {
+ // Start by identifying the extents of the DRAM memory region.
+ const auto dram_extents = memory_layout.GetMainMemoryPhysicalExtents();
+ ASSERT(dram_extents.GetEndAddress() != 0);
+
+ // Determine the end of the pool region.
+ const u64 pool_end = dram_extents.GetEndAddress() - KTraceBufferSize;
+
+ // Find the start of the kernel DRAM region.
+ const KMemoryRegion* kernel_dram_region =
+ memory_layout.GetPhysicalMemoryRegionTree().FindFirstDerived(
+ KMemoryRegionType_DramKernelBase);
+ ASSERT(kernel_dram_region != nullptr);
+
+ const u64 kernel_dram_start = kernel_dram_region->GetAddress();
+ ASSERT(Common::IsAligned(kernel_dram_start, CarveoutAlignment));
+
+ // Find the start of the pool partitions region.
+ const KMemoryRegion* pool_partitions_region =
+ memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
+ KMemoryRegionType_DramPoolPartition, 0);
+ ASSERT(pool_partitions_region != nullptr);
+ const u64 pool_partitions_start = pool_partitions_region->GetAddress();
+
+ // Setup the pool partition layouts.
+ // On 5.0.0+, setup modern 4-pool-partition layout.
+
+ // Get Application and Applet pool sizes.
+ const size_t application_pool_size = KSystemControl::Init::GetApplicationPoolSize();
+ const size_t applet_pool_size = KSystemControl::Init::GetAppletPoolSize();
+ const size_t unsafe_system_pool_min_size =
+ KSystemControl::Init::GetMinimumNonSecureSystemPoolSize();
+
+ // Decide on starting addresses for our pools.
+ const u64 application_pool_start = pool_end - application_pool_size;
+ const u64 applet_pool_start = application_pool_start - applet_pool_size;
+ const u64 unsafe_system_pool_start = std::min(
+ kernel_dram_start + CarveoutSizeMax,
+ Common::AlignDown(applet_pool_start - unsafe_system_pool_min_size, CarveoutAlignment));
+ const size_t unsafe_system_pool_size = applet_pool_start - unsafe_system_pool_start;
+
+ // We want to arrange application pool depending on where the middle of dram is.
+ const u64 dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2;
+ u32 cur_pool_attr = 0;
+ size_t total_overhead_size = 0;
+ if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) {
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, application_pool_start, application_pool_size,
+ KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
+ cur_pool_attr);
+ total_overhead_size +=
+ KMemoryManager::CalculateManagementOverheadSize(application_pool_size);
+ } else {
+ const size_t first_application_pool_size = dram_midpoint - application_pool_start;
+ const size_t second_application_pool_size =
+ application_pool_start + application_pool_size - dram_midpoint;
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, application_pool_start, first_application_pool_size,
+ KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
+ cur_pool_attr);
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, dram_midpoint, second_application_pool_size,
+ KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
+ cur_pool_attr);
+ total_overhead_size +=
+ KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size);
+ total_overhead_size +=
+ KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size);
+ }
+
+ // Insert the applet pool.
+ InsertPoolPartitionRegionIntoBothTrees(memory_layout, applet_pool_start, applet_pool_size,
+ KMemoryRegionType_DramAppletPool,
+ KMemoryRegionType_VirtualDramAppletPool, cur_pool_attr);
+ total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(applet_pool_size);
+
+ // Insert the nonsecure system pool.
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, unsafe_system_pool_start, unsafe_system_pool_size,
+ KMemoryRegionType_DramSystemNonSecurePool, KMemoryRegionType_VirtualDramSystemNonSecurePool,
+ cur_pool_attr);
+ total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(unsafe_system_pool_size);
+
+ // Insert the pool management region.
+ total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(
+ (unsafe_system_pool_start - pool_partitions_start) - total_overhead_size);
+ const u64 pool_management_start = unsafe_system_pool_start - total_overhead_size;
+ const size_t pool_management_size = total_overhead_size;
+ u32 pool_management_attr = 0;
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, pool_management_start, pool_management_size,
+ KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement,
+ pool_management_attr);
+
+ // Insert the system pool.
+ const u64 system_pool_size = pool_management_start - pool_partitions_start;
+ InsertPoolPartitionRegionIntoBothTrees(memory_layout, pool_partitions_start, system_pool_size,
+ KMemoryRegionType_DramSystemPool,
+ KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr);
+}
+
+} // namespace Init
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <array>
+
+#include "common/alignment.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_system_control.h"
+
+namespace Kernel {
+
+namespace {
+
+template <typename... Args>
+KMemoryRegion* AllocateRegion(KMemoryRegionAllocator& memory_region_allocator, Args&&... args) {
+ return memory_region_allocator.Allocate(std::forward<Args>(args)...);
+}
+
+} // namespace
+
+KMemoryRegionTree::KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_)
+ : memory_region_allocator{memory_region_allocator_} {}
+
+void KMemoryRegionTree::InsertDirectly(u64 address, u64 last_address, u32 attr, u32 type_id) {
+ this->insert(*AllocateRegion(memory_region_allocator, address, last_address, attr, type_id));
+}
+
+bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) {
+ // Locate the memory region that contains the address.
+ KMemoryRegion* found = this->FindModifiable(address);
+
+ // We require that the old attr is correct.
+ if (found->GetAttributes() != old_attr) {
+ return false;
+ }
+
+ // We further require that the region can be split from the old region.
+ const u64 inserted_region_end = address + size;
+ const u64 inserted_region_last = inserted_region_end - 1;
+ if (found->GetLastAddress() < inserted_region_last) {
+ return false;
+ }
+
+ // Further, we require that the type id is a valid transformation.
+ if (!found->CanDerive(type_id)) {
+ return false;
+ }
+
+ // Cache information from the region before we remove it.
+ const u64 old_address = found->GetAddress();
+ const u64 old_last = found->GetLastAddress();
+ const u64 old_pair = found->GetPairAddress();
+ const u32 old_type = found->GetType();
+
+ // Erase the existing region from the tree.
+ this->erase(this->iterator_to(*found));
+
+ // Insert the new region into the tree.
+ if (old_address == address) {
+ // Reuse the old object for the new region, if we can.
+ found->Reset(address, inserted_region_last, old_pair, new_attr, type_id);
+ this->insert(*found);
+ } else {
+ // If we can't re-use, adjust the old region.
+ found->Reset(old_address, address - 1, old_pair, old_attr, old_type);
+ this->insert(*found);
+
+ // Insert a new region for the split.
+ const u64 new_pair = (old_pair != std::numeric_limits<u64>::max())
+ ? old_pair + (address - old_address)
+ : old_pair;
+ this->insert(*AllocateRegion(memory_region_allocator, address, inserted_region_last,
+ new_pair, new_attr, type_id));
+ }
+
+ // If we need to insert a region after the region, do so.
+ if (old_last != inserted_region_last) {
+ const u64 after_pair = (old_pair != std::numeric_limits<u64>::max())
+ ? old_pair + (inserted_region_end - old_address)
+ : old_pair;
+ this->insert(*AllocateRegion(memory_region_allocator, inserted_region_end, old_last,
+ after_pair, old_attr, old_type));
+ }
+
+ return true;
+}
+
+VAddr KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id) {
+ // We want to find the total extents of the type id.
+ const auto extents = this->GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
+
+ // Ensure that our alignment is correct.
+ ASSERT(Common::IsAligned(extents.GetAddress(), alignment));
+
+ const u64 first_address = extents.GetAddress();
+ const u64 last_address = extents.GetLastAddress();
+
+ const u64 first_index = first_address / alignment;
+ const u64 last_index = last_address / alignment;
+
+ while (true) {
+ const u64 candidate =
+ KSystemControl::GenerateRandomRange(first_index, last_index) * alignment;
+
+ // Ensure that the candidate doesn't overflow with the size.
+ if (!(candidate < candidate + size)) {
+ continue;
+ }
+
+ const u64 candidate_last = candidate + size - 1;
+
+ // Ensure that the candidate fits within the region.
+ if (candidate_last > last_address) {
+ continue;
+ }
+
+ // Locate the candidate region, and ensure it fits and has the correct type id.
+ if (const auto& candidate_region = *this->Find(candidate);
+ !(candidate_last <= candidate_region.GetLastAddress() &&
+ candidate_region.GetType() == type_id)) {
+ continue;
+ }
+
+ return candidate;
+ }
+}
+
+KMemoryLayout::KMemoryLayout()
+ : virtual_tree{memory_region_allocator}, physical_tree{memory_region_allocator},
+ virtual_linear_tree{memory_region_allocator}, physical_linear_tree{memory_region_allocator} {}
+
+void KMemoryLayout::InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
+ VAddr linear_virtual_start) {
+ // Set static differences.
+ linear_phys_to_virt_diff = linear_virtual_start - aligned_linear_phys_start;
+ linear_virt_to_phys_diff = aligned_linear_phys_start - linear_virtual_start;
+
+ // Initialize linear trees.
+ for (auto& region : GetPhysicalMemoryRegionTree()) {
+ if (region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
+ GetPhysicalLinearMemoryRegionTree().InsertDirectly(
+ region.GetAddress(), region.GetLastAddress(), region.GetAttributes(),
+ region.GetType());
+ }
+ }
+
+ for (auto& region : GetVirtualMemoryRegionTree()) {
+ if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
+ GetVirtualLinearMemoryRegionTree().InsertDirectly(
+ region.GetAddress(), region.GetLastAddress(), region.GetAttributes(),
+ region.GetType());
+ }
+ }
+}
+
+size_t KMemoryLayout::GetResourceRegionSizeForInit() {
+ // Calculate resource region size based on whether we allow extra threads.
+ const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
+ size_t resource_region_size =
+ KernelResourceSize + (use_extra_resources ? KernelSlabHeapAdditionalSize : 0);
+
+ return resource_region_size;
+}
+
+} // 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 @@
-// Copyright 2020 yuzu Emulator Project
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
+#include <utility>
+
+#include "common/alignment.h"
+#include "common/common_sizes.h"
#include "common/common_types.h"
#include "core/device_memory.h"
+#include "core/hle/kernel/k_memory_region.h"
+#include "core/hle/kernel/k_memory_region_type.h"
+#include "core/hle/kernel/memory_types.h"
namespace Kernel {
-constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024;
+constexpr std::size_t L1BlockSize = Common::Size_1_GB;
+constexpr std::size_t L2BlockSize = Common::Size_2_MB;
+
+constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
+ return (Common::DivideUp(size, L1BlockSize) + Common::DivideUp(size, L2BlockSize)) * PageSize;
+}
+
+constexpr std::size_t MainMemorySize = Common::Size_4_GB;
+constexpr std::size_t MainMemorySizeMax = Common::Size_8_GB;
+
+constexpr std::size_t ReservedEarlyDramSize = 0x60000;
+constexpr std::size_t DramPhysicalAddress = 0x80000000;
+
+constexpr std::size_t KernelAslrAlignment = Common::Size_2_MB;
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
+
constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth;
constexpr std::size_t KernelVirtualAddressSpaceEnd =
KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment);
-constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1;
+constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1ULL;
constexpr std::size_t KernelVirtualAddressSpaceSize =
KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
+constexpr std::size_t KernelVirtualAddressCodeBase = KernelVirtualAddressSpaceBase;
+constexpr std::size_t KernelVirtualAddressCodeSize = 0x62000;
+constexpr std::size_t KernelVirtualAddressCodeEnd =
+ KernelVirtualAddressCodeBase + KernelVirtualAddressCodeSize;
+
+constexpr std::size_t KernelPhysicalAddressSpaceBase = 0ULL;
+constexpr std::size_t KernelPhysicalAddressSpaceEnd =
+ KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceWidth;
+constexpr std::size_t KernelPhysicalAddressSpaceLast = KernelPhysicalAddressSpaceEnd - 1ULL;
+constexpr std::size_t KernelPhysicalAddressSpaceSize =
+ KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase;
+constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
+
+constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
+constexpr std::size_t KernelInitialPageHeapSize = Common::Size_128_KB;
+
+constexpr std::size_t KernelSlabHeapDataSize = Common::Size_5_MB;
+constexpr std::size_t KernelSlabHeapGapsSize = Common::Size_2_MB - Common::Size_64_KB;
+constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
+
+// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
+constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000ULL;
+
+constexpr std::size_t KernelResourceSize =
+ KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
constexpr bool IsKernelAddressKey(VAddr key) {
return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
@@ -27,64 +73,327 @@ constexpr bool IsKernelAddress(VAddr address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
}
-class KMemoryRegion final {
- friend class KMemoryLayout;
-
+class KMemoryLayout final {
public:
- constexpr PAddr StartAddress() const {
- return start_address;
+ KMemoryLayout();
+
+ KMemoryRegionTree& GetVirtualMemoryRegionTree() {
+ return virtual_tree;
+ }
+ const KMemoryRegionTree& GetVirtualMemoryRegionTree() const {
+ return virtual_tree;
+ }
+ KMemoryRegionTree& GetPhysicalMemoryRegionTree() {
+ return physical_tree;
+ }
+ const KMemoryRegionTree& GetPhysicalMemoryRegionTree() const {
+ return physical_tree;
+ }
+ KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() {
+ return virtual_linear_tree;
+ }
+ const KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() const {
+ return virtual_linear_tree;
+ }
+ KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() {
+ return physical_linear_tree;
+ }
+ const KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() const {
+ return physical_linear_tree;
+ }
+
+ VAddr GetLinearVirtualAddress(PAddr address) const {
+ return address + linear_phys_to_virt_diff;
+ }
+ PAddr GetLinearPhysicalAddress(VAddr address) const {
+ return address + linear_virt_to_phys_diff;
+ }
+
+ const KMemoryRegion* FindVirtual(VAddr address) const {
+ return Find(address, GetVirtualMemoryRegionTree());
+ }
+ const KMemoryRegion* FindPhysical(PAddr address) const {
+ return Find(address, GetPhysicalMemoryRegionTree());
+ }
+
+ const KMemoryRegion* FindVirtualLinear(VAddr address) const {
+ return Find(address, GetVirtualLinearMemoryRegionTree());
+ }
+ const KMemoryRegion* FindPhysicalLinear(PAddr address) const {
+ return Find(address, GetPhysicalLinearMemoryRegionTree());
+ }
+
+ VAddr GetMainStackTopAddress(s32 core_id) const {
+ return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack);
+ }
+ VAddr GetIdleStackTopAddress(s32 core_id) const {
+ return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack);
+ }
+ VAddr GetExceptionStackTopAddress(s32 core_id) const {
+ return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
+ }
+
+ VAddr GetSlabRegionAddress() const {
+ return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
+ .GetAddress();
+ }
+
+ const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
+ return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
+ }
+ PAddr GetDevicePhysicalAddress(KMemoryRegionType type) const {
+ return GetDeviceRegion(type).GetAddress();
+ }
+ VAddr GetDeviceVirtualAddress(KMemoryRegionType type) const {
+ return GetDeviceRegion(type).GetPairAddress();
+ }
+
+ const KMemoryRegion& GetPoolManagementRegion() const {
+ return Dereference(
+ GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramPoolManagement));
+ }
+ const KMemoryRegion& GetPageTableHeapRegion() const {
+ return Dereference(
+ GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelPtHeap));
+ }
+ const KMemoryRegion& GetKernelStackRegion() const {
+ return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelStack));
+ }
+ const KMemoryRegion& GetTempRegion() const {
+ return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelTemp));
+ }
+
+ const KMemoryRegion& GetKernelTraceBufferRegion() const {
+ return Dereference(GetVirtualLinearMemoryRegionTree().FindByType(
+ KMemoryRegionType_VirtualDramKernelTraceBuffer));
+ }
+
+ const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
+ return Dereference(FindVirtualLinear(address));
+ }
+
+ const KMemoryRegion* GetPhysicalKernelTraceBufferRegion() const {
+ return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_KernelTraceBuffer);
+ }
+ const KMemoryRegion* GetPhysicalOnMemoryBootImageRegion() const {
+ return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_OnMemoryBootImage);
+ }
+ const KMemoryRegion* GetPhysicalDTBRegion() const {
+ return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB);
+ }
+
+ bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
+ return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
+ KMemoryRegionType_DramUserPool);
+ }
+ bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address) const {
+ return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(),
+ KMemoryRegionType_VirtualDramUserPool);
+ }
+
+ bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address, size_t size) const {
+ return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
+ KMemoryRegionType_DramUserPool);
+ }
+ bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address, size_t size) const {
+ return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(),
+ KMemoryRegionType_VirtualDramUserPool);
+ }
+
+ bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
+ return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
+ static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
+ }
+ bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address,
+ size_t size) const {
+ return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
+ static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
+ }
+
+ std::pair<size_t, size_t> GetTotalAndKernelMemorySizes() const {
+ size_t total_size = 0, kernel_size = 0;
+ for (const auto& region : GetPhysicalMemoryRegionTree()) {
+ if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
+ total_size += region.GetSize();
+ if (!region.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
+ kernel_size += region.GetSize();
+ }
+ }
+ }
+ return std::make_pair(total_size, kernel_size);
+ }
+
+ void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
+ VAddr linear_virtual_start);
+ static size_t GetResourceRegionSizeForInit();
+
+ auto GetKernelRegionExtents() const {
+ return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel);
+ }
+ auto GetKernelCodeRegionExtents() const {
+ return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode);
+ }
+ auto GetKernelStackRegionExtents() const {
+ return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelStack);
+ }
+ auto GetKernelMiscRegionExtents() const {
+ return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelMisc);
+ }
+ auto GetKernelSlabRegionExtents() const {
+ return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelSlab);
+ }
+
+ auto GetLinearRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionAttr_LinearMapped);
+ }
+
+ auto GetLinearRegionVirtualExtents() const {
+ const auto physical = GetLinearRegionPhysicalExtents();
+ return KMemoryRegion(GetLinearVirtualAddress(physical.GetAddress()),
+ GetLinearVirtualAddress(physical.GetLastAddress()), 0,
+ KMemoryRegionType_None);
+ }
+
+ auto GetMainMemoryPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Dram);
+ }
+ auto GetCarveoutRegionExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionAttr_CarveoutProtected);
+ }
+
+ auto GetKernelRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramKernelBase);
+ }
+ auto GetKernelCodeRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramKernelCode);
+ }
+ auto GetKernelSlabRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramKernelSlab);
+ }
+ auto GetKernelPageTableHeapRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramKernelPtHeap);
+ }
+ auto GetKernelInitPageTableRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramKernelInitPt);
+ }
+
+ auto GetKernelPoolManagementRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramPoolManagement);
+ }
+ auto GetKernelPoolPartitionRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramPoolPartition);
+ }
+ auto GetKernelSystemPoolRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramSystemPool);
+ }
+ auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramSystemNonSecurePool);
+ }
+ auto GetKernelAppletPoolRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramAppletPool);
+ }
+ auto GetKernelApplicationPoolRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_DramApplicationPool);
}
- constexpr PAddr EndAddress() const {
- return end_address;
+ auto GetKernelTraceBufferRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_KernelTraceBuffer);
}
private:
- constexpr KMemoryRegion() = default;
- constexpr KMemoryRegion(PAddr start_address, PAddr end_address)
- : start_address{start_address}, end_address{end_address} {}
+ template <typename AddressType>
+ static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address,
+ const KMemoryRegionTree& tree, KMemoryRegionType type) {
+ // Check if the cached region already contains the address.
+ if (region != nullptr && region->Contains(address)) {
+ return true;
+ }
- const PAddr start_address{};
- const PAddr end_address{};
-};
+ // Find the containing region, and update the cache.
+ if (const KMemoryRegion* found = tree.Find(address);
+ found != nullptr && found->IsDerivedFrom(type)) {
+ region = found;
+ return true;
+ } else {
+ return false;
+ }
+ }
-class KMemoryLayout final {
-public:
- constexpr const KMemoryRegion& Application() const {
- return application;
+ template <typename AddressType>
+ static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address, size_t size,
+ const KMemoryRegionTree& tree, KMemoryRegionType type) {
+ // Get the end of the checked region.
+ const u64 last_address = address + size - 1;
+
+ // Walk the tree to verify the region is correct.
+ const KMemoryRegion* cur =
+ (region != nullptr && region->Contains(address)) ? region : tree.Find(address);
+ while (cur != nullptr && cur->IsDerivedFrom(type)) {
+ if (last_address <= cur->GetLastAddress()) {
+ region = cur;
+ return true;
+ }
+
+ cur = cur->GetNext();
+ }
+ return false;
}
- constexpr const KMemoryRegion& Applet() const {
- return applet;
+ template <typename AddressType>
+ static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
+ return tree.Find(address);
}
- constexpr const KMemoryRegion& System() const {
- return system;
+ static KMemoryRegion& Dereference(KMemoryRegion* region) {
+ ASSERT(region != nullptr);
+ return *region;
}
- static constexpr KMemoryLayout GetDefaultLayout() {
- constexpr std::size_t application_size{0xcd500000};
- constexpr std::size_t applet_size{0x1fb00000};
- constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size};
- constexpr PAddr application_end_address{Core::DramMemoryMap::End};
- constexpr PAddr applet_start_address{application_start_address - applet_size};
- constexpr PAddr applet_end_address{applet_start_address + applet_size};
- constexpr PAddr system_start_address{Core::DramMemoryMap::SlabHeapEnd};
- constexpr PAddr system_end_address{applet_start_address};
- return {application_start_address, application_end_address, applet_start_address,
- applet_end_address, system_start_address, system_end_address};
+ static const KMemoryRegion& Dereference(const KMemoryRegion* region) {
+ ASSERT(region != nullptr);
+ return *region;
+ }
+
+ VAddr GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
+ const auto& region = Dereference(
+ GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
+ ASSERT(region.GetEndAddress() != 0);
+ return region.GetEndAddress();
}
private:
- constexpr KMemoryLayout(PAddr application_start_address, std::size_t application_size,
- PAddr applet_start_address, std::size_t applet_size,
- PAddr system_start_address, std::size_t system_size)
- : application{application_start_address, application_size},
- applet{applet_start_address, applet_size}, system{system_start_address, system_size} {}
-
- const KMemoryRegion application;
- const KMemoryRegion applet;
- const KMemoryRegion system;
+ u64 linear_phys_to_virt_diff{};
+ u64 linear_virt_to_phys_diff{};
+ KMemoryRegionAllocator memory_region_allocator;
+ KMemoryRegionTree virtual_tree;
+ KMemoryRegionTree physical_tree;
+ KMemoryRegionTree virtual_linear_tree;
+ KMemoryRegionTree physical_linear_tree;
};
+namespace Init {
+
+// These should be generic, regardless of board.
+void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout);
+
+// These may be implemented in a board-specific manner.
+void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout);
+void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout);
+
+} // namespace Init
+
} // 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
return RESULT_SUCCESS;
}
+std::size_t KMemoryManager::Impl::CalculateManagementOverheadSize(std::size_t region_size) {
+ const std::size_t ref_count_size = (region_size / PageSize) * sizeof(u16);
+ const std::size_t optimize_map_size =
+ (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
+ Common::BitSize<u64>()) *
+ sizeof(u64);
+ const std::size_t manager_meta_size =
+ Common::AlignUp(optimize_map_size + ref_count_size, PageSize);
+ const std::size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region_size);
+ return manager_meta_size + page_heap_size;
+}
+
} // 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:
Shift = 4,
Mask = (0xF << Shift),
+
+ // Aliases.
+ Unsafe = Application,
+ Secure = System,
};
enum class Direction : u32 {
@@ -56,6 +60,10 @@ public:
static constexpr std::size_t MaxManagerCount = 10;
public:
+ static std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
+ return Impl::CalculateManagementOverheadSize(region_size);
+ }
+
static constexpr u32 EncodeOption(Pool pool, Direction dir) {
return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) |
(static_cast<u32>(dir) << static_cast<u32>(Direction::Shift));
@@ -86,6 +94,16 @@ private:
Pool pool{};
public:
+ static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
+
+ static constexpr std::size_t CalculateOptimizedProcessOverheadSize(
+ std::size_t region_size) {
+ return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
+ Common::BitSize<u64>()) *
+ sizeof(u64);
+ }
+
+ public:
Impl() = default;
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/intrusive_red_black_tree.h"
+#include "core/hle/kernel/k_memory_region_type.h"
+
+namespace Kernel {
+
+class KMemoryRegionAllocator;
+
+class KMemoryRegion final : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryRegion>,
+ NonCopyable {
+ friend class KMemoryRegionTree;
+
+public:
+ constexpr KMemoryRegion() = default;
+ constexpr KMemoryRegion(u64 address_, u64 last_address_)
+ : address{address_}, last_address{last_address_} {}
+ constexpr KMemoryRegion(u64 address_, u64 last_address_, u64 pair_address_, u32 attributes_,
+ u32 type_id_)
+ : address(address_), last_address(last_address_), pair_address(pair_address_),
+ attributes(attributes_), type_id(type_id_) {}
+ constexpr KMemoryRegion(u64 address_, u64 last_address_, u32 attributes_, u32 type_id_)
+ : KMemoryRegion(address_, last_address_, std::numeric_limits<u64>::max(), attributes_,
+ type_id_) {}
+
+ static constexpr int Compare(const KMemoryRegion& lhs, const KMemoryRegion& rhs) {
+ if (lhs.GetAddress() < rhs.GetAddress()) {
+ return -1;
+ } else if (lhs.GetAddress() <= rhs.GetLastAddress()) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+private:
+ constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
+ address = a;
+ pair_address = p;
+ last_address = la;
+ attributes = r;
+ type_id = t;
+ }
+
+public:
+ constexpr u64 GetAddress() const {
+ return address;
+ }
+
+ constexpr u64 GetPairAddress() const {
+ return pair_address;
+ }
+
+ constexpr u64 GetLastAddress() const {
+ return last_address;
+ }
+
+ constexpr u64 GetEndAddress() const {
+ return this->GetLastAddress() + 1;
+ }
+
+ constexpr size_t GetSize() const {
+ return this->GetEndAddress() - this->GetAddress();
+ }
+
+ constexpr u32 GetAttributes() const {
+ return attributes;
+ }
+
+ constexpr u32 GetType() const {
+ return type_id;
+ }
+
+ constexpr void SetType(u32 type) {
+ ASSERT(this->CanDerive(type));
+ type_id = type;
+ }
+
+ constexpr bool Contains(u64 address) const {
+ ASSERT(this->GetEndAddress() != 0);
+ return this->GetAddress() <= address && address <= this->GetLastAddress();
+ }
+
+ constexpr bool IsDerivedFrom(u32 type) const {
+ return (this->GetType() | type) == this->GetType();
+ }
+
+ constexpr bool HasTypeAttribute(u32 attr) const {
+ return (this->GetType() | attr) == this->GetType();
+ }
+
+ constexpr bool CanDerive(u32 type) const {
+ return (this->GetType() | type) == type;
+ }
+
+ constexpr void SetPairAddress(u64 a) {
+ pair_address = a;
+ }
+
+ constexpr void SetTypeAttribute(u32 attr) {
+ type_id |= attr;
+ }
+
+private:
+ u64 address{};
+ u64 last_address{};
+ u64 pair_address{};
+ u32 attributes{};
+ u32 type_id{};
+};
+
+class KMemoryRegionTree final : NonCopyable {
+public:
+ struct DerivedRegionExtents {
+ const KMemoryRegion* first_region{};
+ const KMemoryRegion* last_region{};
+
+ constexpr DerivedRegionExtents() = default;
+
+ constexpr u64 GetAddress() const {
+ return this->first_region->GetAddress();
+ }
+
+ constexpr u64 GetLastAddress() const {
+ return this->last_region->GetLastAddress();
+ }
+
+ constexpr u64 GetEndAddress() const {
+ return this->GetLastAddress() + 1;
+ }
+
+ constexpr size_t GetSize() const {
+ return this->GetEndAddress() - this->GetAddress();
+ }
+ };
+
+private:
+ using TreeType =
+ Common::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>;
+
+public:
+ using value_type = TreeType::value_type;
+ using size_type = TreeType::size_type;
+ using difference_type = TreeType::difference_type;
+ using pointer = TreeType::pointer;
+ using const_pointer = TreeType::const_pointer;
+ using reference = TreeType::reference;
+ using const_reference = TreeType::const_reference;
+ using iterator = TreeType::iterator;
+ using const_iterator = TreeType::const_iterator;
+
+private:
+ TreeType m_tree{};
+ KMemoryRegionAllocator& memory_region_allocator;
+
+public:
+ explicit KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_);
+
+public:
+ KMemoryRegion* FindModifiable(u64 address) {
+ if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->end()) {
+ return std::addressof(*it);
+ } else {
+ return nullptr;
+ }
+ }
+
+ const KMemoryRegion* Find(u64 address) const {
+ if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->cend()) {
+ return std::addressof(*it);
+ } else {
+ return nullptr;
+ }
+ }
+
+ const KMemoryRegion* FindByType(KMemoryRegionType type_id) const {
+ for (auto it = this->cbegin(); it != this->cend(); ++it) {
+ if (it->GetType() == static_cast<u32>(type_id)) {
+ return std::addressof(*it);
+ }
+ }
+ return nullptr;
+ }
+
+ const KMemoryRegion* FindByTypeAndAttribute(u32 type_id, u32 attr) const {
+ for (auto it = this->cbegin(); it != this->cend(); ++it) {
+ if (it->GetType() == type_id && it->GetAttributes() == attr) {
+ return std::addressof(*it);
+ }
+ }
+ return nullptr;
+ }
+
+ const KMemoryRegion* FindFirstDerived(KMemoryRegionType type_id) const {
+ for (auto it = this->cbegin(); it != this->cend(); it++) {
+ if (it->IsDerivedFrom(type_id)) {
+ return std::addressof(*it);
+ }
+ }
+ return nullptr;
+ }
+
+ const KMemoryRegion* FindLastDerived(KMemoryRegionType type_id) const {
+ const KMemoryRegion* region = nullptr;
+ for (auto it = this->begin(); it != this->end(); it++) {
+ if (it->IsDerivedFrom(type_id)) {
+ region = std::addressof(*it);
+ }
+ }
+ return region;
+ }
+
+ DerivedRegionExtents GetDerivedRegionExtents(KMemoryRegionType type_id) const {
+ DerivedRegionExtents extents;
+
+ ASSERT(extents.first_region == nullptr);
+ ASSERT(extents.last_region == nullptr);
+
+ for (auto it = this->cbegin(); it != this->cend(); it++) {
+ if (it->IsDerivedFrom(type_id)) {
+ if (extents.first_region == nullptr) {
+ extents.first_region = std::addressof(*it);
+ }
+ extents.last_region = std::addressof(*it);
+ }
+ }
+
+ ASSERT(extents.first_region != nullptr);
+ ASSERT(extents.last_region != nullptr);
+
+ return extents;
+ }
+
+ DerivedRegionExtents GetDerivedRegionExtents(u32 type_id) const {
+ return GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
+ }
+
+public:
+ void InsertDirectly(u64 address, u64 last_address, u32 attr = 0, u32 type_id = 0);
+ bool Insert(u64 address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0);
+
+ VAddr GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);
+
+ VAddr GetRandomAlignedRegionWithGuard(size_t size, size_t alignment, u32 type_id,
+ size_t guard_size) {
+ return this->GetRandomAlignedRegion(size + 2 * guard_size, alignment, type_id) + guard_size;
+ }
+
+public:
+ // Iterator accessors.
+ iterator begin() {
+ return m_tree.begin();
+ }
+
+ const_iterator begin() const {
+ return m_tree.begin();
+ }
+
+ iterator end() {
+ return m_tree.end();
+ }
+
+ const_iterator end() const {
+ return m_tree.end();
+ }
+
+ const_iterator cbegin() const {
+ return this->begin();
+ }
+
+ const_iterator cend() const {
+ return this->end();
+ }
+
+ iterator iterator_to(reference ref) {
+ return m_tree.iterator_to(ref);
+ }
+
+ const_iterator iterator_to(const_reference ref) const {
+ return m_tree.iterator_to(ref);
+ }
+
+ // Content management.
+ bool empty() const {
+ return m_tree.empty();
+ }
+
+ reference back() {
+ return m_tree.back();
+ }
+
+ const_reference back() const {
+ return m_tree.back();
+ }
+
+ reference front() {
+ return m_tree.front();
+ }
+
+ const_reference front() const {
+ return m_tree.front();
+ }
+
+ iterator insert(reference ref) {
+ return m_tree.insert(ref);
+ }
+
+ iterator erase(iterator it) {
+ return m_tree.erase(it);
+ }
+
+ iterator find(const_reference ref) const {
+ return m_tree.find(ref);
+ }
+
+ iterator nfind(const_reference ref) const {
+ return m_tree.nfind(ref);
+ }
+};
+
+class KMemoryRegionAllocator final : NonCopyable {
+public:
+ static constexpr size_t MaxMemoryRegions = 200;
+
+ constexpr KMemoryRegionAllocator() = default;
+
+ template <typename... Args>
+ KMemoryRegion* Allocate(Args&&... args) {
+ // Ensure we stay within the bounds of our heap.
+ ASSERT(this->num_regions < MaxMemoryRegions);
+
+ // Create the new region.
+ KMemoryRegion* region = std::addressof(this->region_heap[this->num_regions++]);
+ new (region) KMemoryRegion(std::forward<Args>(args)...);
+
+ return region;
+ }
+
+private:
+ std::array<KMemoryRegion, MaxMemoryRegions> region_heap{};
+ size_t num_regions{};
+};
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/bit_util.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+#define ARCH_ARM64
+#define BOARD_NINTENDO_NX
+
+namespace Kernel {
+
+enum KMemoryRegionType : u32 {
+ KMemoryRegionAttr_CarveoutProtected = 0x04000000,
+ KMemoryRegionAttr_DidKernelMap = 0x08000000,
+ KMemoryRegionAttr_ShouldKernelMap = 0x10000000,
+ KMemoryRegionAttr_UserReadOnly = 0x20000000,
+ KMemoryRegionAttr_NoUserMap = 0x40000000,
+ KMemoryRegionAttr_LinearMapped = 0x80000000,
+};
+DECLARE_ENUM_FLAG_OPERATORS(KMemoryRegionType);
+
+namespace impl {
+
+constexpr size_t BitsForDeriveSparse(size_t n) {
+ return n + 1;
+}
+
+constexpr size_t BitsForDeriveDense(size_t n) {
+ size_t low = 0, high = 1;
+ for (size_t i = 0; i < n - 1; ++i) {
+ if ((++low) == high) {
+ ++high;
+ low = 0;
+ }
+ }
+ return high + 1;
+}
+
+class KMemoryRegionTypeValue {
+public:
+ using ValueType = std::underlying_type_t<KMemoryRegionType>;
+
+ constexpr KMemoryRegionTypeValue() = default;
+
+ constexpr operator KMemoryRegionType() const {
+ return static_cast<KMemoryRegionType>(m_value);
+ }
+
+ constexpr ValueType GetValue() const {
+ return m_value;
+ }
+
+ constexpr const KMemoryRegionTypeValue& Finalize() {
+ m_finalized = true;
+ return *this;
+ }
+
+ constexpr const KMemoryRegionTypeValue& SetSparseOnly() {
+ m_sparse_only = true;
+ return *this;
+ }
+
+ constexpr const KMemoryRegionTypeValue& SetDenseOnly() {
+ m_dense_only = true;
+ return *this;
+ }
+
+ constexpr KMemoryRegionTypeValue& SetAttribute(u32 attr) {
+ m_value |= attr;
+ return *this;
+ }
+
+ constexpr KMemoryRegionTypeValue DeriveInitial(
+ size_t i, size_t next = Common::BitSize<ValueType>()) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value = (ValueType{1} << i);
+ new_type.m_next_bit = next;
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue DeriveAttribute(u32 attr) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value |= attr;
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue DeriveTransition(size_t ofs = 0, size_t adv = 1) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value |= (ValueType{1} << (m_next_bit + ofs));
+ new_type.m_next_bit += adv;
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue DeriveSparse(size_t ofs, size_t n, size_t i) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value |= (ValueType{1} << (m_next_bit + ofs));
+ new_type.m_value |= (ValueType{1} << (m_next_bit + ofs + 1 + i));
+ new_type.m_next_bit += ofs + n + 1;
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue Derive(size_t n, size_t i) const {
+ size_t low = 0, high = 1;
+ for (size_t j = 0; j < i; ++j) {
+ if ((++low) == high) {
+ ++high;
+ low = 0;
+ }
+ }
+
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value |= (ValueType{1} << (m_next_bit + low));
+ new_type.m_value |= (ValueType{1} << (m_next_bit + high));
+ new_type.m_next_bit += BitsForDeriveDense(n);
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue Advance(size_t n) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_next_bit += n;
+ return new_type;
+ }
+
+ constexpr bool IsAncestorOf(ValueType v) const {
+ return (m_value | v) == v;
+ }
+
+private:
+ constexpr KMemoryRegionTypeValue(ValueType v) : m_value(v) {}
+
+private:
+ ValueType m_value{};
+ size_t m_next_bit{};
+ bool m_finalized{};
+ bool m_sparse_only{};
+ bool m_dense_only{};
+};
+
+} // namespace impl
+
+constexpr auto KMemoryRegionType_None = impl::KMemoryRegionTypeValue();
+constexpr auto KMemoryRegionType_Kernel = KMemoryRegionType_None.DeriveInitial(0, 2);
+constexpr auto KMemoryRegionType_Dram = KMemoryRegionType_None.DeriveInitial(1, 2);
+static_assert(KMemoryRegionType_Kernel.GetValue() == 0x1);
+static_assert(KMemoryRegionType_Dram.GetValue() == 0x2);
+
+constexpr auto KMemoryRegionType_DramKernelBase =
+ KMemoryRegionType_Dram.DeriveSparse(0, 3, 0)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap)
+ .SetAttribute(KMemoryRegionAttr_CarveoutProtected);
+constexpr auto KMemoryRegionType_DramReservedBase = KMemoryRegionType_Dram.DeriveSparse(0, 3, 1);
+constexpr auto KMemoryRegionType_DramHeapBase =
+ KMemoryRegionType_Dram.DeriveSparse(0, 3, 2).SetAttribute(KMemoryRegionAttr_LinearMapped);
+static_assert(KMemoryRegionType_DramKernelBase.GetValue() ==
+ (0xE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramReservedBase.GetValue() == (0x16));
+static_assert(KMemoryRegionType_DramHeapBase.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped));
+
+constexpr auto KMemoryRegionType_DramKernelCode =
+ KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 0);
+constexpr auto KMemoryRegionType_DramKernelSlab =
+ KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 1);
+constexpr auto KMemoryRegionType_DramKernelPtHeap =
+ KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 2).SetAttribute(
+ KMemoryRegionAttr_LinearMapped);
+constexpr auto KMemoryRegionType_DramKernelInitPt =
+ KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 3).SetAttribute(
+ KMemoryRegionAttr_LinearMapped);
+static_assert(KMemoryRegionType_DramKernelCode.GetValue() ==
+ (0xCE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramKernelSlab.GetValue() ==
+ (0x14E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramKernelPtHeap.GetValue() ==
+ (0x24E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
+ KMemoryRegionAttr_LinearMapped));
+static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() ==
+ (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
+ KMemoryRegionAttr_LinearMapped));
+
+constexpr auto KMemoryRegionType_DramReservedEarly =
+ KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
+static_assert(KMemoryRegionType_DramReservedEarly.GetValue() ==
+ (0x16 | KMemoryRegionAttr_NoUserMap));
+
+constexpr auto KMemoryRegionType_KernelTraceBuffer =
+ KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 0)
+ .SetAttribute(KMemoryRegionAttr_LinearMapped)
+ .SetAttribute(KMemoryRegionAttr_UserReadOnly);
+constexpr auto KMemoryRegionType_OnMemoryBootImage =
+ KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 1);
+constexpr auto KMemoryRegionType_DTB = KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 2);
+static_assert(KMemoryRegionType_KernelTraceBuffer.GetValue() ==
+ (0xD6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_UserReadOnly));
+static_assert(KMemoryRegionType_OnMemoryBootImage.GetValue() == 0x156);
+static_assert(KMemoryRegionType_DTB.GetValue() == 0x256);
+
+constexpr auto KMemoryRegionType_DramPoolPartition =
+ KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
+static_assert(KMemoryRegionType_DramPoolPartition.GetValue() ==
+ (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+
+constexpr auto KMemoryRegionType_DramPoolManagement =
+ KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(
+ KMemoryRegionAttr_CarveoutProtected);
+constexpr auto KMemoryRegionType_DramUserPool =
+ KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
+static_assert(KMemoryRegionType_DramPoolManagement.GetValue() ==
+ (0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
+ KMemoryRegionAttr_CarveoutProtected));
+static_assert(KMemoryRegionType_DramUserPool.GetValue() ==
+ (0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+
+constexpr auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
+constexpr auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
+constexpr auto KMemoryRegionType_DramSystemNonSecurePool =
+ KMemoryRegionType_DramUserPool.Derive(4, 2);
+constexpr auto KMemoryRegionType_DramSystemPool =
+ KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
+static_assert(KMemoryRegionType_DramApplicationPool.GetValue() ==
+ (0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramAppletPool.GetValue() ==
+ (0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() ==
+ (0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramSystemPool.GetValue() ==
+ (0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
+ KMemoryRegionAttr_CarveoutProtected));
+
+constexpr auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
+constexpr auto KMemoryRegionType_VirtualDramKernelPtHeap =
+ KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
+constexpr auto KMemoryRegionType_VirtualDramKernelTraceBuffer =
+ KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
+static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A);
+static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A);
+static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
+
+constexpr auto KMemoryRegionType_VirtualDramKernelInitPt =
+ KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
+constexpr auto KMemoryRegionType_VirtualDramPoolManagement =
+ KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
+constexpr auto KMemoryRegionType_VirtualDramUserPool =
+ KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
+static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x19A);
+static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
+static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x31A);
+
+// NOTE: For unknown reason, the pools are derived out-of-order here. It's worth eventually trying
+// to understand why Nintendo made this choice.
+// UNUSED: .Derive(6, 0);
+// UNUSED: .Derive(6, 1);
+constexpr auto KMemoryRegionType_VirtualDramAppletPool =
+ KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
+constexpr auto KMemoryRegionType_VirtualDramApplicationPool =
+ KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
+constexpr auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
+ KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
+constexpr auto KMemoryRegionType_VirtualDramSystemPool =
+ KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
+static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x1B1A);
+static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x271A);
+static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
+static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x331A);
+
+constexpr auto KMemoryRegionType_ArchDeviceBase =
+ KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
+constexpr auto KMemoryRegionType_BoardDeviceBase =
+ KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
+static_assert(KMemoryRegionType_ArchDeviceBase.GetValue() == 0x5);
+static_assert(KMemoryRegionType_BoardDeviceBase.GetValue() == 0x5);
+
+#if defined(ARCH_ARM64)
+#include "core/hle/kernel/arch/arm64/k_memory_region_device_types.inc"
+#elif defined(ARCH_ARM)
+#error "Unimplemented"
+#else
+// Default to no architecture devices.
+constexpr auto NumArchitectureDeviceRegions = 0;
+#endif
+static_assert(NumArchitectureDeviceRegions >= 0);
+
+#if defined(BOARD_NINTENDO_NX)
+#include "core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc"
+#else
+// Default to no board devices.
+constexpr auto NumBoardDeviceRegions = 0;
+#endif
+static_assert(NumBoardDeviceRegions >= 0);
+
+constexpr auto KMemoryRegionType_KernelCode = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 0);
+constexpr auto KMemoryRegionType_KernelStack = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 1);
+constexpr auto KMemoryRegionType_KernelMisc = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 2);
+constexpr auto KMemoryRegionType_KernelSlab = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 3);
+static_assert(KMemoryRegionType_KernelCode.GetValue() == 0x19);
+static_assert(KMemoryRegionType_KernelStack.GetValue() == 0x29);
+static_assert(KMemoryRegionType_KernelMisc.GetValue() == 0x49);
+static_assert(KMemoryRegionType_KernelSlab.GetValue() == 0x89);
+
+constexpr auto KMemoryRegionType_KernelMiscDerivedBase =
+ KMemoryRegionType_KernelMisc.DeriveTransition();
+static_assert(KMemoryRegionType_KernelMiscDerivedBase.GetValue() == 0x149);
+
+// UNUSED: .Derive(7, 0);
+constexpr auto KMemoryRegionType_KernelMiscMainStack =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 1);
+constexpr auto KMemoryRegionType_KernelMiscMappedDevice =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 2);
+constexpr auto KMemoryRegionType_KernelMiscExceptionStack =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 3);
+constexpr auto KMemoryRegionType_KernelMiscUnknownDebug =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 4);
+// UNUSED: .Derive(7, 5);
+constexpr auto KMemoryRegionType_KernelMiscIdleStack =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 6);
+static_assert(KMemoryRegionType_KernelMiscMainStack.GetValue() == 0xB49);
+static_assert(KMemoryRegionType_KernelMiscMappedDevice.GetValue() == 0xD49);
+static_assert(KMemoryRegionType_KernelMiscExceptionStack.GetValue() == 0x1349);
+static_assert(KMemoryRegionType_KernelMiscUnknownDebug.GetValue() == 0x1549);
+static_assert(KMemoryRegionType_KernelMiscIdleStack.GetValue() == 0x2349);
+
+constexpr auto KMemoryRegionType_KernelTemp = KMemoryRegionType_Kernel.Advance(2).Derive(2, 0);
+static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
+
+constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
+ if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
+ return KMemoryRegionType_VirtualDramKernelTraceBuffer;
+ } else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
+ return KMemoryRegionType_VirtualDramKernelPtHeap;
+ } else {
+ return KMemoryRegionType_Dram;
+ }
+}
+
+} // 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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#include "common/assert.h"
-#include "core/core.h"
#include "core/core_timing.h"
-#include "core/core_timing_util.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
-KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system)
- : Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {}
+KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_)
+ : Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {}
KResourceLimit::~KResourceLimit() = default;
s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
@@ -83,7 +78,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
- return Reserve(which, value, system.CoreTiming().GetGlobalTimeNs().count() + DefaultTimeout);
+ return Reserve(which, value, core_timing.GetGlobalTimeNs().count() + DefaultTimeout);
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
@@ -114,7 +109,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
}
if (current_hints[index] + value <= limit_values[index] &&
- (timeout < 0 || system.CoreTiming().GetGlobalTimeNs().count() < timeout)) {
+ (timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) {
waiter_count++;
cond_var.Wait(&lock, timeout);
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#pragma once
#include <array>
@@ -15,8 +12,8 @@
union ResultCode;
-namespace Core {
-class System;
+namespace Core::Timing {
+class CoreTiming;
}
namespace Kernel {
@@ -37,7 +34,7 @@ constexpr bool IsValidResourceType(LimitableResource type) {
class KResourceLimit final : public Object {
public:
- explicit KResourceLimit(KernelCore& kernel, Core::System& system);
+ explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_);
~KResourceLimit();
s64 GetLimitValue(LimitableResource which) const;
@@ -75,7 +72,6 @@ private:
mutable KLightLock lock;
s32 waiter_count{};
KLightConditionVariable cond_var;
- KernelCore& kernel;
- Core::System& system;
+ const Core::Timing::CoreTiming& core_timing;
};
} // 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
}
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
- std::scoped_lock lock{guard};
+ KScopedSpinLock lk{guard};
if (KThread* prev_highest_thread = state.highest_priority_thread;
prev_highest_thread != highest_thread) {
if (prev_highest_thread != nullptr) {
@@ -637,11 +637,11 @@ void KScheduler::RescheduleCurrentCore() {
if (phys_core.IsInterrupted()) {
phys_core.ClearInterrupt();
}
- guard.lock();
+ guard.Lock();
if (state.needs_scheduling.load()) {
Schedule();
} else {
- guard.unlock();
+ guard.Unlock();
}
}
@@ -669,7 +669,7 @@ void KScheduler::Unload(KThread* thread) {
} else {
prev_thread = nullptr;
}
- thread->context_guard.unlock();
+ thread->context_guard.Unlock();
}
}
@@ -713,7 +713,7 @@ void KScheduler::ScheduleImpl() {
// If we're not actually switching thread, there's nothing to do.
if (next_thread == current_thread.load()) {
- guard.unlock();
+ guard.Unlock();
return;
}
@@ -732,7 +732,7 @@ void KScheduler::ScheduleImpl() {
} else {
old_context = &idle_thread->GetHostContext();
}
- guard.unlock();
+ guard.Unlock();
Common::Fiber::YieldTo(*old_context, *switch_fiber);
/// 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) {
void KScheduler::SwitchToCurrent() {
while (true) {
{
- std::scoped_lock lock{guard};
+ KScopedSpinLock lk{guard};
current_thread.store(state.highest_priority_thread);
state.needs_scheduling.store(false);
}
const auto is_switch_pending = [this] {
- std::scoped_lock lock{guard};
+ KScopedSpinLock lk{guard};
return state.needs_scheduling.load();
};
do {
auto next_thread = current_thread.load();
if (next_thread != nullptr) {
- next_thread->context_guard.lock();
+ next_thread->context_guard.Lock();
if (next_thread->GetRawState() != ThreadState::Runnable) {
- next_thread->context_guard.unlock();
+ next_thread->context_guard.Unlock();
break;
}
if (next_thread->GetActiveCore() != core_id) {
- next_thread->context_guard.unlock();
+ next_thread->context_guard.Unlock();
break;
}
}
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#pragma once
#include <atomic>
#include "common/common_types.h"
-#include "common/spin_lock.h"
#include "core/hle/kernel/global_scheduler_context.h"
#include "core/hle/kernel/k_priority_queue.h"
#include "core/hle/kernel/k_scheduler_lock.h"
#include "core/hle/kernel/k_scoped_lock.h"
+#include "core/hle/kernel/k_spin_lock.h"
namespace Common {
class Fiber;
@@ -195,12 +192,12 @@ private:
u64 last_context_switch_time{};
const s32 core_id;
- Common::SpinLock guard{};
+ KSpinLock guard{};
};
-class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
+class [[nodiscard]] KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
public:
- explicit KScopedSchedulerLock(KernelCore& kernel);
+ explicit KScopedSchedulerLock(KernelCore & kernel);
~KScopedSchedulerLock();
};
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-// This file references various implementation details from Atmosphere, an open-source firmware for
-// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
-
#pragma once
#include "common/assert.h"
-#include "common/spin_lock.h"
#include "core/hardware_properties.h"
+#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
@@ -34,7 +31,7 @@ public:
} else {
// Otherwise, we want to disable scheduling and acquire the spinlock.
SchedulerType::DisableScheduling(kernel);
- spin_lock.lock();
+ spin_lock.Lock();
// For debug, ensure that our state is valid.
ASSERT(lock_count == 0);
@@ -58,7 +55,7 @@ public:
// Note that we no longer hold the lock, and unlock the spinlock.
owner_thread = nullptr;
- spin_lock.unlock();
+ spin_lock.Unlock();
// Enable scheduling, and perform a rescheduling operation.
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
@@ -67,7 +64,7 @@ public:
private:
KernelCore& kernel;
- Common::SpinLock spin_lock{};
+ KAlignedSpinLock spin_lock{};
s32 lock_count{};
KThread* owner_thread{};
};
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) {
};
template <typename T>
-requires KLockable<T> class KScopedLock {
+requires KLockable<T> class [[nodiscard]] KScopedLock {
public:
- explicit KScopedLock(T* l) : lock_ptr(l) {
+ explicit KScopedLock(T * l) : lock_ptr(l) {
this->lock_ptr->Lock();
}
- explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) { /* ... */
- }
+ explicit KScopedLock(T & l) : KScopedLock(std::addressof(l)) {}
+
~KScopedLock() {
this->lock_ptr->Unlock();
}
KScopedLock(const KScopedLock&) = delete;
- KScopedLock(KScopedLock&&) = delete;
+ KScopedLock& operator=(const KScopedLock&) = delete;
+
+ KScopedLock(KScopedLock &&) = delete;
+ KScopedLock& operator=(KScopedLock&&) = delete;
private:
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 @@
namespace Kernel {
-class KScopedSchedulerLockAndSleep {
+class [[nodiscard]] KScopedSchedulerLockAndSleep {
public:
- explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout)
+ explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout)
: kernel(kernel), thread(t), timeout_tick(timeout) {
// Lock the scheduler.
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:
std::atomic_flag lck = ATOMIC_FLAG_INIT;
};
+// TODO(bunnei): Alias for now, in case we want to implement these accurately in the future.
+using KAlignedSpinLock = KSpinLock;
+using KNotAlignedSpinLock = KSpinLock;
+
using KScopedSpinLock = KScopedLock<KSpinLock>;
+using KScopedAlignedSpinLock = KScopedLock<KAlignedSpinLock>;
+using KScopedNotAlignedSpinLock = KScopedLock<KNotAlignedSpinLock>;
} // 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 @@
-// Copyright 2021 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <random>
-
-#include "core/hle/kernel/k_system_control.h"
-
-namespace Kernel {
-
-namespace {
-template <typename F>
-u64 GenerateUniformRange(u64 min, u64 max, F f) {
- // Handle the case where the difference is too large to represent.
- if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
- return f();
- }
-
- // Iterate until we get a value in range.
- const u64 range_size = ((max + 1) - min);
- const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
- while (true) {
- if (const u64 rnd = f(); rnd < effective_max) {
- return min + (rnd % range_size);
- }
- }
-}
-
-} // Anonymous namespace
-
-u64 KSystemControl::GenerateRandomU64() {
- static std::random_device device;
- static std::mt19937 gen(device());
- static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
- return distribution(gen);
-}
-
-u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
- return GenerateUniformRange(min, max, GenerateRandomU64);
-}
-
-} // 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 @@
#include "common/common_types.h"
-namespace Kernel {
+#define BOARD_NINTENDO_NX
+
+#ifdef BOARD_NINTENDO_NX
-class KSystemControl {
-public:
- KSystemControl() = default;
+#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
- static u64 GenerateRandomRange(u64 min, u64 max);
- static u64 GenerateRandomU64();
-};
+namespace Kernel {
+
+using Kernel::Board::Nintendo::Nx::KSystemControl;
} // namespace Kernel
+
+#else
+#error "Unknown board for KSystemControl"
+#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 @@
#include "common/common_types.h"
#include "common/intrusive_red_black_tree.h"
-#include "common/spin_lock.h"
#include "core/arm/arm_interface.h"
#include "core/hle/kernel/k_affinity_mask.h"
#include "core/hle/kernel/k_light_lock.h"
+#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/svc_common.h"
@@ -402,7 +402,7 @@ public:
return wait_cancelled;
}
- [[nodiscard]] void ClearWaitCancelled() {
+ void ClearWaitCancelled() {
wait_cancelled = false;
}
@@ -732,7 +732,7 @@ private:
s8 priority_inheritance_count{};
bool resource_limit_release_hint{};
StackParameters stack_parameters{};
- Common::SpinLock context_guard{};
+ KSpinLock context_guard{};
// For emulation
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Kernel {
+
+constexpr bool IsKTraceEnabled = false;
+constexpr std::size_t KTraceBufferSize = IsKTraceEnabled ? 16 * 1024 * 1024 : 0;
+
+} // 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 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -12,6 +12,7 @@
#include <utility>
#include "common/assert.h"
+#include "common/common_sizes.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/thread.h"
@@ -66,8 +67,13 @@ struct KernelCore::Impl {
is_phantom_mode_for_singlecore = false;
InitializePhysicalCores();
- InitializeSystemResourceLimit(kernel, system);
- InitializeMemoryLayout();
+
+ // Derive the initial memory layout from the emulated board
+ KMemoryLayout memory_layout;
+ DeriveInitialMemoryLayout(memory_layout);
+ InitializeMemoryLayout(memory_layout);
+ InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout);
+ InitializeSlabHeaps();
InitializeSchedulers();
InitializeSuspendThreads();
InitializePreemption(kernel);
@@ -136,27 +142,33 @@ struct KernelCore::Impl {
}
// Creates the default system resource limit
- void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) {
- system_resource_limit = std::make_shared<KResourceLimit>(kernel, system);
+ void InitializeSystemResourceLimit(KernelCore& kernel,
+ const Core::Timing::CoreTiming& core_timing,
+ const KMemoryLayout& memory_layout) {
+ system_resource_limit = std::make_shared<KResourceLimit>(kernel, core_timing);
+ const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes();
// If setting the default system values fails, then something seriously wrong has occurred.
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000)
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size)
.IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess());
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
.IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 933).IsSuccess());
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
+ system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size);
- // Derived from recent software updates. The kernel reserves 27MB
- constexpr u64 kernel_size{0x1b00000};
- if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size)) {
- UNREACHABLE();
- }
// Reserve secure applet memory, introduced in firmware 5.0.0
- constexpr u64 secure_applet_memory_size{0x400000};
+ constexpr u64 secure_applet_memory_size{Common::Size_4_MB};
ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
secure_applet_memory_size));
+
+ // This memory seems to be reserved on hardware, but is not reserved/used by yuzu.
+ // Likely Horizon OS reserved memory
+ // TODO(ameerj): Derive the memory rather than hardcode it.
+ constexpr u64 unknown_reserved_memory{0x2f896000};
+ ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
+ unknown_reserved_memory));
}
void InitializePreemption(KernelCore& kernel) {
@@ -268,51 +280,319 @@ struct KernelCore::Impl {
return schedulers[thread_id]->GetCurrentThread();
}
- void InitializeMemoryLayout() {
- // Initialize memory layout
- constexpr KMemoryLayout layout{KMemoryLayout::GetDefaultLayout()};
+ void DeriveInitialMemoryLayout(KMemoryLayout& memory_layout) {
+ // Insert the root region for the virtual memory tree, from which all other regions will
+ // derive.
+ memory_layout.GetVirtualMemoryRegionTree().InsertDirectly(
+ KernelVirtualAddressSpaceBase,
+ KernelVirtualAddressSpaceBase + KernelVirtualAddressSpaceSize - 1);
+
+ // Insert the root region for the physical memory tree, from which all other regions will
+ // derive.
+ memory_layout.GetPhysicalMemoryRegionTree().InsertDirectly(
+ KernelPhysicalAddressSpaceBase,
+ KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1);
+
+ // Save start and end for ease of use.
+ const VAddr code_start_virt_addr = KernelVirtualAddressCodeBase;
+ const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
+
+ // Setup the containing kernel region.
+ constexpr size_t KernelRegionSize = Common::Size_1_GB;
+ constexpr size_t KernelRegionAlign = Common::Size_1_GB;
+ constexpr VAddr kernel_region_start =
+ Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
+ size_t kernel_region_size = KernelRegionSize;
+ if (!(kernel_region_start + KernelRegionSize - 1 <= KernelVirtualAddressSpaceLast)) {
+ kernel_region_size = KernelVirtualAddressSpaceEnd - kernel_region_start;
+ }
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
+ kernel_region_start, kernel_region_size, KMemoryRegionType_Kernel));
+
+ // Setup the code region.
+ constexpr size_t CodeRegionAlign = PageSize;
+ constexpr VAddr code_region_start =
+ Common::AlignDown(code_start_virt_addr, CodeRegionAlign);
+ constexpr VAddr code_region_end = Common::AlignUp(code_end_virt_addr, CodeRegionAlign);
+ constexpr size_t code_region_size = code_region_end - code_region_start;
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
+ code_region_start, code_region_size, KMemoryRegionType_KernelCode));
+
+ // Setup board-specific device physical regions.
+ Init::SetupDevicePhysicalMemoryRegions(memory_layout);
+
+ // Determine the amount of space needed for the misc region.
+ size_t misc_region_needed_size;
+ {
+ // Each core has a one page stack for all three stack types (Main, Idle, Exception).
+ misc_region_needed_size = Core::Hardware::NUM_CPU_CORES * (3 * (PageSize + PageSize));
+
+ // Account for each auto-map device.
+ for (const auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
+ if (region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
+ // Check that the region is valid.
+ ASSERT(region.GetEndAddress() != 0);
+
+ // Account for the region.
+ misc_region_needed_size +=
+ PageSize + (Common::AlignUp(region.GetLastAddress(), PageSize) -
+ Common::AlignDown(region.GetAddress(), PageSize));
+ }
+ }
+
+ // Multiply the needed size by three, to account for the need for guard space.
+ misc_region_needed_size *= 3;
+ }
+
+ // Decide on the actual size for the misc region.
+ constexpr size_t MiscRegionAlign = KernelAslrAlignment;
+ constexpr size_t MiscRegionMinimumSize = Common::Size_32_MB;
+ const size_t misc_region_size = Common::AlignUp(
+ std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
+ ASSERT(misc_region_size > 0);
+
+ // Setup the misc region.
+ const VAddr misc_region_start =
+ memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
+ misc_region_size, MiscRegionAlign, KMemoryRegionType_Kernel);
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
+ misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
+
+ // Setup the stack region.
+ constexpr size_t StackRegionSize = Common::Size_14_MB;
+ constexpr size_t StackRegionAlign = KernelAslrAlignment;
+ const VAddr stack_region_start =
+ memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
+ StackRegionSize, StackRegionAlign, KMemoryRegionType_Kernel);
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
+ stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
+
+ // Determine the size of the resource region.
+ const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit();
+
+ // Determine the size of the slab region.
+ const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize);
+ ASSERT(slab_region_size <= resource_region_size);
+
+ // Setup the slab region.
+ const PAddr code_start_phys_addr = KernelPhysicalAddressCodeBase;
+ const PAddr code_end_phys_addr = code_start_phys_addr + code_region_size;
+ const PAddr slab_start_phys_addr = code_end_phys_addr;
+ const PAddr slab_end_phys_addr = slab_start_phys_addr + slab_region_size;
+ constexpr size_t SlabRegionAlign = KernelAslrAlignment;
+ const size_t slab_region_needed_size =
+ Common::AlignUp(code_end_phys_addr + slab_region_size, SlabRegionAlign) -
+ Common::AlignDown(code_end_phys_addr, SlabRegionAlign);
+ const VAddr slab_region_start =
+ memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
+ slab_region_needed_size, SlabRegionAlign, KMemoryRegionType_Kernel) +
+ (code_end_phys_addr % SlabRegionAlign);
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
+ slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
+
+ // Setup the temp region.
+ constexpr size_t TempRegionSize = Common::Size_128_MB;
+ constexpr size_t TempRegionAlign = KernelAslrAlignment;
+ const VAddr temp_region_start =
+ memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
+ TempRegionSize, TempRegionAlign, KMemoryRegionType_Kernel);
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(temp_region_start, TempRegionSize,
+ KMemoryRegionType_KernelTemp));
+
+ // Automatically map in devices that have auto-map attributes.
+ for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
+ // We only care about kernel regions.
+ if (!region.IsDerivedFrom(KMemoryRegionType_Kernel)) {
+ continue;
+ }
+
+ // Check whether we should map the region.
+ if (!region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
+ continue;
+ }
+
+ // If this region has already been mapped, no need to consider it.
+ if (region.HasTypeAttribute(KMemoryRegionAttr_DidKernelMap)) {
+ continue;
+ }
+
+ // Check that the region is valid.
+ ASSERT(region.GetEndAddress() != 0);
+
+ // Set the attribute to note we've mapped this region.
+ region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap);
+
+ // Create a virtual pair region and insert it into the tree.
+ const PAddr map_phys_addr = Common::AlignDown(region.GetAddress(), PageSize);
+ const size_t map_size =
+ Common::AlignUp(region.GetEndAddress(), PageSize) - map_phys_addr;
+ const VAddr map_virt_addr =
+ memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
+ map_size, PageSize, KMemoryRegionType_KernelMisc, PageSize);
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
+ map_virt_addr, map_size, KMemoryRegionType_KernelMiscMappedDevice));
+ region.SetPairAddress(map_virt_addr + region.GetAddress() - map_phys_addr);
+ }
+
+ Init::SetupDramPhysicalMemoryRegions(memory_layout);
+
+ // Insert a physical region for the kernel code region.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ code_start_phys_addr, code_region_size, KMemoryRegionType_DramKernelCode));
+
+ // Insert a physical region for the kernel slab region.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ slab_start_phys_addr, slab_region_size, KMemoryRegionType_DramKernelSlab));
+
+ // Determine size available for kernel page table heaps, requiring > 8 MB.
+ const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
+ const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
+ ASSERT(page_table_heap_size / Common::Size_4_MB > 2);
+
+ // Insert a physical region for the kernel page table heap region
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ slab_end_phys_addr, page_table_heap_size, KMemoryRegionType_DramKernelPtHeap));
+
+ // All DRAM regions that we haven't tagged by this point will be mapped under the linear
+ // mapping. Tag them.
+ for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
+ if (region.GetType() == KMemoryRegionType_Dram) {
+ // Check that the region is valid.
+ ASSERT(region.GetEndAddress() != 0);
+
+ // Set the linear map attribute.
+ region.SetTypeAttribute(KMemoryRegionAttr_LinearMapped);
+ }
+ }
+
+ // Get the linear region extents.
+ const auto linear_extents =
+ memory_layout.GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionAttr_LinearMapped);
+ ASSERT(linear_extents.GetEndAddress() != 0);
+
+ // Setup the linear mapping region.
+ constexpr size_t LinearRegionAlign = Common::Size_1_GB;
+ const PAddr aligned_linear_phys_start =
+ Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
+ const size_t linear_region_size =
+ Common::AlignUp(linear_extents.GetEndAddress(), LinearRegionAlign) -
+ aligned_linear_phys_start;
+ const VAddr linear_region_start =
+ memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
+ linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign);
+
+ const u64 linear_region_phys_to_virt_diff = linear_region_start - aligned_linear_phys_start;
+
+ // Map and create regions for all the linearly-mapped data.
+ {
+ PAddr cur_phys_addr = 0;
+ u64 cur_size = 0;
+ for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
+ if (!region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
+ continue;
+ }
+
+ ASSERT(region.GetEndAddress() != 0);
+
+ if (cur_size == 0) {
+ cur_phys_addr = region.GetAddress();
+ cur_size = region.GetSize();
+ } else if (cur_phys_addr + cur_size == region.GetAddress()) {
+ cur_size += region.GetSize();
+ } else {
+ cur_phys_addr = region.GetAddress();
+ cur_size = region.GetSize();
+ }
+
+ const VAddr region_virt_addr =
+ region.GetAddress() + linear_region_phys_to_virt_diff;
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
+ region_virt_addr, region.GetSize(),
+ GetTypeForVirtualLinearMapping(region.GetType())));
+ region.SetPairAddress(region_virt_addr);
+
+ KMemoryRegion* virt_region =
+ memory_layout.GetVirtualMemoryRegionTree().FindModifiable(region_virt_addr);
+ ASSERT(virt_region != nullptr);
+ virt_region->SetPairAddress(region.GetAddress());
+ }
+ }
+
+ // Insert regions for the initial page table region.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ resource_end_phys_addr, KernelPageTableHeapSize, KMemoryRegionType_DramKernelInitPt));
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
+ resource_end_phys_addr + linear_region_phys_to_virt_diff, KernelPageTableHeapSize,
+ KMemoryRegionType_VirtualDramKernelInitPt));
+
+ // All linear-mapped DRAM regions that we haven't tagged by this point will be allocated to
+ // some pool partition. Tag them.
+ for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
+ if (region.GetType() == (KMemoryRegionType_Dram | KMemoryRegionAttr_LinearMapped)) {
+ region.SetType(KMemoryRegionType_DramPoolPartition);
+ }
+ }
+
+ // Setup all other memory regions needed to arrange the pool partitions.
+ Init::SetupPoolPartitionMemoryRegions(memory_layout);
+
+ // Cache all linear regions in their own trees for faster access, later.
+ memory_layout.InitializeLinearMemoryRegionTrees(aligned_linear_phys_start,
+ linear_region_start);
+ }
+
+ void InitializeMemoryLayout(const KMemoryLayout& memory_layout) {
+ const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
+ const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
+ const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
+
+ // Initialize memory managers
+ memory_manager = std::make_unique<KMemoryManager>();
+ memory_manager->InitializeManager(KMemoryManager::Pool::Application,
+ application_pool.GetAddress(),
+ application_pool.GetEndAddress());
+ memory_manager->InitializeManager(KMemoryManager::Pool::Applet, applet_pool.GetAddress(),
+ applet_pool.GetEndAddress());
+ memory_manager->InitializeManager(KMemoryManager::Pool::System, system_pool.GetAddress(),
+ system_pool.GetEndAddress());
+
+ // Setup memory regions for emulated processes
+ // TODO(bunnei): These should not be hardcoded regions initialized within the kernel
constexpr std::size_t hid_size{0x40000};
constexpr std::size_t font_size{0x1100000};
constexpr std::size_t irs_size{0x8000};
constexpr std::size_t time_size{0x1000};
- constexpr PAddr hid_addr{layout.System().StartAddress()};
- constexpr PAddr font_pa{layout.System().StartAddress() + hid_size};
- constexpr PAddr irs_addr{layout.System().StartAddress() + hid_size + font_size};
- constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
- // Initialize memory manager
- memory_manager = std::make_unique<KMemoryManager>();
- memory_manager->InitializeManager(KMemoryManager::Pool::Application,
- layout.Application().StartAddress(),
- layout.Application().EndAddress());
- memory_manager->InitializeManager(KMemoryManager::Pool::Applet,
- layout.Applet().StartAddress(),
- layout.Applet().EndAddress());
- memory_manager->InitializeManager(KMemoryManager::Pool::System,
- layout.System().StartAddress(),
- layout.System().EndAddress());
+ const PAddr hid_phys_addr{system_pool.GetAddress()};
+ const PAddr font_phys_addr{system_pool.GetAddress() + hid_size};
+ const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
+ const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
hid_shared_mem = Kernel::KSharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / PageSize},
- KMemoryPermission::None, KMemoryPermission::Read, hid_addr, hid_size,
+ system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize},
+ KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size,
"HID:SharedMemory");
font_shared_mem = Kernel::KSharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / PageSize},
- KMemoryPermission::None, KMemoryPermission::Read, font_pa, font_size,
+ system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize},
+ KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size,
"Font:SharedMemory");
irs_shared_mem = Kernel::KSharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / PageSize},
- KMemoryPermission::None, KMemoryPermission::Read, irs_addr, irs_size,
+ system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize},
+ KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size,
"IRS:SharedMemory");
time_shared_mem = Kernel::KSharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / PageSize},
- KMemoryPermission::None, KMemoryPermission::Read, time_addr, time_size,
+ system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
+ KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
"Time:SharedMemory");
+ }
+ void InitializeSlabHeaps() {
// Allocate slab heaps
user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
- constexpr u64 user_slab_heap_size{0x1ef000};
+ // TODO(ameerj): This should be derived, not hardcoded within the kernel
+ constexpr u64 user_slab_heap_size{0x3de000};
// Reserve slab heaps
ASSERT(
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 @@
-// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
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 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/device_memory.h"
#include "core/file_sys/program_metadata.h"
@@ -26,7 +27,6 @@
#include "core/hle/kernel/svc_results.h"
#include "core/hle/lock.h"
#include "core/memory.h"
-#include "core/settings.h"
namespace Kernel {
namespace {
@@ -120,9 +120,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
std::shared_ptr<Process> process = std::make_shared<Process>(system);
process->name = std::move(name);
- // TODO: This is inaccurate
- // The process should hold a reference to the kernel-wide resource limit.
- process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
+ process->resource_limit = kernel.GetSystemResourceLimit();
process->status = ProcessStatus::Created;
process->program_id = 0;
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@@ -160,17 +158,13 @@ void Process::DecrementThreadCount() {
}
u64 Process::GetTotalPhysicalMemoryAvailable() const {
- // TODO: This is expected to always return the application memory pool size after accurately
- // reserving kernel resources. The current workaround uses a process-local resource limit of
- // application memory pool size, which is inaccurate.
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
main_thread_stack_size};
-
+ ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
if (capacity < memory_usage_capacity) {
return capacity;
}
-
return memory_usage_capacity;
}
@@ -272,10 +266,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
system_resource_size = metadata.GetSystemResourceSize();
image_size = code_size;
- // Set initial resource limits
- resource_limit->SetLimitValue(
- LimitableResource::PhysicalMemory,
- kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
code_size + system_resource_size);
if (!memory_reservation.Succeeded()) {
@@ -324,16 +314,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
UNREACHABLE();
}
- // Set initial resource limits
- resource_limit->SetLimitValue(
- LimitableResource::PhysicalMemory,
- kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
-
- resource_limit->SetLimitValue(LimitableResource::Threads, 608);
- resource_limit->SetLimitValue(LimitableResource::Events, 700);
- resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
- resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
-
// Create TLS region
tls_region_address = CreateTLSRegion();
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)
continue;
}
- if (svc_number >= svc_capabilities.size()) {
- LOG_ERROR(Kernel, "Process svc capability is out of range! svc_number={}", svc_number);
- return ResultOutOfRange;
- }
-
svc_capabilities[svc_number] = true;
}
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 {
class ProcessCapabilities {
public:
using InterruptCapabilities = std::bitset<1024>;
- using SyscallCapabilities = std::bitset<128>;
+ using SyscallCapabilities = std::bitset<192>;
ProcessCapabilities() = default;
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)
LOG_DEBUG(Kernel_SVC, "called");
auto& kernel = system.Kernel();
- auto resource_limit = std::make_shared<KResourceLimit>(kernel, system);
+ auto resource_limit = std::make_shared<KResourceLimit>(kernel, system.CoreTiming());
auto* const current_process = kernel.CurrentProcess();
ASSERT(current_process != nullptr);
@@ -2455,6 +2455,74 @@ static const FunctionDef SVC_Table_32[] = {
{0x79, nullptr, "Unknown"},
{0x7A, nullptr, "Unknown"},
{0x7B, nullptr, "TerminateProcess32"},
+ {0x7C, nullptr, "GetProcessInfo32"},
+ {0x7D, nullptr, "CreateResourceLimit32"},
+ {0x7E, nullptr, "SetResourceLimitLimitValue32"},
+ {0x7F, nullptr, "CallSecureMonitor32"},
+ {0x80, nullptr, "Unknown"},
+ {0x81, nullptr, "Unknown"},
+ {0x82, nullptr, "Unknown"},
+ {0x83, nullptr, "Unknown"},
+ {0x84, nullptr, "Unknown"},
+ {0x85, nullptr, "Unknown"},
+ {0x86, nullptr, "Unknown"},
+ {0x87, nullptr, "Unknown"},
+ {0x88, nullptr, "Unknown"},
+ {0x89, nullptr, "Unknown"},
+ {0x8A, nullptr, "Unknown"},
+ {0x8B, nullptr, "Unknown"},
+ {0x8C, nullptr, "Unknown"},
+ {0x8D, nullptr, "Unknown"},
+ {0x8E, nullptr, "Unknown"},
+ {0x8F, nullptr, "Unknown"},
+ {0x90, nullptr, "Unknown"},
+ {0x91, nullptr, "Unknown"},
+ {0x92, nullptr, "Unknown"},
+ {0x93, nullptr, "Unknown"},
+ {0x94, nullptr, "Unknown"},
+ {0x95, nullptr, "Unknown"},
+ {0x96, nullptr, "Unknown"},
+ {0x97, nullptr, "Unknown"},
+ {0x98, nullptr, "Unknown"},
+ {0x99, nullptr, "Unknown"},
+ {0x9A, nullptr, "Unknown"},
+ {0x9B, nullptr, "Unknown"},
+ {0x9C, nullptr, "Unknown"},
+ {0x9D, nullptr, "Unknown"},
+ {0x9E, nullptr, "Unknown"},
+ {0x9F, nullptr, "Unknown"},
+ {0xA0, nullptr, "Unknown"},
+ {0xA1, nullptr, "Unknown"},
+ {0xA2, nullptr, "Unknown"},
+ {0xA3, nullptr, "Unknown"},
+ {0xA4, nullptr, "Unknown"},
+ {0xA5, nullptr, "Unknown"},
+ {0xA6, nullptr, "Unknown"},
+ {0xA7, nullptr, "Unknown"},
+ {0xA8, nullptr, "Unknown"},
+ {0xA9, nullptr, "Unknown"},
+ {0xAA, nullptr, "Unknown"},
+ {0xAB, nullptr, "Unknown"},
+ {0xAC, nullptr, "Unknown"},
+ {0xAD, nullptr, "Unknown"},
+ {0xAE, nullptr, "Unknown"},
+ {0xAF, nullptr, "Unknown"},
+ {0xB0, nullptr, "Unknown"},
+ {0xB1, nullptr, "Unknown"},
+ {0xB2, nullptr, "Unknown"},
+ {0xB3, nullptr, "Unknown"},
+ {0xB4, nullptr, "Unknown"},
+ {0xB5, nullptr, "Unknown"},
+ {0xB6, nullptr, "Unknown"},
+ {0xB7, nullptr, "Unknown"},
+ {0xB8, nullptr, "Unknown"},
+ {0xB9, nullptr, "Unknown"},
+ {0xBA, nullptr, "Unknown"},
+ {0xBB, nullptr, "Unknown"},
+ {0xBC, nullptr, "Unknown"},
+ {0xBD, nullptr, "Unknown"},
+ {0xBE, nullptr, "Unknown"},
+ {0xBF, nullptr, "Unknown"},
};
static const FunctionDef SVC_Table_64[] = {
@@ -2586,6 +2654,70 @@ static const FunctionDef SVC_Table_64[] = {
{0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"},
{0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
{0x7F, nullptr, "CallSecureMonitor"},
+ {0x80, nullptr, "Unknown"},
+ {0x81, nullptr, "Unknown"},
+ {0x82, nullptr, "Unknown"},
+ {0x83, nullptr, "Unknown"},
+ {0x84, nullptr, "Unknown"},
+ {0x85, nullptr, "Unknown"},
+ {0x86, nullptr, "Unknown"},
+ {0x87, nullptr, "Unknown"},
+ {0x88, nullptr, "Unknown"},
+ {0x89, nullptr, "Unknown"},
+ {0x8A, nullptr, "Unknown"},
+ {0x8B, nullptr, "Unknown"},
+ {0x8C, nullptr, "Unknown"},
+ {0x8D, nullptr, "Unknown"},
+ {0x8E, nullptr, "Unknown"},
+ {0x8F, nullptr, "Unknown"},
+ {0x90, nullptr, "Unknown"},
+ {0x91, nullptr, "Unknown"},
+ {0x92, nullptr, "Unknown"},
+ {0x93, nullptr, "Unknown"},
+ {0x94, nullptr, "Unknown"},
+ {0x95, nullptr, "Unknown"},
+ {0x96, nullptr, "Unknown"},
+ {0x97, nullptr, "Unknown"},
+ {0x98, nullptr, "Unknown"},
+ {0x99, nullptr, "Unknown"},
+ {0x9A, nullptr, "Unknown"},
+ {0x9B, nullptr, "Unknown"},
+ {0x9C, nullptr, "Unknown"},
+ {0x9D, nullptr, "Unknown"},
+ {0x9E, nullptr, "Unknown"},
+ {0x9F, nullptr, "Unknown"},
+ {0xA0, nullptr, "Unknown"},
+ {0xA1, nullptr, "Unknown"},
+ {0xA2, nullptr, "Unknown"},
+ {0xA3, nullptr, "Unknown"},
+ {0xA4, nullptr, "Unknown"},
+ {0xA5, nullptr, "Unknown"},
+ {0xA6, nullptr, "Unknown"},
+ {0xA7, nullptr, "Unknown"},
+ {0xA8, nullptr, "Unknown"},
+ {0xA9, nullptr, "Unknown"},
+ {0xAA, nullptr, "Unknown"},
+ {0xAB, nullptr, "Unknown"},
+ {0xAC, nullptr, "Unknown"},
+ {0xAD, nullptr, "Unknown"},
+ {0xAE, nullptr, "Unknown"},
+ {0xAF, nullptr, "Unknown"},
+ {0xB0, nullptr, "Unknown"},
+ {0xB1, nullptr, "Unknown"},
+ {0xB2, nullptr, "Unknown"},
+ {0xB3, nullptr, "Unknown"},
+ {0xB4, nullptr, "Unknown"},
+ {0xB5, nullptr, "Unknown"},
+ {0xB6, nullptr, "Unknown"},
+ {0xB7, nullptr, "Unknown"},
+ {0xB8, nullptr, "Unknown"},
+ {0xB9, nullptr, "Unknown"},
+ {0xBA, nullptr, "Unknown"},
+ {0xBB, nullptr, "Unknown"},
+ {0xBC, nullptr, "Unknown"},
+ {0xBD, nullptr, "Unknown"},
+ {0xBE, nullptr, "Unknown"},
+ {0xBF, nullptr, "Unknown"},
};
static 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:
explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData
- {1, nullptr, "LoadAuthenticationTokenCache"}, // 6.0.0+
- {2, nullptr, "InvalidateAuthenticationTokenCache"}, // 6.0.0+
- {10, nullptr, "EnsureEdgeTokenCacheAsync"}, // 6.0.0+
- {11, nullptr, "LoadEdgeTokenCache"}, // 6.0.0+
- {12, nullptr, "InvalidateEdgeTokenCache"}, // 6.0.0+
+ {0, nullptr, "EnsureAuthenticationTokenCacheAsync"},
+ {1, nullptr, "LoadAuthenticationTokenCache"},
+ {2, nullptr, "InvalidateAuthenticationTokenCache"},
+ {10, nullptr, "EnsureEdgeTokenCacheAsync"},
+ {11, nullptr, "LoadEdgeTokenCache"},
+ {12, nullptr, "InvalidateEdgeTokenCache"},
+ {20, nullptr, "EnsureApplicationAuthenticationCacheAsync"},
+ {21, nullptr, "LoadApplicationAuthenticationTokenCache"},
+ {22, nullptr, "LoadApplicationNetworkServiceClientConfigCache"},
+ {23, nullptr, "IsApplicationAuthenticationCacheAvailable"},
+ {24, nullptr, "InvalidateApplicationAuthenticationCache"},
};
// clang-format on
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
{3, &ACC_SU::ListOpenUsers, "ListOpenUsers"},
{4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"},
{5, &ACC_SU::GetProfile, "GetProfile"},
- {6, nullptr, "GetProfileDigest"}, // 3.0.0+
+ {6, nullptr, "GetProfileDigest"},
{50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
{51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
- {60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0
- {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+
+ {60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
+ {99, nullptr, "DebugActivateOpenContextRetention"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
{102, nullptr, "GetBaasAccountManagerForSystemService"},
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
{104, nullptr, "GetProfileUpdateNotifier"},
- {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
- {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+
+ {105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
+ {106, nullptr, "GetProfileSyncNotifier"},
{110, &ACC_SU::StoreSaveDataThumbnailSystem, "StoreSaveDataThumbnail"},
{111, nullptr, "ClearSaveDataThumbnail"},
{112, nullptr, "LoadSaveDataThumbnail"},
- {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+
- {120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+
- {130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+
- {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
- {150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+
- {190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0
- {191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+
+ {113, nullptr, "GetSaveDataThumbnailExistence"},
+ {120, nullptr, "ListOpenUsersInApplication"},
+ {130, nullptr, "ActivateOpenContextRetention"},
+ {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"},
+ {150, nullptr, "AuthenticateApplicationAsync"},
+ {151, nullptr, "Unknown151"},
+ {152, nullptr, "Unknown152"},
+ {190, nullptr, "GetUserLastOpenedApplication"},
+ {191, nullptr, "ActivateOpenContextHolder"},
{200, nullptr, "BeginUserRegistration"},
{201, nullptr, "CompleteUserRegistration"},
{202, nullptr, "CancelUserRegistration"},
@@ -46,15 +48,15 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{204, nullptr, "SetUserPosition"},
{205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
{206, nullptr, "CompleteUserRegistrationForcibly"},
- {210, nullptr, "CreateFloatingRegistrationRequest"}, // 3.0.0+
- {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+
- {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+
+ {210, nullptr, "CreateFloatingRegistrationRequest"},
+ {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"},
+ {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"},
{230, nullptr, "AuthenticateServiceAsync"},
{250, nullptr, "GetBaasAccountAdministrator"},
{290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"},
- {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"}, // 3.0.0+
+ {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
{299, nullptr, "SuspendBackgroundDaemon"},
- {997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+
+ {997, nullptr, "DebugInvalidateTokenCacheForUser"},
{998, nullptr, "DebugSetUserStateClose"},
{999, nullptr, "DebugSetUserStateOpen"},
};
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
{3, &ACC_U1::ListOpenUsers, "ListOpenUsers"},
{4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"},
{5, &ACC_U1::GetProfile, "GetProfile"},
- {6, nullptr, "GetProfileDigest"}, // 3.0.0+
+ {6, nullptr, "GetProfileDigest"},
{50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
{51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
- {60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0
- {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+
+ {60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
+ {99, nullptr, "DebugActivateOpenContextRetention"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
{102, nullptr, "GetBaasAccountManagerForSystemService"},
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
{104, nullptr, "GetProfileUpdateNotifier"},
- {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
- {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+
+ {105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
+ {106, nullptr, "GetProfileSyncNotifier"},
{110, &ACC_U1::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"},
{111, nullptr, "ClearSaveDataThumbnail"},
{112, nullptr, "LoadSaveDataThumbnail"},
- {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+
- {120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+
- {130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+
- {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
- {150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+
- {190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0
- {191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+
- {997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+
+ {113, nullptr, "GetSaveDataThumbnailExistence"},
+ {120, nullptr, "ListOpenUsersInApplication"},
+ {130, nullptr, "ActivateOpenContextRetention"},
+ {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"},
+ {150, nullptr, "AuthenticateApplicationAsync"},
+ {151, nullptr, "Unknown151"},
+ {152, nullptr, "Unknown152"},
+ {190, nullptr, "GetUserLastOpenedApplication"},
+ {191, nullptr, "ActivateOpenContextHolder"},
+ {997, nullptr, "DebugInvalidateTokenCacheForUser"},
{998, nullptr, "DebugSetUserStateClose"},
{999, nullptr, "DebugSetUserStateOpen"},
};
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 @@
#include <fmt/format.h>
#include "common/file_util.h"
+#include "common/settings.h"
#include "core/hle/service/acc/profile_manager.h"
-#include "core/settings.h"
namespace Service::Account {
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 @@
#include <cinttypes>
#include <cstring>
#include "audio_core/audio_renderer.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -41,7 +42,6 @@
#include "core/hle/service/set/set.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi.h"
-#include "core/settings.h"
namespace Service::AM {
@@ -231,6 +231,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
{10, nullptr, "PerformSystemButtonPressing"},
{20, nullptr, "InvalidateTransitionLayer"},
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
+ {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
{40, nullptr, "GetAppletResourceUsageInfo"},
{100, nullptr, "SetCpuBoostModeForApplet"},
{101, nullptr, "CancelCpuBoostModeForApplet"},
@@ -242,6 +243,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
{130, nullptr, "FriendInvitationSetApplicationParameter"},
{131, nullptr, "FriendInvitationClearApplicationParameter"},
{132, nullptr, "FriendInvitationPushApplicationParameter"},
+ {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
};
// clang-format on
@@ -295,8 +297,9 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
{80, nullptr, "SetWirelessPriorityMode"},
{90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
- {100, nullptr, "SetAlbumImageTakenNotificationEnabled"},
+ {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
{110, nullptr, "SetApplicationAlbumUserData"},
+ {120, nullptr, "SaveCurrentScreenshot"},
{1000, nullptr, "GetDebugStorageChannel"},
};
// clang-format on
@@ -560,6 +563,21 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
}
+void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ // This service call sets an internal flag whether a notification is shown when an image is
+ // captured. Currently we do not support capturing images via the capture button, so this can be
+ // stubbed for now.
+ const bool album_image_taken_notification_enabled = rp.Pop<bool>();
+
+ LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}",
+ album_image_taken_notification_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived");
on_new_message->Initialize();
@@ -630,6 +648,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{11, nullptr, "ReleaseSleepLock"},
{12, nullptr, "ReleaseSleepLockTransiently"},
{13, nullptr, "GetAcquiredSleepLockEvent"},
+ {14, nullptr, "GetWakeupCount"},
{20, nullptr, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, nullptr, "GetReaderLockAccessorEx"},
@@ -641,6 +660,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
{54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
+ {59, nullptr, "SetVrPositionForDebug"},
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
{62, nullptr, "GetHdcpAuthenticationState"},
@@ -649,14 +669,21 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{65, nullptr, "GetApplicationIdByContentActionName"},
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{67, nullptr, "CancelCpuBoostMode"},
+ {68, nullptr, "GetBuiltInDisplayType"},
{80, nullptr, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
{100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
+ {110, nullptr, "OpenMyGpuErrorHandler"},
{200, nullptr, "GetOperationModeSystemInfo"},
{300, nullptr, "GetSettingsPlatformRegion"},
{400, nullptr, "ActivateMigrationService"},
{401, nullptr, "DeactivateMigrationService"},
+ {500, nullptr, "DisableSleepTillShutdown"},
+ {501, nullptr, "SuppressDisablingSleepTemporarily"},
+ {502, nullptr, "IsSleepEnabled"},
+ {503, nullptr, "IsDisablingSleepSuppressed"},
+ {900, nullptr, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
};
// clang-format on
@@ -944,7 +971,7 @@ private:
auto storage = applet->GetBroker().PopNormalDataToGame();
if (storage == nullptr) {
- LOG_ERROR(Service_AM,
+ LOG_DEBUG(Service_AM,
"storage is a nullptr. There is no data in the current normal channel");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL);
@@ -975,7 +1002,7 @@ private:
auto storage = applet->GetBroker().PopInteractiveDataToGame();
if (storage == nullptr) {
- LOG_ERROR(Service_AM,
+ LOG_DEBUG(Service_AM,
"storage is a nullptr. There is no data in the current interactive channel");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL);
@@ -1098,7 +1125,7 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
{2, nullptr, "AreAnyLibraryAppletsLeft"},
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
{11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
- {12, nullptr, "CreateHandleStorage"},
+ {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
};
RegisterHandlers(functions);
}
@@ -1107,14 +1134,15 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default;
void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
+
const auto applet_id = rp.PopRaw<Applets::AppletId>();
- const auto applet_mode = rp.PopRaw<u32>();
+ const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>();
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
applet_mode);
const auto& applet_manager{system.GetAppletManager()};
- const auto applet = applet_manager.GetApplet(applet_id);
+ const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
if (applet == nullptr) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
@@ -1132,9 +1160,18 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const u64 size{rp.Pop<u64>()};
+
+ const s64 size{rp.Pop<s64>()};
+
LOG_DEBUG(Service_AM, "called, size={}", size);
+ if (size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_UNKNOWN);
+ return;
+ }
+
std::vector<u8> buffer(size);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -1143,18 +1180,65 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
}
void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_AM, "called");
+ IPC::RequestParser rp{ctx};
+
+ struct Parameters {
+ u8 permissions;
+ s64 size;
+ };
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+ const auto handle{ctx.GetCopyHandle(0)};
+
+ LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions,
+ parameters.size, handle);
+
+ if (parameters.size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_UNKNOWN);
+ return;
+ }
+
+ auto transfer_mem =
+ system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
+
+ if (transfer_mem == nullptr) {
+ LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_UNKNOWN);
+ return;
+ }
+
+ const u8* const mem_begin = transfer_mem->GetPointer();
+ const u8* const mem_end = mem_begin + transfer_mem->GetSize();
+ std::vector<u8> memory{mem_begin, mem_end};
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IStorage>(system, std::move(memory));
+}
+void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- rp.SetCurrentOffset(3);
- const auto handle{rp.Pop<Kernel::Handle>()};
+ const s64 size{rp.Pop<s64>()};
+ const auto handle{ctx.GetCopyHandle(0)};
+
+ LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
+
+ if (size <= 0) {
+ LOG_ERROR(Service_AM, "size is less than or equal to 0");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_UNKNOWN);
+ return;
+ }
auto transfer_mem =
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
if (transfer_mem == nullptr) {
- LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
+ LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
return;
@@ -1188,11 +1272,14 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
{27, nullptr, "CreateCacheStorage"},
+ {28, nullptr, "GetSaveDataSizeMax"},
+ {29, nullptr, "GetCacheStorageMax"},
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
{33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
{34, nullptr, "SelectApplicationLicense"},
+ {35, nullptr, "GetDeviceSaveDataSizeMax"},
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
{50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
{60, nullptr, "SetMediaPlaybackStateForApplication"},
@@ -1216,6 +1303,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
+ {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
{141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
{150, nullptr, "GetNotificationStorageChannelEvent"},
@@ -1224,6 +1312,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{170, nullptr, "SetHdcpAuthenticationActivated"},
{180, nullptr, "GetLaunchRequiredVersion"},
{181, nullptr, "UpgradeLaunchRequiredVersion"},
+ {190, nullptr, "SendServerMaintenanceOverlayNotification"},
+ {200, nullptr, "GetLastApplicationExitReason"},
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, nullptr, "PrepareForJit"},
@@ -1690,9 +1780,12 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
{21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
{31, nullptr, "GetWriterLockAccessorEx"},
+ {40, nullptr, "IsSleepEnabled"},
+ {41, nullptr, "IsRebootEnabled"},
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
{110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
{200, nullptr, "LaunchDevMenu"},
+ {1000, nullptr, "SetLastApplicationExitReason"},
};
// clang-format on
@@ -1736,6 +1829,7 @@ IGlobalStateController::IGlobalStateController(Core::System& system_)
{13, nullptr, "UpdateDefaultDisplayResolution"},
{14, nullptr, "ShouldSleepOnBoot"},
{15, nullptr, "GetHdcpAuthenticationFailedEvent"},
+ {30, nullptr, "OpenCradleFirmwareUpdater"},
};
// clang-format on
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:
void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx);
void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
+ void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx);
enum class ScreenshotPermission : u32 {
Inherit = 0,
@@ -253,6 +254,7 @@ private:
void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
void CreateStorage(Kernel::HLERequestContext& ctx);
void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
+ void CreateHandleStorage(Kernel::HLERequestContext& ctx);
};
class 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() {
frontend = {};
}
-std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
+std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const {
switch (id) {
case AppletId::Auth:
- return std::make_shared<Auth>(system, *frontend.parental_controls);
+ return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
case AppletId::Controller:
- return std::make_shared<Controller>(system, *frontend.controller);
+ return std::make_shared<Controller>(system, mode, *frontend.controller);
case AppletId::Error:
- return std::make_shared<Error>(system, *frontend.error);
+ return std::make_shared<Error>(system, mode, *frontend.error);
case AppletId::ProfileSelect:
- return std::make_shared<ProfileSelect>(system, *frontend.profile_select);
+ return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
case AppletId::SoftwareKeyboard:
- return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard);
+ return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
case AppletId::Web:
case AppletId::Shop:
case AppletId::OfflineWeb:
case AppletId::LoginShare:
case AppletId::WebAuth:
- return std::make_shared<WebBrowser>(system, *frontend.web_browser);
+ return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser);
case AppletId::PhotoViewer:
- return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer);
+ return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer);
default:
UNIMPLEMENTED_MSG(
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
static_cast<u8>(id));
- return std::make_shared<StubApplet>(system, id);
+ return std::make_shared<StubApplet>(system, id, mode);
}
}
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 {
MyPage = 0x1A,
};
+enum class LibraryAppletMode : u32 {
+ AllForeground = 0,
+ Background = 1,
+ NoUI = 2,
+ BackgroundIndirectDisplay = 3,
+ AllForegroundInitiallyHidden = 4,
+};
+
class AppletDataBroker final {
public:
explicit AppletDataBroker(Kernel::KernelCore& kernel_);
@@ -200,7 +208,7 @@ public:
void SetDefaultAppletsIfMissing();
void ClearAll();
- std::shared_ptr<Applet> GetApplet(AppletId id) const;
+ std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
private:
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(
};
}
-Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_)
- : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
+Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::ControllerApplet& frontend_)
+ : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
Controller::~Controller() = default;
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,
class Controller final : public Applet {
public:
- explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_);
+ explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::ControllerApplet& frontend_);
~Controller() override;
void Initialize() override;
@@ -119,6 +120,7 @@ public:
void ConfigurationComplete();
private:
+ LibraryAppletMode applet_mode;
const Core::Frontend::ControllerApplet& frontend;
Core::System& system;
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) {
} // Anonymous namespace
-Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_)
- : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
+Error::Error(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::ErrorApplet& frontend_)
+ : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
Error::~Error() = default;
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 {
class Error final : public Applet {
public:
- explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_);
+ explicit Error(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::ErrorApplet& frontend_);
~Error() override;
void Initialize() override;
@@ -40,6 +41,7 @@ public:
private:
union ErrorArguments;
+ LibraryAppletMode applet_mode;
const Core::Frontend::ErrorApplet& frontend;
ResultCode error_code = RESULT_SUCCESS;
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)
}
}
-Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_)
- : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
+Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_,
+ Core::Frontend::ParentalControlsApplet& frontend_)
+ : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
Auth::~Auth() = default;
@@ -152,8 +153,9 @@ void Auth::AuthFinished(bool is_successful) {
broker.SignalStateChanged();
}
-PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_)
- : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
+PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::PhotoViewerApplet& frontend_)
+ : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
PhotoViewer::~PhotoViewer() = default;
@@ -202,8 +204,8 @@ void PhotoViewer::ViewFinished() {
broker.SignalStateChanged();
}
-StubApplet::StubApplet(Core::System& system_, AppletId id_)
- : Applet{system_.Kernel()}, id{id_}, system{system_} {}
+StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_)
+ : Applet{system_.Kernel()}, id{id_}, applet_mode{applet_mode_}, system{system_} {}
StubApplet::~StubApplet() = default;
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 {
class Auth final : public Applet {
public:
- explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_);
+ explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_,
+ Core::Frontend::ParentalControlsApplet& frontend_);
~Auth() override;
void Initialize() override;
@@ -32,6 +33,7 @@ public:
void AuthFinished(bool is_successful = true);
private:
+ LibraryAppletMode applet_mode;
Core::Frontend::ParentalControlsApplet& frontend;
Core::System& system;
bool complete = false;
@@ -50,7 +52,8 @@ enum class PhotoViewerAppletMode : u8 {
class PhotoViewer final : public Applet {
public:
- explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_);
+ explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::PhotoViewerApplet& frontend_);
~PhotoViewer() override;
void Initialize() override;
@@ -62,6 +65,7 @@ public:
void ViewFinished();
private:
+ LibraryAppletMode applet_mode;
const Core::Frontend::PhotoViewerApplet& frontend;
bool complete = false;
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
@@ -70,7 +74,7 @@ private:
class StubApplet final : public Applet {
public:
- explicit StubApplet(Core::System& system_, AppletId id_);
+ explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_);
~StubApplet() override;
void Initialize() override;
@@ -82,6 +86,7 @@ public:
private:
AppletId id;
+ LibraryAppletMode applet_mode;
Core::System& system;
};
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 {
constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
-ProfileSelect::ProfileSelect(Core::System& system_,
+ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_)
- : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
+ : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
ProfileSelect::~ProfileSelect() = default;
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
class ProfileSelect final : public Applet {
public:
- explicit ProfileSelect(Core::System& system_,
+ explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_);
~ProfileSelect() override;
@@ -47,6 +47,7 @@ public:
void SelectionComplete(std::optional<Common::UUID> uuid);
private:
+ LibraryAppletMode applet_mode;
const Core::Frontend::ProfileSelectApplet& frontend;
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 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <cstring>
-#include "common/assert.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/software_keyboard.h"
-#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/software_keyboard.h"
namespace Service::AM::Applets {
namespace {
-enum class Request : u32 {
- Finalize = 0x4,
- SetUserWordInfo = 0x6,
- SetCustomizeDic = 0x7,
- Calc = 0xa,
- SetCustomizedDictionaries = 0xb,
- UnsetCustomizedDictionaries = 0xc,
- UnknownD = 0xd,
- UnknownE = 0xe,
-};
-constexpr std::size_t SWKBD_INLINE_INIT_SIZE = 0x8;
-constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
-constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
-constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
-constexpr bool INTERACTIVE_STATUS_OK = false;
+
+// The maximum number of UTF-16 characters that can be input into the swkbd text field.
+constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500;
+
+constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType);
+constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4;
+constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC;
+
+constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) {
+ switch (text_check_result) {
+ case SwkbdTextCheckResult::Success:
+ return "Success";
+ case SwkbdTextCheckResult::Failure:
+ return "Failure";
+ case SwkbdTextCheckResult::Confirm:
+ return "Confirm";
+ case SwkbdTextCheckResult::Silent:
+ return "Silent";
+ default:
+ UNIMPLEMENTED_MSG("Unknown TextCheckResult={}", text_check_result);
+ return "Unknown";
+ }
+}
+
+void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply_type) {
+ std::memcpy(reply.data(), &state, sizeof(SwkbdState));
+ std::memcpy(reply.data() + sizeof(SwkbdState), &reply_type, sizeof(SwkbdReplyType));
+}
+
} // Anonymous namespace
-static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
- KeyboardConfig config, std::u16string initial_text) {
- Core::Frontend::SoftwareKeyboardParameters params{};
-
- params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
- config.submit_text.data(), config.submit_text.size());
- params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
- config.header_text.data(), config.header_text.size());
- params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(),
- config.sub_text.size());
- params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(),
- config.guide_text.size());
- params.initial_text = std::move(initial_text);
- params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit;
- params.password = static_cast<bool>(config.is_password);
- params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position);
- params.value = static_cast<u8>(config.keyset_disable_bitmask);
-
- return params;
-}
-
-SoftwareKeyboard::SoftwareKeyboard(Core::System& system_,
- const Core::Frontend::SoftwareKeyboardApplet& frontend_)
- : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
+
+SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
+ Core::Frontend::SoftwareKeyboardApplet& frontend_)
+ : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
SoftwareKeyboard::~SoftwareKeyboard() = default;
void SoftwareKeyboard::Initialize() {
- complete = false;
- is_inline = false;
- initial_text.clear();
- final_data.clear();
-
Applet::Initialize();
- const auto keyboard_config_storage = broker.PopNormalDataToApplet();
- ASSERT(keyboard_config_storage != nullptr);
- const auto& keyboard_config = keyboard_config_storage->GetData();
-
- if (keyboard_config.size() == SWKBD_INLINE_INIT_SIZE) {
- is_inline = true;
- return;
- }
-
- ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
- std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
+ LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}",
+ applet_mode);
- const auto work_buffer_storage = broker.PopNormalDataToApplet();
- ASSERT_OR_EXECUTE(work_buffer_storage != nullptr, { return; });
- const auto& work_buffer = work_buffer_storage->GetData();
+ LOG_DEBUG(Service_AM,
+ "Initializing Applet with common_args: arg_version={}, lib_version={}, "
+ "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
+ common_args.arguments_version, common_args.library_version,
+ common_args.play_startup_sound, common_args.size, common_args.system_tick,
+ common_args.theme_color);
- if (config.initial_string_size == 0)
- return;
+ swkbd_applet_version = SwkbdAppletVersion{common_args.library_version};
- std::vector<char16_t> string(config.initial_string_size);
- std::memcpy(string.data(), work_buffer.data() + config.initial_string_offset,
- string.size() * 2);
- initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size());
+ switch (applet_mode) {
+ case LibraryAppletMode::AllForeground:
+ InitializeForeground();
+ break;
+ case LibraryAppletMode::Background:
+ case LibraryAppletMode::BackgroundIndirectDisplay:
+ InitializeBackground(applet_mode);
+ break;
+ default:
+ UNREACHABLE_MSG("Invalid LibraryAppletMode={}", applet_mode);
+ break;
+ }
}
bool SoftwareKeyboard::TransactionComplete() const {
@@ -95,106 +82,996 @@ bool SoftwareKeyboard::TransactionComplete() const {
}
ResultCode SoftwareKeyboard::GetStatus() const {
- return RESULT_SUCCESS;
+ return status;
}
void SoftwareKeyboard::ExecuteInteractive() {
- if (complete)
+ if (complete) {
return;
+ }
- const auto storage = broker.PopInteractiveDataToApplet();
- ASSERT(storage != nullptr);
- const auto data = storage->GetData();
- if (!is_inline) {
- const auto status = static_cast<bool>(data[0]);
- if (status == INTERACTIVE_STATUS_OK) {
- complete = true;
- } else {
- std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
- std::memcpy(string.data(), data.data() + 4, string.size() * 2);
- frontend.SendTextCheckDialog(
- Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
- [this] { broker.SignalStateChanged(); });
- }
+ if (is_background) {
+ ProcessInlineKeyboardRequest();
} else {
- Request request{};
- std::memcpy(&request, data.data(), sizeof(Request));
+ ProcessTextCheck();
+ }
+}
+
+void SoftwareKeyboard::Execute() {
+ if (complete) {
+ return;
+ }
+
+ if (is_background) {
+ return;
+ }
+
+ ShowNormalKeyboard();
+}
- switch (request) {
- case Request::Finalize:
- complete = true;
- broker.SignalStateChanged();
+void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text) {
+ if (complete) {
+ return;
+ }
+
+ if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) {
+ SubmitForTextCheck(submitted_text);
+ } else {
+ SubmitNormalOutputAndExit(result, submitted_text);
+ }
+}
+
+void SoftwareKeyboard::SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
+ s32 cursor_position) {
+ if (complete) {
+ return;
+ }
+
+ current_text = std::move(submitted_text);
+ current_cursor_position = cursor_position;
+
+ if (inline_use_utf8) {
+ switch (reply_type) {
+ case SwkbdReplyType::ChangedString:
+ reply_type = SwkbdReplyType::ChangedStringUtf8;
break;
- case Request::Calc: {
- broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1}));
- broker.SignalStateChanged();
+ case SwkbdReplyType::MovedCursor:
+ reply_type = SwkbdReplyType::MovedCursorUtf8;
+ break;
+ case SwkbdReplyType::DecidedEnter:
+ reply_type = SwkbdReplyType::DecidedEnterUtf8;
+ break;
+ default:
break;
}
+ }
+
+ if (use_changed_string_v2) {
+ switch (reply_type) {
+ case SwkbdReplyType::ChangedString:
+ reply_type = SwkbdReplyType::ChangedStringV2;
+ break;
+ case SwkbdReplyType::ChangedStringUtf8:
+ reply_type = SwkbdReplyType::ChangedStringUtf8V2;
+ break;
default:
- UNIMPLEMENTED_MSG("Request {:X} is not implemented", request);
break;
}
}
+
+ if (use_moved_cursor_v2) {
+ switch (reply_type) {
+ case SwkbdReplyType::MovedCursor:
+ reply_type = SwkbdReplyType::MovedCursorV2;
+ break;
+ case SwkbdReplyType::MovedCursorUtf8:
+ reply_type = SwkbdReplyType::MovedCursorUtf8V2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ SendReply(reply_type);
}
-void SoftwareKeyboard::Execute() {
- if (complete) {
- broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
- broker.SignalStateChanged();
+void SoftwareKeyboard::InitializeForeground() {
+ LOG_INFO(Service_AM, "Initializing Normal Software Keyboard Applet.");
+
+ is_background = false;
+
+ const auto swkbd_config_storage = broker.PopNormalDataToApplet();
+ ASSERT(swkbd_config_storage != nullptr);
+
+ const auto& swkbd_config_data = swkbd_config_storage->GetData();
+ ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon));
+
+ std::memcpy(&swkbd_config_common, swkbd_config_data.data(), sizeof(SwkbdConfigCommon));
+
+ switch (swkbd_applet_version) {
+ case SwkbdAppletVersion::Version5:
+ case SwkbdAppletVersion::Version65542:
+ ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld));
+ std::memcpy(&swkbd_config_old, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
+ sizeof(SwkbdConfigOld));
+ break;
+ case SwkbdAppletVersion::Version196615:
+ case SwkbdAppletVersion::Version262152:
+ case SwkbdAppletVersion::Version327689:
+ ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld2));
+ std::memcpy(&swkbd_config_old2, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
+ sizeof(SwkbdConfigOld2));
+ break;
+ case SwkbdAppletVersion::Version393227:
+ case SwkbdAppletVersion::Version524301:
+ ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew));
+ std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
+ sizeof(SwkbdConfigNew));
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown SwkbdConfig revision={} with size={}", swkbd_applet_version,
+ swkbd_config_data.size());
+ ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew));
+ std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
+ sizeof(SwkbdConfigNew));
+ break;
+ }
+
+ const auto work_buffer_storage = broker.PopNormalDataToApplet();
+ ASSERT(work_buffer_storage != nullptr);
+
+ if (swkbd_config_common.initial_string_length == 0) {
+ InitializeFrontendKeyboard();
return;
}
- const auto parameters = ConvertToFrontendParameters(config, initial_text);
- if (!is_inline) {
- frontend.RequestText(
- [this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, parameters);
+ const auto& work_buffer = work_buffer_storage->GetData();
+
+ std::vector<char16_t> initial_string(swkbd_config_common.initial_string_length);
+
+ std::memcpy(initial_string.data(),
+ work_buffer.data() + swkbd_config_common.initial_string_offset,
+ swkbd_config_common.initial_string_length * sizeof(char16_t));
+
+ initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(initial_string.data(),
+ initial_string.size());
+
+ LOG_DEBUG(Service_AM, "\nInitial Text: {}", Common::UTF16ToUTF8(initial_text));
+
+ InitializeFrontendKeyboard();
+}
+
+void SoftwareKeyboard::InitializeBackground(LibraryAppletMode applet_mode) {
+ LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
+
+ is_background = true;
+
+ const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet();
+ ASSERT(swkbd_inline_initialize_arg_storage != nullptr);
+
+ const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData();
+ ASSERT(swkbd_inline_initialize_arg.size() == sizeof(SwkbdInitializeArg));
+
+ std::memcpy(&swkbd_initialize_arg, swkbd_inline_initialize_arg.data(),
+ swkbd_inline_initialize_arg.size());
+
+ if (swkbd_initialize_arg.library_applet_mode_flag) {
+ ASSERT(applet_mode == LibraryAppletMode::Background);
+ } else {
+ ASSERT(applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
+ }
+}
+
+void SoftwareKeyboard::ProcessTextCheck() {
+ const auto text_check_storage = broker.PopInteractiveDataToApplet();
+ ASSERT(text_check_storage != nullptr);
+
+ const auto& text_check_data = text_check_storage->GetData();
+ ASSERT(text_check_data.size() == sizeof(SwkbdTextCheck));
+
+ SwkbdTextCheck swkbd_text_check;
+
+ std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck));
+
+ std::u16string text_check_message = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_text_check.text_check_message.data(), swkbd_text_check.text_check_message.size());
+
+ LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}",
+ GetTextCheckResultName(swkbd_text_check.text_check_result),
+ Common::UTF16ToUTF8(text_check_message));
+
+ switch (swkbd_text_check.text_check_result) {
+ case SwkbdTextCheckResult::Success:
+ SubmitNormalOutputAndExit(SwkbdResult::Ok, current_text);
+ break;
+ case SwkbdTextCheckResult::Failure:
+ ShowTextCheckDialog(SwkbdTextCheckResult::Failure, text_check_message);
+ break;
+ case SwkbdTextCheckResult::Confirm:
+ ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, text_check_message);
+ break;
+ case SwkbdTextCheckResult::Silent:
+ default:
+ break;
}
}
-void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
- std::vector<u8> output_main(SWKBD_OUTPUT_BUFFER_SIZE);
+void SoftwareKeyboard::ProcessInlineKeyboardRequest() {
+ const auto request_data_storage = broker.PopInteractiveDataToApplet();
+ ASSERT(request_data_storage != nullptr);
+
+ const auto& request_data = request_data_storage->GetData();
+ ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand));
- if (text.has_value()) {
- std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
+ SwkbdRequestCommand request_command;
- if (config.utf_8) {
- const u64 size = text->size() + sizeof(u64);
- const auto new_text = Common::UTF16ToUTF8(*text);
+ std::memcpy(&request_command, request_data.data(), sizeof(SwkbdRequestCommand));
- std::memcpy(output_sub.data(), &size, sizeof(u64));
- std::memcpy(output_sub.data() + 8, new_text.data(),
- std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8));
+ switch (request_command) {
+ case SwkbdRequestCommand::Finalize:
+ RequestFinalize(request_data);
+ break;
+ case SwkbdRequestCommand::SetUserWordInfo:
+ RequestSetUserWordInfo(request_data);
+ break;
+ case SwkbdRequestCommand::SetCustomizeDic:
+ RequestSetCustomizeDic(request_data);
+ break;
+ case SwkbdRequestCommand::Calc:
+ RequestCalc(request_data);
+ break;
+ case SwkbdRequestCommand::SetCustomizedDictionaries:
+ RequestSetCustomizedDictionaries(request_data);
+ break;
+ case SwkbdRequestCommand::UnsetCustomizedDictionaries:
+ RequestUnsetCustomizedDictionaries(request_data);
+ break;
+ case SwkbdRequestCommand::SetChangedStringV2Flag:
+ RequestSetChangedStringV2Flag(request_data);
+ break;
+ case SwkbdRequestCommand::SetMovedCursorV2Flag:
+ RequestSetMovedCursorV2Flag(request_data);
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown SwkbdRequestCommand={}", request_command);
+ break;
+ }
+}
- output_main[0] = INTERACTIVE_STATUS_OK;
- std::memcpy(output_main.data() + 4, new_text.data(),
- std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4));
- } else {
- const u64 size = text->size() * 2 + sizeof(u64);
- std::memcpy(output_sub.data(), &size, sizeof(u64));
- std::memcpy(output_sub.data() + 8, text->data(),
- std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
+void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result,
+ std::u16string submitted_text) {
+ std::vector<u8> out_data(sizeof(SwkbdResult) + STRING_BUFFER_SIZE);
- output_main[0] = INTERACTIVE_STATUS_OK;
- std::memcpy(output_main.data() + 4, text->data(),
- std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
- }
+ if (swkbd_config_common.use_utf8) {
+ std::string utf8_submitted_text = Common::UTF16ToUTF8(submitted_text);
- complete = !config.text_check;
- final_data = output_main;
+ LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-8 Submitted Text: {}", result,
+ utf8_submitted_text);
- if (complete) {
- broker.PushNormalDataFromApplet(
- std::make_shared<IStorage>(system, std::move(output_main)));
- broker.SignalStateChanged();
- } else {
- broker.PushInteractiveDataFromApplet(
- std::make_shared<IStorage>(system, std::move(output_sub)));
- }
+ std::memcpy(out_data.data(), &result, sizeof(SwkbdResult));
+ std::memcpy(out_data.data() + sizeof(SwkbdResult), utf8_submitted_text.data(),
+ utf8_submitted_text.size());
} else {
- output_main[0] = 1;
- complete = true;
- broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(output_main)));
- broker.SignalStateChanged();
+ LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-16 Submitted Text: {}", result,
+ Common::UTF16ToUTF8(submitted_text));
+
+ std::memcpy(out_data.data(), &result, sizeof(SwkbdResult));
+ std::memcpy(out_data.data() + sizeof(SwkbdResult), submitted_text.data(),
+ submitted_text.size() * sizeof(char16_t));
+ }
+
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
+
+ ExitKeyboard();
+}
+
+void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
+ current_text = std::move(submitted_text);
+
+ std::vector<u8> out_data(sizeof(u64) + STRING_BUFFER_SIZE);
+
+ if (swkbd_config_common.use_utf8) {
+ std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text);
+ const u64 buffer_size = sizeof(u64) + utf8_submitted_text.size();
+
+ LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size,
+ utf8_submitted_text);
+
+ std::memcpy(out_data.data(), &buffer_size, sizeof(u64));
+ std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(),
+ utf8_submitted_text.size());
+ } else {
+ const u64 buffer_size = sizeof(u64) + current_text.size() * sizeof(char16_t);
+
+ LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size,
+ Common::UTF16ToUTF8(current_text));
+
+ std::memcpy(out_data.data(), &buffer_size, sizeof(u64));
+ std::memcpy(out_data.data() + sizeof(u64), current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ }
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
+}
+
+void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) {
+ switch (reply_type) {
+ case SwkbdReplyType::FinishedInitialize:
+ ReplyFinishedInitialize();
+ break;
+ case SwkbdReplyType::Default:
+ ReplyDefault();
+ break;
+ case SwkbdReplyType::ChangedString:
+ ReplyChangedString();
+ break;
+ case SwkbdReplyType::MovedCursor:
+ ReplyMovedCursor();
+ break;
+ case SwkbdReplyType::MovedTab:
+ ReplyMovedTab();
+ break;
+ case SwkbdReplyType::DecidedEnter:
+ ReplyDecidedEnter();
+ break;
+ case SwkbdReplyType::DecidedCancel:
+ ReplyDecidedCancel();
+ break;
+ case SwkbdReplyType::ChangedStringUtf8:
+ ReplyChangedStringUtf8();
+ break;
+ case SwkbdReplyType::MovedCursorUtf8:
+ ReplyMovedCursorUtf8();
+ break;
+ case SwkbdReplyType::DecidedEnterUtf8:
+ ReplyDecidedEnterUtf8();
+ break;
+ case SwkbdReplyType::UnsetCustomizeDic:
+ ReplyUnsetCustomizeDic();
+ break;
+ case SwkbdReplyType::ReleasedUserWordInfo:
+ ReplyReleasedUserWordInfo();
+ break;
+ case SwkbdReplyType::UnsetCustomizedDictionaries:
+ ReplyUnsetCustomizedDictionaries();
+ break;
+ case SwkbdReplyType::ChangedStringV2:
+ ReplyChangedStringV2();
+ break;
+ case SwkbdReplyType::MovedCursorV2:
+ ReplyMovedCursorV2();
+ break;
+ case SwkbdReplyType::ChangedStringUtf8V2:
+ ReplyChangedStringUtf8V2();
+ break;
+ case SwkbdReplyType::MovedCursorUtf8V2:
+ ReplyMovedCursorUtf8V2();
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown SwkbdReplyType={}", reply_type);
+ ReplyDefault();
+ break;
+ }
+}
+
+void SoftwareKeyboard::ChangeState(SwkbdState state) {
+ swkbd_state = state;
+
+ ReplyDefault();
+}
+
+void SoftwareKeyboard::InitializeFrontendKeyboard() {
+ if (is_background) {
+ const auto& appear_arg = swkbd_calc_arg.appear_arg;
+
+ std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ appear_arg.ok_text.data(), appear_arg.ok_text.size());
+
+ const u32 max_text_length =
+ appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
+ ? appear_arg.max_text_length
+ : DEFAULT_MAX_TEXT_LENGTH;
+
+ const u32 min_text_length =
+ appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
+
+ const s32 initial_cursor_position =
+ current_cursor_position > 0 ? current_cursor_position : 0;
+
+ const auto text_draw_type =
+ max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
+
+ Core::Frontend::KeyboardInitializeParameters initialize_parameters{
+ .ok_text{ok_text},
+ .header_text{},
+ .sub_text{},
+ .guide_text{},
+ .initial_text{current_text},
+ .max_text_length{max_text_length},
+ .min_text_length{min_text_length},
+ .initial_cursor_position{initial_cursor_position},
+ .type{appear_arg.type},
+ .password_mode{SwkbdPasswordMode::Disabled},
+ .text_draw_type{text_draw_type},
+ .key_disable_flags{appear_arg.key_disable_flags},
+ .use_blur_background{false},
+ .enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
+ .enable_return_button{appear_arg.enable_return_button},
+ .disable_cancel_button{appear_arg.disable_cancel_button},
+ };
+
+ frontend.InitializeKeyboard(
+ true, std::move(initialize_parameters), {},
+ [this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) {
+ SubmitTextInline(reply_type, submitted_text, cursor_position);
+ });
+ } else {
+ std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size());
+
+ std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size());
+
+ std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size());
+
+ std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size());
+
+ const u32 max_text_length =
+ swkbd_config_common.max_text_length > 0 &&
+ swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
+ ? swkbd_config_common.max_text_length
+ : DEFAULT_MAX_TEXT_LENGTH;
+
+ const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length
+ ? swkbd_config_common.min_text_length
+ : 0;
+
+ const s32 initial_cursor_position = [this] {
+ switch (swkbd_config_common.initial_cursor_position) {
+ case SwkbdInitialCursorPosition::Start:
+ default:
+ return 0;
+ case SwkbdInitialCursorPosition::End:
+ return static_cast<s32>(initial_text.size());
+ }
+ }();
+
+ const auto text_draw_type = [this, max_text_length] {
+ switch (swkbd_config_common.text_draw_type) {
+ case SwkbdTextDrawType::Line:
+ default:
+ return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
+ case SwkbdTextDrawType::Box:
+ case SwkbdTextDrawType::DownloadCode:
+ return swkbd_config_common.text_draw_type;
+ }
+ }();
+
+ const auto enable_return_button = text_draw_type == SwkbdTextDrawType::Box
+ ? swkbd_config_common.enable_return_button
+ : false;
+
+ const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227
+ ? swkbd_config_new.disable_cancel_button
+ : false;
+
+ Core::Frontend::KeyboardInitializeParameters initialize_parameters{
+ .ok_text{ok_text},
+ .header_text{header_text},
+ .sub_text{sub_text},
+ .guide_text{guide_text},
+ .initial_text{initial_text},
+ .max_text_length{max_text_length},
+ .min_text_length{min_text_length},
+ .initial_cursor_position{initial_cursor_position},
+ .type{swkbd_config_common.type},
+ .password_mode{swkbd_config_common.password_mode},
+ .text_draw_type{text_draw_type},
+ .key_disable_flags{swkbd_config_common.key_disable_flags},
+ .use_blur_background{swkbd_config_common.use_blur_background},
+ .enable_backspace_button{true},
+ .enable_return_button{enable_return_button},
+ .disable_cancel_button{disable_cancel_button},
+ };
+
+ frontend.InitializeKeyboard(false, std::move(initialize_parameters),
+ [this](SwkbdResult result, std::u16string submitted_text) {
+ SubmitTextNormal(result, submitted_text);
+ },
+ {});
+ }
+}
+
+void SoftwareKeyboard::ShowNormalKeyboard() {
+ frontend.ShowNormalKeyboard();
+}
+
+void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) {
+ frontend.ShowTextCheckDialog(text_check_result, text_check_message);
+}
+
+void SoftwareKeyboard::ShowInlineKeyboard() {
+ if (swkbd_state != SwkbdState::InitializedIsHidden) {
+ return;
+ }
+
+ ChangeState(SwkbdState::InitializedIsAppearing);
+
+ const auto& appear_arg = swkbd_calc_arg.appear_arg;
+
+ const u32 max_text_length =
+ appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
+ ? appear_arg.max_text_length
+ : DEFAULT_MAX_TEXT_LENGTH;
+
+ const u32 min_text_length =
+ appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
+
+ Core::Frontend::InlineAppearParameters appear_parameters{
+ .max_text_length{max_text_length},
+ .min_text_length{min_text_length},
+ .key_top_scale_x{swkbd_calc_arg.key_top_scale_x},
+ .key_top_scale_y{swkbd_calc_arg.key_top_scale_y},
+ .key_top_translate_x{swkbd_calc_arg.key_top_translate_x},
+ .key_top_translate_y{swkbd_calc_arg.key_top_translate_y},
+ .type{appear_arg.type},
+ .key_disable_flags{appear_arg.key_disable_flags},
+ .key_top_as_floating{swkbd_calc_arg.key_top_as_floating},
+ .enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
+ .enable_return_button{appear_arg.enable_return_button},
+ .disable_cancel_button{appear_arg.disable_cancel_button},
+ };
+
+ frontend.ShowInlineKeyboard(std::move(appear_parameters));
+
+ ChangeState(SwkbdState::InitializedIsShown);
+}
+
+void SoftwareKeyboard::HideInlineKeyboard() {
+ if (swkbd_state != SwkbdState::InitializedIsShown) {
+ return;
+ }
+
+ ChangeState(SwkbdState::InitializedIsDisappearing);
+
+ frontend.HideInlineKeyboard();
+
+ ChangeState(SwkbdState::InitializedIsHidden);
+}
+
+void SoftwareKeyboard::InlineTextChanged() {
+ Core::Frontend::InlineTextParameters text_parameters{
+ .input_text{current_text},
+ .cursor_position{current_cursor_position},
+ };
+
+ frontend.InlineTextChanged(std::move(text_parameters));
+}
+
+void SoftwareKeyboard::ExitKeyboard() {
+ complete = true;
+ status = RESULT_SUCCESS;
+
+ frontend.ExitKeyboard();
+
+ broker.SignalStateChanged();
+}
+
+// Inline Software Keyboard Requests
+
+void SoftwareKeyboard::RequestFinalize(const std::vector<u8>& request_data) {
+ LOG_DEBUG(Service_AM, "Processing Request: Finalize");
+
+ ChangeState(SwkbdState::NotInitialized);
+
+ ExitKeyboard();
+}
+
+void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector<u8>& request_data) {
+ LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented.");
+}
+
+void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector<u8>& request_data) {
+ LOG_WARNING(Service_AM, "SetCustomizeDic is not implemented.");
+}
+
+void SoftwareKeyboard::RequestCalc(const std::vector<u8>& request_data) {
+ LOG_DEBUG(Service_AM, "Processing Request: Calc");
+
+ ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArg));
+
+ std::memcpy(&swkbd_calc_arg, request_data.data() + sizeof(SwkbdRequestCommand),
+ sizeof(SwkbdCalcArg));
+
+ if (swkbd_calc_arg.flags.set_input_text) {
+ current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_calc_arg.input_text.data(), swkbd_calc_arg.input_text.size());
+ }
+
+ if (swkbd_calc_arg.flags.set_cursor_position) {
+ current_cursor_position = swkbd_calc_arg.cursor_position;
+ }
+
+ if (swkbd_calc_arg.flags.set_utf8_mode) {
+ inline_use_utf8 = swkbd_calc_arg.utf8_mode;
+ }
+
+ if (swkbd_state <= SwkbdState::InitializedIsHidden &&
+ swkbd_calc_arg.flags.unset_customize_dic) {
+ ReplyUnsetCustomizeDic();
}
+
+ if (swkbd_state <= SwkbdState::InitializedIsHidden &&
+ swkbd_calc_arg.flags.unset_user_word_info) {
+ ReplyReleasedUserWordInfo();
+ }
+
+ if (swkbd_state == SwkbdState::NotInitialized && swkbd_calc_arg.flags.set_initialize_arg) {
+ InitializeFrontendKeyboard();
+
+ ChangeState(SwkbdState::InitializedIsHidden);
+
+ ReplyFinishedInitialize();
+ }
+
+ if (!swkbd_calc_arg.flags.set_initialize_arg &&
+ (swkbd_calc_arg.flags.set_input_text || swkbd_calc_arg.flags.set_cursor_position)) {
+ InlineTextChanged();
+ }
+
+ if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg.flags.appear) {
+ ShowInlineKeyboard();
+ return;
+ }
+
+ if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg.flags.disappear) {
+ HideInlineKeyboard();
+ return;
+ }
+}
+
+void SoftwareKeyboard::RequestSetCustomizedDictionaries(const std::vector<u8>& request_data) {
+ LOG_WARNING(Service_AM, "SetCustomizedDictionaries is not implemented.");
+}
+
+void SoftwareKeyboard::RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data) {
+ LOG_WARNING(Service_AM, "(STUBBED) Processing Request: UnsetCustomizedDictionaries");
+
+ ReplyUnsetCustomizedDictionaries();
+}
+
+void SoftwareKeyboard::RequestSetChangedStringV2Flag(const std::vector<u8>& request_data) {
+ LOG_DEBUG(Service_AM, "Processing Request: SetChangedStringV2Flag");
+
+ ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1);
+
+ std::memcpy(&use_changed_string_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1);
+}
+
+void SoftwareKeyboard::RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data) {
+ LOG_DEBUG(Service_AM, "Processing Request: SetMovedCursorV2Flag");
+
+ ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1);
+
+ std::memcpy(&use_moved_cursor_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1);
+}
+
+// Inline Software Keyboard Replies
+
+void SoftwareKeyboard::ReplyFinishedInitialize() {
+ LOG_DEBUG(Service_AM, "Sending Reply: FinishedInitialize");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyDefault() {
+ LOG_DEBUG(Service_AM, "Sending Reply: Default");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyChangedString() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ChangedString");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedString);
+
+ const SwkbdChangedStringArg changed_string_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .dictionary_start_cursor_position{-1},
+ .dictionary_end_cursor_position{-1},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
+ sizeof(SwkbdChangedStringArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedCursor() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedCursor");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursor);
+
+ const SwkbdMovedCursorArg moved_cursor_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
+ sizeof(SwkbdMovedCursorArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedTab() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedTab");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedTabArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedTab);
+
+ const SwkbdMovedTabArg moved_tab_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg,
+ sizeof(SwkbdMovedTabArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyDecidedEnter() {
+ LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnter");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdDecidedEnterArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnter);
+
+ const SwkbdDecidedEnterArg decided_enter_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg,
+ sizeof(SwkbdDecidedEnterArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+
+ HideInlineKeyboard();
+}
+
+void SoftwareKeyboard::ReplyDecidedCancel() {
+ LOG_DEBUG(Service_AM, "Sending Reply: DecidedCancel");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+
+ HideInlineKeyboard();
+}
+
+void SoftwareKeyboard::ReplyChangedStringUtf8() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdChangedStringArg changed_string_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .dictionary_start_cursor_position{-1},
+ .dictionary_end_cursor_position{-1},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
+ sizeof(SwkbdChangedStringArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
}
+
+void SoftwareKeyboard::ReplyMovedCursorUtf8() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdMovedCursorArg moved_cursor_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
+ sizeof(SwkbdMovedCursorArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
+ LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnterUtf8");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdDecidedEnterArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnterUtf8);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdDecidedEnterArg decided_enter_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg,
+ sizeof(SwkbdDecidedEnterArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+
+ HideInlineKeyboard();
+}
+
+void SoftwareKeyboard::ReplyUnsetCustomizeDic() {
+ LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizeDic");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ReleasedUserWordInfo");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
+ LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizedDictionaries");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyChangedStringV2() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringV2");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg) + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringV2);
+
+ const SwkbdChangedStringArg changed_string_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .dictionary_start_cursor_position{-1},
+ .dictionary_end_cursor_position{-1},
+ .cursor_position{current_cursor_position},
+ };
+
+ constexpr u8 flag = 0;
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
+ sizeof(SwkbdChangedStringArg));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg),
+ &flag, 1);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedCursorV2() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorV2");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg) + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorV2);
+
+ const SwkbdMovedCursorArg moved_cursor_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ constexpr u8 flag = 0;
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
+ sizeof(SwkbdMovedCursorArg));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg),
+ &flag, 1);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8V2");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg) + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8V2);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdChangedStringArg changed_string_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .dictionary_start_cursor_position{-1},
+ .dictionary_end_cursor_position{-1},
+ .cursor_position{current_cursor_position},
+ };
+
+ constexpr u8 flag = 0;
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
+ sizeof(SwkbdChangedStringArg));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg),
+ &flag, 1);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8V2");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg) + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8V2);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdMovedCursorArg moved_cursor_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ constexpr u8 flag = 0;
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
+ sizeof(SwkbdMovedCursorArg));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg),
+ &flag, 1);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
} // 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 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
-#include <array>
-#include <string>
-#include <vector>
-
#include "common/common_funcs.h"
#include "common/common_types.h"
-#include "common/swap.h"
-#include "core/hle/service/am/am.h"
+#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
-
-union ResultCode;
+#include "core/hle/service/am/applets/software_keyboard_types.h"
namespace Core {
class System;
@@ -22,45 +16,10 @@ class System;
namespace Service::AM::Applets {
-enum class KeysetDisable : u32 {
- Space = 0x02,
- Address = 0x04,
- Percent = 0x08,
- Slashes = 0x10,
- Numbers = 0x40,
- DownloadCode = 0x80,
-};
-
-struct KeyboardConfig {
- INSERT_PADDING_BYTES(4);
- std::array<char16_t, 9> submit_text;
- u16_le left_symbol_key;
- u16_le right_symbol_key;
- INSERT_PADDING_BYTES(1);
- KeysetDisable keyset_disable_bitmask;
- u32_le initial_cursor_position;
- std::array<char16_t, 65> header_text;
- std::array<char16_t, 129> sub_text;
- std::array<char16_t, 257> guide_text;
- u32_le length_limit;
- INSERT_PADDING_BYTES(4);
- u32_le is_password;
- INSERT_PADDING_BYTES(5);
- bool utf_8;
- bool draw_background;
- u32_le initial_string_offset;
- u32_le initial_string_size;
- u32_le user_dictionary_offset;
- u32_le user_dictionary_size;
- bool text_check;
- u64_le text_check_callback;
-};
-static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size.");
-
class SoftwareKeyboard final : public Applet {
public:
- explicit SoftwareKeyboard(Core::System& system_,
- const Core::Frontend::SoftwareKeyboardApplet& frontend_);
+ explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
+ Core::Frontend::SoftwareKeyboardApplet& frontend_);
~SoftwareKeyboard() override;
void Initialize() override;
@@ -70,17 +29,139 @@ public:
void ExecuteInteractive() override;
void Execute() override;
- void WriteText(std::optional<std::u16string> text);
+ /**
+ * Submits the input text to the application.
+ * If text checking is enabled, the application will verify the input text.
+ * If use_utf8 is enabled, the input text will be converted to UTF-8 prior to being submitted.
+ * This should only be used by the normal software keyboard.
+ *
+ * @param result SwkbdResult enum
+ * @param submitted_text UTF-16 encoded string
+ */
+ void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text);
+
+ /**
+ * Submits the input text to the application.
+ * If utf8_mode is enabled, the input text will be converted to UTF-8 prior to being submitted.
+ * This should only be used by the inline software keyboard.
+ *
+ * @param reply_type SwkbdReplyType enum
+ * @param submitted_text UTF-16 encoded string
+ * @param cursor_position The current position of the text cursor
+ */
+ void SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
+ s32 cursor_position);
private:
- const Core::Frontend::SoftwareKeyboardApplet& frontend;
+ /// Initializes the normal software keyboard.
+ void InitializeForeground();
- KeyboardConfig config;
- std::u16string initial_text;
- bool complete = false;
- bool is_inline = false;
- std::vector<u8> final_data;
+ /// Initializes the inline software keyboard.
+ void InitializeBackground(LibraryAppletMode applet_mode);
+
+ /// Processes the text check sent by the application.
+ void ProcessTextCheck();
+
+ /// Processes the inline software keyboard request command sent by the application.
+ void ProcessInlineKeyboardRequest();
+
+ /// Submits the input text and exits the applet.
+ void SubmitNormalOutputAndExit(SwkbdResult result, std::u16string submitted_text);
+
+ /// Submits the input text for text checking.
+ void SubmitForTextCheck(std::u16string submitted_text);
+
+ /// Sends a reply to the application after processing a request command.
+ void SendReply(SwkbdReplyType reply_type);
+
+ /// Changes the inline keyboard state.
+ void ChangeState(SwkbdState state);
+
+ /**
+ * Signals the frontend to initialize the software keyboard with common parameters.
+ * This initializes either the normal software keyboard or the inline software keyboard
+ * depending on the state of is_background.
+ * Note that this does not cause the keyboard to appear.
+ * Use the respective Show*Keyboard() functions to cause the respective keyboards to appear.
+ */
+ void InitializeFrontendKeyboard();
+
+ /// Signals the frontend to show the normal software keyboard.
+ void ShowNormalKeyboard();
+
+ /// Signals the frontend to show the text check dialog.
+ void ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message);
+
+ /// Signals the frontend to show the inline software keyboard.
+ void ShowInlineKeyboard();
+
+ /// Signals the frontend to hide the inline software keyboard.
+ void HideInlineKeyboard();
+
+ /// Signals the frontend that the current inline keyboard text has changed.
+ void InlineTextChanged();
+
+ /// Signals both the frontend and application that the software keyboard is exiting.
+ void ExitKeyboard();
+
+ // Inline Software Keyboard Requests
+
+ void RequestFinalize(const std::vector<u8>& request_data);
+ void RequestSetUserWordInfo(const std::vector<u8>& request_data);
+ void RequestSetCustomizeDic(const std::vector<u8>& request_data);
+ void RequestCalc(const std::vector<u8>& request_data);
+ void RequestSetCustomizedDictionaries(const std::vector<u8>& request_data);
+ void RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data);
+ void RequestSetChangedStringV2Flag(const std::vector<u8>& request_data);
+ void RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data);
+
+ // Inline Software Keyboard Replies
+
+ void ReplyFinishedInitialize();
+ void ReplyDefault();
+ void ReplyChangedString();
+ void ReplyMovedCursor();
+ void ReplyMovedTab();
+ void ReplyDecidedEnter();
+ void ReplyDecidedCancel();
+ void ReplyChangedStringUtf8();
+ void ReplyMovedCursorUtf8();
+ void ReplyDecidedEnterUtf8();
+ void ReplyUnsetCustomizeDic();
+ void ReplyReleasedUserWordInfo();
+ void ReplyUnsetCustomizedDictionaries();
+ void ReplyChangedStringV2();
+ void ReplyMovedCursorV2();
+ void ReplyChangedStringUtf8V2();
+ void ReplyMovedCursorUtf8V2();
+
+ LibraryAppletMode applet_mode;
+ Core::Frontend::SoftwareKeyboardApplet& frontend;
Core::System& system;
+
+ SwkbdAppletVersion swkbd_applet_version;
+
+ SwkbdConfigCommon swkbd_config_common;
+ SwkbdConfigOld swkbd_config_old;
+ SwkbdConfigOld2 swkbd_config_old2;
+ SwkbdConfigNew swkbd_config_new;
+ std::u16string initial_text;
+
+ SwkbdState swkbd_state{SwkbdState::NotInitialized};
+ SwkbdInitializeArg swkbd_initialize_arg;
+ SwkbdCalcArg swkbd_calc_arg;
+ bool use_changed_string_v2{false};
+ bool use_moved_cursor_v2{false};
+ bool inline_use_utf8{false};
+ s32 current_cursor_position{};
+
+ std::u16string current_text;
+
+ bool is_background{false};
+
+ bool complete{false};
+ ResultCode status{RESULT_SUCCESS};
};
} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+
+namespace Service::AM::Applets {
+
+constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
+constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
+constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
+constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
+constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
+
+enum class SwkbdAppletVersion : u32_le {
+ Version5 = 0x5, // 1.0.0
+ Version65542 = 0x10006, // 2.0.0 - 2.3.0
+ Version196615 = 0x30007, // 3.0.0 - 3.0.2
+ Version262152 = 0x40008, // 4.0.0 - 4.1.0
+ Version327689 = 0x50009, // 5.0.0 - 5.1.0
+ Version393227 = 0x6000B, // 6.0.0 - 7.0.1
+ Version524301 = 0x8000D, // 8.0.0+
+};
+
+enum class SwkbdType : u32 {
+ Normal,
+ NumberPad,
+ Qwerty,
+ Unknown3,
+ Latin,
+ SimplifiedChinese,
+ TraditionalChinese,
+ Korean,
+};
+
+enum class SwkbdInitialCursorPosition : u32 {
+ Start,
+ End,
+};
+
+enum class SwkbdPasswordMode : u32 {
+ Disabled,
+ Enabled,
+};
+
+enum class SwkbdTextDrawType : u32 {
+ Line,
+ Box,
+ DownloadCode,
+};
+
+enum class SwkbdResult : u32 {
+ Ok,
+ Cancel,
+};
+
+enum class SwkbdTextCheckResult : u32 {
+ Success,
+ Failure,
+ Confirm,
+ Silent,
+};
+
+enum class SwkbdState : u32 {
+ NotInitialized = 0x0,
+ InitializedIsHidden = 0x1,
+ InitializedIsAppearing = 0x2,
+ InitializedIsShown = 0x3,
+ InitializedIsDisappearing = 0x4,
+};
+
+enum class SwkbdRequestCommand : u32 {
+ Finalize = 0x4,
+ SetUserWordInfo = 0x6,
+ SetCustomizeDic = 0x7,
+ Calc = 0xA,
+ SetCustomizedDictionaries = 0xB,
+ UnsetCustomizedDictionaries = 0xC,
+ SetChangedStringV2Flag = 0xD,
+ SetMovedCursorV2Flag = 0xE,
+};
+
+enum class SwkbdReplyType : u32 {
+ FinishedInitialize = 0x0,
+ Default = 0x1,
+ ChangedString = 0x2,
+ MovedCursor = 0x3,
+ MovedTab = 0x4,
+ DecidedEnter = 0x5,
+ DecidedCancel = 0x6,
+ ChangedStringUtf8 = 0x7,
+ MovedCursorUtf8 = 0x8,
+ DecidedEnterUtf8 = 0x9,
+ UnsetCustomizeDic = 0xA,
+ ReleasedUserWordInfo = 0xB,
+ UnsetCustomizedDictionaries = 0xC,
+ ChangedStringV2 = 0xD,
+ MovedCursorV2 = 0xE,
+ ChangedStringUtf8V2 = 0xF,
+ MovedCursorUtf8V2 = 0x10,
+};
+
+struct SwkbdKeyDisableFlags {
+ union {
+ u32 raw{};
+
+ BitField<1, 1, u32> space;
+ BitField<2, 1, u32> at;
+ BitField<3, 1, u32> percent;
+ BitField<4, 1, u32> slash;
+ BitField<5, 1, u32> backslash;
+ BitField<6, 1, u32> numbers;
+ BitField<7, 1, u32> download_code;
+ BitField<8, 1, u32> username;
+ };
+};
+static_assert(sizeof(SwkbdKeyDisableFlags) == 0x4, "SwkbdKeyDisableFlags has incorrect size.");
+
+struct SwkbdConfigCommon {
+ SwkbdType type{};
+ std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{};
+ char16_t left_optional_symbol_key{};
+ char16_t right_optional_symbol_key{};
+ bool use_prediction{};
+ INSERT_PADDING_BYTES(1);
+ SwkbdKeyDisableFlags key_disable_flags{};
+ SwkbdInitialCursorPosition initial_cursor_position{};
+ std::array<char16_t, MAX_HEADER_TEXT_LENGTH + 1> header_text{};
+ std::array<char16_t, MAX_SUB_TEXT_LENGTH + 1> sub_text{};
+ std::array<char16_t, MAX_GUIDE_TEXT_LENGTH + 1> guide_text{};
+ u32 max_text_length{};
+ u32 min_text_length{};
+ SwkbdPasswordMode password_mode{};
+ SwkbdTextDrawType text_draw_type{};
+ bool enable_return_button{};
+ bool use_utf8{};
+ bool use_blur_background{};
+ INSERT_PADDING_BYTES(1);
+ u32 initial_string_offset{};
+ u32 initial_string_length{};
+ u32 user_dictionary_offset{};
+ u32 user_dictionary_entries{};
+ bool use_text_check{};
+ INSERT_PADDING_BYTES(3);
+};
+static_assert(sizeof(SwkbdConfigCommon) == 0x3D4, "SwkbdConfigCommon has incorrect size.");
+
+#pragma pack(push, 4)
+// SwkbdAppletVersion 0x5, 0x10006
+struct SwkbdConfigOld {
+ INSERT_PADDING_WORDS(1);
+ VAddr text_check_callback{};
+};
+static_assert(sizeof(SwkbdConfigOld) == 0x3E0 - sizeof(SwkbdConfigCommon),
+ "SwkbdConfigOld has incorrect size.");
+
+// SwkbdAppletVersion 0x30007, 0x40008, 0x50009
+struct SwkbdConfigOld2 {
+ INSERT_PADDING_WORDS(1);
+ VAddr text_check_callback{};
+ std::array<u32, 8> text_grouping{};
+};
+static_assert(sizeof(SwkbdConfigOld2) == 0x400 - sizeof(SwkbdConfigCommon),
+ "SwkbdConfigOld2 has incorrect size.");
+
+// SwkbdAppletVersion 0x6000B, 0x8000D
+struct SwkbdConfigNew {
+ std::array<u32, 8> text_grouping{};
+ std::array<u64, 24> customized_dictionary_set_entries{};
+ u8 total_customized_dictionary_set_entries{};
+ bool disable_cancel_button{};
+ INSERT_PADDING_BYTES(18);
+};
+static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon),
+ "SwkbdConfigNew has incorrect size.");
+#pragma pack(pop)
+
+struct SwkbdTextCheck {
+ SwkbdTextCheckResult text_check_result{};
+ std::array<char16_t, STRING_BUFFER_SIZE / 2> text_check_message{};
+};
+static_assert(sizeof(SwkbdTextCheck) == 0x7D8, "SwkbdTextCheck has incorrect size.");
+
+struct SwkbdCalcArgFlags {
+ union {
+ u64 raw{};
+
+ BitField<0, 1, u64> set_initialize_arg;
+ BitField<1, 1, u64> set_volume;
+ BitField<2, 1, u64> appear;
+ BitField<3, 1, u64> set_input_text;
+ BitField<4, 1, u64> set_cursor_position;
+ BitField<5, 1, u64> set_utf8_mode;
+ BitField<6, 1, u64> unset_customize_dic;
+ BitField<7, 1, u64> disappear;
+ BitField<8, 1, u64> unknown;
+ BitField<9, 1, u64> set_key_top_translate_scale;
+ BitField<10, 1, u64> unset_user_word_info;
+ BitField<11, 1, u64> set_disable_hardware_keyboard;
+ };
+};
+static_assert(sizeof(SwkbdCalcArgFlags) == 0x8, "SwkbdCalcArgFlags has incorrect size.");
+
+struct SwkbdInitializeArg {
+ u32 unknown{};
+ bool library_applet_mode_flag{};
+ bool is_above_hos_500{};
+ INSERT_PADDING_BYTES(2);
+};
+static_assert(sizeof(SwkbdInitializeArg) == 0x8, "SwkbdInitializeArg has incorrect size.");
+
+struct SwkbdAppearArg {
+ SwkbdType type{};
+ std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{};
+ char16_t left_optional_symbol_key{};
+ char16_t right_optional_symbol_key{};
+ bool use_prediction{};
+ bool disable_cancel_button{};
+ SwkbdKeyDisableFlags key_disable_flags{};
+ u32 max_text_length{};
+ u32 min_text_length{};
+ bool enable_return_button{};
+ INSERT_PADDING_BYTES(3);
+ u32 flags{};
+ INSERT_PADDING_WORDS(6);
+};
+static_assert(sizeof(SwkbdAppearArg) == 0x48, "SwkbdAppearArg has incorrect size.");
+
+struct SwkbdCalcArg {
+ u32 unknown{};
+ u16 calc_arg_size{};
+ INSERT_PADDING_BYTES(2);
+ SwkbdCalcArgFlags flags{};
+ SwkbdInitializeArg initialize_arg{};
+ f32 volume{};
+ s32 cursor_position{};
+ SwkbdAppearArg appear_arg{};
+ std::array<char16_t, 0x1FA> input_text{};
+ bool utf8_mode{};
+ INSERT_PADDING_BYTES(1);
+ bool enable_backspace_button{};
+ INSERT_PADDING_BYTES(3);
+ bool key_top_as_floating{};
+ bool footer_scalable{};
+ bool alpha_enabled_in_input_mode{};
+ u8 input_mode_fade_type{};
+ bool disable_touch{};
+ bool disable_hardware_keyboard{};
+ INSERT_PADDING_BYTES(8);
+ f32 key_top_scale_x{};
+ f32 key_top_scale_y{};
+ f32 key_top_translate_x{};
+ f32 key_top_translate_y{};
+ f32 key_top_bg_alpha{};
+ f32 footer_bg_alpha{};
+ f32 balloon_scale{};
+ INSERT_PADDING_WORDS(4);
+ u8 se_group{};
+ INSERT_PADDING_BYTES(3);
+};
+static_assert(sizeof(SwkbdCalcArg) == 0x4A0, "SwkbdCalcArg has incorrect size.");
+
+struct SwkbdChangedStringArg {
+ u32 text_length{};
+ s32 dictionary_start_cursor_position{};
+ s32 dictionary_end_cursor_position{};
+ s32 cursor_position{};
+};
+static_assert(sizeof(SwkbdChangedStringArg) == 0x10, "SwkbdChangedStringArg has incorrect size.");
+
+struct SwkbdMovedCursorArg {
+ u32 text_length{};
+ s32 cursor_position{};
+};
+static_assert(sizeof(SwkbdMovedCursorArg) == 0x8, "SwkbdMovedCursorArg has incorrect size.");
+
+struct SwkbdMovedTabArg {
+ u32 text_length{};
+ s32 cursor_position{};
+};
+static_assert(sizeof(SwkbdMovedTabArg) == 0x8, "SwkbdMovedTabArg has incorrect size.");
+
+struct SwkbdDecidedEnterArg {
+ u32 text_length{};
+};
+static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size.");
+
+} // 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) {
} // namespace
-WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_)
- : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
+WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::WebBrowserApplet& frontend_)
+ : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend(frontend_), system{system_} {}
WebBrowser::~WebBrowser() = default;
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 {
class WebBrowser final : public Applet {
public:
- WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_);
+ WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::WebBrowserApplet& frontend_);
~WebBrowser() override;
@@ -63,6 +64,7 @@ private:
void ExecuteWifi();
void ExecuteLobby();
+ LibraryAppletMode applet_mode;
const Core::Frontend::WebBrowserApplet& frontend;
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 @@
#include <vector>
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
@@ -21,7 +22,6 @@
#include "core/hle/kernel/process.h"
#include "core/hle/service/aoc/aoc_u.h"
#include "core/loader/loader.h"
-#include "core/settings.h"
namespace Service::AOC {
@@ -118,8 +118,10 @@ AOC_U::AOC_U(Core::System& system_)
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
{9, nullptr, "GetAddOnContentLostErrorCode"},
+ {10, nullptr, "GetAddOnContentListChangedEventWithProcessId"},
{100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
{101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
+ {110, nullptr, "CreateContentsServiceManager"},
};
// clang-format on
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 @@
#include <utility>
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hle/service/apm/controller.h"
-#include "core/settings.h"
namespace Service::APM {
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 {
AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendAudioIns"},
- {1, nullptr, "RequestResumeAudioIns"},
- {2, nullptr, "GetAudioInsProcessMasterVolume"},
- {3, nullptr, "SetAudioInsProcessMasterVolume"},
+ {0, nullptr, "RequestSuspend"},
+ {1, nullptr, "RequestResume"},
+ {2, nullptr, "GetProcessMasterVolume"},
+ {3, nullptr, "SetProcessMasterVolume"},
};
// clang-format on
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:
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetAudioInState"},
- {1, nullptr, "StartAudioIn"},
- {2, nullptr, "StopAudioIn"},
+ {1, nullptr, "Start"},
+ {2, nullptr, "Stop"},
{3, nullptr, "AppendAudioInBuffer"},
{4, nullptr, "RegisterBufferEvent"},
{5, nullptr, "GetReleasedAudioInBuffer"},
{6, nullptr, "ContainsAudioInBuffer"},
- {7, nullptr, "AppendAudioInBufferWithUserEvent"},
+ {7, nullptr, "AppendUacInBuffer"},
{8, nullptr, "AppendAudioInBufferAuto"},
- {9, nullptr, "GetReleasedAudioInBufferAuto"},
- {10, nullptr, "AppendAudioInBufferWithUserEventAuto"},
+ {9, nullptr, "GetReleasedAudioInBuffersAuto"},
+ {10, nullptr, "AppendUacInBufferAuto"},
{11, nullptr, "GetAudioInBufferCount"},
- {12, nullptr, "SetAudioInDeviceGain"},
- {13, nullptr, "GetAudioInDeviceGain"},
+ {12, nullptr, "SetDeviceGain"},
+ {13, nullptr, "GetDeviceGain"},
{14, nullptr, "FlushAudioInBuffers"},
};
// 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 {
AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendAudioOuts"},
- {1, nullptr, "RequestResumeAudioOuts"},
- {2, nullptr, "GetAudioOutsProcessMasterVolume"},
- {3, nullptr, "SetAudioOutsProcessMasterVolume"},
- {4, nullptr, "GetAudioOutsProcessRecordVolume"},
- {5, nullptr, "SetAudioOutsProcessRecordVolume"},
+ {0, nullptr, "RequestSuspend"},
+ {1, nullptr, "RequestResume"},
+ {2, nullptr, "GetProcessMasterVolume"},
+ {3, nullptr, "SetProcessMasterVolume"},
+ {4, nullptr, "GetProcessRecordVolume"},
+ {5, nullptr, "SetProcessRecordVolume"},
};
// clang-format on
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:
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
- {1, &IAudioOut::StartAudioOut, "StartAudioOut"},
- {2, &IAudioOut::StopAudioOut, "StopAudioOut"},
+ {1, &IAudioOut::StartAudioOut, "Start"},
+ {2, &IAudioOut::StopAudioOut, "Stop"},
{3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
{4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
- {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"},
+ {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffers"},
{6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
{7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
{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 {
AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendFinalOutputRecorders"},
- {1, nullptr, "RequestResumeFinalOutputRecorders"},
+ {0, nullptr, "RequestSuspend"},
+ {1, nullptr, "RequestResume"},
};
// clang-format on
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:
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetFinalOutputRecorderState"},
- {1, nullptr, "StartFinalOutputRecorder"},
- {2, nullptr, "StopFinalOutputRecorder"},
+ {1, nullptr, "Start"},
+ {2, nullptr, "Stop"},
{3, nullptr, "AppendFinalOutputRecorderBuffer"},
{4, nullptr, "RegisterBufferEvent"},
- {5, nullptr, "GetReleasedFinalOutputRecorderBuffer"},
+ {5, nullptr, "GetReleasedFinalOutputRecorderBuffers"},
{6, nullptr, "ContainsFinalOutputRecorderBuffer"},
{7, nullptr, "GetFinalOutputRecorderBufferEndTime"},
{8, nullptr, "AppendFinalOutputRecorderBufferAuto"},
{9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"},
{10, nullptr, "FlushFinalOutputRecorderBuffers"},
+ {11, nullptr, "AttachWorkBuffer"},
};
// clang-format on
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 {
AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendAudioRenderers"},
- {1, nullptr, "RequestResumeAudioRenderers"},
- {2, nullptr, "GetAudioRenderersProcessMasterVolume"},
- {3, nullptr, "SetAudioRenderersProcessMasterVolume"},
+ {0, nullptr, "RequestSuspend"},
+ {1, nullptr, "RequestResume"},
+ {2, nullptr, "GetProcessMasterVolume"},
+ {3, nullptr, "SetProcessMasterVolume"},
{4, nullptr, "RegisterAppletResourceUserId"},
{5, nullptr, "UnregisterAppletResourceUserId"},
- {6, nullptr, "GetAudioRenderersProcessRecordVolume"},
- {7, nullptr, "SetAudioRenderersProcessRecordVolume"},
+ {6, nullptr, "GetProcessRecordVolume"},
+ {7, nullptr, "SetProcessRecordVolume"},
};
// clang-format on
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"}
// clang-format off
static const FunctionInfo functions[] = {
{0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
- {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
+ {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetWorkBufferSize"},
{2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
- {3, &AudRenU::OpenAudioRendererAuto, "OpenAudioRendererAuto"},
+ {3, &AudRenU::OpenAudioRendererForManualExecution, "OpenAudioRendererForManualExecution"},
{4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
};
// clang-format on
@@ -665,7 +665,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1'));
}
-void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) {
+void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
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:
void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
void GetAudioDeviceService(Kernel::HLERequestContext& ctx);
- void OpenAudioRendererAuto(Kernel::HLERequestContext& ctx);
+ void OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx);
void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
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 {
CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} {
static const FunctionInfo functions[] = {
- {0, nullptr, "InitializeCodecController"},
- {1, nullptr, "FinalizeCodecController"},
- {2, nullptr, "SleepCodecController"},
- {3, nullptr, "WakeCodecController"},
- {4, nullptr, "SetCodecVolume"},
- {5, nullptr, "GetCodecVolumeMax"},
- {6, nullptr, "GetCodecVolumeMin"},
- {7, nullptr, "SetCodecActiveTarget"},
- {8, nullptr, "GetCodecActiveTarget"},
- {9, nullptr, "BindCodecHeadphoneMicJackInterrupt"},
- {10, nullptr, "IsCodecHeadphoneMicJackInserted"},
- {11, nullptr, "ClearCodecHeadphoneMicJackInterrupt"},
- {12, nullptr, "IsCodecDeviceRequested"},
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Finalize"},
+ {2, nullptr, "Sleep"},
+ {3, nullptr, "Wake"},
+ {4, nullptr, "SetVolume"},
+ {5, nullptr, "GetVolumeMax"},
+ {6, nullptr, "GetVolumeMin"},
+ {7, nullptr, "SetActiveTarget"},
+ {8, nullptr, "GetActiveTarget"},
+ {9, nullptr, "BindHeadphoneMicJackInterrupt"},
+ {10, nullptr, "IsHeadphoneMicJackInserted"},
+ {11, nullptr, "ClearHeadphoneMicJackInterrupt"},
+ {12, nullptr, "IsRequested"},
};
RegisterHandlers(functions);
}
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"} {
{1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
{2, nullptr, "OpenOpusDecoderForMultiStream"},
{3, nullptr, "GetWorkBufferSizeForMultiStream"},
+ {4, nullptr, "OpenHardwareOpusDecoderEx"},
+ {5, nullptr, "GetWorkBufferSizeEx"},
+ {6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
+ {7, nullptr, "GetWorkBufferSizeForMultiStreamEx"},
};
RegisterHandlers(functions);
}
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 @@
#include "common/hex_util.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_libzip.h"
@@ -16,7 +17,6 @@
#include "core/frontend/applets/error.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/bcat/backend/boxcat.h"
-#include "core/settings.h"
namespace Service::BCAT {
namespace {
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 @@
#include "backend/boxcat.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/vfs.h"
@@ -18,7 +19,6 @@
#include "core/hle/service/bcat/bcat.h"
#include "core/hle/service/bcat/module.h"
#include "core/hle/service/filesystem/filesystem.h"
-#include "core/settings.h"
namespace Service::BCAT {
@@ -155,10 +155,12 @@ public:
{30210, nullptr, "SetDeliveryTaskTimer"},
{30300, nullptr, "RegisterSystemApplicationDeliveryTasks"},
{90100, nullptr, "EnumerateBackgroundDeliveryTask"},
+ {90101, nullptr, "Unknown90101"},
{90200, nullptr, "GetDeliveryList"},
{90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"},
{90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
{90300, nullptr, "GetPushNotificationLog"},
+ {90301, nullptr, "Unknown90301"},
};
// clang-format on
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:
{11, nullptr, "CreateWakeupTimerEx"},
{12, nullptr, "GetLastEnabledWakeupTimerType"},
{13, nullptr, "CleanAllWakeupTimers"},
- {14, nullptr, "Unknown"},
- {15, nullptr, "Unknown2"},
+ {14, nullptr, "GetPowerButton"},
+ {15, nullptr, "SetEnableWakeupTimer"},
};
// clang-format on
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:
{97, nullptr, "RegisterBleHidEvent"},
{98, nullptr, "SetBleScanParameter"},
{99, nullptr, "MoveToSecondaryPiconet"},
+ {100, nullptr, "IsBluetoothEnabled"},
+ {128, nullptr, "AcquireAudioEvent"},
+ {129, nullptr, "GetAudioEventInfo"},
+ {130, nullptr, "OpenAudioConnection"},
+ {131, nullptr, "CloseAudioConnection"},
+ {132, nullptr, "OpenAudioOut"},
+ {133, nullptr, "CloseAudioOut"},
+ {134, nullptr, "AcquireAudioOutStateChangedEvent"},
+ {135, nullptr, "StartAudioOut"},
+ {136, nullptr, "StopAudioOut"},
+ {137, nullptr, "GetAudioOutState"},
+ {138, nullptr, "GetAudioOutFeedingCodec"},
+ {139, nullptr, "GetAudioOutFeedingParameter"},
+ {140, nullptr, "AcquireAudioOutBufferAvailableEvent"},
+ {141, nullptr, "SendAudioData"},
+ {142, nullptr, "AcquireAudioControlInputStateChangedEvent"},
+ {143, nullptr, "GetAudioControlInputState"},
+ {144, nullptr, "AcquireAudioConnectionStateChangedEvent"},
+ {145, nullptr, "GetConnectedAudioDevice"},
{256, nullptr, "IsManufacturingMode"},
{257, nullptr, "EmulateBluetoothCrash"},
{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:
{10, nullptr, "GetGattClientDisconnectionReason"},
{11, nullptr, "GetBleConnectionParameter"},
{12, nullptr, "GetBleConnectionParameterRequest"},
+ {13, nullptr, "Unknown13"},
};
// clang-format on
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"} {
{16, nullptr, "GetAlbumMountResult"},
{17, nullptr, "GetAlbumUsage16"},
{18, nullptr, "Unknown18"},
+ {19, nullptr, "Unknown19"},
{100, nullptr, "GetAlbumFileCountEx0"},
{101, nullptr, "GetAlbumFileListEx0"},
{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"} {
{141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
{142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
{143, nullptr, "GetAlbumFileList4AaeUidAruid"},
+ {144, nullptr, "GetAllAlbumFileList3AaeAruid"},
{60002, nullptr, "OpenAccessorSessionForApplication"},
};
// 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:
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SubmitContext"},
- {1, nullptr, "CreateReport"},
+ {1, nullptr, "CreateReportV0"},
{2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
{3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
{4, nullptr, "UpdatePowerOnTime"},
@@ -26,6 +26,11 @@ public:
{8, nullptr, "ClearApplicationLaunchTime"},
{9, nullptr, "SubmitAttachment"},
{10, nullptr, "CreateReportWithAttachments"},
+ {11, nullptr, "CreateReport"},
+ {20, nullptr, "RegisterRunningApplet"},
+ {21, nullptr, "UnregisterRunningApplet"},
+ {22, nullptr, "UpdateAppletSuspendedDuration"},
+ {30, nullptr, "InvalidateForcedShutdownDetection"},
};
// clang-format on
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 @@
#include "common/assert.h"
#include "common/file_util.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.h"
@@ -26,7 +27,6 @@
#include "core/hle/service/filesystem/fsp_pr.h"
#include "core/hle/service/filesystem/fsp_srv.h"
#include "core/loader/loader.h"
-#include "core/settings.h"
namespace Service::FileSystem {
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:
explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
: ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
- {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"},
- {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"},
- {4, &IFile::GetSize, "GetSize"}, {5, nullptr, "OperateRange"},
+ {0, &IFile::Read, "Read"},
+ {1, &IFile::Write, "Write"},
+ {2, &IFile::Flush, "Flush"},
+ {3, &IFile::SetSize, "SetSize"},
+ {4, &IFile::GetSize, "GetSize"},
+ {5, nullptr, "OperateRange"},
+ {6, nullptr, "OperateRangeWithBuffer"},
};
RegisterHandlers(functions);
}
@@ -708,7 +712,10 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
{85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
{86, nullptr, "OpenSaveDataMover"},
+ {87, nullptr, "OpenSaveDataTransferManagerForRepair"},
{100, nullptr, "OpenImageDirectoryFileSystem"},
+ {101, nullptr, "OpenBaseFileSystem"},
+ {102, nullptr, "FormatBaseFileSystem"},
{110, nullptr, "OpenContentStorageFileSystem"},
{120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
{130, nullptr, "OpenCustomStorageFileSystem"},
@@ -764,10 +771,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{1008, nullptr, "OpenRegisteredUpdatePartition"},
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1010, nullptr, "SetDataStorageRedirectTarget"},
- {1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"},
+ {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"},
{1012, nullptr, "GetFsStackUsage"},
{1013, nullptr, "UnsetSaveDataRootPath"},
{1014, nullptr, "OutputMultiProgramTagAccessLog"},
+ {1016, nullptr, "FlushAccessLogOnSdCard"},
+ {1017, nullptr, "OutputApplicationInfoAccessLog"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
{1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
@@ -1051,7 +1060,7 @@ void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
-void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
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:
void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
- void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
+ void GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx);
void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
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:
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
{10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
{10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
- {10700, nullptr, "GetPlayHistoryRegistrationKey"},
+ {10700, &IFriendService::GetPlayHistoryRegistrationKey, "GetPlayHistoryRegistrationKey"},
{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
{10702, nullptr, "AddPlayHistory"},
{11000, nullptr, "GetProfileImageUrl"},
@@ -153,6 +153,18 @@ private:
rb.Push(RESULT_SUCCESS);
}
+ void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto local_play = rp.Pop<bool>();
+ const auto uuid = rp.PopRaw<Common::UUID>();
+
+ LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play,
+ uuid.Format());
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
void GetFriendList(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
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_)
{1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"},
{2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"},
{3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"},
+ {4, nullptr, "GetApplicationInstanceUnregistrationNotifier"},
+ {5, nullptr, "ListApplicationInstanceId"},
+ {6, nullptr, "GetMicroApplicationInstanceId"},
+ {7, nullptr, "GetApplicationCertificate"},
+ {9998, nullptr, "GetPreomiaApplicationLaunchProperty"},
+ {9999, nullptr, "GetPreomiaApplicationControlProperty"},
};
// clang-format on
@@ -243,7 +249,8 @@ ARP_W::ARP_W(Core::System& system_, ARPManager& manager_)
// clang-format off
static const FunctionInfo functions[] = {
{0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
- {1, &ARP_W::DeleteProperties, "DeleteProperties"},
+ {1, &ARP_W::UnregisterApplicationInstance , "UnregisterApplicationInstance "},
+ {2, nullptr, "AcquireUpdater"},
};
// clang-format on
@@ -270,7 +277,7 @@ void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface(registrar);
}
-void ARP_W::DeleteProperties(Kernel::HLERequestContext& ctx) {
+void ARP_W::UnregisterApplicationInstance(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
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:
private:
void AcquireRegistrar(Kernel::HLERequestContext& ctx);
- void DeleteProperties(Kernel::HLERequestContext& ctx);
+ void UnregisterApplicationInstance(Kernel::HLERequestContext& ctx);
ARPManager& manager;
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hle/ipc_helpers.h"
#include "core/hle/service/glue/bgtc.h"
namespace Service::Glue {
@@ -9,6 +12,26 @@ namespace Service::Glue {
BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
// clang-format off
static const FunctionInfo functions[] = {
+ {100, &BGTC_T::OpenTaskService, "OpenTaskService"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+BGTC_T::~BGTC_T() = default;
+
+void BGTC_T::OpenTaskService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_BGTC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ITaskService>(system);
+}
+
+ITaskService::ITaskService(Core::System& system_) : ServiceFramework{system_, "ITaskService"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
{1, nullptr, "NotifyTaskStarting"},
{2, nullptr, "NotifyTaskFinished"},
{3, nullptr, "GetTriggerEvent"},
@@ -20,16 +43,18 @@ BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
{13, nullptr, "UnscheduleTask"},
{14, nullptr, "GetScheduleEvent"},
{15, nullptr, "SchedulePeriodicTask"},
+ {16, nullptr, "Unknown16"},
{101, nullptr, "GetOperationMode"},
{102, nullptr, "WillDisconnectNetworkWhenEnteringSleep"},
{103, nullptr, "WillStayHalfAwakeInsteadSleep"},
+ {200, nullptr, "Unknown200"},
};
// clang-format on
RegisterHandlers(functions);
}
-BGTC_T::~BGTC_T() = default;
+ITaskService::~ITaskService() = default;
BGTC_SC::BGTC_SC(Core::System& system_) : ServiceFramework{system_, "bgtc:sc"} {
// 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> {
public:
explicit BGTC_T(Core::System& system_);
~BGTC_T() override;
+
+ void OpenTaskService(Kernel::HLERequestContext& ctx);
+};
+
+class ITaskService final : public ServiceFramework<ITaskService> {
+public:
+ explicit ITaskService(Core::System& system_);
+ ~ITaskService() override;
};
class 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 @@
#include <cstring>
#include "common/common_types.h"
+#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hle/service/hid/controllers/debug_pad.h"
-#include "core/settings.h"
namespace Service::HID {
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 @@
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "common/settings.h"
#include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/settings.h"
namespace Service::HID {
class 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 @@
#include <cstring>
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/hle/service/hid/controllers/gesture.h"
-#include "core/settings.h"
namespace Service::HID {
constexpr 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 @@
#include <cstring>
#include "common/common_types.h"
+#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hle/service/hid/controllers/keyboard.h"
-#include "core/settings.h"
namespace Service::HID {
constexpr 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 @@
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "common/settings.h"
#include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/settings.h"
namespace Service::HID {
class 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 @@
#include <array>
#include "common/bit_field.h"
#include "common/common_types.h"
+#include "common/settings.h"
#include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/settings.h"
namespace Service::HID {
class 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 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/input.h"
@@ -17,7 +18,6 @@
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/hid/controllers/npad.h"
-#include "core/settings.h"
namespace Service::HID {
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
@@ -413,12 +413,16 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
}
- if (controller_type == NPadControllerType::JoyLeft ||
- controller_type == NPadControllerType::JoyRight) {
+ if (controller_type == NPadControllerType::JoyLeft) {
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
}
+ if (controller_type == NPadControllerType::JoyRight) {
+ pad_state.right_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.right_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
+ }
+
if (controller_type == NPadControllerType::GameCube) {
trigger_entry.l_analog = static_cast<s32>(
button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0);
@@ -1134,6 +1138,10 @@ void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_prot
unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
}
+void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
+ analog_stick_use_center_clamp = use_center_clamp;
+}
+
void Controller_NPad::ClearAllConnectedControllers() {
for (auto& controller : connected_controllers) {
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 @@
#include <atomic>
#include "common/bit_field.h"
#include "common/common_types.h"
+#include "common/settings.h"
#include "core/frontend/input.h"
#include "core/hle/kernel/object.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/settings.h"
namespace Kernel {
class KEvent;
@@ -219,6 +219,7 @@ public:
LedPattern GetLedPattern(u32 npad_id);
bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
+ void SetAnalogStickUseCenterClamp(bool use_center_clamp);
void ClearAllConnectedControllers();
void DisconnectAllConnectedControllers();
void ConnectAllDisconnectedControllers();
@@ -577,6 +578,7 @@ private:
std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
std::array<ControllerHolder, 10> connected_controllers{};
std::array<bool, 10> unintended_home_button_input_protection{};
+ bool analog_stick_use_center_clamp{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
bool sixaxis_sensors_enabled{true};
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 @@
#include <cstring>
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
-#include "core/settings.h"
namespace Service::HID {
constexpr 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 @@
#include <array>
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
@@ -23,7 +24,6 @@
#include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/xcd.h"
#include "core/hle/service/service.h"
-#include "core/settings.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/debug_pad.h"
@@ -263,7 +263,7 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
{131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
{132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
- {134, nullptr, "SetNpadAnalogStickUseCenterClamp"},
+ {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
{135, nullptr, "SetNpadCaptureButtonAssignment"},
{136, nullptr, "ClearNpadCaptureButtonAssignment"},
{200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
@@ -278,6 +278,7 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
{209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
{210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
{211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
+ {212, nullptr, "SendVibrationValueInBool"},
{300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
{301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
{302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@@ -1087,6 +1088,27 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
rb.Push(RESULT_SUCCESS);
}
+void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool analog_stick_use_center_clamp;
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ applet_resource->GetController<Controller_NPad>(HidController::NPad)
+ .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
+ parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
@@ -1553,6 +1575,7 @@ public:
{11, nullptr, "SetTouchScreenAutoPilotState"},
{12, nullptr, "UnsetTouchScreenAutoPilotState"},
{13, nullptr, "GetTouchScreenConfiguration"},
+ {14, nullptr, "ProcessTouchScreenAutoTune"},
{20, nullptr, "DeactivateMouse"},
{21, nullptr, "SetMouseAutoPilotState"},
{22, nullptr, "UnsetMouseAutoPilotState"},
@@ -1562,6 +1585,7 @@ public:
{50, nullptr, "DeactivateXpad"},
{51, nullptr, "SetXpadAutoPilotState"},
{52, nullptr, "UnsetXpadAutoPilotState"},
+ {53, nullptr, "DeactivateJoyXpad"},
{60, nullptr, "ClearNpadSystemCommonPolicy"},
{61, nullptr, "DeactivateNpad"},
{62, nullptr, "ForceDisconnectNpad"},
@@ -1632,6 +1656,11 @@ public:
{244, nullptr, "RequestKuinaFirmwareVersion"},
{245, nullptr, "GetKuinaFirmwareVersion"},
{246, nullptr, "GetVidPid"},
+ {247, nullptr, "GetAnalogStickCalibrationValue"},
+ {248, nullptr, "GetUniquePadIdsFull"},
+ {249, nullptr, "ConnectUniquePad"},
+ {250, nullptr, "IsVirtual"},
+ {251, nullptr, "GetAnalogStickModuleParam"},
{301, nullptr, "GetAbstractedPadHandles"},
{302, nullptr, "GetAbstractedPadState"},
{303, nullptr, "GetAbstractedPadsState"},
@@ -1652,12 +1681,16 @@ public:
{401, nullptr, "DisableRailDeviceFiltering"},
{402, nullptr, "EnableWiredPairing"},
{403, nullptr, "EnableShipmentModeAutoClear"},
+ {404, nullptr, "SetRailEnabled"},
{500, nullptr, "SetFactoryInt"},
{501, nullptr, "IsFactoryBootEnabled"},
{550, nullptr, "SetAnalogStickModelDataTemporarily"},
{551, nullptr, "GetAnalogStickModelData"},
{552, nullptr, "ResetAnalogStickModelData"},
{600, nullptr, "ConvertPadState"},
+ {650, nullptr, "AddButtonPlayData"},
+ {651, nullptr, "StartButtonPlayData"},
+ {652, nullptr, "StopButtonPlayData"},
{2000, nullptr, "DeactivateDigitizer"},
{2001, nullptr, "SetDigitizerAutoPilotState"},
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
@@ -1689,6 +1722,8 @@ public:
{215, nullptr, "IsNfcActivated"},
{230, nullptr, "AcquireIrSensorEventHandle"},
{231, nullptr, "ActivateIrSensor"},
+ {232, nullptr, "GetIrSensorState"},
+ {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
{301, nullptr, "ActivateNpadSystem"},
{303, nullptr, "ApplyNpadSystemCommonPolicy"},
{304, nullptr, "EnableAssigningSingleOnSlSrPress"},
@@ -1703,9 +1738,16 @@ public:
{313, nullptr, "GetNpadCaptureButtonAssignment"},
{314, nullptr, "GetAppletFooterUiType"},
{315, nullptr, "GetAppletDetailedUiType"},
+ {316, nullptr, "GetNpadInterfaceType"},
+ {317, nullptr, "GetNpadLeftRightInterfaceType"},
+ {318, nullptr, "HasBattery"},
+ {319, nullptr, "HasLeftRightBattery"},
{321, nullptr, "GetUniquePadsFromNpad"},
{322, nullptr, "GetIrSensorState"},
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
+ {324, nullptr, "GetUniquePadButtonSet"},
+ {325, nullptr, "GetUniquePadColor"},
+ {326, nullptr, "GetUniquePadAppletDetailedUiType"},
{500, nullptr, "SetAppletResourceUserId"},
{501, nullptr, "RegisterAppletResourceUserId"},
{502, nullptr, "UnregisterAppletResourceUserId"},
@@ -1716,10 +1758,13 @@ public:
{511, nullptr, "GetVibrationMasterVolume"},
{512, nullptr, "BeginPermitVibrationSession"},
{513, nullptr, "EndPermitVibrationSession"},
+ {514, nullptr, "Unknown514"},
{520, nullptr, "EnableHandheldHids"},
{521, nullptr, "DisableHandheldHids"},
{522, nullptr, "SetJoyConRailEnabled"},
{523, nullptr, "IsJoyConRailEnabled"},
+ {524, nullptr, "IsHandheldHidsEnabled"},
+ {525, nullptr, "IsJoyConAttachedOnAllRail"},
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
{541, nullptr, "GetPlayReportControllerUsages"},
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
@@ -1795,6 +1840,65 @@ public:
{1154, nullptr, "IsFirmwareAvailableForNotification"},
{1155, nullptr, "SetForceHandheldStyleVibration"},
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
+ {1157, nullptr, "CancelConnectionTrigger"},
+ {1200, nullptr, "IsButtonConfigSupported"},
+ {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
+ {1202, nullptr, "DeleteButtonConfig"},
+ {1203, nullptr, "DeleteButtonConfigEmbedded"},
+ {1204, nullptr, "SetButtonConfigEnabled"},
+ {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
+ {1206, nullptr, "IsButtonConfigEnabled"},
+ {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
+ {1208, nullptr, "SetButtonConfigEmbedded"},
+ {1209, nullptr, "SetButtonConfigFull"},
+ {1210, nullptr, "SetButtonConfigLeft"},
+ {1211, nullptr, "SetButtonConfigRight"},
+ {1212, nullptr, "GetButtonConfigEmbedded"},
+ {1213, nullptr, "GetButtonConfigFull"},
+ {1214, nullptr, "GetButtonConfigLeft"},
+ {1215, nullptr, "GetButtonConfigRight"},
+ {1250, nullptr, "IsCustomButtonConfigSupported"},
+ {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
+ {1252, nullptr, "IsDefaultButtonConfigFull"},
+ {1253, nullptr, "IsDefaultButtonConfigLeft"},
+ {1254, nullptr, "IsDefaultButtonConfigRight"},
+ {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
+ {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
+ {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
+ {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
+ {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
+ {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
+ {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
+ {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
+ {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
+ {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
+ {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
+ {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
+ {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
+ {1268, nullptr, "DeleteButtonConfigStorageFull"},
+ {1269, nullptr, "DeleteButtonConfigStorageLeft"},
+ {1270, nullptr, "DeleteButtonConfigStorageRight"},
+ {1271, nullptr, "IsUsingCustomButtonConfig"},
+ {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
+ {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
+ {1274, nullptr, "SetDefaultButtonConfig"},
+ {1275, nullptr, "SetAllDefaultButtonConfig"},
+ {1276, nullptr, "SetHidButtonConfigEmbedded"},
+ {1277, nullptr, "SetHidButtonConfigFull"},
+ {1278, nullptr, "SetHidButtonConfigLeft"},
+ {1279, nullptr, "SetHidButtonConfigRight"},
+ {1280, nullptr, "GetHidButtonConfigEmbedded"},
+ {1281, nullptr, "GetHidButtonConfigFull"},
+ {1282, nullptr, "GetHidButtonConfigLeft"},
+ {1283, nullptr, "GetHidButtonConfigRight"},
+ {1284, nullptr, "GetButtonConfigStorageEmbedded"},
+ {1285, nullptr, "GetButtonConfigStorageFull"},
+ {1286, nullptr, "GetButtonConfigStorageLeft"},
+ {1287, nullptr, "GetButtonConfigStorageRight"},
+ {1288, nullptr, "SetButtonConfigStorageEmbedded"},
+ {1289, nullptr, "SetButtonConfigStorageFull"},
+ {1290, nullptr, "DeleteButtonConfigStorageRight"},
+ {1291, nullptr, "DeleteButtonConfigStorageRight"},
};
// clang-format on
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:
void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
+ void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx);
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
void SendVibrationValue(Kernel::HLERequestContext& ctx);
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"} {
{20, nullptr, "StartMifareWrite"},
{101, nullptr, "GetAwakeTriggerReasonForLeftRail"},
{102, nullptr, "GetAwakeTriggerReasonForRightRail"},
+ {103, nullptr, "GetAwakeTriggerBatteryLevelTransitionForLeftRail"},
+ {104, nullptr, "GetAwakeTriggerBatteryLevelTransitionForRightRail"},
};
// clang-format on
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:
explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "AddProcessToDebugLaunchQueue"},
- {1, nullptr, "ClearDebugLaunchQueue"},
- {2, nullptr, "GetNsoInfos"},
+ {0, nullptr, "SetProgramArgument"},
+ {1, nullptr, "FlushArguments"},
+ {2, nullptr, "GetProcessModuleInfo"},
};
// clang-format on
@@ -135,8 +135,8 @@ public:
static const FunctionInfo functions[] = {
{0, nullptr, "CreateProcess"},
{1, nullptr, "GetProgramInfo"},
- {2, nullptr, "RegisterTitle"},
- {3, nullptr, "UnregisterTitle"},
+ {2, nullptr, "PinProgram"},
+ {3, nullptr, "UnpinProgram"},
{4, nullptr, "SetEnabledProgramVerification"},
};
// clang-format on
@@ -150,8 +150,8 @@ public:
explicit Shell(Core::System& system_) : ServiceFramework{system_, "ldr:shel"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "AddProcessToLaunchQueue"},
- {1, nullptr, "ClearLaunchQueue"},
+ {0, nullptr, "SetProgramArgument"},
+ {1, nullptr, "FlushArguments"},
};
// clang-format on
@@ -164,19 +164,19 @@ public:
explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &RelocatableObject::LoadNro, "LoadNro"},
- {1, &RelocatableObject::UnloadNro, "UnloadNro"},
- {2, &RelocatableObject::LoadNrr, "LoadNrr"},
- {3, &RelocatableObject::UnloadNrr, "UnloadNrr"},
+ {0, &RelocatableObject::LoadModule, "LoadModule"},
+ {1, &RelocatableObject::UnloadModule, "UnloadModule"},
+ {2, &RelocatableObject::RegisterModuleInfo, "RegisterModuleInfo"},
+ {3, &RelocatableObject::UnregisterModuleInfo, "UnregisterModuleInfo"},
{4, &RelocatableObject::Initialize, "Initialize"},
- {10, nullptr, "LoadNrrEx"},
+ {10, nullptr, "RegisterModuleInfo2"},
};
// clang-format on
RegisterHandlers(functions);
}
- void LoadNrr(Kernel::HLERequestContext& ctx) {
+ void RegisterModuleInfo(Kernel::HLERequestContext& ctx) {
struct Parameters {
u64_le process_id;
u64_le nrr_address;
@@ -273,7 +273,7 @@ public:
rb.Push(RESULT_SUCCESS);
}
- void UnloadNrr(Kernel::HLERequestContext& ctx) {
+ void UnregisterModuleInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto pid = rp.Pop<u64>();
const auto nrr_address = rp.Pop<VAddr>();
@@ -408,7 +408,7 @@ public:
data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite);
}
- void LoadNro(Kernel::HLERequestContext& ctx) {
+ void LoadModule(Kernel::HLERequestContext& ctx) {
struct Parameters {
u64_le process_id;
u64_le image_address;
@@ -546,7 +546,7 @@ public:
return RESULT_SUCCESS;
}
- void UnloadNro(Kernel::HLERequestContext& ctx) {
+ void UnloadModule(Kernel::HLERequestContext& ctx) {
if (!initialized) {
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
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 @@
#include <memory>
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
-#include "core/settings.h"
namespace Service::NFC {
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/settings.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
@@ -10,7 +11,6 @@
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/service.h"
#include "core/network/network.h"
-#include "core/settings.h"
namespace Service::NIFM {
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:
{39, nullptr, "PrepareShutdown"},
{40, nullptr, "ListApplyDeltaTask"},
{41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"},
- {42, nullptr, "Unknown42"},
- {43, nullptr, "Unknown43"},
- {44, nullptr, "Unknown44"},
- {45, nullptr, "Unknown45"},
- {46, nullptr, "Unknown46"},
- {47, nullptr, "Unknown47"},
- {48, nullptr, "Unknown48"},
- {49, nullptr, "Unknown49"},
- {50, nullptr, "Unknown50"},
- {51, nullptr, "Unknown51"},
- {52, nullptr, "Unknown52"},
- {53, nullptr, "Unknown53"},
- {54, nullptr, "Unknown54"},
- {55, nullptr, "Unknown55"},
- {56, nullptr, "Unknown56"},
- {57, nullptr, "Unknown57"},
- {58, nullptr, "Unknown58"},
- {59, nullptr, "Unknown59"},
- {60, nullptr, "Unknown60"},
- {61, nullptr, "Unknown61"},
- {62, nullptr, "Unknown62"},
- {63, nullptr, "Unknown63"},
- {64, nullptr, "Unknown64"},
- {65, nullptr, "Unknown65"},
- {66, nullptr, "Unknown66"},
- {67, nullptr, "Unknown67"},
- {68, nullptr, "Unknown68"},
- {69, nullptr, "Unknown69"},
- {70, nullptr, "Unknown70"},
- {71, nullptr, "Unknown71"},
- {72, nullptr, "Unknown72"},
- {73, nullptr, "Unknown73"},
- {74, nullptr, "Unknown74"},
- {75, nullptr, "Unknown75"},
- {76, nullptr, "Unknown76"},
- {77, nullptr, "Unknown77"},
- {78, nullptr, "Unknown78"},
- {79, nullptr, "Unknown79"},
- {80, nullptr, "Unknown80"},
- {81, nullptr, "Unknown81"},
- {82, nullptr, "Unknown82"},
- {83, nullptr, "Unknown83"},
+ {42, nullptr, "CreateApplyDeltaTaskFromDownloadTask"},
+ {43, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
+ {44, nullptr, "GetApplyDeltaTaskRequiredStorage"},
+ {45, nullptr, "CalculateNetworkInstallTaskContentsSize"},
+ {46, nullptr, "PrepareShutdownForSystemUpdate"},
+ {47, nullptr, "FindMaxRequiredApplicationVersionOfTask"},
+ {48, nullptr, "CommitNetworkInstallTaskPartially"},
+ {49, nullptr, "ListNetworkInstallTaskCommittedContentMeta"},
+ {50, nullptr, "ListNetworkInstallTaskNotCommittedContentMeta"},
+ {51, nullptr, "FindMaxRequiredSystemVersionOfTask"},
+ {52, nullptr, "GetNetworkInstallTaskErrorContext"},
+ {53, nullptr, "CreateLocalCommunicationReceiveApplicationTask"},
+ {54, nullptr, "DestroyLocalCommunicationReceiveApplicationTask"},
+ {55, nullptr, "ListLocalCommunicationReceiveApplicationTask"},
+ {56, nullptr, "RequestLocalCommunicationReceiveApplicationTaskRun"},
+ {57, nullptr, "GetLocalCommunicationReceiveApplicationTaskInfo"},
+ {58, nullptr, "CommitLocalCommunicationReceiveApplicationTask"},
+ {59, nullptr, "ListLocalCommunicationReceiveApplicationTaskContentMeta"},
+ {60, nullptr, "CreateLocalCommunicationSendApplicationTask"},
+ {61, nullptr, "RequestLocalCommunicationSendApplicationTaskRun"},
+ {62, nullptr, "GetLocalCommunicationReceiveApplicationTaskErrorContext"},
+ {63, nullptr, "GetLocalCommunicationSendApplicationTaskInfo"},
+ {64, nullptr, "DestroyLocalCommunicationSendApplicationTask"},
+ {65, nullptr, "GetLocalCommunicationSendApplicationTaskErrorContext"},
+ {66, nullptr, "CalculateLocalCommunicationReceiveApplicationTaskRequiredSize"},
+ {67, nullptr, "ListApplicationLocalCommunicationReceiveApplicationTask"},
+ {68, nullptr, "ListApplicationLocalCommunicationSendApplicationTask"},
+ {69, nullptr, "CreateLocalCommunicationReceiveSystemUpdateTask"},
+ {70, nullptr, "DestroyLocalCommunicationReceiveSystemUpdateTask"},
+ {71, nullptr, "ListLocalCommunicationReceiveSystemUpdateTask"},
+ {72, nullptr, "RequestLocalCommunicationReceiveSystemUpdateTaskRun"},
+ {73, nullptr, "GetLocalCommunicationReceiveSystemUpdateTaskInfo"},
+ {74, nullptr, "CommitLocalCommunicationReceiveSystemUpdateTask"},
+ {75, nullptr, "GetLocalCommunicationReceiveSystemUpdateTaskErrorContext"},
+ {76, nullptr, "CreateLocalCommunicationSendSystemUpdateTask"},
+ {77, nullptr, "RequestLocalCommunicationSendSystemUpdateTaskRun"},
+ {78, nullptr, "GetLocalCommunicationSendSystemUpdateTaskInfo"},
+ {79, nullptr, "DestroyLocalCommunicationSendSystemUpdateTask"},
+ {80, nullptr, "GetLocalCommunicationSendSystemUpdateTaskErrorContext"},
+ {81, nullptr, "ListLocalCommunicationSendSystemUpdateTask"},
+ {82, nullptr, "GetReceivedSystemDataPath"},
+ {83, nullptr, "CalculateApplyDeltaTaskOccupiedSize"},
{84, nullptr, "Unknown84"},
- {85, nullptr, "Unknown85"},
- {86, nullptr, "Unknown86"},
+ {85, nullptr, "ListNetworkInstallTaskContentMetaFromInstallMeta"},
+ {86, nullptr, "ListNetworkInstallTaskOccupiedSize"},
{87, nullptr, "Unknown87"},
{88, nullptr, "Unknown88"},
{89, nullptr, "Unknown89"},
@@ -202,6 +202,17 @@ public:
{116, nullptr, "Unknown116"},
{117, nullptr, "Unknown117"},
{118, nullptr, "Unknown118"},
+ {119, nullptr, "Unknown119"},
+ {120, nullptr, "Unknown120"},
+ {121, nullptr, "Unknown121"},
+ {122, nullptr, "Unknown122"},
+ {123, nullptr, "Unknown123"},
+ {124, nullptr, "Unknown124"},
+ {125, nullptr, "Unknown125"},
+ {126, nullptr, "Unknown126"},
+ {127, nullptr, "Unknown127"},
+ {128, nullptr, "Unknown128"},
+ {129, nullptr, "Unknown129"},
};
// clang-format on
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:
{151, nullptr, "GetStateWithHandover"},
{152, nullptr, "GetStateChangeEventWithHandover"},
{153, nullptr, "GetDropEventWithHandover"},
+ {154, nullptr, "CreateTokenAsync"},
+ {155, nullptr, "CreateTokenAsyncWithApplicationId"},
{161, nullptr, "GetRequestChangeStateCancelEvent"},
{162, nullptr, "RequestChangeStateForceTimedWithCancelEvent"},
{201, nullptr, "RequestChangeStateForceTimed"},
@@ -84,6 +86,7 @@ public:
{151, nullptr, "GetStateWithHandover"},
{152, nullptr, "GetStateChangeEventWithHandover"},
{153, nullptr, "GetDropEventWithHandover"},
+ {154, nullptr, "CreateTokenAsync"},
};
// clang-format on
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 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -14,7 +15,6 @@
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pl_u.h"
#include "core/hle/service/set/set.h"
-#include "core/settings.h"
namespace Service::NS {
@@ -55,6 +55,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{26, nullptr, "BeginInstallApplication"},
{27, nullptr, "DeleteApplicationRecord"},
{30, nullptr, "RequestApplicationUpdateInfo"},
+ {31, nullptr, "Unknown31"},
{32, nullptr, "CancelApplicationDownload"},
{33, nullptr, "ResumeApplicationDownload"},
{35, nullptr, "UpdateVersionList"},
@@ -182,6 +183,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{913, nullptr, "ListAllApplicationRecord"},
{914, nullptr, "HideApplicationRecord"},
{915, nullptr, "ShowApplicationRecord"},
+ {916, nullptr, "IsApplicationAutoDeleteDisabled"},
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
@@ -201,6 +203,8 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{1310, nullptr, "RequestMoveApplicationEntity"},
{1311, nullptr, "EstimateSizeToMove"},
{1312, nullptr, "HasMovableEntity"},
+ {1313, nullptr, "CleanupOrphanContents"},
+ {1314, nullptr, "CheckPreconditionSatisfiedToMove"},
{1400, nullptr, "PrepareShutdown"},
{1500, nullptr, "FormatSdCard"},
{1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
@@ -215,6 +219,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1704, nullptr, "GetApplicationViewWithPromotionInfo"},
+ {1705, nullptr, "IsPatchAutoDeletableApplication"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
@@ -269,6 +274,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2351, nullptr, "RequestNoDownloadRightsErrorResolution"},
{2352, nullptr, "RequestResolveNoDownloadRightsError"},
{2353, nullptr, "GetApplicationDownloadTaskInfo"},
+ {2354, nullptr, "PrioritizeApplicationBackgroundTask"},
+ {2355, nullptr, "Unknown2355"},
+ {2356, nullptr, "Unknown2356"},
{2400, nullptr, "GetPromotionInfo"},
{2401, nullptr, "CountPromotionInfo"},
{2402, nullptr, "ListPromotionInfo"},
@@ -282,6 +290,21 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"},
{2516, nullptr, "EnsureApplicationCertificate"},
{2800, nullptr, "GetApplicationIdOfPreomia"},
+ {3000, nullptr, "RegisterDeviceLockKey"},
+ {3001, nullptr, "UnregisterDeviceLockKey"},
+ {3002, nullptr, "VerifyDeviceLockKey"},
+ {3003, nullptr, "HideApplicationIcon"},
+ {3004, nullptr, "ShowApplicationIcon"},
+ {3005, nullptr, "HideApplicationTitle"},
+ {3006, nullptr, "ShowApplicationTitle"},
+ {3007, nullptr, "EnableGameCard"},
+ {3008, nullptr, "DisableGameCard"},
+ {3009, nullptr, "EnableLocalContentShare"},
+ {3010, nullptr, "DisableLocalContentShare"},
+ {3011, nullptr, "IsApplicationIconHidden"},
+ {3012, nullptr, "IsApplicationTitleHidden"},
+ {3013, nullptr, "IsGameCardEnabled"},
+ {3014, nullptr, "IsLocalContentShareEnabled"},
{9999, nullptr, "GetApplicationCertificate"},
};
// clang-format on
@@ -441,7 +464,11 @@ IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
+ {900, nullptr, "ImportAutoUpdatePolicyJsonForDebug"},
+ {901, nullptr, "ListDefaultAutoUpdatePolicy"},
+ {902, nullptr, "ListAutoUpdatePolicyForSpecificApplication"},
{1000, nullptr, "PerformAutoUpdate"},
+ {1001, nullptr, "ListAutoUpdateSchedule"},
};
// clang-format on
@@ -547,6 +574,9 @@ IFactoryResetInterface::~IFactoryResetInterface() = default;
NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
// clang-format off
static const FunctionInfo functions[] = {
+ {7988, nullptr, "GetDynamicRightsInterface"},
+ {7989, nullptr, "GetReadOnlyApplicationControlDataInterface"},
+ {7991, nullptr, "GetReadOnlyApplicationRecordInterface"},
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
{7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
@@ -575,18 +605,22 @@ public:
{0, nullptr, "LaunchProgram"},
{1, nullptr, "TerminateProcess"},
{2, nullptr, "TerminateProgram"},
- {4, nullptr, "GetShellEventHandle"},
+ {4, nullptr, "GetShellEvent"},
{5, nullptr, "GetShellEventInfo"},
{6, nullptr, "TerminateApplication"},
{7, nullptr, "PrepareLaunchProgramFromHost"},
- {8, nullptr, "LaunchApplication"},
+ {8, nullptr, "LaunchApplicationFromHost"},
{9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
{10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
{11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
- {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"},
+ {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop"},
{13, nullptr, "CreateApplicationResourceForDevelop"},
{14, nullptr, "IsPreomiaForDevelop"},
{15, nullptr, "GetApplicationProgramIdFromHost"},
+ {16, nullptr, "RefreshCachedDebugValues"},
+ {17, nullptr, "PrepareLaunchApplicationFromHost"},
+ {18, nullptr, "GetLaunchEvent"},
+ {19, nullptr, "GetLaunchResult"},
};
// clang-format on
@@ -699,6 +733,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager);
std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager);
std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager);
+ std::make_shared<NS>("ns:ro", system)->InstallAsService(service_manager);
std::make_shared<NS_DEV>(system)->InstallAsService(service_manager);
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_)
{100, nullptr, "RequestApplicationFunctionAuthorization"},
{101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
{102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"},
+ {103, nullptr, "RefreshApplicationFunctionBlackListDebugRecord"},
+ {104, nullptr, "RequestApplicationFunctionAuthorizationByProgramId"},
+ {105, nullptr, "GetFunctionBlackListSystemVersionToAuthorize"},
+ {106, nullptr, "GetFunctionBlackListVersion"},
{1000, nullptr, "LoadNgWordDataForPlatformRegionChina"},
{1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"},
};
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<
IoctlZbcSetTable params{};
std::memcpy(&params, input.data(), input.size());
// TODO(ogniK): What does this even actually do?
- std::memcpy(output.data(), &params, output.size());
+
+ // Prevent null pointer being passed as arg 1
+ if (output.empty()) {
+ LOG_WARNING(Service_NVDRV, "Avoiding passing null pointer to memcpy");
+ } else {
+ std::memcpy(output.data(), &params, output.size());
+ }
return NvResult::Success;
}
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 {
template <typename T>
std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
std::size_t offset) {
- std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
- offset += count * sizeof(T);
- return offset;
+ if (!dst.empty()) {
+ std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
+ }
+ return 0;
}
// Write vectors will write data to the output buffer
template <typename T>
std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
- std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
- offset += src.size() * sizeof(T);
- return offset;
+ if (src.empty()) {
+ return 0;
+ } else {
+ std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
+ offset += src.size() * sizeof(T);
+ return offset;
+ }
}
} // Anonymous namespace
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 @@
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
+#include "common/settings.h"
#include "common/thread.h"
#include "core/core.h"
#include "core/core_timing.h"
@@ -23,7 +24,6 @@
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/perf_stats.h"
-#include "core/settings.h"
#include "video_core/renderer_base.h"
namespace 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:
{22, nullptr, "DeleteSaveDataBackupAsync"},
{25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
{26, nullptr, "DownloadSaveDataBackupAsync"},
+ {27, nullptr, "UploadSaveDataBackupAsync"},
{9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
{9013, nullptr, "GetSaveDataBackupSettingForDebug"},
{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:
{19, nullptr, "SetIrqEnable"},
{20, nullptr, "SetAspmEnable"},
{21, nullptr, "SetResetUponResumeEnable"},
- {22, nullptr, "Unknown22"},
+ {22, nullptr, "ResetFunction"},
{23, nullptr, "Unknown23"},
};
// 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 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/pctl/module.h"
#include "core/hle/service/pctl/pctl.h"
namespace Service::PCTL {
+namespace Error {
+
+constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101};
+constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
+constexpr ResultCode ResultNoCapability{ErrorModule::PCTL, 131};
+constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
+
+} // namespace Error
+
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
- explicit IParentalControlService(Core::System& system_)
- : ServiceFramework{system_, "IParentalControlService"} {
+ explicit IParentalControlService(Core::System& system_, Capability capability)
+ : ServiceFramework{system_, "IParentalControlService"}, system(system_),
+ capability(capability) {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IParentalControlService::Initialize, "Initialize"},
@@ -28,13 +42,13 @@ public:
{1010, nullptr, "IsRestrictedSystemSettingsEntered"},
{1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
{1012, nullptr, "GetRestrictedFeatures"},
- {1013, nullptr, "ConfirmStereoVisionPermission"},
+ {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
{1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
{1015, nullptr, "ConfirmPlayableApplicationVideo"},
{1016, nullptr, "ConfirmShowNewsPermission"},
{1017, nullptr, "EndFreeCommunication"},
- {1018, nullptr, "IsFreeCommunicationAvailable"},
- {1031, nullptr, "IsRestrictionEnabled"},
+ {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
+ {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
{1032, nullptr, "GetSafetyLevel"},
{1033, nullptr, "SetSafetyLevel"},
{1034, nullptr, "GetSafetyLevelSettings"},
@@ -50,6 +64,7 @@ public:
{1046, nullptr, "DisableFeaturesForReset"},
{1047, nullptr, "NotifyApplicationDownloadStarted"},
{1048, nullptr, "NotifyNetworkProfileCreated"},
+ {1049, nullptr, "ResetFreeCommunicationApplicationList"},
{1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
{1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
{1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
@@ -69,6 +84,8 @@ public:
{1421, nullptr, "GetAccountNickname"},
{1424, nullptr, "GetAccountState"},
{1425, nullptr, "RequestPostEvents"},
+ {1426, nullptr, "GetPostEventInterval"},
+ {1427, nullptr, "SetPostEventInterval"},
{1432, nullptr, "GetSynchronizationEvent"},
{1451, nullptr, "StartPlayTimer"},
{1452, nullptr, "StopPlayTimer"},
@@ -119,62 +136,235 @@ public:
}
private:
+ bool CheckFreeCommunicationPermissionImpl() const {
+ if (states.temporary_unlocked) {
+ return true;
+ }
+ if ((states.application_info.parental_control_flag & 1) == 0) {
+ return true;
+ }
+ if (pin_code[0] == '\0') {
+ return true;
+ }
+ if (!settings.is_free_communication_default_on) {
+ return true;
+ }
+ // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
+ // but as we don't have multiproceses support yet, we can just assume our application is
+ // valid for the time being
+ return true;
+ }
+
+ bool ConfirmStereoVisionPermissionImpl() const {
+ if (states.temporary_unlocked) {
+ return true;
+ }
+ if (pin_code[0] == '\0') {
+ return true;
+ }
+ if (!settings.is_stero_vision_restricted) {
+ return false;
+ }
+ return true;
+ }
+
+ void SetStereoVisionRestrictionImpl(bool is_restricted) {
+ if (settings.disabled) {
+ return;
+ }
+
+ if (pin_code[0] == '\0') {
+ return;
+ }
+ settings.is_stero_vision_restricted = is_restricted;
+ }
+
void Initialize(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ LOG_DEBUG(Service_PCTL, "called");
+ IPC::ResponseBuilder rb{ctx, 2};
+
+ if (False(capability & (Capability::Application | Capability::System))) {
+ LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
+ return;
+ }
+
+ // TODO(ogniK): Recovery flag initialization for pctl:r
+
+ const auto tid = system.CurrentProcess()->GetTitleID();
+ if (tid != 0) {
+ const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
+ system.GetContentProvider()};
+ const auto control = pm.GetControlMetadata();
+ if (control.first) {
+ states.tid_from_event = 0;
+ states.launch_time_valid = false;
+ states.is_suspended = false;
+ states.free_communication = false;
+ states.stereo_vision = false;
+ states.application_info = ApplicationInfo{
+ .tid = tid,
+ .age_rating = control.first->GetRatingAge(),
+ .parental_control_flag = control.first->GetParentalControlFlag(),
+ .capability = capability,
+ };
+
+ if (False(capability & (Capability::System | Capability::Recovery))) {
+ // TODO(ogniK): Signal application launch event
+ }
+ }
+ }
- IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(RESULT_SUCCESS);
}
void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ LOG_DEBUG(Service_PCTL, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ if (!CheckFreeCommunicationPermissionImpl()) {
+ rb.Push(Error::ResultNoFreeCommunication);
+ } else {
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ states.free_communication = true;
+ }
+
+ void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PCTL, "called");
+ states.stereo_vision = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
- void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
+ void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
+ if (!CheckFreeCommunicationPermissionImpl()) {
+ rb.Push(Error::ResultNoFreeCommunication);
+ } else {
+ rb.Push(RESULT_SUCCESS);
+ }
+ }
+
+ void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ if (False(capability & (Capability::Status | Capability::Recovery))) {
+ LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
+ rb.Push(Error::ResultNoCapability);
+ rb.Push(false);
+ return;
+ }
+
+ rb.Push(pin_code[0] != '\0');
+ }
+
+ void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ rb.Push(Error::ResultNoCapability);
+ return;
+ }
+
+ if (pin_code[0] == '\0') {
+ rb.Push(Error::ResultNoRestrictionEnabled);
+ return;
+ }
+
rb.Push(RESULT_SUCCESS);
}
void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(RESULT_SUCCESS);
- rb.Push(true);
+ if (!ConfirmStereoVisionPermissionImpl()) {
+ rb.Push(Error::ResultStereoVisionRestricted);
+ rb.Push(false);
+ } else {
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(true);
+ }
}
void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto can_use = rp.Pop<bool>();
- LOG_WARNING(Service_PCTL, "(STUBBED) called, can_use={}", can_use);
-
- can_use_stereo_vision = can_use;
+ LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
IPC::ResponseBuilder rb{ctx, 2};
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ rb.Push(Error::ResultNoCapability);
+ return;
+ }
+
+ SetStereoVisionRestrictionImpl(can_use);
rb.Push(RESULT_SUCCESS);
}
void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3};
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ rb.Push(Error::ResultNoCapability);
+ rb.Push(false);
+ return;
+ }
+
rb.Push(RESULT_SUCCESS);
- rb.Push(can_use_stereo_vision);
+ rb.Push(settings.is_stero_vision_restricted);
}
void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ LOG_DEBUG(Service_PCTL, "called");
+
+ states.stereo_vision = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+ struct ApplicationInfo {
+ u64 tid{};
+ std::array<u8, 32> age_rating{};
+ u32 parental_control_flag{};
+ Capability capability{};
+ };
+
+ struct States {
+ u64 current_tid{};
+ ApplicationInfo application_info{};
+ u64 tid_from_event{};
+ bool launch_time_valid{};
+ bool is_suspended{};
+ bool temporary_unlocked{};
+ bool free_communication{};
+ bool stereo_vision{};
+ };
+
+ struct ParentalControlSettings {
+ bool is_stero_vision_restricted{};
+ bool is_free_communication_default_on{};
+ bool disabled{};
+ };
+
+ States states{};
+ ParentalControlSettings settings{};
+ std::array<char, 8> pin_code{};
bool can_use_stereo_vision = true;
+ Core::System& system;
+ Capability capability{};
};
void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
@@ -182,7 +372,9 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IParentalControlService>(system);
+ // TODO(ogniK): Get TID from process
+
+ rb.PushIpcInterface<IParentalControlService>(system, capability);
}
void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
@@ -190,21 +382,28 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IParentalControlService>(system);
+ rb.PushIpcInterface<IParentalControlService>(system, capability);
}
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
- const char* name)
- : ServiceFramework{system_, name}, module{std::move(module_)} {}
+ const char* name, Capability capability)
+ : ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {}
Module::Interface::~Interface() = default;
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
- std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager);
- std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager);
- std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager);
- std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager);
+ std::make_shared<PCTL>(system, module, "pctl",
+ Capability::Application | Capability::SnsPost | Capability::Status |
+ Capability::StereoVision)
+ ->InstallAsService(service_manager);
+ // TODO(ogniK): Implement remaining capabilities
+ std::make_shared<PCTL>(system, module, "pctl:a", Capability::None)
+ ->InstallAsService(service_manager);
+ std::make_shared<PCTL>(system, module, "pctl:r", Capability::None)
+ ->InstallAsService(service_manager);
+ std::make_shared<PCTL>(system, module, "pctl:s", Capability::None)
+ ->InstallAsService(service_manager);
}
} // 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 @@
#pragma once
+#include "common/common_funcs.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -12,12 +13,23 @@ class System;
namespace Service::PCTL {
+enum class Capability : u32 {
+ None = 0,
+ Application = 1 << 0,
+ SnsPost = 1 << 1,
+ Recovery = 1 << 6,
+ Status = 1 << 8,
+ StereoVision = 1 << 9,
+ System = 1 << 15,
+};
+DECLARE_ENUM_FLAG_OPERATORS(Capability);
+
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
- explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
- const char* name);
+ explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
+ Capability capability);
~Interface() override;
void CreateService(Kernel::HLERequestContext& ctx);
@@ -25,6 +37,9 @@ public:
protected:
std::shared_ptr<Module> module;
+
+ private:
+ Capability capability{};
};
};
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 @@
namespace Service::PCTL {
-PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name)
- : Interface{system_, std::move(module_), name} {
+PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
+ Capability capability)
+ : Interface{system_, std::move(module_), name, capability} {
static const FunctionInfo functions[] = {
{0, &PCTL::CreateService, "CreateService"},
{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 {
class PCTL final : public Module::Interface {
public:
- explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name);
+ explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
+ Capability capability);
~PCTL() override;
};
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 @@
#include <fmt/format.h>
#include "common/assert.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/ipc.h"
@@ -146,6 +147,11 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
service_name);
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
+ if (Settings::values.use_auto_stub) {
+ LOG_WARNING(Service, "Using auto stub fallback!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
}
void 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 @@
#include <array>
#include <chrono>
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/set/set.h"
-#include "core/settings.h"
namespace Service::Set {
namespace {
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"} {
{155, nullptr, "SetAccountOnlineStorageSettings"},
{156, nullptr, "GetPctlReadyFlag"},
{157, nullptr, "SetPctlReadyFlag"},
+ {158, nullptr, "GetAnalogStickUserCalibrationL"},
+ {159, nullptr, "SetAnalogStickUserCalibrationL"},
+ {160, nullptr, "GetAnalogStickUserCalibrationR"},
+ {161, nullptr, "SetAnalogStickUserCalibrationR"},
{162, nullptr, "GetPtmBatteryVersion"},
{163, nullptr, "SetPtmBatteryVersion"},
{164, nullptr, "GetUsb30HostEnableFlag"},
@@ -302,6 +306,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{200, nullptr, "SetButtonConfigRegisteredSettings"},
{201, nullptr, "GetFieldTestingFlag"},
{202, nullptr, "SetFieldTestingFlag"},
+ {203, nullptr, "GetPanelCrcMode"},
+ {204, nullptr, "SetPanelCrcMode"},
};
// clang-format on
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_)
: ServiceFramework{system_, "sm:", 4},
service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} {
static const FunctionInfo functions[] = {
- {0x00000000, &SM::Initialize, "Initialize"},
- {0x00000001, &SM::GetService, "GetService"},
- {0x00000002, &SM::RegisterService, "RegisterService"},
- {0x00000003, &SM::UnregisterService, "UnregisterService"},
+ {0, &SM::Initialize, "Initialize"},
+ {1, &SM::GetService, "GetService"},
+ {2, &SM::RegisterService, "RegisterService"},
+ {3, &SM::UnregisterService, "UnregisterService"},
+ {4, nullptr, "DetachClient"},
};
RegisterHandlers(functions);
}
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"} {
{3, nullptr, "GetMediaList"},
{4, nullptr, "SetMediaType"},
{5, nullptr, "GetMediaType"},
+ {6, nullptr, "Unknown6"},
};
// clang-format on
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 {
NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
// clang-format off
static const FunctionInfo functions[] = {
+ {5, nullptr, "GetSettingUrl"},
{10, nullptr, "GetSettingName"},
{11, nullptr, "GetEnvironmentIdentifier"},
{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 {
SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} {
static const FunctionInfo functions[] = {
- {0, nullptr, "SetDnsAddressesPrivate"},
- {1, nullptr, "GetDnsAddressPrivate"},
+ {0, nullptr, "SetDnsAddressesPrivateRequest"},
+ {1, nullptr, "GetDnsAddressPrivateRequest"},
{2, nullptr, "GetHostByNameRequest"},
{3, nullptr, "GetHostByAddrRequest"},
{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 @@
#include <functional>
#include <vector>
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/spl/csrng.h"
#include "core/hle/service/spl/module.h"
#include "core/hle/service/spl/spl.h"
-#include "core/settings.h"
namespace Service::SPL {
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_)
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
+ {9, nullptr, "ImportLotusKey"},
+ {10, nullptr, "DecryptLotusMessage"},
{11, nullptr, "IsDevelopment"},
{12, nullptr, "GenerateSpecificAesKey"},
{14, nullptr, "DecryptAesKey"},
@@ -123,6 +125,7 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
+ {17, nullptr, "ImportEsKey"},
{18, nullptr, "UnwrapTitleKey"},
{20, nullptr, "PrepareEsCommonKey"},
{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 @@
namespace Service::Time::Clock {
+enum class TimeType : u8 {
+ UserSystemClock,
+ NetworkSystemClock,
+ LocalSystemClock,
+};
+
/// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint
struct SteadyClockTimePoint {
s64 time_point;
@@ -84,7 +90,7 @@ struct ClockSnapshot {
SteadyClockTimePoint steady_clock_time_point;
TimeZone::LocationName location_name;
u8 is_automatic_correction_enabled;
- u8 type;
+ TimeType type;
INSERT_PADDING_BYTES_NOINIT(0x2);
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:
ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
Kernel::KThread* thread, Clock::SystemClockContext user_context,
- Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
+ Clock::SystemClockContext network_context, Clock::TimeType type,
+ Clock::ClockSnapshot& clock_snapshot) {
auto& time_manager{system.GetTimeManager()};
+ clock_snapshot.steady_clock_time_point =
+ time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system);
clock_snapshot.is_automatic_correction_enabled =
time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
- clock_snapshot.user_context = user_context;
- clock_snapshot.network_context = network_context;
+ clock_snapshot.type = type;
if (const ResultCode result{
time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName(
@@ -138,12 +140,11 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
return result;
}
- const auto current_time_point{
- time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
- clock_snapshot.steady_clock_time_point = current_time_point;
+ clock_snapshot.user_context = user_context;
if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime(
- clock_snapshot.user_time, current_time_point, clock_snapshot.user_context)};
+ clock_snapshot.user_time, clock_snapshot.steady_clock_time_point,
+ clock_snapshot.user_context)};
result != RESULT_SUCCESS) {
return result;
}
@@ -157,9 +158,12 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
}
clock_snapshot.user_calendar_time = userCalendarInfo.time;
- clock_snapshot.user_calendar_additional_time = userCalendarInfo.additiona_info;
+ clock_snapshot.user_calendar_additional_time = userCalendarInfo.additional_info;
+
+ clock_snapshot.network_context = network_context;
- if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time, current_time_point,
+ if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time,
+ clock_snapshot.steady_clock_time_point,
clock_snapshot.network_context) != RESULT_SUCCESS) {
clock_snapshot.network_time = 0;
}
@@ -173,8 +177,7 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
}
clock_snapshot.network_calendar_time = networkCalendarInfo.time;
- clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additiona_info;
- clock_snapshot.type = type;
+ clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additional_info;
return RESULT_SUCCESS;
}
@@ -257,9 +260,10 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe
}
void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_Time, "called");
IPC::RequestParser rp{ctx};
- const auto type{rp.PopRaw<u8>()};
+ const auto type{rp.PopEnum<Clock::TimeType>()};
+
+ LOG_DEBUG(Service_Time, "called, type={}", type);
Clock::SystemClockContext user_context{};
if (const ResultCode result{
@@ -270,6 +274,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
rb.Push(result);
return;
}
+
Clock::SystemClockContext network_context{};
if (const ResultCode result{
system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
@@ -295,14 +300,16 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
}
void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_Time, "called");
IPC::RequestParser rp{ctx};
- const auto type{rp.PopRaw<u8>()};
+ const auto type{rp.PopEnum<Clock::TimeType>()};
+
rp.AlignWithPadding();
const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()};
const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()};
+ LOG_DEBUG(Service_Time, "called, type={}", type);
+
Clock::ClockSnapshot clock_snapshot{};
if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal(
&ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
@@ -321,9 +328,14 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
- IPC::RequestParser rp{ctx};
- const auto snapshot_a = rp.PopRaw<Clock::ClockSnapshot>();
- const auto snapshot_b = rp.PopRaw<Clock::ClockSnapshot>();
+ Clock::ClockSnapshot snapshot_a;
+ Clock::ClockSnapshot snapshot_b;
+
+ const auto snapshot_a_data = ctx.ReadBuffer(0);
+ const auto snapshot_b_data = ctx.ReadBuffer(1);
+
+ std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot));
+ std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot));
auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset -
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:
private:
ResultCode GetClockSnapshotFromSystemClockContextInternal(
Kernel::KThread* thread, Clock::SystemClockContext user_context,
- Clock::SystemClockContext network_context, u8 type,
+ Clock::SystemClockContext network_context, Clock::TimeType type,
Clock::ClockSnapshot& cloc_snapshot);
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 @@
#include <chrono>
#include <ctime>
+#include "common/settings.h"
#include "common/time_zone.h"
#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h"
#include "core/hle/service/time/local_system_clock_context_writer.h"
#include "core/hle/service/time/network_system_clock_context_writer.h"
#include "core/hle/service/time/time_manager.h"
-#include "core/settings.h"
namespace Service::Time {
@@ -44,7 +44,11 @@ struct TimeManager::Impl final {
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
- SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
+
+ Clock::SystemClockContext clock_context{};
+ standard_local_system_clock_core.GetClockContext(system, clock_context);
+
+ SetupStandardNetworkSystemClock(clock_context, standard_network_clock_accuracy);
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
SetupEphemeralNetworkSystemClock();
}
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 @@
#include <sstream>
#include "common/logging/log.h"
+#include "common/settings.h"
#include "common/time_zone.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
@@ -15,7 +16,6 @@
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/time/time_manager.h"
#include "core/hle/service/time/time_zone_content_manager.h"
-#include "core/settings.h"
namespace Service::Time::TimeZone {
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,
static ResultCode ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) {
CalendarTimeInternal calendar_time{};
const ResultCode result{
- ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)};
+ ToCalendarTimeInternal(rules, time, calendar_time, calendar.additional_info)};
calendar.time.year = static_cast<s16>(calendar_time.year);
// 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_,
{3, nullptr, "LoadLocationNameList"},
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
{5, nullptr, "GetTimeZoneRuleVersion"},
+ {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
{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 {
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size");
struct CalendarInfo {
- CalendarTime time{};
- CalendarAdditionalInfo additiona_info{};
+ CalendarTime time;
+ CalendarAdditionalInfo additional_info;
};
static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size");
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:
: ServiceFramework{system_, "IClientEpSession"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Open"},
+ {0, nullptr, "ReOpen"},
{1, nullptr, "Close"},
- {2, nullptr, "Unknown2"},
- {3, nullptr, "Populate"},
+ {2, nullptr, "GetCompletionEvent"},
+ {3, nullptr, "PopulateRing"},
{4, nullptr, "PostBufferAsync"},
{5, nullptr, "GetXferReport"},
{6, nullptr, "PostBufferMultiAsync"},
- {7, nullptr, "Unknown7"},
- {8, nullptr, "Unknown8"},
+ {7, nullptr, "CreateSmmuSpace"},
+ {8, nullptr, "ShareReportRing"},
};
// clang-format on
@@ -91,7 +91,7 @@ public:
: ServiceFramework{system_, "IClientIfSession"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown0"},
+ {0, nullptr, "GetStateChangeEvent"},
{1, nullptr, "SetInterface"},
{2, nullptr, "GetInterface"},
{3, nullptr, "GetAlternateInterface"},
@@ -176,15 +176,15 @@ public:
: ServiceFramework{system_, "IPdCradleSession"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "VdmUserWrite"},
- {1, nullptr, "VdmUserRead"},
- {2, nullptr, "Vdm20Init"},
- {3, nullptr, "GetFwType"},
- {4, nullptr, "GetFwRevision"},
- {5, nullptr, "GetManufacturerId"},
- {6, nullptr, "GetDeviceId"},
- {7, nullptr, "Unknown7"},
- {8, nullptr, "Unknown8"},
+ {0, nullptr, "SetCradleVdo"},
+ {1, nullptr, "GetCradleVdo"},
+ {2, nullptr, "ResetCradleUsbHub"},
+ {3, nullptr, "GetHostPdcFirmwareType"},
+ {4, nullptr, "GetHostPdcFirmwareRevision"},
+ {5, nullptr, "GetHostPdcManufactureId"},
+ {6, nullptr, "GetHostPdcDeviceId"},
+ {7, nullptr, "AwakeCradle"},
+ {8, nullptr, "SleepCradle"},
};
// clang-format on
@@ -219,12 +219,12 @@ public:
explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown0"},
- {1, nullptr, "Unknown1"},
- {2, nullptr, "Unknown2"},
- {3, nullptr, "Unknown3"},
- {4, nullptr, "Unknown4"},
- {5, nullptr, "Unknown5"},
+ {0, nullptr, "GetPowerEvent"},
+ {1, nullptr, "GetPowerState"},
+ {2, nullptr, "GetDataEvent"},
+ {3, nullptr, "GetDataRole"},
+ {4, nullptr, "SetDiagData"},
+ {5, nullptr, "GetDiagData"},
};
// clang-format on
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 @@
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/math_util.h"
+#include "common/settings.h"
#include "common/swap.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
@@ -30,7 +31,6 @@
#include "core/hle/service/vi/vi_m.h"
#include "core/hle/service/vi/vi_s.h"
#include "core/hle/service/vi/vi_u.h"
-#include "core/settings.h"
namespace Service::VI {
@@ -695,6 +695,7 @@ public:
{2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
{2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"},
{2209, nullptr, "SetLayerAlpha"},
+ {2210, nullptr, "SetLayerPositionAndSize"},
{2312, nullptr, "CreateStrayLayer"},
{2400, nullptr, "OpenIndirectLayer"},
{2401, nullptr, "CloseIndirectLayer"},
@@ -718,6 +719,7 @@ public:
{3215, nullptr, "SetDisplayGamma"},
{3216, nullptr, "GetDisplayCmuLuma"},
{3217, nullptr, "SetDisplayCmuLuma"},
+ {3218, nullptr, "SetDisplayCrcMode"},
{6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
{8225, nullptr, "GetSharedBufferMemoryHandleId"},
{8250, nullptr, "OpenSharedLayer"},
@@ -729,6 +731,7 @@ public:
{8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
{8257, nullptr, "FillSharedFrameBufferColor"},
{8258, nullptr, "CancelSharedFrameBuffer"},
+ {9000, nullptr, "GetDp2hdmiController"},
};
RegisterHandlers(functions);
}
@@ -808,10 +811,15 @@ public:
{2402, nullptr, "GetDisplayHotplugState"},
{2501, nullptr, "GetCompositorErrorInfo"},
{2601, nullptr, "GetDisplayErrorEvent"},
+ {2701, nullptr, "GetDisplayFatalErrorEvent"},
{4201, nullptr, "SetDisplayAlpha"},
{4203, nullptr, "SetDisplayLayerStack"},
{4205, nullptr, "SetDisplayPowerState"},
{4206, nullptr, "SetDefaultDisplay"},
+ {4207, nullptr, "ResetDisplayPanel"},
+ {4208, nullptr, "SetDisplayFatalErrorEnabled"},
+ {4209, nullptr, "IsDisplayPanelOn"},
+ {4300, nullptr, "GetInternalPanelId"},
{6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
{6001, nullptr, "RemoveFromLayerStack"},
{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:
{28, nullptr, "Unknown28"},
{29, nullptr, "Unknown29"},
{30, nullptr, "Unknown30"},
+ {31, nullptr, "Unknown31"},
+ {32, nullptr, "Unknown32"},
+ {33, nullptr, "Unknown33"},
+ {34, nullptr, "Unknown34"},
+ {35, nullptr, "Unknown35"},
+ {36, nullptr, "Unknown36"},
+ {37, nullptr, "Unknown37"},
};
// clang-format on
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 @@
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "common/swap.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
@@ -22,7 +23,6 @@
#include "core/loader/nro.h"
#include "core/loader/nso.h"
#include "core/memory.h"
-#include "core/settings.h"
namespace Loader {
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 @@
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/lz4_compression.h"
+#include "common/settings.h"
#include "common/swap.h"
#include "core/core.h"
#include "core/file_sys/patch_manager.h"
@@ -20,7 +21,6 @@
#include "core/hle/kernel/process.h"
#include "core/loader/nso.h"
#include "core/memory.h"
-#include "core/settings.h"
namespace Loader {
namespace {
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 @@
#include <fmt/format.h>
#include "common/file_util.h"
#include "common/math_util.h"
+#include "common/settings.h"
#include "core/perf_stats.h"
-#include "core/settings.h"
using namespace std::chrono_literals;
using 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 @@
#include "common/file_util.h"
#include "common/hex_util.h"
#include "common/scm_rev.h"
+#include "common/settings.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/hle_ipc.h"
@@ -22,7 +23,6 @@
#include "core/hle/result.h"
#include "core/memory.h"
#include "core/reporter.h"
-#include "core/settings.h"
namespace {
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 @@
#include "common/file_util.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/loader/loader.h"
-#include "core/settings.h"
#include "core/telemetry_session.h"
#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
motion_from_button.h
motion_input.cpp
motion_input.h
- settings.cpp
- settings.h
touch_from_button.cpp
touch_from_button.h
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 @@
#include <cmath>
#include <thread>
#include "common/math_util.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "input_common/analog_from_button.h"
namespace 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 @@
#include "common/logging/log.h"
#include "common/param_package.h"
+#include "common/settings_input.h"
#include "input_common/gcadapter/gc_adapter.h"
-#include "input_common/settings.h"
namespace GCAdapter {
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 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
-#include "core/settings.h"
+#include "common/settings.h"
#include "input_common/mouse/mouse_input.h"
namespace 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 @@
#include <mutex>
#include <utility>
+#include "common/settings.h"
#include "common/threadsafe_queue.h"
-#include "core/settings.h"
#include "input_common/mouse/mouse_input.h"
#include "input_common/mouse/mouse_poller.h"
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 @@
#include <SDL.h>
#include "common/logging/log.h"
#include "common/param_package.h"
+#include "common/settings_input.h"
#include "common/threadsafe_queue.h"
#include "core/frontend/input.h"
#include "input_common/motion_input.h"
#include "input_common/sdl/sdl_impl.h"
-#include "input_common/settings.h"
namespace InputCommon::SDL {
@@ -761,7 +761,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
for (const auto& joystick : value) {
if (auto* const controller = joystick->GetSDLGameController()) {
std::string name =
- fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
+ fmt::format("{} {}", GetControllerName(controller), joystick->GetPort());
devices.emplace_back(Common::ParamPackage{
{"class", "sdl"},
{"display", std::move(name)},
@@ -782,6 +782,17 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
return devices;
}
+std::string SDLState::GetControllerName(SDL_GameController* controller) const {
+ switch (SDL_GameControllerGetType(controller)) {
+ case SDL_CONTROLLER_TYPE_XBOX360:
+ return "XBox 360 Controller";
+ case SDL_CONTROLLER_TYPE_XBOXONE:
+ return "XBox One Controller";
+ default:
+ return SDL_GameControllerName(controller);
+ }
+}
+
namespace {
Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
float value = 0.1f) {
@@ -930,16 +941,19 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa
return {};
}
+ const bool invert =
+ SDL_GameControllerGetType(controller) != SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
+
// This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
// We will add those afterwards
// This list also excludes Screenshot since theres not really a mapping for that
using ButtonBindings =
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
- static constexpr ButtonBindings switch_to_sdl_button{{
- {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
- {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
- {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
- {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
+ const ButtonBindings switch_to_sdl_button{{
+ {Settings::NativeButton::A, invert ? SDL_CONTROLLER_BUTTON_B : SDL_CONTROLLER_BUTTON_A},
+ {Settings::NativeButton::B, invert ? SDL_CONTROLLER_BUTTON_A : SDL_CONTROLLER_BUTTON_B},
+ {Settings::NativeButton::X, invert ? SDL_CONTROLLER_BUTTON_Y : SDL_CONTROLLER_BUTTON_X},
+ {Settings::NativeButton::Y, invert ? SDL_CONTROLLER_BUTTON_X : SDL_CONTROLLER_BUTTON_Y},
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
{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 @@
#include "input_common/sdl/sdl.h"
union SDL_Event;
+using SDL_GameController = struct _SDL_GameController;
using SDL_Joystick = struct _SDL_Joystick;
using SDL_JoystickID = s32;
@@ -64,6 +65,9 @@ private:
/// Needs to be called before SDL_QuitSubSystem.
void CloseJoysticks();
+ /// Returns a custom name for specific controllers because the default name is not correct
+ std::string GetControllerName(SDL_GameController* controller) const;
+
// Set to true if SDL supports game controller subsystem
bool has_gamecontroller = false;
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/settings.h"
#include "core/frontend/framebuffer_layout.h"
-#include "core/settings.h"
#include "input_common/touch_from_button.h"
namespace 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 @@
#include <thread>
#include <boost/asio.hpp>
#include "common/logging/log.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "input_common/udp/client.h"
#include "input_common/udp/protocol.h"
@@ -27,11 +27,9 @@ class Socket {
public:
using clock = std::chrono::system_clock;
- explicit Socket(const std::string& host, u16 port, std::size_t pad_index_,
- SocketCallback callback_)
+ explicit Socket(const std::string& host, u16 port, SocketCallback callback_)
: callback(std::move(callback_)), timer(io_service),
- socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()),
- pad_index(pad_index_) {
+ socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) {
boost::system::error_code ec{};
auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
if (ec.value() != boost::system::errc::success) {
@@ -99,15 +97,15 @@ private:
void HandleSend(const boost::system::error_code&) {
boost::system::error_code _ignored{};
// Send a request for getting port info for the pad
- const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}};
+ const Request::PortInfo port_info{4, {0, 1, 2, 3}};
const auto port_message = Request::Create(port_info, client_id);
std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);
socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);
// Send a request for getting pad data for the pad
const Request::PadData pad_data{
- Request::PadData::Flags::Id,
- static_cast<u8>(pad_index),
+ Request::PadData::Flags::AllPorts,
+ 0,
EMPTY_MAC_ADDRESS,
};
const auto pad_message = Request::Create(pad_data, client_id);
@@ -122,7 +120,6 @@ private:
udp::socket socket;
const u32 client_id;
- std::size_t pad_index{};
static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>);
@@ -150,34 +147,32 @@ Client::~Client() {
Reset();
}
-Client::ClientData::ClientData() = default;
+Client::ClientConnection::ClientConnection() = default;
-Client::ClientData::~ClientData() = default;
+Client::ClientConnection::~ClientConnection() = default;
std::vector<Common::ParamPackage> Client::GetInputDevices() const {
std::vector<Common::ParamPackage> devices;
- for (std::size_t client = 0; client < clients.size(); client++) {
- if (!DeviceConnected(client)) {
+ for (std::size_t pad = 0; pad < pads.size(); pad++) {
+ if (!DeviceConnected(pad)) {
continue;
}
- std::string name = fmt::format("UDP Controller {}", client);
+ std::string name = fmt::format("UDP Controller {}", pad);
devices.emplace_back(Common::ParamPackage{
{"class", "cemuhookudp"},
{"display", std::move(name)},
- {"port", std::to_string(client)},
+ {"port", std::to_string(pad)},
});
}
return devices;
}
-bool Client::DeviceConnected(std::size_t client) const {
+bool Client::DeviceConnected(std::size_t pad) const {
// Use last timestamp to detect if the socket has stopped sending data
const auto now = std::chrono::steady_clock::now();
- const auto time_difference =
- static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>(
- now - clients[client].last_motion_update)
- .count());
- return time_difference < 1000 && clients[client].active == 1;
+ const auto time_difference = static_cast<u64>(
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - pads[pad].last_update).count());
+ return time_difference < 1000 && pads[pad].connected;
}
void Client::ReloadSockets() {
@@ -202,25 +197,21 @@ void Client::ReloadSockets() {
continue;
}
- for (std::size_t pad = 0; pad < 4; ++pad) {
- const std::size_t client_number =
- GetClientNumber(udp_input_address, udp_input_port, pad);
- if (client_number != MAX_UDP_CLIENTS) {
- LOG_ERROR(Input, "Duplicated UDP servers found");
- continue;
- }
- StartCommunication(client++, udp_input_address, udp_input_port, pad);
+ const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port);
+ if (client_number != MAX_UDP_CLIENTS) {
+ LOG_ERROR(Input, "Duplicated UDP servers found");
+ continue;
}
+ StartCommunication(client++, udp_input_address, udp_input_port);
}
}
-std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const {
+std::size_t Client::GetClientNumber(std::string_view host, u16 port) const {
for (std::size_t client = 0; client < clients.size(); client++) {
if (clients[client].active == -1) {
continue;
}
- if (clients[client].host == host && clients[client].port == port &&
- clients[client].pad_index == pad) {
+ if (clients[client].host == host && clients[client].port == port) {
return client;
}
}
@@ -236,69 +227,75 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) {
}
void Client::OnPadData(Response::PadData data, std::size_t client) {
- // Accept packets only for the correct pad
- if (static_cast<u8>(clients[client].pad_index) != data.info.id) {
+ const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id;
+
+ if (pad_index >= pads.size()) {
+ LOG_ERROR(Input, "Invalid pad id {}", data.info.id);
return;
}
LOG_TRACE(Input, "PadData packet received");
- if (data.packet_counter == clients[client].packet_sequence) {
+ if (data.packet_counter == pads[pad_index].packet_sequence) {
LOG_WARNING(
Input,
"PadData packet dropped because its stale info. Current count: {} Packet count: {}",
- clients[client].packet_sequence, data.packet_counter);
+ pads[pad_index].packet_sequence, data.packet_counter);
+ pads[pad_index].connected = false;
return;
}
- clients[client].active = static_cast<s8>(data.info.is_pad_active);
- clients[client].packet_sequence = data.packet_counter;
+
+ clients[client].active = 1;
+ pads[pad_index].connected = true;
+ pads[pad_index].packet_sequence = data.packet_counter;
+
const auto now = std::chrono::steady_clock::now();
- const auto time_difference =
- static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>(
- now - clients[client].last_motion_update)
- .count());
- clients[client].last_motion_update = now;
+ const auto time_difference = static_cast<u64>(
+ std::chrono::duration_cast<std::chrono::microseconds>(now - pads[pad_index].last_update)
+ .count());
+ pads[pad_index].last_update = now;
+
const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw};
- clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
+ pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
// Gyroscope values are not it the correct scale from better joy.
// Dividing by 312 allows us to make one full turn = 1 turn
// This must be a configurable valued called sensitivity
- clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f);
- clients[client].motion.UpdateRotation(time_difference);
- clients[client].motion.UpdateOrientation(time_difference);
+ pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f);
+ pads[pad_index].motion.UpdateRotation(time_difference);
+ pads[pad_index].motion.UpdateOrientation(time_difference);
{
- std::lock_guard guard(clients[client].status.update_mutex);
- clients[client].status.motion_status = clients[client].motion.GetMotion();
+ std::lock_guard guard(pads[pad_index].status.update_mutex);
+ pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion();
for (std::size_t id = 0; id < data.touch.size(); ++id) {
UpdateTouchInput(data.touch[id], client, id);
}
if (configuring) {
- const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
- const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
- UpdateYuzuSettings(client, accelerometer, gyroscope);
+ const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope();
+ const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration();
+ UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope);
}
}
}
-void Client::StartCommunication(std::size_t client, const std::string& host, u16 port,
- std::size_t pad_index) {
+void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) {
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
[this](Response::PortInfo info) { OnPortInfo(info); },
[this, client](Response::PadData data) { OnPadData(data, client); }};
- LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port,
- pad_index);
+ LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
clients[client].host = host;
clients[client].port = port;
- clients[client].pad_index = pad_index;
clients[client].active = 0;
- clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback);
+ clients[client].socket = std::make_unique<Socket>(host, port, callback);
clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
+
// Set motion parameters
// SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
// Real HW values are unknown, 0.0001 is an approximate to Standard
- clients[client].motion.SetGyroThreshold(0.0001f);
+ for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) {
+ pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f);
+ }
}
void Client::Reset() {
@@ -311,8 +308,8 @@ void Client::Reset() {
}
}
-void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
- const Common::Vec3<float>& gyro) {
+void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
+ const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro) {
if (gyro.Length() > 0.2f) {
LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client,
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
UDPPadStatus pad{
.host = clients[client].host,
.port = clients[client].port,
- .pad_index = clients[client].pad_index,
+ .pad_index = pad_index,
};
for (std::size_t i = 0; i < 3; ++i) {
if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
@@ -391,19 +388,19 @@ void Client::EndConfiguration() {
}
DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) {
- const std::size_t client_number = GetClientNumber(host, port, pad);
- if (client_number == MAX_UDP_CLIENTS) {
- return clients[0].status;
+ const std::size_t client_number = GetClientNumber(host, port);
+ if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) {
+ return pads[0].status;
}
- return clients[client_number].status;
+ return pads[(client_number * PADS_PER_CLIENT) + pad].status;
}
const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const {
- const std::size_t client_number = GetClientNumber(host, port, pad);
- if (client_number == MAX_UDP_CLIENTS) {
- return clients[0].status;
+ const std::size_t client_number = GetClientNumber(host, port);
+ if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) {
+ return pads[0].status;
}
- return clients[client_number].status;
+ return pads[(client_number * PADS_PER_CLIENT) + pad].status;
}
Input::TouchStatus& Client::GetTouchState() {
@@ -422,7 +419,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
return pad_queue;
}
-void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
+void TestCommunication(const std::string& host, u16 port,
const std::function<void()>& success_callback,
const std::function<void()>& failure_callback) {
std::thread([=] {
@@ -432,9 +429,10 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
.port_info = [](Response::PortInfo) {},
.pad_data = [&](Response::PadData) { success_event.Set(); },
};
- Socket socket{host, port, pad_index, std::move(callback)};
+ Socket socket{host, port, std::move(callback)};
std::thread worker_thread{SocketLoop, &socket};
- const bool result = success_event.WaitFor(std::chrono::seconds(5));
+ const bool result =
+ success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10));
socket.Stop();
worker_thread.join();
if (result) {
@@ -446,8 +444,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
}
CalibrationConfigurationJob::CalibrationConfigurationJob(
- const std::string& host, u16 port, std::size_t pad_index,
- std::function<void(Status)> status_callback,
+ const std::string& host, u16 port, std::function<void(Status)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback) {
std::thread([=, this] {
@@ -491,7 +488,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
complete_event.Set();
}
}};
- Socket socket{host, port, pad_index, std::move(callback)};
+ Socket socket{host, port, std::move(callback)};
std::thread worker_thread{SocketLoop, &socket};
complete_event.Wait();
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:
std::vector<Common::ParamPackage> GetInputDevices() const;
- bool DeviceConnected(std::size_t client) const;
+ bool DeviceConnected(std::size_t pad) const;
void ReloadSockets();
Common::SPSCQueue<UDPPadStatus>& GetPadQueue();
@@ -97,38 +97,40 @@ public:
const Input::TouchStatus& GetTouchState() const;
private:
- struct ClientData {
- ClientData();
- ~ClientData();
-
- std::string host{"127.0.0.1"};
- u16 port{26760};
+ struct PadData {
std::size_t pad_index{};
- std::unique_ptr<Socket> socket;
+ bool connected{};
DeviceStatus status;
- std::thread thread;
u64 packet_sequence{};
- s8 active{-1};
// Realtime values
// motion is initalized with PID values for drift correction on joycons
InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f};
- std::chrono::time_point<std::chrono::steady_clock> last_motion_update;
+ std::chrono::time_point<std::chrono::steady_clock> last_update;
+ };
+
+ struct ClientConnection {
+ ClientConnection();
+ ~ClientConnection();
+ std::string host{"127.0.0.1"};
+ u16 port{26760};
+ s8 active{-1};
+ std::unique_ptr<Socket> socket;
+ std::thread thread;
};
// For shutting down, clear all data, join all threads, release usb
void Reset();
// Translates configuration to client number
- std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const;
+ std::size_t GetClientNumber(std::string_view host, u16 port) const;
void OnVersion(Response::Version);
void OnPortInfo(Response::PortInfo);
void OnPadData(Response::PadData, std::size_t client);
- void StartCommunication(std::size_t client, const std::string& host, u16 port,
- std::size_t pad_index);
- void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
- const Common::Vec3<float>& gyro);
+ void StartCommunication(std::size_t client, const std::string& host, u16 port);
+ void UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
+ const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro);
// Returns an unused finger id, if there is no fingers available std::nullopt will be
// returned
@@ -140,10 +142,12 @@ private:
bool configuring = false;
// Allocate clients for 8 udp servers
- static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8;
+ static constexpr std::size_t MAX_UDP_CLIENTS = 8;
+ static constexpr std::size_t PADS_PER_CLIENT = 4;
// Each client can have up 2 touch inputs
static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2;
- std::array<ClientData, MAX_UDP_CLIENTS> clients{};
+ std::array<PadData, MAX_UDP_CLIENTS * PADS_PER_CLIENT> pads{};
+ std::array<ClientConnection, MAX_UDP_CLIENTS> clients{};
Common::SPSCQueue<UDPPadStatus> pad_queue{};
Input::TouchStatus touch_status{};
std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{};
@@ -164,7 +168,7 @@ public:
* @param status_callback Callback for job status updates
* @param data_callback Called when calibration data is ready
*/
- explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index,
+ explicit CalibrationConfigurationJob(const std::string& host, u16 port,
std::function<void(Status)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback);
~CalibrationConfigurationJob();
@@ -174,7 +178,7 @@ private:
Common::Event complete_event;
};
-void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
+void TestCommunication(const std::string& host, u16 port,
const std::function<void()>& success_callback,
const std::function<void()>& failure_callback);
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
texture_cache/types.h
texture_cache/util.cpp
texture_cache/util.h
- textures/astc.cpp
textures/astc.h
textures/decoders.cpp
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 @@
#include "common/div_ceil.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
+#include "common/settings.h"
#include "core/memory.h"
-#include "core/settings.h"
#include "video_core/buffer_cache/buffer_base.h"
#include "video_core/delayed_destruction_ring.h"
#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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <cstring> // for std::memcpy
+#include <algorithm> // for std::copy
#include <numeric>
+#include "common/assert.h"
#include "video_core/command_classes/codecs/vp9.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
@@ -362,7 +363,8 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state)
// surface_luma_offset[0:3] contains the address of the reference frame offsets in the following
// order: last, golden, altref, current. It may be worthwhile to track the updates done here
// to avoid buffering frame data needed for reference frame updating in the header composition.
- std::memcpy(vp9_info.frame_offsets.data(), state.surface_luma_offset.data(), 4 * sizeof(u64));
+ std::copy(state.surface_luma_offset.begin(), state.surface_luma_offset.begin() + 4,
+ vp9_info.frame_offsets.begin());
return vp9_info;
}
@@ -821,11 +823,11 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
// Write headers and frame to buffer
frame.resize(uncompressed_header.size() + compressed_header.size() + bitstream.size());
- std::memcpy(frame.data(), uncompressed_header.data(), uncompressed_header.size());
- std::memcpy(frame.data() + uncompressed_header.size(), compressed_header.data(),
- compressed_header.size());
- std::memcpy(frame.data() + uncompressed_header.size() + compressed_header.size(),
- bitstream.data(), bitstream.size());
+ std::copy(uncompressed_header.begin(), uncompressed_header.end(), frame.begin());
+ std::copy(compressed_header.begin(), compressed_header.end(),
+ frame.begin() + uncompressed_header.size());
+ std::copy(bitstream.begin(), bitstream.end(),
+ frame.begin() + uncompressed_header.size() + compressed_header.size());
// keep track of frame number
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 @@
#pragma once
-#include <type_traits>
#include "common/common_types.h"
namespace Tegra::Engines {
class EngineInterface {
public:
+ virtual ~EngineInterface() = default;
+
/// Write the value to the register identified by method.
virtual void CallMethod(u32 method, u32 method_argument, bool is_last_call) = 0;
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 {
class Fermi2D final : public EngineInterface {
public:
explicit Fermi2D();
- ~Fermi2D();
+ ~Fermi2D() override;
/// Binds a rasterizer to this engine.
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 {
class KeplerMemory final : public EngineInterface {
public:
explicit KeplerMemory(Core::System& system_, MemoryManager& memory_manager);
- ~KeplerMemory();
+ ~KeplerMemory() override;
/// Write the value to the register identified by method.
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 @@
#include "common/assert.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/maxwell_dma.h"
#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:
static_assert(sizeof(RemapConst) == 12);
explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_);
- ~MaxwellDMA();
+ ~MaxwellDMA() override;
/// Write the value to the register identified by method.
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 @@
#include "common/assert.h"
#include "common/microprofile.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/frontend/emu_window.h"
#include "core/hardware_interrupt_manager.h"
#include "core/memory.h"
-#include "core/settings.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/kepler_memory.h"
@@ -519,8 +519,8 @@ void GPU::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const {
interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
}
-void GPU::WaitIdle() const {
- gpu_thread.WaitIdle();
+void GPU::ShutDown() {
+ gpu_thread.ShutDown();
}
void 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:
return *shader_notify;
}
- // Waits for the GPU to finish working
- void WaitIdle() const;
+ // Stops the GPU execution and waits for the GPU to finish working
+ void ShutDown();
/// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame.
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 @@
#include "common/assert.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
+#include "common/settings.h"
#include "common/thread.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
-#include "core/settings.h"
#include "video_core/dma_pusher.h"
#include "video_core/gpu.h"
#include "video_core/gpu_thread.h"
@@ -29,8 +29,7 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
system.RegisterHostThread();
// Wait for first GPU command before acquiring the window context
- while (state.queue.Empty())
- ;
+ state.queue.Wait();
// If emulation was stopped during disk shader loading, abort before trying to acquire context
if (!state.is_running) {
@@ -57,11 +56,17 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
} else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
rasterizer->OnCPUWrite(invalidate->addr, invalidate->size);
} else if (std::holds_alternative<EndProcessingCommand>(next.data)) {
- return;
+ ASSERT(state.is_running == false);
} else {
UNREACHABLE();
}
state.signaled_fence.store(next.fence);
+ if (next.block) {
+ // We have to lock the write_lock to ensure that the condition_variable wait not get a
+ // race between the check and the lock itself.
+ std::lock_guard lk(state.write_lock);
+ state.cv.notify_all();
+ }
}
}
@@ -69,13 +74,7 @@ ThreadManager::ThreadManager(Core::System& system_, bool is_async_)
: system{system_}, is_async{is_async_} {}
ThreadManager::~ThreadManager() {
- if (!thread.joinable()) {
- return;
- }
-
- // Notify GPU thread that a shutdown is pending
- PushCommand(EndProcessingCommand());
- thread.join();
+ ShutDown();
}
void ThreadManager::StartThread(VideoCore::RendererBase& renderer,
@@ -112,9 +111,8 @@ void ThreadManager::FlushRegion(VAddr addr, u64 size) {
case Settings::GPUAccuracy::Extreme: {
auto& gpu = system.GPU();
u64 fence = gpu.RequestFlush(addr, size);
- PushCommand(GPUTickCommand());
- while (fence > gpu.CurrentFlushRequestFence()) {
- }
+ PushCommand(GPUTickCommand(), true);
+ ASSERT(fence <= gpu.CurrentFlushRequestFence());
break;
}
default:
@@ -131,23 +129,45 @@ void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) {
rasterizer->OnCPUWrite(addr, size);
}
-void ThreadManager::WaitIdle() const {
- while (state.last_fence > state.signaled_fence.load(std::memory_order_relaxed) &&
- system.IsPoweredOn()) {
+void ThreadManager::ShutDown() {
+ if (!state.is_running) {
+ return;
}
+
+ {
+ std::lock_guard lk(state.write_lock);
+ state.is_running = false;
+ state.cv.notify_all();
+ }
+
+ if (!thread.joinable()) {
+ return;
+ }
+
+ // Notify GPU thread that a shutdown is pending
+ PushCommand(EndProcessingCommand());
+ thread.join();
}
void ThreadManager::OnCommandListEnd() {
PushCommand(OnCommandListEndCommand());
}
-u64 ThreadManager::PushCommand(CommandData&& command_data) {
- const u64 fence{++state.last_fence};
- state.queue.Push(CommandDataContainer(std::move(command_data), fence));
-
+u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
if (!is_async) {
// In synchronous GPU mode, block the caller until the command has executed
- WaitIdle();
+ block = true;
+ }
+
+ std::unique_lock lk(state.write_lock);
+ const u64 fence{++state.last_fence};
+ state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));
+
+ if (block) {
+ state.cv.wait(lk, [this, fence] {
+ return fence <= state.signaled_fence.load(std::memory_order_relaxed) ||
+ !state.is_running;
+ });
}
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 =
struct CommandDataContainer {
CommandDataContainer() = default;
- explicit CommandDataContainer(CommandData&& data_, u64 next_fence_)
- : data{std::move(data_)}, fence{next_fence_} {}
+ explicit CommandDataContainer(CommandData&& data_, u64 next_fence_, bool block_)
+ : data{std::move(data_)}, fence{next_fence_}, block(block_) {}
CommandData data;
u64 fence{};
+ bool block{};
};
/// Struct used to synchronize the GPU thread
struct SynchState final {
std::atomic_bool is_running{true};
- using CommandQueue = Common::MPSCQueue<CommandDataContainer>;
+ using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
+ std::mutex write_lock;
CommandQueue queue;
u64 last_fence{};
std::atomic<u64> signaled_fence{};
+ std::condition_variable cv;
};
/// Class used to manage the GPU thread
@@ -132,14 +135,14 @@ public:
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated
void FlushAndInvalidateRegion(VAddr addr, u64 size);
- // Wait until the gpu thread is idle.
- void WaitIdle() const;
+ // Stops the GPU execution and waits for the GPU to finish working
+ void ShutDown();
void OnCommandListEnd();
private:
/// Pushes a command to be executed by the GPU thread
- u64 PushCommand(CommandData&& command_data);
+ u64 PushCommand(CommandData&& command_data, bool block = false);
Core::System& system;
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 @@
set(SHADER_FILES
+ astc_decoder.comp
block_linear_unswizzle_2d.comp
block_linear_unswizzle_3d.comp
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)
string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME})
string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
-file(READ ${SOURCE_FILE} CONTENTS)
+FILE(READ ${SOURCE_FILE} line_contents)
+
+# Replace double quotes with single quotes,
+# as double quotes will be used to wrap the lines
+STRING(REGEX REPLACE "\"" "'" line_contents "${line_contents}")
+
+# CMake separates list elements with semicolons, but semicolons
+# are used extensively in the shader code.
+# Replace with a temporary marker, to be reverted later.
+STRING(REGEX REPLACE ";" "{{SEMICOLON}}" line_contents "${line_contents}")
+
+# Make every line an individual element in the CMake list.
+STRING(REGEX REPLACE "\n" ";" line_contents "${line_contents}")
+
+# Build the shader string, wrapping each line in double quotes.
+foreach(line IN LISTS line_contents)
+ string(CONCAT CONTENTS "${CONTENTS}" \"${line}\\n\"\n)
+endforeach()
+
+# Revert the original semicolons in the source.
+STRING(REGEX REPLACE "{{SEMICOLON}}" ";" CONTENTS "${CONTENTS}")
get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY)
make_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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#version 450
+
+#ifdef VULKAN
+
+#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
+#define END_PUSH_CONSTANTS };
+#define UNIFORM(n)
+#define BINDING_INPUT_BUFFER 0
+#define BINDING_ENC_BUFFER 1
+#define BINDING_6_TO_8_BUFFER 2
+#define BINDING_7_TO_8_BUFFER 3
+#define BINDING_8_TO_8_BUFFER 4
+#define BINDING_BYTE_TO_16_BUFFER 5
+#define BINDING_SWIZZLE_BUFFER 6
+#define BINDING_OUTPUT_IMAGE 7
+
+#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
+
+#define BEGIN_PUSH_CONSTANTS
+#define END_PUSH_CONSTANTS
+#define UNIFORM(n) layout(location = n) uniform
+#define BINDING_SWIZZLE_BUFFER 0
+#define BINDING_INPUT_BUFFER 1
+#define BINDING_ENC_BUFFER 2
+#define BINDING_6_TO_8_BUFFER 3
+#define BINDING_7_TO_8_BUFFER 4
+#define BINDING_8_TO_8_BUFFER 5
+#define BINDING_BYTE_TO_16_BUFFER 6
+#define BINDING_OUTPUT_IMAGE 0
+
+#endif
+
+layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
+
+BEGIN_PUSH_CONSTANTS
+UNIFORM(1) uvec2 block_dims;
+
+UNIFORM(2) uint bytes_per_block_log2;
+UNIFORM(3) uint layer_stride;
+UNIFORM(4) uint block_size;
+UNIFORM(5) uint x_shift;
+UNIFORM(6) uint block_height;
+UNIFORM(7) uint block_height_mask;
+END_PUSH_CONSTANTS
+
+struct EncodingData {
+ uint encoding;
+ uint num_bits;
+ uint bit_value;
+ uint quint_trit_value;
+};
+
+struct TexelWeightParams {
+ uvec2 size;
+ uint max_weight;
+ bool dual_plane;
+ bool error_state;
+ bool void_extent_ldr;
+ bool void_extent_hdr;
+};
+
+// Swizzle data
+layout(binding = BINDING_SWIZZLE_BUFFER, std430) readonly buffer SwizzleTable {
+ uint swizzle_table[];
+};
+
+layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 {
+ uint astc_data[];
+};
+
+// ASTC Encodings data
+layout(binding = BINDING_ENC_BUFFER, std430) readonly buffer EncodingsValues {
+ EncodingData encoding_values[];
+};
+// ASTC Precompiled tables
+layout(binding = BINDING_6_TO_8_BUFFER, std430) readonly buffer REPLICATE_6_BIT_TO_8 {
+ uint REPLICATE_6_BIT_TO_8_TABLE[];
+};
+layout(binding = BINDING_7_TO_8_BUFFER, std430) readonly buffer REPLICATE_7_BIT_TO_8 {
+ uint REPLICATE_7_BIT_TO_8_TABLE[];
+};
+layout(binding = BINDING_8_TO_8_BUFFER, std430) readonly buffer REPLICATE_8_BIT_TO_8 {
+ uint REPLICATE_8_BIT_TO_8_TABLE[];
+};
+layout(binding = BINDING_BYTE_TO_16_BUFFER, std430) readonly buffer REPLICATE_BYTE_TO_16 {
+ uint REPLICATE_BYTE_TO_16_TABLE[];
+};
+
+layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image;
+
+const uint GOB_SIZE_X = 64;
+const uint GOB_SIZE_Y = 8;
+const uint GOB_SIZE_Z = 1;
+const uint GOB_SIZE = GOB_SIZE_X * GOB_SIZE_Y * GOB_SIZE_Z;
+
+const uint GOB_SIZE_X_SHIFT = 6;
+const uint GOB_SIZE_Y_SHIFT = 3;
+const uint GOB_SIZE_Z_SHIFT = 0;
+const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT;
+
+const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1, GOB_SIZE_Y - 1);
+
+const int BLOCK_SIZE_IN_BYTES = 16;
+
+const int BLOCK_INFO_ERROR = 0;
+const int BLOCK_INFO_VOID_EXTENT_HDR = 1;
+const int BLOCK_INFO_VOID_EXTENT_LDR = 2;
+const int BLOCK_INFO_NORMAL = 3;
+
+const int JUST_BITS = 0;
+const int QUINT = 1;
+const int TRIT = 2;
+
+// The following constants are expanded variants of the Replicate()
+// function calls corresponding to the following arguments:
+// value: index into the generated table
+// num_bits: the after "REPLICATE" in the table name. i.e. 4 is num_bits in REPLICATE_4.
+// to_bit: the integer after "TO_"
+const uint REPLICATE_BIT_TO_7_TABLE[2] = uint[](0, 127);
+const uint REPLICATE_1_BIT_TO_9_TABLE[2] = uint[](0, 511);
+
+const uint REPLICATE_1_BIT_TO_8_TABLE[2] = uint[](0, 255);
+const uint REPLICATE_2_BIT_TO_8_TABLE[4] = uint[](0, 85, 170, 255);
+const uint REPLICATE_3_BIT_TO_8_TABLE[8] = uint[](0, 36, 73, 109, 146, 182, 219, 255);
+const uint REPLICATE_4_BIT_TO_8_TABLE[16] =
+ uint[](0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255);
+const uint REPLICATE_5_BIT_TO_8_TABLE[32] =
+ uint[](0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165,
+ 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255);
+const uint REPLICATE_1_BIT_TO_6_TABLE[2] = uint[](0, 63);
+const uint REPLICATE_2_BIT_TO_6_TABLE[4] = uint[](0, 21, 42, 63);
+const uint REPLICATE_3_BIT_TO_6_TABLE[8] = uint[](0, 9, 18, 27, 36, 45, 54, 63);
+const uint REPLICATE_4_BIT_TO_6_TABLE[16] =
+ uint[](0, 4, 8, 12, 17, 21, 25, 29, 34, 38, 42, 46, 51, 55, 59, 63);
+const uint REPLICATE_5_BIT_TO_6_TABLE[32] =
+ uint[](0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 33, 35, 37, 39, 41, 43, 45,
+ 47, 49, 51, 53, 55, 57, 59, 61, 63);
+
+// Input ASTC texture globals
+uint current_index = 0;
+int bitsread = 0;
+uint total_bitsread = 0;
+uint local_buff[16];
+
+// Color data globals
+uint color_endpoint_data[16];
+int color_bitsread = 0;
+uint total_color_bitsread = 0;
+int color_index = 0;
+
+// Four values, two endpoints, four maximum paritions
+uint color_values[32];
+int colvals_index = 0;
+
+// Weight data globals
+uint texel_weight_data[16];
+int texel_bitsread = 0;
+uint total_texel_bitsread = 0;
+int texel_index = 0;
+
+bool texel_flag = false;
+
+// Global "vectors" to be pushed into when decoding
+EncodingData result_vector[100];
+int result_index = 0;
+
+EncodingData texel_vector[100];
+int texel_vector_index = 0;
+
+uint unquantized_texel_weights[2][144];
+
+uint SwizzleOffset(uvec2 pos) {
+ pos = pos & SWIZZLE_MASK;
+ return swizzle_table[pos.y * 64 + pos.x];
+}
+
+uint ReadTexel(uint offset) {
+ // extract the 8-bit value from the 32-bit packed data.
+ return bitfieldExtract(astc_data[offset / 4], int((offset * 8) & 24), 8);
+}
+
+// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
+// is the same as [(num_bits - 1):0] and repeats all the way down.
+uint Replicate(uint val, uint num_bits, uint to_bit) {
+ if (num_bits == 0 || to_bit == 0) {
+ return 0;
+ }
+ const uint v = val & uint((1 << num_bits) - 1);
+ uint res = v;
+ uint reslen = num_bits;
+ while (reslen < to_bit) {
+ uint comp = 0;
+ if (num_bits > to_bit - reslen) {
+ uint newshift = to_bit - reslen;
+ comp = num_bits - newshift;
+ num_bits = newshift;
+ }
+ res = uint(res << num_bits);
+ res = uint(res | (v >> comp));
+ reslen += num_bits;
+ }
+ return res;
+}
+
+uvec4 ReplicateByteTo16(uvec4 value) {
+ return uvec4(REPLICATE_BYTE_TO_16_TABLE[value.x], REPLICATE_BYTE_TO_16_TABLE[value.y],
+ REPLICATE_BYTE_TO_16_TABLE[value.z], REPLICATE_BYTE_TO_16_TABLE[value.w]);
+}
+
+uint ReplicateBitTo7(uint value) {
+ return REPLICATE_BIT_TO_7_TABLE[value];
+}
+
+uint ReplicateBitTo9(uint value) {
+ return REPLICATE_1_BIT_TO_9_TABLE[value];
+}
+
+uint FastReplicateTo8(uint value, uint num_bits) {
+ switch (num_bits) {
+ case 1:
+ return REPLICATE_1_BIT_TO_8_TABLE[value];
+ case 2:
+ return REPLICATE_2_BIT_TO_8_TABLE[value];
+ case 3:
+ return REPLICATE_3_BIT_TO_8_TABLE[value];
+ case 4:
+ return REPLICATE_4_BIT_TO_8_TABLE[value];
+ case 5:
+ return REPLICATE_5_BIT_TO_8_TABLE[value];
+ case 6:
+ return REPLICATE_6_BIT_TO_8_TABLE[value];
+ case 7:
+ return REPLICATE_7_BIT_TO_8_TABLE[value];
+ case 8:
+ return REPLICATE_8_BIT_TO_8_TABLE[value];
+ }
+ return Replicate(value, num_bits, 8);
+}
+
+uint FastReplicateTo6(uint value, uint num_bits) {
+ switch (num_bits) {
+ case 1:
+ return REPLICATE_1_BIT_TO_6_TABLE[value];
+ case 2:
+ return REPLICATE_2_BIT_TO_6_TABLE[value];
+ case 3:
+ return REPLICATE_3_BIT_TO_6_TABLE[value];
+ case 4:
+ return REPLICATE_4_BIT_TO_6_TABLE[value];
+ case 5:
+ return REPLICATE_5_BIT_TO_6_TABLE[value];
+ }
+ return Replicate(value, num_bits, 6);
+}
+
+uint Div3Floor(uint v) {
+ return (v * 0x5556) >> 16;
+}
+
+uint Div3Ceil(uint v) {
+ return Div3Floor(v + 2);
+}
+
+uint Div5Floor(uint v) {
+ return (v * 0x3334) >> 16;
+}
+
+uint Div5Ceil(uint v) {
+ return Div5Floor(v + 4);
+}
+
+uint Hash52(uint p) {
+ p ^= p >> 15;
+ p -= p << 17;
+ p += p << 7;
+ p += p << 4;
+ p ^= p >> 5;
+ p += p << 16;
+ p ^= p >> 7;
+ p ^= p >> 3;
+ p ^= p << 6;
+ p ^= p >> 17;
+ return p;
+}
+
+uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bool small_block) {
+ if (partition_count == 1) {
+ return 0;
+ }
+ if (small_block) {
+ x <<= 1;
+ y <<= 1;
+ z <<= 1;
+ }
+
+ seed += (partition_count - 1) * 1024;
+
+ uint rnum = Hash52(uint(seed));
+ uint seed1 = uint(rnum & 0xF);
+ uint seed2 = uint((rnum >> 4) & 0xF);
+ uint seed3 = uint((rnum >> 8) & 0xF);
+ uint seed4 = uint((rnum >> 12) & 0xF);
+ uint seed5 = uint((rnum >> 16) & 0xF);
+ uint seed6 = uint((rnum >> 20) & 0xF);
+ uint seed7 = uint((rnum >> 24) & 0xF);
+ uint seed8 = uint((rnum >> 28) & 0xF);
+ uint seed9 = uint((rnum >> 18) & 0xF);
+ uint seed10 = uint((rnum >> 22) & 0xF);
+ uint seed11 = uint((rnum >> 26) & 0xF);
+ uint seed12 = uint(((rnum >> 30) | (rnum << 2)) & 0xF);
+
+ seed1 = (seed1 * seed1);
+ seed2 = (seed2 * seed2);
+ seed3 = (seed3 * seed3);
+ seed4 = (seed4 * seed4);
+ seed5 = (seed5 * seed5);
+ seed6 = (seed6 * seed6);
+ seed7 = (seed7 * seed7);
+ seed8 = (seed8 * seed8);
+ seed9 = (seed9 * seed9);
+ seed10 = (seed10 * seed10);
+ seed11 = (seed11 * seed11);
+ seed12 = (seed12 * seed12);
+
+ int sh1, sh2, sh3;
+ if ((seed & 1) > 0) {
+ sh1 = (seed & 2) > 0 ? 4 : 5;
+ sh2 = (partition_count == 3) ? 6 : 5;
+ } else {
+ sh1 = (partition_count == 3) ? 6 : 5;
+ sh2 = (seed & 2) > 0 ? 4 : 5;
+ }
+ sh3 = (seed & 0x10) > 0 ? sh1 : sh2;
+
+ seed1 = (seed1 >> sh1);
+ seed2 = (seed2 >> sh2);
+ seed3 = (seed3 >> sh1);
+ seed4 = (seed4 >> sh2);
+ seed5 = (seed5 >> sh1);
+ seed6 = (seed6 >> sh2);
+ seed7 = (seed7 >> sh1);
+ seed8 = (seed8 >> sh2);
+ seed9 = (seed9 >> sh3);
+ seed10 = (seed10 >> sh3);
+ seed11 = (seed11 >> sh3);
+ seed12 = (seed12 >> sh3);
+
+ uint a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
+ uint b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
+ uint c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
+ uint d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
+
+ a &= 0x3F;
+ b &= 0x3F;
+ c &= 0x3F;
+ d &= 0x3F;
+
+ if (partition_count < 4) {
+ d = 0;
+ }
+ if (partition_count < 3) {
+ c = 0;
+ }
+
+ if (a >= b && a >= c && a >= d) {
+ return 0;
+ } else if (b >= c && b >= d) {
+ return 1;
+ } else if (c >= d) {
+ return 2;
+ } else {
+ return 3;
+ }
+}
+
+uint Select2DPartition(uint seed, uint x, uint y, uint partition_count, bool small_block) {
+ return SelectPartition(seed, x, y, 0, partition_count, small_block);
+}
+
+uint ReadBit() {
+ if (current_index >= local_buff.length()) {
+ return 0;
+ }
+ uint bit = bitfieldExtract(local_buff[current_index], bitsread, 1);
+ ++bitsread;
+ ++total_bitsread;
+ if (bitsread == 8) {
+ ++current_index;
+ bitsread = 0;
+ }
+ return bit;
+}
+
+uint StreamBits(uint num_bits) {
+ uint ret = 0;
+ for (uint i = 0; i < num_bits; i++) {
+ ret |= ((ReadBit() & 1) << i);
+ }
+ return ret;
+}
+
+uint ReadColorBit() {
+ uint bit = 0;
+ if (texel_flag) {
+ bit = bitfieldExtract(texel_weight_data[texel_index], texel_bitsread, 1);
+ ++texel_bitsread;
+ ++total_texel_bitsread;
+ if (texel_bitsread == 8) {
+ ++texel_index;
+ texel_bitsread = 0;
+ }
+ } else {
+ bit = bitfieldExtract(color_endpoint_data[color_index], color_bitsread, 1);
+ ++color_bitsread;
+ ++total_color_bitsread;
+ if (color_bitsread == 8) {
+ ++color_index;
+ color_bitsread = 0;
+ }
+ }
+ return bit;
+}
+
+uint StreamColorBits(uint num_bits) {
+ uint ret = 0;
+ for (uint i = 0; i < num_bits; i++) {
+ ret |= ((ReadColorBit() & 1) << i);
+ }
+ return ret;
+}
+
+void ResultEmplaceBack(EncodingData val) {
+ if (texel_flag) {
+ texel_vector[texel_vector_index] = val;
+ ++texel_vector_index;
+ } else {
+ result_vector[result_index] = val;
+ ++result_index;
+ }
+}
+
+// Returns the number of bits required to encode n_vals values.
+uint GetBitLength(uint n_vals, uint encoding_index) {
+ uint total_bits = encoding_values[encoding_index].num_bits * n_vals;
+ if (encoding_values[encoding_index].encoding == TRIT) {
+ total_bits += Div5Ceil(n_vals * 8);
+ } else if (encoding_values[encoding_index].encoding == QUINT) {
+ total_bits += Div3Ceil(n_vals * 7);
+ }
+ return total_bits;
+}
+
+uint GetNumWeightValues(uvec2 size, bool dual_plane) {
+ uint n_vals = size.x * size.y;
+ if (dual_plane) {
+ n_vals *= 2;
+ }
+ return n_vals;
+}
+
+uint GetPackedBitSize(uvec2 size, bool dual_plane, uint max_weight) {
+ uint n_vals = GetNumWeightValues(size, dual_plane);
+ return GetBitLength(n_vals, max_weight);
+}
+
+uint BitsBracket(uint bits, uint pos) {
+ return ((bits >> pos) & 1);
+}
+
+uint BitsOp(uint bits, uint start, uint end) {
+ if (start == end) {
+ return BitsBracket(bits, start);
+ } else if (start > end) {
+ uint t = start;
+ start = end;
+ end = t;
+ }
+
+ uint mask = (1 << (end - start + 1)) - 1;
+ return ((bits >> start) & mask);
+}
+
+void DecodeQuintBlock(uint num_bits) {
+ uint m[3];
+ uint q[3];
+ uint Q;
+ m[0] = StreamColorBits(num_bits);
+ Q = StreamColorBits(3);
+ m[1] = StreamColorBits(num_bits);
+ Q |= StreamColorBits(2) << 3;
+ m[2] = StreamColorBits(num_bits);
+ Q |= StreamColorBits(2) << 5;
+ if (BitsOp(Q, 1, 2) == 3 && BitsOp(Q, 5, 6) == 0) {
+ q[0] = 4;
+ q[1] = 4;
+ q[2] = (BitsBracket(Q, 0) << 2) | ((BitsBracket(Q, 4) & ~BitsBracket(Q, 0)) << 1) |
+ (BitsBracket(Q, 3) & ~BitsBracket(Q, 0));
+ } else {
+ uint C = 0;
+ if (BitsOp(Q, 1, 2) == 3) {
+ q[2] = 4;
+ C = (BitsOp(Q, 3, 4) << 3) | ((~BitsOp(Q, 5, 6) & 3) << 1) | BitsBracket(Q, 0);
+ } else {
+ q[2] = BitsOp(Q, 5, 6);
+ C = BitsOp(Q, 0, 4);
+ }
+ if (BitsOp(C, 0, 2) == 5) {
+ q[1] = 4;
+ q[0] = BitsOp(C, 3, 4);
+ } else {
+ q[1] = BitsOp(C, 3, 4);
+ q[0] = BitsOp(C, 0, 2);
+ }
+ }
+ for (uint i = 0; i < 3; i++) {
+ EncodingData val;
+ val.encoding = QUINT;
+ val.num_bits = num_bits;
+ val.bit_value = m[i];
+ val.quint_trit_value = q[i];
+ ResultEmplaceBack(val);
+ }
+}
+
+void DecodeTritBlock(uint num_bits) {
+ uint m[5];
+ uint t[5];
+ uint T;
+ m[0] = StreamColorBits(num_bits);
+ T = StreamColorBits(2);
+ m[1] = StreamColorBits(num_bits);
+ T |= StreamColorBits(2) << 2;
+ m[2] = StreamColorBits(num_bits);
+ T |= StreamColorBits(1) << 4;
+ m[3] = StreamColorBits(num_bits);
+ T |= StreamColorBits(2) << 5;
+ m[4] = StreamColorBits(num_bits);
+ T |= StreamColorBits(1) << 7;
+ uint C = 0;
+ if (BitsOp(T, 2, 4) == 7) {
+ C = (BitsOp(T, 5, 7) << 2) | BitsOp(T, 0, 1);
+ t[4] = 2;
+ t[3] = 2;
+ } else {
+ C = BitsOp(T, 0, 4);
+ if (BitsOp(T, 5, 6) == 3) {
+ t[4] = 2;
+ t[3] = BitsBracket(T, 7);
+ } else {
+ t[4] = BitsBracket(T, 7);
+ t[3] = BitsOp(T, 5, 6);
+ }
+ }
+ if (BitsOp(C, 0, 1) == 3) {
+ t[2] = 2;
+ t[1] = BitsBracket(C, 4);
+ t[0] = (BitsBracket(C, 3) << 1) | (BitsBracket(C, 2) & ~BitsBracket(C, 3));
+ } else if (BitsOp(C, 2, 3) == 3) {
+ t[2] = 2;
+ t[1] = 2;
+ t[0] = BitsOp(C, 0, 1);
+ } else {
+ t[2] = BitsBracket(C, 4);
+ t[1] = BitsOp(C, 2, 3);
+ t[0] = (BitsBracket(C, 1) << 1) | (BitsBracket(C, 0) & ~BitsBracket(C, 1));
+ }
+ for (uint i = 0; i < 5; i++) {
+ EncodingData val;
+ val.encoding = TRIT;
+ val.num_bits = num_bits;
+ val.bit_value = m[i];
+ val.quint_trit_value = t[i];
+ ResultEmplaceBack(val);
+ }
+}
+
+void DecodeIntegerSequence(uint max_range, uint num_values) {
+ EncodingData val = encoding_values[max_range];
+ uint vals_decoded = 0;
+ while (vals_decoded < num_values) {
+ switch (val.encoding) {
+ case QUINT:
+ DecodeQuintBlock(val.num_bits);
+ vals_decoded += 3;
+ break;
+ case TRIT:
+ DecodeTritBlock(val.num_bits);
+ vals_decoded += 5;
+ break;
+ case JUST_BITS:
+ val.bit_value = StreamColorBits(val.num_bits);
+ ResultEmplaceBack(val);
+ vals_decoded++;
+ break;
+ }
+ }
+}
+
+void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits) {
+ uint num_values = 0;
+ for (uint i = 0; i < num_partitions; i++) {
+ num_values += ((modes[i] >> 2) + 1) << 1;
+ }
+ int range = 256;
+ while (--range > 0) {
+ EncodingData val = encoding_values[range];
+ uint bit_length = GetBitLength(num_values, range);
+ if (bit_length <= color_data_bits) {
+ while (--range > 0) {
+ EncodingData newval = encoding_values[range];
+ if (newval.encoding != val.encoding && newval.num_bits != val.num_bits) {
+ break;
+ }
+ }
+ ++range;
+ break;
+ }
+ }
+ DecodeIntegerSequence(range, num_values);
+ uint out_index = 0;
+ for (int itr = 0; itr < result_index; ++itr) {
+ if (out_index >= num_values) {
+ break;
+ }
+ EncodingData val = result_vector[itr];
+ uint bitlen = val.num_bits;
+ uint bitval = val.bit_value;
+ uint A = 0, B = 0, C = 0, D = 0;
+ A = ReplicateBitTo9((bitval & 1));
+ switch (val.encoding) {
+ case JUST_BITS:
+ color_values[out_index++] = FastReplicateTo8(bitval, bitlen);
+ break;
+ case TRIT: {
+ D = val.quint_trit_value;
+ switch (bitlen) {
+ case 1:
+ C = 204;
+ break;
+ case 2: {
+ C = 93;
+ uint b = (bitval >> 1) & 1;
+ B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
+ break;
+ }
+ case 3: {
+ C = 44;
+ uint cb = (bitval >> 1) & 3;
+ B = (cb << 7) | (cb << 2) | cb;
+ break;
+ }
+ case 4: {
+ C = 22;
+ uint dcb = (bitval >> 1) & 7;
+ B = (dcb << 6) | dcb;
+ break;
+ }
+ case 5: {
+ C = 11;
+ uint edcb = (bitval >> 1) & 0xF;
+ B = (edcb << 5) | (edcb >> 2);
+ break;
+ }
+ case 6: {
+ C = 5;
+ uint fedcb = (bitval >> 1) & 0x1F;
+ B = (fedcb << 4) | (fedcb >> 4);
+ break;
+ }
+ }
+ break;
+ }
+ case QUINT: {
+ D = val.quint_trit_value;
+ switch (bitlen) {
+ case 1:
+ C = 113;
+ break;
+ case 2: {
+ C = 54;
+ uint b = (bitval >> 1) & 1;
+ B = (b << 8) | (b << 3) | (b << 2);
+ break;
+ }
+ case 3: {
+ C = 26;
+ uint cb = (bitval >> 1) & 3;
+ B = (cb << 7) | (cb << 1) | (cb >> 1);
+ break;
+ }
+ case 4: {
+ C = 13;
+ uint dcb = (bitval >> 1) & 7;
+ B = (dcb << 6) | (dcb >> 1);
+ break;
+ }
+ case 5: {
+ C = 6;
+ uint edcb = (bitval >> 1) & 0xF;
+ B = (edcb << 5) | (edcb >> 3);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (val.encoding != JUST_BITS) {
+ uint T = (D * C) + B;
+ T ^= A;
+ T = (A & 0x80) | (T >> 2);
+ color_values[out_index++] = T;
+ }
+ }
+}
+
+ivec2 BitTransferSigned(int a, int b) {
+ ivec2 transferred;
+ transferred.y = b >> 1;
+ transferred.y |= a & 0x80;
+ transferred.x = a >> 1;
+ transferred.x &= 0x3F;
+ if ((transferred.x & 0x20) > 0) {
+ transferred.x -= 0x40;
+ }
+ return transferred;
+}
+
+uvec4 ClampByte(ivec4 color) {
+ for (uint i = 0; i < 4; ++i) {
+ color[i] = (color[i] < 0) ? 0 : ((color[i] > 255) ? 255 : color[i]);
+ }
+ return uvec4(color);
+}
+
+ivec4 BlueContract(int a, int r, int g, int b) {
+ return ivec4(a, (r + b) >> 1, (g + b) >> 1, b);
+}
+
+void ComputeEndpoints(out uvec4 ep1, out uvec4 ep2, uint color_endpoint_mode) {
+#define READ_UINT_VALUES(N) \
+ uint v[N]; \
+ for (uint i = 0; i < N; i++) { \
+ v[i] = color_values[colvals_index++]; \
+ }
+
+#define READ_INT_VALUES(N) \
+ int v[N]; \
+ for (uint i = 0; i < N; i++) { \
+ v[i] = int(color_values[colvals_index++]); \
+ }
+
+ switch (color_endpoint_mode) {
+ case 0: {
+ READ_UINT_VALUES(2)
+ ep1 = uvec4(0xFF, v[0], v[0], v[0]);
+ ep2 = uvec4(0xFF, v[1], v[1], v[1]);
+ break;
+ }
+ case 1: {
+ READ_UINT_VALUES(2)
+ uint L0 = (v[0] >> 2) | (v[1] & 0xC0);
+ uint L1 = max(L0 + (v[1] & 0x3F), 0xFFU);
+ ep1 = uvec4(0xFF, L0, L0, L0);
+ ep2 = uvec4(0xFF, L1, L1, L1);
+ break;
+ }
+ case 4: {
+ READ_UINT_VALUES(4)
+ ep1 = uvec4(v[2], v[0], v[0], v[0]);
+ ep2 = uvec4(v[3], v[1], v[1], v[1]);
+ break;
+ }
+ case 5: {
+ READ_INT_VALUES(4)
+ ivec2 transferred = BitTransferSigned(v[1], v[0]);
+ v[1] = transferred.x;
+ v[0] = transferred.y;
+ transferred = BitTransferSigned(v[3], v[2]);
+ v[3] = transferred.x;
+ v[2] = transferred.y;
+ ep1 = ClampByte(ivec4(v[2], v[0], v[0], v[0]));
+ ep2 = ClampByte(ivec4(v[2] + v[3], v[0] + v[1], v[0] + v[1], v[0] + v[1]));
+ break;
+ }
+ case 6: {
+ READ_UINT_VALUES(4)
+ ep1 = uvec4(0xFF, (v[0] * v[3]) >> 8, (v[1] * v[3]) >> 8, (v[2] * v[3]) >> 8);
+ ep2 = uvec4(0xFF, v[0], v[1], v[2]);
+ break;
+ }
+ case 8: {
+ READ_UINT_VALUES(6)
+ if ((v[1] + v[3] + v[5]) >= (v[0] + v[2] + v[4])) {
+ ep1 = uvec4(0xFF, v[0], v[2], v[4]);
+ ep2 = uvec4(0xFF, v[1], v[3], v[5]);
+ } else {
+ ep1 = uvec4(BlueContract(0xFF, int(v[1]), int(v[3]), int(v[5])));
+ ep2 = uvec4(BlueContract(0xFF, int(v[0]), int(v[2]), int(v[4])));
+ }
+ break;
+ }
+ case 9: {
+ READ_INT_VALUES(6)
+ ivec2 transferred = BitTransferSigned(v[1], v[0]);
+ v[1] = transferred.x;
+ v[0] = transferred.y;
+ transferred = BitTransferSigned(v[3], v[2]);
+ v[3] = transferred.x;
+ v[2] = transferred.y;
+ transferred = BitTransferSigned(v[5], v[4]);
+ v[5] = transferred.x;
+ v[4] = transferred.y;
+ if ((v[1] + v[3] + v[5]) >= 0) {
+ ep1 = ClampByte(ivec4(0xFF, v[0], v[2], v[4]));
+ ep2 = ClampByte(ivec4(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]));
+ } else {
+ ep1 = ClampByte(BlueContract(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]));
+ ep2 = ClampByte(BlueContract(0xFF, v[0], v[2], v[4]));
+ }
+ break;
+ }
+ case 10: {
+ READ_UINT_VALUES(6)
+ ep1 = uvec4(v[4], (v[0] * v[3]) >> 8, (v[1] * v[3]) >> 8, (v[2] * v[3]) >> 8);
+ ep2 = uvec4(v[5], v[0], v[1], v[2]);
+ break;
+ }
+ case 12: {
+ READ_UINT_VALUES(8)
+ if ((v[1] + v[3] + v[5]) >= (v[0] + v[2] + v[4])) {
+ ep1 = uvec4(v[6], v[0], v[2], v[4]);
+ ep2 = uvec4(v[7], v[1], v[3], v[5]);
+ } else {
+ ep1 = uvec4(BlueContract(int(v[7]), int(v[1]), int(v[3]), int(v[5])));
+ ep2 = uvec4(BlueContract(int(v[6]), int(v[0]), int(v[2]), int(v[4])));
+ }
+ break;
+ }
+ case 13: {
+ READ_INT_VALUES(8)
+ ivec2 transferred = BitTransferSigned(v[1], v[0]);
+ v[1] = transferred.x;
+ v[0] = transferred.y;
+ transferred = BitTransferSigned(v[3], v[2]);
+ v[3] = transferred.x;
+ v[2] = transferred.y;
+
+ transferred = BitTransferSigned(v[5], v[4]);
+ v[5] = transferred.x;
+ v[4] = transferred.y;
+
+ transferred = BitTransferSigned(v[7], v[6]);
+ v[7] = transferred.x;
+ v[6] = transferred.y;
+
+ if ((v[1] + v[3] + v[5]) >= 0) {
+ ep1 = ClampByte(ivec4(v[6], v[0], v[2], v[4]));
+ ep2 = ClampByte(ivec4(v[7] + v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5]));
+ } else {
+ ep1 = ClampByte(BlueContract(v[6] + v[7], v[0] + v[1], v[2] + v[3], v[4] + v[5]));
+ ep2 = ClampByte(BlueContract(v[6], v[0], v[2], v[4]));
+ }
+ break;
+ }
+ default: {
+ // HDR mode, or more likely a bug computing the color_endpoint_mode
+ ep1 = uvec4(0xFF, 0xFF, 0, 0);
+ ep2 = uvec4(0xFF, 0xFF, 0, 0);
+ break;
+ }
+ }
+#undef READ_UINT_VALUES
+#undef READ_INT_VALUES
+}
+
+uint UnquantizeTexelWeight(EncodingData val) {
+ uint bitval = val.bit_value;
+ uint bitlen = val.num_bits;
+ uint A = ReplicateBitTo7((bitval & 1));
+ uint B = 0, C = 0, D = 0;
+ uint result = 0;
+ switch (val.encoding) {
+ case JUST_BITS:
+ result = FastReplicateTo6(bitval, bitlen);
+ break;
+ case TRIT: {
+ D = val.quint_trit_value;
+ switch (bitlen) {
+ case 0: {
+ uint results[3] = {0, 32, 63};
+ result = results[D];
+ break;
+ }
+ case 1: {
+ C = 50;
+ break;
+ }
+ case 2: {
+ C = 23;
+ uint b = (bitval >> 1) & 1;
+ B = (b << 6) | (b << 2) | b;
+ break;
+ }
+ case 3: {
+ C = 11;
+ uint cb = (bitval >> 1) & 3;
+ B = (cb << 5) | cb;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case QUINT: {
+ D = val.quint_trit_value;
+ switch (bitlen) {
+ case 0: {
+ uint results[5] = {0, 16, 32, 47, 63};
+ result = results[D];
+ break;
+ }
+ case 1: {
+ C = 28;
+ break;
+ }
+ case 2: {
+ C = 13;
+ uint b = (bitval >> 1) & 1;
+ B = (b << 6) | (b << 1);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (val.encoding != JUST_BITS && bitlen > 0) {
+ result = D * C + B;
+ result ^= A;
+ result = (A & 0x20) | (result >> 2);
+ }
+ if (result > 32) {
+ result += 1;
+ }
+ return result;
+}
+
+void UnquantizeTexelWeights(bool dual_plane, uvec2 size) {
+ uint weight_idx = 0;
+ uint unquantized[2][144];
+ uint area = size.x * size.y;
+ for (uint itr = 0; itr < texel_vector_index; itr++) {
+ unquantized[0][weight_idx] = UnquantizeTexelWeight(texel_vector[itr]);
+ if (dual_plane) {
+ ++itr;
+ unquantized[1][weight_idx] = UnquantizeTexelWeight(texel_vector[itr]);
+ if (itr == texel_vector_index) {
+ break;
+ }
+ }
+ if (++weight_idx >= (area))
+ break;
+ }
+
+ const uint Ds = uint((block_dims.x * 0.5f + 1024) / (block_dims.x - 1));
+ const uint Dt = uint((block_dims.y * 0.5f + 1024) / (block_dims.y - 1));
+ const uint k_plane_scale = dual_plane ? 2 : 1;
+ for (uint plane = 0; plane < k_plane_scale; plane++) {
+ for (uint t = 0; t < block_dims.y; t++) {
+ for (uint s = 0; s < block_dims.x; s++) {
+ uint cs = Ds * s;
+ uint ct = Dt * t;
+ uint gs = (cs * (size.x - 1) + 32) >> 6;
+ uint gt = (ct * (size.y - 1) + 32) >> 6;
+ uint js = gs >> 4;
+ uint fs = gs & 0xF;
+ uint jt = gt >> 4;
+ uint ft = gt & 0x0F;
+ uint w11 = (fs * ft + 8) >> 4;
+ uint w10 = ft - w11;
+ uint w01 = fs - w11;
+ uint w00 = 16 - fs - ft + w11;
+ uvec4 w = uvec4(w00, w01, w10, w11);
+ uint v0 = jt * size.x + js;
+
+ uvec4 p = uvec4(0);
+ if (v0 < area) {
+ p.x = unquantized[plane][v0];
+ }
+ if ((v0 + 1) < (area)) {
+ p.y = unquantized[plane][v0 + 1];
+ }
+ if ((v0 + size.x) < (area)) {
+ p.z = unquantized[plane][(v0 + size.x)];
+ }
+ if ((v0 + size.x + 1) < (area)) {
+ p.w = unquantized[plane][(v0 + size.x + 1)];
+ }
+ unquantized_texel_weights[plane][t * block_dims.x + s] = (uint(dot(p, w)) + 8) >> 4;
+ }
+ }
+ }
+}
+
+int FindLayout(uint mode) {
+ if ((mode & 3) != 0) {
+ if ((mode & 8) != 0) {
+ if ((mode & 4) != 0) {
+ if ((mode & 0x100) != 0) {
+ return 4;
+ }
+ return 3;
+ }
+ return 2;
+ }
+ if ((mode & 4) != 0) {
+ return 1;
+ }
+ return 0;
+ }
+ if ((mode & 0x100) != 0) {
+ if ((mode & 0x80) != 0) {
+ if ((mode & 0x20) != 0) {
+ return 8;
+ }
+ return 7;
+ }
+ return 9;
+ }
+ if ((mode & 0x80) != 0) {
+ return 6;
+ }
+ return 5;
+}
+
+TexelWeightParams DecodeBlockInfo(uint block_index) {
+ TexelWeightParams params = TexelWeightParams(uvec2(0), 0, false, false, false, false);
+ uint mode = StreamBits(11);
+ if ((mode & 0x1ff) == 0x1fc) {
+ if ((mode & 0x200) != 0) {
+ params.void_extent_hdr = true;
+ } else {
+ params.void_extent_ldr = true;
+ }
+ if ((mode & 0x400) == 0 || StreamBits(1) == 0) {
+ params.error_state = true;
+ }
+ return params;
+ }
+ if ((mode & 0xf) == 0) {
+ params.error_state = true;
+ return params;
+ }
+ if ((mode & 3) == 0 && (mode & 0x1c0) == 0x1c0) {
+ params.error_state = true;
+ return params;
+ }
+ uint A, B;
+ uint mode_layout = FindLayout(mode);
+ switch (mode_layout) {
+ case 0:
+ A = (mode >> 5) & 0x3;
+ B = (mode >> 7) & 0x3;
+ params.size = uvec2(B + 4, A + 2);
+ break;
+ case 1:
+ A = (mode >> 5) & 0x3;
+ B = (mode >> 7) & 0x3;
+ params.size = uvec2(B + 8, A + 2);
+ break;
+ case 2:
+ A = (mode >> 5) & 0x3;
+ B = (mode >> 7) & 0x3;
+ params.size = uvec2(A + 2, B + 8);
+ break;
+ case 3:
+ A = (mode >> 5) & 0x3;
+ B = (mode >> 7) & 0x1;
+ params.size = uvec2(A + 2, B + 6);
+ break;
+ case 4:
+ A = (mode >> 5) & 0x3;
+ B = (mode >> 7) & 0x1;
+ params.size = uvec2(B + 2, A + 2);
+ break;
+ case 5:
+ A = (mode >> 5) & 0x3;
+ params.size = uvec2(12, A + 2);
+ break;
+ case 6:
+ A = (mode >> 5) & 0x3;
+ params.size = uvec2(A + 2, 12);
+ break;
+ case 7:
+ params.size = uvec2(6, 10);
+ break;
+ case 8:
+ params.size = uvec2(10, 6);
+ break;
+ case 9:
+ A = (mode >> 5) & 0x3;
+ B = (mode >> 9) & 0x3;
+ params.size = uvec2(A + 6, B + 6);
+ break;
+ default:
+ params.error_state = true;
+ break;
+ }
+ params.dual_plane = (mode_layout != 9) && ((mode & 0x400) != 0);
+ uint weight_index = (mode & 0x10) != 0 ? 1 : 0;
+ if (mode_layout < 5) {
+ weight_index |= (mode & 0x3) << 1;
+ } else {
+ weight_index |= (mode & 0xc) >> 1;
+ }
+ weight_index -= 2;
+ if ((mode_layout != 9) && ((mode & 0x200) != 0)) {
+ const int max_weights[6] = int[6](9, 11, 15, 19, 23, 31);
+ params.max_weight = max_weights[weight_index];
+ } else {
+ const int max_weights[6] = int[6](1, 2, 3, 4, 5, 7);
+ params.max_weight = max_weights[weight_index];
+ }
+ return params;
+}
+
+void FillError(ivec3 coord) {
+ for (uint j = 0; j < block_dims.y; j++) {
+ for (uint i = 0; i < block_dims.x; i++) {
+ imageStore(dest_image, coord + ivec3(i, j, 0), vec4(1.0, 1.0, 0.0, 1.0));
+ }
+ }
+}
+
+void FillVoidExtentLDR(ivec3 coord) {
+ StreamBits(52);
+ uint r_u = StreamBits(16);
+ uint g_u = StreamBits(16);
+ uint b_u = StreamBits(16);
+ uint a_u = StreamBits(16);
+ float a = float(a_u) / 65535.0f;
+ float r = float(r_u) / 65535.0f;
+ float g = float(g_u) / 65535.0f;
+ float b = float(b_u) / 65535.0f;
+ for (uint j = 0; j < block_dims.y; j++) {
+ for (uint i = 0; i < block_dims.x; i++) {
+ imageStore(dest_image, coord + ivec3(i, j, 0), vec4(r, g, b, a));
+ }
+ }
+}
+
+void DecompressBlock(ivec3 coord, uint block_index) {
+ TexelWeightParams params = DecodeBlockInfo(block_index);
+ if (params.error_state) {
+ FillError(coord);
+ return;
+ }
+ if (params.void_extent_hdr) {
+ FillError(coord);
+ return;
+ }
+ if (params.void_extent_ldr) {
+ FillVoidExtentLDR(coord);
+ return;
+ }
+ if ((params.size.x > block_dims.x) || (params.size.y > block_dims.y)) {
+ FillError(coord);
+ return;
+ }
+ uint num_partitions = StreamBits(2) + 1;
+ if (num_partitions > 4 || (num_partitions == 4 && params.dual_plane)) {
+ FillError(coord);
+ return;
+ }
+ int plane_index = -1;
+ uint partition_index = 1;
+ uvec4 color_endpoint_mode = uvec4(0);
+ uint ced_pointer = 0;
+ uint base_cem = 0;
+ if (num_partitions == 1) {
+ color_endpoint_mode.x = StreamBits(4);
+ partition_index = 0;
+ } else {
+ partition_index = StreamBits(10);
+ base_cem = StreamBits(6);
+ }
+ uint base_mode = base_cem & 3;
+ uint weight_bits = GetPackedBitSize(params.size, params.dual_plane, params.max_weight);
+ uint remaining_bits = 128 - weight_bits - total_bitsread;
+ uint extra_cem_bits = 0;
+ if (base_mode > 0) {
+ switch (num_partitions) {
+ case 2:
+ extra_cem_bits += 2;
+ break;
+ case 3:
+ extra_cem_bits += 5;
+ break;
+ case 4:
+ extra_cem_bits += 8;
+ break;
+ default:
+ return;
+ }
+ }
+ remaining_bits -= extra_cem_bits;
+ uint plane_selector_bits = 0;
+ if (params.dual_plane) {
+ plane_selector_bits = 2;
+ }
+ remaining_bits -= plane_selector_bits;
+ if (remaining_bits > 128) {
+ // Bad data, more remaining bits than 4 bytes
+ // return early
+ return;
+ }
+ // Read color data...
+ uint color_data_bits = remaining_bits;
+ while (remaining_bits > 0) {
+ int nb = int(min(remaining_bits, 8U));
+ uint b = StreamBits(nb);
+ color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb));
+ ++ced_pointer;
+ remaining_bits -= nb;
+ }
+ plane_index = int(StreamBits(plane_selector_bits));
+ if (base_mode > 0) {
+ uint extra_cem = StreamBits(extra_cem_bits);
+ uint cem = (extra_cem << 6) | base_cem;
+ cem >>= 2;
+ uvec4 C = uvec4(0);
+ for (uint i = 0; i < num_partitions; i++) {
+ C[i] = (cem & 1);
+ cem >>= 1;
+ }
+ uvec4 M = uvec4(0);
+ for (uint i = 0; i < num_partitions; i++) {
+ M[i] = cem & 3;
+ cem >>= 2;
+ }
+ for (uint i = 0; i < num_partitions; i++) {
+ color_endpoint_mode[i] = base_mode;
+ if (C[i] == 0) {
+ --color_endpoint_mode[i];
+ }
+ color_endpoint_mode[i] <<= 2;
+ color_endpoint_mode[i] |= M[i];
+ }
+ } else if (num_partitions > 1) {
+ uint cem = base_cem >> 2;
+ for (uint i = 0; i < num_partitions; i++) {
+ color_endpoint_mode[i] = cem;
+ }
+ }
+ DecodeColorValues(color_endpoint_mode, num_partitions, color_data_bits);
+
+ uvec4 endpoints[4][2];
+ for (uint i = 0; i < num_partitions; i++) {
+ ComputeEndpoints(endpoints[i][0], endpoints[i][1], color_endpoint_mode[i]);
+ }
+
+ for (uint i = 0; i < 16; i++) {
+ texel_weight_data[i] = local_buff[i];
+ }
+ for (uint i = 0; i < 8; i++) {
+#define REVERSE_BYTE(b) ((b * 0x0802U & 0x22110U) | (b * 0x8020U & 0x88440U)) * 0x10101U >> 16
+ uint a = REVERSE_BYTE(texel_weight_data[i]);
+ uint b = REVERSE_BYTE(texel_weight_data[15 - i]);
+#undef REVERSE_BYTE
+ texel_weight_data[i] = uint(bitfieldExtract(b, 0, 8));
+ texel_weight_data[15 - i] = uint(bitfieldExtract(a, 0, 8));
+ }
+ uint clear_byte_start =
+ (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) >> 3) + 1;
+ texel_weight_data[clear_byte_start - 1] =
+ texel_weight_data[clear_byte_start - 1] &
+ uint(
+ ((1 << (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) % 8)) - 1));
+ for (uint i = 0; i < 16 - clear_byte_start; i++) {
+ texel_weight_data[clear_byte_start + i] = 0U;
+ }
+ texel_flag = true; // use texel "vector" and bit stream in integer decoding
+ DecodeIntegerSequence(params.max_weight, GetNumWeightValues(params.size, params.dual_plane));
+
+ UnquantizeTexelWeights(params.dual_plane, params.size);
+
+ for (uint j = 0; j < block_dims.y; j++) {
+ for (uint i = 0; i < block_dims.x; i++) {
+ uint local_partition = Select2DPartition(partition_index, i, j, num_partitions,
+ (block_dims.y * block_dims.x) < 32);
+ vec4 p;
+ uvec4 C0 = ReplicateByteTo16(endpoints[local_partition][0]);
+ uvec4 C1 = ReplicateByteTo16(endpoints[local_partition][1]);
+ uvec4 plane_vec = uvec4(0);
+ uvec4 weight_vec = uvec4(0);
+ for (uint c = 0; c < 4; c++) {
+ if (params.dual_plane && (((plane_index + 1) & 3) == c)) {
+ plane_vec[c] = 1;
+ }
+ weight_vec[c] = unquantized_texel_weights[plane_vec[c]][j * block_dims.x + i];
+ }
+ vec4 Cf = vec4((C0 * (uvec4(64) - weight_vec) + C1 * weight_vec + uvec4(32)) / 64);
+ p = (Cf / 65535.0);
+ imageStore(dest_image, coord + ivec3(i, j, 0), p.gbar);
+ }
+ }
+}
+
+void main() {
+ uvec3 pos = gl_GlobalInvocationID;
+ pos.x <<= bytes_per_block_log2;
+
+ // Read as soon as possible due to its latency
+ const uint swizzle = SwizzleOffset(pos.xy);
+
+ const uint block_y = pos.y >> GOB_SIZE_Y_SHIFT;
+
+ uint offset = 0;
+ offset += pos.z * layer_stride;
+ offset += (block_y >> block_height) * block_size;
+ offset += (block_y & block_height_mask) << GOB_SIZE_SHIFT;
+ offset += (pos.x >> GOB_SIZE_X_SHIFT) << x_shift;
+ offset += swizzle;
+
+ const ivec3 coord = ivec3(gl_GlobalInvocationID * uvec3(block_dims, 1));
+ uint block_index =
+ pos.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + pos.y * gl_WorkGroupSize.x + pos.x;
+
+ current_index = 0;
+ bitsread = 0;
+ for (int i = 0; i < 16; i++) {
+ local_buff[i] = ReadTexel(offset + i);
+ }
+ DecompressBlock(coord, block_index);
+}
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 @@
namespace HostShaders {
-constexpr std::string_view @CONTENTS_NAME@ = R"(@CONTENTS@)";
+constexpr std::string_view @CONTENTS_NAME@ = {
+@CONTENTS@
+};
} // 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 @@
#include <boost/container_hash/hash.hpp>
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/macro/macro.h"
#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 @@
#include <vector>
#include "common/assert.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
@@ -208,9 +208,9 @@ public:
private:
/// Flushes a memory range to guest memory and removes it from the cache.
void FlushAndRemoveRegion(VAddr addr, std::size_t size) {
- const u64 addr_begin = static_cast<u64>(addr);
- const u64 addr_end = addr_begin + static_cast<u64>(size);
- const auto in_range = [addr_begin, addr_end](CachedQuery& query) {
+ const u64 addr_begin = addr;
+ const u64 addr_end = addr_begin + size;
+ const auto in_range = [addr_begin, addr_end](const CachedQuery& query) {
const u64 cache_begin = query.GetCpuAddr();
const u64 cache_end = cache_begin + query.SizeInBytes();
return cache_begin < addr_end && addr_begin < cache_end;
@@ -230,8 +230,7 @@ private:
rasterizer.UpdatePagesCachedCount(query.GetCpuAddr(), query.SizeInBytes(), -1);
query.Flush();
}
- contents.erase(std::remove_if(std::begin(contents), std::end(contents), in_range),
- std::end(contents));
+ std::erase_if(contents, in_range);
}
}
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 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/frontend/emu_window.h"
-#include "core/settings.h"
#include "video_core/renderer_base.h"
namespace 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 @@
#include "common/logging/log.h"
#include "common/scope_exit.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
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 @@
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/memory.h"
-#include "core/settings.h"
#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/maxwell_3d.h"
#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 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
+#include "common/settings.h"
#include "common/zstd_compression.h"
#include "core/core.h"
#include "core/hle/kernel/process.h"
-#include "core/settings.h"
#include "video_core/engines/shader_type.h"
#include "video_core/renderer_opengl/gl_shader_cache.h"
#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
[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
const VideoCommon::ImageInfo& info) {
- // Disable accelerated uploads for now as they don't implement swizzled uploads
+ return !runtime.HasNativeASTC() && IsPixelFormatASTC(info.format);
+ // Disable other accelerated uploads for now as they don't implement swizzled uploads
return false;
switch (info.type) {
case ImageType::e2D:
@@ -569,7 +570,11 @@ void TextureCacheRuntime::AccelerateImageUpload(Image& image, const ImageBufferM
std::span<const SwizzleParameters> swizzles) {
switch (image.info.type) {
case ImageType::e2D:
- return util_shaders.BlockLinearUpload2D(image, map, swizzles);
+ if (IsPixelFormatASTC(image.info.format)) {
+ return util_shaders.ASTCDecode(image, map, swizzles);
+ } else {
+ return util_shaders.BlockLinearUpload2D(image, map, swizzles);
+ }
case ImageType::e3D:
return util_shaders.BlockLinearUpload3D(image, map, swizzles);
case ImageType::Linear:
@@ -599,6 +604,10 @@ FormatProperties TextureCacheRuntime::FormatInfo(ImageType type, GLenum internal
}
}
+bool TextureCacheRuntime::HasNativeASTC() const noexcept {
+ return device.HasASTC();
+}
+
TextureCacheRuntime::StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_)
: storage_flags{storage_flags_}, map_flags{map_flags_} {}
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:
return has_broken_texture_view_formats;
}
+ bool HasNativeASTC() const noexcept;
+
private:
struct StagingBuffers {
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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
+#include "common/settings.h"
#include "common/telemetry.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/memory.h"
#include "core/perf_stats.h"
-#include "core/settings.h"
#include "core/telemetry_session.h"
#include "video_core/host_shaders/opengl_present_frag.h"
#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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <bit>
#include <span>
#include <string_view>
@@ -11,6 +10,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/div_ceil.h"
+#include "video_core/host_shaders/astc_decoder_comp.h"
#include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h"
#include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h"
#include "video_core/host_shaders/opengl_copy_bc4_comp.h"
@@ -20,16 +20,18 @@
#include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_texture_cache.h"
#include "video_core/renderer_opengl/util_shaders.h"
-#include "video_core/surface.h"
#include "video_core/texture_cache/accelerated_swizzle.h"
#include "video_core/texture_cache/types.h"
#include "video_core/texture_cache/util.h"
+#include "video_core/textures/astc.h"
#include "video_core/textures/decoders.h"
namespace OpenGL {
using namespace HostShaders;
+using namespace Tegra::Texture::ASTC;
+using VideoCommon::Extent2D;
using VideoCommon::Extent3D;
using VideoCommon::ImageCopy;
using VideoCommon::ImageType;
@@ -57,7 +59,7 @@ size_t NumPixelsInCopy(const VideoCommon::ImageCopy& copy) {
} // Anonymous namespace
UtilShaders::UtilShaders(ProgramManager& program_manager_)
- : program_manager{program_manager_},
+ : program_manager{program_manager_}, astc_decoder_program(MakeProgram(ASTC_DECODER_COMP)),
block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)),
block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)),
pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)),
@@ -65,11 +67,79 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) {
const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
swizzle_table_buffer.Create();
+ astc_buffer.Create();
glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
+ glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_BUFFER_DATA), &ASTC_BUFFER_DATA, 0);
}
UtilShaders::~UtilShaders() = default;
+void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
+ std::span<const VideoCommon::SwizzleParameters> swizzles) {
+ static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
+ static constexpr GLuint BINDING_INPUT_BUFFER = 1;
+ static constexpr GLuint BINDING_ENC_BUFFER = 2;
+
+ static constexpr GLuint BINDING_6_TO_8_BUFFER = 3;
+ static constexpr GLuint BINDING_7_TO_8_BUFFER = 4;
+ static constexpr GLuint BINDING_8_TO_8_BUFFER = 5;
+ static constexpr GLuint BINDING_BYTE_TO_16_BUFFER = 6;
+
+ static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
+
+ const Extent2D tile_size{
+ .width = VideoCore::Surface::DefaultBlockWidth(image.info.format),
+ .height = VideoCore::Surface::DefaultBlockHeight(image.info.format),
+ };
+ program_manager.BindHostCompute(astc_decoder_program.handle);
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle,
+ offsetof(AstcBufferData, encoding_values),
+ sizeof(AstcBufferData::encoding_values));
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_6_TO_8_BUFFER, astc_buffer.handle,
+ offsetof(AstcBufferData, replicate_6_to_8),
+ sizeof(AstcBufferData::replicate_6_to_8));
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_7_TO_8_BUFFER, astc_buffer.handle,
+ offsetof(AstcBufferData, replicate_7_to_8),
+ sizeof(AstcBufferData::replicate_7_to_8));
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_8_TO_8_BUFFER, astc_buffer.handle,
+ offsetof(AstcBufferData, replicate_8_to_8),
+ sizeof(AstcBufferData::replicate_8_to_8));
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_BYTE_TO_16_BUFFER, astc_buffer.handle,
+ offsetof(AstcBufferData, replicate_byte_to_16),
+ sizeof(AstcBufferData::replicate_byte_to_16));
+
+ glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
+ glUniform2ui(1, tile_size.width, tile_size.height);
+ // Ensure buffer data is valid before dispatching
+ glFlush();
+ for (const SwizzleParameters& swizzle : swizzles) {
+ const size_t input_offset = swizzle.buffer_offset + map.offset;
+ const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
+ const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
+
+ const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
+ ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
+ ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
+
+ glUniform1ui(2, params.bytes_per_block_log2);
+ glUniform1ui(3, params.layer_stride);
+ glUniform1ui(4, params.block_size);
+ glUniform1ui(5, params.x_shift);
+ glUniform1ui(6, params.block_height);
+ glUniform1ui(7, params.block_height_mask);
+
+ glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
+ GL_WRITE_ONLY, GL_RGBA8);
+ // ASTC texture data
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset,
+ image.guest_size_bytes - swizzle.buffer_offset);
+
+ glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
+ }
+ program_manager.RestoreGuestCompute();
+}
+
void UtilShaders::BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
std::span<const SwizzleParameters> swizzles) {
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:
explicit UtilShaders(ProgramManager& program_manager);
~UtilShaders();
+ void ASTCDecode(Image& image, const ImageBufferMap& map,
+ std::span<const VideoCommon::SwizzleParameters> swizzles);
+
void BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
@@ -59,7 +62,9 @@ private:
ProgramManager& program_manager;
OGLBuffer swizzle_table_buffer;
+ OGLBuffer astc_buffer;
+ OGLProgram astc_decoder_program;
OGLProgram block_linear_unswizzle_2d_program;
OGLProgram block_linear_unswizzle_3d_program;
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 {
{VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT
{VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM
{VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT
- {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB
+ {VK_FORMAT_A8B8G8R8_SRGB_PACK32, Attachable}, // A8B8G8R8_SRGB
{VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // R8G8_UNORM
{VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // R8G8_SNORM
{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 @@
#include <fmt/format.h>
#include "common/logging/log.h"
+#include "common/settings.h"
#include "common/telemetry.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
-#include "core/settings.h"
#include "core/telemetry_session.h"
#include "video_core/gpu.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h"
@@ -143,7 +143,10 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
scheduler.WaitWorker();
- swapchain.AcquireNextImage();
+ while (!swapchain.AcquireNextImage()) {
+ swapchain.Create(layout.width, layout.height, is_srgb);
+ blit_screen.Recreate();
+ }
const VkSemaphore render_semaphore = blit_screen.Draw(*framebuffer, use_accelerated);
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
u32 stride) {
if (device.IsExtExtendedDynamicStateSupported()) {
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
- const VkDeviceSize vk_offset = offset;
+ const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
const VkDeviceSize vk_stride = stride;
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 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/div_ceil.h"
+#include "video_core/host_shaders/astc_decoder_comp_spv.h"
#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
#include "video_core/renderer_vulkan/vk_compute_pass.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
+#include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
+#include "video_core/texture_cache/accelerated_swizzle.h"
+#include "video_core/texture_cache/types.h"
+#include "video_core/textures/astc.h"
+#include "video_core/textures/decoders.h"
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
+
+using Tegra::Texture::SWIZZLE_TABLE;
+using Tegra::Texture::ASTC::EncodingsValues;
+using namespace Tegra::Texture::ASTC;
+
namespace {
+
+constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
+constexpr u32 ASTC_BINDING_ENC_BUFFER = 1;
+constexpr u32 ASTC_BINDING_6_TO_8_BUFFER = 2;
+constexpr u32 ASTC_BINDING_7_TO_8_BUFFER = 3;
+constexpr u32 ASTC_BINDING_8_TO_8_BUFFER = 4;
+constexpr u32 ASTC_BINDING_BYTE_TO_16_BUFFER = 5;
+constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 6;
+constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 7;
+
VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
return {
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
@@ -50,6 +71,67 @@ std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBinding
}};
}
+std::array<VkDescriptorSetLayoutBinding, 8> BuildASTCDescriptorSetBindings() {
+ return {{
+ {
+ .binding = ASTC_BINDING_INPUT_BUFFER,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ {
+ .binding = ASTC_BINDING_ENC_BUFFER,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ {
+ .binding = ASTC_BINDING_6_TO_8_BUFFER,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ {
+ .binding = ASTC_BINDING_7_TO_8_BUFFER,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ {
+ .binding = ASTC_BINDING_8_TO_8_BUFFER,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ {
+ .binding = ASTC_BINDING_BYTE_TO_16_BUFFER,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ {
+ .binding = ASTC_BINDING_SWIZZLE_BUFFER,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ {
+ .binding = ASTC_BINDING_OUTPUT_IMAGE,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ }};
+}
+
VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
return {
.dstBinding = 0,
@@ -61,6 +143,94 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
};
}
+std::array<VkDescriptorUpdateTemplateEntryKHR, 8> BuildASTCPassDescriptorUpdateTemplateEntry() {
+ return {{
+ {
+ .dstBinding = ASTC_BINDING_INPUT_BUFFER,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .offset = ASTC_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry),
+ .stride = sizeof(DescriptorUpdateEntry),
+ },
+ {
+ .dstBinding = ASTC_BINDING_ENC_BUFFER,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .offset = ASTC_BINDING_ENC_BUFFER * sizeof(DescriptorUpdateEntry),
+ .stride = sizeof(DescriptorUpdateEntry),
+ },
+ {
+ .dstBinding = ASTC_BINDING_6_TO_8_BUFFER,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .offset = ASTC_BINDING_6_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
+ .stride = sizeof(DescriptorUpdateEntry),
+ },
+ {
+ .dstBinding = ASTC_BINDING_7_TO_8_BUFFER,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .offset = ASTC_BINDING_7_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
+ .stride = sizeof(DescriptorUpdateEntry),
+ },
+ {
+ .dstBinding = ASTC_BINDING_8_TO_8_BUFFER,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .offset = ASTC_BINDING_8_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
+ .stride = sizeof(DescriptorUpdateEntry),
+ },
+ {
+ .dstBinding = ASTC_BINDING_BYTE_TO_16_BUFFER,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .offset = ASTC_BINDING_BYTE_TO_16_BUFFER * sizeof(DescriptorUpdateEntry),
+ .stride = sizeof(DescriptorUpdateEntry),
+ },
+ {
+ .dstBinding = ASTC_BINDING_SWIZZLE_BUFFER,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .offset = ASTC_BINDING_SWIZZLE_BUFFER * sizeof(DescriptorUpdateEntry),
+ .stride = sizeof(DescriptorUpdateEntry),
+ },
+ {
+ .dstBinding = ASTC_BINDING_OUTPUT_IMAGE,
+ .dstArrayElement = 0,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .offset = ASTC_BINDING_OUTPUT_IMAGE * sizeof(DescriptorUpdateEntry),
+ .stride = sizeof(DescriptorUpdateEntry),
+ },
+ }};
+}
+
+struct AstcPushConstants {
+ std::array<u32, 2> blocks_dims;
+ u32 bytes_per_block_log2;
+ u32 layer_stride;
+ u32 block_size;
+ u32 x_shift;
+ u32 block_height;
+ u32 block_height_mask;
+};
+
+struct AstcBufferData {
+ decltype(SWIZZLE_TABLE) swizzle_table_buffer = SWIZZLE_TABLE;
+ decltype(EncodingsValues) encoding_values = EncodingsValues;
+ decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
+ decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
+ decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
+ decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
+} constexpr ASTC_BUFFER_DATA;
+
} // Anonymous namespace
VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool,
@@ -238,4 +408,167 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
return {staging.buffer, staging.offset};
}
+ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
+ VKDescriptorPool& descriptor_pool_,
+ StagingBufferPool& staging_buffer_pool_,
+ VKUpdateDescriptorQueue& update_descriptor_queue_,
+ MemoryAllocator& memory_allocator_)
+ : VKComputePass(device_, descriptor_pool_, BuildASTCDescriptorSetBindings(),
+ BuildASTCPassDescriptorUpdateTemplateEntry(),
+ BuildComputePushConstantRange(sizeof(AstcPushConstants)),
+ ASTC_DECODER_COMP_SPV),
+ device{device_}, scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
+ update_descriptor_queue{update_descriptor_queue_}, memory_allocator{memory_allocator_} {}
+
+ASTCDecoderPass::~ASTCDecoderPass() = default;
+
+void ASTCDecoderPass::MakeDataBuffer() {
+ constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_BUFFER_DATA) + sizeof(SWIZZLE_TABLE);
+ data_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .size = TOTAL_BUFFER_SIZE,
+ .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .queueFamilyIndexCount = 0,
+ .pQueueFamilyIndices = nullptr,
+ });
+ data_buffer_commit = memory_allocator.Commit(data_buffer, MemoryUsage::Upload);
+
+ const auto staging_ref = staging_buffer_pool.Request(TOTAL_BUFFER_SIZE, MemoryUsage::Upload);
+ std::memcpy(staging_ref.mapped_span.data(), &ASTC_BUFFER_DATA, sizeof(ASTC_BUFFER_DATA));
+ // Tack on the swizzle table at the end of the buffer
+ std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_BUFFER_DATA), &SWIZZLE_TABLE,
+ sizeof(SWIZZLE_TABLE));
+
+ scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
+ TOTAL_BUFFER_SIZE](vk::CommandBuffer cmdbuf) {
+ cmdbuf.CopyBuffer(src, dst,
+ VkBufferCopy{
+ .srcOffset = offset,
+ .dstOffset = 0,
+ .size = TOTAL_BUFFER_SIZE,
+ });
+ cmdbuf.PipelineBarrier(
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
+ VkMemoryBarrier{
+ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = 0,
+ .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
+ });
+ });
+}
+
+void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
+ std::span<const VideoCommon::SwizzleParameters> swizzles) {
+ using namespace VideoCommon::Accelerated;
+ const std::array<u32, 2> block_dims{
+ VideoCore::Surface::DefaultBlockWidth(image.info.format),
+ VideoCore::Surface::DefaultBlockHeight(image.info.format),
+ };
+ scheduler.RequestOutsideRenderPassOperationContext();
+ if (!data_buffer) {
+ MakeDataBuffer();
+ }
+ const VkPipeline vk_pipeline = *pipeline;
+ const VkImageAspectFlags aspect_mask = image.AspectMask();
+ const VkImage vk_image = image.Handle();
+ const bool is_initialized = image.ExchangeInitialization();
+ scheduler.Record(
+ [vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
+ const VkImageMemoryBarrier image_barrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
+ .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = vk_image,
+ .subresourceRange{
+ .aspectMask = aspect_mask,
+ .baseMipLevel = 0,
+ .levelCount = VK_REMAINING_MIP_LEVELS,
+ .baseArrayLayer = 0,
+ .layerCount = VK_REMAINING_ARRAY_LAYERS,
+ },
+ };
+ cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : 0,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
+ cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
+ });
+ for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
+ const size_t input_offset = swizzle.buffer_offset + map.offset;
+ const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
+ const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
+ const u32 num_dispatches_z = image.info.resources.layers;
+
+ update_descriptor_queue.Acquire();
+ update_descriptor_queue.AddBuffer(map.buffer, input_offset,
+ image.guest_size_bytes - swizzle.buffer_offset);
+ update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, encoding_values),
+ sizeof(AstcBufferData::encoding_values));
+ update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_6_to_8),
+ sizeof(AstcBufferData::replicate_6_to_8));
+ update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_7_to_8),
+ sizeof(AstcBufferData::replicate_7_to_8));
+ update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_8_to_8),
+ sizeof(AstcBufferData::replicate_8_to_8));
+ update_descriptor_queue.AddBuffer(*data_buffer,
+ offsetof(AstcBufferData, replicate_byte_to_16),
+ sizeof(AstcBufferData::replicate_byte_to_16));
+ update_descriptor_queue.AddBuffer(*data_buffer, sizeof(AstcBufferData),
+ sizeof(SWIZZLE_TABLE));
+ update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
+
+ const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
+ const VkPipelineLayout vk_layout = *layout;
+
+ // To unswizzle the ASTC data
+ const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
+ ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
+ ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
+ scheduler.Record([vk_layout, num_dispatches_x, num_dispatches_y, num_dispatches_z,
+ block_dims, params, set](vk::CommandBuffer cmdbuf) {
+ const AstcPushConstants uniforms{
+ .blocks_dims = block_dims,
+ .bytes_per_block_log2 = params.bytes_per_block_log2,
+ .layer_stride = params.layer_stride,
+ .block_size = params.block_size,
+ .x_shift = params.x_shift,
+ .block_height = params.block_height,
+ .block_height_mask = params.block_height_mask,
+ };
+ cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, vk_layout, 0, set, {});
+ cmdbuf.PushConstants(vk_layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
+ cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, num_dispatches_z);
+ });
+ }
+ scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
+ const VkImageMemoryBarrier image_barrier{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = vk_image,
+ .subresourceRange{
+ .aspectMask = aspect_mask,
+ .baseMipLevel = 0,
+ .levelCount = VK_REMAINING_MIP_LEVELS,
+ .baseArrayLayer = 0,
+ .layerCount = VK_REMAINING_ARRAY_LAYERS,
+ },
+ };
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, image_barrier);
+ });
+}
+
} // 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 @@
#include "common/common_types.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
+#include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
+namespace VideoCommon {
+struct SwizzleParameters;
+}
+
namespace Vulkan {
class Device;
class StagingBufferPool;
class VKScheduler;
class VKUpdateDescriptorQueue;
+class Image;
+struct StagingBufferRef;
class VKComputePass {
public:
@@ -77,4 +84,29 @@ private:
VKUpdateDescriptorQueue& update_descriptor_queue;
};
+class ASTCDecoderPass final : public VKComputePass {
+public:
+ explicit ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
+ VKDescriptorPool& descriptor_pool_,
+ StagingBufferPool& staging_buffer_pool_,
+ VKUpdateDescriptorQueue& update_descriptor_queue_,
+ MemoryAllocator& memory_allocator_);
+ ~ASTCDecoderPass();
+
+ void Assemble(Image& image, const StagingBufferRef& map,
+ std::span<const VideoCommon::SwizzleParameters> swizzles);
+
+private:
+ void MakeDataBuffer();
+
+ const Device& device;
+ VKScheduler& scheduler;
+ StagingBufferPool& staging_buffer_pool;
+ VKUpdateDescriptorQueue& update_descriptor_queue;
+ MemoryAllocator& memory_allocator;
+
+ vk::Buffer data_buffer;
+ MemoryCommit data_buffer_commit;
+};
+
} // 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 @@
#include <atomic>
#include <chrono>
-#include "core/settings.h"
+#include "common/settings.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/vulkan_common/vulkan_device.h"
#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:
}
/// Returns true when a tick has been hit by the GPU.
- [[nodiscard]] bool IsFree(u64 tick) {
- return gpu_tick.load(std::memory_order_relaxed) >= tick;
+ [[nodiscard]] bool IsFree(u64 tick) const noexcept {
+ return KnownGpuTick() >= tick;
}
/// 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 @@
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_vulkan/blit_image.h"
@@ -241,7 +241,10 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
update_descriptor_queue(device, scheduler),
blit_image(device, scheduler, state_tracker, descriptor_pool),
- texture_cache_runtime{device, scheduler, memory_allocator, staging_pool, blit_image},
+ astc_decoder_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue,
+ memory_allocator),
+ texture_cache_runtime{device, scheduler, memory_allocator,
+ staging_pool, blit_image, astc_decoder_pass},
texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory),
buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
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:
VKDescriptorPool descriptor_pool;
VKUpdateDescriptorQueue update_descriptor_queue;
BlitImageHelper blit_image;
+ ASTCDecoderPass astc_decoder_pass;
GraphicsPipelineCacheKey graphics_key;
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) {
resource_ticks.resize(image_count);
}
-void VKSwapchain::AcquireNextImage() {
- device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(),
- *present_semaphores[frame_index], {}, &image_index);
+bool VKSwapchain::AcquireNextImage() {
+ const VkResult result =
+ device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(),
+ *present_semaphores[frame_index], {}, &image_index);
scheduler.Wait(resource_ticks[image_index]);
+ return result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR;
}
bool 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:
void Create(u32 width, u32 height, bool srgb);
/// Acquires the next image in the swapchain, waits as needed.
- void AcquireNextImage();
+ bool AcquireNextImage();
/// Presents the rendered image to the swapchain. Returns true when the swapchains had to be
/// 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 @@
#include <span>
#include <vector>
+#include "common/bit_cast.h"
+
#include "video_core/engines/fermi_2d.h"
#include "video_core/renderer_vulkan/blit_image.h"
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
+#include "video_core/renderer_vulkan/vk_compute_pass.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -807,7 +810,7 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
}
if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
- flags |= VideoCommon::ImageFlagBits::Converted;
+ flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
}
if (runtime.device.HasDebuggingToolAttached()) {
if (image) {
@@ -816,6 +819,38 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
}
}
+ static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
+ .pNext = nullptr,
+ .usage = VK_IMAGE_USAGE_STORAGE_BIT,
+ };
+ if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
+ const auto& device = runtime.device.GetLogical();
+ storage_image_views.reserve(info.resources.levels);
+ for (s32 level = 0; level < info.resources.levels; ++level) {
+ storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .pNext = &storage_image_view_usage_create_info,
+ .flags = 0,
+ .image = *image,
+ .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+ .format = VK_FORMAT_A8B8G8R8_UNORM_PACK32,
+ .components{
+ .r = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .g = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .b = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .a = VK_COMPONENT_SWIZZLE_IDENTITY,
+ },
+ .subresourceRange{
+ .aspectMask = aspect_mask,
+ .baseMipLevel = static_cast<u32>(level),
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = VK_REMAINING_ARRAY_LAYERS,
+ },
+ }));
+ }
+ }
}
void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
@@ -918,7 +953,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
}
}
const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
- const VkFormat vk_format = format_info.format;
const VkImageViewUsageCreateInfo image_view_usage{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
.pNext = nullptr,
@@ -930,7 +964,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.flags = 0,
.image = image.Handle(),
.viewType = VkImageViewType{},
- .format = vk_format,
+ .format = format_info.format,
.components{
.r = ComponentSwizzle(swizzle[0]),
.g = ComponentSwizzle(swizzle[1]),
@@ -982,7 +1016,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.pNext = nullptr,
.flags = 0,
.buffer = image.Buffer(),
- .format = vk_format,
+ .format = format_info.format,
.offset = 0, // TODO: Redesign buffer cache to support this
.range = image.guest_size_bytes,
});
@@ -1030,14 +1064,13 @@ vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) {
Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) {
const auto& device = runtime.device;
const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported();
- const std::array<float, 4> color = tsc.BorderColor();
- // C++20 bit_cast
- VkClearColorValue border_color;
- std::memcpy(&border_color, &color, sizeof(color));
+ const auto color = tsc.BorderColor();
+
const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
.pNext = nullptr,
- .customBorderColor = border_color,
+ // TODO: Make use of std::bit_cast once libc++ supports it.
+ .customBorderColor = Common::BitCast<VkClearColorValue>(color),
.format = VK_FORMAT_UNDEFINED,
};
const void* pnext = nullptr;
@@ -1167,4 +1200,13 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
}
}
+void TextureCacheRuntime::AccelerateImageUpload(
+ Image& image, const StagingBufferRef& map,
+ std::span<const VideoCommon::SwizzleParameters> swizzles) {
+ if (IsPixelFormatASTC(image.info.format)) {
+ return astc_decoder_pass.Assemble(image, map, swizzles);
+ }
+ UNREACHABLE();
+}
+
} // 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;
using VideoCommon::RenderTargets;
using VideoCore::Surface::PixelFormat;
+class ASTCDecoderPass;
class BlitImageHelper;
class Device;
class Image;
@@ -60,6 +61,7 @@ struct TextureCacheRuntime {
MemoryAllocator& memory_allocator;
StagingBufferPool& staging_buffer_pool;
BlitImageHelper& blit_image_helper;
+ ASTCDecoderPass& astc_decoder_pass;
std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache{};
void Finish();
@@ -83,9 +85,7 @@ struct TextureCacheRuntime {
}
void AccelerateImageUpload(Image&, const StagingBufferRef&,
- std::span<const VideoCommon::SwizzleParameters>) {
- UNREACHABLE();
- }
+ std::span<const VideoCommon::SwizzleParameters>);
void InsertUploadMemoryBarrier() {}
@@ -121,15 +121,26 @@ public:
return *buffer;
}
- [[nodiscard]] VkImageCreateFlags AspectMask() const noexcept {
+ [[nodiscard]] VkImageAspectFlags AspectMask() const noexcept {
return aspect_mask;
}
+ [[nodiscard]] VkImageView StorageImageView(s32 level) const noexcept {
+ return *storage_image_views[level];
+ }
+
+ /// Returns true when the image is already initialized and mark it as initialized
+ [[nodiscard]] bool ExchangeInitialization() noexcept {
+ return std::exchange(initialized, true);
+ }
+
private:
VKScheduler* scheduler;
vk::Image image;
vk::Buffer buffer;
MemoryCommit commit;
+ vk::ImageView image_view;
+ std::vector<vk::ImageView> storage_image_views;
VkImageAspectFlags aspect_mask = 0;
bool initialized = false;
};
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 @@
namespace VideoCommon::Accelerated {
struct BlockLinearSwizzle2DParams {
- std::array<u32, 3> origin;
- std::array<s32, 3> destination;
+ alignas(16) std::array<u32, 3> origin;
+ alignas(16) std::array<s32, 3> destination;
u32 bytes_per_block_log2;
u32 layer_stride;
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 @@
#include <algorithm>
#include "common/assert.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "video_core/compatible_formats.h"
#include "video_core/surface.h"
#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 @@
#include "video_core/texture_cache/formatter.h"
#include "video_core/texture_cache/samples_helper.h"
#include "video_core/texture_cache/util.h"
-#include "video_core/textures/astc.h"
#include "video_core/textures/decoders.h"
namespace VideoCommon {
@@ -269,16 +268,19 @@ template <u32 GOB_EXTENT>
return num_tiles << shift;
}
-[[nodiscard]] constexpr std::array<u32, MAX_MIP_LEVELS> CalculateLevelSizes(const LevelInfo& info,
- u32 num_levels) {
+[[nodiscard]] constexpr LevelArray CalculateLevelSizes(const LevelInfo& info, u32 num_levels) {
ASSERT(num_levels <= MAX_MIP_LEVELS);
- std::array<u32, MAX_MIP_LEVELS> sizes{};
+ LevelArray sizes{};
for (u32 level = 0; level < num_levels; ++level) {
sizes[level] = CalculateLevelSize(info, level);
}
return sizes;
}
+[[nodiscard]] u32 CalculateLevelBytes(const LevelArray& sizes, u32 num_levels) {
+ return std::reduce(sizes.begin(), sizes.begin() + num_levels, 0U);
+}
+
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block,
u32 num_samples, u32 tile_width_spacing) {
const auto [samples_x, samples_y] = Samples(num_samples);
@@ -567,10 +569,10 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr
const u32 num_levels = info.resources.levels;
const std::array sizes = CalculateLevelSizes(level_info, num_levels);
- size_t guest_offset = std::reduce(sizes.begin(), sizes.begin() + level, 0);
+ size_t guest_offset = CalculateLevelBytes(sizes, level);
const size_t layer_stride =
- AlignLayerSize(std::reduce(sizes.begin(), sizes.begin() + num_levels, 0), size,
- level_info.block, tile_size.height, info.tile_width_spacing);
+ AlignLayerSize(CalculateLevelBytes(sizes, num_levels), size, level_info.block,
+ tile_size.height, info.tile_width_spacing);
const size_t subresource_size = sizes[level];
const auto dst_data = std::make_unique<u8[]>(subresource_size);
@@ -644,10 +646,10 @@ u32 CalculateLayerSize(const ImageInfo& info) noexcept {
info.tile_width_spacing, info.resources.levels);
}
-std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets(const ImageInfo& info) noexcept {
+LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept {
ASSERT(info.resources.levels <= static_cast<s32>(MAX_MIP_LEVELS));
const LevelInfo level_info = MakeLevelInfo(info);
- std::array<u32, MAX_MIP_LEVELS> offsets{};
+ LevelArray offsets{};
u32 offset = 0;
for (s32 level = 0; level < info.resources.levels; ++level) {
offsets[level] = offset;
@@ -813,7 +815,7 @@ std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, GP
const Extent2D tile_size = DefaultBlockSize(info.format);
const std::array level_sizes = CalculateLevelSizes(level_info, num_levels);
const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing);
- const u32 layer_size = std::reduce(level_sizes.begin(), level_sizes.begin() + num_levels, 0);
+ const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels);
const u32 layer_stride = AlignLayerSize(layer_size, size, level_info.block, tile_size.height,
info.tile_width_spacing);
size_t guest_offset = 0;
@@ -879,17 +881,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
ASSERT(copy.image_extent == mip_size);
ASSERT(copy.buffer_row_length == Common::AlignUp(mip_size.width, tile_size.width));
ASSERT(copy.buffer_image_height == Common::AlignUp(mip_size.height, tile_size.height));
-
- if (IsPixelFormatASTC(info.format)) {
- ASSERT(copy.image_extent.depth == 1);
- Tegra::Texture::ASTC::Decompress(input.subspan(copy.buffer_offset),
- copy.image_extent.width, copy.image_extent.height,
- copy.image_subresource.num_layers, tile_size.width,
- tile_size.height, output.subspan(output_offset));
- } else {
- DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
- output.subspan(output_offset));
- }
+ DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
+ output.subspan(output_offset));
copy.buffer_offset = output_offset;
copy.buffer_row_length = mip_size.width;
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 {
using Tegra::Texture::TICEntry;
+using LevelArray = std::array<u32, MAX_MIP_LEVELS>;
+
struct OverlapResult {
GPUVAddr gpu_addr;
VAddr cpu_addr;
@@ -36,8 +38,7 @@ struct OverlapResult {
[[nodiscard]] u32 CalculateLayerSize(const ImageInfo& info) noexcept;
-[[nodiscard]] std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets(
- const ImageInfo& info) noexcept;
+[[nodiscard]] LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept;
[[nodiscard]] std::vector<u32> CalculateSliceOffsets(const ImageInfo& info);
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 @@
-// Copyright 2016 The University of North Carolina at Chapel Hill
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
-// <http://gamma.cs.unc.edu/FasTC/>
-
-#include <algorithm>
-#include <cassert>
-#include <cstring>
-#include <span>
-#include <vector>
-
-#include <boost/container/static_vector.hpp>
-
-#include "common/common_types.h"
-
-#include "video_core/textures/astc.h"
-
-namespace {
-
-/// Count the number of bits set in a number.
-constexpr u32 Popcnt(u32 n) {
- u32 c = 0;
- for (; n; c++) {
- n &= n - 1;
- }
- return c;
-}
-
-} // Anonymous namespace
-
-class InputBitStream {
-public:
- constexpr explicit InputBitStream(std::span<const u8> data, size_t start_offset = 0)
- : cur_byte{data.data()}, total_bits{data.size()}, next_bit{start_offset % 8} {}
-
- constexpr size_t GetBitsRead() const {
- return bits_read;
- }
-
- constexpr bool ReadBit() {
- if (bits_read >= total_bits * 8) {
- return 0;
- }
- const bool bit = ((*cur_byte >> next_bit) & 1) != 0;
- ++next_bit;
- while (next_bit >= 8) {
- next_bit -= 8;
- ++cur_byte;
- }
- ++bits_read;
- return bit;
- }
-
- constexpr u32 ReadBits(std::size_t nBits) {
- u32 ret = 0;
- for (std::size_t i = 0; i < nBits; ++i) {
- ret |= (ReadBit() & 1) << i;
- }
- return ret;
- }
-
- template <std::size_t nBits>
- constexpr u32 ReadBits() {
- u32 ret = 0;
- for (std::size_t i = 0; i < nBits; ++i) {
- ret |= (ReadBit() & 1) << i;
- }
- return ret;
- }
-
-private:
- const u8* cur_byte;
- size_t total_bits = 0;
- size_t next_bit = 0;
- size_t bits_read = 0;
-};
-
-class OutputBitStream {
-public:
- constexpr explicit OutputBitStream(u8* ptr, std::size_t bits = 0, std::size_t start_offset = 0)
- : cur_byte{ptr}, num_bits{bits}, next_bit{start_offset % 8} {}
-
- constexpr std::size_t GetBitsWritten() const {
- return bits_written;
- }
-
- constexpr void WriteBitsR(u32 val, u32 nBits) {
- for (u32 i = 0; i < nBits; i++) {
- WriteBit((val >> (nBits - i - 1)) & 1);
- }
- }
-
- constexpr void WriteBits(u32 val, u32 nBits) {
- for (u32 i = 0; i < nBits; i++) {
- WriteBit((val >> i) & 1);
- }
- }
-
-private:
- constexpr void WriteBit(bool b) {
- if (bits_written >= num_bits) {
- return;
- }
-
- const u32 mask = 1 << next_bit++;
-
- // clear the bit
- *cur_byte &= static_cast<u8>(~mask);
-
- // Write the bit, if necessary
- if (b)
- *cur_byte |= static_cast<u8>(mask);
-
- // Next byte?
- if (next_bit >= 8) {
- cur_byte += 1;
- next_bit = 0;
- }
- }
-
- u8* cur_byte;
- std::size_t num_bits;
- std::size_t bits_written = 0;
- std::size_t next_bit = 0;
-};
-
-template <typename IntType>
-class Bits {
-public:
- explicit Bits(const IntType& v) : m_Bits(v) {}
-
- Bits(const Bits&) = delete;
- Bits& operator=(const Bits&) = delete;
-
- u8 operator[](u32 bitPos) const {
- return static_cast<u8>((m_Bits >> bitPos) & 1);
- }
-
- IntType operator()(u32 start, u32 end) const {
- if (start == end) {
- return (*this)[start];
- } else if (start > end) {
- u32 t = start;
- start = end;
- end = t;
- }
-
- u64 mask = (1 << (end - start + 1)) - 1;
- return (m_Bits >> start) & static_cast<IntType>(mask);
- }
-
-private:
- const IntType& m_Bits;
-};
-
-enum class IntegerEncoding { JustBits, Qus32, Trit };
-
-struct IntegerEncodedValue {
- constexpr IntegerEncodedValue() = default;
-
- constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
- : encoding{encoding_}, num_bits{num_bits_} {}
-
- constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
- return encoding == other.encoding && num_bits == other.num_bits;
- }
-
- // Returns the number of bits required to encode nVals values.
- u32 GetBitLength(u32 nVals) const {
- u32 totalBits = num_bits * nVals;
- if (encoding == IntegerEncoding::Trit) {
- totalBits += (nVals * 8 + 4) / 5;
- } else if (encoding == IntegerEncoding::Qus32) {
- totalBits += (nVals * 7 + 2) / 3;
- }
- return totalBits;
- }
-
- IntegerEncoding encoding{};
- u32 num_bits = 0;
- u32 bit_value = 0;
- union {
- u32 qus32_value = 0;
- u32 trit_value;
- };
-};
-using IntegerEncodedVector = boost::container::static_vector<
- IntegerEncodedValue, 256,
- boost::container::static_vector_options<
- boost::container::inplace_alignment<alignof(IntegerEncodedValue)>,
- boost::container::throw_on_overflow<false>>::type>;
-
-static void DecodeTritBlock(InputBitStream& bits, IntegerEncodedVector& result, u32 nBitsPerValue) {
- // Implement the algorithm in section C.2.12
- std::array<u32, 5> m;
- std::array<u32, 5> t;
- u32 T;
-
- // Read the trit encoded block according to
- // table C.2.14
- m[0] = bits.ReadBits(nBitsPerValue);
- T = bits.ReadBits<2>();
- m[1] = bits.ReadBits(nBitsPerValue);
- T |= bits.ReadBits<2>() << 2;
- m[2] = bits.ReadBits(nBitsPerValue);
- T |= bits.ReadBit() << 4;
- m[3] = bits.ReadBits(nBitsPerValue);
- T |= bits.ReadBits<2>() << 5;
- m[4] = bits.ReadBits(nBitsPerValue);
- T |= bits.ReadBit() << 7;
-
- u32 C = 0;
-
- Bits<u32> Tb(T);
- if (Tb(2, 4) == 7) {
- C = (Tb(5, 7) << 2) | Tb(0, 1);
- t[4] = t[3] = 2;
- } else {
- C = Tb(0, 4);
- if (Tb(5, 6) == 3) {
- t[4] = 2;
- t[3] = Tb[7];
- } else {
- t[4] = Tb[7];
- t[3] = Tb(5, 6);
- }
- }
-
- Bits<u32> Cb(C);
- if (Cb(0, 1) == 3) {
- t[2] = 2;
- t[1] = Cb[4];
- t[0] = (Cb[3] << 1) | (Cb[2] & ~Cb[3]);
- } else if (Cb(2, 3) == 3) {
- t[2] = 2;
- t[1] = 2;
- t[0] = Cb(0, 1);
- } else {
- t[2] = Cb[4];
- t[1] = Cb(2, 3);
- t[0] = (Cb[1] << 1) | (Cb[0] & ~Cb[1]);
- }
-
- for (std::size_t i = 0; i < 5; ++i) {
- IntegerEncodedValue& val = result.emplace_back(IntegerEncoding::Trit, nBitsPerValue);
- val.bit_value = m[i];
- val.trit_value = t[i];
- }
-}
-
-static void DecodeQus32Block(InputBitStream& bits, IntegerEncodedVector& result,
- u32 nBitsPerValue) {
- // Implement the algorithm in section C.2.12
- u32 m[3];
- u32 q[3];
- u32 Q;
-
- // Read the trit encoded block according to
- // table C.2.15
- m[0] = bits.ReadBits(nBitsPerValue);
- Q = bits.ReadBits<3>();
- m[1] = bits.ReadBits(nBitsPerValue);
- Q |= bits.ReadBits<2>() << 3;
- m[2] = bits.ReadBits(nBitsPerValue);
- Q |= bits.ReadBits<2>() << 5;
-
- Bits<u32> Qb(Q);
- if (Qb(1, 2) == 3 && Qb(5, 6) == 0) {
- q[0] = q[1] = 4;
- q[2] = (Qb[0] << 2) | ((Qb[4] & ~Qb[0]) << 1) | (Qb[3] & ~Qb[0]);
- } else {
- u32 C = 0;
- if (Qb(1, 2) == 3) {
- q[2] = 4;
- C = (Qb(3, 4) << 3) | ((~Qb(5, 6) & 3) << 1) | Qb[0];
- } else {
- q[2] = Qb(5, 6);
- C = Qb(0, 4);
- }
-
- Bits<u32> Cb(C);
- if (Cb(0, 2) == 5) {
- q[1] = 4;
- q[0] = Cb(3, 4);
- } else {
- q[1] = Cb(3, 4);
- q[0] = Cb(0, 2);
- }
- }
-
- for (std::size_t i = 0; i < 3; ++i) {
- IntegerEncodedValue& val = result.emplace_back(IntegerEncoding::Qus32, nBitsPerValue);
- val.bit_value = m[i];
- val.qus32_value = q[i];
- }
-}
-
-// Returns a new instance of this struct that corresponds to the
-// can take no more than maxval values
-static constexpr IntegerEncodedValue CreateEncoding(u32 maxVal) {
- while (maxVal > 0) {
- u32 check = maxVal + 1;
-
- // Is maxVal a power of two?
- if (!(check & (check - 1))) {
- return IntegerEncodedValue(IntegerEncoding::JustBits, Popcnt(maxVal));
- }
-
- // Is maxVal of the type 3*2^n - 1?
- if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
- return IntegerEncodedValue(IntegerEncoding::Trit, Popcnt(check / 3 - 1));
- }
-
- // Is maxVal of the type 5*2^n - 1?
- if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
- return IntegerEncodedValue(IntegerEncoding::Qus32, Popcnt(check / 5 - 1));
- }
-
- // Apparently it can't be represented with a bounded integer sequence...
- // just iterate.
- maxVal--;
- }
- return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
-}
-
-static constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
- std::array<IntegerEncodedValue, 256> encodings{};
- for (std::size_t i = 0; i < encodings.size(); ++i) {
- encodings[i] = CreateEncoding(static_cast<u32>(i));
- }
- return encodings;
-}
-
-static constexpr std::array EncodingsValues = MakeEncodedValues();
-
-// Fills result with the values that are encoded in the given
-// bitstream. We must know beforehand what the maximum possible
-// value is, and how many values we're decoding.
-static void DecodeIntegerSequence(IntegerEncodedVector& result, InputBitStream& bits, u32 maxRange,
- u32 nValues) {
- // Determine encoding parameters
- IntegerEncodedValue val = EncodingsValues[maxRange];
-
- // Start decoding
- u32 nValsDecoded = 0;
- while (nValsDecoded < nValues) {
- switch (val.encoding) {
- case IntegerEncoding::Qus32:
- DecodeQus32Block(bits, result, val.num_bits);
- nValsDecoded += 3;
- break;
-
- case IntegerEncoding::Trit:
- DecodeTritBlock(bits, result, val.num_bits);
- nValsDecoded += 5;
- break;
-
- case IntegerEncoding::JustBits:
- val.bit_value = bits.ReadBits(val.num_bits);
- result.push_back(val);
- nValsDecoded++;
- break;
- }
- }
-}
-
-namespace ASTCC {
-
-struct TexelWeightParams {
- u32 m_Width = 0;
- u32 m_Height = 0;
- bool m_bDualPlane = false;
- u32 m_MaxWeight = 0;
- bool m_bError = false;
- bool m_bVoidExtentLDR = false;
- bool m_bVoidExtentHDR = false;
-
- u32 GetPackedBitSize() const {
- // How many indices do we have?
- u32 nIdxs = m_Height * m_Width;
- if (m_bDualPlane) {
- nIdxs *= 2;
- }
-
- return EncodingsValues[m_MaxWeight].GetBitLength(nIdxs);
- }
-
- u32 GetNumWeightValues() const {
- u32 ret = m_Width * m_Height;
- if (m_bDualPlane) {
- ret *= 2;
- }
- return ret;
- }
-};
-
-static TexelWeightParams DecodeBlockInfo(InputBitStream& strm) {
- TexelWeightParams params;
-
- // Read the entire block mode all at once
- u16 modeBits = static_cast<u16>(strm.ReadBits<11>());
-
- // Does this match the void extent block mode?
- if ((modeBits & 0x01FF) == 0x1FC) {
- if (modeBits & 0x200) {
- params.m_bVoidExtentHDR = true;
- } else {
- params.m_bVoidExtentLDR = true;
- }
-
- // Next two bits must be one.
- if (!(modeBits & 0x400) || !strm.ReadBit()) {
- params.m_bError = true;
- }
-
- return params;
- }
-
- // First check if the last four bits are zero
- if ((modeBits & 0xF) == 0) {
- params.m_bError = true;
- return params;
- }
-
- // If the last two bits are zero, then if bits
- // [6-8] are all ones, this is also reserved.
- if ((modeBits & 0x3) == 0 && (modeBits & 0x1C0) == 0x1C0) {
- params.m_bError = true;
- return params;
- }
-
- // Otherwise, there is no error... Figure out the layout
- // of the block mode. Layout is determined by a number
- // between 0 and 9 corresponding to table C.2.8 of the
- // ASTC spec.
- u32 layout = 0;
-
- if ((modeBits & 0x1) || (modeBits & 0x2)) {
- // layout is in [0-4]
- if (modeBits & 0x8) {
- // layout is in [2-4]
- if (modeBits & 0x4) {
- // layout is in [3-4]
- if (modeBits & 0x100) {
- layout = 4;
- } else {
- layout = 3;
- }
- } else {
- layout = 2;
- }
- } else {
- // layout is in [0-1]
- if (modeBits & 0x4) {
- layout = 1;
- } else {
- layout = 0;
- }
- }
- } else {
- // layout is in [5-9]
- if (modeBits & 0x100) {
- // layout is in [7-9]
- if (modeBits & 0x80) {
- // layout is in [7-8]
- assert((modeBits & 0x40) == 0U);
- if (modeBits & 0x20) {
- layout = 8;
- } else {
- layout = 7;
- }
- } else {
- layout = 9;
- }
- } else {
- // layout is in [5-6]
- if (modeBits & 0x80) {
- layout = 6;
- } else {
- layout = 5;
- }
- }
- }
-
- assert(layout < 10);
-
- // Determine R
- u32 R = !!(modeBits & 0x10);
- if (layout < 5) {
- R |= (modeBits & 0x3) << 1;
- } else {
- R |= (modeBits & 0xC) >> 1;
- }
- assert(2 <= R && R <= 7);
-
- // Determine width & height
- switch (layout) {
- case 0: {
- u32 A = (modeBits >> 5) & 0x3;
- u32 B = (modeBits >> 7) & 0x3;
- params.m_Width = B + 4;
- params.m_Height = A + 2;
- break;
- }
-
- case 1: {
- u32 A = (modeBits >> 5) & 0x3;
- u32 B = (modeBits >> 7) & 0x3;
- params.m_Width = B + 8;
- params.m_Height = A + 2;
- break;
- }
-
- case 2: {
- u32 A = (modeBits >> 5) & 0x3;
- u32 B = (modeBits >> 7) & 0x3;
- params.m_Width = A + 2;
- params.m_Height = B + 8;
- break;
- }
-
- case 3: {
- u32 A = (modeBits >> 5) & 0x3;
- u32 B = (modeBits >> 7) & 0x1;
- params.m_Width = A + 2;
- params.m_Height = B + 6;
- break;
- }
-
- case 4: {
- u32 A = (modeBits >> 5) & 0x3;
- u32 B = (modeBits >> 7) & 0x1;
- params.m_Width = B + 2;
- params.m_Height = A + 2;
- break;
- }
-
- case 5: {
- u32 A = (modeBits >> 5) & 0x3;
- params.m_Width = 12;
- params.m_Height = A + 2;
- break;
- }
-
- case 6: {
- u32 A = (modeBits >> 5) & 0x3;
- params.m_Width = A + 2;
- params.m_Height = 12;
- break;
- }
-
- case 7: {
- params.m_Width = 6;
- params.m_Height = 10;
- break;
- }
-
- case 8: {
- params.m_Width = 10;
- params.m_Height = 6;
- break;
- }
-
- case 9: {
- u32 A = (modeBits >> 5) & 0x3;
- u32 B = (modeBits >> 9) & 0x3;
- params.m_Width = A + 6;
- params.m_Height = B + 6;
- break;
- }
-
- default:
- assert(false && "Don't know this layout...");
- params.m_bError = true;
- break;
- }
-
- // Determine whether or not we're using dual planes
- // and/or high precision layouts.
- bool D = (layout != 9) && (modeBits & 0x400);
- bool H = (layout != 9) && (modeBits & 0x200);
-
- if (H) {
- const u32 maxWeights[6] = {9, 11, 15, 19, 23, 31};
- params.m_MaxWeight = maxWeights[R - 2];
- } else {
- const u32 maxWeights[6] = {1, 2, 3, 4, 5, 7};
- params.m_MaxWeight = maxWeights[R - 2];
- }
-
- params.m_bDualPlane = D;
-
- return params;
-}
-
-static void FillVoidExtentLDR(InputBitStream& strm, std::span<u32> outBuf, u32 blockWidth,
- u32 blockHeight) {
- // Don't actually care about the void extent, just read the bits...
- for (s32 i = 0; i < 4; ++i) {
- strm.ReadBits<13>();
- }
-
- // Decode the RGBA components and renormalize them to the range [0, 255]
- u16 r = static_cast<u16>(strm.ReadBits<16>());
- u16 g = static_cast<u16>(strm.ReadBits<16>());
- u16 b = static_cast<u16>(strm.ReadBits<16>());
- u16 a = static_cast<u16>(strm.ReadBits<16>());
-
- u32 rgba = (r >> 8) | (g & 0xFF00) | (static_cast<u32>(b) & 0xFF00) << 8 |
- (static_cast<u32>(a) & 0xFF00) << 16;
-
- for (u32 j = 0; j < blockHeight; j++) {
- for (u32 i = 0; i < blockWidth; i++) {
- outBuf[j * blockWidth + i] = rgba;
- }
- }
-}
-
-static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) {
- for (u32 j = 0; j < blockHeight; j++) {
- for (u32 i = 0; i < blockWidth; i++) {
- outBuf[j * blockWidth + i] = 0xFFFF00FF;
- }
- }
-}
-
-// Replicates low numBits such that [(toBit - 1):(toBit - 1 - fromBit)]
-// is the same as [(numBits - 1):0] and repeats all the way down.
-template <typename IntType>
-static constexpr IntType Replicate(IntType val, u32 numBits, u32 toBit) {
- if (numBits == 0) {
- return 0;
- }
- if (toBit == 0) {
- return 0;
- }
- const IntType v = val & static_cast<IntType>((1 << numBits) - 1);
- IntType res = v;
- u32 reslen = numBits;
- while (reslen < toBit) {
- u32 comp = 0;
- if (numBits > toBit - reslen) {
- u32 newshift = toBit - reslen;
- comp = numBits - newshift;
- numBits = newshift;
- }
- res = static_cast<IntType>(res << numBits);
- res = static_cast<IntType>(res | (v >> comp));
- reslen += numBits;
- }
- return res;
-}
-
-static constexpr std::size_t NumReplicateEntries(u32 num_bits) {
- return std::size_t(1) << num_bits;
-}
-
-template <typename IntType, u32 num_bits, u32 to_bit>
-static constexpr auto MakeReplicateTable() {
- std::array<IntType, NumReplicateEntries(num_bits)> table{};
- for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
- table[value] = Replicate(value, num_bits, to_bit);
- }
- return table;
-}
-
-static constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
-static constexpr u32 ReplicateByteTo16(std::size_t value) {
- return REPLICATE_BYTE_TO_16_TABLE[value];
-}
-
-static constexpr auto REPLICATE_BIT_TO_7_TABLE = MakeReplicateTable<u32, 1, 7>();
-static constexpr u32 ReplicateBitTo7(std::size_t value) {
- return REPLICATE_BIT_TO_7_TABLE[value];
-}
-
-static constexpr auto REPLICATE_BIT_TO_9_TABLE = MakeReplicateTable<u32, 1, 9>();
-static constexpr u32 ReplicateBitTo9(std::size_t value) {
- return REPLICATE_BIT_TO_9_TABLE[value];
-}
-
-static constexpr auto REPLICATE_1_BIT_TO_8_TABLE = MakeReplicateTable<u32, 1, 8>();
-static constexpr auto REPLICATE_2_BIT_TO_8_TABLE = MakeReplicateTable<u32, 2, 8>();
-static constexpr auto REPLICATE_3_BIT_TO_8_TABLE = MakeReplicateTable<u32, 3, 8>();
-static constexpr auto REPLICATE_4_BIT_TO_8_TABLE = MakeReplicateTable<u32, 4, 8>();
-static constexpr auto REPLICATE_5_BIT_TO_8_TABLE = MakeReplicateTable<u32, 5, 8>();
-static constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
-static constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
-static constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
-/// Use a precompiled table with the most common usages, if it's not in the expected range, fallback
-/// to the runtime implementation
-static constexpr u32 FastReplicateTo8(u32 value, u32 num_bits) {
- switch (num_bits) {
- case 1:
- return REPLICATE_1_BIT_TO_8_TABLE[value];
- case 2:
- return REPLICATE_2_BIT_TO_8_TABLE[value];
- case 3:
- return REPLICATE_3_BIT_TO_8_TABLE[value];
- case 4:
- return REPLICATE_4_BIT_TO_8_TABLE[value];
- case 5:
- return REPLICATE_5_BIT_TO_8_TABLE[value];
- case 6:
- return REPLICATE_6_BIT_TO_8_TABLE[value];
- case 7:
- return REPLICATE_7_BIT_TO_8_TABLE[value];
- case 8:
- return REPLICATE_8_BIT_TO_8_TABLE[value];
- default:
- return Replicate(value, num_bits, 8);
- }
-}
-
-static constexpr auto REPLICATE_1_BIT_TO_6_TABLE = MakeReplicateTable<u32, 1, 6>();
-static constexpr auto REPLICATE_2_BIT_TO_6_TABLE = MakeReplicateTable<u32, 2, 6>();
-static constexpr auto REPLICATE_3_BIT_TO_6_TABLE = MakeReplicateTable<u32, 3, 6>();
-static constexpr auto REPLICATE_4_BIT_TO_6_TABLE = MakeReplicateTable<u32, 4, 6>();
-static constexpr auto REPLICATE_5_BIT_TO_6_TABLE = MakeReplicateTable<u32, 5, 6>();
-static constexpr u32 FastReplicateTo6(u32 value, u32 num_bits) {
- switch (num_bits) {
- case 1:
- return REPLICATE_1_BIT_TO_6_TABLE[value];
- case 2:
- return REPLICATE_2_BIT_TO_6_TABLE[value];
- case 3:
- return REPLICATE_3_BIT_TO_6_TABLE[value];
- case 4:
- return REPLICATE_4_BIT_TO_6_TABLE[value];
- case 5:
- return REPLICATE_5_BIT_TO_6_TABLE[value];
- default:
- return Replicate(value, num_bits, 6);
- }
-}
-
-class Pixel {
-protected:
- using ChannelType = s16;
- u8 m_BitDepth[4] = {8, 8, 8, 8};
- s16 color[4] = {};
-
-public:
- Pixel() = default;
- Pixel(u32 a, u32 r, u32 g, u32 b, u32 bitDepth = 8)
- : m_BitDepth{u8(bitDepth), u8(bitDepth), u8(bitDepth), u8(bitDepth)},
- color{static_cast<ChannelType>(a), static_cast<ChannelType>(r),
- static_cast<ChannelType>(g), static_cast<ChannelType>(b)} {}
-
- // Changes the depth of each pixel. This scales the values to
- // the appropriate bit depth by either truncating the least
- // significant bits when going from larger to smaller bit depth
- // or by repeating the most significant bits when going from
- // smaller to larger bit depths.
- void ChangeBitDepth() {
- for (u32 i = 0; i < 4; i++) {
- Component(i) = ChangeBitDepth(Component(i), m_BitDepth[i]);
- m_BitDepth[i] = 8;
- }
- }
-
- template <typename IntType>
- static float ConvertChannelToFloat(IntType channel, u8 bitDepth) {
- float denominator = static_cast<float>((1 << bitDepth) - 1);
- return static_cast<float>(channel) / denominator;
- }
-
- // Changes the bit depth of a single component. See the comment
- // above for how we do this.
- static ChannelType ChangeBitDepth(Pixel::ChannelType val, u8 oldDepth) {
- assert(oldDepth <= 8);
-
- if (oldDepth == 8) {
- // Do nothing
- return val;
- } else if (oldDepth == 0) {
- return static_cast<ChannelType>((1 << 8) - 1);
- } else if (8 > oldDepth) {
- return static_cast<ChannelType>(FastReplicateTo8(static_cast<u32>(val), oldDepth));
- } else {
- // oldDepth > newDepth
- const u8 bitsWasted = static_cast<u8>(oldDepth - 8);
- u16 v = static_cast<u16>(val);
- v = static_cast<u16>((v + (1 << (bitsWasted - 1))) >> bitsWasted);
- v = ::std::min<u16>(::std::max<u16>(0, v), static_cast<u16>((1 << 8) - 1));
- return static_cast<u8>(v);
- }
-
- assert(false && "We shouldn't get here.");
- return 0;
- }
-
- const ChannelType& A() const {
- return color[0];
- }
- ChannelType& A() {
- return color[0];
- }
- const ChannelType& R() const {
- return color[1];
- }
- ChannelType& R() {
- return color[1];
- }
- const ChannelType& G() const {
- return color[2];
- }
- ChannelType& G() {
- return color[2];
- }
- const ChannelType& B() const {
- return color[3];
- }
- ChannelType& B() {
- return color[3];
- }
- const ChannelType& Component(u32 idx) const {
- return color[idx];
- }
- ChannelType& Component(u32 idx) {
- return color[idx];
- }
-
- void GetBitDepth(u8 (&outDepth)[4]) const {
- for (s32 i = 0; i < 4; i++) {
- outDepth[i] = m_BitDepth[i];
- }
- }
-
- // Take all of the components, transform them to their 8-bit variants,
- // and then pack each channel into an R8G8B8A8 32-bit integer. We assume
- // that the architecture is little-endian, so the alpha channel will end
- // up in the most-significant byte.
- u32 Pack() const {
- Pixel eightBit(*this);
- eightBit.ChangeBitDepth();
-
- u32 r = 0;
- r |= eightBit.A();
- r <<= 8;
- r |= eightBit.B();
- r <<= 8;
- r |= eightBit.G();
- r <<= 8;
- r |= eightBit.R();
- return r;
- }
-
- // Clamps the pixel to the range [0,255]
- void ClampByte() {
- for (u32 i = 0; i < 4; i++) {
- color[i] = (color[i] < 0) ? 0 : ((color[i] > 255) ? 255 : color[i]);
- }
- }
-
- void MakeOpaque() {
- A() = 255;
- }
-};
-
-static void DecodeColorValues(u32* out, std::span<u8> data, const u32* modes, const u32 nPartitions,
- const u32 nBitsForColorData) {
- // First figure out how many color values we have
- u32 nValues = 0;
- for (u32 i = 0; i < nPartitions; i++) {
- nValues += ((modes[i] >> 2) + 1) << 1;
- }
-
- // Then based on the number of values and the remaining number of bits,
- // figure out the max value for each of them...
- u32 range = 256;
- while (--range > 0) {
- IntegerEncodedValue val = EncodingsValues[range];
- u32 bitLength = val.GetBitLength(nValues);
- if (bitLength <= nBitsForColorData) {
- // Find the smallest possible range that matches the given encoding
- while (--range > 0) {
- IntegerEncodedValue newval = EncodingsValues[range];
- if (!newval.MatchesEncoding(val)) {
- break;
- }
- }
-
- // Return to last matching range.
- range++;
- break;
- }
- }
-
- // We now have enough to decode our integer sequence.
- IntegerEncodedVector decodedColorValues;
-
- InputBitStream colorStream(data, 0);
- DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues);
-
- // Once we have the decoded values, we need to dequantize them to the 0-255 range
- // This procedure is outlined in ASTC spec C.2.13
- u32 outIdx = 0;
- for (auto itr = decodedColorValues.begin(); itr != decodedColorValues.end(); ++itr) {
- // Have we already decoded all that we need?
- if (outIdx >= nValues) {
- break;
- }
-
- const IntegerEncodedValue& val = *itr;
- u32 bitlen = val.num_bits;
- u32 bitval = val.bit_value;
-
- assert(bitlen >= 1);
-
- u32 A = 0, B = 0, C = 0, D = 0;
- // A is just the lsb replicated 9 times.
- A = ReplicateBitTo9(bitval & 1);
-
- switch (val.encoding) {
- // Replicate bits
- case IntegerEncoding::JustBits:
- out[outIdx++] = FastReplicateTo8(bitval, bitlen);
- break;
-
- // Use algorithm in C.2.13
- case IntegerEncoding::Trit: {
-
- D = val.trit_value;
-
- switch (bitlen) {
- case 1: {
- C = 204;
- } break;
-
- case 2: {
- C = 93;
- // B = b000b0bb0
- u32 b = (bitval >> 1) & 1;
- B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
- } break;
-
- case 3: {
- C = 44;
- // B = cb000cbcb
- u32 cb = (bitval >> 1) & 3;
- B = (cb << 7) | (cb << 2) | cb;
- } break;
-
- case 4: {
- C = 22;
- // B = dcb000dcb
- u32 dcb = (bitval >> 1) & 7;
- B = (dcb << 6) | dcb;
- } break;
-
- case 5: {
- C = 11;
- // B = edcb000ed
- u32 edcb = (bitval >> 1) & 0xF;
- B = (edcb << 5) | (edcb >> 2);
- } break;
-
- case 6: {
- C = 5;
- // B = fedcb000f
- u32 fedcb = (bitval >> 1) & 0x1F;
- B = (fedcb << 4) | (fedcb >> 4);
- } break;
-
- default:
- assert(false && "Unsupported trit encoding for color values!");
- break;
- } // switch(bitlen)
- } // case IntegerEncoding::Trit
- break;
-
- case IntegerEncoding::Qus32: {
-
- D = val.qus32_value;
-
- switch (bitlen) {
- case 1: {
- C = 113;
- } break;
-
- case 2: {
- C = 54;
- // B = b0000bb00
- u32 b = (bitval >> 1) & 1;
- B = (b << 8) | (b << 3) | (b << 2);
- } break;
-
- case 3: {
- C = 26;
- // B = cb0000cbc
- u32 cb = (bitval >> 1) & 3;
- B = (cb << 7) | (cb << 1) | (cb >> 1);
- } break;
-
- case 4: {
- C = 13;
- // B = dcb0000dc
- u32 dcb = (bitval >> 1) & 7;
- B = (dcb << 6) | (dcb >> 1);
- } break;
-
- case 5: {
- C = 6;
- // B = edcb0000e
- u32 edcb = (bitval >> 1) & 0xF;
- B = (edcb << 5) | (edcb >> 3);
- } break;
-
- default:
- assert(false && "Unsupported quint encoding for color values!");
- break;
- } // switch(bitlen)
- } // case IntegerEncoding::Qus32
- break;
- } // switch(val.encoding)
-
- if (val.encoding != IntegerEncoding::JustBits) {
- u32 T = D * C + B;
- T ^= A;
- T = (A & 0x80) | (T >> 2);
- out[outIdx++] = T;
- }
- }
-
- // Make sure that each of our values is in the proper range...
- for (u32 i = 0; i < nValues; i++) {
- assert(out[i] <= 255);
- }
-}
-
-static u32 UnquantizeTexelWeight(const IntegerEncodedValue& val) {
- u32 bitval = val.bit_value;
- u32 bitlen = val.num_bits;
-
- u32 A = ReplicateBitTo7(bitval & 1);
- u32 B = 0, C = 0, D = 0;
-
- u32 result = 0;
- switch (val.encoding) {
- case IntegerEncoding::JustBits:
- result = FastReplicateTo6(bitval, bitlen);
- break;
-
- case IntegerEncoding::Trit: {
- D = val.trit_value;
- assert(D < 3);
-
- switch (bitlen) {
- case 0: {
- u32 results[3] = {0, 32, 63};
- result = results[D];
- } break;
-
- case 1: {
- C = 50;
- } break;
-
- case 2: {
- C = 23;
- u32 b = (bitval >> 1) & 1;
- B = (b << 6) | (b << 2) | b;
- } break;
-
- case 3: {
- C = 11;
- u32 cb = (bitval >> 1) & 3;
- B = (cb << 5) | cb;
- } break;
-
- default:
- assert(false && "Invalid trit encoding for texel weight");
- break;
- }
- } break;
-
- case IntegerEncoding::Qus32: {
- D = val.qus32_value;
- assert(D < 5);
-
- switch (bitlen) {
- case 0: {
- u32 results[5] = {0, 16, 32, 47, 63};
- result = results[D];
- } break;
-
- case 1: {
- C = 28;
- } break;
-
- case 2: {
- C = 13;
- u32 b = (bitval >> 1) & 1;
- B = (b << 6) | (b << 1);
- } break;
-
- default:
- assert(false && "Invalid quint encoding for texel weight");
- break;
- }
- } break;
- }
-
- if (val.encoding != IntegerEncoding::JustBits && bitlen > 0) {
- // Decode the value...
- result = D * C + B;
- result ^= A;
- result = (A & 0x20) | (result >> 2);
- }
-
- assert(result < 64);
-
- // Change from [0,63] to [0,64]
- if (result > 32) {
- result += 1;
- }
-
- return result;
-}
-
-static void UnquantizeTexelWeights(u32 out[2][144], const IntegerEncodedVector& weights,
- const TexelWeightParams& params, const u32 blockWidth,
- const u32 blockHeight) {
- u32 weightIdx = 0;
- u32 unquantized[2][144];
-
- for (auto itr = weights.begin(); itr != weights.end(); ++itr) {
- unquantized[0][weightIdx] = UnquantizeTexelWeight(*itr);
-
- if (params.m_bDualPlane) {
- ++itr;
- unquantized[1][weightIdx] = UnquantizeTexelWeight(*itr);
- if (itr == weights.end()) {
- break;
- }
- }
-
- if (++weightIdx >= (params.m_Width * params.m_Height))
- break;
- }
-
- // Do infill if necessary (Section C.2.18) ...
- u32 Ds = (1024 + (blockWidth / 2)) / (blockWidth - 1);
- u32 Dt = (1024 + (blockHeight / 2)) / (blockHeight - 1);
-
- const u32 kPlaneScale = params.m_bDualPlane ? 2U : 1U;
- for (u32 plane = 0; plane < kPlaneScale; plane++)
- for (u32 t = 0; t < blockHeight; t++)
- for (u32 s = 0; s < blockWidth; s++) {
- u32 cs = Ds * s;
- u32 ct = Dt * t;
-
- u32 gs = (cs * (params.m_Width - 1) + 32) >> 6;
- u32 gt = (ct * (params.m_Height - 1) + 32) >> 6;
-
- u32 js = gs >> 4;
- u32 fs = gs & 0xF;
-
- u32 jt = gt >> 4;
- u32 ft = gt & 0x0F;
-
- u32 w11 = (fs * ft + 8) >> 4;
- u32 w10 = ft - w11;
- u32 w01 = fs - w11;
- u32 w00 = 16 - fs - ft + w11;
-
- u32 v0 = js + jt * params.m_Width;
-
-#define FIND_TEXEL(tidx, bidx) \
- u32 p##bidx = 0; \
- do { \
- if ((tidx) < (params.m_Width * params.m_Height)) { \
- p##bidx = unquantized[plane][(tidx)]; \
- } \
- } while (0)
-
- FIND_TEXEL(v0, 00);
- FIND_TEXEL(v0 + 1, 01);
- FIND_TEXEL(v0 + params.m_Width, 10);
- FIND_TEXEL(v0 + params.m_Width + 1, 11);
-
-#undef FIND_TEXEL
-
- out[plane][t * blockWidth + s] =
- (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4;
- }
-}
-
-// Transfers a bit as described in C.2.14
-static inline void BitTransferSigned(s32& a, s32& b) {
- b >>= 1;
- b |= a & 0x80;
- a >>= 1;
- a &= 0x3F;
- if (a & 0x20)
- a -= 0x40;
-}
-
-// Adds more precision to the blue channel as described
-// in C.2.14
-static inline Pixel BlueContract(s32 a, s32 r, s32 g, s32 b) {
- return Pixel(static_cast<s16>(a), static_cast<s16>((r + b) >> 1),
- static_cast<s16>((g + b) >> 1), static_cast<s16>(b));
-}
-
-// Partition selection functions as specified in
-// C.2.21
-static inline u32 hash52(u32 p) {
- p ^= p >> 15;
- p -= p << 17;
- p += p << 7;
- p += p << 4;
- p ^= p >> 5;
- p += p << 16;
- p ^= p >> 7;
- p ^= p >> 3;
- p ^= p << 6;
- p ^= p >> 17;
- return p;
-}
-
-static u32 SelectPartition(s32 seed, s32 x, s32 y, s32 z, s32 partitionCount, s32 smallBlock) {
- if (1 == partitionCount)
- return 0;
-
- if (smallBlock) {
- x <<= 1;
- y <<= 1;
- z <<= 1;
- }
-
- seed += (partitionCount - 1) * 1024;
-
- u32 rnum = hash52(static_cast<u32>(seed));
- u8 seed1 = static_cast<u8>(rnum & 0xF);
- u8 seed2 = static_cast<u8>((rnum >> 4) & 0xF);
- u8 seed3 = static_cast<u8>((rnum >> 8) & 0xF);
- u8 seed4 = static_cast<u8>((rnum >> 12) & 0xF);
- u8 seed5 = static_cast<u8>((rnum >> 16) & 0xF);
- u8 seed6 = static_cast<u8>((rnum >> 20) & 0xF);
- u8 seed7 = static_cast<u8>((rnum >> 24) & 0xF);
- u8 seed8 = static_cast<u8>((rnum >> 28) & 0xF);
- u8 seed9 = static_cast<u8>((rnum >> 18) & 0xF);
- u8 seed10 = static_cast<u8>((rnum >> 22) & 0xF);
- u8 seed11 = static_cast<u8>((rnum >> 26) & 0xF);
- u8 seed12 = static_cast<u8>(((rnum >> 30) | (rnum << 2)) & 0xF);
-
- seed1 = static_cast<u8>(seed1 * seed1);
- seed2 = static_cast<u8>(seed2 * seed2);
- seed3 = static_cast<u8>(seed3 * seed3);
- seed4 = static_cast<u8>(seed4 * seed4);
- seed5 = static_cast<u8>(seed5 * seed5);
- seed6 = static_cast<u8>(seed6 * seed6);
- seed7 = static_cast<u8>(seed7 * seed7);
- seed8 = static_cast<u8>(seed8 * seed8);
- seed9 = static_cast<u8>(seed9 * seed9);
- seed10 = static_cast<u8>(seed10 * seed10);
- seed11 = static_cast<u8>(seed11 * seed11);
- seed12 = static_cast<u8>(seed12 * seed12);
-
- s32 sh1, sh2, sh3;
- if (seed & 1) {
- sh1 = (seed & 2) ? 4 : 5;
- sh2 = (partitionCount == 3) ? 6 : 5;
- } else {
- sh1 = (partitionCount == 3) ? 6 : 5;
- sh2 = (seed & 2) ? 4 : 5;
- }
- sh3 = (seed & 0x10) ? sh1 : sh2;
-
- seed1 = static_cast<u8>(seed1 >> sh1);
- seed2 = static_cast<u8>(seed2 >> sh2);
- seed3 = static_cast<u8>(seed3 >> sh1);
- seed4 = static_cast<u8>(seed4 >> sh2);
- seed5 = static_cast<u8>(seed5 >> sh1);
- seed6 = static_cast<u8>(seed6 >> sh2);
- seed7 = static_cast<u8>(seed7 >> sh1);
- seed8 = static_cast<u8>(seed8 >> sh2);
- seed9 = static_cast<u8>(seed9 >> sh3);
- seed10 = static_cast<u8>(seed10 >> sh3);
- seed11 = static_cast<u8>(seed11 >> sh3);
- seed12 = static_cast<u8>(seed12 >> sh3);
-
- s32 a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
- s32 b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
- s32 c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
- s32 d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
-
- a &= 0x3F;
- b &= 0x3F;
- c &= 0x3F;
- d &= 0x3F;
-
- if (partitionCount < 4)
- d = 0;
- if (partitionCount < 3)
- c = 0;
-
- if (a >= b && a >= c && a >= d)
- return 0;
- else if (b >= c && b >= d)
- return 1;
- else if (c >= d)
- return 2;
- return 3;
-}
-
-static inline u32 Select2DPartition(s32 seed, s32 x, s32 y, s32 partitionCount, s32 smallBlock) {
- return SelectPartition(seed, x, y, 0, partitionCount, smallBlock);
-}
-
-// Section C.2.14
-static void ComputeEndpos32s(Pixel& ep1, Pixel& ep2, const u32*& colorValues,
- u32 colorEndpos32Mode) {
-#define READ_UINT_VALUES(N) \
- u32 v[N]; \
- for (u32 i = 0; i < N; i++) { \
- v[i] = *(colorValues++); \
- }
-
-#define READ_INT_VALUES(N) \
- s32 v[N]; \
- for (u32 i = 0; i < N; i++) { \
- v[i] = static_cast<s32>(*(colorValues++)); \
- }
-
- switch (colorEndpos32Mode) {
- case 0: {
- READ_UINT_VALUES(2)
- ep1 = Pixel(0xFF, v[0], v[0], v[0]);
- ep2 = Pixel(0xFF, v[1], v[1], v[1]);
- } break;
-
- case 1: {
- READ_UINT_VALUES(2)
- u32 L0 = (v[0] >> 2) | (v[1] & 0xC0);
- u32 L1 = std::max(L0 + (v[1] & 0x3F), 0xFFU);
- ep1 = Pixel(0xFF, L0, L0, L0);
- ep2 = Pixel(0xFF, L1, L1, L1);
- } break;
-
- case 4: {
- READ_UINT_VALUES(4)
- ep1 = Pixel(v[2], v[0], v[0], v[0]);
- ep2 = Pixel(v[3], v[1], v[1], v[1]);
- } break;
-
- case 5: {
- READ_INT_VALUES(4)
- BitTransferSigned(v[1], v[0]);
- BitTransferSigned(v[3], v[2]);
- ep1 = Pixel(v[2], v[0], v[0], v[0]);
- ep2 = Pixel(v[2] + v[3], v[0] + v[1], v[0] + v[1], v[0] + v[1]);
- ep1.ClampByte();
- ep2.ClampByte();
- } break;
-
- case 6: {
- READ_UINT_VALUES(4)
- ep1 = Pixel(0xFF, v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8);
- ep2 = Pixel(0xFF, v[0], v[1], v[2]);
- } break;
-
- case 8: {
- READ_UINT_VALUES(6)
- if (v[1] + v[3] + v[5] >= v[0] + v[2] + v[4]) {
- ep1 = Pixel(0xFF, v[0], v[2], v[4]);
- ep2 = Pixel(0xFF, v[1], v[3], v[5]);
- } else {
- ep1 = BlueContract(0xFF, v[1], v[3], v[5]);
- ep2 = BlueContract(0xFF, v[0], v[2], v[4]);
- }
- } break;
-
- case 9: {
- READ_INT_VALUES(6)
- BitTransferSigned(v[1], v[0]);
- BitTransferSigned(v[3], v[2]);
- BitTransferSigned(v[5], v[4]);
- if (v[1] + v[3] + v[5] >= 0) {
- ep1 = Pixel(0xFF, v[0], v[2], v[4]);
- ep2 = Pixel(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]);
- } else {
- ep1 = BlueContract(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]);
- ep2 = BlueContract(0xFF, v[0], v[2], v[4]);
- }
- ep1.ClampByte();
- ep2.ClampByte();
- } break;
-
- case 10: {
- READ_UINT_VALUES(6)
- ep1 = Pixel(v[4], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8);
- ep2 = Pixel(v[5], v[0], v[1], v[2]);
- } break;
-
- case 12: {
- READ_UINT_VALUES(8)
- if (v[1] + v[3] + v[5] >= v[0] + v[2] + v[4]) {
- ep1 = Pixel(v[6], v[0], v[2], v[4]);
- ep2 = Pixel(v[7], v[1], v[3], v[5]);
- } else {
- ep1 = BlueContract(v[7], v[1], v[3], v[5]);
- ep2 = BlueContract(v[6], v[0], v[2], v[4]);
- }
- } break;
-
- case 13: {
- READ_INT_VALUES(8)
- BitTransferSigned(v[1], v[0]);
- BitTransferSigned(v[3], v[2]);
- BitTransferSigned(v[5], v[4]);
- BitTransferSigned(v[7], v[6]);
- if (v[1] + v[3] + v[5] >= 0) {
- ep1 = Pixel(v[6], v[0], v[2], v[4]);
- ep2 = Pixel(v[7] + v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5]);
- } else {
- ep1 = BlueContract(v[6] + v[7], v[0] + v[1], v[2] + v[3], v[4] + v[5]);
- ep2 = BlueContract(v[6], v[0], v[2], v[4]);
- }
- ep1.ClampByte();
- ep2.ClampByte();
- } break;
-
- default:
- assert(false && "Unsupported color endpoint mode (is it HDR?)");
- break;
- }
-
-#undef READ_UINT_VALUES
-#undef READ_INT_VALUES
-}
-
-static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
- const u32 blockHeight, std::span<u32, 12 * 12> outBuf) {
- InputBitStream strm(inBuf);
- TexelWeightParams weightParams = DecodeBlockInfo(strm);
-
- // Was there an error?
- if (weightParams.m_bError) {
- assert(false && "Invalid block mode");
- FillError(outBuf, blockWidth, blockHeight);
- return;
- }
-
- if (weightParams.m_bVoidExtentLDR) {
- FillVoidExtentLDR(strm, outBuf, blockWidth, blockHeight);
- return;
- }
-
- if (weightParams.m_bVoidExtentHDR) {
- assert(false && "HDR void extent blocks are unsupported!");
- FillError(outBuf, blockWidth, blockHeight);
- return;
- }
-
- if (weightParams.m_Width > blockWidth) {
- assert(false && "Texel weight grid width should be smaller than block width");
- FillError(outBuf, blockWidth, blockHeight);
- return;
- }
-
- if (weightParams.m_Height > blockHeight) {
- assert(false && "Texel weight grid height should be smaller than block height");
- FillError(outBuf, blockWidth, blockHeight);
- return;
- }
-
- // Read num partitions
- u32 nPartitions = strm.ReadBits<2>() + 1;
- assert(nPartitions <= 4);
-
- if (nPartitions == 4 && weightParams.m_bDualPlane) {
- assert(false && "Dual plane mode is incompatible with four partition blocks");
- FillError(outBuf, blockWidth, blockHeight);
- return;
- }
-
- // Based on the number of partitions, read the color endpos32 mode for
- // each partition.
-
- // Determine partitions, partition index, and color endpos32 modes
- s32 planeIdx = -1;
- u32 partitionIndex;
- u32 colorEndpos32Mode[4] = {0, 0, 0, 0};
-
- // Define color data.
- u8 colorEndpos32Data[16];
- memset(colorEndpos32Data, 0, sizeof(colorEndpos32Data));
- OutputBitStream colorEndpos32Stream(colorEndpos32Data, 16 * 8, 0);
-
- // Read extra config data...
- u32 baseCEM = 0;
- if (nPartitions == 1) {
- colorEndpos32Mode[0] = strm.ReadBits<4>();
- partitionIndex = 0;
- } else {
- partitionIndex = strm.ReadBits<10>();
- baseCEM = strm.ReadBits<6>();
- }
- u32 baseMode = (baseCEM & 3);
-
- // Remaining bits are color endpos32 data...
- u32 nWeightBits = weightParams.GetPackedBitSize();
- s32 remainingBits = 128 - nWeightBits - static_cast<s32>(strm.GetBitsRead());
-
- // Consider extra bits prior to texel data...
- u32 extraCEMbits = 0;
- if (baseMode) {
- switch (nPartitions) {
- case 2:
- extraCEMbits += 2;
- break;
- case 3:
- extraCEMbits += 5;
- break;
- case 4:
- extraCEMbits += 8;
- break;
- default:
- assert(false);
- break;
- }
- }
- remainingBits -= extraCEMbits;
-
- // Do we have a dual plane situation?
- u32 planeSelectorBits = 0;
- if (weightParams.m_bDualPlane) {
- planeSelectorBits = 2;
- }
- remainingBits -= planeSelectorBits;
-
- // Read color data...
- u32 colorDataBits = remainingBits;
- while (remainingBits > 0) {
- u32 nb = std::min(remainingBits, 8);
- u32 b = strm.ReadBits(nb);
- colorEndpos32Stream.WriteBits(b, nb);
- remainingBits -= 8;
- }
-
- // Read the plane selection bits
- planeIdx = strm.ReadBits(planeSelectorBits);
-
- // Read the rest of the CEM
- if (baseMode) {
- u32 extraCEM = strm.ReadBits(extraCEMbits);
- u32 CEM = (extraCEM << 6) | baseCEM;
- CEM >>= 2;
-
- bool C[4] = {0};
- for (u32 i = 0; i < nPartitions; i++) {
- C[i] = CEM & 1;
- CEM >>= 1;
- }
-
- u8 M[4] = {0};
- for (u32 i = 0; i < nPartitions; i++) {
- M[i] = CEM & 3;
- CEM >>= 2;
- assert(M[i] <= 3);
- }
-
- for (u32 i = 0; i < nPartitions; i++) {
- colorEndpos32Mode[i] = baseMode;
- if (!(C[i]))
- colorEndpos32Mode[i] -= 1;
- colorEndpos32Mode[i] <<= 2;
- colorEndpos32Mode[i] |= M[i];
- }
- } else if (nPartitions > 1) {
- u32 CEM = baseCEM >> 2;
- for (u32 i = 0; i < nPartitions; i++) {
- colorEndpos32Mode[i] = CEM;
- }
- }
-
- // Make sure everything up till here is sane.
- for (u32 i = 0; i < nPartitions; i++) {
- assert(colorEndpos32Mode[i] < 16);
- }
- assert(strm.GetBitsRead() + weightParams.GetPackedBitSize() == 128);
-
- // Decode both color data and texel weight data
- u32 colorValues[32]; // Four values, two endpos32s, four maximum paritions
- DecodeColorValues(colorValues, colorEndpos32Data, colorEndpos32Mode, nPartitions,
- colorDataBits);
-
- Pixel endpos32s[4][2];
- const u32* colorValuesPtr = colorValues;
- for (u32 i = 0; i < nPartitions; i++) {
- ComputeEndpos32s(endpos32s[i][0], endpos32s[i][1], colorValuesPtr, colorEndpos32Mode[i]);
- }
-
- // Read the texel weight data..
- std::array<u8, 16> texelWeightData;
- std::ranges::copy(inBuf, texelWeightData.begin());
-
- // Reverse everything
- for (u32 i = 0; i < 8; i++) {
-// Taken from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
-#define REVERSE_BYTE(b) (((b)*0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32
- u8 a = static_cast<u8>(REVERSE_BYTE(texelWeightData[i]));
- u8 b = static_cast<u8>(REVERSE_BYTE(texelWeightData[15 - i]));
-#undef REVERSE_BYTE
-
- texelWeightData[i] = b;
- texelWeightData[15 - i] = a;
- }
-
- // Make sure that higher non-texel bits are set to zero
- const u32 clearByteStart = (weightParams.GetPackedBitSize() >> 3) + 1;
- if (clearByteStart > 0 && clearByteStart <= texelWeightData.size()) {
- texelWeightData[clearByteStart - 1] &=
- static_cast<u8>((1 << (weightParams.GetPackedBitSize() % 8)) - 1);
- std::memset(texelWeightData.data() + clearByteStart, 0,
- std::min(16U - clearByteStart, 16U));
- }
-
- IntegerEncodedVector texelWeightValues;
-
- InputBitStream weightStream(texelWeightData);
-
- DecodeIntegerSequence(texelWeightValues, weightStream, weightParams.m_MaxWeight,
- weightParams.GetNumWeightValues());
-
- // Blocks can be at most 12x12, so we can have as many as 144 weights
- u32 weights[2][144];
- UnquantizeTexelWeights(weights, texelWeightValues, weightParams, blockWidth, blockHeight);
-
- // Now that we have endpos32s and weights, we can s32erpolate and generate
- // the proper decoding...
- for (u32 j = 0; j < blockHeight; j++)
- for (u32 i = 0; i < blockWidth; i++) {
- u32 partition = Select2DPartition(partitionIndex, i, j, nPartitions,
- (blockHeight * blockWidth) < 32);
- assert(partition < nPartitions);
-
- Pixel p;
- for (u32 c = 0; c < 4; c++) {
- u32 C0 = endpos32s[partition][0].Component(c);
- C0 = ReplicateByteTo16(C0);
- u32 C1 = endpos32s[partition][1].Component(c);
- C1 = ReplicateByteTo16(C1);
-
- u32 plane = 0;
- if (weightParams.m_bDualPlane && (((planeIdx + 1) & 3) == c)) {
- plane = 1;
- }
-
- u32 weight = weights[plane][j * blockWidth + i];
- u32 C = (C0 * (64 - weight) + C1 * weight + 32) / 64;
- if (C == 65535) {
- p.Component(c) = 255;
- } else {
- double Cf = static_cast<double>(C);
- p.Component(c) = static_cast<u16>(255.0 * (Cf / 65536.0) + 0.5);
- }
- }
-
- outBuf[j * blockWidth + i] = p.Pack();
- }
-}
-
-} // namespace ASTCC
-
-namespace Tegra::Texture::ASTC {
-
-void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
- uint32_t block_width, uint32_t block_height, std::span<uint8_t> output) {
- u32 block_index = 0;
- std::size_t depth_offset = 0;
- for (u32 z = 0; z < depth; z++) {
- for (u32 y = 0; y < height; y += block_height) {
- for (u32 x = 0; x < width; x += block_width) {
- const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)};
-
- // Blocks can be at most 12x12
- std::array<u32, 12 * 12> uncompData;
- ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData);
-
- u32 decompWidth = std::min(block_width, width - x);
- u32 decompHeight = std::min(block_height, height - y);
-
- const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4);
- for (u32 jj = 0; jj < decompHeight; jj++) {
- std::memcpy(outRow.data() + jj * width * 4,
- uncompData.data() + jj * block_width, decompWidth * 4);
- }
- ++block_index;
- }
- }
- depth_offset += height * width * 4;
- }
-}
-
-} // 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 @@
#pragma once
-#include <cstdint>
+#include <bit>
+#include "common/common_types.h"
namespace Tegra::Texture::ASTC {
-void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
- uint32_t block_width, uint32_t block_height, std::span<uint8_t> output);
+enum class IntegerEncoding { JustBits, Quint, Trit };
+
+struct IntegerEncodedValue {
+ constexpr IntegerEncodedValue() = default;
+
+ constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
+ : encoding{encoding_}, num_bits{num_bits_} {}
+
+ constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
+ return encoding == other.encoding && num_bits == other.num_bits;
+ }
+
+ // Returns the number of bits required to encode num_vals values.
+ u32 GetBitLength(u32 num_vals) const {
+ u32 total_bits = num_bits * num_vals;
+ if (encoding == IntegerEncoding::Trit) {
+ total_bits += (num_vals * 8 + 4) / 5;
+ } else if (encoding == IntegerEncoding::Quint) {
+ total_bits += (num_vals * 7 + 2) / 3;
+ }
+ return total_bits;
+ }
+
+ IntegerEncoding encoding{};
+ u32 num_bits = 0;
+ u32 bit_value = 0;
+ union {
+ u32 quint_value = 0;
+ u32 trit_value;
+ };
+};
+
+// Returns a new instance of this struct that corresponds to the
+// can take no more than mav_value values
+constexpr IntegerEncodedValue CreateEncoding(u32 mav_value) {
+ while (mav_value > 0) {
+ u32 check = mav_value + 1;
+
+ // Is mav_value a power of two?
+ if (!(check & (check - 1))) {
+ return IntegerEncodedValue(IntegerEncoding::JustBits, std::popcount(mav_value));
+ }
+
+ // Is mav_value of the type 3*2^n - 1?
+ if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
+ return IntegerEncodedValue(IntegerEncoding::Trit, std::popcount(check / 3 - 1));
+ }
+
+ // Is mav_value of the type 5*2^n - 1?
+ if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
+ return IntegerEncodedValue(IntegerEncoding::Quint, std::popcount(check / 5 - 1));
+ }
+
+ // Apparently it can't be represented with a bounded integer sequence...
+ // just iterate.
+ mav_value--;
+ }
+ return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
+}
+
+constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
+ std::array<IntegerEncodedValue, 256> encodings{};
+ for (std::size_t i = 0; i < encodings.size(); ++i) {
+ encodings[i] = CreateEncoding(static_cast<u32>(i));
+ }
+ return encodings;
+}
+
+constexpr std::array<IntegerEncodedValue, 256> EncodingsValues = MakeEncodedValues();
+
+// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
+// is the same as [(num_bits - 1):0] and repeats all the way down.
+template <typename IntType>
+constexpr IntType Replicate(IntType val, u32 num_bits, u32 to_bit) {
+ if (num_bits == 0 || to_bit == 0) {
+ return 0;
+ }
+ const IntType v = val & static_cast<IntType>((1 << num_bits) - 1);
+ IntType res = v;
+ u32 reslen = num_bits;
+ while (reslen < to_bit) {
+ u32 comp = 0;
+ if (num_bits > to_bit - reslen) {
+ u32 newshift = to_bit - reslen;
+ comp = num_bits - newshift;
+ num_bits = newshift;
+ }
+ res = static_cast<IntType>(res << num_bits);
+ res = static_cast<IntType>(res | (v >> comp));
+ reslen += num_bits;
+ }
+ return res;
+}
+
+constexpr std::size_t NumReplicateEntries(u32 num_bits) {
+ return std::size_t(1) << num_bits;
+}
+
+template <typename IntType, u32 num_bits, u32 to_bit>
+constexpr auto MakeReplicateTable() {
+ std::array<IntType, NumReplicateEntries(num_bits)> table{};
+ for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
+ table[value] = Replicate(value, num_bits, to_bit);
+ }
+ return table;
+}
+
+constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
+constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
+constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
+constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
+
+struct AstcBufferData {
+ decltype(EncodingsValues) encoding_values = EncodingsValues;
+ decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
+ decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
+ decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
+ decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
+} constexpr ASTC_BUFFER_DATA;
} // 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 @@
#include "video_core/textures/texture.h"
namespace Tegra::Texture {
-
namespace {
-/**
- * This table represents the internal swizzle of a gob, in format 16 bytes x 2 sector packing.
- * Calculates the offset of an (x, y) position within a swizzled texture.
- * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
- */
-constexpr SwizzleTable MakeSwizzleTableConst() {
- SwizzleTable table{};
- for (u32 y = 0; y < table.size(); ++y) {
- for (u32 x = 0; x < table[0].size(); ++x) {
- table[y][x] = ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
- (y % 2) * 16 + (x % 16);
- }
- }
- return table;
-}
-
-constexpr SwizzleTable SWIZZLE_TABLE = MakeSwizzleTableConst();
-
template <bool TO_LINEAR>
void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width,
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
}
} // Anonymous namespace
-SwizzleTable MakeSwizzleTable() {
- return SWIZZLE_TABLE;
-}
-
void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth,
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_
using SwizzleTable = std::array<std::array<u32, GOB_SIZE_X>, GOB_SIZE_Y>;
-/// Returns a z-order swizzle table
-SwizzleTable MakeSwizzleTable();
+/**
+ * This table represents the internal swizzle of a gob, in format 16 bytes x 2 sector packing.
+ * Calculates the offset of an (x, y) position within a swizzled texture.
+ * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
+ */
+constexpr SwizzleTable MakeSwizzleTable() {
+ SwizzleTable table{};
+ for (u32 y = 0; y < table.size(); ++y) {
+ for (u32 x = 0; x < table[0].size(); ++x) {
+ table[y][x] = ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
+ (y % 2) * 16 + (x % 16);
+ }
+ }
+ return table;
+}
+constexpr SwizzleTable SWIZZLE_TABLE = MakeSwizzleTable();
/// Unswizzles a block linear texture into linear memory.
void 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 @@
#include <array>
#include "common/cityhash.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "video_core/textures/texture.h"
using 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 @@
#include <memory>
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#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 @@
#include <vector>
#include "common/assert.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "video_core/vulkan_common/nsight_aftermath_tracker.h"
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
@@ -51,7 +51,7 @@ constexpr std::array REQUIRED_EXTENSIONS{
#ifdef _WIN32
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
#endif
-#ifdef __linux__
+#ifdef __unix__
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
#endif
};
@@ -294,6 +294,15 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
};
SetNext(next, bit8_storage);
+ VkPhysicalDeviceRobustness2FeaturesEXT robustness2{
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT,
+ .pNext = nullptr,
+ .robustBufferAccess2 = true,
+ .robustImageAccess2 = true,
+ .nullDescriptor = true,
+ };
+ SetNext(next, robustness2);
+
VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT,
.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:
: memory{std::move(memory_)}, allocation_size{allocation_size_}, property_flags{properties},
shifted_memory_type{1U << type} {}
-#if defined(_WIN32) || defined(__linux__)
+#if defined(_WIN32) || defined(__unix__)
~MemoryAllocation() {
if (owning_opengl_handle != 0) {
glDeleteMemoryObjectsEXT(1, &owning_opengl_handle);
@@ -114,7 +114,7 @@ public:
}
return owning_opengl_handle;
}
-#elif __linux__
+#elif __unix__
[[nodiscard]] u32 ExportOpenGLHandle() {
if (!owning_opengl_handle) {
glCreateMemoryObjectsEXT(1, &owning_opengl_handle);
@@ -165,7 +165,7 @@ private:
const u32 shifted_memory_type; ///< Shifted Vulkan memory type.
std::vector<Range> commits; ///< All commit ranges done from this allocation.
std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before.
-#if defined(_WIN32) || defined(__linux__)
+#if defined(_WIN32) || defined(__unix__)
u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle.
#endif
};
@@ -249,7 +249,7 @@ void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u6
.pNext = nullptr,
#ifdef _WIN32
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
-#elif __linux__
+#elif __unix__
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
#else
.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
applets/profile_select.h
applets/software_keyboard.cpp
applets/software_keyboard.h
+ applets/software_keyboard.ui
applets/web_browser.cpp
applets/web_browser.h
bootmanager.cpp
@@ -143,6 +144,9 @@ add_executable(yuzu
uisettings.h
util/limitable_input_dialog.cpp
util/limitable_input_dialog.h
+ util/overlay_dialog.cpp
+ util/overlay_dialog.h
+ util/overlay_dialog.ui
util/sequence_dialog/sequence_dialog.cpp
util/sequence_dialog/sequence_dialog.h
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 @@
#include "yuzu/applets/controller.h"
#include "yuzu/configuration/configure_input.h"
#include "yuzu/configuration/configure_input_profile_dialog.h"
+#include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_vibration.h"
#include "yuzu/configuration/input_profiles.h"
#include "yuzu/main.h"
@@ -206,6 +207,9 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
connect(ui->vibrationButton, &QPushButton::clicked, this,
&QtControllerSelectorDialog::CallConfigureVibrationDialog);
+ connect(ui->motionButton, &QPushButton::clicked, this,
+ &QtControllerSelectorDialog::CallConfigureMotionTouchDialog);
+
connect(ui->inputConfigButton, &QPushButton::clicked, this,
&QtControllerSelectorDialog::CallConfigureInputProfileDialog);
@@ -276,6 +280,18 @@ void QtControllerSelectorDialog::CallConfigureVibrationDialog() {
}
}
+void QtControllerSelectorDialog::CallConfigureMotionTouchDialog() {
+ ConfigureMotionTouch dialog(this, input_subsystem);
+
+ dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
+ Qt::WindowSystemMenuHint);
+ dialog.setWindowModality(Qt::WindowModal);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ dialog.ApplyConfiguration();
+ }
+}
+
void QtControllerSelectorDialog::CallConfigureInputProfileDialog() {
ConfigureInputProfileDialog dialog(this, input_subsystem, input_profiles.get());
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:
// Initializes the "Configure Vibration" Dialog.
void CallConfigureVibrationDialog();
+ // Initializes the "Configure Motion / Touch" Dialog.
+ void CallConfigureMotionTouchDialog();
+
// Initializes the "Create Input Profile" Dialog.
void CallConfigureInputProfileDialog();
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;
void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const {
callback = std::move(finished);
emit MainWindowDisplayError(
- tr("An error has occurred.\nPlease try again or contact the developer of the "
- "software.\n\nError Code: %1-%2 (0x%3)")
+ tr("Error Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
- .arg(error.raw, 8, 16, QChar::fromLatin1('0')));
+ .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
+ tr("An error has occurred.\nPlease try again or contact the developer of the software."));
}
void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
@@ -32,13 +32,14 @@ void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::secon
const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count());
emit MainWindowDisplayError(
- tr("An error occurred on %1 at %2.\nPlease try again or contact the "
- "developer of the software.\n\nError Code: %3-%4 (0x%5)")
- .arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy")))
- .arg(date_time.toString(QStringLiteral("h:mm:ss A")))
+ tr("Error Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
- .arg(error.raw, 8, 16, QChar::fromLatin1('0')));
+ .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
+ tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the "
+ "software.")
+ .arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy")))
+ .arg(date_time.toString(QStringLiteral("h:mm:ss A"))));
}
void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text,
@@ -46,10 +47,11 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te
std::function<void()> finished) const {
callback = std::move(finished);
emit MainWindowDisplayError(
- tr("An error has occurred.\nError Code: %1-%2 (0x%3)\n\n%4\n\n%5")
+ tr("Error Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
- .arg(error.raw, 8, 16, QChar::fromLatin1('0'))
+ .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
+ tr("An error has occurred.\n\n%1\n\n%2")
.arg(QString::fromStdString(dialog_text))
.arg(QString::fromStdString(fullscreen_text)));
}
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:
std::function<void()> finished) const override;
signals:
- void MainWindowDisplayError(QString error) const;
+ void MainWindowDisplayError(QString error_code, QString error_text) const;
private:
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 @@
-// Copyright 2018 yuzu Emulator Project
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <algorithm>
-#include <mutex>
-#include <QDialogButtonBox>
-#include <QFont>
-#include <QLabel>
-#include <QLineEdit>
-#include <QVBoxLayout>
-#include "core/hle/lock.h"
+#include <QCursor>
+#include <QKeyEvent>
+#include <QScreen>
+
+#include "common/logging/log.h"
+#include "common/settings.h"
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/frontend/input_interpreter.h"
+#include "ui_software_keyboard.h"
#include "yuzu/applets/software_keyboard.h"
#include "yuzu/main.h"
+#include "yuzu/util/overlay_dialog.h"
+
+namespace {
+
+using namespace Service::AM::Applets;
+
+constexpr float BASE_HEADER_FONT_SIZE = 23.0f;
+constexpr float BASE_SUB_FONT_SIZE = 17.0f;
+constexpr float BASE_EDITOR_FONT_SIZE = 26.0f;
+constexpr float BASE_CHAR_BUTTON_FONT_SIZE = 28.0f;
+constexpr float BASE_LABEL_BUTTON_FONT_SIZE = 18.0f;
+constexpr float BASE_ICON_BUTTON_SIZE = 36.0f;
+[[maybe_unused]] constexpr float BASE_WIDTH = 1280.0f;
+constexpr float BASE_HEIGHT = 720.0f;
+
+} // Anonymous namespace
+
+QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
+ QWidget* parent, Core::System& system_, bool is_inline_,
+ Core::Frontend::KeyboardInitializeParameters initialize_parameters_)
+ : QDialog(parent), ui{std::make_unique<Ui::QtSoftwareKeyboardDialog>()}, system{system_},
+ is_inline{is_inline_}, initialize_parameters{std::move(initialize_parameters_)} {
+ ui->setupUi(this);
+
+ setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint |
+ Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint);
+ setWindowModality(Qt::WindowModal);
+ setAttribute(Qt::WA_DeleteOnClose);
+ setAttribute(Qt::WA_TranslucentBackground);
+
+ keyboard_buttons = {{
+ {{
+ {
+ ui->button_1,
+ ui->button_2,
+ ui->button_3,
+ ui->button_4,
+ ui->button_5,
+ ui->button_6,
+ ui->button_7,
+ ui->button_8,
+ ui->button_9,
+ ui->button_0,
+ ui->button_minus,
+ ui->button_backspace,
+ },
+ {
+ ui->button_q,
+ ui->button_w,
+ ui->button_e,
+ ui->button_r,
+ ui->button_t,
+ ui->button_y,
+ ui->button_u,
+ ui->button_i,
+ ui->button_o,
+ ui->button_p,
+ ui->button_slash,
+ ui->button_return,
+ },
+ {
+ ui->button_a,
+ ui->button_s,
+ ui->button_d,
+ ui->button_f,
+ ui->button_g,
+ ui->button_h,
+ ui->button_j,
+ ui->button_k,
+ ui->button_l,
+ ui->button_colon,
+ ui->button_apostrophe,
+ ui->button_return,
+ },
+ {
+ ui->button_z,
+ ui->button_x,
+ ui->button_c,
+ ui->button_v,
+ ui->button_b,
+ ui->button_n,
+ ui->button_m,
+ ui->button_comma,
+ ui->button_dot,
+ ui->button_question,
+ ui->button_exclamation,
+ ui->button_ok,
+ },
+ {
+ ui->button_shift,
+ ui->button_shift,
+ ui->button_space,
+ ui->button_space,
+ ui->button_space,
+ ui->button_space,
+ ui->button_space,
+ ui->button_space,
+ ui->button_space,
+ ui->button_space,
+ ui->button_space,
+ ui->button_ok,
+ },
+ }},
+ {{
+ {
+ ui->button_hash,
+ ui->button_left_bracket,
+ ui->button_right_bracket,
+ ui->button_dollar,
+ ui->button_percent,
+ ui->button_circumflex,
+ ui->button_ampersand,
+ ui->button_asterisk,
+ ui->button_left_parenthesis,
+ ui->button_right_parenthesis,
+ ui->button_underscore,
+ ui->button_backspace_shift,
+ },
+ {
+ ui->button_q_shift,
+ ui->button_w_shift,
+ ui->button_e_shift,
+ ui->button_r_shift,
+ ui->button_t_shift,
+ ui->button_y_shift,
+ ui->button_u_shift,
+ ui->button_i_shift,
+ ui->button_o_shift,
+ ui->button_p_shift,
+ ui->button_at,
+ ui->button_return_shift,
+ },
+ {
+ ui->button_a_shift,
+ ui->button_s_shift,
+ ui->button_d_shift,
+ ui->button_f_shift,
+ ui->button_g_shift,
+ ui->button_h_shift,
+ ui->button_j_shift,
+ ui->button_k_shift,
+ ui->button_l_shift,
+ ui->button_semicolon,
+ ui->button_quotation,
+ ui->button_return_shift,
+ },
+ {
+ ui->button_z_shift,
+ ui->button_x_shift,
+ ui->button_c_shift,
+ ui->button_v_shift,
+ ui->button_b_shift,
+ ui->button_n_shift,
+ ui->button_m_shift,
+ ui->button_less_than,
+ ui->button_greater_than,
+ ui->button_plus,
+ ui->button_equal,
+ ui->button_ok_shift,
+ },
+ {
+ ui->button_shift_shift,
+ ui->button_shift_shift,
+ ui->button_space_shift,
+ ui->button_space_shift,
+ ui->button_space_shift,
+ ui->button_space_shift,
+ ui->button_space_shift,
+ ui->button_space_shift,
+ ui->button_space_shift,
+ ui->button_space_shift,
+ ui->button_space_shift,
+ ui->button_ok_shift,
+ },
+ }},
+ }};
-QtSoftwareKeyboardValidator::QtSoftwareKeyboardValidator(
- Core::Frontend::SoftwareKeyboardParameters parameters)
- : parameters(std::move(parameters)) {}
+ numberpad_buttons = {{
+ {
+ ui->button_1_num,
+ ui->button_2_num,
+ ui->button_3_num,
+ ui->button_backspace_num,
+ },
+ {
+ ui->button_4_num,
+ ui->button_5_num,
+ ui->button_6_num,
+ ui->button_ok_num,
+ },
+ {
+ ui->button_7_num,
+ ui->button_8_num,
+ ui->button_9_num,
+ ui->button_ok_num,
+ },
+ {
+ nullptr,
+ ui->button_0_num,
+ nullptr,
+ ui->button_ok_num,
+ },
+ }};
-QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int& pos) const {
- if (input.size() > static_cast<s64>(parameters.max_length)) {
- return Invalid;
+ all_buttons = {
+ ui->button_1,
+ ui->button_2,
+ ui->button_3,
+ ui->button_4,
+ ui->button_5,
+ ui->button_6,
+ ui->button_7,
+ ui->button_8,
+ ui->button_9,
+ ui->button_0,
+ ui->button_minus,
+ ui->button_backspace,
+ ui->button_q,
+ ui->button_w,
+ ui->button_e,
+ ui->button_r,
+ ui->button_t,
+ ui->button_y,
+ ui->button_u,
+ ui->button_i,
+ ui->button_o,
+ ui->button_p,
+ ui->button_slash,
+ ui->button_return,
+ ui->button_a,
+ ui->button_s,
+ ui->button_d,
+ ui->button_f,
+ ui->button_g,
+ ui->button_h,
+ ui->button_j,
+ ui->button_k,
+ ui->button_l,
+ ui->button_colon,
+ ui->button_apostrophe,
+ ui->button_z,
+ ui->button_x,
+ ui->button_c,
+ ui->button_v,
+ ui->button_b,
+ ui->button_n,
+ ui->button_m,
+ ui->button_comma,
+ ui->button_dot,
+ ui->button_question,
+ ui->button_exclamation,
+ ui->button_ok,
+ ui->button_shift,
+ ui->button_space,
+ ui->button_hash,
+ ui->button_left_bracket,
+ ui->button_right_bracket,
+ ui->button_dollar,
+ ui->button_percent,
+ ui->button_circumflex,
+ ui->button_ampersand,
+ ui->button_asterisk,
+ ui->button_left_parenthesis,
+ ui->button_right_parenthesis,
+ ui->button_underscore,
+ ui->button_backspace_shift,
+ ui->button_q_shift,
+ ui->button_w_shift,
+ ui->button_e_shift,
+ ui->button_r_shift,
+ ui->button_t_shift,
+ ui->button_y_shift,
+ ui->button_u_shift,
+ ui->button_i_shift,
+ ui->button_o_shift,
+ ui->button_p_shift,
+ ui->button_at,
+ ui->button_return_shift,
+ ui->button_a_shift,
+ ui->button_s_shift,
+ ui->button_d_shift,
+ ui->button_f_shift,
+ ui->button_g_shift,
+ ui->button_h_shift,
+ ui->button_j_shift,
+ ui->button_k_shift,
+ ui->button_l_shift,
+ ui->button_semicolon,
+ ui->button_quotation,
+ ui->button_z_shift,
+ ui->button_x_shift,
+ ui->button_c_shift,
+ ui->button_v_shift,
+ ui->button_b_shift,
+ ui->button_n_shift,
+ ui->button_m_shift,
+ ui->button_less_than,
+ ui->button_greater_than,
+ ui->button_plus,
+ ui->button_equal,
+ ui->button_ok_shift,
+ ui->button_shift_shift,
+ ui->button_space_shift,
+ ui->button_1_num,
+ ui->button_2_num,
+ ui->button_3_num,
+ ui->button_backspace_num,
+ ui->button_4_num,
+ ui->button_5_num,
+ ui->button_6_num,
+ ui->button_ok_num,
+ ui->button_7_num,
+ ui->button_8_num,
+ ui->button_9_num,
+ ui->button_0_num,
+ };
+
+ SetupMouseHover();
+
+ if (!initialize_parameters.ok_text.empty()) {
+ ui->button_ok->setText(QString::fromStdU16String(initialize_parameters.ok_text));
}
- if (parameters.disable_space && input.contains(QLatin1Char{' '})) {
- return Invalid;
+
+ ui->label_header->setText(QString::fromStdU16String(initialize_parameters.header_text));
+ ui->label_sub->setText(QString::fromStdU16String(initialize_parameters.sub_text));
+
+ current_text = initialize_parameters.initial_text;
+ cursor_position = initialize_parameters.initial_cursor_position;
+
+ SetTextDrawType();
+
+ for (auto* button : all_buttons) {
+ connect(button, &QPushButton::clicked, this, [this, button](bool) {
+ if (is_inline) {
+ InlineKeyboardButtonClicked(button);
+ } else {
+ NormalKeyboardButtonClicked(button);
+ }
+ });
}
- if (parameters.disable_address && input.contains(QLatin1Char{'@'})) {
- return Invalid;
+
+ // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend
+ if (system.IsPoweredOn()) {
+ input_interpreter = std::make_unique<InputInterpreter>(system);
}
- if (parameters.disable_percent && input.contains(QLatin1Char{'%'})) {
- return Invalid;
+}
+
+QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() {
+ StopInputThread();
+}
+
+void QtSoftwareKeyboardDialog::ShowNormalKeyboard(QPoint pos, QSize size) {
+ if (isVisible()) {
+ return;
}
- if (parameters.disable_slash &&
- (input.contains(QLatin1Char{'/'}) || input.contains(QLatin1Char{'\\'}))) {
- return Invalid;
+
+ MoveAndResizeWindow(pos, size);
+
+ SetKeyboardType();
+ SetPasswordMode();
+ SetControllerImage();
+ DisableKeyboardButtons();
+ SetBackspaceOkEnabled();
+
+ open();
+}
+
+void QtSoftwareKeyboardDialog::ShowTextCheckDialog(
+ Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) {
+ switch (text_check_result) {
+ case SwkbdTextCheckResult::Success:
+ case SwkbdTextCheckResult::Silent:
+ default:
+ break;
+ case SwkbdTextCheckResult::Failure: {
+ StopInputThread();
+
+ OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message),
+ QString{}, tr("OK"), Qt::AlignCenter);
+ dialog.exec();
+
+ StartInputThread();
+ break;
}
- if (parameters.disable_number &&
- std::any_of(input.begin(), input.end(), [](QChar c) { return c.isDigit(); })) {
- return Invalid;
+ case SwkbdTextCheckResult::Confirm: {
+ StopInputThread();
+
+ OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message),
+ tr("Cancel"), tr("OK"), Qt::AlignCenter);
+ if (dialog.exec() == QDialog::Accepted) {
+ emit SubmitNormalText(SwkbdResult::Ok, current_text);
+ break;
+ }
+
+ StartInputThread();
+ break;
}
+ }
+}
+
+void QtSoftwareKeyboardDialog::ShowInlineKeyboard(
+ Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, QSize size) {
+ MoveAndResizeWindow(pos, size);
+
+ ui->topOSK->setStyleSheet(QStringLiteral("background: rgba(0, 0, 0, 0);"));
+
+ ui->headerOSK->hide();
+ ui->subOSK->hide();
+ ui->inputOSK->hide();
+ ui->charactersOSK->hide();
+ ui->inputBoxOSK->hide();
+ ui->charactersBoxOSK->hide();
+
+ initialize_parameters.max_text_length = appear_parameters.max_text_length;
+ initialize_parameters.min_text_length = appear_parameters.min_text_length;
+ initialize_parameters.type = appear_parameters.type;
+ initialize_parameters.key_disable_flags = appear_parameters.key_disable_flags;
+ initialize_parameters.enable_backspace_button = appear_parameters.enable_backspace_button;
+ initialize_parameters.enable_return_button = appear_parameters.enable_return_button;
+ initialize_parameters.disable_cancel_button = initialize_parameters.disable_cancel_button;
- if (parameters.disable_download_code && std::any_of(input.begin(), input.end(), [](QChar c) {
- return c == QLatin1Char{'O'} || c == QLatin1Char{'I'};
- })) {
- return Invalid;
+ SetKeyboardType();
+ SetControllerImage();
+ DisableKeyboardButtons();
+ SetBackspaceOkEnabled();
+
+ open();
+}
+
+void QtSoftwareKeyboardDialog::HideInlineKeyboard() {
+ StopInputThread();
+ QDialog::hide();
+}
+
+void QtSoftwareKeyboardDialog::InlineTextChanged(
+ Core::Frontend::InlineTextParameters text_parameters) {
+ current_text = text_parameters.input_text;
+ cursor_position = text_parameters.cursor_position;
+
+ SetBackspaceOkEnabled();
+}
+
+void QtSoftwareKeyboardDialog::ExitKeyboard() {
+ StopInputThread();
+ QDialog::done(QDialog::Accepted);
+}
+
+void QtSoftwareKeyboardDialog::open() {
+ QDialog::open();
+
+ row = 0;
+ column = 0;
+
+ const auto* const curr_button =
+ keyboard_buttons[static_cast<int>(bottom_osk_index)][row][column];
+
+ // This is a workaround for setFocus() randomly not showing focus in the UI
+ QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center()));
+
+ StartInputThread();
+}
+
+void QtSoftwareKeyboardDialog::reject() {
+ // Pressing the ESC key in a dialog calls QDialog::reject().
+ // We will override this behavior to the "Cancel" action on the software keyboard.
+ if (is_inline) {
+ emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
+ } else {
+ emit SubmitNormalText(SwkbdResult::Cancel, current_text);
}
+}
+
+void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) {
+ if (!is_inline) {
+ QDialog::keyPressEvent(event);
+ return;
+ }
+
+ const auto entered_key = event->key();
- return Acceptable;
+ switch (entered_key) {
+ case Qt::Key_Escape:
+ QDialog::keyPressEvent(event);
+ return;
+ case Qt::Key_Backspace:
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ ui->button_backspace->click();
+ break;
+ case BottomOSKIndex::UpperCase:
+ ui->button_backspace_shift->click();
+ break;
+ case BottomOSKIndex::NumberPad:
+ ui->button_backspace_num->click();
+ break;
+ default:
+ break;
+ }
+ return;
+ case Qt::Key_Return:
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ ui->button_ok->click();
+ break;
+ case BottomOSKIndex::UpperCase:
+ ui->button_ok_shift->click();
+ break;
+ case BottomOSKIndex::NumberPad:
+ ui->button_ok_num->click();
+ break;
+ default:
+ break;
+ }
+ return;
+ case Qt::Key_Left:
+ MoveTextCursorDirection(Direction::Left);
+ return;
+ case Qt::Key_Right:
+ MoveTextCursorDirection(Direction::Right);
+ return;
+ default:
+ break;
+ }
+
+ const auto entered_text = event->text();
+
+ if (entered_text.isEmpty()) {
+ return;
+ }
+
+ InlineTextInsertString(entered_text.toStdU16String());
}
-QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
- QWidget* parent, Core::Frontend::SoftwareKeyboardParameters parameters_)
- : QDialog(parent), parameters(std::move(parameters_)) {
- layout = new QVBoxLayout;
-
- header_label = new QLabel(QString::fromStdU16String(parameters.header_text));
- header_label->setFont({header_label->font().family(), 11, QFont::Bold});
- if (header_label->text().isEmpty())
- header_label->setText(tr("Enter text:"));
-
- sub_label = new QLabel(QString::fromStdU16String(parameters.sub_text));
- sub_label->setFont({sub_label->font().family(), sub_label->font().pointSize(),
- sub_label->font().weight(), true});
- sub_label->setHidden(parameters.sub_text.empty());
-
- guide_label = new QLabel(QString::fromStdU16String(parameters.guide_text));
- guide_label->setHidden(parameters.guide_text.empty());
-
- length_label = new QLabel(QStringLiteral("0/%1").arg(parameters.max_length));
- length_label->setAlignment(Qt::AlignRight);
- length_label->setFont({length_label->font().family(), 8});
-
- line_edit = new QLineEdit;
- line_edit->setValidator(new QtSoftwareKeyboardValidator(parameters));
- line_edit->setMaxLength(static_cast<int>(parameters.max_length));
- line_edit->setText(QString::fromStdU16String(parameters.initial_text));
- line_edit->setCursorPosition(
- parameters.cursor_at_beginning ? 0 : static_cast<int>(parameters.initial_text.size()));
- line_edit->setEchoMode(parameters.password ? QLineEdit::Password : QLineEdit::Normal);
-
- connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) {
- length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length));
- });
-
- buttons = new QDialogButtonBox(QDialogButtonBox::Cancel);
- if (parameters.submit_text.empty()) {
- buttons->addButton(QDialogButtonBox::Ok);
+void QtSoftwareKeyboardDialog::MoveAndResizeWindow(QPoint pos, QSize size) {
+ QDialog::move(pos);
+ QDialog::resize(size);
+
+ // High DPI
+ const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f;
+
+ RescaleKeyboardElements(size.width(), size.height(), dpi_scale);
+}
+
+void QtSoftwareKeyboardDialog::RescaleKeyboardElements(float width, float height, float dpi_scale) {
+ const auto header_font_size = BASE_HEADER_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+ const auto sub_font_size = BASE_SUB_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+ const auto editor_font_size = BASE_EDITOR_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+ const auto char_button_font_size =
+ BASE_CHAR_BUTTON_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+ const auto label_button_font_size =
+ BASE_LABEL_BUTTON_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+
+ QFont header_font(QStringLiteral("MS Shell Dlg 2"), header_font_size, QFont::Normal);
+ QFont sub_font(QStringLiteral("MS Shell Dlg 2"), sub_font_size, QFont::Normal);
+ QFont editor_font(QStringLiteral("MS Shell Dlg 2"), editor_font_size, QFont::Normal);
+ QFont char_button_font(QStringLiteral("MS Shell Dlg 2"), char_button_font_size, QFont::Normal);
+ QFont label_button_font(QStringLiteral("MS Shell Dlg 2"), label_button_font_size,
+ QFont::Normal);
+
+ ui->label_header->setFont(header_font);
+ ui->label_sub->setFont(sub_font);
+ ui->line_edit_osk->setFont(editor_font);
+ ui->text_edit_osk->setFont(editor_font);
+ ui->label_characters->setFont(sub_font);
+ ui->label_characters_box->setFont(sub_font);
+
+ ui->label_shift->setFont(label_button_font);
+ ui->label_shift_shift->setFont(label_button_font);
+ ui->label_cancel->setFont(label_button_font);
+ ui->label_cancel_shift->setFont(label_button_font);
+ ui->label_cancel_num->setFont(label_button_font);
+ ui->label_enter->setFont(label_button_font);
+ ui->label_enter_shift->setFont(label_button_font);
+ ui->label_enter_num->setFont(label_button_font);
+
+ for (auto* button : all_buttons) {
+ if (button == ui->button_return || button == ui->button_return_shift) {
+ button->setFont(label_button_font);
+ continue;
+ }
+
+ if (button == ui->button_space || button == ui->button_space_shift) {
+ button->setFont(label_button_font);
+ continue;
+ }
+
+ if (button == ui->button_shift || button == ui->button_shift_shift) {
+ button->setFont(label_button_font);
+ button->setIconSize(QSize(BASE_ICON_BUTTON_SIZE, BASE_ICON_BUTTON_SIZE) *
+ (height / BASE_HEIGHT));
+ continue;
+ }
+
+ if (button == ui->button_backspace || button == ui->button_backspace_shift ||
+ button == ui->button_backspace_num) {
+ button->setFont(label_button_font);
+ button->setIconSize(QSize(BASE_ICON_BUTTON_SIZE, BASE_ICON_BUTTON_SIZE) *
+ (height / BASE_HEIGHT));
+ continue;
+ }
+
+ if (button == ui->button_ok || button == ui->button_ok_shift ||
+ button == ui->button_ok_num) {
+ button->setFont(label_button_font);
+ continue;
+ }
+
+ button->setFont(char_button_font);
+ }
+}
+
+void QtSoftwareKeyboardDialog::SetKeyboardType() {
+ switch (initialize_parameters.type) {
+ case SwkbdType::Normal:
+ case SwkbdType::Qwerty:
+ case SwkbdType::Unknown3:
+ case SwkbdType::Latin:
+ case SwkbdType::SimplifiedChinese:
+ case SwkbdType::TraditionalChinese:
+ case SwkbdType::Korean:
+ default: {
+ bottom_osk_index = BottomOSKIndex::LowerCase;
+ ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
+
+ ui->verticalLayout_2->setStretch(0, 320);
+ ui->verticalLayout_2->setStretch(1, 400);
+
+ ui->gridLineOSK->setRowStretch(5, 94);
+ ui->gridBoxOSK->setRowStretch(2, 81);
+ break;
+ }
+ case SwkbdType::NumberPad: {
+ bottom_osk_index = BottomOSKIndex::NumberPad;
+ ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
+
+ ui->verticalLayout_2->setStretch(0, 370);
+ ui->verticalLayout_2->setStretch(1, 350);
+
+ ui->gridLineOSK->setRowStretch(5, 144);
+ ui->gridBoxOSK->setRowStretch(2, 131);
+ break;
+ }
+ }
+}
+
+void QtSoftwareKeyboardDialog::SetPasswordMode() {
+ switch (initialize_parameters.password_mode) {
+ case SwkbdPasswordMode::Disabled:
+ default:
+ ui->line_edit_osk->setEchoMode(QLineEdit::Normal);
+ break;
+ case SwkbdPasswordMode::Enabled:
+ ui->line_edit_osk->setEchoMode(QLineEdit::Password);
+ break;
+ }
+}
+
+void QtSoftwareKeyboardDialog::SetTextDrawType() {
+ switch (initialize_parameters.text_draw_type) {
+ case SwkbdTextDrawType::Line:
+ case SwkbdTextDrawType::DownloadCode: {
+ ui->topOSK->setCurrentIndex(0);
+
+ if (initialize_parameters.max_text_length <= 10) {
+ ui->gridLineOSK->setColumnStretch(0, 390);
+ ui->gridLineOSK->setColumnStretch(1, 500);
+ ui->gridLineOSK->setColumnStretch(2, 390);
+ } else {
+ ui->gridLineOSK->setColumnStretch(0, 130);
+ ui->gridLineOSK->setColumnStretch(1, 1020);
+ ui->gridLineOSK->setColumnStretch(2, 130);
+ }
+
+ if (is_inline) {
+ return;
+ }
+
+ connect(ui->line_edit_osk, &QLineEdit::textChanged, [this](const QString& changed_string) {
+ const auto is_valid = ValidateInputText(changed_string);
+
+ const auto text_length = static_cast<u32>(changed_string.length());
+
+ ui->label_characters->setText(QStringLiteral("%1/%2")
+ .arg(text_length)
+ .arg(initialize_parameters.max_text_length));
+
+ ui->button_ok->setEnabled(is_valid);
+ ui->button_ok_shift->setEnabled(is_valid);
+ ui->button_ok_num->setEnabled(is_valid);
+
+ ui->line_edit_osk->setFocus();
+ });
+
+ connect(ui->line_edit_osk, &QLineEdit::cursorPositionChanged,
+ [this](int old_cursor_position, int new_cursor_position) {
+ ui->button_backspace->setEnabled(
+ initialize_parameters.enable_backspace_button && new_cursor_position > 0);
+ ui->button_backspace_shift->setEnabled(
+ initialize_parameters.enable_backspace_button && new_cursor_position > 0);
+ ui->button_backspace_num->setEnabled(
+ initialize_parameters.enable_backspace_button && new_cursor_position > 0);
+
+ ui->line_edit_osk->setFocus();
+ });
+
+ connect(ui->line_edit_osk, &QLineEdit::returnPressed, [this] {
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ ui->button_ok->click();
+ break;
+ case BottomOSKIndex::UpperCase:
+ ui->button_ok_shift->click();
+ break;
+ case BottomOSKIndex::NumberPad:
+ ui->button_ok_num->click();
+ break;
+ default:
+ break;
+ }
+ });
+
+ ui->line_edit_osk->setPlaceholderText(
+ QString::fromStdU16String(initialize_parameters.guide_text));
+ ui->line_edit_osk->setText(QString::fromStdU16String(initialize_parameters.initial_text));
+ ui->line_edit_osk->setMaxLength(initialize_parameters.max_text_length);
+ ui->line_edit_osk->setCursorPosition(initialize_parameters.initial_cursor_position);
+
+ ui->label_characters->setText(QStringLiteral("%1/%2")
+ .arg(initialize_parameters.initial_text.size())
+ .arg(initialize_parameters.max_text_length));
+ break;
+ }
+ case SwkbdTextDrawType::Box:
+ default: {
+ ui->topOSK->setCurrentIndex(1);
+
+ if (is_inline) {
+ return;
+ }
+
+ connect(ui->text_edit_osk, &QTextEdit::textChanged, [this] {
+ if (static_cast<u32>(ui->text_edit_osk->toPlainText().length()) >
+ initialize_parameters.max_text_length) {
+ auto text_cursor = ui->text_edit_osk->textCursor();
+ ui->text_edit_osk->setTextCursor(text_cursor);
+ text_cursor.deletePreviousChar();
+ }
+
+ const auto is_valid = ValidateInputText(ui->text_edit_osk->toPlainText());
+
+ const auto text_length = static_cast<u32>(ui->text_edit_osk->toPlainText().length());
+
+ ui->label_characters_box->setText(QStringLiteral("%1/%2")
+ .arg(text_length)
+ .arg(initialize_parameters.max_text_length));
+
+ ui->button_ok->setEnabled(is_valid);
+ ui->button_ok_shift->setEnabled(is_valid);
+ ui->button_ok_num->setEnabled(is_valid);
+
+ ui->text_edit_osk->setFocus();
+ });
+
+ connect(ui->text_edit_osk, &QTextEdit::cursorPositionChanged, [this] {
+ const auto new_cursor_position = ui->text_edit_osk->textCursor().position();
+
+ ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button &&
+ new_cursor_position > 0);
+ ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button &&
+ new_cursor_position > 0);
+ ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button &&
+ new_cursor_position > 0);
+
+ ui->text_edit_osk->setFocus();
+ });
+
+ ui->text_edit_osk->setPlaceholderText(
+ QString::fromStdU16String(initialize_parameters.guide_text));
+ ui->text_edit_osk->setText(QString::fromStdU16String(initialize_parameters.initial_text));
+ ui->text_edit_osk->moveCursor(initialize_parameters.initial_cursor_position == 0
+ ? QTextCursor::Start
+ : QTextCursor::End);
+
+ ui->label_characters_box->setText(QStringLiteral("%1/%2")
+ .arg(initialize_parameters.initial_text.size())
+ .arg(initialize_parameters.max_text_length));
+ break;
+ }
+ }
+}
+
+void QtSoftwareKeyboardDialog::SetControllerImage() {
+ const auto controller_type = Settings::values.players.GetValue()[8].connected
+ ? Settings::values.players.GetValue()[8].controller_type
+ : Settings::values.players.GetValue()[0].controller_type;
+
+ const QString theme = [] {
+ if (QIcon::themeName().contains(QStringLiteral("dark")) ||
+ QIcon::themeName().contains(QStringLiteral("midnight"))) {
+ return QStringLiteral("_dark");
+ } else {
+ return QString{};
+ }
+ }();
+
+ switch (controller_type) {
+ case Settings::ControllerType::ProController:
+ case Settings::ControllerType::GameCube:
+ ui->icon_controller->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
+ ui->icon_controller_shift->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
+ ui->icon_controller_num->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
+ break;
+ case Settings::ControllerType::DualJoyconDetached:
+ ui->icon_controller->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
+ ui->icon_controller_shift->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
+ ui->icon_controller_num->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
+ break;
+ case Settings::ControllerType::LeftJoycon:
+ ui->icon_controller->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
+ .arg(theme));
+ ui->icon_controller_shift->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
+ .arg(theme));
+ ui->icon_controller_num->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
+ .arg(theme));
+ break;
+ case Settings::ControllerType::RightJoycon:
+ ui->icon_controller->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
+ .arg(theme));
+ ui->icon_controller_shift->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
+ .arg(theme));
+ ui->icon_controller_num->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
+ .arg(theme));
+ break;
+ case Settings::ControllerType::Handheld:
+ ui->icon_controller->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
+ ui->icon_controller_shift->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
+ ui->icon_controller_num->setStyleSheet(
+ QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
+ break;
+ default:
+ break;
+ }
+}
+
+void QtSoftwareKeyboardDialog::DisableKeyboardButtons() {
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ case BottomOSKIndex::UpperCase:
+ default: {
+ for (const auto& keys : keyboard_buttons) {
+ for (const auto& rows : keys) {
+ for (auto* button : rows) {
+ if (!button) {
+ continue;
+ }
+
+ button->setEnabled(true);
+ }
+ }
+ }
+
+ const auto& key_disable_flags = initialize_parameters.key_disable_flags;
+
+ ui->button_space->setDisabled(key_disable_flags.space);
+ ui->button_space_shift->setDisabled(key_disable_flags.space);
+
+ ui->button_at->setDisabled(key_disable_flags.at || key_disable_flags.username);
+
+ ui->button_percent->setDisabled(key_disable_flags.percent || key_disable_flags.username);
+
+ ui->button_slash->setDisabled(key_disable_flags.slash);
+
+ ui->button_1->setDisabled(key_disable_flags.numbers);
+ ui->button_2->setDisabled(key_disable_flags.numbers);
+ ui->button_3->setDisabled(key_disable_flags.numbers);
+ ui->button_4->setDisabled(key_disable_flags.numbers);
+ ui->button_5->setDisabled(key_disable_flags.numbers);
+ ui->button_6->setDisabled(key_disable_flags.numbers);
+ ui->button_7->setDisabled(key_disable_flags.numbers);
+ ui->button_8->setDisabled(key_disable_flags.numbers);
+ ui->button_9->setDisabled(key_disable_flags.numbers);
+ ui->button_0->setDisabled(key_disable_flags.numbers);
+
+ ui->button_return->setEnabled(initialize_parameters.enable_return_button);
+ ui->button_return_shift->setEnabled(initialize_parameters.enable_return_button);
+ break;
+ }
+ case BottomOSKIndex::NumberPad: {
+ for (const auto& rows : numberpad_buttons) {
+ for (auto* button : rows) {
+ if (!button) {
+ continue;
+ }
+
+ button->setEnabled(true);
+ }
+ }
+ break;
+ }
+ }
+}
+
+void QtSoftwareKeyboardDialog::SetBackspaceOkEnabled() {
+ if (is_inline) {
+ ui->button_ok->setEnabled(current_text.size() >= initialize_parameters.min_text_length);
+ ui->button_ok_shift->setEnabled(current_text.size() >=
+ initialize_parameters.min_text_length);
+ ui->button_ok_num->setEnabled(current_text.size() >= initialize_parameters.min_text_length);
+
+ ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button &&
+ cursor_position > 0);
+ ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button &&
+ cursor_position > 0);
+ ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button &&
+ cursor_position > 0);
} else {
- buttons->addButton(QString::fromStdU16String(parameters.submit_text),
- QDialogButtonBox::AcceptRole);
+ const auto text_length = [this] {
+ if (ui->topOSK->currentIndex() == 1) {
+ return static_cast<u32>(ui->text_edit_osk->toPlainText().length());
+ } else {
+ return static_cast<u32>(ui->line_edit_osk->text().length());
+ }
+ }();
+
+ const auto normal_cursor_position = [this] {
+ if (ui->topOSK->currentIndex() == 1) {
+ return ui->text_edit_osk->textCursor().position();
+ } else {
+ return ui->line_edit_osk->cursorPosition();
+ }
+ }();
+
+ ui->button_ok->setEnabled(text_length >= initialize_parameters.min_text_length);
+ ui->button_ok_shift->setEnabled(text_length >= initialize_parameters.min_text_length);
+ ui->button_ok_num->setEnabled(text_length >= initialize_parameters.min_text_length);
+
+ ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button &&
+ normal_cursor_position > 0);
+ ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button &&
+ normal_cursor_position > 0);
+ ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button &&
+ normal_cursor_position > 0);
}
- connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept);
- connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject);
- layout->addWidget(header_label);
- layout->addWidget(sub_label);
- layout->addWidget(guide_label);
- layout->addWidget(length_label);
- layout->addWidget(line_edit);
- layout->addWidget(buttons);
- setLayout(layout);
- setWindowTitle(tr("Software Keyboard"));
}
-QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default;
+bool QtSoftwareKeyboardDialog::ValidateInputText(const QString& input_text) {
+ const auto& key_disable_flags = initialize_parameters.key_disable_flags;
+
+ const auto input_text_length = static_cast<u32>(input_text.length());
+
+ if (input_text_length < initialize_parameters.min_text_length ||
+ input_text_length > initialize_parameters.max_text_length) {
+ return false;
+ }
+
+ if (key_disable_flags.space && input_text.contains(QLatin1Char{' '})) {
+ return false;
+ }
+
+ if ((key_disable_flags.at || key_disable_flags.username) &&
+ input_text.contains(QLatin1Char{'@'})) {
+ return false;
+ }
+
+ if ((key_disable_flags.percent || key_disable_flags.username) &&
+ input_text.contains(QLatin1Char{'%'})) {
+ return false;
+ }
+
+ if (key_disable_flags.slash && input_text.contains(QLatin1Char{'/'})) {
+ return false;
+ }
+
+ if ((key_disable_flags.backslash || key_disable_flags.username) &&
+ input_text.contains(QLatin1Char('\\'))) {
+ return false;
+ }
-void QtSoftwareKeyboardDialog::accept() {
- text = line_edit->text().toStdU16String();
- QDialog::accept();
+ if (key_disable_flags.numbers &&
+ std::any_of(input_text.begin(), input_text.end(), [](QChar c) { return c.isDigit(); })) {
+ return false;
+ }
+
+ if (bottom_osk_index == BottomOSKIndex::NumberPad &&
+ std::any_of(input_text.begin(), input_text.end(), [](QChar c) { return !c.isDigit(); })) {
+ return false;
+ }
+
+ return true;
}
-void QtSoftwareKeyboardDialog::reject() {
- text.clear();
- QDialog::reject();
+void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() {
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ bottom_osk_index = BottomOSKIndex::UpperCase;
+ ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
+
+ ui->button_shift_shift->setStyleSheet(
+ QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);"
+ "\nbackground-position: left top;"
+ "\nbackground-repeat: no-repeat;"
+ "\nbackground-origin: content;"));
+
+ ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
+ ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
+ break;
+ case BottomOSKIndex::UpperCase:
+ if (caps_lock_enabled) {
+ caps_lock_enabled = false;
+
+ ui->button_shift_shift->setStyleSheet(
+ QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);"
+ "\nbackground-position: left top;"
+ "\nbackground-repeat: no-repeat;"
+ "\nbackground-origin: content;"));
+
+ ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
+ ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
+
+ ui->label_shift_shift->setText(QStringLiteral("Caps Lock"));
+
+ bottom_osk_index = BottomOSKIndex::LowerCase;
+ ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
+ } else {
+ caps_lock_enabled = true;
+
+ ui->button_shift_shift->setStyleSheet(
+ QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_on.png);"
+ "\nbackground-position: left top;"
+ "\nbackground-repeat: no-repeat;"
+ "\nbackground-origin: content;"));
+
+ ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
+ ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
+
+ ui->label_shift_shift->setText(QStringLiteral("Caps Lock Off"));
+ }
+ break;
+ case BottomOSKIndex::NumberPad:
+ default:
+ break;
+ }
}
-std::u16string QtSoftwareKeyboardDialog::GetText() const {
- return text;
+void QtSoftwareKeyboardDialog::NormalKeyboardButtonClicked(QPushButton* button) {
+ if (button == ui->button_ampersand) {
+ if (ui->topOSK->currentIndex() == 1) {
+ ui->text_edit_osk->insertPlainText(QStringLiteral("&"));
+ } else {
+ ui->line_edit_osk->insert(QStringLiteral("&"));
+ }
+ return;
+ }
+
+ if (button == ui->button_return || button == ui->button_return_shift) {
+ if (ui->topOSK->currentIndex() == 1) {
+ ui->text_edit_osk->insertPlainText(QStringLiteral("\n"));
+ } else {
+ ui->line_edit_osk->insert(QStringLiteral("\n"));
+ }
+ return;
+ }
+
+ if (button == ui->button_space || button == ui->button_space_shift) {
+ if (ui->topOSK->currentIndex() == 1) {
+ ui->text_edit_osk->insertPlainText(QStringLiteral(" "));
+ } else {
+ ui->line_edit_osk->insert(QStringLiteral(" "));
+ }
+ return;
+ }
+
+ if (button == ui->button_shift || button == ui->button_shift_shift) {
+ ChangeBottomOSKIndex();
+ return;
+ }
+
+ if (button == ui->button_backspace || button == ui->button_backspace_shift ||
+ button == ui->button_backspace_num) {
+ if (ui->topOSK->currentIndex() == 1) {
+ auto text_cursor = ui->text_edit_osk->textCursor();
+ ui->text_edit_osk->setTextCursor(text_cursor);
+ text_cursor.deletePreviousChar();
+ } else {
+ ui->line_edit_osk->backspace();
+ }
+ return;
+ }
+
+ if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) {
+ if (ui->topOSK->currentIndex() == 1) {
+ emit SubmitNormalText(SwkbdResult::Ok,
+ ui->text_edit_osk->toPlainText().toStdU16String());
+ } else {
+ emit SubmitNormalText(SwkbdResult::Ok, ui->line_edit_osk->text().toStdU16String());
+ }
+ return;
+ }
+
+ if (ui->topOSK->currentIndex() == 1) {
+ ui->text_edit_osk->insertPlainText(button->text());
+ } else {
+ ui->line_edit_osk->insert(button->text());
+ }
+
+ // Revert the keyboard to lowercase if the shift key is active.
+ if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) {
+ // This is set to true since ChangeBottomOSKIndex will change bottom_osk_index to LowerCase
+ // if bottom_osk_index is UpperCase and caps_lock_enabled is true.
+ caps_lock_enabled = true;
+ ChangeBottomOSKIndex();
+ }
+}
+
+void QtSoftwareKeyboardDialog::InlineKeyboardButtonClicked(QPushButton* button) {
+ if (!button->isEnabled()) {
+ return;
+ }
+
+ if (button == ui->button_ampersand) {
+ InlineTextInsertString(u"&");
+ return;
+ }
+
+ if (button == ui->button_return || button == ui->button_return_shift) {
+ InlineTextInsertString(u"\n");
+ return;
+ }
+
+ if (button == ui->button_space || button == ui->button_space_shift) {
+ InlineTextInsertString(u" ");
+ return;
+ }
+
+ if (button == ui->button_shift || button == ui->button_shift_shift) {
+ ChangeBottomOSKIndex();
+ return;
+ }
+
+ if (button == ui->button_backspace || button == ui->button_backspace_shift ||
+ button == ui->button_backspace_num) {
+ if (cursor_position <= 0 || current_text.empty()) {
+ cursor_position = 0;
+ return;
+ }
+
+ --cursor_position;
+
+ current_text.erase(cursor_position, 1);
+
+ SetBackspaceOkEnabled();
+
+ emit SubmitInlineText(SwkbdReplyType::ChangedString, current_text, cursor_position);
+ return;
+ }
+
+ if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) {
+ emit SubmitInlineText(SwkbdReplyType::DecidedEnter, current_text, cursor_position);
+ return;
+ }
+
+ InlineTextInsertString(button->text().toStdU16String());
+
+ // Revert the keyboard to lowercase if the shift key is active.
+ if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) {
+ // This is set to true since ChangeBottomOSKIndex will change bottom_osk_index to LowerCase
+ // if bottom_osk_index is UpperCase and caps_lock_enabled is true.
+ caps_lock_enabled = true;
+ ChangeBottomOSKIndex();
+ }
+}
+
+void QtSoftwareKeyboardDialog::InlineTextInsertString(std::u16string_view string) {
+ if ((current_text.size() + string.size()) > initialize_parameters.max_text_length) {
+ return;
+ }
+
+ current_text.insert(cursor_position, string);
+
+ cursor_position += static_cast<s32>(string.size());
+
+ SetBackspaceOkEnabled();
+
+ emit SubmitInlineText(SwkbdReplyType::ChangedString, current_text, cursor_position);
+}
+
+void QtSoftwareKeyboardDialog::SetupMouseHover() {
+ // setFocus() has a bug where continuously changing focus will cause the focus UI to
+ // mysteriously disappear. A workaround we have found is using the mouse to hover over
+ // the buttons to act in place of the button focus. As a result, we will have to set
+ // a blank cursor when hovering over all the buttons and set a no focus policy so the
+ // buttons do not stay in focus in addition to the mouse hover.
+ for (auto* button : all_buttons) {
+ button->setCursor(QCursor(Qt::BlankCursor));
+ button->setFocusPolicy(Qt::NoFocus);
+ }
+}
+
+template <HIDButton... T>
+void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() {
+ const auto f = [this](HIDButton button) {
+ if (input_interpreter->IsButtonPressedOnce(button)) {
+ TranslateButtonPress(button);
+ }
+ };
+
+ (f(T), ...);
+}
+
+template <HIDButton... T>
+void QtSoftwareKeyboardDialog::HandleButtonHold() {
+ const auto f = [this](HIDButton button) {
+ if (input_interpreter->IsButtonHeld(button)) {
+ TranslateButtonPress(button);
+ }
+ };
+
+ (f(T), ...);
+}
+
+void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
+ switch (button) {
+ case HIDButton::A:
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ case BottomOSKIndex::UpperCase:
+ keyboard_buttons[static_cast<std::size_t>(bottom_osk_index)][row][column]->click();
+ break;
+ case BottomOSKIndex::NumberPad:
+ numberpad_buttons[row][column]->click();
+ break;
+ default:
+ break;
+ }
+ break;
+ case HIDButton::B:
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ ui->button_backspace->click();
+ break;
+ case BottomOSKIndex::UpperCase:
+ ui->button_backspace_shift->click();
+ break;
+ case BottomOSKIndex::NumberPad:
+ ui->button_backspace_num->click();
+ break;
+ default:
+ break;
+ }
+ break;
+ case HIDButton::X:
+ if (is_inline) {
+ emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
+ } else {
+ if (ui->topOSK->currentIndex() == 1) {
+ emit SubmitNormalText(SwkbdResult::Cancel,
+ ui->text_edit_osk->toPlainText().toStdU16String());
+ } else {
+ emit SubmitNormalText(SwkbdResult::Cancel,
+ ui->line_edit_osk->text().toStdU16String());
+ }
+ }
+ break;
+ case HIDButton::Y:
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ ui->button_space->click();
+ break;
+ case BottomOSKIndex::UpperCase:
+ ui->button_space_shift->click();
+ break;
+ case BottomOSKIndex::NumberPad:
+ default:
+ break;
+ }
+ break;
+ case HIDButton::LStick:
+ case HIDButton::RStick:
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ ui->button_shift->click();
+ break;
+ case BottomOSKIndex::UpperCase:
+ ui->button_shift_shift->click();
+ break;
+ case BottomOSKIndex::NumberPad:
+ default:
+ break;
+ }
+ break;
+ case HIDButton::L:
+ MoveTextCursorDirection(Direction::Left);
+ break;
+ case HIDButton::R:
+ MoveTextCursorDirection(Direction::Right);
+ break;
+ case HIDButton::Plus:
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ ui->button_ok->click();
+ break;
+ case BottomOSKIndex::UpperCase:
+ ui->button_ok_shift->click();
+ break;
+ case BottomOSKIndex::NumberPad:
+ ui->button_ok_num->click();
+ break;
+ default:
+ break;
+ }
+ break;
+ case HIDButton::DLeft:
+ case HIDButton::LStickLeft:
+ case HIDButton::RStickLeft:
+ MoveButtonDirection(Direction::Left);
+ break;
+ case HIDButton::DUp:
+ case HIDButton::LStickUp:
+ case HIDButton::RStickUp:
+ MoveButtonDirection(Direction::Up);
+ break;
+ case HIDButton::DRight:
+ case HIDButton::LStickRight:
+ case HIDButton::RStickRight:
+ MoveButtonDirection(Direction::Right);
+ break;
+ case HIDButton::DDown:
+ case HIDButton::LStickDown:
+ case HIDButton::RStickDown:
+ MoveButtonDirection(Direction::Down);
+ break;
+ default:
+ break;
+ }
+}
+
+void QtSoftwareKeyboardDialog::MoveButtonDirection(Direction direction) {
+ // Changes the row or column index depending on the direction.
+ auto move_direction = [this, direction](std::size_t max_rows, std::size_t max_columns) {
+ switch (direction) {
+ case Direction::Left:
+ column = (column + max_columns - 1) % max_columns;
+ break;
+ case Direction::Up:
+ row = (row + max_rows - 1) % max_rows;
+ break;
+ case Direction::Right:
+ column = (column + 1) % max_columns;
+ break;
+ case Direction::Down:
+ row = (row + 1) % max_rows;
+ break;
+ default:
+ break;
+ }
+ };
+
+ switch (bottom_osk_index) {
+ case BottomOSKIndex::LowerCase:
+ case BottomOSKIndex::UpperCase: {
+ const auto index = static_cast<std::size_t>(bottom_osk_index);
+
+ const auto* const prev_button = keyboard_buttons[index][row][column];
+ move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL);
+ auto* curr_button = keyboard_buttons[index][row][column];
+
+ while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) {
+ move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL);
+ curr_button = keyboard_buttons[index][row][column];
+ }
+
+ // This is a workaround for setFocus() randomly not showing focus in the UI
+ QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center()));
+ break;
+ }
+ case BottomOSKIndex::NumberPad: {
+ const auto* const prev_button = numberpad_buttons[row][column];
+ move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD);
+ auto* curr_button = numberpad_buttons[row][column];
+
+ while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) {
+ move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD);
+ curr_button = numberpad_buttons[row][column];
+ }
+
+ // This is a workaround for setFocus() randomly not showing focus in the UI
+ QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center()));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void QtSoftwareKeyboardDialog::MoveTextCursorDirection(Direction direction) {
+ switch (direction) {
+ case Direction::Left:
+ if (is_inline) {
+ if (cursor_position <= 0) {
+ cursor_position = 0;
+ } else {
+ --cursor_position;
+ emit SubmitInlineText(SwkbdReplyType::MovedCursor, current_text, cursor_position);
+ }
+ } else {
+ if (ui->topOSK->currentIndex() == 1) {
+ ui->text_edit_osk->moveCursor(QTextCursor::Left);
+ } else {
+ ui->line_edit_osk->setCursorPosition(ui->line_edit_osk->cursorPosition() - 1);
+ }
+ }
+ break;
+ case Direction::Right:
+ if (is_inline) {
+ if (cursor_position >= static_cast<s32>(current_text.size())) {
+ cursor_position = static_cast<s32>(current_text.size());
+ } else {
+ ++cursor_position;
+ emit SubmitInlineText(SwkbdReplyType::MovedCursor, current_text, cursor_position);
+ }
+ } else {
+ if (ui->topOSK->currentIndex() == 1) {
+ ui->text_edit_osk->moveCursor(QTextCursor::Right);
+ } else {
+ ui->line_edit_osk->setCursorPosition(ui->line_edit_osk->cursorPosition() + 1);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void QtSoftwareKeyboardDialog::StartInputThread() {
+ if (input_thread_running) {
+ return;
+ }
+
+ input_thread_running = true;
+
+ input_thread = std::thread(&QtSoftwareKeyboardDialog::InputThread, this);
+}
+
+void QtSoftwareKeyboardDialog::StopInputThread() {
+ input_thread_running = false;
+
+ if (input_thread.joinable()) {
+ input_thread.join();
+ }
+
+ if (input_interpreter) {
+ input_interpreter->ResetButtonStates();
+ }
+}
+
+void QtSoftwareKeyboardDialog::InputThread() {
+ while (input_thread_running) {
+ input_interpreter->PollInput();
+
+ HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::X, HIDButton::Y,
+ HIDButton::LStick, HIDButton::RStick, HIDButton::L, HIDButton::R,
+ HIDButton::Plus, HIDButton::DLeft, HIDButton::DUp,
+ HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft,
+ HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown,
+ HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight,
+ HIDButton::RStickDown>();
+
+ HandleButtonHold<HIDButton::B, HIDButton::L, HIDButton::R, HIDButton::DLeft, HIDButton::DUp,
+ HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft,
+ HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown,
+ HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight,
+ HIDButton::RStickDown>();
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
}
QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) {
- connect(this, &QtSoftwareKeyboard::MainWindowGetText, &main_window,
- &GMainWindow::SoftwareKeyboardGetText, Qt::QueuedConnection);
- connect(this, &QtSoftwareKeyboard::MainWindowTextCheckDialog, &main_window,
- &GMainWindow::SoftwareKeyboardInvokeCheckDialog, Qt::BlockingQueuedConnection);
- connect(&main_window, &GMainWindow::SoftwareKeyboardFinishedText, this,
- &QtSoftwareKeyboard::MainWindowFinishedText, Qt::QueuedConnection);
+ connect(this, &QtSoftwareKeyboard::MainWindowInitializeKeyboard, &main_window,
+ &GMainWindow::SoftwareKeyboardInitialize, Qt::QueuedConnection);
+ connect(this, &QtSoftwareKeyboard::MainWindowShowNormalKeyboard, &main_window,
+ &GMainWindow::SoftwareKeyboardShowNormal, Qt::QueuedConnection);
+ connect(this, &QtSoftwareKeyboard::MainWindowShowTextCheckDialog, &main_window,
+ &GMainWindow::SoftwareKeyboardShowTextCheck, Qt::QueuedConnection);
+ connect(this, &QtSoftwareKeyboard::MainWindowShowInlineKeyboard, &main_window,
+ &GMainWindow::SoftwareKeyboardShowInline, Qt::QueuedConnection);
+ connect(this, &QtSoftwareKeyboard::MainWindowHideInlineKeyboard, &main_window,
+ &GMainWindow::SoftwareKeyboardHideInline, Qt::QueuedConnection);
+ connect(this, &QtSoftwareKeyboard::MainWindowInlineTextChanged, &main_window,
+ &GMainWindow::SoftwareKeyboardInlineTextChanged, Qt::QueuedConnection);
+ connect(this, &QtSoftwareKeyboard::MainWindowExitKeyboard, &main_window,
+ &GMainWindow::SoftwareKeyboardExit, Qt::QueuedConnection);
+ connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitNormalText, this,
+ &QtSoftwareKeyboard::SubmitNormalText, Qt::QueuedConnection);
+ connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitInlineText, this,
+ &QtSoftwareKeyboard::SubmitInlineText, Qt::QueuedConnection);
}
QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
-void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out,
- Core::Frontend::SoftwareKeyboardParameters parameters) const {
- text_output = std::move(out);
- emit MainWindowGetText(parameters);
+void QtSoftwareKeyboard::InitializeKeyboard(
+ bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
+ std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
+ std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+ submit_inline_callback_) {
+ if (is_inline) {
+ submit_inline_callback = std::move(submit_inline_callback_);
+ } else {
+ submit_normal_callback = std::move(submit_normal_callback_);
+ }
+
+ LOG_INFO(Service_AM,
+ "\nKeyboardInitializeParameters:"
+ "\nok_text={}"
+ "\nheader_text={}"
+ "\nsub_text={}"
+ "\nguide_text={}"
+ "\ninitial_text={}"
+ "\nmax_text_length={}"
+ "\nmin_text_length={}"
+ "\ninitial_cursor_position={}"
+ "\ntype={}"
+ "\npassword_mode={}"
+ "\ntext_draw_type={}"
+ "\nkey_disable_flags={}"
+ "\nuse_blur_background={}"
+ "\nenable_backspace_button={}"
+ "\nenable_return_button={}"
+ "\ndisable_cancel_button={}",
+ Common::UTF16ToUTF8(initialize_parameters.ok_text),
+ Common::UTF16ToUTF8(initialize_parameters.header_text),
+ Common::UTF16ToUTF8(initialize_parameters.sub_text),
+ Common::UTF16ToUTF8(initialize_parameters.guide_text),
+ Common::UTF16ToUTF8(initialize_parameters.initial_text),
+ initialize_parameters.max_text_length, initialize_parameters.min_text_length,
+ initialize_parameters.initial_cursor_position, initialize_parameters.type,
+ initialize_parameters.password_mode, initialize_parameters.text_draw_type,
+ initialize_parameters.key_disable_flags.raw, initialize_parameters.use_blur_background,
+ initialize_parameters.enable_backspace_button,
+ initialize_parameters.enable_return_button,
+ initialize_parameters.disable_cancel_button);
+
+ emit MainWindowInitializeKeyboard(is_inline, std::move(initialize_parameters));
+}
+
+void QtSoftwareKeyboard::ShowNormalKeyboard() const {
+ emit MainWindowShowNormalKeyboard();
+}
+
+void QtSoftwareKeyboard::ShowTextCheckDialog(
+ Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) const {
+ emit MainWindowShowTextCheckDialog(text_check_result, text_check_message);
+}
+
+void QtSoftwareKeyboard::ShowInlineKeyboard(
+ Core::Frontend::InlineAppearParameters appear_parameters) const {
+ LOG_INFO(Service_AM,
+ "\nInlineAppearParameters:"
+ "\nmax_text_length={}"
+ "\nmin_text_length={}"
+ "\nkey_top_scale_x={}"
+ "\nkey_top_scale_y={}"
+ "\nkey_top_translate_x={}"
+ "\nkey_top_translate_y={}"
+ "\ntype={}"
+ "\nkey_disable_flags={}"
+ "\nkey_top_as_floating={}"
+ "\nenable_backspace_button={}"
+ "\nenable_return_button={}"
+ "\ndisable_cancel_button={}",
+ appear_parameters.max_text_length, appear_parameters.min_text_length,
+ appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y,
+ appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y,
+ appear_parameters.type, appear_parameters.key_disable_flags.raw,
+ appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button,
+ appear_parameters.enable_return_button, appear_parameters.disable_cancel_button);
+
+ emit MainWindowShowInlineKeyboard(std::move(appear_parameters));
+}
+
+void QtSoftwareKeyboard::HideInlineKeyboard() const {
+ emit MainWindowHideInlineKeyboard();
+}
+
+void QtSoftwareKeyboard::InlineTextChanged(
+ Core::Frontend::InlineTextParameters text_parameters) const {
+ LOG_INFO(Service_AM,
+ "\nInlineTextParameters:"
+ "\ninput_text={}"
+ "\ncursor_position={}",
+ Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
+
+ emit MainWindowInlineTextChanged(std::move(text_parameters));
}
-void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message,
- std::function<void()> finished_check_) const {
- finished_check = std::move(finished_check_);
- emit MainWindowTextCheckDialog(error_message);
+void QtSoftwareKeyboard::ExitKeyboard() const {
+ emit MainWindowExitKeyboard();
}
-void QtSoftwareKeyboard::MainWindowFinishedText(std::optional<std::u16string> text) {
- // Acquire the HLE mutex
- std::lock_guard lock{HLE::g_hle_lock};
- text_output(std::move(text));
+void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Applets::SwkbdResult result,
+ std::u16string submitted_text) const {
+ submit_normal_callback(result, submitted_text);
}
-void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() {
- // Acquire the HLE mutex
- std::lock_guard lock{HLE::g_hle_lock};
- finished_check();
+void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
+ std::u16string submitted_text,
+ s32 cursor_position) const {
+ submit_inline_callback(reply_type, submitted_text, cursor_position);
}
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 @@
-// Copyright 2018 yuzu Emulator Project
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
+#include <array>
+#include <atomic>
+#include <memory>
+#include <thread>
+
#include <QDialog>
#include <QValidator>
+
#include "core/frontend/applets/software_keyboard.h"
-class GMainWindow;
-class QDialogButtonBox;
-class QLabel;
-class QLineEdit;
-class QVBoxLayout;
-class QtSoftwareKeyboard;
+enum class HIDButton : u8;
-class QtSoftwareKeyboardValidator final : public QValidator {
-public:
- explicit QtSoftwareKeyboardValidator(Core::Frontend::SoftwareKeyboardParameters parameters);
- State validate(QString& input, int& pos) const override;
+class InputInterpreter;
-private:
- Core::Frontend::SoftwareKeyboardParameters parameters;
-};
+namespace Core {
+class System;
+}
+
+namespace Ui {
+class QtSoftwareKeyboardDialog;
+}
+
+class GMainWindow;
class QtSoftwareKeyboardDialog final : public QDialog {
Q_OBJECT
public:
- QtSoftwareKeyboardDialog(QWidget* parent,
- Core::Frontend::SoftwareKeyboardParameters parameters);
+ QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_,
+ Core::Frontend::KeyboardInitializeParameters initialize_parameters_);
~QtSoftwareKeyboardDialog() override;
- void accept() override;
+ void ShowNormalKeyboard(QPoint pos, QSize size);
+
+ void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message);
+
+ void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos,
+ QSize size);
+
+ void HideInlineKeyboard();
+
+ void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
+
+ void ExitKeyboard();
+
+signals:
+ void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
+ std::u16string submitted_text) const;
+
+ void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
+ std::u16string submitted_text, s32 cursor_position) const;
+
+public slots:
+ void open() override;
void reject() override;
- std::u16string GetText() const;
+protected:
+ /// We override the keyPressEvent for inputting text into the inline software keyboard.
+ void keyPressEvent(QKeyEvent* event) override;
private:
- std::u16string text;
+ enum class Direction {
+ Left,
+ Up,
+ Right,
+ Down,
+ };
+
+ enum class BottomOSKIndex {
+ LowerCase,
+ UpperCase,
+ NumberPad,
+ };
+
+ /**
+ * Moves and resizes the window to a specified position and size.
+ *
+ * @param pos Top-left window position
+ * @param size Window size
+ */
+ void MoveAndResizeWindow(QPoint pos, QSize size);
+
+ /**
+ * Rescales all keyboard elements to account for High DPI displays.
+ *
+ * @param width Window width
+ * @param height Window height
+ * @param dpi_scale Display scaling factor
+ */
+ void RescaleKeyboardElements(float width, float height, float dpi_scale);
+
+ /// Sets the keyboard type based on initialize_parameters.
+ void SetKeyboardType();
+
+ /// Sets the password mode based on initialize_parameters.
+ void SetPasswordMode();
+
+ /// Sets the text draw type based on initialize_parameters.
+ void SetTextDrawType();
+
+ /// Sets the controller image at the bottom left of the software keyboard.
+ void SetControllerImage();
+
+ /// Disables buttons based on initialize_parameters.
+ void DisableKeyboardButtons();
+
+ /// Changes whether the backspace or/and ok buttons should be enabled or disabled.
+ void SetBackspaceOkEnabled();
+
+ /**
+ * Validates the input text sent in based on the parameters in initialize_parameters.
+ *
+ * @param input_text Input text
+ *
+ * @returns True if the input text is valid, false otherwise.
+ */
+ bool ValidateInputText(const QString& input_text);
+
+ /// Switches between LowerCase and UpperCase (Shift and Caps Lock)
+ void ChangeBottomOSKIndex();
+
+ /// Processes a keyboard button click from the UI as normal keyboard input.
+ void NormalKeyboardButtonClicked(QPushButton* button);
+
+ /// Processes a keyboard button click from the UI as inline keyboard input.
+ void InlineKeyboardButtonClicked(QPushButton* button);
+
+ /**
+ * Inserts a string of arbitrary length into the current_text at the current cursor position.
+ * This is only used for the inline software keyboard.
+ */
+ void InlineTextInsertString(std::u16string_view string);
- QDialogButtonBox* buttons;
- QLabel* header_label;
- QLabel* sub_label;
- QLabel* guide_label;
- QLabel* length_label;
- QLineEdit* line_edit;
- QVBoxLayout* layout;
+ /// Setup the mouse hover workaround for "focusing" buttons. This should only be called once.
+ void SetupMouseHover();
- Core::Frontend::SoftwareKeyboardParameters parameters;
+ /**
+ * Handles button presses and converts them into keyboard input.
+ *
+ * @tparam HIDButton The list of buttons that can be converted into keyboard input.
+ */
+ template <HIDButton... T>
+ void HandleButtonPressedOnce();
+
+ /**
+ * Handles button holds and converts them into keyboard input.
+ *
+ * @tparam HIDButton The list of buttons that can be converted into keyboard input.
+ */
+ template <HIDButton... T>
+ void HandleButtonHold();
+
+ /**
+ * Translates a button press to focus or click a keyboard button.
+ *
+ * @param button The button press to process.
+ */
+ void TranslateButtonPress(HIDButton button);
+
+ /**
+ * Moves the focus of a button in a certain direction.
+ *
+ * @param direction The direction to move.
+ */
+ void MoveButtonDirection(Direction direction);
+
+ /**
+ * Moves the text cursor in a certain direction.
+ *
+ * @param direction The direction to move.
+ */
+ void MoveTextCursorDirection(Direction direction);
+
+ void StartInputThread();
+ void StopInputThread();
+
+ /// The thread where input is being polled and processed.
+ void InputThread();
+
+ std::unique_ptr<Ui::QtSoftwareKeyboardDialog> ui;
+
+ Core::System& system;
+
+ // True if it is the inline software keyboard.
+ bool is_inline;
+
+ // Common software keyboard initialize parameters.
+ Core::Frontend::KeyboardInitializeParameters initialize_parameters;
+
+ // Used only by the inline software keyboard since the QLineEdit or QTextEdit is hidden.
+ std::u16string current_text;
+ s32 cursor_position{0};
+
+ static constexpr std::size_t NUM_ROWS_NORMAL = 5;
+ static constexpr std::size_t NUM_COLUMNS_NORMAL = 12;
+ static constexpr std::size_t NUM_ROWS_NUMPAD = 4;
+ static constexpr std::size_t NUM_COLUMNS_NUMPAD = 4;
+
+ // Stores the normal keyboard layout.
+ std::array<std::array<std::array<QPushButton*, NUM_COLUMNS_NORMAL>, NUM_ROWS_NORMAL>, 2>
+ keyboard_buttons;
+ // Stores the numberpad keyboard layout.
+ std::array<std::array<QPushButton*, NUM_COLUMNS_NUMPAD>, NUM_ROWS_NUMPAD> numberpad_buttons;
+
+ // Contains a set of all buttons used in keyboard_buttons and numberpad_buttons.
+ std::array<QPushButton*, 110> all_buttons;
+
+ std::size_t row{0};
+ std::size_t column{0};
+
+ BottomOSKIndex bottom_osk_index{BottomOSKIndex::LowerCase};
+ std::atomic<bool> caps_lock_enabled{false};
+
+ std::unique_ptr<InputInterpreter> input_interpreter;
+
+ std::thread input_thread;
+
+ std::atomic<bool> input_thread_running{};
};
class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet {
@@ -58,19 +232,54 @@ public:
explicit QtSoftwareKeyboard(GMainWindow& parent);
~QtSoftwareKeyboard() override;
- void RequestText(std::function<void(std::optional<std::u16string>)> out,
- Core::Frontend::SoftwareKeyboardParameters parameters) const override;
- void SendTextCheckDialog(std::u16string error_message,
- std::function<void()> finished_check_) const override;
+ void InitializeKeyboard(
+ bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
+ std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
+ submit_normal_callback_,
+ std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+ submit_inline_callback_) override;
+
+ void ShowNormalKeyboard() const override;
+
+ void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) const override;
+
+ void ShowInlineKeyboard(
+ Core::Frontend::InlineAppearParameters appear_parameters) const override;
+
+ void HideInlineKeyboard() const override;
+
+ void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override;
+
+ void ExitKeyboard() const override;
signals:
- void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const;
- void MainWindowTextCheckDialog(std::u16string error_message) const;
+ void MainWindowInitializeKeyboard(
+ bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) const;
+
+ void MainWindowShowNormalKeyboard() const;
+
+ void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) const;
+
+ void MainWindowShowInlineKeyboard(
+ Core::Frontend::InlineAppearParameters appear_parameters) const;
+
+ void MainWindowHideInlineKeyboard() const;
+
+ void MainWindowInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const;
+
+ void MainWindowExitKeyboard() const;
private:
- void MainWindowFinishedText(std::optional<std::u16string> text);
- void MainWindowFinishedCheckDialog();
+ void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
+ std::u16string submitted_text) const;
+
+ void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
+ std::u16string submitted_text, s32 cursor_position) const;
- mutable std::function<void(std::optional<std::u16string>)> text_output;
- mutable std::function<void()> finished_check;
+ mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
+ submit_normal_callback;
+ mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+ submit_inline_callback;
};
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtSoftwareKeyboardDialog</class>
+ <widget class="QDialog" name="QtSoftwareKeyboardDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1280</width>
+ <height>720</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Software Keyboard</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="mainOSK" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="320,400">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QStackedWidget" name="topOSK">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="lineOSK">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>100</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="lineOSKVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="gridLineOSK" rowstretch="40,50,23,48,65,94" columnstretch="130,1020,130">
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item row="4" column="2">
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="4" column="0">
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="5" column="1">
+ <widget class="QWidget" name="charactersOSK" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignRight|Qt::AlignTop">
+ <widget class="QLabel" name="label_characters">
+ <property name="font">
+ <font>
+ <pointsize>17</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">0/32</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="5" column="0">
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="4" column="1">
+ <widget class="QWidget" name="inputOSK" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QLineEdit" name="line_edit_osk">
+ <property name="font">
+ <font>
+ <pointsize>26</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ </font>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="maxLength">
+ <number>32</number>
+ </property>
+ <property name="placeholderText">
+ <string>Enter Text</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="verticalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" colspan="3">
+ <widget class="QWidget" name="headerOSK" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="130,1020,130">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer_18">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>127</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_header">
+ <property name="font">
+ <font>
+ <pointsize>23</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_19">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>127</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="3">
+ <widget class="QWidget" name="subOSK" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="130,1020,130">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer_16">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>127</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_sub">
+ <property name="font">
+ <font>
+ <pointsize>17</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_17">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>127</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="boxOSK">
+ <layout class="QVBoxLayout" name="boxOSKVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="gridBoxOSK" rowstretch="61,178,81" columnstretch="120,1040,120">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item row="0" column="1">
+ <spacer name="verticalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer_20">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2">
+ <spacer name="horizontalSpacer_21">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" alignment="Qt::AlignRight|Qt::AlignTop">
+ <widget class="QWidget" name="charactersBoxOSK" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_characters_box">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>17</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">0/500</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QWidget" name="inputBoxOSK" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>14</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>14</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QTextEdit" name="text_edit_osk">
+ <property name="font">
+ <font>
+ <pointsize>26</pointsize>
+ </font>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="html">
+ <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;
+&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;
+p, li { white-space: pre-wrap; }
+&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;
+&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>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="bottomOSK">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="normalOSK">
+ <layout class="QVBoxLayout" name="normalPageVerticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <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">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item row="6" column="1" colspan="12">
+ <widget class="QWidget" name="legendOSK" native="true">
+ <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">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="icon_controller" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_L" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_14">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="arrow_left" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_13">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_R" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_12">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="arrow_right" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_11">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_press_stick" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_10">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_shift">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Shift</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_15">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_X" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_cancel">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_A" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_7">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_enter">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Enter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="11">
+ <widget class="QPushButton" name="button_minus">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">-</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="11">
+ <widget class="QPushButton" name="button_apostrophe">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">'</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="11">
+ <widget class="QPushButton" name="button_slash">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">/</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="11">
+ <widget class="QPushButton" name="button_exclamation">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">!</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="7">
+ <widget class="QPushButton" name="button_7">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">7</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="8">
+ <widget class="QPushButton" name="button_8">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">8</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="10">
+ <widget class="QPushButton" name="button_0">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="9">
+ <widget class="QPushButton" name="button_9">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">9</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="button_w">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">w</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="4">
+ <widget class="QPushButton" name="button_r">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">r</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QPushButton" name="button_e">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">e</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QPushButton" name="button_q">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">q</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="7">
+ <widget class="QPushButton" name="button_u">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">u</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="6">
+ <widget class="QPushButton" name="button_y">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">y</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="5">
+ <widget class="QPushButton" name="button_t">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">t</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="9">
+ <widget class="QPushButton" name="button_o">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">o</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="10">
+ <widget class="QPushButton" name="button_p">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">p</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="8">
+ <widget class="QPushButton" name="button_i">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">i</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QPushButton" name="button_a">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">a</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <widget class="QPushButton" name="button_s">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">s</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3">
+ <widget class="QPushButton" name="button_d">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">d</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="4">
+ <widget class="QPushButton" name="button_f">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">f</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="6">
+ <widget class="QPushButton" name="button_h">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">h</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="7">
+ <widget class="QPushButton" name="button_j">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">j</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="5">
+ <widget class="QPushButton" name="button_g">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">g</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="8">
+ <widget class="QPushButton" name="button_k">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">k</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="9">
+ <widget class="QPushButton" name="button_l">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">l</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="10">
+ <widget class="QPushButton" name="button_colon">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="12" rowspan="2">
+ <widget class="QPushButton" name="button_return">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Return</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="12" rowspan="2">
+ <widget class="QPushButton" name="button_ok">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">OK</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QPushButton" name="button_z">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">z</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3">
+ <widget class="QPushButton" name="button_c">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">c</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
+ <widget class="QPushButton" name="button_x">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">x</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="4">
+ <widget class="QPushButton" name="button_v">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">v</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="7">
+ <widget class="QPushButton" name="button_m">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">m</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="8">
+ <widget class="QPushButton" name="button_comma">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">,</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="6">
+ <widget class="QPushButton" name="button_n">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">n</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="5">
+ <widget class="QPushButton" name="button_b">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">b</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="2">
+ <widget class="QPushButton" name="button_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="10">
+ <widget class="QPushButton" name="button_question">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">?</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="9">
+ <widget class="QPushButton" name="button_dot">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="button_1">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QPushButton" name="button_3">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">3</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QPushButton" name="button_4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">4</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="button_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">2</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="6">
+ <widget class="QPushButton" name="button_6">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">6</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="5">
+ <widget class="QPushButton" name="button_5">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">5</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="3" colspan="9">
+ <widget class="QPushButton" name="button_space">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Space</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="12">
+ <widget class="QPushButton" name="button_backspace">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="13">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="shiftOSK">
+ <layout class="QVBoxLayout" name="shiftPageVerticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <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">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item row="6" column="1" colspan="12">
+ <widget class="QWidget" name="legendOSKshift" native="true">
+ <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">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="icon_controller_shift" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_22">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_L_shift" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_23">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="arrow_left_shift" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_24">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_R_shift" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_25">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="arrow_right_shift" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_26">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_press_stick_shift" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_27">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_shift_shift">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Caps Lock</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_28">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_X_shift" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_29">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_cancel_shift">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_30">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_A_shift" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_31">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_enter_shift">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Enter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_32">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="11">
+ <widget class="QPushButton" name="button_underscore">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">_</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="11">
+ <widget class="QPushButton" name="button_quotation">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">&quot;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="11">
+ <widget class="QPushButton" name="button_at">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">@</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="11">
+ <widget class="QPushButton" name="button_equal">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">=</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="7">
+ <widget class="QPushButton" name="button_ampersand">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">&amp;&amp;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="8">
+ <widget class="QPushButton" name="button_asterisk">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">*</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="10">
+ <widget class="QPushButton" name="button_right_parenthesis">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="9">
+ <widget class="QPushButton" name="button_left_parenthesis">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">(</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="button_w_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">W</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="4">
+ <widget class="QPushButton" name="button_r_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">R</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QPushButton" name="button_e_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">E</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QPushButton" name="button_q_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Q</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="7">
+ <widget class="QPushButton" name="button_u_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">U</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="6">
+ <widget class="QPushButton" name="button_y_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Y</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="5">
+ <widget class="QPushButton" name="button_t_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">T</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="9">
+ <widget class="QPushButton" name="button_o_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">O</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="10">
+ <widget class="QPushButton" name="button_p_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">P</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="8">
+ <widget class="QPushButton" name="button_i_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">I</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QPushButton" name="button_a_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <widget class="QPushButton" name="button_s_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">S</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3">
+ <widget class="QPushButton" name="button_d_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">D</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="4">
+ <widget class="QPushButton" name="button_f_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">F</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="6">
+ <widget class="QPushButton" name="button_h_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">H</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="7">
+ <widget class="QPushButton" name="button_j_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">J</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="5">
+ <widget class="QPushButton" name="button_g_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">G</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="8">
+ <widget class="QPushButton" name="button_k_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">K</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="9">
+ <widget class="QPushButton" name="button_l_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">L</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="10">
+ <widget class="QPushButton" name="button_semicolon">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="12" rowspan="2">
+ <widget class="QPushButton" name="button_return_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Return</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="12" rowspan="2">
+ <widget class="QPushButton" name="button_ok_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">OK</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QPushButton" name="button_z_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Z</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3">
+ <widget class="QPushButton" name="button_c_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">C</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
+ <widget class="QPushButton" name="button_x_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">X</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="4">
+ <widget class="QPushButton" name="button_v_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">V</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="7">
+ <widget class="QPushButton" name="button_m_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">M</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="8">
+ <widget class="QPushButton" name="button_less_than">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="6">
+ <widget class="QPushButton" name="button_n_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">N</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="5">
+ <widget class="QPushButton" name="button_b_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">B</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="2">
+ <widget class="QPushButton" name="button_shift_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="10">
+ <widget class="QPushButton" name="button_plus">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">+</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="9">
+ <widget class="QPushButton" name="button_greater_than">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="button_hash">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">#</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QPushButton" name="button_right_bracket">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">]</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QPushButton" name="button_dollar">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">$</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="button_left_bracket">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">[</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="6">
+ <widget class="QPushButton" name="button_circumflex">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">^</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="5">
+ <widget class="QPushButton" name="button_percent">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">%</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="3" colspan="9">
+ <widget class="QPushButton" name="button_space_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Space</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="12">
+ <widget class="QPushButton" name="button_backspace_shift">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer_33">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1">
+ <spacer name="verticalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="13">
+ <spacer name="horizontalSpacer_34">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="numOSK">
+ <layout class="QVBoxLayout" name="graphicsTabVerticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="kbOSKnum" rowstretch="18,63,63,63,63,10,70" columnstretch="54,307,186,186,186,120,187,54">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item row="1" column="5">
+ <widget class="QPushButton" name="button_backspace_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="6">
+ <spacer name="horizontalSpacer_35">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1">
+ <spacer name="horizontalSpacer_36">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="2">
+ <spacer name="verticalSpacer_7">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="6" column="1" colspan="6">
+ <widget class="QWidget" name="legendOSKnum" native="true">
+ <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">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer_48">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="icon_controller_num" native="true">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_38">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_L_num" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_39">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="arrow_left_num" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_40">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_R_num" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_41">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="arrow_right_num" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_42">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_X_num" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_43">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_cancel_num">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_44">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="button_A_num" native="true"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_45">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_enter_num">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Enter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_46">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="4">
+ <widget class="QPushButton" name="button_6_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">6</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="button_4_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">4</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="4">
+ <widget class="QPushButton" name="button_9_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">9</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QPushButton" name="button_5_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">5</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="5" rowspan="3">
+ <widget class="QPushButton" name="button_ok_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">OK</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <widget class="QPushButton" name="button_7_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">7</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3">
+ <widget class="QPushButton" name="button_8_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">8</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QPushButton" name="button_2_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">2</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="button_1_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3">
+ <widget class="QPushButton" name="button_0_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4">
+ <widget class="QPushButton" name="button_3_num">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>28</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">3</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer_37">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="7">
+ <spacer name="horizontalSpacer_47">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="5" column="3">
+ <spacer name="verticalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>button_1</tabstop>
+ <tabstop>button_2</tabstop>
+ <tabstop>button_3</tabstop>
+ <tabstop>button_4</tabstop>
+ <tabstop>button_5</tabstop>
+ <tabstop>button_6</tabstop>
+ <tabstop>button_7</tabstop>
+ <tabstop>button_8</tabstop>
+ <tabstop>button_9</tabstop>
+ <tabstop>button_0</tabstop>
+ <tabstop>button_minus</tabstop>
+ <tabstop>button_backspace</tabstop>
+ <tabstop>button_q</tabstop>
+ <tabstop>button_w</tabstop>
+ <tabstop>button_e</tabstop>
+ <tabstop>button_r</tabstop>
+ <tabstop>button_t</tabstop>
+ <tabstop>button_y</tabstop>
+ <tabstop>button_u</tabstop>
+ <tabstop>button_i</tabstop>
+ <tabstop>button_o</tabstop>
+ <tabstop>button_p</tabstop>
+ <tabstop>button_slash</tabstop>
+ <tabstop>button_return</tabstop>
+ <tabstop>button_a</tabstop>
+ <tabstop>button_s</tabstop>
+ <tabstop>button_d</tabstop>
+ <tabstop>button_f</tabstop>
+ <tabstop>button_g</tabstop>
+ <tabstop>button_h</tabstop>
+ <tabstop>button_j</tabstop>
+ <tabstop>button_k</tabstop>
+ <tabstop>button_l</tabstop>
+ <tabstop>button_colon</tabstop>
+ <tabstop>button_apostrophe</tabstop>
+ <tabstop>button_z</tabstop>
+ <tabstop>button_x</tabstop>
+ <tabstop>button_c</tabstop>
+ <tabstop>button_v</tabstop>
+ <tabstop>button_b</tabstop>
+ <tabstop>button_n</tabstop>
+ <tabstop>button_m</tabstop>
+ <tabstop>button_comma</tabstop>
+ <tabstop>button_dot</tabstop>
+ <tabstop>button_question</tabstop>
+ <tabstop>button_exclamation</tabstop>
+ <tabstop>button_ok</tabstop>
+ <tabstop>button_shift</tabstop>
+ <tabstop>button_space</tabstop>
+ <tabstop>button_hash</tabstop>
+ <tabstop>button_left_bracket</tabstop>
+ <tabstop>button_right_bracket</tabstop>
+ <tabstop>button_dollar</tabstop>
+ <tabstop>button_percent</tabstop>
+ <tabstop>button_circumflex</tabstop>
+ <tabstop>button_ampersand</tabstop>
+ <tabstop>button_asterisk</tabstop>
+ <tabstop>button_left_parenthesis</tabstop>
+ <tabstop>button_right_parenthesis</tabstop>
+ <tabstop>button_underscore</tabstop>
+ <tabstop>button_backspace_shift</tabstop>
+ <tabstop>button_q_shift</tabstop>
+ <tabstop>button_w_shift</tabstop>
+ <tabstop>button_e_shift</tabstop>
+ <tabstop>button_r_shift</tabstop>
+ <tabstop>button_t_shift</tabstop>
+ <tabstop>button_y_shift</tabstop>
+ <tabstop>button_u_shift</tabstop>
+ <tabstop>button_i_shift</tabstop>
+ <tabstop>button_o_shift</tabstop>
+ <tabstop>button_p_shift</tabstop>
+ <tabstop>button_at</tabstop>
+ <tabstop>button_return_shift</tabstop>
+ <tabstop>button_a_shift</tabstop>
+ <tabstop>button_s_shift</tabstop>
+ <tabstop>button_d_shift</tabstop>
+ <tabstop>button_f_shift</tabstop>
+ <tabstop>button_g_shift</tabstop>
+ <tabstop>button_h_shift</tabstop>
+ <tabstop>button_j_shift</tabstop>
+ <tabstop>button_k_shift</tabstop>
+ <tabstop>button_l_shift</tabstop>
+ <tabstop>button_semicolon</tabstop>
+ <tabstop>button_quotation</tabstop>
+ <tabstop>button_z_shift</tabstop>
+ <tabstop>button_x_shift</tabstop>
+ <tabstop>button_c_shift</tabstop>
+ <tabstop>button_v_shift</tabstop>
+ <tabstop>button_b_shift</tabstop>
+ <tabstop>button_n_shift</tabstop>
+ <tabstop>button_m_shift</tabstop>
+ <tabstop>button_less_than</tabstop>
+ <tabstop>button_greater_than</tabstop>
+ <tabstop>button_plus</tabstop>
+ <tabstop>button_equal</tabstop>
+ <tabstop>button_ok_shift</tabstop>
+ <tabstop>button_shift_shift</tabstop>
+ <tabstop>button_space_shift</tabstop>
+ <tabstop>button_1_num</tabstop>
+ <tabstop>button_2_num</tabstop>
+ <tabstop>button_3_num</tabstop>
+ <tabstop>button_backspace_num</tabstop>
+ <tabstop>button_4_num</tabstop>
+ <tabstop>button_5_num</tabstop>
+ <tabstop>button_6_num</tabstop>
+ <tabstop>button_ok_num</tabstop>
+ <tabstop>button_7_num</tabstop>
+ <tabstop>button_8_num</tabstop>
+ <tabstop>button_9_num</tabstop>
+ <tabstop>button_0_num</tabstop>
+ </tabstops>
+ <resources>
+ <include location="../../../dist/icons/overlay/overlay.qrc"/>
+ </resources>
+ <connections/>
+</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 @@
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
#include "core/hle/kernel/process.h"
-#include "core/settings.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
#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() {
ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
Settings::values.extended_logging =
ReadSetting(QStringLiteral("extended_logging"), false).toBool();
+ Settings::values.use_debug_asserts =
+ ReadSetting(QStringLiteral("use_debug_asserts"), false).toBool();
+ Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
qt_config->endGroup();
}
@@ -770,6 +773,13 @@ void Config::ReadRendererValues() {
ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
+#ifdef _WIN32
+ ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 0);
+#else
+ // *nix platforms may have issues with the borderless windowed fullscreen mode.
+ // Default to exclusive fullscreen on these platforms for now.
+ ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 1);
+#endif
ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
@@ -1230,6 +1240,7 @@ void Config::SaveDebuggingValues() {
WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
+ WriteSetting(QStringLiteral("use_debug_asserts"), Settings::values.use_debug_asserts, false);
WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false);
qt_config->endGroup();
@@ -1333,6 +1344,13 @@ void Config::SaveRendererValues() {
Settings::values.renderer_backend.UsingGlobal(), 0);
WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
+#ifdef _WIN32
+ WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 0);
+#else
+ // *nix platforms may have issues with the borderless windowed fullscreen mode.
+ // Default to exclusive fullscreen on these platforms for now.
+ WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 1);
+#endif
WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
@@ -1584,7 +1602,7 @@ void Config::Reload() {
ReadValues();
// To apply default value changes
SaveValues();
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
}
void 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 @@
#include <string>
#include <QMetaType>
#include <QVariant>
-#include "core/settings.h"
+#include "common/settings.h"
#include "yuzu/uisettings.h"
class QSettings;
@@ -131,6 +131,6 @@ private:
bool global;
};
-// These metatype declarations cannot be in core/settings.h because core is devoid of QT
+// These metatype declarations cannot be in common/settings.h because core is devoid of QT
Q_DECLARE_METATYPE(Settings::RendererBackend);
Q_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 @@
#include <QComboBox>
#include <QObject>
#include <QString>
-#include "core/settings.h"
+#include "common/settings.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_per_game.h"
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 @@
#include <QCheckBox>
#include <QComboBox>
#include <QString>
-#include "core/settings.h"
+#include "common/settings.h"
namespace ConfigurationShared {
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 @@
#include "audio_core/sink.h"
#include "audio_core/sink_details.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_audio.h"
#include "yuzu/configuration/configuration_shared.h"
#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 @@
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_cpu.h"
#include "yuzu/configuration/configure_cpu.h"
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 @@
#include <memory>
#include <QWidget>
-#include "core/settings.h"
+#include "common/settings.h"
namespace Ui {
class 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 @@
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_cpu_debug.h"
#include "yuzu/configuration/configure_cpu_debug.h"
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 @@
#include <memory>
#include <QWidget>
-#include "core/settings.h"
+#include "common/settings.h"
namespace Ui {
class 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 @@
#include "common/file_util.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_debug.h"
#include "yuzu/configuration/configure_debug.h"
#include "yuzu/debugger/console.h"
@@ -34,6 +34,8 @@ void ConfigureDebug::SetConfiguration() {
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
ui->reporting_services->setChecked(Settings::values.reporting_services);
ui->quest_flag->setChecked(Settings::values.quest_flag);
+ ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts);
+ ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
@@ -47,13 +49,15 @@ void ConfigureDebug::ApplyConfiguration() {
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
Settings::values.reporting_services = ui->reporting_services->isChecked();
Settings::values.quest_flag = ui->quest_flag->isChecked();
+ Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
+ Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
Settings::values.extended_logging = ui->extended_logging->isChecked();
Debugger::ToggleConsole();
- Log::Filter filter;
+ Common::Log::Filter filter;
filter.ParseFilterString(Settings::values.log_filter);
- Log::SetGlobalFilter(filter);
+ Common::Log::SetGlobalFilter(filter);
}
void 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 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="use_debug_asserts">
+ <property name="text">
+ <string>Enable Debug Asserts</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="use_auto_stub">
+ <property name="text">
+ <string>Enable Auto-Stub</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>This will be reset automatically when yuzu closes.</string>
+ </property>
+ <property name="indent">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</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 @@
#include <QHash>
#include <QListWidgetItem>
#include <QSignalBlocker>
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_dialog.h"
@@ -55,7 +55,7 @@ void ConfigureDialog::ApplyConfiguration() {
ui->debugTab->ApplyConfiguration();
ui->webTab->ApplyConfiguration();
ui->serviceTab->ApplyConfiguration();
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
Settings::LogSettings();
}
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 @@
#include <QMessageBox>
#include "common/common_paths.h"
#include "common/file_util.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "ui_configure_filesystem.h"
#include "yuzu/configuration/configure_filesystem.h"
#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 @@
#include <QCheckBox>
#include <QSpinBox>
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_general.h"
#include "yuzu/configuration/configuration_shared.h"
#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 @@
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_graphics.h"
#include "video_core/vulkan_common/vulkan_instance.h"
#include "video_core/vulkan_common/vulkan_library.h"
@@ -77,18 +77,25 @@ void ConfigureGraphics::SetConfiguration() {
if (Settings::IsConfiguringGlobal()) {
ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
+ ui->fullscreen_mode_combobox->setCurrentIndex(Settings::values.fullscreen_mode.GetValue());
ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
} else {
ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
ConfigurationShared::SetHighlight(ui->api_layout,
!Settings::values.renderer_backend.UsingGlobal());
+
+ ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox,
+ &Settings::values.fullscreen_mode);
+ ConfigurationShared::SetHighlight(ui->fullscreen_mode_label,
+ !Settings::values.fullscreen_mode.UsingGlobal());
+
ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
&Settings::values.aspect_ratio);
+ ConfigurationShared::SetHighlight(ui->ar_label,
+ !Settings::values.aspect_ratio.UsingGlobal());
ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
- ConfigurationShared::SetHighlight(ui->ar_label,
- !Settings::values.aspect_ratio.UsingGlobal());
ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
}
@@ -107,6 +114,9 @@ void ConfigureGraphics::ApplyConfiguration() {
if (Settings::values.vulkan_device.UsingGlobal()) {
Settings::values.vulkan_device.SetValue(vulkan_device);
}
+ if (Settings::values.fullscreen_mode.UsingGlobal()) {
+ Settings::values.fullscreen_mode.SetValue(ui->fullscreen_mode_combobox->currentIndex());
+ }
if (Settings::values.aspect_ratio.UsingGlobal()) {
Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
}
@@ -140,6 +150,8 @@ void ConfigureGraphics::ApplyConfiguration() {
}
}
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
+ ui->fullscreen_mode_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
ui->aspect_ratio_combobox);
@@ -227,7 +239,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
vulkan_devices.clear();
vulkan_devices.reserve(physical_devices.size());
for (const VkPhysicalDevice device : physical_devices) {
- const char* const name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
+ const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
vulkan_devices.push_back(QString::fromStdString(name));
}
@@ -253,6 +265,7 @@ void ConfigureGraphics::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
+ ui->fullscreen_mode_combobox->setEnabled(Settings::values.fullscreen_mode.UsingGlobal());
ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
ui->use_asynchronous_gpu_emulation->setEnabled(
Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
@@ -278,6 +291,8 @@ void ConfigureGraphics::SetupPerGameUI() {
ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
Settings::values.aspect_ratio.GetValue(true));
+ ConfigurationShared::SetColoredComboBox(ui->fullscreen_mode_combobox, ui->fullscreen_mode_label,
+ Settings::values.fullscreen_mode.GetValue(true));
ConfigurationShared::InsertGlobalItem(
ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
}
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 @@
#include <vector>
#include <QString>
#include <QWidget>
-#include "core/settings.h"
+#include "common/settings.h"
namespace ConfigurationShared {
enum 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 @@
</widget>
</item>
<item>
+ <widget class="QWidget" name="fullscreen_mode_layout" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_1">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="fullscreen_mode_label">
+ <property name="text">
+ <string>Fullscreen Mode:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="fullscreen_mode_combobox">
+ <item>
+ <property name="text">
+ <string>Borderless Windowed</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Exclusive Fullscreen</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="QWidget" name="aspect_ratio_layout" native="true">
- <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_graphics_advanced.h"
#include "yuzu/configuration/configuration_shared.h"
#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 @@
#include <QMenu>
#include <QMessageBox>
#include <QStandardItemModel>
-#include "core/settings.h"
+#include "common/settings.h"
#include "ui_configure_hotkeys.h"
#include "yuzu/configuration/config.h"
#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 @@
// Refer to the license.txt file included.
#include <QColorDialog>
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_input_advanced.h"
#include "yuzu/configuration/configure_input_advanced.h"
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 @@
#include <QWidget>
#include "common/param_package.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "ui_configure_input.h"
class 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 @@
#include <array>
#include <QFrame>
#include <QPointer>
+#include "common/settings.h"
#include "core/frontend/input.h"
-#include "core/settings.h"
class QLabel;
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 @@
#include <QVBoxLayout>
#include "common/logging/log.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "input_common/main.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
@@ -23,8 +23,7 @@
#include "yuzu/configuration/configure_touch_from_button.h"
CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
- const std::string& host, u16 port,
- u8 pad_index)
+ const std::string& host, u16 port)
: QDialog(parent) {
layout = new QVBoxLayout;
status_label = new QLabel(tr("Communicating with the server..."));
@@ -41,7 +40,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
using namespace InputCommon::CemuhookUDP;
job = std::make_unique<CalibrationConfigurationJob>(
- host, port, pad_index,
+ host, port,
[this](CalibrationConfigurationJob::Status status) {
QString text;
switch (status) {
@@ -217,7 +216,7 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
ui->udp_test->setText(tr("Testing"));
udp_test_in_progress = true;
InputCommon::CemuhookUDP::TestCommunication(
- ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0,
+ ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()),
[this] {
LOG_INFO(Frontend, "UDP input test success");
QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
@@ -232,7 +231,7 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() {
ui->touch_calibration_config->setEnabled(false);
ui->touch_calibration_config->setText(tr("Configuring"));
CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(),
- static_cast<u16>(ui->udp_port->text().toUInt()), 0);
+ static_cast<u16>(ui->udp_port->text().toUInt()));
dialog.exec();
if (dialog.completed) {
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;
class CalibrationConfigurationDialog : public QDialog {
Q_OBJECT
public:
- explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port,
- u8 pad_index);
+ explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port);
~CalibrationConfigurationDialog() override;
private:
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() {
ui->graphicsAdvancedTab->ApplyConfiguration();
ui->audioTab->ApplyConfiguration();
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
Settings::LogSettings();
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 @@
#include <QVBoxLayout>
#include "common/assert.h"
#include "common/file_util.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/service/acc/profile_manager.h"
-#include "core/settings.h"
#include "ui_configure_profile_manager.h"
#include "yuzu/configuration/configure_profile_manager.h"
#include "yuzu/util/limitable_input_dialog.h"
@@ -180,7 +180,7 @@ void ConfigureProfileManager::ApplyConfiguration() {
return;
}
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
}
void 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 @@
#include <QGraphicsItem>
#include <QtConcurrent/QtConcurrent>
+#include "common/settings.h"
#include "core/hle/service/bcat/backend/boxcat.h"
-#include "core/settings.h"
#include "ui_configure_service.h"
#include "yuzu/configuration/configure_service.h"
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 @@
#include <QMessageBox>
#include "common/assert.h"
#include "common/file_util.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/hle/service/time/time.h"
-#include "core/settings.h"
#include "ui_configure_system.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_system.h"
@@ -199,7 +199,7 @@ void ConfigureSystem::ApplyConfiguration() {
}
}
- Settings::Apply(system);
+ system.ApplySettings();
}
void 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 @@
#include <QStandardItemModel>
#include <QTimer>
#include "common/param_package.h"
+#include "common/settings.h"
#include "core/frontend/framebuffer_layout.h"
-#include "core/settings.h"
#include "input_common/main.h"
#include "ui_configure_touch_from_button.h"
#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 @@
#include <QDirIterator>
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/settings.h"
#include "core/core.h"
-#include "core/settings.h"
#include "ui_configure_ui.h"
#include "yuzu/configuration/configure_ui.h"
#include "yuzu/uisettings.h"
@@ -85,7 +85,7 @@ void ConfigureUi::ApplyConfiguration() {
UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked();
Common::FS::GetUserPath(Common::FS::UserPath::ScreenshotsDir,
ui->screenshot_path_edit->text().toStdString());
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
}
void 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 @@
#include <fmt/format.h>
#include "common/param_package.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "ui_configure_vibration.h"
#include "yuzu/configuration/configure_vibration.h"
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 @@
#include <QIcon>
#include <QMessageBox>
#include <QtConcurrent/QtConcurrentRun>
-#include "core/settings.h"
+#include "common/settings.h"
#include "core/telemetry_session.h"
#include "ui_configure_web.h"
#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() {
freopen_s(&temp, "CONIN$", "r", stdin);
freopen_s(&temp, "CONOUT$", "w", stdout);
freopen_s(&temp, "CONOUT$", "w", stderr);
- Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
+ Common::Log::AddBackend(std::make_unique<Common::Log::ColorConsoleBackend>());
}
} else {
if (FreeConsole()) {
// In order to close the console, we have to also detach the streams on it.
// Just redirect them to NUL if there is no console window
- Log::RemoveBackend(Log::ColorConsoleBackend::Name());
+ Common::Log::RemoveBackend(Common::Log::ColorConsoleBackend::Name());
freopen_s(&temp, "NUL", "r", stdin);
freopen_s(&temp, "NUL", "w", stdout);
freopen_s(&temp, "NUL", "w", stderr);
@@ -43,9 +43,9 @@ void ToggleConsole() {
}
#else
if (UISettings::values.show_console) {
- Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
+ Common::Log::AddBackend(std::make_unique<Common::Log::ColorConsoleBackend>());
} else {
- Log::RemoveBackend(Log::ColorConsoleBackend::Name());
+ Common::Log::RemoveBackend(Common::Log::ColorConsoleBackend::Name());
}
#endif
}
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 @@
#include <QAction>
#include <QLayout>
#include <QString>
-#include "core/settings.h"
+#include "common/settings.h"
#include "yuzu/configuration/configure_input_player_widget.h"
#include "yuzu/debugger/controller.h"
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
#ifdef ARCHITECTURE_x86_64
#include "common/x64/cpu_detect.h"
#endif
+#include "common/settings.h"
#include "common/telemetry.h"
#include "core/core.h"
#include "core/crypto/key_manager.h"
@@ -98,9 +99,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
#include "core/perf_stats.h"
-#include "core/settings.h"
#include "core/telemetry_session.h"
#include "input_common/main.h"
+#include "util/overlay_dialog.h"
#include "video_core/gpu.h"
#include "video_core/shader_notify.h"
#include "yuzu/about_dialog.h"
@@ -164,19 +165,21 @@ void GMainWindow::ShowTelemetryCallout() {
"<br/><br/>Would you like to share your usage data with us?");
if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) {
Settings::values.enable_telemetry = false;
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
}
}
const int GMainWindow::max_recent_files_item;
static void InitializeLogging() {
+ using namespace Common;
+
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
- const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir);
- Common::FS::CreateFullPath(log_dir);
+ const std::string& log_dir = FS::GetUserPath(FS::UserPath::LogDir);
+ FS::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
#ifdef _WIN32
Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
@@ -225,6 +228,8 @@ GMainWindow::GMainWindow()
SetDiscordEnabled(UISettings::values.enable_discord_presence);
discord_rpc->Update();
+ RegisterMetaTypes();
+
InitializeWidgets();
InitializeDebugWidgets();
InitializeRecentFileMenuActions();
@@ -320,6 +325,34 @@ GMainWindow::GMainWindow()
continue;
}
+ // Launch game with a specific user
+ if (args[i] == QStringLiteral("-u")) {
+ if (i >= args.size() - 1) {
+ continue;
+ }
+
+ if (args[i + 1].startsWith(QChar::fromLatin1('-'))) {
+ continue;
+ }
+
+ bool argument_ok;
+ const std::size_t selected_user = args[++i].toUInt(&argument_ok);
+
+ if (!argument_ok) {
+ LOG_ERROR(Frontend, "Invalid user argument");
+ continue;
+ }
+
+ const Service::Account::ProfileManager manager;
+ if (!manager.UserExistsIndex(selected_user)) {
+ LOG_ERROR(Frontend, "Selected user doesn't exist");
+ continue;
+ }
+
+ Settings::values.current_user = selected_user;
+ continue;
+ }
+
// Launch game at path
if (args[i] == QStringLiteral("-g")) {
if (i >= args.size() - 1) {
@@ -345,6 +378,55 @@ GMainWindow::~GMainWindow() {
delete render_window;
}
+void GMainWindow::RegisterMetaTypes() {
+ // Register integral and floating point types
+ qRegisterMetaType<u8>("u8");
+ qRegisterMetaType<u16>("u16");
+ qRegisterMetaType<u32>("u32");
+ qRegisterMetaType<u64>("u64");
+ qRegisterMetaType<u128>("u128");
+ qRegisterMetaType<s8>("s8");
+ qRegisterMetaType<s16>("s16");
+ qRegisterMetaType<s32>("s32");
+ qRegisterMetaType<s64>("s64");
+ qRegisterMetaType<f32>("f32");
+ qRegisterMetaType<f64>("f64");
+
+ // Register string types
+ qRegisterMetaType<std::string>("std::string");
+ qRegisterMetaType<std::wstring>("std::wstring");
+ qRegisterMetaType<std::u8string>("std::u8string");
+ qRegisterMetaType<std::u16string>("std::u16string");
+ qRegisterMetaType<std::u32string>("std::u32string");
+ qRegisterMetaType<std::string_view>("std::string_view");
+ qRegisterMetaType<std::wstring_view>("std::wstring_view");
+ qRegisterMetaType<std::u8string_view>("std::u8string_view");
+ qRegisterMetaType<std::u16string_view>("std::u16string_view");
+ qRegisterMetaType<std::u32string_view>("std::u32string_view");
+
+ // Register applet types
+
+ // Controller Applet
+ qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
+
+ // Software Keyboard Applet
+ qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>(
+ "Core::Frontend::KeyboardInitializeParameters");
+ qRegisterMetaType<Core::Frontend::InlineAppearParameters>(
+ "Core::Frontend::InlineAppearParameters");
+ qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters");
+ qRegisterMetaType<Service::AM::Applets::SwkbdResult>("Service::AM::Applets::SwkbdResult");
+ qRegisterMetaType<Service::AM::Applets::SwkbdTextCheckResult>(
+ "Service::AM::Applets::SwkbdTextCheckResult");
+ qRegisterMetaType<Service::AM::Applets::SwkbdReplyType>("Service::AM::Applets::SwkbdReplyType");
+
+ // Web Browser Applet
+ qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
+
+ // Register loader types
+ qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
+}
+
void GMainWindow::ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters) {
QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
@@ -357,7 +439,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
emit ControllerSelectorReconfigureFinished();
// Don't forget to apply settings.
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
config->Save();
UpdateStatusButtons();
@@ -384,25 +466,112 @@ void GMainWindow::ProfileSelectorSelectProfile() {
emit ProfileSelectorFinishedSelection(uuid);
}
-void GMainWindow::SoftwareKeyboardGetText(
- const Core::Frontend::SoftwareKeyboardParameters& parameters) {
- QtSoftwareKeyboardDialog dialog(this, parameters);
- dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
- Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
- Qt::WindowCloseButtonHint);
- dialog.setWindowModality(Qt::WindowModal);
+void GMainWindow::SoftwareKeyboardInitialize(
+ bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) {
+ if (software_keyboard) {
+ LOG_ERROR(Frontend, "The software keyboard is already initialized!");
+ return;
+ }
- if (dialog.exec() == QDialog::Rejected) {
- emit SoftwareKeyboardFinishedText(std::nullopt);
+ software_keyboard = new QtSoftwareKeyboardDialog(render_window, Core::System::GetInstance(),
+ is_inline, std::move(initialize_parameters));
+
+ if (is_inline) {
+ connect(
+ software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this,
+ [this](Service::AM::Applets::SwkbdReplyType reply_type, std::u16string submitted_text,
+ s32 cursor_position) {
+ emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position);
+ },
+ Qt::QueuedConnection);
+ } else {
+ connect(
+ software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this,
+ [this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text) {
+ emit SoftwareKeyboardSubmitNormalText(result, submitted_text);
+ },
+ Qt::QueuedConnection);
+ }
+}
+
+void GMainWindow::SoftwareKeyboardShowNormal() {
+ if (!software_keyboard) {
+ LOG_ERROR(Frontend, "The software keyboard is not initialized!");
+ return;
+ }
+
+ const auto& layout = render_window->GetFramebufferLayout();
+
+ const auto x = layout.screen.left;
+ const auto y = layout.screen.top;
+ const auto w = layout.screen.GetWidth();
+ const auto h = layout.screen.GetHeight();
+
+ software_keyboard->ShowNormalKeyboard(render_window->mapToGlobal(QPoint(x, y)), QSize(w, h));
+}
+
+void GMainWindow::SoftwareKeyboardShowTextCheck(
+ Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) {
+ if (!software_keyboard) {
+ LOG_ERROR(Frontend, "The software keyboard is not initialized!");
return;
}
- emit SoftwareKeyboardFinishedText(dialog.GetText());
+ software_keyboard->ShowTextCheckDialog(text_check_result, text_check_message);
}
-void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) {
- QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message));
- emit SoftwareKeyboardFinishedCheckDialog();
+void GMainWindow::SoftwareKeyboardShowInline(
+ Core::Frontend::InlineAppearParameters appear_parameters) {
+ if (!software_keyboard) {
+ LOG_ERROR(Frontend, "The software keyboard is not initialized!");
+ return;
+ }
+
+ const auto& layout = render_window->GetFramebufferLayout();
+
+ const auto x =
+ static_cast<int>(layout.screen.left + (0.5f * layout.screen.GetWidth() *
+ ((2.0f * appear_parameters.key_top_translate_x) +
+ (1.0f - appear_parameters.key_top_scale_x))));
+ const auto y =
+ static_cast<int>(layout.screen.top + (layout.screen.GetHeight() *
+ ((2.0f * appear_parameters.key_top_translate_y) +
+ (1.0f - appear_parameters.key_top_scale_y))));
+ const auto w = static_cast<int>(layout.screen.GetWidth() * appear_parameters.key_top_scale_x);
+ const auto h = static_cast<int>(layout.screen.GetHeight() * appear_parameters.key_top_scale_y);
+
+ software_keyboard->ShowInlineKeyboard(std::move(appear_parameters),
+ render_window->mapToGlobal(QPoint(x, y)), QSize(w, h));
+}
+
+void GMainWindow::SoftwareKeyboardHideInline() {
+ if (!software_keyboard) {
+ LOG_ERROR(Frontend, "The software keyboard is not initialized!");
+ return;
+ }
+
+ software_keyboard->HideInlineKeyboard();
+}
+
+void GMainWindow::SoftwareKeyboardInlineTextChanged(
+ Core::Frontend::InlineTextParameters text_parameters) {
+ if (!software_keyboard) {
+ LOG_ERROR(Frontend, "The software keyboard is not initialized!");
+ return;
+ }
+
+ software_keyboard->InlineTextChanged(std::move(text_parameters));
+}
+
+void GMainWindow::SoftwareKeyboardExit() {
+ if (!software_keyboard) {
+ return;
+ }
+
+ software_keyboard->ExitKeyboard();
+
+ software_keyboard = nullptr;
}
void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
@@ -622,7 +791,7 @@ void GMainWindow::InitializeWidgets() {
Settings::values.use_asynchronous_gpu_emulation.SetValue(
!Settings::values.use_asynchronous_gpu_emulation.GetValue());
async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
});
async_status_button->setText(tr("ASYNC"));
async_status_button->setCheckable(true);
@@ -638,7 +807,7 @@ void GMainWindow::InitializeWidgets() {
}
Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue());
multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
});
multicore_status_button->setText(tr("MULTICORE"));
multicore_status_button->setCheckable(true);
@@ -669,7 +838,7 @@ void GMainWindow::InitializeWidgets() {
Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL);
}
- Settings::Apply(Core::System::GetInstance());
+ Core::System::GetInstance().ApplySettings();
});
statusBar()->insertPermanentWidget(0, renderer_status_button);
@@ -948,6 +1117,10 @@ void GMainWindow::ConnectWidgetEvents() {
connect(this, &GMainWindow::EmulationStopping, render_window,
&GRenderWindow::OnEmulationStopping);
+ // Software Keyboard Applet
+ connect(this, &GMainWindow::EmulationStarting, this, &GMainWindow::SoftwareKeyboardExit);
+ connect(this, &GMainWindow::EmulationStopping, this, &GMainWindow::SoftwareKeyboardExit);
+
connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
}
@@ -2157,15 +2330,6 @@ void GMainWindow::OnStartGame() {
emu_thread->SetRunning(true);
- qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
- qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
- "Core::Frontend::SoftwareKeyboardParameters");
- qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
- qRegisterMetaType<std::string>("std::string");
- qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
- qRegisterMetaType<std::string_view>("std::string_view");
- qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
-
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
ui.action_Start->setEnabled(false);
@@ -2214,8 +2378,11 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) {
BootGame(last_filename_booted, program_index);
}
-void GMainWindow::ErrorDisplayDisplayError(QString body) {
- QMessageBox::critical(this, tr("Error Display"), body);
+void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
+ OverlayDialog dialog(render_window, Core::System::GetInstance(), error_code, error_text,
+ QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter);
+ dialog.exec();
+
emit ErrorDisplayFinished();
}
@@ -2267,24 +2434,66 @@ void GMainWindow::ToggleFullscreen() {
void GMainWindow::ShowFullscreen() {
if (ui.action_Single_Window_Mode->isChecked()) {
UISettings::values.geometry = saveGeometry();
+
ui.menubar->hide();
statusBar()->hide();
- showFullScreen();
+
+ if (Settings::values.fullscreen_mode.GetValue() == 1) {
+ showFullScreen();
+ return;
+ }
+
+ hide();
+ setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
+ const auto screen_geometry = QApplication::desktop()->screenGeometry(this);
+ setGeometry(screen_geometry.x(), screen_geometry.y(), screen_geometry.width(),
+ screen_geometry.height() + 1);
+ raise();
+ showNormal();
} else {
UISettings::values.renderwindow_geometry = render_window->saveGeometry();
- render_window->showFullScreen();
+
+ if (Settings::values.fullscreen_mode.GetValue() == 1) {
+ render_window->showFullScreen();
+ return;
+ }
+
+ render_window->hide();
+ render_window->setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
+ const auto screen_geometry = QApplication::desktop()->screenGeometry(this);
+ render_window->setGeometry(screen_geometry.x(), screen_geometry.y(),
+ screen_geometry.width(), screen_geometry.height() + 1);
+ render_window->raise();
+ render_window->showNormal();
}
}
void GMainWindow::HideFullscreen() {
if (ui.action_Single_Window_Mode->isChecked()) {
+ if (Settings::values.fullscreen_mode.GetValue() == 1) {
+ showNormal();
+ restoreGeometry(UISettings::values.geometry);
+ } else {
+ hide();
+ setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
+ restoreGeometry(UISettings::values.geometry);
+ raise();
+ show();
+ }
+
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
ui.menubar->show();
- showNormal();
- restoreGeometry(UISettings::values.geometry);
} else {
- render_window->showNormal();
- render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
+ if (Settings::values.fullscreen_mode.GetValue() == 1) {
+ render_window->showNormal();
+ render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
+ } else {
+ render_window->hide();
+ render_window->setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
+ render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
+ render_window->raise();
+ render_window->show();
+ }
}
}
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;
enum class InstalledEntryType;
class GameListPlaceholder;
+class QtSoftwareKeyboardDialog;
+
namespace Core::Frontend {
struct ControllerParameters;
-struct SoftwareKeyboardParameters;
+struct InlineAppearParameters;
+struct InlineTextParameters;
+struct KeyboardInitializeParameters;
} // namespace Core::Frontend
namespace DiscordRPC {
@@ -57,8 +61,11 @@ class InputSubsystem;
}
namespace Service::AM::Applets {
+enum class SwkbdResult : u32;
+enum class SwkbdTextCheckResult : u32;
+enum class SwkbdReplyType : u32;
enum class WebExitReason : u32;
-}
+} // namespace Service::AM::Applets
enum class EmulatedDirectoryTarget {
NAND,
@@ -128,8 +135,10 @@ signals:
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
- void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
- void SoftwareKeyboardFinishedCheckDialog();
+ void SoftwareKeyboardSubmitNormalText(Service::AM::Applets::SwkbdResult result,
+ std::u16string submitted_text);
+ void SoftwareKeyboardSubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
+ std::u16string submitted_text, s32 cursor_position);
void WebBrowserExtractOfflineRomFS();
void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url);
@@ -139,15 +148,24 @@ public slots:
void OnExecuteProgram(std::size_t program_index);
void ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters);
- void ErrorDisplayDisplayError(QString body);
+ void SoftwareKeyboardInitialize(
+ bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters);
+ void SoftwareKeyboardShowNormal();
+ void SoftwareKeyboardShowTextCheck(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message);
+ void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters);
+ void SoftwareKeyboardHideInline();
+ void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
+ void SoftwareKeyboardExit();
+ void ErrorDisplayDisplayError(QString error_code, QString error_text);
void ProfileSelectorSelectProfile();
- void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
- void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
bool is_local);
void OnAppFocusStateChanged(Qt::ApplicationState state);
private:
+ void RegisterMetaTypes();
+
void InitializeWidgets();
void InitializeDebugWidgets();
void InitializeRecentFileMenuActions();
@@ -334,6 +352,9 @@ private:
// Disables the web applet for the rest of the emulated session
bool disable_web_applet{};
+ // Applets
+ QtSoftwareKeyboardDialog* software_keyboard = nullptr;
+
protected:
void dropEvent(QDropEvent* event) override;
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QKeyEvent>
+#include <QScreen>
+
+#include "core/core.h"
+#include "core/frontend/input_interpreter.h"
+#include "ui_overlay_dialog.h"
+#include "yuzu/util/overlay_dialog.h"
+
+namespace {
+
+constexpr float BASE_TITLE_FONT_SIZE = 14.0f;
+constexpr float BASE_FONT_SIZE = 18.0f;
+constexpr float BASE_WIDTH = 1280.0f;
+constexpr float BASE_HEIGHT = 720.0f;
+
+} // Anonymous namespace
+
+OverlayDialog::OverlayDialog(QWidget* parent, Core::System& system, const QString& title_text,
+ const QString& body_text, const QString& left_button_text,
+ const QString& right_button_text, Qt::Alignment alignment,
+ bool use_rich_text_)
+ : QDialog(parent), ui{std::make_unique<Ui::OverlayDialog>()}, use_rich_text{use_rich_text_} {
+ ui->setupUi(this);
+
+ setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint |
+ Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint);
+ setWindowModality(Qt::WindowModal);
+ setAttribute(Qt::WA_TranslucentBackground);
+
+ if (use_rich_text) {
+ InitializeRichTextDialog(title_text, body_text, left_button_text, right_button_text,
+ alignment);
+ } else {
+ InitializeRegularTextDialog(title_text, body_text, left_button_text, right_button_text,
+ alignment);
+ }
+
+ MoveAndResizeWindow();
+
+ // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend
+ if (system.IsPoweredOn()) {
+ input_interpreter = std::make_unique<InputInterpreter>(system);
+
+ StartInputThread();
+ }
+}
+
+OverlayDialog::~OverlayDialog() {
+ StopInputThread();
+}
+
+void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const QString& body_text,
+ const QString& left_button_text,
+ const QString& right_button_text,
+ Qt::Alignment alignment) {
+ ui->stackedDialog->setCurrentIndex(0);
+
+ ui->label_title->setText(title_text);
+ ui->label_dialog->setText(body_text);
+ ui->button_cancel->setText(left_button_text);
+ ui->button_ok_label->setText(right_button_text);
+
+ ui->label_dialog->setAlignment(alignment);
+
+ if (title_text.isEmpty()) {
+ ui->label_title->hide();
+ ui->verticalLayout_2->setStretch(0, 0);
+ ui->verticalLayout_2->setStretch(1, 219);
+ ui->verticalLayout_2->setStretch(2, 82);
+ }
+
+ if (left_button_text.isEmpty()) {
+ ui->button_cancel->hide();
+ ui->button_cancel->setEnabled(false);
+ }
+
+ if (right_button_text.isEmpty()) {
+ ui->button_ok_label->hide();
+ ui->button_ok_label->setEnabled(false);
+ }
+
+ connect(
+ ui->button_cancel, &QPushButton::clicked, this,
+ [this](bool) {
+ StopInputThread();
+ QDialog::reject();
+ },
+ Qt::QueuedConnection);
+ connect(
+ ui->button_ok_label, &QPushButton::clicked, this,
+ [this](bool) {
+ StopInputThread();
+ QDialog::accept();
+ },
+ Qt::QueuedConnection);
+}
+
+void OverlayDialog::InitializeRichTextDialog(const QString& title_text, const QString& body_text,
+ const QString& left_button_text,
+ const QString& right_button_text,
+ Qt::Alignment alignment) {
+ ui->stackedDialog->setCurrentIndex(1);
+
+ ui->label_title_rich->setText(title_text);
+ ui->text_browser_dialog->setText(body_text);
+ ui->button_cancel_rich->setText(left_button_text);
+ ui->button_ok_rich->setText(right_button_text);
+
+ // TODO (Morph/Rei): Replace this with something that works better
+ ui->text_browser_dialog->setAlignment(alignment);
+
+ if (title_text.isEmpty()) {
+ ui->label_title_rich->hide();
+ ui->verticalLayout_3->setStretch(0, 0);
+ ui->verticalLayout_3->setStretch(1, 438);
+ ui->verticalLayout_3->setStretch(2, 82);
+ }
+
+ if (left_button_text.isEmpty()) {
+ ui->button_cancel_rich->hide();
+ ui->button_cancel_rich->setEnabled(false);
+ }
+
+ if (right_button_text.isEmpty()) {
+ ui->button_ok_rich->hide();
+ ui->button_ok_rich->setEnabled(false);
+ }
+
+ connect(
+ ui->button_cancel_rich, &QPushButton::clicked, this,
+ [this](bool) {
+ StopInputThread();
+ QDialog::reject();
+ },
+ Qt::QueuedConnection);
+ connect(
+ ui->button_ok_rich, &QPushButton::clicked, this,
+ [this](bool) {
+ StopInputThread();
+ QDialog::accept();
+ },
+ Qt::QueuedConnection);
+}
+
+void OverlayDialog::MoveAndResizeWindow() {
+ const auto pos = parentWidget()->mapToGlobal(parentWidget()->rect().topLeft());
+ const auto width = static_cast<float>(parentWidget()->width());
+ const auto height = static_cast<float>(parentWidget()->height());
+
+ // High DPI
+ const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f;
+
+ const auto title_text_font_size = BASE_TITLE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+ const auto body_text_font_size =
+ BASE_FONT_SIZE * (((width / BASE_WIDTH) + (height / BASE_HEIGHT)) / 2.0f) / dpi_scale;
+ const auto button_text_font_size = BASE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+
+ QFont title_text_font(QStringLiteral("MS Shell Dlg 2"), title_text_font_size, QFont::Normal);
+ QFont body_text_font(QStringLiteral("MS Shell Dlg 2"), body_text_font_size, QFont::Normal);
+ QFont button_text_font(QStringLiteral("MS Shell Dlg 2"), button_text_font_size, QFont::Normal);
+
+ if (use_rich_text) {
+ ui->label_title_rich->setFont(title_text_font);
+ ui->text_browser_dialog->setFont(body_text_font);
+ ui->button_cancel_rich->setFont(button_text_font);
+ ui->button_ok_rich->setFont(button_text_font);
+ } else {
+ ui->label_title->setFont(title_text_font);
+ ui->label_dialog->setFont(body_text_font);
+ ui->button_cancel->setFont(button_text_font);
+ ui->button_ok_label->setFont(button_text_font);
+ }
+
+ QDialog::move(pos);
+ QDialog::resize(width, height);
+}
+
+template <HIDButton... T>
+void OverlayDialog::HandleButtonPressedOnce() {
+ const auto f = [this](HIDButton button) {
+ if (input_interpreter->IsButtonPressedOnce(button)) {
+ TranslateButtonPress(button);
+ }
+ };
+
+ (f(T), ...);
+}
+
+void OverlayDialog::TranslateButtonPress(HIDButton button) {
+ QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel;
+ QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label;
+
+ // TODO (Morph): Handle QTextBrowser text scrolling
+ // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it
+
+ switch (button) {
+ case HIDButton::A:
+ case HIDButton::B:
+ if (left_button->hasFocus()) {
+ left_button->click();
+ } else if (right_button->hasFocus()) {
+ right_button->click();
+ }
+ break;
+ case HIDButton::DLeft:
+ case HIDButton::LStickLeft:
+ focusPreviousChild();
+ break;
+ case HIDButton::DRight:
+ case HIDButton::LStickRight:
+ focusNextChild();
+ break;
+ default:
+ break;
+ }
+}
+
+void OverlayDialog::StartInputThread() {
+ if (input_thread_running) {
+ return;
+ }
+
+ input_thread_running = true;
+
+ input_thread = std::thread(&OverlayDialog::InputThread, this);
+}
+
+void OverlayDialog::StopInputThread() {
+ input_thread_running = false;
+
+ if (input_thread.joinable()) {
+ input_thread.join();
+ }
+}
+
+void OverlayDialog::InputThread() {
+ while (input_thread_running) {
+ input_interpreter->PollInput();
+
+ HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::DLeft, HIDButton::DRight,
+ HIDButton::LStickLeft, HIDButton::LStickRight>();
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+}
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <atomic>
+#include <memory>
+#include <thread>
+
+#include <QDialog>
+
+#include "common/common_types.h"
+
+enum class HIDButton : u8;
+
+class InputInterpreter;
+
+namespace Core {
+class System;
+}
+
+namespace Ui {
+class OverlayDialog;
+}
+
+/**
+ * An OverlayDialog is an interactive dialog that accepts controller input (while a game is running)
+ * This dialog attempts to replicate the look and feel of the Nintendo Switch's overlay dialogs and
+ * provide some extra features such as embedding HTML/Rich Text content in a QTextBrowser.
+ * The OverlayDialog provides 2 modes: one to embed regular text into a QLabel and another to embed
+ * HTML/Rich Text content into a QTextBrowser.
+ */
+class OverlayDialog final : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit OverlayDialog(QWidget* parent, Core::System& system, const QString& title_text,
+ const QString& body_text, const QString& left_button_text,
+ const QString& right_button_text,
+ Qt::Alignment alignment = Qt::AlignCenter, bool use_rich_text_ = false);
+ ~OverlayDialog() override;
+
+private:
+ /**
+ * Initializes a text dialog with a QLabel storing text.
+ * Only use this for short text as the dialog buttons would be squashed with longer text.
+ *
+ * @param title_text Title text to be displayed
+ * @param body_text Main text to be displayed
+ * @param left_button_text Left button text. If empty, the button is hidden and disabled
+ * @param right_button_text Right button text. If empty, the button is hidden and disabled
+ * @param alignment Main text alignment
+ */
+ void InitializeRegularTextDialog(const QString& title_text, const QString& body_text,
+ const QString& left_button_text,
+ const QString& right_button_text, Qt::Alignment alignment);
+
+ /**
+ * Initializes a text dialog with a QTextBrowser storing text.
+ * This is ideal for longer text or rich text content. A scrollbar is shown for longer text.
+ *
+ * @param title_text Title text to be displayed
+ * @param body_text Main text to be displayed
+ * @param left_button_text Left button text. If empty, the button is hidden and disabled
+ * @param right_button_text Right button text. If empty, the button is hidden and disabled
+ * @param alignment Main text alignment
+ */
+ void InitializeRichTextDialog(const QString& title_text, const QString& body_text,
+ const QString& left_button_text, const QString& right_button_text,
+ Qt::Alignment alignment);
+
+ /// Moves and resizes the dialog to be fully overlayed on top of the parent window.
+ void MoveAndResizeWindow();
+
+ /**
+ * Handles button presses and converts them into keyboard input.
+ *
+ * @tparam HIDButton The list of buttons that can be converted into keyboard input.
+ */
+ template <HIDButton... T>
+ void HandleButtonPressedOnce();
+
+ /**
+ * Translates a button press to focus or click either the left or right buttons.
+ *
+ * @param button The button press to process.
+ */
+ void TranslateButtonPress(HIDButton button);
+
+ void StartInputThread();
+ void StopInputThread();
+
+ /// The thread where input is being polled and processed.
+ void InputThread();
+
+ std::unique_ptr<Ui::OverlayDialog> ui;
+
+ bool use_rich_text;
+
+ std::unique_ptr<InputInterpreter> input_interpreter;
+
+ std::thread input_thread;
+
+ std::atomic<bool> input_thread_running{};
+};
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>OverlayDialog</class>
+ <widget class="QDialog" name="OverlayDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1280</width>
+ <height>720</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QStackedWidget" name="stackedDialog">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="lineDialog">
+ <layout class="QGridLayout" name="lineDialogGridLayout" rowstretch="210,300,210" columnstretch="250,780,250">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item row="1" column="1">
+ <widget class="QWidget" name="contentDialog" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="70,149,82">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_title">
+ <property name="font">
+ <font>
+ <pointsize>14</pointsize>
+ </font>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_dialog">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonsDialog" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="button_cancel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="button_ok_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="2">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="richDialog">
+ <layout class="QGridLayout" name="richDialogGridLayout" rowstretch="100,520,100" columnstretch="165,950,165">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <spacer name="verticalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1">
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1">
+ <widget class="QWidget" name="contentRichDialog" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_3" stretch="70,368,82">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_title_rich">
+ <property name="font">
+ <font>
+ <pointsize>14</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextBrowser" name="text_browser_dialog">
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="html">
+ <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;
+&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;
+p, li { white-space: pre-wrap; }
+&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;
+&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>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="buttonsRichDialog" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="button_cancel_rich">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="button_ok_rich">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../../../dist/icons/overlay/overlay.qrc"/>
+ </resources>
+ <connections/>
+</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 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/param_package.h"
+#include "common/settings.h"
#include "core/hle/service/acc/profile_manager.h"
-#include "core/settings.h"
#include "input_common/main.h"
#include "input_common/udp/client.h"
#include "yuzu_cmd/config.h"
@@ -428,6 +428,10 @@ void Config::ReadValues() {
Settings::values.reporting_services =
sdl2_config->GetBoolean("Debugging", "reporting_services", false);
Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false);
+ Settings::values.use_debug_asserts =
+ sdl2_config->GetBoolean("Debugging", "use_debug_asserts", false);
+ Settings::values.use_auto_stub = sdl2_config->GetBoolean("Debugging", "use_auto_stub", false);
+
Settings::values.disable_macro_jit =
sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
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
# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
# false: Retail/Normal Mode (default), true: Kiosk Mode
quest_flag =
+# Determines whether debug asserts should be enabled, which will throw an exception on asserts.
+# false: Disabled (default), true: Enabled
+use_debug_asserts =
+# Determines whether unimplemented HLE service calls should be automatically stubbed.
+# false: Disabled (default), true: Enabled
+use_auto_stub =
# Enables/Disables the macro JIT compiler
disable_macro_jit=false
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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
-#include "core/settings.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
#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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
-#include "core/settings.h"
+#include "common/settings.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
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 @@
#include "common/nvidia_flags.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "common/telemetry.h"
#include "core/core.h"
@@ -29,7 +30,6 @@
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
-#include "core/settings.h"
#include "core/telemetry_session.h"
#include "input_common/main.h"
#include "video_core/renderer_base.h"
@@ -74,14 +74,16 @@ static void PrintVersion() {
}
static void InitializeLogging() {
+ using namespace Common;
+
Log::Filter log_filter(Log::Level::Debug);
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
- const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir);
- Common::FS::CreateFullPath(log_dir);
+ const std::string& log_dir = FS::GetUserPath(FS::UserPath::LogDir);
+ FS::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
#ifdef _WIN32
Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
@@ -164,7 +166,7 @@ int main(int argc, char** argv) {
InputCommon::InputSubsystem input_subsystem;
// Apply the command line arguments
- Settings::Apply(system);
+ system.ApplySettings();
std::unique_ptr<EmuWindow_SDL2> emu_window;
switch (Settings::values.renderer_backend.GetValue()) {