summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt22
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt13
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt23
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt16
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt45
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt13
-rw-r--r--src/android/app/src/main/jni/native.cpp11
-rw-r--r--src/android/app/src/main/jni/native_input.cpp76
-rw-r--r--src/android/app/src/main/res/values/strings.xml1
-rw-r--r--src/audio_core/sink/cubeb_sink.cpp4
-rw-r--r--src/audio_core/sink/sink_stream.cpp4
-rw-r--r--src/common/demangle.cpp4
-rw-r--r--src/common/host_memory.cpp4
-rw-r--r--src/common/page_table.cpp4
-rw-r--r--src/common/scope_exit.h66
-rw-r--r--src/core/CMakeLists.txt191
-rw-r--r--src/core/core.cpp11
-rw-r--r--src/core/cpu_manager.cpp4
-rw-r--r--src/core/device_memory_manager.inc4
-rw-r--r--src/core/file_sys/fs_directory.h4
-rw-r--r--src/core/file_sys/fs_path_utility.h12
-rw-r--r--src/core/file_sys/fssystem/fssystem_aes_xts_storage.h1
-rw-r--r--src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp4
-rw-r--r--src/core/file_sys/program_metadata.cpp4
-rw-r--r--src/core/file_sys/system_archive/shared_font.cpp2
-rw-r--r--src/core/hle/kernel/k_client_session.cpp8
-rw-r--r--src/core/hle/kernel/k_page_table_base.cpp40
-rw-r--r--src/core/hle/kernel/k_process.cpp16
-rw-r--r--src/core/hle/kernel/k_server_session.cpp36
-rw-r--r--src/core/hle/kernel/k_thread_local_page.cpp4
-rw-r--r--src/core/hle/kernel/k_transfer_memory.cpp4
-rw-r--r--src/core/hle/kernel/kernel.cpp12
-rw-r--r--src/core/hle/kernel/svc/svc_code_memory.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_device_address_space.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_event.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_ipc.cpp8
-rw-r--r--src/core/hle/kernel/svc/svc_port.cpp8
-rw-r--r--src/core/hle/kernel/svc/svc_resource_limit.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_session.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_synchronization.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_thread.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_transfer_memory.cpp4
-rw-r--r--src/core/hle/service/am/am.cpp10
-rw-r--r--src/core/hle/service/am/am.h6
-rw-r--r--src/core/hle/service/am/applet.h6
-rw-r--r--src/core/hle/service/am/applet_data_broker.cpp4
-rw-r--r--src/core/hle/service/am/display_layer_manager.cpp151
-rw-r--r--src/core/hle/service/am/display_layer_manager.h62
-rw-r--r--src/core/hle/service/am/frontend/applet_web_browser.cpp2
-rw-r--r--src/core/hle/service/am/library_applet_storage.cpp4
-rw-r--r--src/core/hle/service/am/managed_layer_holder.cpp59
-rw-r--r--src/core/hle/service/am/managed_layer_holder.h32
-rw-r--r--src/core/hle/service/am/process.cpp4
-rw-r--r--src/core/hle/service/am/service/all_system_applet_proxies_service.cpp13
-rw-r--r--src/core/hle/service/am/service/all_system_applet_proxies_service.h8
-rw-r--r--src/core/hle/service/am/service/application_functions.cpp11
-rw-r--r--src/core/hle/service/am/service/application_proxy.cpp9
-rw-r--r--src/core/hle/service/am/service/application_proxy.h3
-rw-r--r--src/core/hle/service/am/service/application_proxy_service.cpp7
-rw-r--r--src/core/hle/service/am/service/application_proxy_service.h7
-rw-r--r--src/core/hle/service/am/service/display_controller.cpp6
-rw-r--r--src/core/hle/service/am/service/library_applet_creator.cpp2
-rw-r--r--src/core/hle/service/am/service/library_applet_proxy.cpp10
-rw-r--r--src/core/hle/service/am/service/library_applet_proxy.h3
-rw-r--r--src/core/hle/service/am/service/library_applet_self_accessor.cpp11
-rw-r--r--src/core/hle/service/am/service/self_controller.cpp53
-rw-r--r--src/core/hle/service/am/service/self_controller.h3
-rw-r--r--src/core/hle/service/am/service/system_applet_proxy.cpp10
-rw-r--r--src/core/hle/service/am/service/system_applet_proxy.h3
-rw-r--r--src/core/hle/service/am/service/window_controller.cpp2
-rw-r--r--src/core/hle/service/am/system_buffer_manager.cpp80
-rw-r--r--src/core/hle/service/am/system_buffer_manager.h52
-rw-r--r--src/core/hle/service/audio/audctl.cpp201
-rw-r--r--src/core/hle/service/audio/audctl.h50
-rw-r--r--src/core/hle/service/audio/audio.cpp4
-rw-r--r--src/core/hle/service/audio/audio_controller.cpp174
-rw-r--r--src/core/hle/service/audio/audio_controller.h58
-rw-r--r--src/core/hle/service/btm/btm.cpp272
-rw-r--r--src/core/hle/service/btm/btm.h4
-rw-r--r--src/core/hle/service/btm/btm_debug.cpp33
-rw-r--r--src/core/hle/service/btm/btm_debug.h21
-rw-r--r--src/core/hle/service/btm/btm_system.cpp31
-rw-r--r--src/core/hle/service/btm/btm_system.h25
-rw-r--r--src/core/hle/service/btm/btm_system_core.cpp127
-rw-r--r--src/core/hle/service/btm/btm_system_core.h60
-rw-r--r--src/core/hle/service/btm/btm_user.cpp30
-rw-r--r--src/core/hle/service/btm/btm_user.h25
-rw-r--r--src/core/hle/service/btm/btm_user_core.cpp103
-rw-r--r--src/core/hle/service/btm/btm_user_core.h47
-rw-r--r--src/core/hle/service/glue/time/static.cpp41
-rw-r--r--src/core/hle/service/glue/time/time_zone.cpp36
-rw-r--r--src/core/hle/service/ns/account_proxy_interface.cpp21
-rw-r--r--src/core/hle/service/ns/account_proxy_interface.h16
-rw-r--r--src/core/hle/service/ns/application_manager_interface.cpp519
-rw-r--r--src/core/hle/service/ns/application_manager_interface.h62
-rw-r--r--src/core/hle/service/ns/application_version_interface.cpp33
-rw-r--r--src/core/hle/service/ns/application_version_interface.h16
-rw-r--r--src/core/hle/service/ns/content_management_interface.cpp72
-rw-r--r--src/core/hle/service/ns/content_management_interface.h25
-rw-r--r--src/core/hle/service/ns/develop_interface.cpp38
-rw-r--r--src/core/hle/service/ns/develop_interface.h16
-rw-r--r--src/core/hle/service/ns/document_interface.cpp38
-rw-r--r--src/core/hle/service/ns/document_interface.h22
-rw-r--r--src/core/hle/service/ns/download_task_interface.cpp39
-rw-r--r--src/core/hle/service/ns/download_task_interface.h20
-rw-r--r--src/core/hle/service/ns/dynamic_rights_interface.cpp62
-rw-r--r--src/core/hle/service/ns/dynamic_rights_interface.h22
-rw-r--r--src/core/hle/service/ns/ecommerce_interface.cpp27
-rw-r--r--src/core/hle/service/ns/ecommerce_interface.h16
-rw-r--r--src/core/hle/service/ns/factory_reset_interface.cpp27
-rw-r--r--src/core/hle/service/ns/factory_reset_interface.h16
-rw-r--r--src/core/hle/service/ns/ns.cpp903
-rw-r--r--src/core/hle/service/ns/ns.h133
-rw-r--r--src/core/hle/service/ns/ns_results.h (renamed from src/core/hle/service/ns/errors.h)0
-rw-r--r--src/core/hle/service/ns/ns_types.h116
-rw-r--r--src/core/hle/service/ns/pdm_qry.cpp67
-rw-r--r--src/core/hle/service/ns/platform_service_manager.cpp (renamed from src/core/hle/service/ns/iplatform_service_manager.cpp)130
-rw-r--r--src/core/hle/service/ns/platform_service_manager.h (renamed from src/core/hle/service/ns/iplatform_service_manager.h)33
-rw-r--r--src/core/hle/service/ns/query_service.cpp56
-rw-r--r--src/core/hle/service/ns/query_service.h (renamed from src/core/hle/service/ns/pdm_qry.h)12
-rw-r--r--src/core/hle/service/ns/read_only_application_control_data_interface.cpp122
-rw-r--r--src/core/hle/service/ns/read_only_application_control_data_interface.h30
-rw-r--r--src/core/hle/service/ns/read_only_application_record_interface.cpp38
-rw-r--r--src/core/hle/service/ns/read_only_application_record_interface.h22
-rw-r--r--src/core/hle/service/ns/service_getter_interface.cpp120
-rw-r--r--src/core/hle/service/ns/service_getter_interface.h47
-rw-r--r--src/core/hle/service/ns/system_update_control.cpp44
-rw-r--r--src/core/hle/service/ns/system_update_control.h16
-rw-r--r--src/core/hle/service/ns/system_update_interface.cpp61
-rw-r--r--src/core/hle/service/ns/system_update_interface.h38
-rw-r--r--src/core/hle/service/ns/vulnerability_manager_interface.cpp31
-rw-r--r--src/core/hle/service/ns/vulnerability_manager_interface.h21
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp4
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp3
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h9
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp10
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.h4
-rw-r--r--src/core/hle/service/nvnflinger/binder.h23
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item_consumer.cpp2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item_consumer.h2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp76
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.h10
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.cpp32
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.h8
-rw-r--r--src/core/hle/service/nvnflinger/consumer_base.cpp2
-rw-r--r--src/core/hle/service/nvnflinger/consumer_base.h4
-rw-r--r--src/core/hle/service/nvnflinger/display.h53
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.cpp67
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.h20
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver.cpp (renamed from src/core/hle/service/vi/hos_binder_driver.cpp)31
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver.h (renamed from src/core/hle/service/vi/hos_binder_driver.h)30
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp22
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver_server.h16
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp333
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h166
-rw-r--r--src/core/hle/service/nvnflinger/surface_flinger.cpp139
-rw-r--r--src/core/hle/service/nvnflinger/surface_flinger.h69
-rw-r--r--src/core/hle/service/psc/time/static.cpp33
-rw-r--r--src/core/hle/service/psc/time/steady_clock.cpp25
-rw-r--r--src/core/hle/service/psc/time/system_clock.cpp8
-rw-r--r--src/core/hle/service/psc/time/time_zone_service.cpp32
-rw-r--r--src/core/hle/service/server_manager.cpp8
-rw-r--r--src/core/hle/service/service.cpp136
-rw-r--r--src/core/hle/service/service.h21
-rw-r--r--src/core/hle/service/services.cpp136
-rw-r--r--src/core/hle/service/services.h22
-rw-r--r--src/core/hle/service/vi/application_display_service.cpp123
-rw-r--r--src/core/hle/service/vi/application_display_service.h34
-rw-r--r--src/core/hle/service/vi/application_root_service.cpp13
-rw-r--r--src/core/hle/service/vi/application_root_service.h12
-rw-r--r--src/core/hle/service/vi/conductor.cpp114
-rw-r--r--src/core/hle/service/vi/conductor.h57
-rw-r--r--src/core/hle/service/vi/container.cpp226
-rw-r--r--src/core/hle/service/vi/container.h89
-rw-r--r--src/core/hle/service/vi/display.h44
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp143
-rw-r--r--src/core/hle/service/vi/display/vi_display.h143
-rw-r--r--src/core/hle/service/vi/display_list.h83
-rw-r--r--src/core/hle/service/vi/layer.h81
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp18
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h118
-rw-r--r--src/core/hle/service/vi/layer_list.h71
-rw-r--r--src/core/hle/service/vi/manager_display_service.cpp46
-rw-r--r--src/core/hle/service/vi/manager_display_service.h21
-rw-r--r--src/core/hle/service/vi/manager_root_service.cpp14
-rw-r--r--src/core/hle/service/vi/manager_root_service.h14
-rw-r--r--src/core/hle/service/vi/service_creator.cpp5
-rw-r--r--src/core/hle/service/vi/service_creator.h9
-rw-r--r--src/core/hle/service/vi/shared_buffer_manager.cpp (renamed from src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp)138
-rw-r--r--src/core/hle/service/vi/shared_buffer_manager.h (renamed from src/core/hle/service/nvnflinger/fb_share_buffer_manager.h)46
-rw-r--r--src/core/hle/service/vi/system_display_service.cpp66
-rw-r--r--src/core/hle/service/vi/system_display_service.h20
-rw-r--r--src/core/hle/service/vi/system_root_service.cpp11
-rw-r--r--src/core/hle/service/vi/system_root_service.h12
-rw-r--r--src/core/hle/service/vi/vi.cpp21
-rw-r--r--src/core/hle/service/vi/vi.h10
-rw-r--r--src/core/hle/service/vi/vi_types.h10
-rw-r--r--src/core/hle/service/vi/vsync_manager.cpp26
-rw-r--r--src/core/hle/service/vi/vsync_manager.h29
-rw-r--r--src/core/loader/nca.cpp4
-rw-r--r--src/core/memory.cpp8
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp4
-rw-r--r--src/hid_core/frontend/emulated_controller.cpp50
-rw-r--r--src/input_common/helpers/joycon_driver.cpp4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp47
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_special.cpp8
-rw-r--r--src/shader_recompiler/profile.h1
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h4
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/fence_manager.h4
-rw-r--r--src/video_core/gpu_thread.cpp4
-rw-r--r--src/video_core/host1x/ffmpeg/ffmpeg.cpp4
-rw-r--r--src/video_core/macro/macro_hle.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp8
-rw-r--r--src/video_core/renderer_vulkan/present/layer.cpp4
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp8
-rw-r--r--src/video_core/surface.cpp14
-rw-r--r--src/video_core/surface.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h6
-rw-r--r--src/video_core/vulkan_common/nsight_aftermath_tracker.cpp4
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h5
-rw-r--r--src/yuzu/main.cpp137
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui8
-rw-r--r--src/yuzu_cmd/yuzu.cpp4
237 files changed, 5746 insertions, 3915 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
index d35de80c4..a84ac77a2 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
@@ -64,17 +64,17 @@ data class PlayerInput(
64 fun hasMapping(): Boolean { 64 fun hasMapping(): Boolean {
65 var hasMapping = false 65 var hasMapping = false
66 buttons.forEach { 66 buttons.forEach {
67 if (it != "[empty]") { 67 if (it != "[empty]" && it.isNotEmpty()) {
68 hasMapping = true 68 hasMapping = true
69 } 69 }
70 } 70 }
71 analogs.forEach { 71 analogs.forEach {
72 if (it != "[empty]") { 72 if (it != "[empty]" && it.isNotEmpty()) {
73 hasMapping = true 73 hasMapping = true
74 } 74 }
75 } 75 }
76 motions.forEach { 76 motions.forEach {
77 if (it != "[empty]") { 77 if (it != "[empty]" && it.isNotEmpty()) {
78 hasMapping = true 78 hasMapping = true
79 } 79 }
80 } 80 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
index a0d8cfede..6f16cf5b1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
@@ -6,7 +6,8 @@ package org.yuzu.yuzu_emu.features.settings.model
6import org.yuzu.yuzu_emu.utils.NativeConfig 6import org.yuzu.yuzu_emu.utils.NativeConfig
7 7
8enum class StringSetting(override val key: String) : AbstractStringSetting { 8enum class StringSetting(override val key: String) : AbstractStringSetting {
9 DRIVER_PATH("driver_path"); 9 DRIVER_PATH("driver_path"),
10 DEVICE_NAME("device_name");
10 11
11 override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal) 12 override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
12 13
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
index 8f724835e..5fdf98318 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
@@ -16,6 +16,7 @@ import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
16import org.yuzu.yuzu_emu.features.settings.model.IntSetting 16import org.yuzu.yuzu_emu.features.settings.model.IntSetting
17import org.yuzu.yuzu_emu.features.settings.model.LongSetting 17import org.yuzu.yuzu_emu.features.settings.model.LongSetting
18import org.yuzu.yuzu_emu.features.settings.model.ShortSetting 18import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
19import org.yuzu.yuzu_emu.features.settings.model.StringSetting
19import org.yuzu.yuzu_emu.utils.NativeConfig 20import org.yuzu.yuzu_emu.utils.NativeConfig
20 21
21/** 22/**
@@ -75,6 +76,9 @@ abstract class SettingsItem(
75 get() = NativeLibrary.isRunning() && !setting.global && 76 get() = NativeLibrary.isRunning() && !setting.global &&
76 !NativeConfig.isPerGameConfigLoaded() 77 !NativeConfig.isPerGameConfigLoaded()
77 78
79 val clearable: Boolean
80 get() = !setting.global && NativeConfig.isPerGameConfigLoaded()
81
78 companion object { 82 companion object {
79 const val TYPE_HEADER = 0 83 const val TYPE_HEADER = 0
80 const val TYPE_SWITCH = 1 84 const val TYPE_SWITCH = 1
@@ -87,6 +91,7 @@ abstract class SettingsItem(
87 const val TYPE_INPUT = 8 91 const val TYPE_INPUT = 8
88 const val TYPE_INT_SINGLE_CHOICE = 9 92 const val TYPE_INT_SINGLE_CHOICE = 9
89 const val TYPE_INPUT_PROFILE = 10 93 const val TYPE_INPUT_PROFILE = 10
94 const val TYPE_STRING_INPUT = 11
90 95
91 const val FASTMEM_COMBINED = "fastmem_combined" 96 const val FASTMEM_COMBINED = "fastmem_combined"
92 97
@@ -105,6 +110,7 @@ abstract class SettingsItem(
105 110
106 // List of all general 111 // List of all general
107 val settingsItems = HashMap<String, SettingsItem>().apply { 112 val settingsItems = HashMap<String, SettingsItem>().apply {
113 put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
108 put( 114 put(
109 SwitchSetting( 115 SwitchSetting(
110 BooleanSetting.RENDERER_USE_SPEED_LIMIT, 116 BooleanSetting.RENDERER_USE_SPEED_LIMIT,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt
new file mode 100644
index 000000000..1eb999416
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.model.view
5
6import androidx.annotation.StringRes
7import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
8
9class StringInputSetting(
10 setting: AbstractStringSetting,
11 @StringRes titleId: Int = 0,
12 titleString: String = "",
13 @StringRes descriptionId: Int = 0,
14 descriptionString: String = ""
15) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
16 override val type = TYPE_STRING_INPUT
17
18 fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal)
19
20 fun setSelectedValue(selection: String) =
21 (setting as AbstractStringSetting).setString(selection)
22}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
index 45c8faa10..500ac6e66 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
@@ -85,6 +85,10 @@ class SettingsAdapter(
85 InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this) 85 InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
86 } 86 }
87 87
88 SettingsItem.TYPE_STRING_INPUT -> {
89 StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
90 }
91
88 else -> { 92 else -> {
89 HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) 93 HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
90 } 94 }
@@ -392,6 +396,15 @@ class SettingsAdapter(
392 popup.show() 396 popup.show()
393 } 397 }
394 398
399 fun onStringInputClick(item: StringInputSetting, position: Int) {
400 SettingsDialogFragment.newInstance(
401 settingsViewModel,
402 item,
403 SettingsItem.TYPE_STRING_INPUT,
404 position
405 ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
406 }
407
395 fun onLongClick(item: SettingsItem, position: Int): Boolean { 408 fun onLongClick(item: SettingsItem, position: Int): Boolean {
396 SettingsDialogFragment.newInstance( 409 SettingsDialogFragment.newInstance(
397 settingsViewModel, 410 settingsViewModel,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
index a81ff6b1a..7f562a1f4 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
@@ -14,6 +14,7 @@ import androidx.fragment.app.activityViewModels
14import com.google.android.material.dialog.MaterialAlertDialogBuilder 14import com.google.android.material.dialog.MaterialAlertDialogBuilder
15import com.google.android.material.slider.Slider 15import com.google.android.material.slider.Slider
16import org.yuzu.yuzu_emu.R 16import org.yuzu.yuzu_emu.R
17import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
17import org.yuzu.yuzu_emu.databinding.DialogSliderBinding 18import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
18import org.yuzu.yuzu_emu.features.input.NativeInput 19import org.yuzu.yuzu_emu.features.input.NativeInput
19import org.yuzu.yuzu_emu.features.input.model.AnalogDirection 20import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
@@ -23,6 +24,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
23import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 24import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
24import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting 25import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
25import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting 26import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
27import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
26import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting 28import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
27import org.yuzu.yuzu_emu.utils.ParamPackage 29import org.yuzu.yuzu_emu.utils.ParamPackage
28import org.yuzu.yuzu_emu.utils.collect 30import org.yuzu.yuzu_emu.utils.collect
@@ -37,6 +39,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
37 private val settingsViewModel: SettingsViewModel by activityViewModels() 39 private val settingsViewModel: SettingsViewModel by activityViewModels()
38 40
39 private lateinit var sliderBinding: DialogSliderBinding 41 private lateinit var sliderBinding: DialogSliderBinding
42 private lateinit var stringInputBinding: DialogEditTextBinding
40 43
41 override fun onCreate(savedInstanceState: Bundle?) { 44 override fun onCreate(savedInstanceState: Bundle?) {
42 super.onCreate(savedInstanceState) 45 super.onCreate(savedInstanceState)
@@ -131,6 +134,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
131 .create() 134 .create()
132 } 135 }
133 136
137 SettingsItem.TYPE_STRING_INPUT -> {
138 stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
139 val item = settingsViewModel.clickedItem as StringInputSetting
140 stringInputBinding.editText.setText(item.getSelectedValue())
141 MaterialAlertDialogBuilder(requireContext())
142 .setTitle(item.title)
143 .setView(stringInputBinding.root)
144 .setPositiveButton(android.R.string.ok, this)
145 .setNegativeButton(android.R.string.cancel, defaultCancelListener)
146 .create()
147 }
148
134 SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { 149 SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
135 val item = settingsViewModel.clickedItem as StringSingleChoiceSetting 150 val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
136 MaterialAlertDialogBuilder(requireContext()) 151 MaterialAlertDialogBuilder(requireContext())
@@ -158,6 +173,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
158 ): View? { 173 ): View? {
159 return when (type) { 174 return when (type) {
160 SettingsItem.TYPE_SLIDER -> sliderBinding.root 175 SettingsItem.TYPE_SLIDER -> sliderBinding.root
176 SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root
161 else -> super.onCreateView(inflater, container, savedInstanceState) 177 else -> super.onCreateView(inflater, container, savedInstanceState)
162 } 178 }
163 } 179 }
@@ -200,6 +216,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
200 val sliderSetting = settingsViewModel.clickedItem as SliderSetting 216 val sliderSetting = settingsViewModel.clickedItem as SliderSetting
201 sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) 217 sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
202 } 218 }
219
220 is StringInputSetting -> {
221 val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
222 stringInputSetting.setSelectedValue(
223 (stringInputBinding.editText.text ?: "").toString()
224 )
225 }
203 } 226 }
204 closeDialog() 227 closeDialog()
205 } 228 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index e491c29a2..3ea5f5008 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting
23import org.yuzu.yuzu_emu.features.settings.model.Settings 23import org.yuzu.yuzu_emu.features.settings.model.Settings
24import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag 24import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
25import org.yuzu.yuzu_emu.features.settings.model.ShortSetting 25import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
26import org.yuzu.yuzu_emu.features.settings.model.StringSetting
26import org.yuzu.yuzu_emu.features.settings.model.view.* 27import org.yuzu.yuzu_emu.features.settings.model.view.*
27import org.yuzu.yuzu_emu.utils.InputHandler 28import org.yuzu.yuzu_emu.utils.InputHandler
28import org.yuzu.yuzu_emu.utils.NativeConfig 29import org.yuzu.yuzu_emu.utils.NativeConfig
@@ -153,6 +154,7 @@ class SettingsFragmentPresenter(
153 154
154 private fun addSystemSettings(sl: ArrayList<SettingsItem>) { 155 private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
155 sl.apply { 156 sl.apply {
157 add(StringSetting.DEVICE_NAME.key)
156 add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) 158 add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
157 add(ShortSetting.RENDERER_SPEED_LIMIT.key) 159 add(ShortSetting.RENDERER_SPEED_LIMIT.key)
158 add(BooleanSetting.USE_DOCKED_MODE.key) 160 add(BooleanSetting.USE_DOCKED_MODE.key)
@@ -778,7 +780,7 @@ class SettingsFragmentPresenter(
778 playerIndex: Int, 780 playerIndex: Int,
779 paramName: String, 781 paramName: String,
780 stick: NativeAnalog, 782 stick: NativeAnalog,
781 defaultValue: Int 783 defaultValue: Float
782 ): AbstractIntSetting = 784 ): AbstractIntSetting =
783 object : AbstractIntSetting { 785 object : AbstractIntSetting {
784 val params get() = NativeInput.getStickParam(playerIndex, stick) 786 val params get() = NativeInput.getStickParam(playerIndex, stick)
@@ -786,7 +788,7 @@ class SettingsFragmentPresenter(
786 override val key = "" 788 override val key = ""
787 789
788 override fun getInt(needsGlobal: Boolean): Int = 790 override fun getInt(needsGlobal: Boolean): Int =
789 (params.get(paramName, 0.15f) * 100).toInt() 791 (params.get(paramName, defaultValue) * 100).toInt()
790 792
791 override fun setInt(value: Int) { 793 override fun setInt(value: Int) {
792 val tempParams = params 794 val tempParams = params
@@ -794,12 +796,12 @@ class SettingsFragmentPresenter(
794 NativeInput.setStickParam(playerIndex, stick, tempParams) 796 NativeInput.setStickParam(playerIndex, stick, tempParams)
795 } 797 }
796 798
797 override val defaultValue = defaultValue 799 override val defaultValue = (defaultValue * 100).toInt()
798 800
799 override fun getValueAsString(needsGlobal: Boolean): String = 801 override fun getValueAsString(needsGlobal: Boolean): String =
800 getInt(needsGlobal).toString() 802 getInt(needsGlobal).toString()
801 803
802 override fun reset() = setInt(defaultValue) 804 override fun reset() = setInt(this.defaultValue)
803 } 805 }
804 806
805 private fun getExtraStickSettings( 807 private fun getExtraStickSettings(
@@ -809,11 +811,11 @@ class SettingsFragmentPresenter(
809 val stickIsController = 811 val stickIsController =
810 NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog)) 812 NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
811 val modifierRangeSetting = 813 val modifierRangeSetting =
812 getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50) 814 getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f)
813 val stickRangeSetting = 815 val stickRangeSetting =
814 getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95) 816 getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f)
815 val stickDeadzoneSetting = 817 val stickDeadzoneSetting =
816 getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15) 818 getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f)
817 819
818 val out = mutableListOf<SettingsItem>().apply { 820 val out = mutableListOf<SettingsItem>().apply {
819 if (stickIsController) { 821 if (stickIsController) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
index 367db7fd2..0309fad59 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
@@ -13,7 +13,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
13import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting 13import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
14import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 14import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
15import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 15import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
16import org.yuzu.yuzu_emu.utils.NativeConfig
17import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible 16import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
18 17
19class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : 18class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -32,9 +31,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
32 val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) 31 val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
33 binding.textSettingValue.text = dateFormatter.format(zonedTime) 32 binding.textSettingValue.text = dateFormatter.format(zonedTime)
34 33
35 binding.buttonClear.setVisible( 34 binding.buttonClear.setVisible(setting.clearable)
36 !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
37 )
38 binding.buttonClear.setOnClickListener { 35 binding.buttonClear.setOnClickListener {
39 adapter.onClearClick(setting, bindingAdapterPosition) 36 adapter.onClearClick(setting, bindingAdapterPosition)
40 } 37 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
index e2fe0b072..489f55455 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
@@ -10,7 +10,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
10import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting 10import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
11import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting 11import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
12import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 12import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
13import org.yuzu.yuzu_emu.utils.NativeConfig
14import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible 13import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
15 14
16class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : 15class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -48,9 +47,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
48 binding.textSettingValue.setVisible(false) 47 binding.textSettingValue.setVisible(false)
49 } 48 }
50 49
51 binding.buttonClear.setVisible( 50 binding.buttonClear.setVisible(setting.clearable)
52 !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
53 )
54 binding.buttonClear.setOnClickListener { 51 binding.buttonClear.setOnClickListener {
55 adapter.onClearClick(setting, bindingAdapterPosition) 52 adapter.onClearClick(setting, bindingAdapterPosition)
56 } 53 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
index a37b59b44..90a7138cb 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
@@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
10import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting 10import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
12import org.yuzu.yuzu_emu.utils.NativeConfig
13import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible 12import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
14 13
15class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : 14class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -28,9 +27,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
28 setting.units 27 setting.units
29 ) 28 )
30 29
31 binding.buttonClear.setVisible( 30 binding.buttonClear.setVisible(setting.clearable)
32 !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
33 )
34 binding.buttonClear.setOnClickListener { 31 binding.buttonClear.setOnClickListener {
35 adapter.onClearClick(setting, bindingAdapterPosition) 32 adapter.onClearClick(setting, bindingAdapterPosition)
36 } 33 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt
new file mode 100644
index 000000000..a4fd36f62
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt
@@ -0,0 +1,45 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.ui.viewholder
5
6import android.view.View
7import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
8import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
9import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
10import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
11import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
12
13class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
14 SettingViewHolder(binding.root, adapter) {
15 private lateinit var setting: StringInputSetting
16
17 override fun bind(item: SettingsItem) {
18 setting = item as StringInputSetting
19 binding.textSettingName.text = setting.title
20 binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
21 binding.textSettingDescription.text = setting.description
22 binding.textSettingValue.setVisible(true)
23 binding.textSettingValue.text = setting.getSelectedValue()
24
25 binding.buttonClear.setVisible(setting.clearable)
26 binding.buttonClear.setOnClickListener {
27 adapter.onClearClick(setting, bindingAdapterPosition)
28 }
29
30 setStyle(setting.isEditable, binding)
31 }
32
33 override fun onClick(clicked: View) {
34 if (setting.isEditable) {
35 adapter.onStringInputClick(setting, bindingAdapterPosition)
36 }
37 }
38
39 override fun onLongClick(clicked: View): Boolean {
40 if (setting.isEditable) {
41 return adapter.onLongClick(setting, bindingAdapterPosition)
42 }
43 return false
44 }
45}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
index 53f7b301f..e5763264a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
@@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
10import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting 10import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
12import org.yuzu.yuzu_emu.utils.NativeConfig
13import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible 12import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
14 13
15class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : 14class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
@@ -29,9 +28,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
29 adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition) 28 adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
30 } 29 }
31 30
32 binding.buttonClear.setVisible( 31 binding.buttonClear.setVisible(setting.clearable)
33 !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
34 )
35 binding.buttonClear.setOnClickListener { 32 binding.buttonClear.setOnClickListener {
36 adapter.onClearClick(setting, bindingAdapterPosition) 33 adapter.onClearClick(setting, bindingAdapterPosition)
37 } 34 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index c3b2b11f8..bcc880e17 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -810,7 +810,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
810 } 810 }
811 } 811 }
812 } 812 }
813 binding.doneControlConfig.setVisible(false) 813 binding.doneControlConfig.setVisible(true)
814 binding.surfaceInputOverlay.setIsInEditMode(true) 814 binding.surfaceInputOverlay.setIsInEditMode(true)
815 } 815 }
816 816
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
index 66907085a..737e03584 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
@@ -28,6 +28,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
28import org.yuzu.yuzu_emu.R 28import org.yuzu.yuzu_emu.R
29import org.yuzu.yuzu_emu.features.input.model.NativeAnalog 29import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
30import org.yuzu.yuzu_emu.features.input.model.NativeButton 30import org.yuzu.yuzu_emu.features.input.model.NativeButton
31import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
31import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting 32import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
32import org.yuzu.yuzu_emu.features.settings.model.IntSetting 33import org.yuzu.yuzu_emu.features.settings.model.IntSetting
33import org.yuzu.yuzu_emu.overlay.model.OverlayControl 34import org.yuzu.yuzu_emu.overlay.model.OverlayControl
@@ -99,12 +100,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
99 } 100 }
100 101
101 var shouldUpdateView = false 102 var shouldUpdateView = false
102 val playerIndex = 103 val playerIndex = when (NativeInput.getStyleIndex(0)) {
103 if (NativeInput.isHandheldOnly()) { 104 NpadStyleIndex.Handheld -> 8
104 NativeInput.ConsoleDevice 105 else -> 0
105 } else { 106 }
106 NativeInput.Player1Device
107 }
108 107
109 for (button in overlayButtons) { 108 for (button in overlayButtons) {
110 if (!button.updateStatus(event)) { 109 if (!button.updateStatus(event)) {
@@ -664,7 +663,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
664 663
665 val overlayControlData = NativeConfig.getOverlayControlData() 664 val overlayControlData = NativeConfig.getOverlayControlData()
666 overlayControlData.forEach { 665 overlayControlData.forEach {
667 it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false 666 it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true
668 } 667 }
669 NativeConfig.setOverlayControlData(overlayControlData) 668 NativeConfig.setOverlayControlData(overlayControlData)
670 669
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 50cef5d2a..1226219ad 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -292,6 +292,9 @@ void EmulationSession::ShutdownEmulation() {
292 // Unload user input. 292 // Unload user input.
293 m_system.HIDCore().UnloadInputDevices(); 293 m_system.HIDCore().UnloadInputDevices();
294 294
295 // Enable all controllers
296 m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
297
295 // Shutdown the main emulated process 298 // Shutdown the main emulated process
296 if (m_load_result == Core::SystemResultStatus::Success) { 299 if (m_load_result == Core::SystemResultStatus::Success) {
297 m_system.DetachDebugger(); 300 m_system.DetachDebugger();
@@ -404,7 +407,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
404 const size_t program_index, 407 const size_t program_index,
405 const bool frontend_initiated) { 408 const bool frontend_initiated) {
406 MicroProfileOnThreadCreate("EmuThread"); 409 MicroProfileOnThreadCreate("EmuThread");
407 SCOPE_EXIT({ MicroProfileShutdown(); }); 410 SCOPE_EXIT {
411 MicroProfileShutdown();
412 };
408 413
409 LOG_INFO(Frontend, "starting"); 414 LOG_INFO(Frontend, "starting");
410 415
@@ -413,7 +418,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
413 return Core::SystemResultStatus::ErrorLoader; 418 return Core::SystemResultStatus::ErrorLoader;
414 } 419 }
415 420
416 SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); 421 SCOPE_EXIT {
422 EmulationSession::GetInstance().ShutdownEmulation();
423 };
417 424
418 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, 425 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
419 frontend_initiated); 426 frontend_initiated);
diff --git a/src/android/app/src/main/jni/native_input.cpp b/src/android/app/src/main/jni/native_input.cpp
index 37a65f2b8..4935a4607 100644
--- a/src/android/app/src/main/jni/native_input.cpp
+++ b/src/android/app/src/main/jni/native_input.cpp
@@ -102,8 +102,50 @@ void ApplyControllerConfig(size_t player_index,
102 } 102 }
103} 103}
104 104
105std::vector<s32> GetSupportedStyles(int player_index) {
106 auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
107 const auto npad_style_set = hid_core.GetSupportedStyleTag();
108 std::vector<s32> supported_indexes;
109 if (npad_style_set.fullkey == 1) {
110 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey));
111 }
112
113 if (npad_style_set.joycon_dual == 1) {
114 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual));
115 }
116
117 if (npad_style_set.joycon_left == 1) {
118 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft));
119 }
120
121 if (npad_style_set.joycon_right == 1) {
122 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight));
123 }
124
125 if (player_index == 0 && npad_style_set.handheld == 1) {
126 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld));
127 }
128
129 if (npad_style_set.gamecube == 1) {
130 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube));
131 }
132
133 return supported_indexes;
134}
135
105void ConnectController(size_t player_index, bool connected) { 136void ConnectController(size_t player_index, bool connected) {
106 auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); 137 auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
138 ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) {
139 auto supported_styles = GetSupportedStyles(player_index);
140 auto controller_style = controller->GetNpadStyleIndex(true);
141 auto style = std::find(supported_styles.begin(), supported_styles.end(),
142 static_cast<int>(controller_style));
143 if (style == supported_styles.end() && !supported_styles.empty()) {
144 controller->SetNpadStyleIndex(
145 static_cast<Core::HID::NpadStyleIndex>(supported_styles[0]));
146 }
147 });
148
107 if (player_index == 0) { 149 if (player_index == 0) {
108 auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); 150 auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
109 auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); 151 auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
@@ -522,36 +564,10 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv
522 564
523jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl( 565jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
524 JNIEnv* env, jobject j_obj, jint j_player_index) { 566 JNIEnv* env, jobject j_obj, jint j_player_index) {
525 auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); 567 auto supported_styles = GetSupportedStyles(j_player_index);
526 const auto npad_style_set = hid_core.GetSupportedStyleTag(); 568 jintArray j_supported_indexes = env->NewIntArray(supported_styles.size());
527 std::vector<s32> supported_indexes; 569 env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(),
528 if (npad_style_set.fullkey == 1) { 570 supported_styles.data());
529 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey));
530 }
531
532 if (npad_style_set.joycon_dual == 1) {
533 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual));
534 }
535
536 if (npad_style_set.joycon_left == 1) {
537 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft));
538 }
539
540 if (npad_style_set.joycon_right == 1) {
541 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight));
542 }
543
544 if (j_player_index == 0 && npad_style_set.handheld == 1) {
545 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld));
546 }
547
548 if (npad_style_set.gamecube == 1) {
549 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube));
550 }
551
552 jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size());
553 env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(),
554 supported_indexes.data());
555 return j_supported_indexes; 571 return j_supported_indexes;
556} 572}
557 573
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 6a631f664..f7f19cdad 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -209,6 +209,7 @@
209 <string name="value_with_units">%1$s%2$s</string> 209 <string name="value_with_units">%1$s%2$s</string>
210 210
211 <!-- System settings strings --> 211 <!-- System settings strings -->
212 <string name="device_name">Device name</string>
212 <string name="use_docked_mode">Docked Mode</string> 213 <string name="use_docked_mode">Docked Mode</string>
213 <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string> 214 <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string>
214 <string name="emulated_region">Emulated region</string> 215 <string name="emulated_region">Emulated region</string>
diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp
index d97ca2a40..49efae8e3 100644
--- a/src/audio_core/sink/cubeb_sink.cpp
+++ b/src/audio_core/sink/cubeb_sink.cpp
@@ -357,7 +357,9 @@ bool IsCubebSuitable() {
357 return false; 357 return false;
358 } 358 }
359 359
360 SCOPE_EXIT({ cubeb_destroy(ctx); }); 360 SCOPE_EXIT {
361 cubeb_destroy(ctx);
362 };
361 363
362#ifdef _WIN32 364#ifdef _WIN32
363 if (SUCCEEDED(com_init_result)) { 365 if (SUCCEEDED(com_init_result)) {
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp
index c047b0668..0a98eb31e 100644
--- a/src/audio_core/sink/sink_stream.cpp
+++ b/src/audio_core/sink/sink_stream.cpp
@@ -20,10 +20,10 @@
20namespace AudioCore::Sink { 20namespace AudioCore::Sink {
21 21
22void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { 22void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
23 SCOPE_EXIT({ 23 SCOPE_EXIT {
24 queue.enqueue(buffer); 24 queue.enqueue(buffer);
25 ++queued_buffers; 25 ++queued_buffers;
26 }); 26 };
27 27
28 if (type == StreamType::In) { 28 if (type == StreamType::In) {
29 return; 29 return;
diff --git a/src/common/demangle.cpp b/src/common/demangle.cpp
index 6e117cb41..b2c9d126a 100644
--- a/src/common/demangle.cpp
+++ b/src/common/demangle.cpp
@@ -20,7 +20,9 @@ std::string DemangleSymbol(const std::string& mangled) {
20 } 20 }
21 21
22 char* demangled = nullptr; 22 char* demangled = nullptr;
23 SCOPE_EXIT({ std::free(demangled); }); 23 SCOPE_EXIT {
24 std::free(demangled);
25 };
24 26
25 if (is_itanium(mangled)) { 27 if (is_itanium(mangled)) {
26 demangled = llvm::itaniumDemangle(mangled.c_str()); 28 demangled = llvm::itaniumDemangle(mangled.c_str());
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 860c39e6a..e0b5a6a67 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -430,11 +430,11 @@ public:
430 explicit Impl(size_t backing_size_, size_t virtual_size_) 430 explicit Impl(size_t backing_size_, size_t virtual_size_)
431 : backing_size{backing_size_}, virtual_size{virtual_size_} { 431 : backing_size{backing_size_}, virtual_size{virtual_size_} {
432 bool good = false; 432 bool good = false;
433 SCOPE_EXIT({ 433 SCOPE_EXIT {
434 if (!good) { 434 if (!good) {
435 Release(); 435 Release();
436 } 436 }
437 }); 437 };
438 438
439 long page_size = sysconf(_SC_PAGESIZE); 439 long page_size = sysconf(_SC_PAGESIZE);
440 if (page_size != 0x1000) { 440 if (page_size != 0x1000) {
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp
index 85dc18c11..3205eb7da 100644
--- a/src/common/page_table.cpp
+++ b/src/common/page_table.cpp
@@ -24,10 +24,10 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c
24 out_entry->block_size = page_size; 24 out_entry->block_size = page_size;
25 25
26 // Regardless of whether the page was mapped, advance on exit. 26 // Regardless of whether the page was mapped, advance on exit.
27 SCOPE_EXIT({ 27 SCOPE_EXIT {
28 context->next_page += 1; 28 context->next_page += 1;
29 context->next_offset += page_size; 29 context->next_offset += page_size;
30 }); 30 };
31 31
32 // Validate that we can read the actual entry. 32 // Validate that we can read the actual entry.
33 const auto page = context->next_page; 33 const auto page = context->next_page;
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h
index e9c789c88..f3e88cde9 100644
--- a/src/common/scope_exit.h
+++ b/src/common/scope_exit.h
@@ -7,29 +7,61 @@
7#include "common/common_funcs.h" 7#include "common/common_funcs.h"
8 8
9namespace detail { 9namespace detail {
10template <typename Func> 10template <class F>
11struct ScopeExitHelper { 11class ScopeGuard {
12 explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {} 12 YUZU_NON_COPYABLE(ScopeGuard);
13 ~ScopeExitHelper() { 13
14private:
15 F f;
16 bool active;
17
18public:
19 constexpr ScopeGuard(F f_) : f(std::move(f_)), active(true) {}
20 constexpr ~ScopeGuard() {
14 if (active) { 21 if (active) {
15 func(); 22 f();
16 } 23 }
17 } 24 }
18 25 constexpr void Cancel() {
19 void Cancel() {
20 active = false; 26 active = false;
21 } 27 }
22 28
23 Func func; 29 constexpr ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) {
24 bool active{true}; 30 rhs.Cancel();
31 }
32
33 ScopeGuard& operator=(ScopeGuard&& rhs) = delete;
25}; 34};
26 35
27template <typename Func> 36template <class F>
28ScopeExitHelper<Func> ScopeExit(Func&& func) { 37constexpr ScopeGuard<F> MakeScopeGuard(F f) {
29 return ScopeExitHelper<Func>(std::forward<Func>(func)); 38 return ScopeGuard<F>(std::move(f));
30} 39}
40
41enum class ScopeGuardOnExit {};
42
43template <typename F>
44constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
45 return ScopeGuard<F>(std::forward<F>(f));
46}
47
31} // namespace detail 48} // namespace detail
32 49
50#define CONCATENATE_IMPL(s1, s2) s1##s2
51#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
52
53#ifdef __COUNTER__
54#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__)
55#else
56#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__)
57#endif
58
59/**
60 * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
61 * used when the caller might want to cancel the ScopeExit.
62 */
63#define SCOPE_GUARD detail::ScopeGuardOnExit() + [&]()
64
33/** 65/**
34 * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy 66 * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
35 * for doing ad-hoc clean-up tasks in a function with multiple returns. 67 * for doing ad-hoc clean-up tasks in a function with multiple returns.
@@ -38,7 +70,7 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
38 * \code 70 * \code
39 * const int saved_val = g_foo; 71 * const int saved_val = g_foo;
40 * g_foo = 55; 72 * g_foo = 55;
41 * SCOPE_EXIT({ g_foo = saved_val; }); 73 * SCOPE_EXIT{ g_foo = saved_val; };
42 * 74 *
43 * if (Bar()) { 75 * if (Bar()) {
44 * return 0; 76 * return 0;
@@ -47,10 +79,4 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
47 * } 79 * }
48 * \endcode 80 * \endcode
49 */ 81 */
50#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) 82#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD
51
52/**
53 * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
54 * used when the caller might want to cancel the ScopeExit.
55 */
56#define SCOPE_GUARD(body) detail::ScopeExit([&]() body)
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7770dbeae..f67a12f8f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -2,8 +2,8 @@
2# SPDX-License-Identifier: GPL-2.0-or-later 2# SPDX-License-Identifier: GPL-2.0-or-later
3 3
4add_library(core STATIC 4add_library(core STATIC
5 arm/arm_interface.h
6 arm/arm_interface.cpp 5 arm/arm_interface.cpp
6 arm/arm_interface.h
7 arm/debug.cpp 7 arm/debug.cpp
8 arm/debug.h 8 arm/debug.h
9 arm/exclusive_monitor.cpp 9 arm/exclusive_monitor.cpp
@@ -37,10 +37,10 @@ add_library(core STATIC
37 debugger/gdbstub.h 37 debugger/gdbstub.h
38 debugger/gdbstub_arch.cpp 38 debugger/gdbstub_arch.cpp
39 debugger/gdbstub_arch.h 39 debugger/gdbstub_arch.h
40 device_memory_manager.h
41 device_memory_manager.inc
42 device_memory.cpp 40 device_memory.cpp
43 device_memory.h 41 device_memory.h
42 device_memory_manager.h
43 device_memory_manager.inc
44 file_sys/bis_factory.cpp 44 file_sys/bis_factory.cpp
45 file_sys/bis_factory.h 45 file_sys/bis_factory.h
46 file_sys/card_image.cpp 46 file_sys/card_image.cpp
@@ -390,6 +390,20 @@ add_library(core STATIC
390 hle/service/acc/errors.h 390 hle/service/acc/errors.h
391 hle/service/acc/profile_manager.cpp 391 hle/service/acc/profile_manager.cpp
392 hle/service/acc/profile_manager.h 392 hle/service/acc/profile_manager.h
393 hle/service/am/am.cpp
394 hle/service/am/am.h
395 hle/service/am/am_results.h
396 hle/service/am/am_types.h
397 hle/service/am/applet.cpp
398 hle/service/am/applet.h
399 hle/service/am/applet_data_broker.cpp
400 hle/service/am/applet_data_broker.h
401 hle/service/am/applet_manager.cpp
402 hle/service/am/applet_manager.h
403 hle/service/am/applet_message_queue.cpp
404 hle/service/am/applet_message_queue.h
405 hle/service/am/display_layer_manager.cpp
406 hle/service/am/display_layer_manager.h
393 hle/service/am/frontend/applet_cabinet.cpp 407 hle/service/am/frontend/applet_cabinet.cpp
394 hle/service/am/frontend/applet_cabinet.h 408 hle/service/am/frontend/applet_cabinet.h
395 hle/service/am/frontend/applet_controller.cpp 409 hle/service/am/frontend/applet_controller.cpp
@@ -411,24 +425,10 @@ add_library(core STATIC
411 hle/service/am/frontend/applet_web_browser_types.h 425 hle/service/am/frontend/applet_web_browser_types.h
412 hle/service/am/frontend/applets.cpp 426 hle/service/am/frontend/applets.cpp
413 hle/service/am/frontend/applets.h 427 hle/service/am/frontend/applets.h
414 hle/service/am/am.cpp
415 hle/service/am/am.h
416 hle/service/am/am_results.h
417 hle/service/am/am_types.h
418 hle/service/am/applet.cpp
419 hle/service/am/applet.h
420 hle/service/am/applet_manager.cpp
421 hle/service/am/applet_data_broker.cpp
422 hle/service/am/applet_data_broker.h
423 hle/service/am/applet_manager.h
424 hle/service/am/applet_message_queue.cpp
425 hle/service/am/applet_message_queue.h
426 hle/service/am/hid_registration.cpp 428 hle/service/am/hid_registration.cpp
427 hle/service/am/hid_registration.h 429 hle/service/am/hid_registration.h
428 hle/service/am/library_applet_storage.cpp 430 hle/service/am/library_applet_storage.cpp
429 hle/service/am/library_applet_storage.h 431 hle/service/am/library_applet_storage.h
430 hle/service/am/managed_layer_holder.cpp
431 hle/service/am/managed_layer_holder.h
432 hle/service/am/process.cpp 432 hle/service/am/process.cpp
433 hle/service/am/process.h 433 hle/service/am/process.h
434 hle/service/am/service/all_system_applet_proxies_service.cpp 434 hle/service/am/service/all_system_applet_proxies_service.cpp
@@ -441,10 +441,10 @@ add_library(core STATIC
441 hle/service/am/service/application_creator.h 441 hle/service/am/service/application_creator.h
442 hle/service/am/service/application_functions.cpp 442 hle/service/am/service/application_functions.cpp
443 hle/service/am/service/application_functions.h 443 hle/service/am/service/application_functions.h
444 hle/service/am/service/application_proxy_service.cpp
445 hle/service/am/service/application_proxy_service.h
446 hle/service/am/service/application_proxy.cpp 444 hle/service/am/service/application_proxy.cpp
447 hle/service/am/service/application_proxy.h 445 hle/service/am/service/application_proxy.h
446 hle/service/am/service/application_proxy_service.cpp
447 hle/service/am/service/application_proxy_service.h
448 hle/service/am/service/audio_controller.cpp 448 hle/service/am/service/audio_controller.cpp
449 hle/service/am/service/audio_controller.h 449 hle/service/am/service/audio_controller.h
450 hle/service/am/service/common_state_getter.cpp 450 hle/service/am/service/common_state_getter.cpp
@@ -473,16 +473,14 @@ add_library(core STATIC
473 hle/service/am/service/process_winding_controller.h 473 hle/service/am/service/process_winding_controller.h
474 hle/service/am/service/self_controller.cpp 474 hle/service/am/service/self_controller.cpp
475 hle/service/am/service/self_controller.h 475 hle/service/am/service/self_controller.h
476 hle/service/am/service/storage_accessor.cpp
477 hle/service/am/service/storage_accessor.h
478 hle/service/am/service/storage.cpp 476 hle/service/am/service/storage.cpp
479 hle/service/am/service/storage.h 477 hle/service/am/service/storage.h
478 hle/service/am/service/storage_accessor.cpp
479 hle/service/am/service/storage_accessor.h
480 hle/service/am/service/system_applet_proxy.cpp 480 hle/service/am/service/system_applet_proxy.cpp
481 hle/service/am/service/system_applet_proxy.h 481 hle/service/am/service/system_applet_proxy.h
482 hle/service/am/service/window_controller.cpp 482 hle/service/am/service/window_controller.cpp
483 hle/service/am/service/window_controller.h 483 hle/service/am/service/window_controller.h
484 hle/service/am/system_buffer_manager.cpp
485 hle/service/am/system_buffer_manager.h
486 hle/service/aoc/aoc_u.cpp 484 hle/service/aoc/aoc_u.cpp
487 hle/service/aoc/aoc_u.h 485 hle/service/aoc/aoc_u.h
488 hle/service/apm/apm.cpp 486 hle/service/apm/apm.cpp
@@ -491,12 +489,12 @@ add_library(core STATIC
491 hle/service/apm/apm_controller.h 489 hle/service/apm/apm_controller.h
492 hle/service/apm/apm_interface.cpp 490 hle/service/apm/apm_interface.cpp
493 hle/service/apm/apm_interface.h 491 hle/service/apm/apm_interface.h
494 hle/service/audio/audctl.cpp
495 hle/service/audio/audctl.h
496 hle/service/audio/audin_u.cpp 492 hle/service/audio/audin_u.cpp
497 hle/service/audio/audin_u.h 493 hle/service/audio/audin_u.h
498 hle/service/audio/audio.cpp 494 hle/service/audio/audio.cpp
499 hle/service/audio/audio.h 495 hle/service/audio/audio.h
496 hle/service/audio/audio_controller.cpp
497 hle/service/audio/audio_controller.h
500 hle/service/audio/audout_u.cpp 498 hle/service/audio/audout_u.cpp
501 hle/service/audio/audout_u.h 499 hle/service/audio/audout_u.h
502 hle/service/audio/audrec_a.cpp 500 hle/service/audio/audrec_a.cpp
@@ -510,18 +508,6 @@ add_library(core STATIC
510 hle/service/audio/hwopus.h 508 hle/service/audio/hwopus.h
511 hle/service/bcat/backend/backend.cpp 509 hle/service/bcat/backend/backend.cpp
512 hle/service/bcat/backend/backend.h 510 hle/service/bcat/backend/backend.h
513 hle/service/bcat/news/newly_arrived_event_holder.cpp
514 hle/service/bcat/news/newly_arrived_event_holder.h
515 hle/service/bcat/news/news_data_service.cpp
516 hle/service/bcat/news/news_data_service.h
517 hle/service/bcat/news/news_database_service.cpp
518 hle/service/bcat/news/news_database_service.h
519 hle/service/bcat/news/news_service.cpp
520 hle/service/bcat/news/news_service.h
521 hle/service/bcat/news/overwrite_event_holder.cpp
522 hle/service/bcat/news/overwrite_event_holder.h
523 hle/service/bcat/news/service_creator.cpp
524 hle/service/bcat/news/service_creator.h
525 hle/service/bcat/bcat.cpp 511 hle/service/bcat/bcat.cpp
526 hle/service/bcat/bcat.h 512 hle/service/bcat/bcat.h
527 hle/service/bcat/bcat_result.h 513 hle/service/bcat/bcat_result.h
@@ -537,6 +523,18 @@ add_library(core STATIC
537 hle/service/bcat/delivery_cache_progress_service.h 523 hle/service/bcat/delivery_cache_progress_service.h
538 hle/service/bcat/delivery_cache_storage_service.cpp 524 hle/service/bcat/delivery_cache_storage_service.cpp
539 hle/service/bcat/delivery_cache_storage_service.h 525 hle/service/bcat/delivery_cache_storage_service.h
526 hle/service/bcat/news/newly_arrived_event_holder.cpp
527 hle/service/bcat/news/newly_arrived_event_holder.h
528 hle/service/bcat/news/news_data_service.cpp
529 hle/service/bcat/news/news_data_service.h
530 hle/service/bcat/news/news_database_service.cpp
531 hle/service/bcat/news/news_database_service.h
532 hle/service/bcat/news/news_service.cpp
533 hle/service/bcat/news/news_service.h
534 hle/service/bcat/news/overwrite_event_holder.cpp
535 hle/service/bcat/news/overwrite_event_holder.h
536 hle/service/bcat/news/service_creator.cpp
537 hle/service/bcat/news/service_creator.h
540 hle/service/bcat/service_creator.cpp 538 hle/service/bcat/service_creator.cpp
541 hle/service/bcat/service_creator.h 539 hle/service/bcat/service_creator.h
542 hle/service/bpc/bpc.cpp 540 hle/service/bpc/bpc.cpp
@@ -545,6 +543,16 @@ add_library(core STATIC
545 hle/service/btdrv/btdrv.h 543 hle/service/btdrv/btdrv.h
546 hle/service/btm/btm.cpp 544 hle/service/btm/btm.cpp
547 hle/service/btm/btm.h 545 hle/service/btm/btm.h
546 hle/service/btm/btm_debug.cpp
547 hle/service/btm/btm_debug.h
548 hle/service/btm/btm_system.cpp
549 hle/service/btm/btm_system.h
550 hle/service/btm/btm_system_core.cpp
551 hle/service/btm/btm_system_core.h
552 hle/service/btm/btm_user.cpp
553 hle/service/btm/btm_user.h
554 hle/service/btm/btm_user_core.cpp
555 hle/service/btm/btm_user_core.h
548 hle/service/caps/caps.cpp 556 hle/service/caps/caps.cpp
549 hle/service/caps/caps.h 557 hle/service/caps/caps.h
550 hle/service/caps/caps_a.cpp 558 hle/service/caps/caps_a.cpp
@@ -600,8 +608,6 @@ add_library(core STATIC
600 hle/service/filesystem/romfs_controller.h 608 hle/service/filesystem/romfs_controller.h
601 hle/service/filesystem/save_data_controller.cpp 609 hle/service/filesystem/save_data_controller.cpp
602 hle/service/filesystem/save_data_controller.h 610 hle/service/filesystem/save_data_controller.h
603 hle/service/fgm/fgm.cpp
604 hle/service/fgm/fgm.h
605 hle/service/friend/friend.cpp 611 hle/service/friend/friend.cpp
606 hle/service/friend/friend.h 612 hle/service/friend/friend.h
607 hle/service/friend/friend_interface.cpp 613 hle/service/friend/friend_interface.cpp
@@ -739,15 +745,48 @@ add_library(core STATIC
739 hle/service/nim/nim.h 745 hle/service/nim/nim.h
740 hle/service/npns/npns.cpp 746 hle/service/npns/npns.cpp
741 hle/service/npns/npns.h 747 hle/service/npns/npns.h
742 hle/service/ns/errors.h 748 hle/service/ns/account_proxy_interface.cpp
743 hle/service/ns/iplatform_service_manager.cpp 749 hle/service/ns/account_proxy_interface.h
744 hle/service/ns/iplatform_service_manager.h 750 hle/service/ns/application_manager_interface.cpp
751 hle/service/ns/application_manager_interface.h
752 hle/service/ns/application_version_interface.cpp
753 hle/service/ns/application_version_interface.h
754 hle/service/ns/content_management_interface.cpp
755 hle/service/ns/content_management_interface.h
756 hle/service/ns/develop_interface.cpp
757 hle/service/ns/develop_interface.h
758 hle/service/ns/document_interface.cpp
759 hle/service/ns/document_interface.h
760 hle/service/ns/download_task_interface.cpp
761 hle/service/ns/download_task_interface.h
762 hle/service/ns/dynamic_rights_interface.cpp
763 hle/service/ns/dynamic_rights_interface.h
764 hle/service/ns/ecommerce_interface.cpp
765 hle/service/ns/ecommerce_interface.h
766 hle/service/ns/factory_reset_interface.cpp
767 hle/service/ns/factory_reset_interface.h
745 hle/service/ns/language.cpp 768 hle/service/ns/language.cpp
746 hle/service/ns/language.h 769 hle/service/ns/language.h
747 hle/service/ns/ns.cpp 770 hle/service/ns/ns.cpp
748 hle/service/ns/ns.h 771 hle/service/ns/ns.h
749 hle/service/ns/pdm_qry.cpp 772 hle/service/ns/ns_results.h
750 hle/service/ns/pdm_qry.h 773 hle/service/ns/ns_types.h
774 hle/service/ns/platform_service_manager.cpp
775 hle/service/ns/platform_service_manager.h
776 hle/service/ns/query_service.cpp
777 hle/service/ns/query_service.h
778 hle/service/ns/read_only_application_control_data_interface.cpp
779 hle/service/ns/read_only_application_control_data_interface.h
780 hle/service/ns/read_only_application_record_interface.cpp
781 hle/service/ns/read_only_application_record_interface.h
782 hle/service/ns/service_getter_interface.cpp
783 hle/service/ns/service_getter_interface.h
784 hle/service/ns/system_update_control.cpp
785 hle/service/ns/system_update_control.h
786 hle/service/ns/system_update_interface.cpp
787 hle/service/ns/system_update_interface.h
788 hle/service/ns/vulnerability_manager_interface.cpp
789 hle/service/ns/vulnerability_manager_interface.h
751 hle/service/nvdrv/core/container.cpp 790 hle/service/nvdrv/core/container.cpp
752 hle/service/nvdrv/core/container.h 791 hle/service/nvdrv/core/container.h
753 hle/service/nvdrv/core/heap_mapper.cpp 792 hle/service/nvdrv/core/heap_mapper.cpp
@@ -800,14 +839,14 @@ add_library(core STATIC
800 hle/service/nvnflinger/consumer_base.cpp 839 hle/service/nvnflinger/consumer_base.cpp
801 hle/service/nvnflinger/consumer_base.h 840 hle/service/nvnflinger/consumer_base.h
802 hle/service/nvnflinger/consumer_listener.h 841 hle/service/nvnflinger/consumer_listener.h
803 hle/service/nvnflinger/fb_share_buffer_manager.cpp
804 hle/service/nvnflinger/fb_share_buffer_manager.h
805 hle/service/nvnflinger/graphic_buffer_producer.cpp 842 hle/service/nvnflinger/graphic_buffer_producer.cpp
806 hle/service/nvnflinger/graphic_buffer_producer.h 843 hle/service/nvnflinger/graphic_buffer_producer.h
807 hle/service/nvnflinger/hos_binder_driver_server.cpp
808 hle/service/nvnflinger/hos_binder_driver_server.h
809 hle/service/nvnflinger/hardware_composer.cpp 844 hle/service/nvnflinger/hardware_composer.cpp
810 hle/service/nvnflinger/hardware_composer.h 845 hle/service/nvnflinger/hardware_composer.h
846 hle/service/nvnflinger/hos_binder_driver.cpp
847 hle/service/nvnflinger/hos_binder_driver.h
848 hle/service/nvnflinger/hos_binder_driver_server.cpp
849 hle/service/nvnflinger/hos_binder_driver_server.h
811 hle/service/nvnflinger/hwc_layer.h 850 hle/service/nvnflinger/hwc_layer.h
812 hle/service/nvnflinger/nvnflinger.cpp 851 hle/service/nvnflinger/nvnflinger.cpp
813 hle/service/nvnflinger/nvnflinger.h 852 hle/service/nvnflinger/nvnflinger.h
@@ -815,6 +854,8 @@ add_library(core STATIC
815 hle/service/nvnflinger/pixel_format.h 854 hle/service/nvnflinger/pixel_format.h
816 hle/service/nvnflinger/producer_listener.h 855 hle/service/nvnflinger/producer_listener.h
817 hle/service/nvnflinger/status.h 856 hle/service/nvnflinger/status.h
857 hle/service/nvnflinger/surface_flinger.cpp
858 hle/service/nvnflinger/surface_flinger.h
818 hle/service/nvnflinger/ui/fence.h 859 hle/service/nvnflinger/ui/fence.h
819 hle/service/nvnflinger/ui/graphic_buffer.cpp 860 hle/service/nvnflinger/ui/graphic_buffer.cpp
820 hle/service/nvnflinger/ui/graphic_buffer.h 861 hle/service/nvnflinger/ui/graphic_buffer.h
@@ -831,11 +872,11 @@ add_library(core STATIC
831 hle/service/omm/power_state_interface.h 872 hle/service/omm/power_state_interface.h
832 hle/service/os/event.cpp 873 hle/service/os/event.cpp
833 hle/service/os/event.h 874 hle/service/os/event.h
875 hle/service/os/multi_wait.cpp
876 hle/service/os/multi_wait.h
834 hle/service/os/multi_wait_holder.cpp 877 hle/service/os/multi_wait_holder.cpp
835 hle/service/os/multi_wait_holder.h 878 hle/service/os/multi_wait_holder.h
836 hle/service/os/multi_wait_utils.h 879 hle/service/os/multi_wait_utils.h
837 hle/service/os/multi_wait.cpp
838 hle/service/os/multi_wait.h
839 hle/service/os/mutex.cpp 880 hle/service/os/mutex.cpp
840 hle/service/os/mutex.h 881 hle/service/os/mutex.h
841 hle/service/pcie/pcie.cpp 882 hle/service/pcie/pcie.cpp
@@ -873,15 +914,17 @@ add_library(core STATIC
873 hle/service/psc/time/common.cpp 914 hle/service/psc/time/common.cpp
874 hle/service/psc/time/common.h 915 hle/service/psc/time/common.h
875 hle/service/psc/time/errors.h 916 hle/service/psc/time/errors.h
876 hle/service/psc/time/shared_memory.cpp
877 hle/service/psc/time/shared_memory.h
878 hle/service/psc/time/static.cpp
879 hle/service/psc/time/static.h
880 hle/service/psc/time/manager.h 917 hle/service/psc/time/manager.h
918 hle/service/psc/time/power_state_request_manager.cpp
919 hle/service/psc/time/power_state_request_manager.h
881 hle/service/psc/time/power_state_service.cpp 920 hle/service/psc/time/power_state_service.cpp
882 hle/service/psc/time/power_state_service.h 921 hle/service/psc/time/power_state_service.h
883 hle/service/psc/time/service_manager.cpp 922 hle/service/psc/time/service_manager.cpp
884 hle/service/psc/time/service_manager.h 923 hle/service/psc/time/service_manager.h
924 hle/service/psc/time/shared_memory.cpp
925 hle/service/psc/time/shared_memory.h
926 hle/service/psc/time/static.cpp
927 hle/service/psc/time/static.h
885 hle/service/psc/time/steady_clock.cpp 928 hle/service/psc/time/steady_clock.cpp
886 hle/service/psc/time/steady_clock.h 929 hle/service/psc/time/steady_clock.h
887 hle/service/psc/time/system_clock.cpp 930 hle/service/psc/time/system_clock.cpp
@@ -890,8 +933,6 @@ add_library(core STATIC
890 hle/service/psc/time/time_zone.h 933 hle/service/psc/time/time_zone.h
891 hle/service/psc/time/time_zone_service.cpp 934 hle/service/psc/time/time_zone_service.cpp
892 hle/service/psc/time/time_zone_service.h 935 hle/service/psc/time/time_zone_service.h
893 hle/service/psc/time/power_state_request_manager.cpp
894 hle/service/psc/time/power_state_request_manager.h
895 hle/service/ptm/psm.cpp 936 hle/service/ptm/psm.cpp
896 hle/service/ptm/psm.h 937 hle/service/ptm/psm.h
897 hle/service/ptm/ptm.cpp 938 hle/service/ptm/ptm.cpp
@@ -908,19 +949,21 @@ add_library(core STATIC
908 hle/service/server_manager.h 949 hle/service/server_manager.h
909 hle/service/service.cpp 950 hle/service/service.cpp
910 hle/service/service.h 951 hle/service/service.h
952 hle/service/services.cpp
953 hle/service/services.h
954 hle/service/set/factory_settings_server.cpp
955 hle/service/set/factory_settings_server.h
956 hle/service/set/firmware_debug_settings_server.cpp
957 hle/service/set/firmware_debug_settings_server.h
958 hle/service/set/key_code_map.h
911 hle/service/set/setting_formats/appln_settings.cpp 959 hle/service/set/setting_formats/appln_settings.cpp
912 hle/service/set/setting_formats/appln_settings.h 960 hle/service/set/setting_formats/appln_settings.h
913 hle/service/set/setting_formats/device_settings.cpp 961 hle/service/set/setting_formats/device_settings.cpp
914 hle/service/set/setting_formats/device_settings.h 962 hle/service/set/setting_formats/device_settings.h
915 hle/service/set/setting_formats/system_settings.cpp
916 hle/service/set/setting_formats/system_settings.h
917 hle/service/set/setting_formats/private_settings.cpp 963 hle/service/set/setting_formats/private_settings.cpp
918 hle/service/set/setting_formats/private_settings.h 964 hle/service/set/setting_formats/private_settings.h
919 hle/service/set/factory_settings_server.cpp 965 hle/service/set/setting_formats/system_settings.cpp
920 hle/service/set/factory_settings_server.h 966 hle/service/set/setting_formats/system_settings.h
921 hle/service/set/firmware_debug_settings_server.cpp
922 hle/service/set/firmware_debug_settings_server.h
923 hle/service/set/key_code_map.h
924 hle/service/set/settings.cpp 967 hle/service/set/settings.cpp
925 hle/service/set/settings.h 968 hle/service/set/settings.h
926 hle/service/set/settings_server.cpp 969 hle/service/set/settings_server.cpp
@@ -955,30 +998,36 @@ add_library(core STATIC
955 hle/service/ssl/ssl_backend.h 998 hle/service/ssl/ssl_backend.h
956 hle/service/usb/usb.cpp 999 hle/service/usb/usb.cpp
957 hle/service/usb/usb.h 1000 hle/service/usb/usb.h
958 hle/service/vi/display/vi_display.cpp
959 hle/service/vi/display/vi_display.h
960 hle/service/vi/layer/vi_layer.cpp
961 hle/service/vi/layer/vi_layer.h
962 hle/service/vi/application_display_service.cpp 1001 hle/service/vi/application_display_service.cpp
963 hle/service/vi/application_display_service.h 1002 hle/service/vi/application_display_service.h
964 hle/service/vi/application_root_service.cpp 1003 hle/service/vi/application_root_service.cpp
965 hle/service/vi/application_root_service.h 1004 hle/service/vi/application_root_service.h
966 hle/service/vi/hos_binder_driver.cpp 1005 hle/service/vi/conductor.cpp
967 hle/service/vi/hos_binder_driver.h 1006 hle/service/vi/conductor.h
1007 hle/service/vi/container.cpp
1008 hle/service/vi/container.h
1009 hle/service/vi/display.h
1010 hle/service/vi/display_list.h
1011 hle/service/vi/layer.h
1012 hle/service/vi/layer_list.h
968 hle/service/vi/manager_display_service.cpp 1013 hle/service/vi/manager_display_service.cpp
969 hle/service/vi/manager_display_service.h 1014 hle/service/vi/manager_display_service.h
970 hle/service/vi/manager_root_service.cpp 1015 hle/service/vi/manager_root_service.cpp
971 hle/service/vi/manager_root_service.h 1016 hle/service/vi/manager_root_service.h
972 hle/service/vi/service_creator.cpp 1017 hle/service/vi/service_creator.cpp
973 hle/service/vi/service_creator.h 1018 hle/service/vi/service_creator.h
1019 hle/service/vi/shared_buffer_manager.cpp
1020 hle/service/vi/shared_buffer_manager.h
974 hle/service/vi/system_display_service.cpp 1021 hle/service/vi/system_display_service.cpp
975 hle/service/vi/system_display_service.h 1022 hle/service/vi/system_display_service.h
976 hle/service/vi/system_root_service.cpp 1023 hle/service/vi/system_root_service.cpp
977 hle/service/vi/system_root_service.h 1024 hle/service/vi/system_root_service.h
978 hle/service/vi/vi_results.h
979 hle/service/vi/vi_types.h
980 hle/service/vi/vi.cpp 1025 hle/service/vi/vi.cpp
981 hle/service/vi/vi.h 1026 hle/service/vi/vi.h
1027 hle/service/vi/vi_results.h
1028 hle/service/vi/vi_types.h
1029 hle/service/vi/vsync_manager.cpp
1030 hle/service/vi/vsync_manager.h
982 internal_network/network.cpp 1031 internal_network/network.cpp
983 internal_network/network.h 1032 internal_network/network.h
984 internal_network/network_interface.cpp 1033 internal_network/network_interface.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index bd5f11d53..9e8936728 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -47,6 +47,7 @@
47#include "core/hle/service/psc/time/system_clock.h" 47#include "core/hle/service/psc/time/system_clock.h"
48#include "core/hle/service/psc/time/time_zone_service.h" 48#include "core/hle/service/psc/time/time_zone_service.h"
49#include "core/hle/service/service.h" 49#include "core/hle/service/service.h"
50#include "core/hle/service/services.h"
50#include "core/hle/service/set/system_settings_server.h" 51#include "core/hle/service/set/system_settings_server.h"
51#include "core/hle/service/sm/sm.h" 52#include "core/hle/service/sm/sm.h"
52#include "core/internal_network/network.h" 53#include "core/internal_network/network.h"
@@ -310,7 +311,8 @@ struct System::Impl {
310 audio_core = std::make_unique<AudioCore::AudioCore>(system); 311 audio_core = std::make_unique<AudioCore::AudioCore>(system);
311 312
312 service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); 313 service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
313 services = std::make_unique<Service::Services>(service_manager, system); 314 services =
315 std::make_unique<Service::Services>(service_manager, system, stop_event.get_token());
314 316
315 is_powered_on = true; 317 is_powered_on = true;
316 exit_locked = false; 318 exit_locked = false;
@@ -458,11 +460,10 @@ struct System::Impl {
458 gpu_core->NotifyShutdown(); 460 gpu_core->NotifyShutdown();
459 } 461 }
460 462
463 stop_event.request_stop();
464 core_timing.SyncPause(false);
461 Network::CancelPendingSocketOperations(); 465 Network::CancelPendingSocketOperations();
462 kernel.SuspendEmulation(true); 466 kernel.SuspendEmulation(true);
463 if (services) {
464 services->KillNVNFlinger();
465 }
466 kernel.CloseServices(); 467 kernel.CloseServices();
467 kernel.ShutdownCores(); 468 kernel.ShutdownCores();
468 applet_manager.Reset(); 469 applet_manager.Reset();
@@ -480,6 +481,7 @@ struct System::Impl {
480 cpu_manager.Shutdown(); 481 cpu_manager.Shutdown();
481 debugger.reset(); 482 debugger.reset();
482 kernel.Shutdown(); 483 kernel.Shutdown();
484 stop_event = {};
483 Network::RestartSocketOperations(); 485 Network::RestartSocketOperations();
484 486
485 if (auto room_member = room_network.GetRoomMember().lock()) { 487 if (auto room_member = room_network.GetRoomMember().lock()) {
@@ -615,6 +617,7 @@ struct System::Impl {
615 617
616 ExecuteProgramCallback execute_program_callback; 618 ExecuteProgramCallback execute_program_callback;
617 ExitCallback exit_callback; 619 ExitCallback exit_callback;
620 std::stop_source stop_event;
618 621
619 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; 622 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
620 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; 623 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 7a5c22f78..9b1c77387 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -199,10 +199,10 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
199 data.host_context = Common::Fiber::ThreadToFiber(); 199 data.host_context = Common::Fiber::ThreadToFiber();
200 200
201 // Cleanup 201 // Cleanup
202 SCOPE_EXIT({ 202 SCOPE_EXIT {
203 data.host_context->Exit(); 203 data.host_context->Exit();
204 MicroProfileOnThreadExit(); 204 MicroProfileOnThreadExit();
205 }); 205 };
206 206
207 // Running 207 // Running
208 if (!gpu_barrier->Sync(token)) { 208 if (!gpu_barrier->Sync(token)) {
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
index 6dfee806c..37c1e69c3 100644
--- a/src/core/device_memory_manager.inc
+++ b/src/core/device_memory_manager.inc
@@ -391,12 +391,12 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o
391 std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); 391 std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
392 const auto current_vaddr = 392 const auto current_vaddr =
393 static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset); 393 static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
394 SCOPE_EXIT({ 394 SCOPE_EXIT{
395 page_index += next_pages; 395 page_index += next_pages;
396 page_offset = 0; 396 page_offset = 0;
397 increment(copy_amount); 397 increment(copy_amount);
398 remaining_size -= copy_amount; 398 remaining_size -= copy_amount;
399 }); 399 };
400 400
401 auto phys_addr = compressed_physical_ptr[page_index]; 401 auto phys_addr = compressed_physical_ptr[page_index];
402 if (phys_addr == 0) { 402 if (phys_addr == 0) {
diff --git a/src/core/file_sys/fs_directory.h b/src/core/file_sys/fs_directory.h
index 25c9cb18a..3f90abb8f 100644
--- a/src/core/file_sys/fs_directory.h
+++ b/src/core/file_sys/fs_directory.h
@@ -3,6 +3,10 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <string_view>
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9
6namespace FileSys { 10namespace FileSys {
7 11
8constexpr inline size_t EntryNameLengthMax = 0x300; 12constexpr inline size_t EntryNameLengthMax = 0x300;
diff --git a/src/core/file_sys/fs_path_utility.h b/src/core/file_sys/fs_path_utility.h
index e9011d065..5643141f9 100644
--- a/src/core/file_sys/fs_path_utility.h
+++ b/src/core/file_sys/fs_path_utility.h
@@ -447,7 +447,7 @@ public:
447 char* replacement_path = nullptr; 447 char* replacement_path = nullptr;
448 size_t replacement_path_size = 0; 448 size_t replacement_path_size = 0;
449 449
450 SCOPE_EXIT({ 450 SCOPE_EXIT {
451 if (replacement_path != nullptr) { 451 if (replacement_path != nullptr) {
452 if (std::is_constant_evaluated()) { 452 if (std::is_constant_evaluated()) {
453 delete[] replacement_path; 453 delete[] replacement_path;
@@ -455,7 +455,7 @@ public:
455 Deallocate(replacement_path, replacement_path_size); 455 Deallocate(replacement_path, replacement_path_size);
456 } 456 }
457 } 457 }
458 }); 458 };
459 459
460 // Perform path replacement, if necessary 460 // Perform path replacement, if necessary
461 if (IsParentDirectoryPathReplacementNeeded(cur_path)) { 461 if (IsParentDirectoryPathReplacementNeeded(cur_path)) {
@@ -1102,8 +1102,8 @@ public:
1102 R_SUCCEED(); 1102 R_SUCCEED();
1103 } 1103 }
1104 1104
1105 static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len, 1105 static constexpr Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
1106 const PathFlags& flags) { 1106 const PathFlags& flags) {
1107 // Use StringTraits names for remainder of scope 1107 // Use StringTraits names for remainder of scope
1108 using namespace StringTraits; 1108 using namespace StringTraits;
1109 1109
@@ -1199,7 +1199,7 @@ public:
1199 const size_t replaced_src_len = path_len - (src - path); 1199 const size_t replaced_src_len = path_len - (src - path);
1200 1200
1201 char* replaced_src = nullptr; 1201 char* replaced_src = nullptr;
1202 SCOPE_EXIT({ 1202 SCOPE_EXIT {
1203 if (replaced_src != nullptr) { 1203 if (replaced_src != nullptr) {
1204 if (std::is_constant_evaluated()) { 1204 if (std::is_constant_evaluated()) {
1205 delete[] replaced_src; 1205 delete[] replaced_src;
@@ -1207,7 +1207,7 @@ public:
1207 Deallocate(replaced_src, replaced_src_len); 1207 Deallocate(replaced_src, replaced_src_len);
1208 } 1208 }
1209 } 1209 }
1210 }); 1210 };
1211 1211
1212 if (std::is_constant_evaluated()) { 1212 if (std::is_constant_evaluated()) {
1213 replaced_src = new char[replaced_src_len]; 1213 replaced_src = new char[replaced_src_len];
diff --git a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
index f342efb57..0e83ca1b9 100644
--- a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <mutex>
6#include <optional> 7#include <optional>
7 8
8#include "core/crypto/aes_util.h" 9#include "core/crypto/aes_util.h"
diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp
index caea0b8f8..a68fd973c 100644
--- a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp
+++ b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp
@@ -36,7 +36,9 @@ Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 lay
36 // Get the base storage size. 36 // Get the base storage size.
37 m_base_storage_size = base_storages[2]->GetSize(); 37 m_base_storage_size = base_storages[2]->GetSize();
38 { 38 {
39 auto size_guard = SCOPE_GUARD({ m_base_storage_size = 0; }); 39 auto size_guard = SCOPE_GUARD {
40 m_base_storage_size = 0;
41 };
40 R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize) 42 R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize)
41 << m_log_size_ratio << m_log_size_ratio, 43 << m_log_size_ratio << m_log_size_ratio,
42 ResultHierarchicalSha256BaseStorageTooLarge); 44 ResultHierarchicalSha256BaseStorageTooLarge);
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index ae4e441c9..289969cc4 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -98,7 +98,9 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
98 98
99Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) { 99Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
100 const u64 original_program_id = aci_header.title_id; 100 const u64 original_program_id = aci_header.title_id;
101 SCOPE_EXIT({ aci_header.title_id = original_program_id; }); 101 SCOPE_EXIT {
102 aci_header.title_id = original_program_id;
103 };
102 104
103 return this->Load(file); 105 return this->Load(file);
104} 106}
diff --git a/src/core/file_sys/system_archive/shared_font.cpp b/src/core/file_sys/system_archive/shared_font.cpp
index deb52069d..9ea16aa59 100644
--- a/src/core/file_sys/system_archive/shared_font.cpp
+++ b/src/core/file_sys/system_archive/shared_font.cpp
@@ -9,7 +9,7 @@
9#include "core/file_sys/system_archive/data/font_standard.h" 9#include "core/file_sys/system_archive/data/font_standard.h"
10#include "core/file_sys/system_archive/shared_font.h" 10#include "core/file_sys/system_archive/shared_font.h"
11#include "core/file_sys/vfs/vfs_vector.h" 11#include "core/file_sys/vfs/vfs_vector.h"
12#include "core/hle/service/ns/iplatform_service_manager.h" 12#include "core/hle/service/ns/platform_service_manager.h"
13 13
14namespace FileSys::SystemArchive { 14namespace FileSys::SystemArchive {
15 15
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp
index 472e8571c..3e01e3b67 100644
--- a/src/core/hle/kernel/k_client_session.cpp
+++ b/src/core/hle/kernel/k_client_session.cpp
@@ -24,7 +24,9 @@ Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) {
24 // Create a session request. 24 // Create a session request.
25 KSessionRequest* request = KSessionRequest::Create(m_kernel); 25 KSessionRequest* request = KSessionRequest::Create(m_kernel);
26 R_UNLESS(request != nullptr, ResultOutOfResource); 26 R_UNLESS(request != nullptr, ResultOutOfResource);
27 SCOPE_EXIT({ request->Close(); }); 27 SCOPE_EXIT {
28 request->Close();
29 };
28 30
29 // Initialize the request. 31 // Initialize the request.
30 request->Initialize(nullptr, address, size); 32 request->Initialize(nullptr, address, size);
@@ -37,7 +39,9 @@ Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t
37 // Create a session request. 39 // Create a session request.
38 KSessionRequest* request = KSessionRequest::Create(m_kernel); 40 KSessionRequest* request = KSessionRequest::Create(m_kernel);
39 R_UNLESS(request != nullptr, ResultOutOfResource); 41 R_UNLESS(request != nullptr, ResultOutOfResource);
40 SCOPE_EXIT({ request->Close(); }); 42 SCOPE_EXIT {
43 request->Close();
44 };
41 45
42 // Initialize the request. 46 // Initialize the request.
43 request->Initialize(event, address, size); 47 request->Initialize(event, address, size);
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp
index 1dd86fb3c..19cdf4f3a 100644
--- a/src/core/hle/kernel/k_page_table_base.cpp
+++ b/src/core/hle/kernel/k_page_table_base.cpp
@@ -1305,11 +1305,11 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr
1305 1305
1306 // Ensure that we maintain the instruction cache. 1306 // Ensure that we maintain the instruction cache.
1307 bool reprotected_pages = false; 1307 bool reprotected_pages = false;
1308 SCOPE_EXIT({ 1308 SCOPE_EXIT {
1309 if (reprotected_pages && any_code_pages) { 1309 if (reprotected_pages && any_code_pages) {
1310 InvalidateInstructionCache(m_kernel, this, dst_address, size); 1310 InvalidateInstructionCache(m_kernel, this, dst_address, size);
1311 } 1311 }
1312 }); 1312 };
1313 1313
1314 // Unmap. 1314 // Unmap.
1315 { 1315 {
@@ -1397,7 +1397,9 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
1397 // Close the opened pages when we're done with them. 1397 // Close the opened pages when we're done with them.
1398 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed 1398 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
1399 // automatically. 1399 // automatically.
1400 SCOPE_EXIT({ pg.Close(); }); 1400 SCOPE_EXIT {
1401 pg.Close();
1402 };
1401 1403
1402 // Clear all the newly allocated pages. 1404 // Clear all the newly allocated pages.
1403 for (const auto& it : pg) { 1405 for (const auto& it : pg) {
@@ -1603,7 +1605,9 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
1603 m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option)); 1605 m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
1604 1606
1605 // Ensure that the page group is closed when we're done working with it. 1607 // Ensure that the page group is closed when we're done working with it.
1606 SCOPE_EXIT({ pg.Close(); }); 1608 SCOPE_EXIT {
1609 pg.Close();
1610 };
1607 1611
1608 // Clear all pages. 1612 // Clear all pages.
1609 for (const auto& it : pg) { 1613 for (const auto& it : pg) {
@@ -2191,7 +2195,9 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
2191 // Close the opened pages when we're done with them. 2195 // Close the opened pages when we're done with them.
2192 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed 2196 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
2193 // automatically. 2197 // automatically.
2194 SCOPE_EXIT({ pg.Close(); }); 2198 SCOPE_EXIT {
2199 pg.Close();
2200 };
2195 2201
2196 // Clear all the newly allocated pages. 2202 // Clear all the newly allocated pages.
2197 for (const auto& it : pg) { 2203 for (const auto& it : pg) {
@@ -2592,7 +2598,9 @@ Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddre
2592 // Temporarily unlock ourselves, so that other operations can occur while we flush the 2598 // Temporarily unlock ourselves, so that other operations can occur while we flush the
2593 // region. 2599 // region.
2594 m_general_lock.Unlock(); 2600 m_general_lock.Unlock();
2595 SCOPE_EXIT({ m_general_lock.Lock(); }); 2601 SCOPE_EXIT {
2602 m_general_lock.Lock();
2603 };
2596 2604
2597 // Flush the region. 2605 // Flush the region.
2598 R_ASSERT(FlushDataCache(dst_address, size)); 2606 R_ASSERT(FlushDataCache(dst_address, size));
@@ -3311,10 +3319,10 @@ Result KPageTableBase::ReadIoMemoryImpl(KProcessAddress dst_addr, KPhysicalAddre
3311 // Ensure we unmap the io memory when we're done with it. 3319 // Ensure we unmap the io memory when we're done with it.
3312 const KPageProperties unmap_properties = 3320 const KPageProperties unmap_properties =
3313 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; 3321 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
3314 SCOPE_EXIT({ 3322 SCOPE_EXIT {
3315 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, 3323 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
3316 unmap_properties, OperationType::Unmap, true)); 3324 unmap_properties, OperationType::Unmap, true));
3317 }); 3325 };
3318 3326
3319 // Read the memory. 3327 // Read the memory.
3320 const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); 3328 const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
@@ -3347,10 +3355,10 @@ Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, KProcessAdd
3347 // Ensure we unmap the io memory when we're done with it. 3355 // Ensure we unmap the io memory when we're done with it.
3348 const KPageProperties unmap_properties = 3356 const KPageProperties unmap_properties =
3349 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; 3357 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
3350 SCOPE_EXIT({ 3358 SCOPE_EXIT {
3351 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, 3359 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
3352 unmap_properties, OperationType::Unmap, true)); 3360 unmap_properties, OperationType::Unmap, true));
3353 }); 3361 };
3354 3362
3355 // Write the memory. 3363 // Write the memory.
3356 const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); 3364 const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
@@ -4491,14 +4499,14 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size,
4491 4499
4492 // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll 4500 // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll
4493 // free on scope exit. 4501 // free on scope exit.
4494 SCOPE_EXIT({ 4502 SCOPE_EXIT {
4495 if (start_partial_page != 0) { 4503 if (start_partial_page != 0) {
4496 m_kernel.MemoryManager().Close(start_partial_page, 1); 4504 m_kernel.MemoryManager().Close(start_partial_page, 1);
4497 } 4505 }
4498 if (end_partial_page != 0) { 4506 if (end_partial_page != 0) {
4499 m_kernel.MemoryManager().Close(end_partial_page, 1); 4507 m_kernel.MemoryManager().Close(end_partial_page, 1);
4500 } 4508 }
4501 }); 4509 };
4502 4510
4503 ON_RESULT_FAILURE { 4511 ON_RESULT_FAILURE {
4504 if (cur_mapped_addr != dst_addr) { 4512 if (cur_mapped_addr != dst_addr) {
@@ -5166,10 +5174,10 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
5166 GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value)); 5174 GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value));
5167 5175
5168 // If we fail in the next bit (or retry), we need to cleanup the pages. 5176 // If we fail in the next bit (or retry), we need to cleanup the pages.
5169 auto pg_guard = SCOPE_GUARD({ 5177 auto pg_guard = SCOPE_GUARD {
5170 pg.OpenFirst(); 5178 pg.OpenFirst();
5171 pg.Close(); 5179 pg.Close();
5172 }); 5180 };
5173 5181
5174 // Map the memory. 5182 // Map the memory.
5175 { 5183 {
@@ -5694,7 +5702,9 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
5694 5702
5695 // Ensure that any pages we track are closed on exit. 5703 // Ensure that any pages we track are closed on exit.
5696 KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); 5704 KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
5697 SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); 5705 SCOPE_EXIT {
5706 pages_to_close.CloseAndReset();
5707 };
5698 5708
5699 // Make a page group representing the region to unmap. 5709 // Make a page group representing the region to unmap.
5700 this->MakePageGroup(pages_to_close, virt_addr, num_pages); 5710 this->MakePageGroup(pages_to_close, virt_addr, num_pages);
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 1bcc42890..cb9a11a63 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -77,7 +77,9 @@ Result TerminateChildren(KernelCore& kernel, KProcess* process,
77 } 77 }
78 78
79 // Terminate and close the thread. 79 // Terminate and close the thread.
80 SCOPE_EXIT({ cur_child->Close(); }); 80 SCOPE_EXIT {
81 cur_child->Close();
82 };
81 83
82 if (const Result terminate_result = cur_child->Terminate(); 84 if (const Result terminate_result = cur_child->Terminate();
83 ResultTerminationRequested == terminate_result) { 85 ResultTerminationRequested == terminate_result) {
@@ -466,11 +468,11 @@ void KProcess::DoWorkerTaskImpl() {
466 468
467Result KProcess::StartTermination() { 469Result KProcess::StartTermination() {
468 // Finalize the handle table when we're done, if the process isn't immortal. 470 // Finalize the handle table when we're done, if the process isn't immortal.
469 SCOPE_EXIT({ 471 SCOPE_EXIT {
470 if (!m_is_immortal) { 472 if (!m_is_immortal) {
471 this->FinalizeHandleTable(); 473 this->FinalizeHandleTable();
472 } 474 }
473 }); 475 };
474 476
475 // Terminate child threads other than the current one. 477 // Terminate child threads other than the current one.
476 R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel))); 478 R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel)));
@@ -964,7 +966,9 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
964 // Create a new thread for the process. 966 // Create a new thread for the process.
965 KThread* main_thread = KThread::Create(m_kernel); 967 KThread* main_thread = KThread::Create(m_kernel);
966 R_UNLESS(main_thread != nullptr, ResultOutOfResource); 968 R_UNLESS(main_thread != nullptr, ResultOutOfResource);
967 SCOPE_EXIT({ main_thread->Close(); }); 969 SCOPE_EXIT {
970 main_thread->Close();
971 };
968 972
969 // Initialize the thread. 973 // Initialize the thread.
970 R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0, 974 R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0,
@@ -1155,7 +1159,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
1155 Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); 1159 Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
1156 1160
1157 // Ensure we maintain a clean state on exit. 1161 // Ensure we maintain a clean state on exit.
1158 SCOPE_EXIT({ res_limit->Close(); }); 1162 SCOPE_EXIT {
1163 res_limit->Close();
1164 };
1159 1165
1160 // Declare flags and code address. 1166 // Declare flags and code address.
1161 Svc::CreateProcessFlag flag{}; 1167 Svc::CreateProcessFlag flag{};
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index adaabdd6d..40c3323ef 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -651,11 +651,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
651 // Process any special data. 651 // Process any special data.
652 if (src_header.GetHasSpecialHeader()) { 652 if (src_header.GetHasSpecialHeader()) {
653 // After we process, make sure we track whether the receive list is broken. 653 // After we process, make sure we track whether the receive list is broken.
654 SCOPE_EXIT({ 654 SCOPE_EXIT {
655 if (offset > dst_recv_list_idx) { 655 if (offset > dst_recv_list_idx) {
656 recv_list_broken = true; 656 recv_list_broken = true;
657 } 657 }
658 }); 658 };
659 659
660 // Process special data. 660 // Process special data.
661 R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread, 661 R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread,
@@ -665,11 +665,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
665 // Process any pointer buffers. 665 // Process any pointer buffers.
666 for (auto i = 0; i < src_header.GetPointerCount(); ++i) { 666 for (auto i = 0; i < src_header.GetPointerCount(); ++i) {
667 // After we process, make sure we track whether the receive list is broken. 667 // After we process, make sure we track whether the receive list is broken.
668 SCOPE_EXIT({ 668 SCOPE_EXIT {
669 if (offset > dst_recv_list_idx) { 669 if (offset > dst_recv_list_idx) {
670 recv_list_broken = true; 670 recv_list_broken = true;
671 } 671 }
672 }); 672 };
673 673
674 R_TRY(ProcessReceiveMessagePointerDescriptors( 674 R_TRY(ProcessReceiveMessagePointerDescriptors(
675 offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list, 675 offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list,
@@ -680,11 +680,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
680 // Process any map alias buffers. 680 // Process any map alias buffers.
681 for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { 681 for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
682 // After we process, make sure we track whether the receive list is broken. 682 // After we process, make sure we track whether the receive list is broken.
683 SCOPE_EXIT({ 683 SCOPE_EXIT {
684 if (offset > dst_recv_list_idx) { 684 if (offset > dst_recv_list_idx) {
685 recv_list_broken = true; 685 recv_list_broken = true;
686 } 686 }
687 }); 687 };
688 688
689 // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite. 689 // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite.
690 const KMemoryPermission perm = (i >= src_header.GetSendCount()) 690 const KMemoryPermission perm = (i >= src_header.GetSendCount())
@@ -702,11 +702,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
702 // Process any raw data. 702 // Process any raw data.
703 if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) { 703 if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) {
704 // After we process, make sure we track whether the receive list is broken. 704 // After we process, make sure we track whether the receive list is broken.
705 SCOPE_EXIT({ 705 SCOPE_EXIT {
706 if (offset + raw_count > dst_recv_list_idx) { 706 if (offset + raw_count > dst_recv_list_idx) {
707 recv_list_broken = true; 707 recv_list_broken = true;
708 } 708 }
709 }); 709 };
710 710
711 // Get the offset and size. 711 // Get the offset and size.
712 const size_t offset_words = offset * sizeof(u32); 712 const size_t offset_words = offset * sizeof(u32);
@@ -1124,7 +1124,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
1124 client_thread->Open(); 1124 client_thread->Open();
1125 } 1125 }
1126 1126
1127 SCOPE_EXIT({ client_thread->Close(); }); 1127 SCOPE_EXIT {
1128 client_thread->Close();
1129 };
1128 1130
1129 // Set the request as our current. 1131 // Set the request as our current.
1130 m_current_request = request; 1132 m_current_request = request;
@@ -1174,7 +1176,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
1174 // Reply to the client. 1176 // Reply to the client.
1175 { 1177 {
1176 // After we reply, close our reference to the request. 1178 // After we reply, close our reference to the request.
1177 SCOPE_EXIT({ request->Close(); }); 1179 SCOPE_EXIT {
1180 request->Close();
1181 };
1178 1182
1179 // Get the event to check whether the request is async. 1183 // Get the event to check whether the request is async.
1180 if (KEvent* event = request->GetEvent(); event != nullptr) { 1184 if (KEvent* event = request->GetEvent(); event != nullptr) {
@@ -1236,7 +1240,9 @@ Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buff
1236 } 1240 }
1237 1241
1238 // Close reference to the request once we're done processing it. 1242 // Close reference to the request once we're done processing it.
1239 SCOPE_EXIT({ request->Close(); }); 1243 SCOPE_EXIT {
1244 request->Close();
1245 };
1240 1246
1241 // Extract relevant information from the request. 1247 // Extract relevant information from the request.
1242 const uint64_t client_message = request->GetAddress(); 1248 const uint64_t client_message = request->GetAddress();
@@ -1394,7 +1400,9 @@ void KServerSession::CleanupRequests() {
1394 } 1400 }
1395 1401
1396 // Close a reference to the request once it's cleaned up. 1402 // Close a reference to the request once it's cleaned up.
1397 SCOPE_EXIT({ request->Close(); }); 1403 SCOPE_EXIT {
1404 request->Close();
1405 };
1398 1406
1399 // Extract relevant information from the request. 1407 // Extract relevant information from the request.
1400 const uint64_t client_message = request->GetAddress(); 1408 const uint64_t client_message = request->GetAddress();
@@ -1491,7 +1499,9 @@ void KServerSession::OnClientClosed() {
1491 ASSERT(thread != nullptr); 1499 ASSERT(thread != nullptr);
1492 1500
1493 // Ensure that we close the request when done. 1501 // Ensure that we close the request when done.
1494 SCOPE_EXIT({ request->Close(); }); 1502 SCOPE_EXIT {
1503 request->Close();
1504 };
1495 1505
1496 // If we're terminating, close a reference to the thread and event. 1506 // If we're terminating, close a reference to the thread and event.
1497 if (terminate) { 1507 if (terminate) {
diff --git a/src/core/hle/kernel/k_thread_local_page.cpp b/src/core/hle/kernel/k_thread_local_page.cpp
index a632d1634..1952c0083 100644
--- a/src/core/hle/kernel/k_thread_local_page.cpp
+++ b/src/core/hle/kernel/k_thread_local_page.cpp
@@ -21,7 +21,9 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
21 // Allocate a new page. 21 // Allocate a new page.
22 KPageBuffer* page_buf = KPageBuffer::Allocate(kernel); 22 KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
23 R_UNLESS(page_buf != nullptr, ResultOutOfMemory); 23 R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
24 auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); }); 24 auto page_buf_guard = SCOPE_GUARD {
25 KPageBuffer::Free(kernel, page_buf);
26 };
25 27
26 // Map the address in. 28 // Map the address in.
27 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf); 29 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp
index cbb1b02bb..09295e8ad 100644
--- a/src/core/hle/kernel/k_transfer_memory.cpp
+++ b/src/core/hle/kernel/k_transfer_memory.cpp
@@ -24,7 +24,9 @@ Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
24 24
25 // Construct the page group, guarding to make sure our state is valid on exit. 25 // Construct the page group, guarding to make sure our state is valid on exit.
26 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager()); 26 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
27 auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); }); 27 auto pg_guard = SCOPE_GUARD {
28 m_page_group.reset();
29 };
28 30
29 // Lock the memory. 31 // Lock the memory.
30 R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size, 32 R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4f4b02fac..9e5eaeec4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -109,7 +109,9 @@ struct KernelCore::Impl {
109 109
110 void Shutdown() { 110 void Shutdown() {
111 is_shutting_down.store(true, std::memory_order_relaxed); 111 is_shutting_down.store(true, std::memory_order_relaxed);
112 SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); }); 112 SCOPE_EXIT {
113 is_shutting_down.store(false, std::memory_order_relaxed);
114 };
113 115
114 CloseServices(); 116 CloseServices();
115 117
@@ -1080,7 +1082,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
1080 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); 1082 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
1081 1083
1082 // Ensure that we don't hold onto any extra references. 1084 // Ensure that we don't hold onto any extra references.
1083 SCOPE_EXIT({ process->Close(); }); 1085 SCOPE_EXIT {
1086 process->Close();
1087 };
1084 1088
1085 // Register the new process. 1089 // Register the new process.
1086 KProcess::Register(*this, process); 1090 KProcess::Register(*this, process);
@@ -1108,7 +1112,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
1108 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); 1112 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
1109 1113
1110 // Ensure that we don't hold onto any extra references. 1114 // Ensure that we don't hold onto any extra references.
1111 SCOPE_EXIT({ process->Close(); }); 1115 SCOPE_EXIT {
1116 process->Close();
1117 };
1112 1118
1113 // Register the new process. 1119 // Register the new process.
1114 KProcess::Register(*this, process); 1120 KProcess::Register(*this, process);
diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp
index bae4cb0cd..7be2802f0 100644
--- a/src/core/hle/kernel/svc/svc_code_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_code_memory.cpp
@@ -45,7 +45,9 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t
45 45
46 KCodeMemory* code_mem = KCodeMemory::Create(kernel); 46 KCodeMemory* code_mem = KCodeMemory::Create(kernel);
47 R_UNLESS(code_mem != nullptr, ResultOutOfResource); 47 R_UNLESS(code_mem != nullptr, ResultOutOfResource);
48 SCOPE_EXIT({ code_mem->Close(); }); 48 SCOPE_EXIT {
49 code_mem->Close();
50 };
49 51
50 // Verify that the region is in range. 52 // Verify that the region is in range.
51 R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size), 53 R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size),
diff --git a/src/core/hle/kernel/svc/svc_device_address_space.cpp b/src/core/hle/kernel/svc/svc_device_address_space.cpp
index 42add9473..ac828320f 100644
--- a/src/core/hle/kernel/svc/svc_device_address_space.cpp
+++ b/src/core/hle/kernel/svc/svc_device_address_space.cpp
@@ -28,7 +28,9 @@ Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_
28 // Create the device address space. 28 // Create the device address space.
29 KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel()); 29 KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
30 R_UNLESS(das != nullptr, ResultOutOfResource); 30 R_UNLESS(das != nullptr, ResultOutOfResource);
31 SCOPE_EXIT({ das->Close(); }); 31 SCOPE_EXIT {
32 das->Close();
33 };
32 34
33 // Initialize the device address space. 35 // Initialize the device address space.
34 R_TRY(das->Initialize(das_address, das_size)); 36 R_TRY(das->Initialize(das_address, das_size));
diff --git a/src/core/hle/kernel/svc/svc_event.cpp b/src/core/hle/kernel/svc/svc_event.cpp
index 901202e6a..8e4beb396 100644
--- a/src/core/hle/kernel/svc/svc_event.cpp
+++ b/src/core/hle/kernel/svc/svc_event.cpp
@@ -72,10 +72,10 @@ Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
72 event_reservation.Commit(); 72 event_reservation.Commit();
73 73
74 // Ensure that we clean up the event (and its only references are handle table) on function end. 74 // Ensure that we clean up the event (and its only references are handle table) on function end.
75 SCOPE_EXIT({ 75 SCOPE_EXIT {
76 event->GetReadableEvent().Close(); 76 event->GetReadableEvent().Close();
77 event->Close(); 77 event->Close();
78 }); 78 };
79 79
80 // Register the event. 80 // Register the event.
81 KEvent::Register(kernel, event); 81 KEvent::Register(kernel, event);
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp
index 85cc4f561..b619bd70a 100644
--- a/src/core/hle/kernel/svc/svc_ipc.cpp
+++ b/src/core/hle/kernel/svc/svc_ipc.cpp
@@ -129,11 +129,11 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
129 } 129 }
130 130
131 // Ensure handles are closed when we're done. 131 // Ensure handles are closed when we're done.
132 SCOPE_EXIT({ 132 SCOPE_EXIT {
133 for (auto i = 0; i < num_handles; ++i) { 133 for (auto i = 0; i < num_handles; ++i) {
134 objs[i]->Close(); 134 objs[i]->Close();
135 } 135 }
136 }); 136 };
137 137
138 R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs, 138 R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs,
139 num_handles, reply_target, timeout_ns)); 139 num_handles, reply_target, timeout_ns));
@@ -208,10 +208,10 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha
208 event_reservation.Commit(); 208 event_reservation.Commit();
209 209
210 // At end of scope, kill the standing references to the sub events. 210 // At end of scope, kill the standing references to the sub events.
211 SCOPE_EXIT({ 211 SCOPE_EXIT {
212 event->GetReadableEvent().Close(); 212 event->GetReadableEvent().Close();
213 event->Close(); 213 event->Close();
214 }); 214 };
215 215
216 // Register the event. 216 // Register the event.
217 KEvent::Register(system.Kernel(), event); 217 KEvent::Register(system.Kernel(), event);
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp
index 737749f7d..9a22dadaf 100644
--- a/src/core/hle/kernel/svc/svc_port.cpp
+++ b/src/core/hle/kernel/svc/svc_port.cpp
@@ -68,10 +68,10 @@ Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
68 port->Initialize(max_sessions, is_light, name); 68 port->Initialize(max_sessions, is_light, name);
69 69
70 // Ensure that we clean up the port (and its only references are handle table) on function end. 70 // Ensure that we clean up the port (and its only references are handle table) on function end.
71 SCOPE_EXIT({ 71 SCOPE_EXIT {
72 port->GetServerPort().Close(); 72 port->GetServerPort().Close();
73 port->GetClientPort().Close(); 73 port->GetClientPort().Close();
74 }); 74 };
75 75
76 // Register the port. 76 // Register the port.
77 KPort::Register(kernel, port); 77 KPort::Register(kernel, port);
@@ -150,10 +150,10 @@ Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t
150 KPort::Register(system.Kernel(), port); 150 KPort::Register(system.Kernel(), port);
151 151
152 // Ensure that our only reference to the port is in the handle table when we're done. 152 // Ensure that our only reference to the port is in the handle table when we're done.
153 SCOPE_EXIT({ 153 SCOPE_EXIT {
154 port->GetClientPort().Close(); 154 port->GetClientPort().Close();
155 port->GetServerPort().Close(); 155 port->GetServerPort().Close();
156 }); 156 };
157 157
158 // Register the handle in the table. 158 // Register the handle in the table.
159 R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort()))); 159 R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
diff --git a/src/core/hle/kernel/svc/svc_resource_limit.cpp b/src/core/hle/kernel/svc/svc_resource_limit.cpp
index c8e820b6a..6f3972482 100644
--- a/src/core/hle/kernel/svc/svc_resource_limit.cpp
+++ b/src/core/hle/kernel/svc/svc_resource_limit.cpp
@@ -18,7 +18,9 @@ Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
18 R_UNLESS(resource_limit != nullptr, ResultOutOfResource); 18 R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
19 19
20 // Ensure we don't leak a reference to the limit. 20 // Ensure we don't leak a reference to the limit.
21 SCOPE_EXIT({ resource_limit->Close(); }); 21 SCOPE_EXIT {
22 resource_limit->Close();
23 };
22 24
23 // Initialize the resource limit. 25 // Initialize the resource limit.
24 resource_limit->Initialize(); 26 resource_limit->Initialize();
diff --git a/src/core/hle/kernel/svc/svc_session.cpp b/src/core/hle/kernel/svc/svc_session.cpp
index 2f5905f32..b034d21d1 100644
--- a/src/core/hle/kernel/svc/svc_session.cpp
+++ b/src/core/hle/kernel/svc/svc_session.cpp
@@ -69,10 +69,10 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
69 69
70 // Ensure that we clean up the session (and its only references are handle table) on function 70 // Ensure that we clean up the session (and its only references are handle table) on function
71 // end. 71 // end.
72 SCOPE_EXIT({ 72 SCOPE_EXIT {
73 session->GetClientSession().Close(); 73 session->GetClientSession().Close();
74 session->GetServerSession().Close(); 74 session->GetServerSession().Close();
75 }); 75 };
76 76
77 // Register the session. 77 // Register the session.
78 T::Register(system.Kernel(), session); 78 T::Register(system.Kernel(), session);
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp
index 6c79cfd8d..fb03908d7 100644
--- a/src/core/hle/kernel/svc/svc_synchronization.cpp
+++ b/src/core/hle/kernel/svc/svc_synchronization.cpp
@@ -78,11 +78,11 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha
78 } 78 }
79 79
80 // Ensure handles are closed when we're done. 80 // Ensure handles are closed when we're done.
81 SCOPE_EXIT({ 81 SCOPE_EXIT {
82 for (auto i = 0; i < num_handles; ++i) { 82 for (auto i = 0; i < num_handles; ++i) {
83 objs[i]->Close(); 83 objs[i]->Close();
84 } 84 }
85 }); 85 };
86 86
87 // Convert the timeout from nanoseconds to ticks. 87 // Convert the timeout from nanoseconds to ticks.
88 s64 timeout; 88 s64 timeout;
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp
index 7681afa33..7517bb9d3 100644
--- a/src/core/hle/kernel/svc/svc_thread.cpp
+++ b/src/core/hle/kernel/svc/svc_thread.cpp
@@ -51,7 +51,9 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u
51 // Create the thread. 51 // Create the thread.
52 KThread* thread = KThread::Create(kernel); 52 KThread* thread = KThread::Create(kernel);
53 R_UNLESS(thread != nullptr, ResultOutOfResource) 53 R_UNLESS(thread != nullptr, ResultOutOfResource)
54 SCOPE_EXIT({ thread->Close(); }); 54 SCOPE_EXIT {
55 thread->Close();
56 };
55 57
56 // Initialize the thread. 58 // Initialize the thread.
57 { 59 {
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
index 671bca23f..2ea0d4421 100644
--- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
@@ -52,7 +52,9 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
52 R_UNLESS(trmem != nullptr, ResultOutOfResource); 52 R_UNLESS(trmem != nullptr, ResultOutOfResource);
53 53
54 // Ensure the only reference is in the handle table when we're done. 54 // Ensure the only reference is in the handle table when we're done.
55 SCOPE_EXIT({ trmem->Close(); }); 55 SCOPE_EXIT {
56 trmem->Close();
57 };
56 58
57 // Ensure that the region is in range. 59 // Ensure that the region is in range.
58 R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory); 60 R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory);
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 9dc710ba9..8c4e14f08 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -8,13 +8,13 @@
8 8
9namespace Service::AM { 9namespace Service::AM {
10 10
11void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { 11void LoopProcess(Core::System& system) {
12 auto server_manager = std::make_unique<ServerManager>(system); 12 auto server_manager = std::make_unique<ServerManager>(system);
13 13
14 server_manager->RegisterNamedService( 14 server_manager->RegisterNamedService("appletAE",
15 "appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, nvnflinger)); 15 std::make_shared<IAllSystemAppletProxiesService>(system));
16 server_manager->RegisterNamedService( 16 server_manager->RegisterNamedService("appletOE",
17 "appletOE", std::make_shared<IApplicationProxyService>(system, nvnflinger)); 17 std::make_shared<IApplicationProxyService>(system));
18 ServerManager::RunServer(std::move(server_manager)); 18 ServerManager::RunServer(std::move(server_manager));
19} 19}
20 20
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 4a2d797bd..1afe253ae 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -7,12 +7,8 @@ namespace Core {
7class System; 7class System;
8} 8}
9 9
10namespace Service::Nvnflinger {
11class Nvnflinger;
12}
13
14namespace Service::AM { 10namespace Service::AM {
15 11
16void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system); 12void LoopProcess(Core::System& system);
17 13
18} // namespace Service::AM 14} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h
index 4f34d4811..ad602153e 100644
--- a/src/core/hle/service/am/applet.h
+++ b/src/core/hle/service/am/applet.h
@@ -14,10 +14,9 @@
14 14
15#include "core/hle/service/am/am_types.h" 15#include "core/hle/service/am/am_types.h"
16#include "core/hle/service/am/applet_message_queue.h" 16#include "core/hle/service/am/applet_message_queue.h"
17#include "core/hle/service/am/display_layer_manager.h"
17#include "core/hle/service/am/hid_registration.h" 18#include "core/hle/service/am/hid_registration.h"
18#include "core/hle/service/am/managed_layer_holder.h"
19#include "core/hle/service/am/process.h" 19#include "core/hle/service/am/process.h"
20#include "core/hle/service/am/system_buffer_manager.h"
21 20
22namespace Service::AM { 21namespace Service::AM {
23 22
@@ -54,8 +53,7 @@ struct Applet {
54 HidRegistration hid_registration; 53 HidRegistration hid_registration;
55 54
56 // vi state 55 // vi state
57 SystemBufferManager system_buffer_manager{}; 56 DisplayLayerManager display_layer_manager{};
58 ManagedLayerHolder managed_layer_holder{};
59 57
60 // Applet common functions 58 // Applet common functions
61 Result terminate_result{}; 59 Result terminate_result{};
diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp
index 4d58c4db5..9057244a9 100644
--- a/src/core/hle/service/am/applet_data_broker.cpp
+++ b/src/core/hle/service/am/applet_data_broker.cpp
@@ -24,11 +24,11 @@ void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
24Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) { 24Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
25 std::scoped_lock lk{m_lock}; 25 std::scoped_lock lk{m_lock};
26 26
27 SCOPE_EXIT({ 27 SCOPE_EXIT {
28 if (m_data.empty()) { 28 if (m_data.empty()) {
29 m_event.Clear(); 29 m_event.Clear();
30 } 30 }
31 }); 31 };
32 32
33 R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); 33 R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
34 34
diff --git a/src/core/hle/service/am/display_layer_manager.cpp b/src/core/hle/service/am/display_layer_manager.cpp
new file mode 100644
index 000000000..85ff6fb88
--- /dev/null
+++ b/src/core/hle/service/am/display_layer_manager.cpp
@@ -0,0 +1,151 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/am/display_layer_manager.h"
6#include "core/hle/service/sm/sm.h"
7#include "core/hle/service/vi/application_display_service.h"
8#include "core/hle/service/vi/container.h"
9#include "core/hle/service/vi/manager_display_service.h"
10#include "core/hle/service/vi/manager_root_service.h"
11#include "core/hle/service/vi/shared_buffer_manager.h"
12#include "core/hle/service/vi/vi_results.h"
13#include "core/hle/service/vi/vi_types.h"
14
15namespace Service::AM {
16
17DisplayLayerManager::DisplayLayerManager() = default;
18DisplayLayerManager::~DisplayLayerManager() {
19 this->Finalize();
20}
21
22void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* process,
23 AppletId applet_id, LibraryAppletMode mode) {
24 R_ASSERT(system.ServiceManager()
25 .GetService<VI::IManagerRootService>("vi:m", true)
26 ->GetDisplayService(&m_display_service, VI::Policy::Compositor));
27 R_ASSERT(m_display_service->GetManagerDisplayService(&m_manager_display_service));
28
29 m_process = process;
30 m_system_shared_buffer_id = 0;
31 m_system_shared_layer_id = 0;
32 m_applet_id = applet_id;
33 m_buffer_sharing_enabled = false;
34 m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
35 mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
36}
37
38void DisplayLayerManager::Finalize() {
39 if (!m_manager_display_service) {
40 return;
41 }
42
43 // Clean up managed layers.
44 for (const auto& layer : m_managed_display_layers) {
45 m_manager_display_service->DestroyManagedLayer(layer);
46 }
47
48 for (const auto& layer : m_managed_display_recording_layers) {
49 m_manager_display_service->DestroyManagedLayer(layer);
50 }
51
52 // Clean up shared layers.
53 if (m_buffer_sharing_enabled) {
54 m_manager_display_service->DestroySharedLayerSession(m_process);
55 }
56
57 m_manager_display_service = nullptr;
58 m_display_service = nullptr;
59}
60
61Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
62 R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
63
64 // TODO(Subv): Find out how AM determines the display to use, for now just
65 // create the layer in the Default display.
66 u64 display_id;
67 R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
68 R_TRY(m_manager_display_service->CreateManagedLayer(
69 out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
70
71 m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
72 m_managed_display_layers.emplace(*out_layer_id);
73
74 R_SUCCEED();
75}
76
77Result DisplayLayerManager::CreateManagedDisplaySeparableLayer(u64* out_layer_id,
78 u64* out_recording_layer_id) {
79 R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
80
81 // TODO(Subv): Find out how AM determines the display to use, for now just
82 // create the layer in the Default display.
83 // This calls nn::vi::CreateRecordingLayer() which creates another layer.
84 // Currently we do not support more than 1 layer per display, output 1 layer id for now.
85 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
86 // side effects.
87 *out_recording_layer_id = 0;
88 R_RETURN(this->CreateManagedDisplayLayer(out_layer_id));
89}
90
91Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
92 // Succeed if already enabled.
93 R_SUCCEED_IF(m_buffer_sharing_enabled);
94
95 // Ensure we can access shared layers.
96 R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed);
97 R_UNLESS(m_applet_id != AppletId::Application, VI::ResultPermissionDenied);
98
99 // Create the shared layer.
100 u64 display_id;
101 R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
102 R_TRY(m_manager_display_service->CreateSharedLayerSession(m_process, &m_system_shared_buffer_id,
103 &m_system_shared_layer_id, display_id,
104 m_blending_enabled));
105
106 // We succeeded, so set up remaining state.
107 m_buffer_sharing_enabled = true;
108 m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
109 R_SUCCEED();
110}
111
112Result DisplayLayerManager::GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
113 u64* out_system_shared_layer_id) {
114 R_TRY(this->IsSystemBufferSharingEnabled());
115
116 *out_system_shared_buffer_id = m_system_shared_buffer_id;
117 *out_system_shared_layer_id = m_system_shared_layer_id;
118
119 R_SUCCEED();
120}
121
122void DisplayLayerManager::SetWindowVisibility(bool visible) {
123 if (m_visible == visible) {
124 return;
125 }
126
127 m_visible = visible;
128
129 if (m_manager_display_service) {
130 if (m_system_shared_layer_id) {
131 m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
132 }
133
134 for (const auto layer_id : m_managed_display_layers) {
135 m_manager_display_service->SetLayerVisibility(m_visible, layer_id);
136 }
137 }
138}
139
140bool DisplayLayerManager::GetWindowVisibility() const {
141 return m_visible;
142}
143
144Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written,
145 s32* out_fbshare_layer_index) {
146 R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied);
147 R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer(
148 out_was_written, out_fbshare_layer_index));
149}
150
151} // namespace Service::AM
diff --git a/src/core/hle/service/am/display_layer_manager.h b/src/core/hle/service/am/display_layer_manager.h
new file mode 100644
index 000000000..a66509c04
--- /dev/null
+++ b/src/core/hle/service/am/display_layer_manager.h
@@ -0,0 +1,62 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8#include "common/common_types.h"
9#include "core/hle/result.h"
10#include "core/hle/service/am/am_types.h"
11
12namespace Core {
13class System;
14}
15
16namespace Kernel {
17class KProcess;
18}
19
20namespace Service::VI {
21class IApplicationDisplayService;
22class IManagerDisplayService;
23} // namespace Service::VI
24
25namespace Service::AM {
26
27class DisplayLayerManager {
28public:
29 explicit DisplayLayerManager();
30 ~DisplayLayerManager();
31
32 void Initialize(Core::System& system, Kernel::KProcess* process, AppletId applet_id,
33 LibraryAppletMode mode);
34 void Finalize();
35
36 Result CreateManagedDisplayLayer(u64* out_layer_id);
37 Result CreateManagedDisplaySeparableLayer(u64* out_layer_id, u64* out_recording_layer_id);
38
39 Result IsSystemBufferSharingEnabled();
40 Result GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
41 u64* out_system_shared_layer_id);
42
43 void SetWindowVisibility(bool visible);
44 bool GetWindowVisibility() const;
45
46 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
47
48private:
49 Kernel::KProcess* m_process{};
50 std::shared_ptr<VI::IApplicationDisplayService> m_display_service{};
51 std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{};
52 std::set<u64> m_managed_display_layers{};
53 std::set<u64> m_managed_display_recording_layers{};
54 u64 m_system_shared_buffer_id{};
55 u64 m_system_shared_layer_id{};
56 AppletId m_applet_id{};
57 bool m_buffer_sharing_enabled{};
58 bool m_blending_enabled{};
59 bool m_visible{true};
60};
61
62} // namespace Service::AM
diff --git a/src/core/hle/service/am/frontend/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp
index bb60260b4..835c20c4e 100644
--- a/src/core/hle/service/am/frontend/applet_web_browser.cpp
+++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp
@@ -22,7 +22,7 @@
22#include "core/hle/service/am/frontend/applet_web_browser.h" 22#include "core/hle/service/am/frontend/applet_web_browser.h"
23#include "core/hle/service/am/service/storage.h" 23#include "core/hle/service/am/service/storage.h"
24#include "core/hle/service/filesystem/filesystem.h" 24#include "core/hle/service/filesystem/filesystem.h"
25#include "core/hle/service/ns/iplatform_service_manager.h" 25#include "core/hle/service/ns/platform_service_manager.h"
26#include "core/loader/loader.h" 26#include "core/loader/loader.h"
27 27
28namespace Service::AM::Frontend { 28namespace Service::AM::Frontend {
diff --git a/src/core/hle/service/am/library_applet_storage.cpp b/src/core/hle/service/am/library_applet_storage.cpp
index 46e6c0111..0412c215d 100644
--- a/src/core/hle/service/am/library_applet_storage.cpp
+++ b/src/core/hle/service/am/library_applet_storage.cpp
@@ -70,7 +70,7 @@ public:
70 Result Read(s64 offset, void* buffer, size_t size) override { 70 Result Read(s64 offset, void* buffer, size_t size) override {
71 R_TRY(ValidateOffset(offset, size, m_size)); 71 R_TRY(ValidateOffset(offset, size, m_size));
72 72
73 m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size); 73 m_memory.ReadBlock(m_trmem->GetSourceAddress() + offset, buffer, size);
74 74
75 R_SUCCEED(); 75 R_SUCCEED();
76 } 76 }
@@ -79,7 +79,7 @@ public:
79 R_UNLESS(m_is_writable, ResultUnknown); 79 R_UNLESS(m_is_writable, ResultUnknown);
80 R_TRY(ValidateOffset(offset, size, m_size)); 80 R_TRY(ValidateOffset(offset, size, m_size));
81 81
82 m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size); 82 m_memory.WriteBlock(m_trmem->GetSourceAddress() + offset, buffer, size);
83 83
84 R_SUCCEED(); 84 R_SUCCEED();
85 } 85 }
diff --git a/src/core/hle/service/am/managed_layer_holder.cpp b/src/core/hle/service/am/managed_layer_holder.cpp
deleted file mode 100644
index 61eb8641a..000000000
--- a/src/core/hle/service/am/managed_layer_holder.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/managed_layer_holder.h"
5#include "core/hle/service/nvnflinger/nvnflinger.h"
6
7namespace Service::AM {
8
9ManagedLayerHolder::ManagedLayerHolder() = default;
10ManagedLayerHolder::~ManagedLayerHolder() {
11 if (!m_nvnflinger) {
12 return;
13 }
14
15 for (const auto& layer : m_managed_display_layers) {
16 m_nvnflinger->DestroyLayer(layer);
17 }
18
19 for (const auto& layer : m_managed_display_recording_layers) {
20 m_nvnflinger->DestroyLayer(layer);
21 }
22
23 m_nvnflinger = nullptr;
24}
25
26void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
27 m_nvnflinger = nvnflinger;
28}
29
30void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
31 // TODO(Subv): Find out how AM determines the display to use, for now just
32 // create the layer in the Default display.
33 const auto display_id = m_nvnflinger->OpenDisplay("Default");
34 const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
35
36 m_managed_display_layers.emplace(*layer_id);
37
38 *out_layer = *layer_id;
39}
40
41void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
42 u64* out_recording_layer) {
43 // TODO(Subv): Find out how AM determines the display to use, for now just
44 // create the layer in the Default display.
45 // This calls nn::vi::CreateRecordingLayer() which creates another layer.
46 // Currently we do not support more than 1 layer per display, output 1 layer id for now.
47 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
48 // side effects.
49 // TODO: Support multiple layers
50 const auto display_id = m_nvnflinger->OpenDisplay("Default");
51 const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
52
53 m_managed_display_layers.emplace(*layer_id);
54
55 *out_layer = *layer_id;
56 *out_recording_layer = 0;
57}
58
59} // namespace Service::AM
diff --git a/src/core/hle/service/am/managed_layer_holder.h b/src/core/hle/service/am/managed_layer_holder.h
deleted file mode 100644
index f7fe03f24..000000000
--- a/src/core/hle/service/am/managed_layer_holder.h
+++ /dev/null
@@ -1,32 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11namespace Service::Nvnflinger {
12class Nvnflinger;
13}
14
15namespace Service::AM {
16
17class ManagedLayerHolder {
18public:
19 ManagedLayerHolder();
20 ~ManagedLayerHolder();
21
22 void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
23 void CreateManagedDisplayLayer(u64* out_layer);
24 void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
25
26private:
27 Nvnflinger::Nvnflinger* m_nvnflinger{};
28 std::set<u64> m_managed_display_layers{};
29 std::set<u64> m_managed_display_recording_layers{};
30};
31
32} // namespace Service::AM
diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp
index 992c50713..388d2045c 100644
--- a/src/core/hle/service/am/process.cpp
+++ b/src/core/hle/service/am/process.cpp
@@ -68,7 +68,9 @@ bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_k
68 Kernel::KProcess::Register(m_system.Kernel(), process); 68 Kernel::KProcess::Register(m_system.Kernel(), process);
69 69
70 // On exit, ensure we free the additional reference to the process. 70 // On exit, ensure we free the additional reference to the process.
71 SCOPE_EXIT({ process->Close(); }); 71 SCOPE_EXIT {
72 process->Close();
73 };
72 74
73 // Insert process modules into memory. 75 // Insert process modules into memory.
74 const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); 76 const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
index eebd90ba2..21747783a 100644
--- a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
+++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
@@ -10,9 +10,8 @@
10 10
11namespace Service::AM { 11namespace Service::AM {
12 12
13IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_, 13IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_)
14 Nvnflinger::Nvnflinger& nvnflinger) 14 : ServiceFramework{system_, "appletAE"} {
15 : ServiceFramework{system_, "appletAE"}, m_nvnflinger{nvnflinger} {
16 // clang-format off 15 // clang-format off
17 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
18 {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"}, 17 {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
@@ -37,8 +36,8 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
37 LOG_DEBUG(Service_AM, "called"); 36 LOG_DEBUG(Service_AM, "called");
38 37
39 if (const auto applet = this->GetAppletFromProcessId(pid); applet) { 38 if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
40 *out_system_applet_proxy = std::make_shared<ISystemAppletProxy>( 39 *out_system_applet_proxy =
41 system, applet, process_handle.Get(), m_nvnflinger); 40 std::make_shared<ISystemAppletProxy>(system, applet, process_handle.Get());
42 R_SUCCEED(); 41 R_SUCCEED();
43 } else { 42 } else {
44 UNIMPLEMENTED(); 43 UNIMPLEMENTED();
@@ -53,8 +52,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
53 LOG_DEBUG(Service_AM, "called"); 52 LOG_DEBUG(Service_AM, "called");
54 53
55 if (const auto applet = this->GetAppletFromProcessId(pid); applet) { 54 if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
56 *out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>( 55 *out_library_applet_proxy =
57 system, applet, process_handle.Get(), m_nvnflinger); 56 std::make_shared<ILibraryAppletProxy>(system, applet, process_handle.Get());
58 R_SUCCEED(); 57 R_SUCCEED();
59 } else { 58 } else {
60 UNIMPLEMENTED(); 59 UNIMPLEMENTED();
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.h b/src/core/hle/service/am/service/all_system_applet_proxies_service.h
index 38b1ca2ea..0e2dcb86d 100644
--- a/src/core/hle/service/am/service/all_system_applet_proxies_service.h
+++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.h
@@ -8,10 +8,6 @@
8 8
9namespace Service { 9namespace Service {
10 10
11namespace Nvnflinger {
12class Nvnflinger;
13}
14
15namespace AM { 11namespace AM {
16 12
17struct Applet; 13struct Applet;
@@ -22,8 +18,7 @@ class ISystemAppletProxy;
22class IAllSystemAppletProxiesService final 18class IAllSystemAppletProxiesService final
23 : public ServiceFramework<IAllSystemAppletProxiesService> { 19 : public ServiceFramework<IAllSystemAppletProxiesService> {
24public: 20public:
25 explicit IAllSystemAppletProxiesService(Core::System& system_, 21 explicit IAllSystemAppletProxiesService(Core::System& system_);
26 Nvnflinger::Nvnflinger& nvnflinger);
27 ~IAllSystemAppletProxiesService() override; 22 ~IAllSystemAppletProxiesService() override;
28 23
29private: 24private:
@@ -40,7 +35,6 @@ private:
40 35
41private: 36private:
42 std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); 37 std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
43 Nvnflinger::Nvnflinger& m_nvnflinger;
44}; 38};
45 39
46} // namespace AM 40} // namespace AM
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
index 63dd12a47..cb53b07e0 100644
--- a/src/core/hle/service/am/service/application_functions.cpp
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -16,7 +16,8 @@
16#include "core/hle/service/filesystem/filesystem.h" 16#include "core/hle/service/filesystem/filesystem.h"
17#include "core/hle/service/filesystem/save_data_controller.h" 17#include "core/hle/service/filesystem/save_data_controller.h"
18#include "core/hle/service/glue/glue_manager.h" 18#include "core/hle/service/glue/glue_manager.h"
19#include "core/hle/service/ns/ns.h" 19#include "core/hle/service/ns/application_manager_interface.h"
20#include "core/hle/service/ns/service_getter_interface.h"
20#include "core/hle/service/sm/sm.h" 21#include "core/hle/service/sm/sm.h"
21 22
22namespace Service::AM { 23namespace Service::AM {
@@ -163,11 +164,13 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
163 164
164 // Call IApplicationManagerInterface implementation. 165 // Call IApplicationManagerInterface implementation.
165 auto& service_manager = system.ServiceManager(); 166 auto& service_manager = system.ServiceManager();
166 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); 167 auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2");
167 auto app_man = ns_am2->GetApplicationManagerInterface(); 168
169 std::shared_ptr<NS::IApplicationManagerInterface> app_man;
170 R_TRY(ns_am2->GetApplicationManagerInterface(&app_man));
168 171
169 // Get desired application language 172 // Get desired application language
170 u8 desired_language{}; 173 NS::ApplicationLanguage desired_language{};
171 R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); 174 R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
172 175
173 // Convert to settings language code. 176 // Convert to settings language code.
diff --git a/src/core/hle/service/am/service/application_proxy.cpp b/src/core/hle/service/am/service/application_proxy.cpp
index 776f4552b..19d6a3b89 100644
--- a/src/core/hle/service/am/service/application_proxy.cpp
+++ b/src/core/hle/service/am/service/application_proxy.cpp
@@ -17,9 +17,9 @@
17namespace Service::AM { 17namespace Service::AM {
18 18
19IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, 19IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
20 Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger) 20 Kernel::KProcess* process)
21 : ServiceFramework{system_, "IApplicationProxy"}, 21 : ServiceFramework{system_, "IApplicationProxy"}, m_process{process}, m_applet{
22 m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { 22 std::move(applet)} {
23 // clang-format off 23 // clang-format off
24 static const FunctionInfo functions[] = { 24 static const FunctionInfo functions[] = {
25 {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, 25 {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@@ -77,8 +77,7 @@ Result IApplicationProxy::GetWindowController(
77Result IApplicationProxy::GetSelfController( 77Result IApplicationProxy::GetSelfController(
78 Out<SharedPointer<ISelfController>> out_self_controller) { 78 Out<SharedPointer<ISelfController>> out_self_controller) {
79 LOG_DEBUG(Service_AM, "called"); 79 LOG_DEBUG(Service_AM, "called");
80 *out_self_controller = 80 *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
81 std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
82 R_SUCCEED(); 81 R_SUCCEED();
83} 82}
84 83
diff --git a/src/core/hle/service/am/service/application_proxy.h b/src/core/hle/service/am/service/application_proxy.h
index 1ebc593ba..6da350df7 100644
--- a/src/core/hle/service/am/service/application_proxy.h
+++ b/src/core/hle/service/am/service/application_proxy.h
@@ -22,7 +22,7 @@ class IWindowController;
22class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { 22class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
23public: 23public:
24 explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, 24 explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
25 Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); 25 Kernel::KProcess* process);
26 ~IApplicationProxy(); 26 ~IApplicationProxy();
27 27
28private: 28private:
@@ -40,7 +40,6 @@ private:
40 Out<SharedPointer<IApplicationFunctions>> out_application_functions); 40 Out<SharedPointer<IApplicationFunctions>> out_application_functions);
41 41
42private: 42private:
43 Nvnflinger::Nvnflinger& m_nvnflinger;
44 Kernel::KProcess* const m_process; 43 Kernel::KProcess* const m_process;
45 const std::shared_ptr<Applet> m_applet; 44 const std::shared_ptr<Applet> m_applet;
46}; 45};
diff --git a/src/core/hle/service/am/service/application_proxy_service.cpp b/src/core/hle/service/am/service/application_proxy_service.cpp
index 36d4478df..fd66e77b9 100644
--- a/src/core/hle/service/am/service/application_proxy_service.cpp
+++ b/src/core/hle/service/am/service/application_proxy_service.cpp
@@ -10,9 +10,8 @@
10 10
11namespace Service::AM { 11namespace Service::AM {
12 12
13IApplicationProxyService::IApplicationProxyService(Core::System& system_, 13IApplicationProxyService::IApplicationProxyService(Core::System& system_)
14 Nvnflinger::Nvnflinger& nvnflinger) 14 : ServiceFramework{system_, "appletOE"} {
15 : ServiceFramework{system_, "appletOE"}, m_nvnflinger{nvnflinger} {
16 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
17 {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"}, 16 {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
18 }; 17 };
@@ -28,7 +27,7 @@ Result IApplicationProxyService::OpenApplicationProxy(
28 27
29 if (const auto applet = this->GetAppletFromProcessId(pid)) { 28 if (const auto applet = this->GetAppletFromProcessId(pid)) {
30 *out_application_proxy = 29 *out_application_proxy =
31 std::make_shared<IApplicationProxy>(system, applet, process_handle.Get(), m_nvnflinger); 30 std::make_shared<IApplicationProxy>(system, applet, process_handle.Get());
32 R_SUCCEED(); 31 R_SUCCEED();
33 } else { 32 } else {
34 UNIMPLEMENTED(); 33 UNIMPLEMENTED();
diff --git a/src/core/hle/service/am/service/application_proxy_service.h b/src/core/hle/service/am/service/application_proxy_service.h
index 1c1d32d0b..8efafa31a 100644
--- a/src/core/hle/service/am/service/application_proxy_service.h
+++ b/src/core/hle/service/am/service/application_proxy_service.h
@@ -8,10 +8,6 @@
8 8
9namespace Service { 9namespace Service {
10 10
11namespace Nvnflinger {
12class Nvnflinger;
13}
14
15namespace AM { 11namespace AM {
16 12
17struct Applet; 13struct Applet;
@@ -19,7 +15,7 @@ class IApplicationProxy;
19 15
20class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> { 16class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
21public: 17public:
22 explicit IApplicationProxyService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger); 18 explicit IApplicationProxyService(Core::System& system_);
23 ~IApplicationProxyService() override; 19 ~IApplicationProxyService() override;
24 20
25private: 21private:
@@ -28,7 +24,6 @@ private:
28 24
29private: 25private:
30 std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); 26 std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
31 Nvnflinger::Nvnflinger& m_nvnflinger;
32}; 27};
33 28
34} // namespace AM 29} // namespace AM
diff --git a/src/core/hle/service/am/service/display_controller.cpp b/src/core/hle/service/am/service/display_controller.cpp
index 249c73dfb..ed71f9093 100644
--- a/src/core/hle/service/am/service/display_controller.cpp
+++ b/src/core/hle/service/am/service/display_controller.cpp
@@ -69,7 +69,7 @@ Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_i
69Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer( 69Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
70 Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { 70 Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
71 LOG_WARNING(Service_AM, "(STUBBED) called"); 71 LOG_WARNING(Service_AM, "(STUBBED) called");
72 R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, 72 R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
73 out_fbshare_layer_index)); 73 out_fbshare_layer_index));
74} 74}
75 75
@@ -81,7 +81,7 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
81Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer( 81Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
82 Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { 82 Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
83 LOG_WARNING(Service_AM, "(STUBBED) called"); 83 LOG_WARNING(Service_AM, "(STUBBED) called");
84 R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, 84 R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
85 out_fbshare_layer_index)); 85 out_fbshare_layer_index));
86} 86}
87 87
@@ -93,7 +93,7 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
93Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer( 93Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
94 Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { 94 Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
95 LOG_WARNING(Service_AM, "(STUBBED) called"); 95 LOG_WARNING(Service_AM, "(STUBBED) called");
96 R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, 96 R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written,
97 out_fbshare_layer_index)); 97 out_fbshare_layer_index));
98} 98}
99 99
diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp
index 166637d60..c97358d81 100644
--- a/src/core/hle/service/am/service/library_applet_creator.cpp
+++ b/src/core/hle/service/am/service/library_applet_creator.cpp
@@ -135,7 +135,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
135 case LibraryAppletMode::AllForegroundInitiallyHidden: 135 case LibraryAppletMode::AllForegroundInitiallyHidden:
136 applet->hid_registration.EnableAppletToGetInput(false); 136 applet->hid_registration.EnableAppletToGetInput(false);
137 applet->focus_state = FocusState::NotInFocus; 137 applet->focus_state = FocusState::NotInFocus;
138 applet->system_buffer_manager.SetWindowVisibility(false); 138 applet->display_layer_manager.SetWindowVisibility(false);
139 applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground); 139 applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
140 break; 140 break;
141 } 141 }
diff --git a/src/core/hle/service/am/service/library_applet_proxy.cpp b/src/core/hle/service/am/service/library_applet_proxy.cpp
index bcb44a71c..58e709347 100644
--- a/src/core/hle/service/am/service/library_applet_proxy.cpp
+++ b/src/core/hle/service/am/service/library_applet_proxy.cpp
@@ -19,10 +19,9 @@
19namespace Service::AM { 19namespace Service::AM {
20 20
21ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, 21ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
22 Kernel::KProcess* process, 22 Kernel::KProcess* process)
23 Nvnflinger::Nvnflinger& nvnflinger) 23 : ServiceFramework{system_, "ILibraryAppletProxy"}, m_process{process}, m_applet{
24 : ServiceFramework{system_, "ILibraryAppletProxy"}, 24 std::move(applet)} {
25 m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
26 // clang-format off 25 // clang-format off
27 static const FunctionInfo functions[] = { 26 static const FunctionInfo functions[] = {
28 {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, 27 {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@@ -83,8 +82,7 @@ Result ILibraryAppletProxy::GetWindowController(
83Result ILibraryAppletProxy::GetSelfController( 82Result ILibraryAppletProxy::GetSelfController(
84 Out<SharedPointer<ISelfController>> out_self_controller) { 83 Out<SharedPointer<ISelfController>> out_self_controller) {
85 LOG_DEBUG(Service_AM, "called"); 84 LOG_DEBUG(Service_AM, "called");
86 *out_self_controller = 85 *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
87 std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
88 R_SUCCEED(); 86 R_SUCCEED();
89} 87}
90 88
diff --git a/src/core/hle/service/am/service/library_applet_proxy.h b/src/core/hle/service/am/service/library_applet_proxy.h
index 23e64e295..7d0714b85 100644
--- a/src/core/hle/service/am/service/library_applet_proxy.h
+++ b/src/core/hle/service/am/service/library_applet_proxy.h
@@ -25,7 +25,7 @@ class IWindowController;
25class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { 25class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
26public: 26public:
27 explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, 27 explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
28 Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); 28 Kernel::KProcess* process);
29 ~ILibraryAppletProxy(); 29 ~ILibraryAppletProxy();
30 30
31private: 31private:
@@ -47,7 +47,6 @@ private:
47 Result GetGlobalStateController( 47 Result GetGlobalStateController(
48 Out<SharedPointer<IGlobalStateController>> out_global_state_controller); 48 Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
49 49
50 Nvnflinger::Nvnflinger& m_nvnflinger;
51 Kernel::KProcess* const m_process; 50 Kernel::KProcess* const m_process;
52 const std::shared_ptr<Applet> m_applet; 51 const std::shared_ptr<Applet> m_applet;
53}; 52};
diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.cpp b/src/core/hle/service/am/service/library_applet_self_accessor.cpp
index 94bd4dae6..330eb26f0 100644
--- a/src/core/hle/service/am/service/library_applet_self_accessor.cpp
+++ b/src/core/hle/service/am/service/library_applet_self_accessor.cpp
@@ -14,7 +14,8 @@
14#include "core/hle/service/cmif_serialization.h" 14#include "core/hle/service/cmif_serialization.h"
15#include "core/hle/service/filesystem/filesystem.h" 15#include "core/hle/service/filesystem/filesystem.h"
16#include "core/hle/service/glue/glue_manager.h" 16#include "core/hle/service/glue/glue_manager.h"
17#include "core/hle/service/ns/ns.h" 17#include "core/hle/service/ns/application_manager_interface.h"
18#include "core/hle/service/ns/service_getter_interface.h"
18#include "core/hle/service/sm/sm.h" 19#include "core/hle/service/sm/sm.h"
19 20
20namespace Service::AM { 21namespace Service::AM {
@@ -256,11 +257,13 @@ Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(
256 257
257 // Call IApplicationManagerInterface implementation. 258 // Call IApplicationManagerInterface implementation.
258 auto& service_manager = system.ServiceManager(); 259 auto& service_manager = system.ServiceManager();
259 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); 260 auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2");
260 auto app_man = ns_am2->GetApplicationManagerInterface(); 261
262 std::shared_ptr<NS::IApplicationManagerInterface> app_man;
263 R_TRY(ns_am2->GetApplicationManagerInterface(&app_man));
261 264
262 // Get desired application language 265 // Get desired application language
263 u8 desired_language{}; 266 NS::ApplicationLanguage desired_language{};
264 R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); 267 R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
265 268
266 // Convert to settings language code. 269 // Convert to settings language code.
diff --git a/src/core/hle/service/am/service/self_controller.cpp b/src/core/hle/service/am/service/self_controller.cpp
index 5c4c13de1..06314407c 100644
--- a/src/core/hle/service/am/service/self_controller.cpp
+++ b/src/core/hle/service/am/service/self_controller.cpp
@@ -15,9 +15,9 @@
15namespace Service::AM { 15namespace Service::AM {
16 16
17ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet, 17ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
18 Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger) 18 Kernel::KProcess* process)
19 : ServiceFramework{system_, "ISelfController"}, 19 : ServiceFramework{system_, "ISelfController"}, m_process{process}, m_applet{
20 m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { 20 std::move(applet)} {
21 // clang-format off 21 // clang-format off
22 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
23 {0, D<&ISelfController::Exit>, "Exit"}, 23 {0, D<&ISelfController::Exit>, "Exit"},
@@ -72,9 +72,16 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
72 // clang-format on 72 // clang-format on
73 73
74 RegisterHandlers(functions); 74 RegisterHandlers(functions);
75
76 std::scoped_lock lk{m_applet->lock};
77 m_applet->display_layer_manager.Initialize(system, m_process, m_applet->applet_id,
78 m_applet->library_applet_mode);
75} 79}
76 80
77ISelfController::~ISelfController() = default; 81ISelfController::~ISelfController() {
82 std::scoped_lock lk{m_applet->lock};
83 m_applet->display_layer_manager.Finalize();
84}
78 85
79Result ISelfController::Exit() { 86Result ISelfController::Exit() {
80 LOG_DEBUG(Service_AM, "called"); 87 LOG_DEBUG(Service_AM, "called");
@@ -212,48 +219,42 @@ Result ISelfController::SetAlbumImageOrientation(
212 219
213Result ISelfController::IsSystemBufferSharingEnabled() { 220Result ISelfController::IsSystemBufferSharingEnabled() {
214 LOG_INFO(Service_AM, "called"); 221 LOG_INFO(Service_AM, "called");
215 R_SUCCEED_IF(m_applet->system_buffer_manager.Initialize( 222
216 &m_nvnflinger, m_process, m_applet->applet_id, m_applet->library_applet_mode)); 223 std::scoped_lock lk{m_applet->lock};
217 R_THROW(VI::ResultOperationFailed); 224 R_RETURN(m_applet->display_layer_manager.IsSystemBufferSharingEnabled());
218} 225}
219 226
220Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) { 227Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) {
221 LOG_WARNING(Service_AM, "(STUBBED) called"); 228 LOG_INFO(Service_AM, "called");
222
223 R_TRY(this->IsSystemBufferSharingEnabled());
224 229
225 u64 layer_id; 230 u64 layer_id;
226 m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id); 231
227 R_SUCCEED(); 232 std::scoped_lock lk{m_applet->lock};
233 R_RETURN(m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id));
228} 234}
229 235
230Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) { 236Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) {
231 LOG_INFO(Service_AM, "(STUBBED) called"); 237 LOG_INFO(Service_AM, "called");
232
233 R_TRY(this->IsSystemBufferSharingEnabled());
234 238
235 m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id); 239 std::scoped_lock lk{m_applet->lock};
236 R_SUCCEED(); 240 R_RETURN(
241 m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id));
237} 242}
238 243
239Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) { 244Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) {
240 LOG_INFO(Service_AM, "called"); 245 LOG_INFO(Service_AM, "called");
241 246
242 m_applet->managed_layer_holder.Initialize(&m_nvnflinger); 247 std::scoped_lock lk{m_applet->lock};
243 m_applet->managed_layer_holder.CreateManagedDisplayLayer(out_layer_id); 248 R_RETURN(m_applet->display_layer_manager.CreateManagedDisplayLayer(out_layer_id));
244
245 R_SUCCEED();
246} 249}
247 250
248Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id, 251Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id,
249 Out<u64> out_recording_layer_id) { 252 Out<u64> out_recording_layer_id) {
250 LOG_WARNING(Service_AM, "(STUBBED) called"); 253 LOG_WARNING(Service_AM, "(STUBBED) called");
251 254
252 m_applet->managed_layer_holder.Initialize(&m_nvnflinger); 255 std::scoped_lock lk{m_applet->lock};
253 m_applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(out_layer_id, 256 R_RETURN(m_applet->display_layer_manager.CreateManagedDisplaySeparableLayer(
254 out_recording_layer_id); 257 out_layer_id, out_recording_layer_id));
255
256 R_SUCCEED();
257} 258}
258 259
259Result ISelfController::SetHandlesRequestToDisplay(bool enable) { 260Result ISelfController::SetHandlesRequestToDisplay(bool enable) {
diff --git a/src/core/hle/service/am/service/self_controller.h b/src/core/hle/service/am/service/self_controller.h
index 01fa381a3..eca083cfe 100644
--- a/src/core/hle/service/am/service/self_controller.h
+++ b/src/core/hle/service/am/service/self_controller.h
@@ -23,7 +23,7 @@ struct Applet;
23class ISelfController final : public ServiceFramework<ISelfController> { 23class ISelfController final : public ServiceFramework<ISelfController> {
24public: 24public:
25 explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet, 25 explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
26 Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); 26 Kernel::KProcess* process);
27 ~ISelfController() override; 27 ~ISelfController() override;
28 28
29private: 29private:
@@ -64,7 +64,6 @@ private:
64 Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option); 64 Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
65 Result SetRecordVolumeMuted(bool muted); 65 Result SetRecordVolumeMuted(bool muted);
66 66
67 Nvnflinger::Nvnflinger& m_nvnflinger;
68 Kernel::KProcess* const m_process; 67 Kernel::KProcess* const m_process;
69 const std::shared_ptr<Applet> m_applet; 68 const std::shared_ptr<Applet> m_applet;
70}; 69};
diff --git a/src/core/hle/service/am/service/system_applet_proxy.cpp b/src/core/hle/service/am/service/system_applet_proxy.cpp
index 5ec509d2e..d1871ef9b 100644
--- a/src/core/hle/service/am/service/system_applet_proxy.cpp
+++ b/src/core/hle/service/am/service/system_applet_proxy.cpp
@@ -19,10 +19,9 @@
19namespace Service::AM { 19namespace Service::AM {
20 20
21ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, 21ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
22 Kernel::KProcess* process, 22 Kernel::KProcess* process)
23 Nvnflinger::Nvnflinger& nvnflinger) 23 : ServiceFramework{system_, "ISystemAppletProxy"}, m_process{process}, m_applet{
24 : ServiceFramework{system_, "ISystemAppletProxy"}, 24 std::move(applet)} {
25 m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
26 // clang-format off 25 // clang-format off
27 static const FunctionInfo functions[] = { 26 static const FunctionInfo functions[] = {
28 {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, 27 {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@@ -83,8 +82,7 @@ Result ISystemAppletProxy::GetWindowController(
83Result ISystemAppletProxy::GetSelfController( 82Result ISystemAppletProxy::GetSelfController(
84 Out<SharedPointer<ISelfController>> out_self_controller) { 83 Out<SharedPointer<ISelfController>> out_self_controller) {
85 LOG_DEBUG(Service_AM, "called"); 84 LOG_DEBUG(Service_AM, "called");
86 *out_self_controller = 85 *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
87 std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
88 R_SUCCEED(); 86 R_SUCCEED();
89} 87}
90 88
diff --git a/src/core/hle/service/am/service/system_applet_proxy.h b/src/core/hle/service/am/service/system_applet_proxy.h
index 3d5040315..67cd50e03 100644
--- a/src/core/hle/service/am/service/system_applet_proxy.h
+++ b/src/core/hle/service/am/service/system_applet_proxy.h
@@ -25,7 +25,7 @@ class IWindowController;
25class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { 25class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
26public: 26public:
27 explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet, 27 explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet,
28 Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); 28 Kernel::KProcess* process);
29 ~ISystemAppletProxy(); 29 ~ISystemAppletProxy();
30 30
31private: 31private:
@@ -46,7 +46,6 @@ private:
46 Result GetGlobalStateController( 46 Result GetGlobalStateController(
47 Out<SharedPointer<IGlobalStateController>> out_global_state_controller); 47 Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
48 48
49 Nvnflinger::Nvnflinger& m_nvnflinger;
50 Kernel::KProcess* const m_process; 49 Kernel::KProcess* const m_process;
51 const std::shared_ptr<Applet> m_applet; 50 const std::shared_ptr<Applet> m_applet;
52}; 51};
diff --git a/src/core/hle/service/am/service/window_controller.cpp b/src/core/hle/service/am/service/window_controller.cpp
index b874ecb91..99a4f50a2 100644
--- a/src/core/hle/service/am/service/window_controller.cpp
+++ b/src/core/hle/service/am/service/window_controller.cpp
@@ -63,7 +63,7 @@ Result IWindowController::RejectToChangeIntoBackground() {
63} 63}
64 64
65Result IWindowController::SetAppletWindowVisibility(bool visible) { 65Result IWindowController::SetAppletWindowVisibility(bool visible) {
66 m_applet->system_buffer_manager.SetWindowVisibility(visible); 66 m_applet->display_layer_manager.SetWindowVisibility(visible);
67 m_applet->hid_registration.EnableAppletToGetInput(visible); 67 m_applet->hid_registration.EnableAppletToGetInput(visible);
68 68
69 if (visible) { 69 if (visible) {
diff --git a/src/core/hle/service/am/system_buffer_manager.cpp b/src/core/hle/service/am/system_buffer_manager.cpp
deleted file mode 100644
index 48923fe41..000000000
--- a/src/core/hle/service/am/system_buffer_manager.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/system_buffer_manager.h"
5#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
6#include "core/hle/service/nvnflinger/nvnflinger.h"
7#include "core/hle/service/vi/vi_results.h"
8
9namespace Service::AM {
10
11SystemBufferManager::SystemBufferManager() = default;
12
13SystemBufferManager::~SystemBufferManager() {
14 if (!m_nvnflinger) {
15 return;
16 }
17
18 // Clean up shared layers.
19 if (m_buffer_sharing_enabled) {
20 m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
21 }
22}
23
24bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
25 AppletId applet_id, LibraryAppletMode mode) {
26 if (m_nvnflinger) {
27 return m_buffer_sharing_enabled;
28 }
29
30 m_process = process;
31 m_nvnflinger = nvnflinger;
32 m_buffer_sharing_enabled = false;
33 m_system_shared_buffer_id = 0;
34 m_system_shared_layer_id = 0;
35
36 if (applet_id <= AppletId::Application) {
37 return false;
38 }
39
40 Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
41 if (mode == LibraryAppletMode::PartialForeground ||
42 mode == LibraryAppletMode::PartialForegroundIndirectDisplay) {
43 blending = Nvnflinger::LayerBlending::Coverage;
44 }
45
46 const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
47 const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
48 m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending);
49
50 if (res.IsSuccess()) {
51 m_buffer_sharing_enabled = true;
52 m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
53 }
54
55 return m_buffer_sharing_enabled;
56}
57
58void SystemBufferManager::SetWindowVisibility(bool visible) {
59 if (m_visible == visible) {
60 return;
61 }
62
63 m_visible = visible;
64
65 if (m_nvnflinger) {
66 m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
67 }
68}
69
70Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
71 s32* out_fbshare_layer_index) {
72 if (!m_buffer_sharing_enabled) {
73 return VI::ResultPermissionDenied;
74 }
75
76 return m_nvnflinger->GetSystemBufferManager().WriteAppletCaptureBuffer(out_was_written,
77 out_fbshare_layer_index);
78}
79
80} // namespace Service::AM
diff --git a/src/core/hle/service/am/system_buffer_manager.h b/src/core/hle/service/am/system_buffer_manager.h
deleted file mode 100644
index 0690f68b6..000000000
--- a/src/core/hle/service/am/system_buffer_manager.h
+++ /dev/null
@@ -1,52 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11#include "core/hle/service/am/am_types.h"
12
13namespace Kernel {
14class KProcess;
15}
16
17namespace Service::Nvnflinger {
18class Nvnflinger;
19}
20
21union Result;
22
23namespace Service::AM {
24
25class SystemBufferManager {
26public:
27 SystemBufferManager();
28 ~SystemBufferManager();
29
30 bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id,
31 LibraryAppletMode mode);
32
33 void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
34 u64* out_system_shared_layer_id) {
35 *out_system_shared_buffer_id = m_system_shared_buffer_id;
36 *out_system_shared_layer_id = m_system_shared_layer_id;
37 }
38
39 void SetWindowVisibility(bool visible);
40
41 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
42
43private:
44 Kernel::KProcess* m_process{};
45 Nvnflinger::Nvnflinger* m_nvnflinger{};
46 bool m_buffer_sharing_enabled{};
47 bool m_visible{true};
48 u64 m_system_shared_buffer_id{};
49 u64 m_system_shared_layer_id{};
50};
51
52} // namespace Service::AM
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
deleted file mode 100644
index cf4bb4034..000000000
--- a/src/core/hle/service/audio/audctl.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/audio/audctl.h"
6#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/set/system_settings_server.h"
8#include "core/hle/service/sm/sm.h"
9
10namespace Service::Audio {
11
12AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, nullptr, "GetTargetVolume"},
16 {1, nullptr, "SetTargetVolume"},
17 {2, &AudCtl::GetTargetVolumeMin, "GetTargetVolumeMin"},
18 {3, &AudCtl::GetTargetVolumeMax, "GetTargetVolumeMax"},
19 {4, nullptr, "IsTargetMute"},
20 {5, nullptr, "SetTargetMute"},
21 {6, nullptr, "IsTargetConnected"},
22 {7, nullptr, "SetDefaultTarget"},
23 {8, nullptr, "GetDefaultTarget"},
24 {9, &AudCtl::GetAudioOutputMode, "GetAudioOutputMode"},
25 {10, &AudCtl::SetAudioOutputMode, "SetAudioOutputMode"},
26 {11, nullptr, "SetForceMutePolicy"},
27 {12, &AudCtl::GetForceMutePolicy, "GetForceMutePolicy"},
28 {13, &AudCtl::GetOutputModeSetting, "GetOutputModeSetting"},
29 {14, &AudCtl::SetOutputModeSetting, "SetOutputModeSetting"},
30 {15, nullptr, "SetOutputTarget"},
31 {16, nullptr, "SetInputTargetForceEnabled"},
32 {17, &AudCtl::SetHeadphoneOutputLevelMode, "SetHeadphoneOutputLevelMode"},
33 {18, &AudCtl::GetHeadphoneOutputLevelMode, "GetHeadphoneOutputLevelMode"},
34 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
35 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
36 {21, nullptr, "GetAudioOutputTargetForPlayReport"},
37 {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
38 {23, nullptr, "SetSystemOutputMasterVolume"},
39 {24, nullptr, "GetSystemOutputMasterVolume"},
40 {25, nullptr, "GetAudioVolumeDataForPlayReport"},
41 {26, nullptr, "UpdateHeadphoneSettings"},
42 {27, nullptr, "SetVolumeMappingTableForDev"},
43 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
44 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
45 {30, &AudCtl::SetSpeakerAutoMuteEnabled, "SetSpeakerAutoMuteEnabled"},
46 {31, &AudCtl::IsSpeakerAutoMuteEnabled, "IsSpeakerAutoMuteEnabled"},
47 {32, nullptr, "GetActiveOutputTarget"},
48 {33, nullptr, "GetTargetDeviceInfo"},
49 {34, nullptr, "AcquireTargetNotification"},
50 {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
51 {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
52 {37, nullptr, "SetHearingProtectionSafeguardEnabled"},
53 {38, nullptr, "IsHearingProtectionSafeguardEnabled"},
54 {39, nullptr, "IsHearingProtectionSafeguardMonitoringOutputForDebug"},
55 {40, nullptr, "GetSystemInformationForDebug"},
56 {41, nullptr, "SetVolumeButtonLongPressTime"},
57 {42, nullptr, "SetNativeVolumeForDebug"},
58 {10000, nullptr, "NotifyAudioOutputTargetForPlayReport"},
59 {10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"},
60 {10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"},
61 {10100, nullptr, "GetAudioVolumeDataForPlayReport"},
62 {10101, nullptr, "BindAudioVolumeUpdateEventForPlayReport"},
63 {10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"},
64 {10103, nullptr, "GetAudioOutputTargetForPlayReport"},
65 {10104, nullptr, "GetAudioOutputChannelCountForPlayReport"},
66 {10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
67 {10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"},
68 {50000, nullptr, "SetAnalogInputBoostGainForPrototyping"},
69 };
70 // clang-format on
71
72 RegisterHandlers(functions);
73
74 m_set_sys =
75 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
76}
77
78AudCtl::~AudCtl() = default;
79
80void AudCtl::GetTargetVolumeMin(HLERequestContext& ctx) {
81 LOG_DEBUG(Audio, "called.");
82
83 // This service function is currently hardcoded on the
84 // actual console to this value (as of 8.0.0).
85 constexpr s32 target_min_volume = 0;
86
87 IPC::ResponseBuilder rb{ctx, 3};
88 rb.Push(ResultSuccess);
89 rb.Push(target_min_volume);
90}
91
92void AudCtl::GetTargetVolumeMax(HLERequestContext& ctx) {
93 LOG_DEBUG(Audio, "called.");
94
95 // This service function is currently hardcoded on the
96 // actual console to this value (as of 8.0.0).
97 constexpr s32 target_max_volume = 15;
98
99 IPC::ResponseBuilder rb{ctx, 3};
100 rb.Push(ResultSuccess);
101 rb.Push(target_max_volume);
102}
103
104void AudCtl::GetAudioOutputMode(HLERequestContext& ctx) {
105 IPC::RequestParser rp{ctx};
106 const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()};
107
108 Set::AudioOutputMode output_mode{};
109 const auto result = m_set_sys->GetAudioOutputMode(&output_mode, target);
110
111 LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
112
113 IPC::ResponseBuilder rb{ctx, 3};
114 rb.Push(result);
115 rb.PushEnum(output_mode);
116}
117
118void AudCtl::SetAudioOutputMode(HLERequestContext& ctx) {
119 IPC::RequestParser rp{ctx};
120 const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()};
121 const auto output_mode{rp.PopEnum<Set::AudioOutputMode>()};
122
123 const auto result = m_set_sys->SetAudioOutputMode(target, output_mode);
124
125 LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
126
127 IPC::ResponseBuilder rb{ctx, 2};
128 rb.Push(result);
129}
130
131void AudCtl::GetForceMutePolicy(HLERequestContext& ctx) {
132 LOG_WARNING(Audio, "(STUBBED) called");
133
134 IPC::ResponseBuilder rb{ctx, 3};
135 rb.Push(ResultSuccess);
136 rb.PushEnum(ForceMutePolicy::Disable);
137}
138
139void AudCtl::GetOutputModeSetting(HLERequestContext& ctx) {
140 IPC::RequestParser rp{ctx};
141 const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()};
142
143 LOG_WARNING(Audio, "(STUBBED) called, target={}", target);
144
145 IPC::ResponseBuilder rb{ctx, 3};
146 rb.Push(ResultSuccess);
147 rb.PushEnum(Set::AudioOutputMode::ch_7_1);
148}
149
150void AudCtl::SetOutputModeSetting(HLERequestContext& ctx) {
151 IPC::RequestParser rp{ctx};
152 const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()};
153 const auto output_mode{rp.PopEnum<Set::AudioOutputMode>()};
154
155 LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
156
157 IPC::ResponseBuilder rb{ctx, 2};
158 rb.Push(ResultSuccess);
159}
160
161void AudCtl::SetHeadphoneOutputLevelMode(HLERequestContext& ctx) {
162 LOG_WARNING(Audio, "(STUBBED) called");
163
164 IPC::ResponseBuilder rb{ctx, 2};
165 rb.Push(ResultSuccess);
166}
167
168void AudCtl::GetHeadphoneOutputLevelMode(HLERequestContext& ctx) {
169 LOG_WARNING(Audio, "(STUBBED) called");
170
171 IPC::ResponseBuilder rb{ctx, 3};
172 rb.Push(ResultSuccess);
173 rb.PushEnum(HeadphoneOutputLevelMode::Normal);
174}
175
176void AudCtl::SetSpeakerAutoMuteEnabled(HLERequestContext& ctx) {
177 IPC::RequestParser rp{ctx};
178 const auto is_speaker_auto_mute_enabled{rp.Pop<bool>()};
179
180 LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}",
181 is_speaker_auto_mute_enabled);
182
183 const auto result = m_set_sys->SetSpeakerAutoMuteFlag(is_speaker_auto_mute_enabled);
184
185 IPC::ResponseBuilder rb{ctx, 2};
186 rb.Push(result);
187}
188
189void AudCtl::IsSpeakerAutoMuteEnabled(HLERequestContext& ctx) {
190 bool is_speaker_auto_mute_enabled{};
191 const auto result = m_set_sys->GetSpeakerAutoMuteFlag(&is_speaker_auto_mute_enabled);
192
193 LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}",
194 is_speaker_auto_mute_enabled);
195
196 IPC::ResponseBuilder rb{ctx, 3};
197 rb.Push(result);
198 rb.Push<u8>(is_speaker_auto_mute_enabled);
199}
200
201} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h
deleted file mode 100644
index 4c90ead70..000000000
--- a/src/core/hle/service/audio/audctl.h
+++ /dev/null
@@ -1,50 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Core {
9class System;
10}
11
12namespace Service::Set {
13class ISystemSettingsServer;
14}
15
16namespace Service::Audio {
17
18class AudCtl final : public ServiceFramework<AudCtl> {
19public:
20 explicit AudCtl(Core::System& system_);
21 ~AudCtl() override;
22
23private:
24 enum class ForceMutePolicy {
25 Disable,
26 SpeakerMuteOnHeadphoneUnplugged,
27 };
28
29 enum class HeadphoneOutputLevelMode {
30 Normal,
31 HighPower,
32 };
33
34 void GetTargetVolumeMin(HLERequestContext& ctx);
35 void GetTargetVolumeMax(HLERequestContext& ctx);
36 void GetAudioOutputMode(HLERequestContext& ctx);
37 void SetAudioOutputMode(HLERequestContext& ctx);
38 void GetForceMutePolicy(HLERequestContext& ctx);
39 void GetOutputModeSetting(HLERequestContext& ctx);
40 void SetOutputModeSetting(HLERequestContext& ctx);
41 void SetHeadphoneOutputLevelMode(HLERequestContext& ctx);
42 void GetHeadphoneOutputLevelMode(HLERequestContext& ctx);
43 void SetSpeakerAutoMuteEnabled(HLERequestContext& ctx);
44 void IsSpeakerAutoMuteEnabled(HLERequestContext& ctx);
45 void AcquireTargetNotification(HLERequestContext& ctx);
46
47 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
48};
49
50} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index dccd16309..44af030eb 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -2,9 +2,9 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/core.h" 4#include "core/core.h"
5#include "core/hle/service/audio/audctl.h"
6#include "core/hle/service/audio/audin_u.h" 5#include "core/hle/service/audio/audin_u.h"
7#include "core/hle/service/audio/audio.h" 6#include "core/hle/service/audio/audio.h"
7#include "core/hle/service/audio/audio_controller.h"
8#include "core/hle/service/audio/audout_u.h" 8#include "core/hle/service/audio/audout_u.h"
9#include "core/hle/service/audio/audrec_a.h" 9#include "core/hle/service/audio/audrec_a.h"
10#include "core/hle/service/audio/audrec_u.h" 10#include "core/hle/service/audio/audrec_u.h"
@@ -18,7 +18,7 @@ namespace Service::Audio {
18void LoopProcess(Core::System& system) { 18void LoopProcess(Core::System& system) {
19 auto server_manager = std::make_unique<ServerManager>(system); 19 auto server_manager = std::make_unique<ServerManager>(system);
20 20
21 server_manager->RegisterNamedService("audctl", std::make_shared<AudCtl>(system)); 21 server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
22 server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system)); 22 server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system));
23 server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system)); 23 server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system));
24 server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system)); 24 server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system));
diff --git a/src/core/hle/service/audio/audio_controller.cpp b/src/core/hle/service/audio/audio_controller.cpp
new file mode 100644
index 000000000..a6da66d0f
--- /dev/null
+++ b/src/core/hle/service/audio/audio_controller.cpp
@@ -0,0 +1,174 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/audio/audio_controller.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/ipc_helpers.h"
8#include "core/hle/service/set/system_settings_server.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::Audio {
12
13IAudioController::IAudioController(Core::System& system_)
14 : ServiceFramework{system_, "audctl"}, service_context{system, "audctl"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GetTargetVolume"},
18 {1, nullptr, "SetTargetVolume"},
19 {2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
20 {3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
21 {4, nullptr, "IsTargetMute"},
22 {5, nullptr, "SetTargetMute"},
23 {6, nullptr, "IsTargetConnected"},
24 {7, nullptr, "SetDefaultTarget"},
25 {8, nullptr, "GetDefaultTarget"},
26 {9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
27 {10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
28 {11, nullptr, "SetForceMutePolicy"},
29 {12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
30 {13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
31 {14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
32 {15, nullptr, "SetOutputTarget"},
33 {16, nullptr, "SetInputTargetForceEnabled"},
34 {17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
35 {18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
36 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
37 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
38 {21, nullptr, "GetAudioOutputTargetForPlayReport"},
39 {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
40 {23, nullptr, "SetSystemOutputMasterVolume"},
41 {24, nullptr, "GetSystemOutputMasterVolume"},
42 {25, nullptr, "GetAudioVolumeDataForPlayReport"},
43 {26, nullptr, "UpdateHeadphoneSettings"},
44 {27, nullptr, "SetVolumeMappingTableForDev"},
45 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
46 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
47 {30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
48 {31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
49 {32, nullptr, "GetActiveOutputTarget"},
50 {33, nullptr, "GetTargetDeviceInfo"},
51 {34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
52 {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
53 {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
54 {37, nullptr, "SetHearingProtectionSafeguardEnabled"},
55 {38, nullptr, "IsHearingProtectionSafeguardEnabled"},
56 {39, nullptr, "IsHearingProtectionSafeguardMonitoringOutputForDebug"},
57 {40, nullptr, "GetSystemInformationForDebug"},
58 {41, nullptr, "SetVolumeButtonLongPressTime"},
59 {42, nullptr, "SetNativeVolumeForDebug"},
60 {10000, nullptr, "NotifyAudioOutputTargetForPlayReport"},
61 {10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"},
62 {10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"},
63 {10100, nullptr, "GetAudioVolumeDataForPlayReport"},
64 {10101, nullptr, "BindAudioVolumeUpdateEventForPlayReport"},
65 {10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"},
66 {10103, nullptr, "GetAudioOutputTargetForPlayReport"},
67 {10104, nullptr, "GetAudioOutputChannelCountForPlayReport"},
68 {10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
69 {10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"},
70 {50000, nullptr, "SetAnalogInputBoostGainForPrototyping"},
71 };
72 // clang-format on
73
74 RegisterHandlers(functions);
75
76 m_set_sys =
77 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
78 notification_event = service_context.CreateEvent("IAudioController:NotificationEvent");
79}
80
81IAudioController::~IAudioController() {
82 service_context.CloseEvent(notification_event);
83};
84
85Result IAudioController::GetTargetVolumeMin(Out<s32> out_target_min_volume) {
86 LOG_DEBUG(Audio, "called.");
87
88 // This service function is currently hardcoded on the
89 // actual console to this value (as of 8.0.0).
90 *out_target_min_volume = 0;
91 R_SUCCEED();
92}
93
94Result IAudioController::GetTargetVolumeMax(Out<s32> out_target_max_volume) {
95 LOG_DEBUG(Audio, "called.");
96
97 // This service function is currently hardcoded on the
98 // actual console to this value (as of 8.0.0).
99 *out_target_max_volume = 15;
100 R_SUCCEED();
101}
102
103Result IAudioController::GetAudioOutputMode(Out<Set::AudioOutputMode> out_output_mode,
104 Set::AudioOutputModeTarget target) {
105 const auto result = m_set_sys->GetAudioOutputMode(out_output_mode, target);
106
107 LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, *out_output_mode);
108 R_RETURN(result);
109}
110
111Result IAudioController::SetAudioOutputMode(Set::AudioOutputModeTarget target,
112 Set::AudioOutputMode output_mode) {
113 LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
114
115 R_RETURN(m_set_sys->SetAudioOutputMode(target, output_mode));
116}
117
118Result IAudioController::GetForceMutePolicy(Out<ForceMutePolicy> out_mute_policy) {
119 LOG_WARNING(Audio, "(STUBBED) called");
120
121 // Removed on FW 13.2.1+
122 *out_mute_policy = ForceMutePolicy::Disable;
123 R_SUCCEED();
124}
125
126Result IAudioController::GetOutputModeSetting(Out<Set::AudioOutputMode> out_output_mode,
127 Set::AudioOutputModeTarget target) {
128 LOG_WARNING(Audio, "(STUBBED) called, target={}", target);
129
130 *out_output_mode = Set::AudioOutputMode::ch_7_1;
131 R_SUCCEED();
132}
133
134Result IAudioController::SetOutputModeSetting(Set::AudioOutputModeTarget target,
135 Set::AudioOutputMode output_mode) {
136 LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode);
137 R_SUCCEED();
138}
139
140Result IAudioController::SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode) {
141 LOG_WARNING(Audio, "(STUBBED) called");
142 R_SUCCEED();
143}
144
145Result IAudioController::GetHeadphoneOutputLevelMode(
146 Out<HeadphoneOutputLevelMode> out_output_level_mode) {
147 LOG_INFO(Audio, "called");
148
149 *out_output_level_mode = HeadphoneOutputLevelMode::Normal;
150 R_SUCCEED();
151}
152
153Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
154 LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
155
156 R_RETURN(m_set_sys->SetSpeakerAutoMuteFlag(is_speaker_auto_mute_enabled));
157}
158
159Result IAudioController::IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled) {
160 const auto result = m_set_sys->GetSpeakerAutoMuteFlag(out_is_speaker_auto_mute_enabled);
161
162 LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", *out_is_speaker_auto_mute_enabled);
163 R_RETURN(result);
164}
165
166Result IAudioController::AcquireTargetNotification(
167 OutCopyHandle<Kernel::KReadableEvent> out_notification_event) {
168 LOG_WARNING(Service_AM, "(STUBBED) called");
169
170 *out_notification_event = &notification_event->GetReadableEvent();
171 R_SUCCEED();
172}
173
174} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_controller.h b/src/core/hle/service/audio/audio_controller.h
new file mode 100644
index 000000000..9e8514373
--- /dev/null
+++ b/src/core/hle/service/audio/audio_controller.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8#include "core/hle/service/set/settings_types.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::Set {
15class ISystemSettingsServer;
16}
17
18namespace Service::Audio {
19
20class IAudioController final : public ServiceFramework<IAudioController> {
21public:
22 explicit IAudioController(Core::System& system_);
23 ~IAudioController() override;
24
25private:
26 enum class ForceMutePolicy {
27 Disable,
28 SpeakerMuteOnHeadphoneUnplugged,
29 };
30
31 enum class HeadphoneOutputLevelMode {
32 Normal,
33 HighPower,
34 };
35
36 Result GetTargetVolumeMin(Out<s32> out_target_min_volume);
37 Result GetTargetVolumeMax(Out<s32> out_target_max_volume);
38 Result GetAudioOutputMode(Out<Set::AudioOutputMode> out_output_mode,
39 Set::AudioOutputModeTarget target);
40 Result SetAudioOutputMode(Set::AudioOutputModeTarget target, Set::AudioOutputMode output_mode);
41 Result GetForceMutePolicy(Out<ForceMutePolicy> out_mute_policy);
42 Result GetOutputModeSetting(Out<Set::AudioOutputMode> out_output_mode,
43 Set::AudioOutputModeTarget target);
44 Result SetOutputModeSetting(Set::AudioOutputModeTarget target,
45 Set::AudioOutputMode output_mode);
46 Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
47 Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
48 Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
49 Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
50 Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event);
51
52 KernelHelpers::ServiceContext service_context;
53
54 Kernel::KEvent* notification_event;
55 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
56};
57
58} // namespace Service::Audio
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 2dc23e674..d120dade8 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -3,141 +3,18 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "common/logging/log.h"
7#include "core/core.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/btm/btm.h" 6#include "core/hle/service/btm/btm.h"
10#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/btm/btm_debug.h"
11#include "core/hle/service/kernel_helpers.h" 8#include "core/hle/service/btm/btm_system.h"
9#include "core/hle/service/btm/btm_user.h"
12#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
13#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
14 12
15namespace Service::BTM { 13namespace Service::BTM {
16 14
17class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { 15class IBtm final : public ServiceFramework<IBtm> {
18public: 16public:
19 explicit IBtmUserCore(Core::System& system_) 17 explicit IBtm(Core::System& system_) : ServiceFramework{system_, "btm"} {
20 : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
24 {1, nullptr, "GetBleScanFilterParameter"},
25 {2, nullptr, "GetBleScanFilterParameter2"},
26 {3, nullptr, "StartBleScanForGeneral"},
27 {4, nullptr, "StopBleScanForGeneral"},
28 {5, nullptr, "GetBleScanResultsForGeneral"},
29 {6, nullptr, "StartBleScanForPaired"},
30 {7, nullptr, "StopBleScanForPaired"},
31 {8, nullptr, "StartBleScanForSmartDevice"},
32 {9, nullptr, "StopBleScanForSmartDevice"},
33 {10, nullptr, "GetBleScanResultsForSmartDevice"},
34 {17, &IBtmUserCore::AcquireBleConnectionEvent, "AcquireBleConnectionEvent"},
35 {18, nullptr, "BleConnect"},
36 {19, nullptr, "BleDisconnect"},
37 {20, nullptr, "BleGetConnectionState"},
38 {21, nullptr, "AcquireBlePairingEvent"},
39 {22, nullptr, "BlePairDevice"},
40 {23, nullptr, "BleUnPairDevice"},
41 {24, nullptr, "BleUnPairDevice2"},
42 {25, nullptr, "BleGetPairedDevices"},
43 {26, &IBtmUserCore::AcquireBleServiceDiscoveryEvent, "AcquireBleServiceDiscoveryEvent"},
44 {27, nullptr, "GetGattServices"},
45 {28, nullptr, "GetGattService"},
46 {29, nullptr, "GetGattIncludedServices"},
47 {30, nullptr, "GetBelongingGattService"},
48 {31, nullptr, "GetGattCharacteristics"},
49 {32, nullptr, "GetGattDescriptors"},
50 {33, &IBtmUserCore::AcquireBleMtuConfigEvent, "AcquireBleMtuConfigEvent"},
51 {34, nullptr, "ConfigureBleMtu"},
52 {35, nullptr, "GetBleMtu"},
53 {36, nullptr, "RegisterBleGattDataPath"},
54 {37, nullptr, "UnregisterBleGattDataPath"},
55 };
56 // clang-format on
57 RegisterHandlers(functions);
58
59 scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
60 connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
61 service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
62 config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
63 }
64
65 ~IBtmUserCore() override {
66 service_context.CloseEvent(scan_event);
67 service_context.CloseEvent(connection_event);
68 service_context.CloseEvent(service_discovery_event);
69 service_context.CloseEvent(config_event);
70 }
71
72private:
73 void AcquireBleScanEvent(HLERequestContext& ctx) {
74 LOG_WARNING(Service_BTM, "(STUBBED) called");
75
76 IPC::ResponseBuilder rb{ctx, 3, 1};
77 rb.Push(ResultSuccess);
78 rb.Push(true);
79 rb.PushCopyObjects(scan_event->GetReadableEvent());
80 }
81
82 void AcquireBleConnectionEvent(HLERequestContext& ctx) {
83 LOG_WARNING(Service_BTM, "(STUBBED) called");
84
85 IPC::ResponseBuilder rb{ctx, 3, 1};
86 rb.Push(ResultSuccess);
87 rb.Push(true);
88 rb.PushCopyObjects(connection_event->GetReadableEvent());
89 }
90
91 void AcquireBleServiceDiscoveryEvent(HLERequestContext& ctx) {
92 LOG_WARNING(Service_BTM, "(STUBBED) called");
93
94 IPC::ResponseBuilder rb{ctx, 3, 1};
95 rb.Push(ResultSuccess);
96 rb.Push(true);
97 rb.PushCopyObjects(service_discovery_event->GetReadableEvent());
98 }
99
100 void AcquireBleMtuConfigEvent(HLERequestContext& ctx) {
101 LOG_WARNING(Service_BTM, "(STUBBED) called");
102
103 IPC::ResponseBuilder rb{ctx, 3, 1};
104 rb.Push(ResultSuccess);
105 rb.Push(true);
106 rb.PushCopyObjects(config_event->GetReadableEvent());
107 }
108
109 KernelHelpers::ServiceContext service_context;
110
111 Kernel::KEvent* scan_event;
112 Kernel::KEvent* connection_event;
113 Kernel::KEvent* service_discovery_event;
114 Kernel::KEvent* config_event;
115};
116
117class BTM_USR final : public ServiceFramework<BTM_USR> {
118public:
119 explicit BTM_USR(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
120 // clang-format off
121 static const FunctionInfo functions[] = {
122 {0, &BTM_USR::GetCore, "GetCore"},
123 };
124 // clang-format on
125 RegisterHandlers(functions);
126 }
127
128private:
129 void GetCore(HLERequestContext& ctx) {
130 LOG_WARNING(Service_BTM, "called");
131
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(ResultSuccess);
134 rb.PushIpcInterface<IBtmUserCore>(system);
135 }
136};
137
138class BTM final : public ServiceFramework<BTM> {
139public:
140 explicit BTM(Core::System& system_) : ServiceFramework{system_, "btm"} {
141 // clang-format off 18 // clang-format off
142 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
143 {0, nullptr, "GetState"}, 20 {0, nullptr, "GetState"},
@@ -232,144 +109,13 @@ public:
232 } 109 }
233}; 110};
234 111
235class BTM_DBG final : public ServiceFramework<BTM_DBG> {
236public:
237 explicit BTM_DBG(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
238 // clang-format off
239 static const FunctionInfo functions[] = {
240 {0, nullptr, "AcquireDiscoveryEvent"},
241 {1, nullptr, "StartDiscovery"},
242 {2, nullptr, "CancelDiscovery"},
243 {3, nullptr, "GetDeviceProperty"},
244 {4, nullptr, "CreateBond"},
245 {5, nullptr, "CancelBond"},
246 {6, nullptr, "SetTsiMode"},
247 {7, nullptr, "GeneralTest"},
248 {8, nullptr, "HidConnect"},
249 {9, nullptr, "GeneralGet"},
250 {10, nullptr, "GetGattClientDisconnectionReason"},
251 {11, nullptr, "GetBleConnectionParameter"},
252 {12, nullptr, "GetBleConnectionParameterRequest"},
253 {13, nullptr, "Unknown13"},
254 };
255 // clang-format on
256
257 RegisterHandlers(functions);
258 }
259};
260
261class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
262public:
263 explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
264 // clang-format off
265 static const FunctionInfo functions[] = {
266 {0, &IBtmSystemCore::StartGamepadPairing, "StartGamepadPairing"},
267 {1, &IBtmSystemCore::CancelGamepadPairing, "CancelGamepadPairing"},
268 {2, nullptr, "ClearGamepadPairingDatabase"},
269 {3, nullptr, "GetPairedGamepadCount"},
270 {4, nullptr, "EnableRadio"},
271 {5, nullptr, "DisableRadio"},
272 {6, &IBtmSystemCore::IsRadioEnabled, "IsRadioEnabled"},
273 {7, nullptr, "AcquireRadioEvent"},
274 {8, nullptr, "AcquireGamepadPairingEvent"},
275 {9, nullptr, "IsGamepadPairingStarted"},
276 {10, nullptr, "StartAudioDeviceDiscovery"},
277 {11, nullptr, "StopAudioDeviceDiscovery"},
278 {12, nullptr, "IsDiscoveryingAudioDevice"},
279 {13, nullptr, "GetDiscoveredAudioDevice"},
280 {14, nullptr, "AcquireAudioDeviceConnectionEvent"},
281 {15, nullptr, "ConnectAudioDevice"},
282 {16, nullptr, "IsConnectingAudioDevice"},
283 {17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"},
284 {18, nullptr, "DisconnectAudioDevice"},
285 {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
286 {20, &IBtmSystemCore::GetPairedAudioDevices, "GetPairedAudioDevices"},
287 {21, nullptr, "RemoveAudioDevicePairing"},
288 {22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"},
289 {23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"}
290 };
291 // clang-format on
292
293 RegisterHandlers(functions);
294 }
295
296private:
297 void IsRadioEnabled(HLERequestContext& ctx) {
298 LOG_DEBUG(Service_BTM, "(STUBBED) called"); // Spams a lot when controller applet is running
299
300 IPC::ResponseBuilder rb{ctx, 3};
301 rb.Push(ResultSuccess);
302 rb.Push(true);
303 }
304
305 void StartGamepadPairing(HLERequestContext& ctx) {
306 LOG_WARNING(Service_BTM, "(STUBBED) called");
307 IPC::ResponseBuilder rb{ctx, 2};
308 rb.Push(ResultSuccess);
309 }
310
311 void CancelGamepadPairing(HLERequestContext& ctx) {
312 LOG_WARNING(Service_BTM, "(STUBBED) called");
313 IPC::ResponseBuilder rb{ctx, 2};
314 rb.Push(ResultSuccess);
315 }
316
317 void CancelAudioDeviceConnectionRejection(HLERequestContext& ctx) {
318 LOG_WARNING(Service_BTM, "(STUBBED) called");
319 IPC::ResponseBuilder rb{ctx, 2};
320 rb.Push(ResultSuccess);
321 }
322
323 void GetConnectedAudioDevices(HLERequestContext& ctx) {
324 LOG_WARNING(Service_BTM, "(STUBBED) called");
325 IPC::ResponseBuilder rb{ctx, 3};
326 rb.Push(ResultSuccess);
327 rb.Push<u32>(0);
328 }
329
330 void GetPairedAudioDevices(HLERequestContext& ctx) {
331 LOG_WARNING(Service_BTM, "(STUBBED) called");
332 IPC::ResponseBuilder rb{ctx, 3};
333 rb.Push(ResultSuccess);
334 rb.Push<u32>(0);
335 }
336
337 void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) {
338 LOG_WARNING(Service_BTM, "(STUBBED) called");
339 IPC::ResponseBuilder rb{ctx, 2};
340 rb.Push(ResultSuccess);
341 }
342};
343
344class BTM_SYS final : public ServiceFramework<BTM_SYS> {
345public:
346 explicit BTM_SYS(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
347 // clang-format off
348 static const FunctionInfo functions[] = {
349 {0, &BTM_SYS::GetCore, "GetCore"},
350 };
351 // clang-format on
352
353 RegisterHandlers(functions);
354 }
355
356private:
357 void GetCore(HLERequestContext& ctx) {
358 LOG_WARNING(Service_BTM, "called");
359
360 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
361 rb.Push(ResultSuccess);
362 rb.PushIpcInterface<IBtmSystemCore>(system);
363 }
364};
365
366void LoopProcess(Core::System& system) { 112void LoopProcess(Core::System& system) {
367 auto server_manager = std::make_unique<ServerManager>(system); 113 auto server_manager = std::make_unique<ServerManager>(system);
368 114
369 server_manager->RegisterNamedService("btm", std::make_shared<BTM>(system)); 115 server_manager->RegisterNamedService("btm", std::make_shared<IBtm>(system));
370 server_manager->RegisterNamedService("btm:dbg", std::make_shared<BTM_DBG>(system)); 116 server_manager->RegisterNamedService("btm:dbg", std::make_shared<IBtmDebug>(system));
371 server_manager->RegisterNamedService("btm:sys", std::make_shared<BTM_SYS>(system)); 117 server_manager->RegisterNamedService("btm:sys", std::make_shared<IBtmSystem>(system));
372 server_manager->RegisterNamedService("btm:u", std::make_shared<BTM_USR>(system)); 118 server_manager->RegisterNamedService("btm:u", std::make_shared<IBtmUser>(system));
373 ServerManager::RunServer(std::move(server_manager)); 119 ServerManager::RunServer(std::move(server_manager));
374} 120}
375 121
diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h
index a99b34364..0bf77d053 100644
--- a/src/core/hle/service/btm/btm.h
+++ b/src/core/hle/service/btm/btm.h
@@ -3,10 +3,6 @@
3 3
4#pragma once 4#pragma once
5 5
6namespace Service::SM {
7class ServiceManager;
8}
9
10namespace Core { 6namespace Core {
11class System; 7class System;
12}; 8};
diff --git a/src/core/hle/service/btm/btm_debug.cpp b/src/core/hle/service/btm/btm_debug.cpp
new file mode 100644
index 000000000..4d61d2641
--- /dev/null
+++ b/src/core/hle/service/btm/btm_debug.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/btm/btm_debug.h"
5
6namespace Service::BTM {
7
8IBtmDebug::IBtmDebug(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "AcquireDiscoveryEvent"},
12 {1, nullptr, "StartDiscovery"},
13 {2, nullptr, "CancelDiscovery"},
14 {3, nullptr, "GetDeviceProperty"},
15 {4, nullptr, "CreateBond"},
16 {5, nullptr, "CancelBond"},
17 {6, nullptr, "SetTsiMode"},
18 {7, nullptr, "GeneralTest"},
19 {8, nullptr, "HidConnect"},
20 {9, nullptr, "GeneralGet"},
21 {10, nullptr, "GetGattClientDisconnectionReason"},
22 {11, nullptr, "GetBleConnectionParameter"},
23 {12, nullptr, "GetBleConnectionParameterRequest"},
24 {13, nullptr, "Unknown13"},
25 };
26 // clang-format on
27
28 RegisterHandlers(functions);
29}
30
31IBtmDebug::~IBtmDebug() = default;
32
33} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_debug.h b/src/core/hle/service/btm/btm_debug.h
new file mode 100644
index 000000000..bf4f7e14f
--- /dev/null
+++ b/src/core/hle/service/btm/btm_debug.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14
15class IBtmDebug final : public ServiceFramework<IBtmDebug> {
16public:
17 explicit IBtmDebug(Core::System& system_);
18 ~IBtmDebug() override;
19};
20
21} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system.cpp b/src/core/hle/service/btm/btm_system.cpp
new file mode 100644
index 000000000..99718a7b0
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system.cpp
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_system.h"
6#include "core/hle/service/btm/btm_system_core.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/service.h"
9
10namespace Service::BTM {
11
12IBtmSystem::IBtmSystem(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, C<&IBtmSystem::GetCore>, "GetCore"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IBtmSystem::~IBtmSystem() = default;
23
24Result IBtmSystem::GetCore(OutInterface<IBtmSystemCore> out_interface) {
25 LOG_WARNING(Service_BTM, "called");
26
27 *out_interface = std::make_shared<IBtmSystemCore>(system);
28 R_SUCCEED();
29}
30
31} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system.h b/src/core/hle/service/btm/btm_system.h
new file mode 100644
index 000000000..fe1c6dbd7
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14class IBtmSystemCore;
15
16class IBtmSystem final : public ServiceFramework<IBtmSystem> {
17public:
18 explicit IBtmSystem(Core::System& system_);
19 ~IBtmSystem() override;
20
21private:
22 Result GetCore(OutInterface<IBtmSystemCore> out_interface);
23};
24
25} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system_core.cpp b/src/core/hle/service/btm/btm_system_core.cpp
new file mode 100644
index 000000000..4bc8a9e8b
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system_core.cpp
@@ -0,0 +1,127 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_system_core.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/set/system_settings_server.h"
8#include "core/hle/service/sm/sm.h"
9
10namespace Service::BTM {
11
12IBtmSystemCore::IBtmSystemCore(Core::System& system_)
13 : ServiceFramework{system_, "IBtmSystemCore"}, service_context{system_, "IBtmSystemCore"} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, C<&IBtmSystemCore::StartGamepadPairing>, "StartGamepadPairing"},
17 {1, C<&IBtmSystemCore::CancelGamepadPairing>, "CancelGamepadPairing"},
18 {2, nullptr, "ClearGamepadPairingDatabase"},
19 {3, nullptr, "GetPairedGamepadCount"},
20 {4, C<&IBtmSystemCore::EnableRadio>, "EnableRadio"},
21 {5, C<&IBtmSystemCore::DisableRadio>, "DisableRadio"},
22 {6, C<&IBtmSystemCore::IsRadioEnabled>, "IsRadioEnabled"},
23 {7, C<&IBtmSystemCore::AcquireRadioEvent>, "AcquireRadioEvent"},
24 {8, nullptr, "AcquireGamepadPairingEvent"},
25 {9, nullptr, "IsGamepadPairingStarted"},
26 {10, nullptr, "StartAudioDeviceDiscovery"},
27 {11, nullptr, "StopAudioDeviceDiscovery"},
28 {12, nullptr, "IsDiscoveryingAudioDevice"},
29 {13, nullptr, "GetDiscoveredAudioDevice"},
30 {14, C<&IBtmSystemCore::AcquireAudioDeviceConnectionEvent>, "AcquireAudioDeviceConnectionEvent"},
31 {15, nullptr, "ConnectAudioDevice"},
32 {16, nullptr, "IsConnectingAudioDevice"},
33 {17, C<&IBtmSystemCore::GetConnectedAudioDevices>, "GetConnectedAudioDevices"},
34 {18, nullptr, "DisconnectAudioDevice"},
35 {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
36 {20, C<&IBtmSystemCore::GetPairedAudioDevices>, "GetPairedAudioDevices"},
37 {21, nullptr, "RemoveAudioDevicePairing"},
38 {22, C<&IBtmSystemCore::RequestAudioDeviceConnectionRejection>, "RequestAudioDeviceConnectionRejection"},
39 {23, C<&IBtmSystemCore::CancelAudioDeviceConnectionRejection>, "CancelAudioDeviceConnectionRejection"}
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44 radio_event = service_context.CreateEvent("IBtmSystemCore::RadioEvent");
45 audio_device_connection_event =
46 service_context.CreateEvent("IBtmSystemCore::AudioDeviceConnectionEvent");
47
48 m_set_sys =
49 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
50}
51
52IBtmSystemCore::~IBtmSystemCore() {
53 service_context.CloseEvent(radio_event);
54 service_context.CloseEvent(audio_device_connection_event);
55}
56
57Result IBtmSystemCore::StartGamepadPairing() {
58 LOG_WARNING(Service_BTM, "(STUBBED) called");
59 R_SUCCEED();
60}
61
62Result IBtmSystemCore::CancelGamepadPairing() {
63 LOG_WARNING(Service_BTM, "(STUBBED) called");
64 R_SUCCEED();
65}
66
67Result IBtmSystemCore::EnableRadio() {
68 LOG_DEBUG(Service_BTM, "called");
69
70 R_RETURN(m_set_sys->SetBluetoothEnableFlag(true));
71}
72Result IBtmSystemCore::DisableRadio() {
73 LOG_DEBUG(Service_BTM, "called");
74
75 R_RETURN(m_set_sys->SetBluetoothEnableFlag(false));
76}
77
78Result IBtmSystemCore::IsRadioEnabled(Out<bool> out_is_enabled) {
79 LOG_DEBUG(Service_BTM, "called");
80
81 R_RETURN(m_set_sys->GetBluetoothEnableFlag(out_is_enabled));
82}
83
84Result IBtmSystemCore::AcquireRadioEvent(Out<bool> out_is_valid,
85 OutCopyHandle<Kernel::KReadableEvent> out_event) {
86 LOG_WARNING(Service_BTM, "(STUBBED) called");
87
88 *out_is_valid = true;
89 *out_event = &radio_event->GetReadableEvent();
90 R_SUCCEED();
91}
92
93Result IBtmSystemCore::AcquireAudioDeviceConnectionEvent(
94 OutCopyHandle<Kernel::KReadableEvent> out_event) {
95 LOG_WARNING(Service_BTM, "(STUBBED) called");
96
97 *out_event = &audio_device_connection_event->GetReadableEvent();
98 R_SUCCEED();
99}
100
101Result IBtmSystemCore::GetConnectedAudioDevices(
102 Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
103 LOG_WARNING(Service_BTM, "(STUBBED) called");
104
105 *out_count = 0;
106 R_SUCCEED();
107}
108
109Result IBtmSystemCore::GetPairedAudioDevices(
110 Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
111 LOG_WARNING(Service_BTM, "(STUBBED) called");
112
113 *out_count = 0;
114 R_SUCCEED();
115}
116
117Result IBtmSystemCore::RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
118 LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
119 R_SUCCEED();
120}
121
122Result IBtmSystemCore::CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
123 LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
124 R_SUCCEED();
125}
126
127} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system_core.h b/src/core/hle/service/btm/btm_system_core.h
new file mode 100644
index 000000000..06498b21e
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system_core.h
@@ -0,0 +1,60 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Kernel {
11class KEvent;
12class KReadableEvent;
13} // namespace Kernel
14
15namespace Core {
16class System;
17}
18
19namespace Service::Set {
20class ISystemSettingsServer;
21}
22
23namespace Service::BTM {
24
25class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
26public:
27 explicit IBtmSystemCore(Core::System& system_);
28 ~IBtmSystemCore() override;
29
30private:
31 Result StartGamepadPairing();
32 Result CancelGamepadPairing();
33 Result EnableRadio();
34 Result DisableRadio();
35 Result IsRadioEnabled(Out<bool> out_is_enabled);
36
37 Result AcquireRadioEvent(Out<bool> out_is_valid,
38 OutCopyHandle<Kernel::KReadableEvent> out_event);
39
40 Result AcquireAudioDeviceConnectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
41
42 Result GetConnectedAudioDevices(
43 Out<s32> out_count,
44 OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);
45
46 Result GetPairedAudioDevices(
47 Out<s32> out_count,
48 OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);
49
50 Result RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
51 Result CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
52
53 KernelHelpers::ServiceContext service_context;
54
55 Kernel::KEvent* radio_event;
56 Kernel::KEvent* audio_device_connection_event;
57 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
58};
59
60} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user.cpp b/src/core/hle/service/btm/btm_user.cpp
new file mode 100644
index 000000000..d2e228f8d
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user.cpp
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_user.h"
6#include "core/hle/service/btm/btm_user_core.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::BTM {
10
11IBtmUser::IBtmUser(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, C<&IBtmUser::GetCore>, "GetCore"},
15 };
16 // clang-format on
17
18 RegisterHandlers(functions);
19}
20
21IBtmUser::~IBtmUser() = default;
22
23Result IBtmUser::GetCore(OutInterface<IBtmUserCore> out_interface) {
24 LOG_WARNING(Service_BTM, "called");
25
26 *out_interface = std::make_shared<IBtmUserCore>(system);
27 R_SUCCEED();
28}
29
30} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user.h b/src/core/hle/service/btm/btm_user.h
new file mode 100644
index 000000000..d9ee5db45
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14class IBtmUserCore;
15
16class IBtmUser final : public ServiceFramework<IBtmUser> {
17public:
18 explicit IBtmUser(Core::System& system_);
19 ~IBtmUser() override;
20
21private:
22 Result GetCore(OutInterface<IBtmUserCore> out_interface);
23};
24
25} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user_core.cpp b/src/core/hle/service/btm/btm_user_core.cpp
new file mode 100644
index 000000000..6f9fa589b
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user_core.cpp
@@ -0,0 +1,103 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <memory>
5
6#include "common/logging/log.h"
7#include "core/core.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/btm/btm_user_core.h"
10#include "core/hle/service/cmif_serialization.h"
11
12namespace Service::BTM {
13
14IBtmUserCore::IBtmUserCore(Core::System& system_)
15 : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, C<&IBtmUserCore::AcquireBleScanEvent>, "AcquireBleScanEvent"},
19 {1, nullptr, "GetBleScanFilterParameter"},
20 {2, nullptr, "GetBleScanFilterParameter2"},
21 {3, nullptr, "StartBleScanForGeneral"},
22 {4, nullptr, "StopBleScanForGeneral"},
23 {5, nullptr, "GetBleScanResultsForGeneral"},
24 {6, nullptr, "StartBleScanForPaired"},
25 {7, nullptr, "StopBleScanForPaired"},
26 {8, nullptr, "StartBleScanForSmartDevice"},
27 {9, nullptr, "StopBleScanForSmartDevice"},
28 {10, nullptr, "GetBleScanResultsForSmartDevice"},
29 {17, C<&IBtmUserCore::AcquireBleConnectionEvent>, "AcquireBleConnectionEvent"},
30 {18, nullptr, "BleConnect"},
31 {19, nullptr, "BleDisconnect"},
32 {20, nullptr, "BleGetConnectionState"},
33 {21, nullptr, "AcquireBlePairingEvent"},
34 {22, nullptr, "BlePairDevice"},
35 {23, nullptr, "BleUnPairDevice"},
36 {24, nullptr, "BleUnPairDevice2"},
37 {25, nullptr, "BleGetPairedDevices"},
38 {26, C<&IBtmUserCore::AcquireBleServiceDiscoveryEvent>, "AcquireBleServiceDiscoveryEvent"},
39 {27, nullptr, "GetGattServices"},
40 {28, nullptr, "GetGattService"},
41 {29, nullptr, "GetGattIncludedServices"},
42 {30, nullptr, "GetBelongingGattService"},
43 {31, nullptr, "GetGattCharacteristics"},
44 {32, nullptr, "GetGattDescriptors"},
45 {33, C<&IBtmUserCore::AcquireBleMtuConfigEvent>, "AcquireBleMtuConfigEvent"},
46 {34, nullptr, "ConfigureBleMtu"},
47 {35, nullptr, "GetBleMtu"},
48 {36, nullptr, "RegisterBleGattDataPath"},
49 {37, nullptr, "UnregisterBleGattDataPath"},
50 };
51 // clang-format on
52 RegisterHandlers(functions);
53
54 scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
55 connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
56 service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
57 config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
58}
59
60IBtmUserCore::~IBtmUserCore() {
61 service_context.CloseEvent(scan_event);
62 service_context.CloseEvent(connection_event);
63 service_context.CloseEvent(service_discovery_event);
64 service_context.CloseEvent(config_event);
65}
66
67Result IBtmUserCore::AcquireBleScanEvent(Out<bool> out_is_valid,
68 OutCopyHandle<Kernel::KReadableEvent> out_event) {
69 LOG_WARNING(Service_BTM, "(STUBBED) called");
70
71 *out_is_valid = true;
72 *out_event = &scan_event->GetReadableEvent();
73 R_SUCCEED();
74}
75
76Result IBtmUserCore::AcquireBleConnectionEvent(Out<bool> out_is_valid,
77 OutCopyHandle<Kernel::KReadableEvent> out_event) {
78 LOG_WARNING(Service_BTM, "(STUBBED) called");
79
80 *out_is_valid = true;
81 *out_event = &connection_event->GetReadableEvent();
82 R_SUCCEED();
83}
84
85Result IBtmUserCore::AcquireBleServiceDiscoveryEvent(
86 Out<bool> out_is_valid, OutCopyHandle<Kernel::KReadableEvent> out_event) {
87 LOG_WARNING(Service_BTM, "(STUBBED) called");
88
89 *out_is_valid = true;
90 *out_event = &service_discovery_event->GetReadableEvent();
91 R_SUCCEED();
92}
93
94Result IBtmUserCore::AcquireBleMtuConfigEvent(Out<bool> out_is_valid,
95 OutCopyHandle<Kernel::KReadableEvent> out_event) {
96 LOG_WARNING(Service_BTM, "(STUBBED) called");
97
98 *out_is_valid = true;
99 *out_event = &config_event->GetReadableEvent();
100 R_SUCCEED();
101}
102
103} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user_core.h b/src/core/hle/service/btm/btm_user_core.h
new file mode 100644
index 000000000..dc0a22e81
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user_core.h
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Kernel {
11class KEvent;
12class KReadableEvent;
13} // namespace Kernel
14
15namespace Core {
16class System;
17}
18
19namespace Service::BTM {
20
21class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
22public:
23 explicit IBtmUserCore(Core::System& system_);
24 ~IBtmUserCore() override;
25
26private:
27 Result AcquireBleScanEvent(Out<bool> out_is_valid,
28 OutCopyHandle<Kernel::KReadableEvent> out_event);
29
30 Result AcquireBleConnectionEvent(Out<bool> out_is_valid,
31 OutCopyHandle<Kernel::KReadableEvent> out_event);
32
33 Result AcquireBleServiceDiscoveryEvent(Out<bool> out_is_valid,
34 OutCopyHandle<Kernel::KReadableEvent> out_event);
35
36 Result AcquireBleMtuConfigEvent(Out<bool> out_is_valid,
37 OutCopyHandle<Kernel::KReadableEvent> out_event);
38
39 KernelHelpers::ServiceContext service_context;
40
41 Kernel::KEvent* scan_event;
42 Kernel::KEvent* connection_event;
43 Kernel::KEvent* service_discovery_event;
44 Kernel::KEvent* config_event;
45};
46
47} // namespace Service::BTM
diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp
index ec9b0efb1..b801faef2 100644
--- a/src/core/hle/service/glue/time/static.cpp
+++ b/src/core/hle/service/glue/time/static.cpp
@@ -142,16 +142,18 @@ Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
142} 142}
143 143
144Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) { 144Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
145 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); 145 SCOPE_EXIT {
146 LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value);
147 };
146 148
147 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value)); 149 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value));
148} 150}
149 151
150Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( 152Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
151 Out<bool> out_automatic_correction) { 153 Out<bool> out_automatic_correction) {
152 SCOPE_EXIT({ 154 SCOPE_EXIT {
153 LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction); 155 LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction);
154 }); 156 };
155 157
156 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( 158 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled(
157 out_automatic_correction)); 159 out_automatic_correction));
@@ -166,21 +168,27 @@ Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
166} 168}
167 169
168Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) { 170Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
169 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_year={}", *out_year); }); 171 SCOPE_EXIT {
172 LOG_DEBUG(Service_Time, "called. out_year={}", *out_year);
173 };
170 174
171 R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time", 175 R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time",
172 "standard_user_clock_initial_year")); 176 "standard_user_clock_initial_year"));
173} 177}
174 178
175Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { 179Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
176 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); 180 SCOPE_EXIT {
181 LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
182 };
177 183
178 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); 184 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient));
179} 185}
180 186
181Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 187Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
182 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { 188 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
183 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 189 SCOPE_EXIT {
190 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
191 };
184 192
185 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 193 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
186 out_time_point)); 194 out_time_point));
@@ -188,15 +196,18 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
188 196
189Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( 197Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
190 Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) { 198 Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) {
191 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); 199 SCOPE_EXIT {
200 LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
201 };
192 202
193 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); 203 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
194} 204}
195 205
196Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, 206Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot,
197 Service::PSC::Time::TimeType type) { 207 Service::PSC::Time::TimeType type) {
198 SCOPE_EXIT( 208 SCOPE_EXIT {
199 { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); 209 LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
210 };
200 211
201 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); 212 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type));
202} 213}
@@ -205,11 +216,11 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
205 Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot, 216 Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
206 const Service::PSC::Time::SystemClockContext& user_context, 217 const Service::PSC::Time::SystemClockContext& user_context,
207 const Service::PSC::Time::SystemClockContext& network_context) { 218 const Service::PSC::Time::SystemClockContext& network_context) {
208 SCOPE_EXIT({ 219 SCOPE_EXIT {
209 LOG_DEBUG(Service_Time, 220 LOG_DEBUG(Service_Time,
210 "called. type={} out_snapshot={} user_context={} network_context={}", type, 221 "called. type={} out_snapshot={} user_context={} network_context={}", type,
211 *out_snapshot, user_context, network_context); 222 *out_snapshot, user_context, network_context);
212 }); 223 };
213 224
214 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext( 225 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(
215 type, out_snapshot, user_context, network_context)); 226 type, out_snapshot, user_context, network_context));
@@ -218,14 +229,18 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
218Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time, 229Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time,
219 InClockSnapshot a, 230 InClockSnapshot a,
220 InClockSnapshot b) { 231 InClockSnapshot b) {
221 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 232 SCOPE_EXIT {
233 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
234 };
222 235
223 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); 236 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b));
224} 237}
225 238
226Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, 239Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
227 InClockSnapshot b) { 240 InClockSnapshot b) {
228 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 241 SCOPE_EXIT {
242 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
243 };
229 244
230 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); 245 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
231} 246}
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp
index 36f163419..f4d0c87d5 100644
--- a/src/core/hle/service/glue/time/time_zone.cpp
+++ b/src/core/hle/service/glue/time/time_zone.cpp
@@ -57,7 +57,9 @@ TimeZoneService::~TimeZoneService() = default;
57 57
58Result TimeZoneService::GetDeviceLocationName( 58Result TimeZoneService::GetDeviceLocationName(
59 Out<Service::PSC::Time::LocationName> out_location_name) { 59 Out<Service::PSC::Time::LocationName> out_location_name) {
60 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); }); 60 SCOPE_EXIT {
61 LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name);
62 };
61 63
62 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); 64 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
63} 65}
@@ -94,7 +96,9 @@ Result TimeZoneService::SetDeviceLocationName(
94} 96}
95 97
96Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { 98Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
97 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); }); 99 SCOPE_EXIT {
100 LOG_DEBUG(Service_Time, "called. out_count={}", *out_count);
101 };
98 102
99 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); 103 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count));
100} 104}
@@ -102,10 +106,10 @@ Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
102Result TimeZoneService::LoadLocationNameList( 106Result TimeZoneService::LoadLocationNameList(
103 Out<u32> out_count, 107 Out<u32> out_count,
104 OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) { 108 OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) {
105 SCOPE_EXIT({ 109 SCOPE_EXIT {
106 LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}", 110 LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}",
107 index, *out_count, out_names[0], out_names[1]); 111 index, *out_count, out_names[0], out_names[1]);
108 }); 112 };
109 113
110 std::scoped_lock l{m_mutex}; 114 std::scoped_lock l{m_mutex};
111 R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index)); 115 R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index));
@@ -124,7 +128,9 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule,
124 128
125Result TimeZoneService::GetTimeZoneRuleVersion( 129Result TimeZoneService::GetTimeZoneRuleVersion(
126 Out<Service::PSC::Time::RuleVersion> out_rule_version) { 130 Out<Service::PSC::Time::RuleVersion> out_rule_version) {
127 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); }); 131 SCOPE_EXIT {
132 LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version);
133 };
128 134
129 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); 135 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version));
130} 136}
@@ -132,10 +138,10 @@ Result TimeZoneService::GetTimeZoneRuleVersion(
132Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( 138Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
133 Out<Service::PSC::Time::LocationName> location_name, 139 Out<Service::PSC::Time::LocationName> location_name,
134 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { 140 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
135 SCOPE_EXIT({ 141 SCOPE_EXIT {
136 LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name, 142 LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name,
137 *out_time_point); 143 *out_time_point);
138 }); 144 };
139 145
140 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point)); 146 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point));
141} 147}
@@ -178,10 +184,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
178Result TimeZoneService::ToCalendarTime( 184Result TimeZoneService::ToCalendarTime(
179 Out<Service::PSC::Time::CalendarTime> out_calendar_time, 185 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
180 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) { 186 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) {
181 SCOPE_EXIT({ 187 SCOPE_EXIT {
182 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 188 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
183 *out_calendar_time, *out_additional_info); 189 *out_calendar_time, *out_additional_info);
184 }); 190 };
185 191
186 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); 192 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
187} 193}
@@ -189,10 +195,10 @@ Result TimeZoneService::ToCalendarTime(
189Result TimeZoneService::ToCalendarTimeWithMyRule( 195Result TimeZoneService::ToCalendarTimeWithMyRule(
190 Out<Service::PSC::Time::CalendarTime> out_calendar_time, 196 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
191 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) { 197 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) {
192 SCOPE_EXIT({ 198 SCOPE_EXIT {
193 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 199 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
194 *out_calendar_time, *out_additional_info); 200 *out_calendar_time, *out_additional_info);
195 }); 201 };
196 202
197 R_RETURN( 203 R_RETURN(
198 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); 204 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
@@ -202,11 +208,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
202 OutArray<s64, BufferAttr_HipcPointer> out_times, 208 OutArray<s64, BufferAttr_HipcPointer> out_times,
203 const Service::PSC::Time::CalendarTime& calendar_time, 209 const Service::PSC::Time::CalendarTime& calendar_time,
204 InRule rule) { 210 InRule rule) {
205 SCOPE_EXIT({ 211 SCOPE_EXIT {
206 LOG_DEBUG(Service_Time, 212 LOG_DEBUG(Service_Time,
207 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", 213 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
208 calendar_time, *out_count, out_times[0], out_times[1]); 214 calendar_time, *out_count, out_times[0], out_times[1]);
209 }); 215 };
210 216
211 R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule)); 217 R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule));
212} 218}
@@ -214,11 +220,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
214Result TimeZoneService::ToPosixTimeWithMyRule( 220Result TimeZoneService::ToPosixTimeWithMyRule(
215 Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, 221 Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
216 const Service::PSC::Time::CalendarTime& calendar_time) { 222 const Service::PSC::Time::CalendarTime& calendar_time) {
217 SCOPE_EXIT({ 223 SCOPE_EXIT {
218 LOG_DEBUG(Service_Time, 224 LOG_DEBUG(Service_Time,
219 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", 225 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
220 calendar_time, *out_count, out_times[0], out_times[1]); 226 calendar_time, *out_count, out_times[0], out_times[1]);
221 }); 227 };
222 228
223 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time)); 229 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time));
224} 230}
diff --git a/src/core/hle/service/ns/account_proxy_interface.cpp b/src/core/hle/service/ns/account_proxy_interface.cpp
new file mode 100644
index 000000000..e5041af66
--- /dev/null
+++ b/src/core/hle/service/ns/account_proxy_interface.cpp
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/ns/account_proxy_interface.h"
5
6namespace Service::NS {
7
8IAccountProxyInterface::IAccountProxyInterface(Core::System& system_)
9 : ServiceFramework{system_, "IAccountProxyInterface"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "CreateUserAccount"},
13 };
14 // clang-format on
15
16 RegisterHandlers(functions);
17}
18
19IAccountProxyInterface::~IAccountProxyInterface() = default;
20
21} // namespace Service::NS
diff --git a/src/core/hle/service/ns/account_proxy_interface.h b/src/core/hle/service/ns/account_proxy_interface.h
new file mode 100644
index 000000000..e944d2a75
--- /dev/null
+++ b/src/core/hle/service/ns/account_proxy_interface.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::NS {
9
10class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
11public:
12 explicit IAccountProxyInterface(Core::System& system_);
13 ~IAccountProxyInterface() override;
14};
15
16} // namespace Service::NS
diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp
new file mode 100644
index 000000000..7a91727f9
--- /dev/null
+++ b/src/core/hle/service/ns/application_manager_interface.cpp
@@ -0,0 +1,519 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/file_sys/nca_metadata.h"
5#include "core/file_sys/registered_cache.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/ns/application_manager_interface.h"
9#include "core/hle/service/ns/content_management_interface.h"
10#include "core/hle/service/ns/read_only_application_control_data_interface.h"
11
12namespace Service::NS {
13
14IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_)
15 : ServiceFramework{system_, "IApplicationManagerInterface"},
16 service_context{system, "IApplicationManagerInterface"},
17 record_update_system_event{service_context}, sd_card_mount_status_event{service_context},
18 gamecard_update_detection_event{service_context},
19 gamecard_mount_status_event{service_context}, gamecard_mount_failure_event{service_context} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, D<&IApplicationManagerInterface::ListApplicationRecord>, "ListApplicationRecord"},
23 {1, nullptr, "GenerateApplicationRecordCount"},
24 {2, D<&IApplicationManagerInterface::GetApplicationRecordUpdateSystemEvent>, "GetApplicationRecordUpdateSystemEvent"},
25 {3, nullptr, "GetApplicationViewDeprecated"},
26 {4, nullptr, "DeleteApplicationEntity"},
27 {5, nullptr, "DeleteApplicationCompletely"},
28 {6, nullptr, "IsAnyApplicationEntityRedundant"},
29 {7, nullptr, "DeleteRedundantApplicationEntity"},
30 {8, nullptr, "IsApplicationEntityMovable"},
31 {9, nullptr, "MoveApplicationEntity"},
32 {11, nullptr, "CalculateApplicationOccupiedSize"},
33 {16, nullptr, "PushApplicationRecord"},
34 {17, nullptr, "ListApplicationRecordContentMeta"},
35 {19, nullptr, "LaunchApplicationOld"},
36 {21, nullptr, "GetApplicationContentPath"},
37 {22, nullptr, "TerminateApplication"},
38 {23, nullptr, "ResolveApplicationContentPath"},
39 {26, nullptr, "BeginInstallApplication"},
40 {27, nullptr, "DeleteApplicationRecord"},
41 {30, nullptr, "RequestApplicationUpdateInfo"},
42 {31, nullptr, "Unknown31"},
43 {32, nullptr, "CancelApplicationDownload"},
44 {33, nullptr, "ResumeApplicationDownload"},
45 {35, nullptr, "UpdateVersionList"},
46 {36, nullptr, "PushLaunchVersion"},
47 {37, nullptr, "ListRequiredVersion"},
48 {38, D<&IApplicationManagerInterface::CheckApplicationLaunchVersion>, "CheckApplicationLaunchVersion"},
49 {39, nullptr, "CheckApplicationLaunchRights"},
50 {40, nullptr, "GetApplicationLogoData"},
51 {41, nullptr, "CalculateApplicationDownloadRequiredSize"},
52 {42, nullptr, "CleanupSdCard"},
53 {43, D<&IApplicationManagerInterface::CheckSdCardMountStatus>, "CheckSdCardMountStatus"},
54 {44, D<&IApplicationManagerInterface::GetSdCardMountStatusChangedEvent>, "GetSdCardMountStatusChangedEvent"},
55 {45, nullptr, "GetGameCardAttachmentEvent"},
56 {46, nullptr, "GetGameCardAttachmentInfo"},
57 {47, nullptr, "GetTotalSpaceSize"},
58 {48, D<&IApplicationManagerInterface::GetFreeSpaceSize>, "GetFreeSpaceSize"},
59 {49, nullptr, "GetSdCardRemovedEvent"},
60 {52, D<&IApplicationManagerInterface::GetGameCardUpdateDetectionEvent>, "GetGameCardUpdateDetectionEvent"},
61 {53, nullptr, "DisableApplicationAutoDelete"},
62 {54, nullptr, "EnableApplicationAutoDelete"},
63 {55, D<&IApplicationManagerInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"},
64 {56, nullptr, "SetApplicationTerminateResult"},
65 {57, nullptr, "ClearApplicationTerminateResult"},
66 {58, nullptr, "GetLastSdCardMountUnexpectedResult"},
67 {59, D<&IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"},
68 {60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
69 {61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
70 {62, nullptr, "GetGameCardStopper"},
71 {63, nullptr, "IsSystemProgramInstalled"},
72 {64, nullptr, "StartApplyDeltaTask"},
73 {65, nullptr, "GetRequestServerStopper"},
74 {66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
75 {67, nullptr, "CancelApplicationApplyDelta"},
76 {68, nullptr, "ResumeApplicationApplyDelta"},
77 {69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
78 {70, D<&IApplicationManagerInterface::ResumeAll>, "ResumeAll"},
79 {71, D<&IApplicationManagerInterface::GetStorageSize>, "GetStorageSize"},
80 {80, nullptr, "RequestDownloadApplication"},
81 {81, nullptr, "RequestDownloadAddOnContent"},
82 {82, nullptr, "DownloadApplication"},
83 {83, nullptr, "CheckApplicationResumeRights"},
84 {84, nullptr, "GetDynamicCommitEvent"},
85 {85, nullptr, "RequestUpdateApplication2"},
86 {86, nullptr, "EnableApplicationCrashReport"},
87 {87, nullptr, "IsApplicationCrashReportEnabled"},
88 {90, nullptr, "BoostSystemMemoryResourceLimit"},
89 {91, nullptr, "DeprecatedLaunchApplication"},
90 {92, nullptr, "GetRunningApplicationProgramId"},
91 {93, nullptr, "GetMainApplicationProgramIndex"},
92 {94, nullptr, "LaunchApplication"},
93 {95, nullptr, "GetApplicationLaunchInfo"},
94 {96, nullptr, "AcquireApplicationLaunchInfo"},
95 {97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"},
96 {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
97 {99, nullptr, "LaunchDevMenu"},
98 {100, nullptr, "ResetToFactorySettings"},
99 {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
100 {102, nullptr, "ResetToFactorySettingsForRefurbishment"},
101 {103, nullptr, "ResetToFactorySettingsWithPlatformRegion"},
102 {104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"},
103 {105, nullptr, "RequestResetToFactorySettingsSecurely"},
104 {106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"},
105 {200, nullptr, "CalculateUserSaveDataStatistics"},
106 {201, nullptr, "DeleteUserSaveDataAll"},
107 {210, nullptr, "DeleteUserSystemSaveData"},
108 {211, nullptr, "DeleteSaveData"},
109 {220, nullptr, "UnregisterNetworkServiceAccount"},
110 {221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"},
111 {300, nullptr, "GetApplicationShellEvent"},
112 {301, nullptr, "PopApplicationShellEventInfo"},
113 {302, nullptr, "LaunchLibraryApplet"},
114 {303, nullptr, "TerminateLibraryApplet"},
115 {304, nullptr, "LaunchSystemApplet"},
116 {305, nullptr, "TerminateSystemApplet"},
117 {306, nullptr, "LaunchOverlayApplet"},
118 {307, nullptr, "TerminateOverlayApplet"},
119 {400, D<&IApplicationManagerInterface::GetApplicationControlData>, "GetApplicationControlData"},
120 {401, nullptr, "InvalidateAllApplicationControlCache"},
121 {402, nullptr, "RequestDownloadApplicationControlData"},
122 {403, nullptr, "GetMaxApplicationControlCacheCount"},
123 {404, nullptr, "InvalidateApplicationControlCache"},
124 {405, nullptr, "ListApplicationControlCacheEntryInfo"},
125 {406, nullptr, "GetApplicationControlProperty"},
126 {407, nullptr, "ListApplicationTitle"},
127 {408, nullptr, "ListApplicationIcon"},
128 {502, nullptr, "RequestCheckGameCardRegistration"},
129 {503, nullptr, "RequestGameCardRegistrationGoldPoint"},
130 {504, nullptr, "RequestRegisterGameCard"},
131 {505, D<&IApplicationManagerInterface::GetGameCardMountFailureEvent>, "GetGameCardMountFailureEvent"},
132 {506, nullptr, "IsGameCardInserted"},
133 {507, nullptr, "EnsureGameCardAccess"},
134 {508, nullptr, "GetLastGameCardMountFailureResult"},
135 {509, nullptr, "ListApplicationIdOnGameCard"},
136 {510, nullptr, "GetGameCardPlatformRegion"},
137 {600, nullptr, "CountApplicationContentMeta"},
138 {601, nullptr, "ListApplicationContentMetaStatus"},
139 {602, nullptr, "ListAvailableAddOnContent"},
140 {603, nullptr, "GetOwnedApplicationContentMetaStatus"},
141 {604, nullptr, "RegisterContentsExternalKey"},
142 {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
143 {606, nullptr, "GetContentMetaStorage"},
144 {607, nullptr, "ListAvailableAddOnContent"},
145 {609, nullptr, "ListAvailabilityAssuredAddOnContent"},
146 {610, nullptr, "GetInstalledContentMetaStorage"},
147 {611, nullptr, "PrepareAddOnContent"},
148 {700, nullptr, "PushDownloadTaskList"},
149 {701, nullptr, "ClearTaskStatusList"},
150 {702, nullptr, "RequestDownloadTaskList"},
151 {703, nullptr, "RequestEnsureDownloadTask"},
152 {704, nullptr, "ListDownloadTaskStatus"},
153 {705, nullptr, "RequestDownloadTaskListData"},
154 {800, nullptr, "RequestVersionList"},
155 {801, nullptr, "ListVersionList"},
156 {802, nullptr, "RequestVersionListData"},
157 {900, nullptr, "GetApplicationRecord"},
158 {901, nullptr, "GetApplicationRecordProperty"},
159 {902, nullptr, "EnableApplicationAutoUpdate"},
160 {903, nullptr, "DisableApplicationAutoUpdate"},
161 {904, nullptr, "TouchApplication"},
162 {905, nullptr, "RequestApplicationUpdate"},
163 {906, D<&IApplicationManagerInterface::IsApplicationUpdateRequested>, "IsApplicationUpdateRequested"},
164 {907, nullptr, "WithdrawApplicationUpdateRequest"},
165 {908, nullptr, "ListApplicationRecordInstalledContentMeta"},
166 {909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
167 {910, nullptr, "HasApplicationRecord"},
168 {911, nullptr, "SetPreInstalledApplication"},
169 {912, nullptr, "ClearPreInstalledApplicationFlag"},
170 {913, nullptr, "ListAllApplicationRecord"},
171 {914, nullptr, "HideApplicationRecord"},
172 {915, nullptr, "ShowApplicationRecord"},
173 {916, nullptr, "IsApplicationAutoDeleteDisabled"},
174 {1000, nullptr, "RequestVerifyApplicationDeprecated"},
175 {1001, nullptr, "CorruptApplicationForDebug"},
176 {1002, nullptr, "RequestVerifyAddOnContentsRights"},
177 {1003, nullptr, "RequestVerifyApplication"},
178 {1004, nullptr, "CorruptContentForDebug"},
179 {1200, nullptr, "NeedsUpdateVulnerability"},
180 {1300, D<&IApplicationManagerInterface::IsAnyApplicationEntityInstalled>, "IsAnyApplicationEntityInstalled"},
181 {1301, nullptr, "DeleteApplicationContentEntities"},
182 {1302, nullptr, "CleanupUnrecordedApplicationEntity"},
183 {1303, nullptr, "CleanupAddOnContentsWithNoRights"},
184 {1304, nullptr, "DeleteApplicationContentEntity"},
185 {1305, nullptr, "TryDeleteRunningApplicationEntity"},
186 {1306, nullptr, "TryDeleteRunningApplicationCompletely"},
187 {1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
188 {1308, nullptr, "DeleteApplicationCompletelyForDebug"},
189 {1309, nullptr, "CleanupUnavailableAddOnContents"},
190 {1310, nullptr, "RequestMoveApplicationEntity"},
191 {1311, nullptr, "EstimateSizeToMove"},
192 {1312, nullptr, "HasMovableEntity"},
193 {1313, nullptr, "CleanupOrphanContents"},
194 {1314, nullptr, "CheckPreconditionSatisfiedToMove"},
195 {1400, nullptr, "PrepareShutdown"},
196 {1500, nullptr, "FormatSdCard"},
197 {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
198 {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
199 {1504, nullptr, "InsertSdCard"},
200 {1505, nullptr, "RemoveSdCard"},
201 {1506, nullptr, "GetSdCardStartupStatus"},
202 {1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
203 {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
204 {1700, nullptr, "ListApplicationDownloadingContentMeta"},
205 {1701, D<&IApplicationManagerInterface::GetApplicationView>, "GetApplicationView"},
206 {1702, nullptr, "GetApplicationDownloadTaskStatus"},
207 {1703, nullptr, "GetApplicationViewDownloadErrorContext"},
208 {1704, D<&IApplicationManagerInterface::GetApplicationViewWithPromotionInfo>, "GetApplicationViewWithPromotionInfo"},
209 {1705, nullptr, "IsPatchAutoDeletableApplication"},
210 {1800, nullptr, "IsNotificationSetupCompleted"},
211 {1801, nullptr, "GetLastNotificationInfoCount"},
212 {1802, nullptr, "ListLastNotificationInfo"},
213 {1803, nullptr, "ListNotificationTask"},
214 {1900, nullptr, "IsActiveAccount"},
215 {1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
216 {1902, nullptr, "GetApplicationTicketInfo"},
217 {1903, nullptr, "RequestDownloadApplicationPrepurchasedRightsForAccount"},
218 {2000, nullptr, "GetSystemDeliveryInfo"},
219 {2001, nullptr, "SelectLatestSystemDeliveryInfo"},
220 {2002, nullptr, "VerifyDeliveryProtocolVersion"},
221 {2003, nullptr, "GetApplicationDeliveryInfo"},
222 {2004, nullptr, "HasAllContentsToDeliver"},
223 {2005, nullptr, "CompareApplicationDeliveryInfo"},
224 {2006, nullptr, "CanDeliverApplication"},
225 {2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
226 {2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
227 {2009, nullptr, "EstimateRequiredSize"},
228 {2010, nullptr, "RequestReceiveApplication"},
229 {2011, nullptr, "CommitReceiveApplication"},
230 {2012, nullptr, "GetReceiveApplicationProgress"},
231 {2013, nullptr, "RequestSendApplication"},
232 {2014, nullptr, "GetSendApplicationProgress"},
233 {2015, nullptr, "CompareSystemDeliveryInfo"},
234 {2016, nullptr, "ListNotCommittedContentMeta"},
235 {2017, nullptr, "CreateDownloadTask"},
236 {2018, nullptr, "GetApplicationDeliveryInfoHash"},
237 {2050, D<&IApplicationManagerInterface::GetApplicationRightsOnClient>, "GetApplicationRightsOnClient"},
238 {2051, nullptr, "InvalidateRightsIdCache"},
239 {2100, D<&IApplicationManagerInterface::GetApplicationTerminateResult>, "GetApplicationTerminateResult"},
240 {2101, nullptr, "GetRawApplicationTerminateResult"},
241 {2150, nullptr, "CreateRightsEnvironment"},
242 {2151, nullptr, "DestroyRightsEnvironment"},
243 {2152, nullptr, "ActivateRightsEnvironment"},
244 {2153, nullptr, "DeactivateRightsEnvironment"},
245 {2154, nullptr, "ForceActivateRightsContextForExit"},
246 {2155, nullptr, "UpdateRightsEnvironmentStatus"},
247 {2156, nullptr, "CreateRightsEnvironmentForMicroApplication"},
248 {2160, nullptr, "AddTargetApplicationToRightsEnvironment"},
249 {2161, nullptr, "SetUsersToRightsEnvironment"},
250 {2170, nullptr, "GetRightsEnvironmentStatus"},
251 {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
252 {2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
253 {2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"},
254 {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
255 {2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
256 {2199, nullptr, "GetRightsEnvironmentCountForDebug"},
257 {2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
258 {2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
259 {2250, nullptr, "RequestReportActiveELicence"},
260 {2300, nullptr, "ListEventLog"},
261 {2350, nullptr, "PerformAutoUpdateByApplicationId"},
262 {2351, nullptr, "RequestNoDownloadRightsErrorResolution"},
263 {2352, nullptr, "RequestResolveNoDownloadRightsError"},
264 {2353, nullptr, "GetApplicationDownloadTaskInfo"},
265 {2354, nullptr, "PrioritizeApplicationBackgroundTask"},
266 {2355, nullptr, "PreferStorageEfficientUpdate"},
267 {2356, nullptr, "RequestStorageEfficientUpdatePreferable"},
268 {2357, nullptr, "EnableMultiCoreDownload"},
269 {2358, nullptr, "DisableMultiCoreDownload"},
270 {2359, nullptr, "IsMultiCoreDownloadEnabled"},
271 {2400, nullptr, "GetPromotionInfo"},
272 {2401, nullptr, "CountPromotionInfo"},
273 {2402, nullptr, "ListPromotionInfo"},
274 {2403, nullptr, "ImportPromotionJsonForDebug"},
275 {2404, nullptr, "ClearPromotionInfoForDebug"},
276 {2500, nullptr, "ConfirmAvailableTime"},
277 {2510, nullptr, "CreateApplicationResource"},
278 {2511, nullptr, "GetApplicationResource"},
279 {2513, nullptr, "LaunchMicroApplication"},
280 {2514, nullptr, "ClearTaskOfAsyncTaskManager"},
281 {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"},
282 {2516, nullptr, "EnsureApplicationCertificate"},
283 {2517, nullptr, "CreateApplicationInstance"},
284 {2518, nullptr, "UpdateQualificationForDebug"},
285 {2519, nullptr, "IsQualificationTransitionSupported"},
286 {2520, nullptr, "IsQualificationTransitionSupportedByProcessId"},
287 {2521, nullptr, "GetRightsUserChangedEvent"},
288 {2522, nullptr, "IsRomRedirectionAvailable"},
289 {2800, nullptr, "GetApplicationIdOfPreomia"},
290 {3000, nullptr, "RegisterDeviceLockKey"},
291 {3001, nullptr, "UnregisterDeviceLockKey"},
292 {3002, nullptr, "VerifyDeviceLockKey"},
293 {3003, nullptr, "HideApplicationIcon"},
294 {3004, nullptr, "ShowApplicationIcon"},
295 {3005, nullptr, "HideApplicationTitle"},
296 {3006, nullptr, "ShowApplicationTitle"},
297 {3007, nullptr, "EnableGameCard"},
298 {3008, nullptr, "DisableGameCard"},
299 {3009, nullptr, "EnableLocalContentShare"},
300 {3010, nullptr, "DisableLocalContentShare"},
301 {3011, nullptr, "IsApplicationIconHidden"},
302 {3012, nullptr, "IsApplicationTitleHidden"},
303 {3013, nullptr, "IsGameCardEnabled"},
304 {3014, nullptr, "IsLocalContentShareEnabled"},
305 {3050, nullptr, "ListAssignELicenseTaskResult"},
306 {9999, nullptr, "GetApplicationCertificate"},
307 };
308 // clang-format on
309
310 RegisterHandlers(functions);
311}
312
313IApplicationManagerInterface::~IApplicationManagerInterface() = default;
314
315Result IApplicationManagerInterface::GetApplicationControlData(
316 OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size,
317 ApplicationControlSource application_control_source, u64 application_id) {
318 LOG_DEBUG(Service_NS, "called");
319 R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationControlData(
320 out_buffer, out_actual_size, application_control_source, application_id));
321}
322
323Result IApplicationManagerInterface::GetApplicationDesiredLanguage(
324 Out<ApplicationLanguage> out_desired_language, u32 supported_languages) {
325 LOG_DEBUG(Service_NS, "called");
326 R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationDesiredLanguage(
327 out_desired_language, supported_languages));
328}
329
330Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
331 Out<u64> out_language_code, ApplicationLanguage application_language) {
332 LOG_DEBUG(Service_NS, "called");
333 R_RETURN(
334 IReadOnlyApplicationControlDataInterface(system).ConvertApplicationLanguageToLanguageCode(
335 out_language_code, application_language));
336}
337
338Result IApplicationManagerInterface::ListApplicationRecord(
339 OutArray<ApplicationRecord, BufferAttr_HipcMapAlias> out_records, Out<s32> out_count,
340 s32 offset) {
341 const auto limit = out_records.size();
342
343 LOG_WARNING(Service_NS, "(STUBBED) called");
344 const auto& cache = system.GetContentProviderUnion();
345 const auto installed_games = cache.ListEntriesFilterOrigin(
346 std::nullopt, FileSys::TitleType::Application, FileSys::ContentRecordType::Program);
347
348 size_t i = 0;
349 u8 ii = 24;
350
351 for (const auto& [slot, game] : installed_games) {
352 if (i >= limit) {
353 break;
354 }
355 if (game.title_id == 0 || game.title_id < 0x0100000000001FFFull) {
356 continue;
357 }
358 if (offset > 0) {
359 offset--;
360 continue;
361 }
362
363 ApplicationRecord record{};
364 record.application_id = game.title_id;
365 record.type = ApplicationRecordType::Installed;
366 record.unknown = 0; // 2 = needs update
367 record.unknown2 = ii++;
368
369 out_records[i++] = record;
370 }
371
372 *out_count = static_cast<s32>(i);
373 R_SUCCEED();
374}
375
376Result IApplicationManagerInterface::GetApplicationRecordUpdateSystemEvent(
377 OutCopyHandle<Kernel::KReadableEvent> out_event) {
378 LOG_WARNING(Service_NS, "(STUBBED) called");
379
380 record_update_system_event.Signal();
381 *out_event = record_update_system_event.GetHandle();
382
383 R_SUCCEED();
384}
385
386Result IApplicationManagerInterface::GetGameCardMountFailureEvent(
387 OutCopyHandle<Kernel::KReadableEvent> out_event) {
388 LOG_WARNING(Service_NS, "(STUBBED) called");
389 *out_event = gamecard_mount_failure_event.GetHandle();
390 R_SUCCEED();
391}
392
393Result IApplicationManagerInterface::IsAnyApplicationEntityInstalled(
394 Out<bool> out_is_any_application_entity_installed) {
395 LOG_WARNING(Service_NS, "(STUBBED) called");
396 *out_is_any_application_entity_installed = true;
397 R_SUCCEED();
398}
399
400Result IApplicationManagerInterface::GetApplicationView(
401 OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views,
402 InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
403 const auto size = std::min(out_application_views.size(), application_ids.size());
404 LOG_WARNING(Service_NS, "(STUBBED) called, size={}", application_ids.size());
405
406 for (size_t i = 0; i < size; i++) {
407 ApplicationView view{};
408 view.application_id = application_ids[i];
409 view.unk = 0x70000;
410 view.flags = 0x401f17;
411
412 out_application_views[i] = view;
413 }
414
415 R_SUCCEED();
416}
417
418Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo(
419 OutArray<ApplicationViewWithPromotionInfo, BufferAttr_HipcMapAlias> out_application_views,
420 InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
421 const auto size = std::min(out_application_views.size(), application_ids.size());
422 LOG_WARNING(Service_NS, "(STUBBED) called, size={}", application_ids.size());
423
424 for (size_t i = 0; i < size; i++) {
425 ApplicationViewWithPromotionInfo view{};
426 view.view.application_id = application_ids[i];
427 view.view.unk = 0x70000;
428 view.view.flags = 0x401f17;
429 view.promotion = {};
430
431 out_application_views[i] = view;
432 }
433
434 R_SUCCEED();
435}
436
437Result IApplicationManagerInterface::GetApplicationRightsOnClient(
438 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
439 u32 flags, u64 application_id, Uid account_id) {
440 LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}",
441 flags, application_id, account_id.uuid.FormattedString());
442
443 if (!out_rights.empty()) {
444 ApplicationRightsOnClient rights{};
445 rights.application_id = application_id;
446 rights.uid = account_id.uuid;
447 rights.flags = 0;
448 rights.flags2 = 0;
449
450 out_rights[0] = rights;
451 *out_count = 1;
452 } else {
453 *out_count = 0;
454 }
455
456 R_SUCCEED();
457}
458
459Result IApplicationManagerInterface::CheckSdCardMountStatus() {
460 LOG_DEBUG(Service_NS, "called");
461 R_RETURN(IContentManagementInterface(system).CheckSdCardMountStatus());
462}
463
464Result IApplicationManagerInterface::GetSdCardMountStatusChangedEvent(
465 OutCopyHandle<Kernel::KReadableEvent> out_event) {
466 LOG_WARNING(Service_NS, "(STUBBED) called");
467 *out_event = sd_card_mount_status_event.GetHandle();
468 R_SUCCEED();
469}
470
471Result IApplicationManagerInterface::GetFreeSpaceSize(Out<s64> out_free_space_size,
472 FileSys::StorageId storage_id) {
473 LOG_DEBUG(Service_NS, "called");
474 R_RETURN(IContentManagementInterface(system).GetFreeSpaceSize(out_free_space_size, storage_id));
475}
476
477Result IApplicationManagerInterface::GetGameCardUpdateDetectionEvent(
478 OutCopyHandle<Kernel::KReadableEvent> out_event) {
479 LOG_WARNING(Service_NS, "(STUBBED) called");
480 *out_event = gamecard_update_detection_event.GetHandle();
481 R_SUCCEED();
482}
483
484Result IApplicationManagerInterface::ResumeAll() {
485 LOG_WARNING(Service_NS, "(STUBBED) called");
486 R_SUCCEED();
487}
488
489Result IApplicationManagerInterface::GetStorageSize(Out<s64> out_total_space_size,
490 Out<s64> out_free_space_size,
491 FileSys::StorageId storage_id) {
492 LOG_INFO(Service_NS, "called, storage_id={}", storage_id);
493 *out_total_space_size = system.GetFileSystemController().GetTotalSpaceSize(storage_id);
494 *out_free_space_size = system.GetFileSystemController().GetFreeSpaceSize(storage_id);
495 R_SUCCEED();
496}
497
498Result IApplicationManagerInterface::IsApplicationUpdateRequested(Out<bool> out_update_required,
499 Out<u32> out_update_version,
500 u64 application_id) {
501 LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id);
502 *out_update_required = false;
503 *out_update_version = 0;
504 R_SUCCEED();
505}
506
507Result IApplicationManagerInterface::CheckApplicationLaunchVersion(u64 application_id) {
508 LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id);
509 R_SUCCEED();
510}
511
512Result IApplicationManagerInterface::GetApplicationTerminateResult(Out<Result> out_result,
513 u64 application_id) {
514 LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id);
515 *out_result = ResultSuccess;
516 R_SUCCEED();
517}
518
519} // namespace Service::NS
diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h
new file mode 100644
index 000000000..f33d269b3
--- /dev/null
+++ b/src/core/hle/service/ns/application_manager_interface.h
@@ -0,0 +1,62 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/ns/language.h"
8#include "core/hle/service/ns/ns_types.h"
9#include "core/hle/service/os/event.h"
10#include "core/hle/service/service.h"
11
12namespace Service::NS {
13
14class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
15public:
16 explicit IApplicationManagerInterface(Core::System& system_);
17 ~IApplicationManagerInterface() override;
18
19 Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
20 Out<u32> out_actual_size,
21 ApplicationControlSource application_control_source,
22 u64 application_id);
23 Result GetApplicationDesiredLanguage(Out<ApplicationLanguage> out_desired_language,
24 u32 supported_languages);
25 Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code,
26 ApplicationLanguage application_language);
27 Result ListApplicationRecord(OutArray<ApplicationRecord, BufferAttr_HipcMapAlias> out_records,
28 Out<s32> out_count, s32 offset);
29 Result GetApplicationRecordUpdateSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
30 Result GetGameCardMountFailureEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
31 Result IsAnyApplicationEntityInstalled(Out<bool> out_is_any_application_entity_installed);
32 Result GetApplicationView(
33 OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views,
34 InArray<u64, BufferAttr_HipcMapAlias> application_ids);
35 Result GetApplicationViewWithPromotionInfo(
36 OutArray<ApplicationViewWithPromotionInfo, BufferAttr_HipcMapAlias> out_application_views,
37 InArray<u64, BufferAttr_HipcMapAlias> application_ids);
38 Result GetApplicationRightsOnClient(
39 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
40 u32 flags, u64 application_id, Uid account_id);
41 Result CheckSdCardMountStatus();
42 Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
43 Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id);
44 Result GetGameCardUpdateDetectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
45 Result ResumeAll();
46 Result GetStorageSize(Out<s64> out_total_space_size, Out<s64> out_free_space_size,
47 FileSys::StorageId storage_id);
48 Result IsApplicationUpdateRequested(Out<bool> out_update_required, Out<u32> out_update_version,
49 u64 application_id);
50 Result CheckApplicationLaunchVersion(u64 application_id);
51 Result GetApplicationTerminateResult(Out<Result> out_result, u64 application_id);
52
53private:
54 KernelHelpers::ServiceContext service_context;
55 Event record_update_system_event;
56 Event sd_card_mount_status_event;
57 Event gamecard_update_detection_event;
58 Event gamecard_mount_status_event;
59 Event gamecard_mount_failure_event;
60};
61
62} // namespace Service::NS
diff --git a/src/core/hle/service/ns/application_version_interface.cpp b/src/core/hle/service/ns/application_version_interface.cpp
new file mode 100644
index 000000000..b89e127db
--- /dev/null
+++ b/src/core/hle/service/ns/application_version_interface.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/ns/application_version_interface.h"
5
6namespace Service::NS {
7
8IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_)
9 : ServiceFramework{system_, "IApplicationVersionInterface"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetLaunchRequiredVersion"},
13 {1, nullptr, "UpgradeLaunchRequiredVersion"},
14 {35, nullptr, "UpdateVersionList"},
15 {36, nullptr, "PushLaunchVersion"},
16 {37, nullptr, "ListRequiredVersion"},
17 {800, nullptr, "RequestVersionList"},
18 {801, nullptr, "ListVersionList"},
19 {802, nullptr, "RequestVersionListData"},
20 {900, nullptr, "ImportAutoUpdatePolicyJsonForDebug"},
21 {901, nullptr, "ListDefaultAutoUpdatePolicy"},
22 {902, nullptr, "ListAutoUpdatePolicyForSpecificApplication"},
23 {1000, nullptr, "PerformAutoUpdate"},
24 {1001, nullptr, "ListAutoUpdateSchedule"},
25 };
26 // clang-format on
27
28 RegisterHandlers(functions);
29}
30
31IApplicationVersionInterface::~IApplicationVersionInterface() = default;
32
33} // namespace Service::NS
diff --git a/src/core/hle/service/ns/application_version_interface.h b/src/core/hle/service/ns/application_version_interface.h
new file mode 100644
index 000000000..b288cff1b
--- /dev/null
+++ b/src/core/hle/service/ns/application_version_interface.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::NS {
9
10class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
11public:
12 explicit IApplicationVersionInterface(Core::System& system_);
13 ~IApplicationVersionInterface() override;
14};
15
16} // namespace Service::NS
diff --git a/src/core/hle/service/ns/content_management_interface.cpp b/src/core/hle/service/ns/content_management_interface.cpp
new file mode 100644
index 000000000..69bb3f6e4
--- /dev/null
+++ b/src/core/hle/service/ns/content_management_interface.cpp
@@ -0,0 +1,72 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/common_funcs.h"
5#include "core/core.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/ns/content_management_interface.h"
9#include "core/hle/service/ns/ns_types.h"
10
11namespace Service::NS {
12
13IContentManagementInterface::IContentManagementInterface(Core::System& system_)
14 : ServiceFramework{system_, "IContentManagementInterface"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {11, D<&IContentManagementInterface::CalculateApplicationOccupiedSize>, "CalculateApplicationOccupiedSize"},
18 {43, D<&IContentManagementInterface::CheckSdCardMountStatus>, "CheckSdCardMountStatus"},
19 {47, D<&IContentManagementInterface::GetTotalSpaceSize>, "GetTotalSpaceSize"},
20 {48, D<&IContentManagementInterface::GetFreeSpaceSize>, "GetFreeSpaceSize"},
21 {600, nullptr, "CountApplicationContentMeta"},
22 {601, nullptr, "ListApplicationContentMetaStatus"},
23 {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
24 {607, nullptr, "IsAnyApplicationRunning"},
25 };
26 // clang-format on
27
28 RegisterHandlers(functions);
29}
30
31IContentManagementInterface::~IContentManagementInterface() = default;
32
33Result IContentManagementInterface::CalculateApplicationOccupiedSize(
34 Out<ApplicationOccupiedSize> out_size, u64 application_id) {
35 LOG_WARNING(Service_NS, "(STUBBED) called, application_id={:016X}", application_id);
36
37 using namespace Common::Literals;
38
39 constexpr ApplicationOccupiedSizeEntity stub_entity{
40 .storage_id = FileSys::StorageId::SdCard,
41 .app_size = 8_GiB,
42 .patch_size = 2_GiB,
43 .aoc_size = 12_MiB,
44 };
45
46 for (auto& entity : out_size->entities) {
47 entity = stub_entity;
48 }
49
50 R_SUCCEED();
51}
52
53Result IContentManagementInterface::CheckSdCardMountStatus() {
54 LOG_WARNING(Service_NS, "(STUBBED) called");
55 R_SUCCEED();
56}
57
58Result IContentManagementInterface::GetTotalSpaceSize(Out<s64> out_total_space_size,
59 FileSys::StorageId storage_id) {
60 LOG_INFO(Service_NS, "(STUBBED) called, storage_id={}", storage_id);
61 *out_total_space_size = system.GetFileSystemController().GetTotalSpaceSize(storage_id);
62 R_SUCCEED();
63}
64
65Result IContentManagementInterface::GetFreeSpaceSize(Out<s64> out_free_space_size,
66 FileSys::StorageId storage_id) {
67 LOG_INFO(Service_NS, "(STUBBED) called, storage_id={}", storage_id);
68 *out_free_space_size = system.GetFileSystemController().GetFreeSpaceSize(storage_id);
69 R_SUCCEED();
70}
71
72} // namespace Service::NS
diff --git a/src/core/hle/service/ns/content_management_interface.h b/src/core/hle/service/ns/content_management_interface.h
new file mode 100644
index 000000000..2894628e5
--- /dev/null
+++ b/src/core/hle/service/ns/content_management_interface.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/ns/ns_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::NS {
11
12class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> {
13public:
14 explicit IContentManagementInterface(Core::System& system_);
15 ~IContentManagementInterface() override;
16
17public:
18 Result CalculateApplicationOccupiedSize(Out<ApplicationOccupiedSize> out_size,
19 u64 application_id);
20 Result CheckSdCardMountStatus();
21 Result GetTotalSpaceSize(Out<s64> out_total_space_size, FileSys::StorageId storage_id);
22 Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id);
23};
24
25} // namespace Service::NS
diff --git a/src/core/hle/service/ns/develop_interface.cpp b/src/core/hle/service/ns/develop_interface.cpp
new file mode 100644
index 000000000..880bdbebb
--- /dev/null
+++ b/src/core/hle/service/ns/develop_interface.cpp
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/ns/develop_interface.h"
5
6namespace Service::NS {
7
8IDevelopInterface::IDevelopInterface(Core::System& system_) : ServiceFramework{system_, "ns:dev"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "LaunchProgram"},
12 {1, nullptr, "TerminateProcess"},
13 {2, nullptr, "TerminateProgram"},
14 {4, nullptr, "GetShellEvent"},
15 {5, nullptr, "GetShellEventInfo"},
16 {6, nullptr, "TerminateApplication"},
17 {7, nullptr, "PrepareLaunchProgramFromHost"},
18 {8, nullptr, "LaunchApplicationFromHost"},
19 {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
20 {10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
21 {11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
22 {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop"},
23 {13, nullptr, "CreateApplicationResourceForDevelop"},
24 {14, nullptr, "IsPreomiaForDevelop"},
25 {15, nullptr, "GetApplicationProgramIdFromHost"},
26 {16, nullptr, "RefreshCachedDebugValues"},
27 {17, nullptr, "PrepareLaunchApplicationFromHost"},
28 {18, nullptr, "GetLaunchEvent"},
29 {19, nullptr, "GetLaunchResult"},
30 };
31 // clang-format on
32
33 RegisterHandlers(functions);
34}
35
36IDevelopInterface::~IDevelopInterface() = default;
37
38} // namespace Service::NS
diff --git a/src/core/hle/service/ns/develop_interface.h b/src/core/hle/service/ns/develop_interface.h
new file mode 100644
index 000000000..a9f81ccd6
--- /dev/null
+++ b/src/core/hle/service/ns/develop_interface.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::NS {
9
10class IDevelopInterface final : public ServiceFramework<IDevelopInterface> {
11public:
12 explicit IDevelopInterface(Core::System& system_);
13 ~IDevelopInterface() override;
14};
15
16} // namespace Service::NS
diff --git a/src/core/hle/service/ns/document_interface.cpp b/src/core/hle/service/ns/document_interface.cpp
new file mode 100644
index 000000000..51a1e46c0
--- /dev/null
+++ b/src/core/hle/service/ns/document_interface.cpp
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/ns/document_interface.h"
7
8namespace Service::NS {
9
10IDocumentInterface::IDocumentInterface(Core::System& system_)
11 : ServiceFramework{system_, "IDocumentInterface"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {21, nullptr, "GetApplicationContentPath"},
15 {23, D<&IDocumentInterface::ResolveApplicationContentPath>, "ResolveApplicationContentPath"},
16 {92, D<&IDocumentInterface::GetRunningApplicationProgramId>, "GetRunningApplicationProgramId"},
17 };
18 // clang-format on
19
20 RegisterHandlers(functions);
21}
22
23IDocumentInterface::~IDocumentInterface() = default;
24
25Result IDocumentInterface::ResolveApplicationContentPath(ContentPath content_path) {
26 LOG_WARNING(Service_NS, "(STUBBED) called, file_system_proxy_type={}, program_id={:016X}",
27 content_path.file_system_proxy_type, content_path.program_id);
28 R_SUCCEED();
29}
30
31Result IDocumentInterface::GetRunningApplicationProgramId(Out<u64> out_program_id,
32 u64 caller_program_id) {
33 LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id);
34 *out_program_id = system.GetApplicationProcessProgramID();
35 R_SUCCEED();
36}
37
38} // namespace Service::NS
diff --git a/src/core/hle/service/ns/document_interface.h b/src/core/hle/service/ns/document_interface.h
new file mode 100644
index 000000000..cd461652c
--- /dev/null
+++ b/src/core/hle/service/ns/document_interface.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/ns/ns_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::NS {
11
12class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
13public:
14 explicit IDocumentInterface(Core::System& system_);
15 ~IDocumentInterface() override;
16
17private:
18 Result ResolveApplicationContentPath(ContentPath content_path);
19 Result GetRunningApplicationProgramId(Out<u64> out_program_id, u64 caller_program_id);
20};
21
22} // namespace Service::NS
diff --git a/src/core/hle/service/ns/download_task_interface.cpp b/src/core/hle/service/ns/download_task_interface.cpp
new file mode 100644
index 000000000..62dc7f187
--- /dev/null
+++ b/src/core/hle/service/ns/download_task_interface.cpp
@@ -0,0 +1,39 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ns/download_task_interface.h"
6
7namespace Service::NS {
8
9IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_)
10 : ServiceFramework{system_, "IDownloadTaskInterface"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {701, nullptr, "ClearTaskStatusList"},
14 {702, nullptr, "RequestDownloadTaskList"},
15 {703, nullptr, "RequestEnsureDownloadTask"},
16 {704, nullptr, "ListDownloadTaskStatus"},
17 {705, nullptr, "RequestDownloadTaskListData"},
18 {706, nullptr, "TryCommitCurrentApplicationDownloadTask"},
19 {707, D<&IDownloadTaskInterface::EnableAutoCommit>, "EnableAutoCommit"},
20 {708, D<&IDownloadTaskInterface::DisableAutoCommit>, "DisableAutoCommit"},
21 {709, nullptr, "TriggerDynamicCommitEvent"},
22 };
23 // clang-format on
24
25 RegisterHandlers(functions);
26}
27
28IDownloadTaskInterface::~IDownloadTaskInterface() = default;
29
30Result IDownloadTaskInterface::EnableAutoCommit() {
31 LOG_WARNING(Service_NS, "(STUBBED) called");
32 R_SUCCEED();
33}
34Result IDownloadTaskInterface::DisableAutoCommit() {
35 LOG_WARNING(Service_NS, "(STUBBED) called");
36 R_SUCCEED();
37}
38
39} // namespace Service::NS
diff --git a/src/core/hle/service/ns/download_task_interface.h b/src/core/hle/service/ns/download_task_interface.h
new file mode 100644
index 000000000..b1cb69cb8
--- /dev/null
+++ b/src/core/hle/service/ns/download_task_interface.h
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::NS {
9
10class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
11public:
12 explicit IDownloadTaskInterface(Core::System& system_);
13 ~IDownloadTaskInterface() override;
14
15private:
16 Result EnableAutoCommit();
17 Result DisableAutoCommit();
18};
19
20} // namespace Service::NS
diff --git a/src/core/hle/service/ns/dynamic_rights_interface.cpp b/src/core/hle/service/ns/dynamic_rights_interface.cpp
new file mode 100644
index 000000000..ce81e203f
--- /dev/null
+++ b/src/core/hle/service/ns/dynamic_rights_interface.cpp
@@ -0,0 +1,62 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ns/dynamic_rights_interface.h"
6
7namespace Service::NS {
8
9IDynamicRightsInterface::IDynamicRightsInterface(Core::System& system_)
10 : ServiceFramework{system_, "DynamicRightsInterface"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "RequestApplicationRightsOnServer"},
14 {1, nullptr, "RequestAssignRights"},
15 {4, nullptr, "DeprecatedRequestAssignRightsToResume"},
16 {5, D<&IDynamicRightsInterface::VerifyActivatedRightsOwners>, "VerifyActivatedRightsOwners"},
17 {6, nullptr, "DeprecatedGetApplicationRightsStatus"},
18 {7, nullptr, "RequestPrefetchForDynamicRights"},
19 {8, nullptr, "GetDynamicRightsState"},
20 {9, nullptr, "RequestApplicationRightsOnServerToResume"},
21 {10, nullptr, "RequestAssignRightsToResume"},
22 {11, nullptr, "GetActivatedRightsUsers"},
23 {12, nullptr, "GetApplicationRightsStatus"},
24 {13, D<&IDynamicRightsInterface::GetRunningApplicationStatus>, "GetRunningApplicationStatus"},
25 {14, nullptr, "SelectApplicationLicense"},
26 {15, nullptr, "RequestContentsAuthorizationToken"},
27 {16, nullptr, "QualifyUser"},
28 {17, nullptr, "QualifyUserWithProcessId"},
29 {18, D<&IDynamicRightsInterface::NotifyApplicationRightsCheckStart>, "NotifyApplicationRightsCheckStart"},
30 {19, nullptr, "UpdateUserList"},
31 {20, nullptr, "IsRightsLostUser"},
32 {21, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
33 {22, nullptr, "GetLimitedApplicationLicense"},
34 {23, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
35 {24, nullptr, "NotifyLimitedApplicationLicenseUpgradableEventForDebug"},
36 {25, nullptr, "RequestProceedDynamicRightsState"},
37 };
38 // clang-format on
39
40 RegisterHandlers(functions);
41}
42
43IDynamicRightsInterface::~IDynamicRightsInterface() = default;
44
45Result IDynamicRightsInterface::NotifyApplicationRightsCheckStart() {
46 LOG_WARNING(Service_NS, "(STUBBED) called");
47 R_SUCCEED();
48}
49
50Result IDynamicRightsInterface::GetRunningApplicationStatus(Out<u32> out_status,
51 u64 rights_handle) {
52 LOG_WARNING(Service_NS, "(STUBBED) called, rights_handle={:#x}", rights_handle);
53 *out_status = 0;
54 R_SUCCEED();
55}
56
57Result IDynamicRightsInterface::VerifyActivatedRightsOwners(u64 rights_handle) {
58 LOG_WARNING(Service_NS, "(STUBBED) called, rights_handle={:#x}", rights_handle);
59 R_SUCCEED();
60}
61
62} // namespace Service::NS
diff --git a/src/core/hle/service/ns/dynamic_rights_interface.h b/src/core/hle/service/ns/dynamic_rights_interface.h
new file mode 100644
index 000000000..877e009b0
--- /dev/null
+++ b/src/core/hle/service/ns/dynamic_rights_interface.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::NS {
10
11class IDynamicRightsInterface final : public ServiceFramework<IDynamicRightsInterface> {
12public:
13 explicit IDynamicRightsInterface(Core::System& system_);
14 ~IDynamicRightsInterface() override;
15
16private:
17 Result NotifyApplicationRightsCheckStart();
18 Result GetRunningApplicationStatus(Out<u32> out_status, u64 rights_handle);
19 Result VerifyActivatedRightsOwners(u64 rights_handle);
20};
21
22} // namespace Service::NS
diff --git a/src/core/hle/service/ns/ecommerce_interface.cpp b/src/core/hle/service/ns/ecommerce_interface.cpp
new file mode 100644
index 000000000..76fc425f0
--- /dev/null
+++ b/src/core/hle/service/ns/ecommerce_interface.cpp
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/ns/ecommerce_interface.h"
5
6namespace Service::NS {
7
8IECommerceInterface::IECommerceInterface(Core::System& system_)
9 : ServiceFramework{system_, "IECommerceInterface"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestLinkDevice"},
13 {1, nullptr, "RequestCleanupAllPreInstalledApplications"},
14 {2, nullptr, "RequestCleanupPreInstalledApplication"},
15 {3, nullptr, "RequestSyncRights"},
16 {4, nullptr, "RequestUnlinkDevice"},
17 {5, nullptr, "RequestRevokeAllELicense"},
18 {6, nullptr, "RequestSyncRightsBasedOnAssignedELicenses"},
19 };
20 // clang-format on
21
22 RegisterHandlers(functions);
23}
24
25IECommerceInterface::~IECommerceInterface() = default;
26
27} // namespace Service::NS
diff --git a/src/core/hle/service/ns/ecommerce_interface.h b/src/core/hle/service/ns/ecommerce_interface.h
new file mode 100644
index 000000000..4352101f4
--- /dev/null
+++ b/src/core/hle/service/ns/ecommerce_interface.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::NS {
9
10class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
11public:
12 explicit IECommerceInterface(Core::System& system_);
13 ~IECommerceInterface() override;
14};
15
16} // namespace Service::NS
diff --git a/src/core/hle/service/ns/factory_reset_interface.cpp b/src/core/hle/service/ns/factory_reset_interface.cpp
new file mode 100644
index 000000000..fd5cf7e1f
--- /dev/null
+++ b/src/core/hle/service/ns/factory_reset_interface.cpp
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/ns/factory_reset_interface.h"
5
6namespace Service::NS {
7
8IFactoryResetInterface::IFactoryResetInterface(Core::System& system_)
9 : ServiceFramework{system_, "IFactoryResetInterface"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {100, nullptr, "ResetToFactorySettings"},
13 {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
14 {102, nullptr, "ResetToFactorySettingsForRefurbishment"},
15 {103, nullptr, "ResetToFactorySettingsWithPlatformRegion"},
16 {104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"},
17 {105, nullptr, "RequestResetToFactorySettingsSecurely"},
18 {106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"},
19 };
20 // clang-format on
21
22 RegisterHandlers(functions);
23}
24
25IFactoryResetInterface::~IFactoryResetInterface() = default;
26
27} // namespace Service::NS
diff --git a/src/core/hle/service/ns/factory_reset_interface.h b/src/core/hle/service/ns/factory_reset_interface.h
new file mode 100644
index 000000000..50d125123
--- /dev/null
+++ b/src/core/hle/service/ns/factory_reset_interface.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::NS {
9
10class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
11public:
12 explicit IFactoryResetInterface(Core::System& system_);
13 ~IFactoryResetInterface() override;
14};
15
16} // namespace Service::NS
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 19c3ff01b..8402e83cb 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -1,893 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h" 4#include "core/hle/service/ns/develop_interface.h"
5#include "common/settings.h"
6#include "core/arm/debug.h"
7#include "core/core.h"
8#include "core/file_sys/control_metadata.h"
9#include "core/file_sys/patch_manager.h"
10#include "core/file_sys/vfs/vfs.h"
11#include "core/hle/service/filesystem/filesystem.h"
12#include "core/hle/service/glue/glue_manager.h"
13#include "core/hle/service/ipc_helpers.h"
14#include "core/hle/service/ns/errors.h"
15#include "core/hle/service/ns/iplatform_service_manager.h"
16#include "core/hle/service/ns/language.h"
17#include "core/hle/service/ns/ns.h" 5#include "core/hle/service/ns/ns.h"
18#include "core/hle/service/ns/pdm_qry.h" 6#include "core/hle/service/ns/platform_service_manager.h"
7#include "core/hle/service/ns/query_service.h"
8#include "core/hle/service/ns/service_getter_interface.h"
9#include "core/hle/service/ns/system_update_interface.h"
10#include "core/hle/service/ns/vulnerability_manager_interface.h"
19#include "core/hle/service/server_manager.h" 11#include "core/hle/service/server_manager.h"
20#include "core/hle/service/set/settings_server.h"
21 12
22namespace Service::NS { 13namespace Service::NS {
23 14
24IAccountProxyInterface::IAccountProxyInterface(Core::System& system_)
25 : ServiceFramework{system_, "IAccountProxyInterface"} {
26 // clang-format off
27 static const FunctionInfo functions[] = {
28 {0, nullptr, "CreateUserAccount"},
29 };
30 // clang-format on
31
32 RegisterHandlers(functions);
33}
34
35IAccountProxyInterface::~IAccountProxyInterface() = default;
36
37IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_)
38 : ServiceFramework{system_, "IApplicationManagerInterface"} {
39 // clang-format off
40 static const FunctionInfo functions[] = {
41 {0, nullptr, "ListApplicationRecord"},
42 {1, nullptr, "GenerateApplicationRecordCount"},
43 {2, nullptr, "GetApplicationRecordUpdateSystemEvent"},
44 {3, nullptr, "GetApplicationViewDeprecated"},
45 {4, nullptr, "DeleteApplicationEntity"},
46 {5, nullptr, "DeleteApplicationCompletely"},
47 {6, nullptr, "IsAnyApplicationEntityRedundant"},
48 {7, nullptr, "DeleteRedundantApplicationEntity"},
49 {8, nullptr, "IsApplicationEntityMovable"},
50 {9, nullptr, "MoveApplicationEntity"},
51 {11, nullptr, "CalculateApplicationOccupiedSize"},
52 {16, nullptr, "PushApplicationRecord"},
53 {17, nullptr, "ListApplicationRecordContentMeta"},
54 {19, nullptr, "LaunchApplicationOld"},
55 {21, nullptr, "GetApplicationContentPath"},
56 {22, nullptr, "TerminateApplication"},
57 {23, nullptr, "ResolveApplicationContentPath"},
58 {26, nullptr, "BeginInstallApplication"},
59 {27, nullptr, "DeleteApplicationRecord"},
60 {30, nullptr, "RequestApplicationUpdateInfo"},
61 {31, nullptr, "Unknown31"},
62 {32, nullptr, "CancelApplicationDownload"},
63 {33, nullptr, "ResumeApplicationDownload"},
64 {35, nullptr, "UpdateVersionList"},
65 {36, nullptr, "PushLaunchVersion"},
66 {37, nullptr, "ListRequiredVersion"},
67 {38, nullptr, "CheckApplicationLaunchVersion"},
68 {39, nullptr, "CheckApplicationLaunchRights"},
69 {40, nullptr, "GetApplicationLogoData"},
70 {41, nullptr, "CalculateApplicationDownloadRequiredSize"},
71 {42, nullptr, "CleanupSdCard"},
72 {43, nullptr, "CheckSdCardMountStatus"},
73 {44, nullptr, "GetSdCardMountStatusChangedEvent"},
74 {45, nullptr, "GetGameCardAttachmentEvent"},
75 {46, nullptr, "GetGameCardAttachmentInfo"},
76 {47, nullptr, "GetTotalSpaceSize"},
77 {48, nullptr, "GetFreeSpaceSize"},
78 {49, nullptr, "GetSdCardRemovedEvent"},
79 {52, nullptr, "GetGameCardUpdateDetectionEvent"},
80 {53, nullptr, "DisableApplicationAutoDelete"},
81 {54, nullptr, "EnableApplicationAutoDelete"},
82 {55, &IApplicationManagerInterface::GetApplicationDesiredLanguage, "GetApplicationDesiredLanguage"},
83 {56, nullptr, "SetApplicationTerminateResult"},
84 {57, nullptr, "ClearApplicationTerminateResult"},
85 {58, nullptr, "GetLastSdCardMountUnexpectedResult"},
86 {59, &IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode, "ConvertApplicationLanguageToLanguageCode"},
87 {60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
88 {61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
89 {62, nullptr, "GetGameCardStopper"},
90 {63, nullptr, "IsSystemProgramInstalled"},
91 {64, nullptr, "StartApplyDeltaTask"},
92 {65, nullptr, "GetRequestServerStopper"},
93 {66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
94 {67, nullptr, "CancelApplicationApplyDelta"},
95 {68, nullptr, "ResumeApplicationApplyDelta"},
96 {69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
97 {70, nullptr, "ResumeAll"},
98 {71, nullptr, "GetStorageSize"},
99 {80, nullptr, "RequestDownloadApplication"},
100 {81, nullptr, "RequestDownloadAddOnContent"},
101 {82, nullptr, "DownloadApplication"},
102 {83, nullptr, "CheckApplicationResumeRights"},
103 {84, nullptr, "GetDynamicCommitEvent"},
104 {85, nullptr, "RequestUpdateApplication2"},
105 {86, nullptr, "EnableApplicationCrashReport"},
106 {87, nullptr, "IsApplicationCrashReportEnabled"},
107 {90, nullptr, "BoostSystemMemoryResourceLimit"},
108 {91, nullptr, "DeprecatedLaunchApplication"},
109 {92, nullptr, "GetRunningApplicationProgramId"},
110 {93, nullptr, "GetMainApplicationProgramIndex"},
111 {94, nullptr, "LaunchApplication"},
112 {95, nullptr, "GetApplicationLaunchInfo"},
113 {96, nullptr, "AcquireApplicationLaunchInfo"},
114 {97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"},
115 {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
116 {99, nullptr, "LaunchDevMenu"},
117 {100, nullptr, "ResetToFactorySettings"},
118 {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
119 {102, nullptr, "ResetToFactorySettingsForRefurbishment"},
120 {103, nullptr, "ResetToFactorySettingsWithPlatformRegion"},
121 {104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"},
122 {105, nullptr, "RequestResetToFactorySettingsSecurely"},
123 {106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"},
124 {200, nullptr, "CalculateUserSaveDataStatistics"},
125 {201, nullptr, "DeleteUserSaveDataAll"},
126 {210, nullptr, "DeleteUserSystemSaveData"},
127 {211, nullptr, "DeleteSaveData"},
128 {220, nullptr, "UnregisterNetworkServiceAccount"},
129 {221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"},
130 {300, nullptr, "GetApplicationShellEvent"},
131 {301, nullptr, "PopApplicationShellEventInfo"},
132 {302, nullptr, "LaunchLibraryApplet"},
133 {303, nullptr, "TerminateLibraryApplet"},
134 {304, nullptr, "LaunchSystemApplet"},
135 {305, nullptr, "TerminateSystemApplet"},
136 {306, nullptr, "LaunchOverlayApplet"},
137 {307, nullptr, "TerminateOverlayApplet"},
138 {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
139 {401, nullptr, "InvalidateAllApplicationControlCache"},
140 {402, nullptr, "RequestDownloadApplicationControlData"},
141 {403, nullptr, "GetMaxApplicationControlCacheCount"},
142 {404, nullptr, "InvalidateApplicationControlCache"},
143 {405, nullptr, "ListApplicationControlCacheEntryInfo"},
144 {406, nullptr, "GetApplicationControlProperty"},
145 {407, nullptr, "ListApplicationTitle"},
146 {408, nullptr, "ListApplicationIcon"},
147 {502, nullptr, "RequestCheckGameCardRegistration"},
148 {503, nullptr, "RequestGameCardRegistrationGoldPoint"},
149 {504, nullptr, "RequestRegisterGameCard"},
150 {505, nullptr, "GetGameCardMountFailureEvent"},
151 {506, nullptr, "IsGameCardInserted"},
152 {507, nullptr, "EnsureGameCardAccess"},
153 {508, nullptr, "GetLastGameCardMountFailureResult"},
154 {509, nullptr, "ListApplicationIdOnGameCard"},
155 {510, nullptr, "GetGameCardPlatformRegion"},
156 {600, nullptr, "CountApplicationContentMeta"},
157 {601, nullptr, "ListApplicationContentMetaStatus"},
158 {602, nullptr, "ListAvailableAddOnContent"},
159 {603, nullptr, "GetOwnedApplicationContentMetaStatus"},
160 {604, nullptr, "RegisterContentsExternalKey"},
161 {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
162 {606, nullptr, "GetContentMetaStorage"},
163 {607, nullptr, "ListAvailableAddOnContent"},
164 {609, nullptr, "ListAvailabilityAssuredAddOnContent"},
165 {610, nullptr, "GetInstalledContentMetaStorage"},
166 {611, nullptr, "PrepareAddOnContent"},
167 {700, nullptr, "PushDownloadTaskList"},
168 {701, nullptr, "ClearTaskStatusList"},
169 {702, nullptr, "RequestDownloadTaskList"},
170 {703, nullptr, "RequestEnsureDownloadTask"},
171 {704, nullptr, "ListDownloadTaskStatus"},
172 {705, nullptr, "RequestDownloadTaskListData"},
173 {800, nullptr, "RequestVersionList"},
174 {801, nullptr, "ListVersionList"},
175 {802, nullptr, "RequestVersionListData"},
176 {900, nullptr, "GetApplicationRecord"},
177 {901, nullptr, "GetApplicationRecordProperty"},
178 {902, nullptr, "EnableApplicationAutoUpdate"},
179 {903, nullptr, "DisableApplicationAutoUpdate"},
180 {904, nullptr, "TouchApplication"},
181 {905, nullptr, "RequestApplicationUpdate"},
182 {906, nullptr, "IsApplicationUpdateRequested"},
183 {907, nullptr, "WithdrawApplicationUpdateRequest"},
184 {908, nullptr, "ListApplicationRecordInstalledContentMeta"},
185 {909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
186 {910, nullptr, "HasApplicationRecord"},
187 {911, nullptr, "SetPreInstalledApplication"},
188 {912, nullptr, "ClearPreInstalledApplicationFlag"},
189 {913, nullptr, "ListAllApplicationRecord"},
190 {914, nullptr, "HideApplicationRecord"},
191 {915, nullptr, "ShowApplicationRecord"},
192 {916, nullptr, "IsApplicationAutoDeleteDisabled"},
193 {1000, nullptr, "RequestVerifyApplicationDeprecated"},
194 {1001, nullptr, "CorruptApplicationForDebug"},
195 {1002, nullptr, "RequestVerifyAddOnContentsRights"},
196 {1003, nullptr, "RequestVerifyApplication"},
197 {1004, nullptr, "CorruptContentForDebug"},
198 {1200, nullptr, "NeedsUpdateVulnerability"},
199 {1300, nullptr, "IsAnyApplicationEntityInstalled"},
200 {1301, nullptr, "DeleteApplicationContentEntities"},
201 {1302, nullptr, "CleanupUnrecordedApplicationEntity"},
202 {1303, nullptr, "CleanupAddOnContentsWithNoRights"},
203 {1304, nullptr, "DeleteApplicationContentEntity"},
204 {1305, nullptr, "TryDeleteRunningApplicationEntity"},
205 {1306, nullptr, "TryDeleteRunningApplicationCompletely"},
206 {1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
207 {1308, nullptr, "DeleteApplicationCompletelyForDebug"},
208 {1309, nullptr, "CleanupUnavailableAddOnContents"},
209 {1310, nullptr, "RequestMoveApplicationEntity"},
210 {1311, nullptr, "EstimateSizeToMove"},
211 {1312, nullptr, "HasMovableEntity"},
212 {1313, nullptr, "CleanupOrphanContents"},
213 {1314, nullptr, "CheckPreconditionSatisfiedToMove"},
214 {1400, nullptr, "PrepareShutdown"},
215 {1500, nullptr, "FormatSdCard"},
216 {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
217 {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
218 {1504, nullptr, "InsertSdCard"},
219 {1505, nullptr, "RemoveSdCard"},
220 {1506, nullptr, "GetSdCardStartupStatus"},
221 {1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
222 {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
223 {1700, nullptr, "ListApplicationDownloadingContentMeta"},
224 {1701, nullptr, "GetApplicationView"},
225 {1702, nullptr, "GetApplicationDownloadTaskStatus"},
226 {1703, nullptr, "GetApplicationViewDownloadErrorContext"},
227 {1704, nullptr, "GetApplicationViewWithPromotionInfo"},
228 {1705, nullptr, "IsPatchAutoDeletableApplication"},
229 {1800, nullptr, "IsNotificationSetupCompleted"},
230 {1801, nullptr, "GetLastNotificationInfoCount"},
231 {1802, nullptr, "ListLastNotificationInfo"},
232 {1803, nullptr, "ListNotificationTask"},
233 {1900, nullptr, "IsActiveAccount"},
234 {1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
235 {1902, nullptr, "GetApplicationTicketInfo"},
236 {1903, nullptr, "RequestDownloadApplicationPrepurchasedRightsForAccount"},
237 {2000, nullptr, "GetSystemDeliveryInfo"},
238 {2001, nullptr, "SelectLatestSystemDeliveryInfo"},
239 {2002, nullptr, "VerifyDeliveryProtocolVersion"},
240 {2003, nullptr, "GetApplicationDeliveryInfo"},
241 {2004, nullptr, "HasAllContentsToDeliver"},
242 {2005, nullptr, "CompareApplicationDeliveryInfo"},
243 {2006, nullptr, "CanDeliverApplication"},
244 {2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
245 {2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
246 {2009, nullptr, "EstimateRequiredSize"},
247 {2010, nullptr, "RequestReceiveApplication"},
248 {2011, nullptr, "CommitReceiveApplication"},
249 {2012, nullptr, "GetReceiveApplicationProgress"},
250 {2013, nullptr, "RequestSendApplication"},
251 {2014, nullptr, "GetSendApplicationProgress"},
252 {2015, nullptr, "CompareSystemDeliveryInfo"},
253 {2016, nullptr, "ListNotCommittedContentMeta"},
254 {2017, nullptr, "CreateDownloadTask"},
255 {2018, nullptr, "GetApplicationDeliveryInfoHash"},
256 {2050, nullptr, "GetApplicationRightsOnClient"},
257 {2051, nullptr, "InvalidateRightsIdCache"},
258 {2100, nullptr, "GetApplicationTerminateResult"},
259 {2101, nullptr, "GetRawApplicationTerminateResult"},
260 {2150, nullptr, "CreateRightsEnvironment"},
261 {2151, nullptr, "DestroyRightsEnvironment"},
262 {2152, nullptr, "ActivateRightsEnvironment"},
263 {2153, nullptr, "DeactivateRightsEnvironment"},
264 {2154, nullptr, "ForceActivateRightsContextForExit"},
265 {2155, nullptr, "UpdateRightsEnvironmentStatus"},
266 {2156, nullptr, "CreateRightsEnvironmentForMicroApplication"},
267 {2160, nullptr, "AddTargetApplicationToRightsEnvironment"},
268 {2161, nullptr, "SetUsersToRightsEnvironment"},
269 {2170, nullptr, "GetRightsEnvironmentStatus"},
270 {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
271 {2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
272 {2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"},
273 {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
274 {2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
275 {2199, nullptr, "GetRightsEnvironmentCountForDebug"},
276 {2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
277 {2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
278 {2250, nullptr, "RequestReportActiveELicence"},
279 {2300, nullptr, "ListEventLog"},
280 {2350, nullptr, "PerformAutoUpdateByApplicationId"},
281 {2351, nullptr, "RequestNoDownloadRightsErrorResolution"},
282 {2352, nullptr, "RequestResolveNoDownloadRightsError"},
283 {2353, nullptr, "GetApplicationDownloadTaskInfo"},
284 {2354, nullptr, "PrioritizeApplicationBackgroundTask"},
285 {2355, nullptr, "PreferStorageEfficientUpdate"},
286 {2356, nullptr, "RequestStorageEfficientUpdatePreferable"},
287 {2357, nullptr, "EnableMultiCoreDownload"},
288 {2358, nullptr, "DisableMultiCoreDownload"},
289 {2359, nullptr, "IsMultiCoreDownloadEnabled"},
290 {2400, nullptr, "GetPromotionInfo"},
291 {2401, nullptr, "CountPromotionInfo"},
292 {2402, nullptr, "ListPromotionInfo"},
293 {2403, nullptr, "ImportPromotionJsonForDebug"},
294 {2404, nullptr, "ClearPromotionInfoForDebug"},
295 {2500, nullptr, "ConfirmAvailableTime"},
296 {2510, nullptr, "CreateApplicationResource"},
297 {2511, nullptr, "GetApplicationResource"},
298 {2513, nullptr, "LaunchMicroApplication"},
299 {2514, nullptr, "ClearTaskOfAsyncTaskManager"},
300 {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"},
301 {2516, nullptr, "EnsureApplicationCertificate"},
302 {2517, nullptr, "CreateApplicationInstance"},
303 {2518, nullptr, "UpdateQualificationForDebug"},
304 {2519, nullptr, "IsQualificationTransitionSupported"},
305 {2520, nullptr, "IsQualificationTransitionSupportedByProcessId"},
306 {2521, nullptr, "GetRightsUserChangedEvent"},
307 {2522, nullptr, "IsRomRedirectionAvailable"},
308 {2800, nullptr, "GetApplicationIdOfPreomia"},
309 {3000, nullptr, "RegisterDeviceLockKey"},
310 {3001, nullptr, "UnregisterDeviceLockKey"},
311 {3002, nullptr, "VerifyDeviceLockKey"},
312 {3003, nullptr, "HideApplicationIcon"},
313 {3004, nullptr, "ShowApplicationIcon"},
314 {3005, nullptr, "HideApplicationTitle"},
315 {3006, nullptr, "ShowApplicationTitle"},
316 {3007, nullptr, "EnableGameCard"},
317 {3008, nullptr, "DisableGameCard"},
318 {3009, nullptr, "EnableLocalContentShare"},
319 {3010, nullptr, "DisableLocalContentShare"},
320 {3011, nullptr, "IsApplicationIconHidden"},
321 {3012, nullptr, "IsApplicationTitleHidden"},
322 {3013, nullptr, "IsGameCardEnabled"},
323 {3014, nullptr, "IsLocalContentShareEnabled"},
324 {3050, nullptr, "ListAssignELicenseTaskResult"},
325 {9999, nullptr, "GetApplicationCertificate"},
326 };
327 // clang-format on
328
329 RegisterHandlers(functions);
330}
331
332IApplicationManagerInterface::~IApplicationManagerInterface() = default;
333
334void IApplicationManagerInterface::GetApplicationControlData(HLERequestContext& ctx) {
335 IPC::RequestParser rp{ctx};
336 const auto flag = rp.PopRaw<u64>();
337 LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
338
339 const auto title_id = rp.PopRaw<u64>();
340
341 const auto size = ctx.GetWriteBufferSize();
342
343 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
344 system.GetContentProvider()};
345 const auto control = pm.GetControlMetadata();
346
347 std::vector<u8> out;
348
349 if (control.first != nullptr) {
350 if (size < 0x4000) {
351 LOG_ERROR(Service_NS,
352 "output buffer is too small! (actual={:016X}, expected_min=0x4000)", size);
353 IPC::ResponseBuilder rb{ctx, 2};
354 // TODO(DarkLordZach): Find a better error code for this.
355 rb.Push(ResultUnknown);
356 return;
357 }
358
359 out.resize(0x4000);
360 const auto bytes = control.first->GetRawBytes();
361 std::memcpy(out.data(), bytes.data(), bytes.size());
362 } else {
363 LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
364 title_id);
365 out.resize(std::min<u64>(0x4000, size));
366 }
367
368 if (control.second != nullptr) {
369 if (size < 0x4000 + control.second->GetSize()) {
370 LOG_ERROR(Service_NS,
371 "output buffer is too small! (actual={:016X}, expected_min={:016X})", size,
372 0x4000 + control.second->GetSize());
373 IPC::ResponseBuilder rb{ctx, 2};
374 // TODO(DarkLordZach): Find a better error code for this.
375 rb.Push(ResultUnknown);
376 return;
377 }
378
379 out.resize(0x4000 + control.second->GetSize());
380 control.second->Read(out.data() + 0x4000, control.second->GetSize());
381 } else {
382 LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
383 title_id);
384 }
385
386 ctx.WriteBuffer(out);
387
388 IPC::ResponseBuilder rb{ctx, 3};
389 rb.Push(ResultSuccess);
390 rb.Push<u32>(static_cast<u32>(out.size()));
391}
392
393void IApplicationManagerInterface::GetApplicationDesiredLanguage(HLERequestContext& ctx) {
394 IPC::RequestParser rp{ctx};
395 const auto supported_languages = rp.Pop<u32>();
396
397 u8 desired_language{};
398 const auto res = GetApplicationDesiredLanguage(&desired_language, supported_languages);
399 if (res == ResultSuccess) {
400 IPC::ResponseBuilder rb{ctx, 3};
401 rb.Push(ResultSuccess);
402 rb.Push<u32>(desired_language);
403 } else {
404 IPC::ResponseBuilder rb{ctx, 2};
405 rb.Push(res);
406 }
407}
408
409Result IApplicationManagerInterface::GetApplicationDesiredLanguage(u8* out_desired_language,
410 const u32 supported_languages) {
411 LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages);
412
413 // Get language code from settings
414 const auto language_code =
415 Set::GetLanguageCodeFromIndex(static_cast<s32>(Settings::values.language_index.GetValue()));
416
417 // Convert to application language, get priority list
418 const auto application_language = ConvertToApplicationLanguage(language_code);
419 if (application_language == std::nullopt) {
420 LOG_ERROR(Service_NS, "Could not convert application language! language_code={}",
421 language_code);
422 return Service::NS::ResultApplicationLanguageNotFound;
423 }
424 const auto priority_list = GetApplicationLanguagePriorityList(*application_language);
425 if (!priority_list) {
426 LOG_ERROR(Service_NS,
427 "Could not find application language priorities! application_language={}",
428 *application_language);
429 return Service::NS::ResultApplicationLanguageNotFound;
430 }
431
432 // Try to find a valid language.
433 for (const auto lang : *priority_list) {
434 const auto supported_flag = GetSupportedLanguageFlag(lang);
435 if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
436 *out_desired_language = static_cast<u8>(lang);
437 return ResultSuccess;
438 }
439 }
440
441 LOG_ERROR(Service_NS, "Could not find a valid language! supported_languages={:08X}",
442 supported_languages);
443 return Service::NS::ResultApplicationLanguageNotFound;
444}
445
446void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
447 HLERequestContext& ctx) {
448 IPC::RequestParser rp{ctx};
449 const auto application_language = rp.Pop<u8>();
450
451 u64 language_code{};
452 const auto res = ConvertApplicationLanguageToLanguageCode(&language_code, application_language);
453 if (res == ResultSuccess) {
454 IPC::ResponseBuilder rb{ctx, 4};
455 rb.Push(ResultSuccess);
456 rb.Push(language_code);
457 } else {
458 IPC::ResponseBuilder rb{ctx, 2};
459 rb.Push(res);
460 }
461}
462
463Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
464 u64* out_language_code, u8 application_language) {
465 const auto language_code =
466 ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language));
467 if (language_code == std::nullopt) {
468 LOG_ERROR(Service_NS, "Language not found! application_language={}", application_language);
469 return Service::NS::ResultApplicationLanguageNotFound;
470 }
471
472 *out_language_code = static_cast<u64>(*language_code);
473 return ResultSuccess;
474}
475
476IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_)
477 : ServiceFramework{system_, "IApplicationVersionInterface"} {
478 // clang-format off
479 static const FunctionInfo functions[] = {
480 {0, nullptr, "GetLaunchRequiredVersion"},
481 {1, nullptr, "UpgradeLaunchRequiredVersion"},
482 {35, nullptr, "UpdateVersionList"},
483 {36, nullptr, "PushLaunchVersion"},
484 {37, nullptr, "ListRequiredVersion"},
485 {800, nullptr, "RequestVersionList"},
486 {801, nullptr, "ListVersionList"},
487 {802, nullptr, "RequestVersionListData"},
488 {900, nullptr, "ImportAutoUpdatePolicyJsonForDebug"},
489 {901, nullptr, "ListDefaultAutoUpdatePolicy"},
490 {902, nullptr, "ListAutoUpdatePolicyForSpecificApplication"},
491 {1000, nullptr, "PerformAutoUpdate"},
492 {1001, nullptr, "ListAutoUpdateSchedule"},
493 };
494 // clang-format on
495
496 RegisterHandlers(functions);
497}
498
499IApplicationVersionInterface::~IApplicationVersionInterface() = default;
500
501IContentManagementInterface::IContentManagementInterface(Core::System& system_)
502 : ServiceFramework{system_, "IContentManagementInterface"} {
503 // clang-format off
504 static const FunctionInfo functions[] = {
505 {11, nullptr, "CalculateApplicationOccupiedSize"},
506 {43, nullptr, "CheckSdCardMountStatus"},
507 {47, &IContentManagementInterface::GetTotalSpaceSize, "GetTotalSpaceSize"},
508 {48, &IContentManagementInterface::GetFreeSpaceSize, "GetFreeSpaceSize"},
509 {600, nullptr, "CountApplicationContentMeta"},
510 {601, nullptr, "ListApplicationContentMetaStatus"},
511 {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
512 {607, nullptr, "IsAnyApplicationRunning"},
513 };
514 // clang-format on
515
516 RegisterHandlers(functions);
517}
518
519IContentManagementInterface::~IContentManagementInterface() = default;
520
521void IContentManagementInterface::GetTotalSpaceSize(HLERequestContext& ctx) {
522 IPC::RequestParser rp{ctx};
523 const auto storage{rp.PopEnum<FileSys::StorageId>()};
524
525 LOG_INFO(Service_Capture, "called, storage={}", storage);
526
527 IPC::ResponseBuilder rb{ctx, 4};
528 rb.Push(ResultSuccess);
529 rb.Push<u64>(system.GetFileSystemController().GetTotalSpaceSize(storage));
530}
531
532void IContentManagementInterface::GetFreeSpaceSize(HLERequestContext& ctx) {
533 IPC::RequestParser rp{ctx};
534 const auto storage{rp.PopEnum<FileSys::StorageId>()};
535
536 LOG_INFO(Service_Capture, "called, storage={}", storage);
537
538 IPC::ResponseBuilder rb{ctx, 4};
539 rb.Push(ResultSuccess);
540 rb.Push<u64>(system.GetFileSystemController().GetFreeSpaceSize(storage));
541}
542
543IDocumentInterface::IDocumentInterface(Core::System& system_)
544 : ServiceFramework{system_, "IDocumentInterface"} {
545 // clang-format off
546 static const FunctionInfo functions[] = {
547 {21, nullptr, "GetApplicationContentPath"},
548 {23, &IDocumentInterface::ResolveApplicationContentPath, "ResolveApplicationContentPath"},
549 {92, &IDocumentInterface::GetRunningApplicationProgramId, "GetRunningApplicationProgramId"},
550 };
551 // clang-format on
552
553 RegisterHandlers(functions);
554}
555
556IDocumentInterface::~IDocumentInterface() = default;
557
558void IDocumentInterface::ResolveApplicationContentPath(HLERequestContext& ctx) {
559 struct ContentPath {
560 u8 file_system_proxy_type;
561 u64 program_id;
562 };
563 static_assert(sizeof(ContentPath) == 0x10, "ContentPath has wrong size");
564
565 IPC::RequestParser rp{ctx};
566 auto content_path = rp.PopRaw<ContentPath>();
567 LOG_WARNING(Service_NS, "(STUBBED) called, file_system_proxy_type={}, program_id={:016X}",
568 content_path.file_system_proxy_type, content_path.program_id);
569
570 IPC::ResponseBuilder rb{ctx, 2};
571 rb.Push(ResultSuccess);
572}
573
574void IDocumentInterface::GetRunningApplicationProgramId(HLERequestContext& ctx) {
575 IPC::RequestParser rp{ctx};
576 const auto caller_program_id = rp.PopRaw<u64>();
577 LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id);
578
579 IPC::ResponseBuilder rb{ctx, 4};
580 rb.Push(ResultSuccess);
581 rb.Push<u64>(system.GetApplicationProcessProgramID());
582}
583
584IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_)
585 : ServiceFramework{system_, "IDownloadTaskInterface"} {
586 // clang-format off
587 static const FunctionInfo functions[] = {
588 {701, nullptr, "ClearTaskStatusList"},
589 {702, nullptr, "RequestDownloadTaskList"},
590 {703, nullptr, "RequestEnsureDownloadTask"},
591 {704, nullptr, "ListDownloadTaskStatus"},
592 {705, nullptr, "RequestDownloadTaskListData"},
593 {706, nullptr, "TryCommitCurrentApplicationDownloadTask"},
594 {707, nullptr, "EnableAutoCommit"},
595 {708, nullptr, "DisableAutoCommit"},
596 {709, nullptr, "TriggerDynamicCommitEvent"},
597 };
598 // clang-format on
599
600 RegisterHandlers(functions);
601}
602
603IDownloadTaskInterface::~IDownloadTaskInterface() = default;
604
605IECommerceInterface::IECommerceInterface(Core::System& system_)
606 : ServiceFramework{system_, "IECommerceInterface"} {
607 // clang-format off
608 static const FunctionInfo functions[] = {
609 {0, nullptr, "RequestLinkDevice"},
610 {1, nullptr, "RequestCleanupAllPreInstalledApplications"},
611 {2, nullptr, "RequestCleanupPreInstalledApplication"},
612 {3, nullptr, "RequestSyncRights"},
613 {4, nullptr, "RequestUnlinkDevice"},
614 {5, nullptr, "RequestRevokeAllELicense"},
615 {6, nullptr, "RequestSyncRightsBasedOnAssignedELicenses"},
616 };
617 // clang-format on
618
619 RegisterHandlers(functions);
620}
621
622IECommerceInterface::~IECommerceInterface() = default;
623
624IFactoryResetInterface::IFactoryResetInterface(Core::System& system_)
625 : ServiceFramework{system_, "IFactoryResetInterface"} {
626 // clang-format off
627 static const FunctionInfo functions[] = {
628 {100, nullptr, "ResetToFactorySettings"},
629 {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
630 {102, nullptr, "ResetToFactorySettingsForRefurbishment"},
631 {103, nullptr, "ResetToFactorySettingsWithPlatformRegion"},
632 {104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"},
633 {105, nullptr, "RequestResetToFactorySettingsSecurely"},
634 {106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"},
635 };
636 // clang-format on
637
638 RegisterHandlers(functions);
639}
640
641IFactoryResetInterface::~IFactoryResetInterface() = default;
642
643IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::System& system_)
644 : ServiceFramework{system_, "IReadOnlyApplicationRecordInterface"} {
645 static const FunctionInfo functions[] = {
646 {0, &IReadOnlyApplicationRecordInterface::HasApplicationRecord, "HasApplicationRecord"},
647 {1, nullptr, "NotifyApplicationFailure"},
648 {2, &IReadOnlyApplicationRecordInterface::IsDataCorruptedResult, "IsDataCorruptedResult"},
649 };
650 // clang-format on
651
652 RegisterHandlers(functions);
653}
654
655IReadOnlyApplicationRecordInterface::~IReadOnlyApplicationRecordInterface() = default;
656
657void IReadOnlyApplicationRecordInterface::HasApplicationRecord(HLERequestContext& ctx) {
658 IPC::RequestParser rp{ctx};
659 const u64 program_id = rp.PopRaw<u64>();
660 LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:X}", program_id);
661
662 IPC::ResponseBuilder rb{ctx, 3};
663 rb.Push(ResultSuccess);
664 rb.Push<u8>(1);
665}
666
667void IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(HLERequestContext& ctx) {
668 IPC::RequestParser rp{ctx};
669 const auto result = rp.PopRaw<Result>();
670 LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue());
671
672 IPC::ResponseBuilder rb{ctx, 3};
673 rb.Push(ResultSuccess);
674 rb.Push<u8>(0);
675}
676
677IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
678 Core::System& system_)
679 : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
680 // clang-format off
681 static const FunctionInfo functions[] = {
682 {0, &IReadOnlyApplicationControlDataInterface::GetApplicationControlData, "GetApplicationControlData"},
683 {1, nullptr, "GetApplicationDesiredLanguage"},
684 {2, nullptr, "ConvertApplicationLanguageToLanguageCode"},
685 {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
686 {4, nullptr, "SelectApplicationDesiredLanguage"},
687 };
688 // clang-format on
689
690 RegisterHandlers(functions);
691}
692
693IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default;
694
695void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(HLERequestContext& ctx) {
696 enum class ApplicationControlSource : u8 {
697 CacheOnly,
698 Storage,
699 StorageOnly,
700 };
701
702 struct RequestParameters {
703 ApplicationControlSource source;
704 u64 application_id;
705 };
706 static_assert(sizeof(RequestParameters) == 0x10, "RequestParameters has incorrect size.");
707
708 IPC::RequestParser rp{ctx};
709 std::vector<u8> nacp_data{};
710 const auto parameters{rp.PopRaw<RequestParameters>()};
711 const auto result =
712 system.GetARPManager().GetControlProperty(&nacp_data, parameters.application_id);
713
714 if (result == ResultSuccess) {
715 ctx.WriteBuffer(nacp_data.data(), nacp_data.size());
716 }
717
718 IPC::ResponseBuilder rb{ctx, 2};
719 rb.Push(result);
720}
721
722NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
723 // clang-format off
724 static const FunctionInfo functions[] = {
725 {7988, nullptr, "GetDynamicRightsInterface"},
726 {7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"},
727 {7991, &NS::PushInterface<IReadOnlyApplicationRecordInterface>, "GetReadOnlyApplicationRecordInterface"},
728 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
729 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
730 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
731 {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
732 {7996, &NS::PushIApplicationManagerInterface, "GetApplicationManagerInterface"},
733 {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
734 {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"},
735 {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
736 };
737 // clang-format on
738
739 RegisterHandlers(functions);
740}
741
742NS::~NS() = default;
743
744std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const {
745 return GetInterface<IApplicationManagerInterface>(system);
746}
747
748class NS_DEV final : public ServiceFramework<NS_DEV> {
749public:
750 explicit NS_DEV(Core::System& system_) : ServiceFramework{system_, "ns:dev"} {
751 // clang-format off
752 static const FunctionInfo functions[] = {
753 {0, nullptr, "LaunchProgram"},
754 {1, nullptr, "TerminateProcess"},
755 {2, nullptr, "TerminateProgram"},
756 {4, nullptr, "GetShellEvent"},
757 {5, nullptr, "GetShellEventInfo"},
758 {6, nullptr, "TerminateApplication"},
759 {7, nullptr, "PrepareLaunchProgramFromHost"},
760 {8, nullptr, "LaunchApplicationFromHost"},
761 {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
762 {10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
763 {11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
764 {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop"},
765 {13, nullptr, "CreateApplicationResourceForDevelop"},
766 {14, nullptr, "IsPreomiaForDevelop"},
767 {15, nullptr, "GetApplicationProgramIdFromHost"},
768 {16, nullptr, "RefreshCachedDebugValues"},
769 {17, nullptr, "PrepareLaunchApplicationFromHost"},
770 {18, nullptr, "GetLaunchEvent"},
771 {19, nullptr, "GetLaunchResult"},
772 };
773 // clang-format on
774
775 RegisterHandlers(functions);
776 }
777};
778
779class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> {
780public:
781 explicit ISystemUpdateControl(Core::System& system_)
782 : ServiceFramework{system_, "ISystemUpdateControl"} {
783 // clang-format off
784 static const FunctionInfo functions[] = {
785 {0, nullptr, "HasDownloaded"},
786 {1, nullptr, "RequestCheckLatestUpdate"},
787 {2, nullptr, "RequestDownloadLatestUpdate"},
788 {3, nullptr, "GetDownloadProgress"},
789 {4, nullptr, "ApplyDownloadedUpdate"},
790 {5, nullptr, "RequestPrepareCardUpdate"},
791 {6, nullptr, "GetPrepareCardUpdateProgress"},
792 {7, nullptr, "HasPreparedCardUpdate"},
793 {8, nullptr, "ApplyCardUpdate"},
794 {9, nullptr, "GetDownloadedEulaDataSize"},
795 {10, nullptr, "GetDownloadedEulaData"},
796 {11, nullptr, "SetupCardUpdate"},
797 {12, nullptr, "GetPreparedCardUpdateEulaDataSize"},
798 {13, nullptr, "GetPreparedCardUpdateEulaData"},
799 {14, nullptr, "SetupCardUpdateViaSystemUpdater"},
800 {15, nullptr, "HasReceived"},
801 {16, nullptr, "RequestReceiveSystemUpdate"},
802 {17, nullptr, "GetReceiveProgress"},
803 {18, nullptr, "ApplyReceivedUpdate"},
804 {19, nullptr, "GetReceivedEulaDataSize"},
805 {20, nullptr, "GetReceivedEulaData"},
806 {21, nullptr, "SetupToReceiveSystemUpdate"},
807 {22, nullptr, "RequestCheckLatestUpdateIncludesRebootlessUpdate"},
808 };
809 // clang-format on
810
811 RegisterHandlers(functions);
812 }
813};
814
815class NS_SU final : public ServiceFramework<NS_SU> {
816public:
817 explicit NS_SU(Core::System& system_) : ServiceFramework{system_, "ns:su"} {
818 // clang-format off
819 static const FunctionInfo functions[] = {
820 {0, nullptr, "GetBackgroundNetworkUpdateState"},
821 {1, &NS_SU::OpenSystemUpdateControl, "OpenSystemUpdateControl"},
822 {2, nullptr, "NotifyExFatDriverRequired"},
823 {3, nullptr, "ClearExFatDriverStatusForDebug"},
824 {4, nullptr, "RequestBackgroundNetworkUpdate"},
825 {5, nullptr, "NotifyBackgroundNetworkUpdate"},
826 {6, nullptr, "NotifyExFatDriverDownloadedForDebug"},
827 {9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"},
828 {10, nullptr, "NotifySystemUpdateForContentDelivery"},
829 {11, nullptr, "PrepareShutdown"},
830 {12, nullptr, "Unknown12"},
831 {13, nullptr, "Unknown13"},
832 {14, nullptr, "Unknown14"},
833 {15, nullptr, "Unknown15"},
834 {16, nullptr, "DestroySystemUpdateTask"},
835 {17, nullptr, "RequestSendSystemUpdate"},
836 {18, nullptr, "GetSendSystemUpdateProgress"},
837 };
838 // clang-format on
839
840 RegisterHandlers(functions);
841 }
842
843private:
844 void OpenSystemUpdateControl(HLERequestContext& ctx) {
845 LOG_DEBUG(Service_NS, "called");
846
847 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
848 rb.Push(ResultSuccess);
849 rb.PushIpcInterface<ISystemUpdateControl>(system);
850 }
851};
852
853class NS_VM final : public ServiceFramework<NS_VM> {
854public:
855 explicit NS_VM(Core::System& system_) : ServiceFramework{system_, "ns:vm"} {
856 // clang-format off
857 static const FunctionInfo functions[] = {
858 {1200, &NS_VM::NeedsUpdateVulnerability, "NeedsUpdateVulnerability"},
859 {1201, nullptr, "UpdateSafeSystemVersionForDebug"},
860 {1202, nullptr, "GetSafeSystemVersion"},
861 };
862 // clang-format on
863
864 RegisterHandlers(functions);
865 }
866
867private:
868 void NeedsUpdateVulnerability(HLERequestContext& ctx) {
869 LOG_WARNING(Service_NS, "(STUBBED) called");
870
871 IPC::ResponseBuilder rb{ctx, 3};
872 rb.Push(ResultSuccess);
873 rb.Push(false);
874 }
875};
876
877void LoopProcess(Core::System& system) { 15void LoopProcess(Core::System& system) {
878 auto server_manager = std::make_unique<ServerManager>(system); 16 auto server_manager = std::make_unique<ServerManager>(system);
879 17
880 server_manager->RegisterNamedService("ns:am2", std::make_shared<NS>("ns:am2", system)); 18 server_manager->RegisterNamedService(
881 server_manager->RegisterNamedService("ns:ec", std::make_shared<NS>("ns:ec", system)); 19 "ns:am2", std::make_shared<IServiceGetterInterface>(system, "ns:am2"));
882 server_manager->RegisterNamedService("ns:rid", std::make_shared<NS>("ns:rid", system)); 20 server_manager->RegisterNamedService(
883 server_manager->RegisterNamedService("ns:rt", std::make_shared<NS>("ns:rt", system)); 21 "ns:ec", std::make_shared<IServiceGetterInterface>(system, "ns:ec"));
884 server_manager->RegisterNamedService("ns:web", std::make_shared<NS>("ns:web", system)); 22 server_manager->RegisterNamedService(
885 server_manager->RegisterNamedService("ns:ro", std::make_shared<NS>("ns:ro", system)); 23 "ns:rid", std::make_shared<IServiceGetterInterface>(system, "ns:rid"));
886 24 server_manager->RegisterNamedService(
887 server_manager->RegisterNamedService("ns:dev", std::make_shared<NS_DEV>(system)); 25 "ns:rt", std::make_shared<IServiceGetterInterface>(system, "ns:rt"));
888 server_manager->RegisterNamedService("ns:su", std::make_shared<NS_SU>(system)); 26 server_manager->RegisterNamedService(
889 server_manager->RegisterNamedService("ns:vm", std::make_shared<NS_VM>(system)); 27 "ns:web", std::make_shared<IServiceGetterInterface>(system, "ns:web"));
890 server_manager->RegisterNamedService("pdm:qry", std::make_shared<PDM_QRY>(system)); 28 server_manager->RegisterNamedService(
29 "ns:ro", std::make_shared<IServiceGetterInterface>(system, "ns:ro"));
30
31 server_manager->RegisterNamedService("ns:dev", std::make_shared<IDevelopInterface>(system));
32 server_manager->RegisterNamedService("ns:su", std::make_shared<ISystemUpdateInterface>(system));
33 server_manager->RegisterNamedService("ns:vm",
34 std::make_shared<IVulnerabilityManagerInterface>(system));
35 server_manager->RegisterNamedService("pdm:qry", std::make_shared<IQueryService>(system));
891 36
892 server_manager->RegisterNamedService("pl:s", 37 server_manager->RegisterNamedService("pl:s",
893 std::make_shared<IPlatformServiceManager>(system, "pl:s")); 38 std::make_shared<IPlatformServiceManager>(system, "pl:s"));
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index 9ee306ef9..f79b4ae3d 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -3,141 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/service.h"
7
8namespace Core { 6namespace Core {
9class System; 7class System;
10} 8}
11 9
12namespace Service { 10namespace Service::NS {
13
14namespace FileSystem {
15class FileSystemController;
16} // namespace FileSystem
17
18namespace NS {
19
20class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
21public:
22 explicit IAccountProxyInterface(Core::System& system_);
23 ~IAccountProxyInterface() override;
24};
25
26class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
27public:
28 explicit IApplicationManagerInterface(Core::System& system_);
29 ~IApplicationManagerInterface() override;
30
31 Result GetApplicationDesiredLanguage(u8* out_desired_language, u32 supported_languages);
32 Result ConvertApplicationLanguageToLanguageCode(u64* out_language_code,
33 u8 application_language);
34
35private:
36 void GetApplicationControlData(HLERequestContext& ctx);
37 void GetApplicationDesiredLanguage(HLERequestContext& ctx);
38 void ConvertApplicationLanguageToLanguageCode(HLERequestContext& ctx);
39};
40
41class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
42public:
43 explicit IApplicationVersionInterface(Core::System& system_);
44 ~IApplicationVersionInterface() override;
45};
46
47class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> {
48public:
49 explicit IContentManagementInterface(Core::System& system_);
50 ~IContentManagementInterface() override;
51
52private:
53 void GetTotalSpaceSize(HLERequestContext& ctx);
54 void GetFreeSpaceSize(HLERequestContext& ctx);
55};
56
57class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
58public:
59 explicit IDocumentInterface(Core::System& system_);
60 ~IDocumentInterface() override;
61
62private:
63 void ResolveApplicationContentPath(HLERequestContext& ctx);
64 void GetRunningApplicationProgramId(HLERequestContext& ctx);
65};
66
67class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
68public:
69 explicit IDownloadTaskInterface(Core::System& system_);
70 ~IDownloadTaskInterface() override;
71};
72
73class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
74public:
75 explicit IECommerceInterface(Core::System& system_);
76 ~IECommerceInterface() override;
77};
78
79class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
80public:
81 explicit IFactoryResetInterface(Core::System& system_);
82 ~IFactoryResetInterface() override;
83};
84
85class IReadOnlyApplicationRecordInterface final
86 : public ServiceFramework<IReadOnlyApplicationRecordInterface> {
87public:
88 explicit IReadOnlyApplicationRecordInterface(Core::System& system_);
89 ~IReadOnlyApplicationRecordInterface() override;
90
91private:
92 void HasApplicationRecord(HLERequestContext& ctx);
93 void IsDataCorruptedResult(HLERequestContext& ctx);
94};
95
96class IReadOnlyApplicationControlDataInterface final
97 : public ServiceFramework<IReadOnlyApplicationControlDataInterface> {
98public:
99 explicit IReadOnlyApplicationControlDataInterface(Core::System& system_);
100 ~IReadOnlyApplicationControlDataInterface() override;
101
102private:
103 void GetApplicationControlData(HLERequestContext& ctx);
104};
105
106class NS final : public ServiceFramework<NS> {
107public:
108 explicit NS(const char* name, Core::System& system_);
109 ~NS() override;
110
111 std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const;
112
113private:
114 template <typename T, typename... Args>
115 void PushInterface(HLERequestContext& ctx) {
116 LOG_DEBUG(Service_NS, "called");
117
118 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
119 rb.Push(ResultSuccess);
120 rb.PushIpcInterface<T>(system);
121 }
122
123 void PushIApplicationManagerInterface(HLERequestContext& ctx) {
124 LOG_DEBUG(Service_NS, "called");
125
126 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
127 rb.Push(ResultSuccess);
128 rb.PushIpcInterface<IApplicationManagerInterface>(system);
129 }
130
131 template <typename T, typename... Args>
132 std::shared_ptr<T> GetInterface(Args&&... args) const {
133 static_assert(std::is_base_of_v<SessionRequestHandler, T>,
134 "Not a base of ServiceFrameworkBase");
135
136 return std::make_shared<T>(std::forward<Args>(args)...);
137 }
138};
139 11
140void LoopProcess(Core::System& system); 12void LoopProcess(Core::System& system);
141 13
142} // namespace NS 14} // namespace Service::NS
143} // namespace Service
diff --git a/src/core/hle/service/ns/errors.h b/src/core/hle/service/ns/ns_results.h
index 16d2ea6f7..16d2ea6f7 100644
--- a/src/core/hle/service/ns/errors.h
+++ b/src/core/hle/service/ns/ns_results.h
diff --git a/src/core/hle/service/ns/ns_types.h b/src/core/hle/service/ns/ns_types.h
new file mode 100644
index 000000000..2dd664c4e
--- /dev/null
+++ b/src/core/hle/service/ns/ns_types.h
@@ -0,0 +1,116 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/uuid.h"
8#include "core/file_sys/romfs_factory.h"
9
10namespace Service::NS {
11
12enum class ApplicationRecordType : u8 {
13 Installing = 2,
14 Installed = 3,
15 GameCardNotInserted = 5,
16 Archived = 11,
17 GameCard = 16,
18};
19
20enum class ApplicationControlSource : u8 {
21 CacheOnly = 0,
22 Storage = 1,
23 StorageOnly = 2,
24};
25
26enum class BackgroundNetworkUpdateState : u8 {
27 None,
28 InProgress,
29 Ready,
30};
31
32struct ApplicationRecord {
33 u64 application_id;
34 ApplicationRecordType type;
35 u8 unknown;
36 INSERT_PADDING_BYTES_NOINIT(0x6);
37 u8 unknown2;
38 INSERT_PADDING_BYTES_NOINIT(0x7);
39};
40static_assert(sizeof(ApplicationRecord) == 0x18, "ApplicationRecord has incorrect size.");
41
42/// ApplicationView
43struct ApplicationView {
44 u64 application_id; ///< ApplicationId.
45 u32 unk; ///< Unknown.
46 u32 flags; ///< Flags.
47 std::array<u8, 0x10> unk_x10; ///< Unknown.
48 u32 unk_x20; ///< Unknown.
49 u16 unk_x24; ///< Unknown.
50 std::array<u8, 0x2> unk_x26; ///< Unknown.
51 std::array<u8, 0x8> unk_x28; ///< Unknown.
52 std::array<u8, 0x10> unk_x30; ///< Unknown.
53 u32 unk_x40; ///< Unknown.
54 u8 unk_x44; ///< Unknown.
55 std::array<u8, 0xb> unk_x45; ///< Unknown.
56};
57static_assert(sizeof(ApplicationView) == 0x50, "ApplicationView has incorrect size.");
58
59struct ApplicationRightsOnClient {
60 u64 application_id;
61 Common::UUID uid;
62 u8 flags;
63 u8 flags2;
64 INSERT_PADDING_BYTES_NOINIT(0x6);
65};
66static_assert(sizeof(ApplicationRightsOnClient) == 0x20,
67 "ApplicationRightsOnClient has incorrect size.");
68
69/// NsPromotionInfo
70struct PromotionInfo {
71 u64 start_timestamp; ///< POSIX timestamp for the promotion start.
72 u64 end_timestamp; ///< POSIX timestamp for the promotion end.
73 s64 remaining_time; ///< Remaining time until the promotion ends, in nanoseconds
74 ///< ({end_timestamp - current_time} converted to nanoseconds).
75 INSERT_PADDING_BYTES_NOINIT(0x4);
76 u8 flags; ///< Flags. Bit0: whether the PromotionInfo is valid (including bit1). Bit1 clear:
77 ///< remaining_time is set.
78 INSERT_PADDING_BYTES_NOINIT(0x3);
79};
80static_assert(sizeof(PromotionInfo) == 0x20, "PromotionInfo has incorrect size.");
81
82/// NsApplicationViewWithPromotionInfo
83struct ApplicationViewWithPromotionInfo {
84 ApplicationView view; ///< \ref NsApplicationView
85 PromotionInfo promotion; ///< \ref NsPromotionInfo
86};
87static_assert(sizeof(ApplicationViewWithPromotionInfo) == 0x70,
88 "ApplicationViewWithPromotionInfo has incorrect size.");
89
90struct ApplicationOccupiedSizeEntity {
91 FileSys::StorageId storage_id;
92 u64 app_size;
93 u64 patch_size;
94 u64 aoc_size;
95};
96static_assert(sizeof(ApplicationOccupiedSizeEntity) == 0x20,
97 "ApplicationOccupiedSizeEntity has incorrect size.");
98
99struct ApplicationOccupiedSize {
100 std::array<ApplicationOccupiedSizeEntity, 4> entities;
101};
102static_assert(sizeof(ApplicationOccupiedSize) == 0x80,
103 "ApplicationOccupiedSize has incorrect size.");
104
105struct ContentPath {
106 u8 file_system_proxy_type;
107 u64 program_id;
108};
109static_assert(sizeof(ContentPath) == 0x10, "ContentPath has incorrect size.");
110
111struct Uid {
112 alignas(8) Common::UUID uuid;
113};
114static_assert(sizeof(Uid) == 0x10, "Uid has incorrect size.");
115
116} // namespace Service::NS
diff --git a/src/core/hle/service/ns/pdm_qry.cpp b/src/core/hle/service/ns/pdm_qry.cpp
deleted file mode 100644
index ce0ee30e0..000000000
--- a/src/core/hle/service/ns/pdm_qry.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <memory>
5
6#include "common/logging/log.h"
7#include "common/uuid.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/ns/pdm_qry.h"
10#include "core/hle/service/service.h"
11
12namespace Service::NS {
13
14PDM_QRY::PDM_QRY(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, nullptr, "QueryAppletEvent"},
18 {1, nullptr, "QueryPlayStatistics"},
19 {2, nullptr, "QueryPlayStatisticsByUserAccountId"},
20 {3, nullptr, "QueryPlayStatisticsByNetworkServiceAccountId"},
21 {4, nullptr, "QueryPlayStatisticsByApplicationId"},
22 {5, &PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId, "QueryPlayStatisticsByApplicationIdAndUserAccountId"},
23 {6, nullptr, "QueryPlayStatisticsByApplicationIdAndNetworkServiceAccountId"},
24 {7, nullptr, "QueryLastPlayTimeV0"},
25 {8, nullptr, "QueryPlayEvent"},
26 {9, nullptr, "GetAvailablePlayEventRange"},
27 {10, nullptr, "QueryAccountEvent"},
28 {11, nullptr, "QueryAccountPlayEvent"},
29 {12, nullptr, "GetAvailableAccountPlayEventRange"},
30 {13, nullptr, "QueryApplicationPlayStatisticsForSystemV0"},
31 {14, nullptr, "QueryRecentlyPlayedApplication"},
32 {15, nullptr, "GetRecentlyPlayedApplicationUpdateEvent"},
33 {16, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystemV0"},
34 {17, nullptr, "QueryLastPlayTime"},
35 {18, nullptr, "QueryApplicationPlayStatisticsForSystem"},
36 {19, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystem"},
37 };
38 // clang-format on
39
40 RegisterHandlers(functions);
41}
42
43PDM_QRY::~PDM_QRY() = default;
44
45void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(HLERequestContext& ctx) {
46 IPC::RequestParser rp{ctx};
47 const auto unknown = rp.Pop<bool>();
48 rp.Pop<u8>(); // Padding
49 const auto application_id = rp.Pop<u64>();
50 const auto user_account_uid = rp.PopRaw<Common::UUID>();
51
52 // TODO(German77): Read statistics of the game
53 PlayStatistics statistics{
54 .application_id = application_id,
55 .total_launches = 1,
56 };
57
58 LOG_WARNING(Service_NS,
59 "(STUBBED) called. unknown={}. application_id=0x{:016X}, user_account_uid=0x{}",
60 unknown, application_id, user_account_uid.RawString());
61
62 IPC::ResponseBuilder rb{ctx, 12};
63 rb.Push(ResultSuccess);
64 rb.PushRaw(statistics);
65}
66
67} // namespace Service::NS
diff --git a/src/core/hle/service/ns/iplatform_service_manager.cpp b/src/core/hle/service/ns/platform_service_manager.cpp
index 46268be95..23cf05005 100644
--- a/src/core/hle/service/ns/iplatform_service_manager.cpp
+++ b/src/core/hle/service/ns/platform_service_manager.cpp
@@ -18,9 +18,9 @@
18#include "core/hle/kernel/k_shared_memory.h" 18#include "core/hle/kernel/k_shared_memory.h"
19#include "core/hle/kernel/kernel.h" 19#include "core/hle/kernel/kernel.h"
20#include "core/hle/kernel/physical_memory.h" 20#include "core/hle/kernel/physical_memory.h"
21#include "core/hle/service/cmif_serialization.h"
21#include "core/hle/service/filesystem/filesystem.h" 22#include "core/hle/service/filesystem/filesystem.h"
22#include "core/hle/service/ipc_helpers.h" 23#include "core/hle/service/ns/platform_service_manager.h"
23#include "core/hle/service/ns/iplatform_service_manager.h"
24 24
25namespace Service::NS { 25namespace Service::NS {
26 26
@@ -37,11 +37,6 @@ constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf
37constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; 37constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
38constexpr FontRegion EMPTY_REGION{0, 0}; 38constexpr FontRegion EMPTY_REGION{0, 0};
39 39
40enum class LoadState : u32 {
41 Loading = 0,
42 Done = 1,
43};
44
45static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMemory& output, 40static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMemory& output,
46 std::size_t& offset) { 41 std::size_t& offset) {
47 ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, 42 ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE,
@@ -138,13 +133,13 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch
138 : ServiceFramework{system_, service_name_}, impl{std::make_unique<Impl>()} { 133 : ServiceFramework{system_, service_name_}, impl{std::make_unique<Impl>()} {
139 // clang-format off 134 // clang-format off
140 static const FunctionInfo functions[] = { 135 static const FunctionInfo functions[] = {
141 {0, &IPlatformServiceManager::RequestLoad, "RequestLoad"}, 136 {0, D<&IPlatformServiceManager::RequestLoad>, "RequestLoad"},
142 {1, &IPlatformServiceManager::GetLoadState, "GetLoadState"}, 137 {1, D<&IPlatformServiceManager::GetLoadState>, "GetLoadState"},
143 {2, &IPlatformServiceManager::GetSize, "GetSize"}, 138 {2, D<&IPlatformServiceManager::GetSize>, "GetSize"},
144 {3, &IPlatformServiceManager::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, 139 {3, D<&IPlatformServiceManager::GetSharedMemoryAddressOffset>, "GetSharedMemoryAddressOffset"},
145 {4, &IPlatformServiceManager::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, 140 {4, D<&IPlatformServiceManager::GetSharedMemoryNativeHandle>, "GetSharedMemoryNativeHandle"},
146 {5, &IPlatformServiceManager::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, 141 {5, D<&IPlatformServiceManager::GetSharedFontInOrderOfPriority>, "GetSharedFontInOrderOfPriority"},
147 {6, &IPlatformServiceManager::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriorityForSystem"}, 142 {6, D<&IPlatformServiceManager::GetSharedFontInOrderOfPriority>, "GetSharedFontInOrderOfPriorityForSystem"},
148 {100, nullptr, "RequestApplicationFunctionAuthorization"}, 143 {100, nullptr, "RequestApplicationFunctionAuthorization"},
149 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, 144 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
150 {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"}, 145 {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"},
@@ -208,47 +203,33 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch
208 203
209IPlatformServiceManager::~IPlatformServiceManager() = default; 204IPlatformServiceManager::~IPlatformServiceManager() = default;
210 205
211void IPlatformServiceManager::RequestLoad(HLERequestContext& ctx) { 206Result IPlatformServiceManager::RequestLoad(SharedFontType type) {
212 IPC::RequestParser rp{ctx};
213 const u32 shared_font_type{rp.Pop<u32>()};
214 // Games don't call this so all fonts should be loaded 207 // Games don't call this so all fonts should be loaded
215 LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); 208 LOG_DEBUG(Service_NS, "called, shared_font_type={}", type);
216 209 R_SUCCEED();
217 IPC::ResponseBuilder rb{ctx, 2};
218 rb.Push(ResultSuccess);
219} 210}
220 211
221void IPlatformServiceManager::GetLoadState(HLERequestContext& ctx) { 212Result IPlatformServiceManager::GetLoadState(Out<LoadState> out_load_state, SharedFontType type) {
222 IPC::RequestParser rp{ctx}; 213 LOG_DEBUG(Service_NS, "called, shared_font_type={}", type);
223 const u32 font_id{rp.Pop<u32>()}; 214 *out_load_state = LoadState::Loaded;
224 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 215 R_SUCCEED();
225
226 IPC::ResponseBuilder rb{ctx, 3};
227 rb.Push(ResultSuccess);
228 rb.Push<u32>(static_cast<u32>(LoadState::Done));
229} 216}
230 217
231void IPlatformServiceManager::GetSize(HLERequestContext& ctx) { 218Result IPlatformServiceManager::GetSize(Out<u32> out_size, SharedFontType type) {
232 IPC::RequestParser rp{ctx}; 219 LOG_DEBUG(Service_NS, "called, shared_font_type={}", type);
233 const u32 font_id{rp.Pop<u32>()}; 220 *out_size = impl->GetSharedFontRegion(static_cast<size_t>(type)).size;
234 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 221 R_SUCCEED();
235
236 IPC::ResponseBuilder rb{ctx, 3};
237 rb.Push(ResultSuccess);
238 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
239} 222}
240 223
241void IPlatformServiceManager::GetSharedMemoryAddressOffset(HLERequestContext& ctx) { 224Result IPlatformServiceManager::GetSharedMemoryAddressOffset(Out<u32> out_shared_memory_offset,
242 IPC::RequestParser rp{ctx}; 225 SharedFontType type) {
243 const u32 font_id{rp.Pop<u32>()}; 226 LOG_DEBUG(Service_NS, "called, shared_font_type={}", type);
244 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 227 *out_shared_memory_offset = impl->GetSharedFontRegion(static_cast<size_t>(type)).offset;
245 228 R_SUCCEED();
246 IPC::ResponseBuilder rb{ctx, 3};
247 rb.Push(ResultSuccess);
248 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
249} 229}
250 230
251void IPlatformServiceManager::GetSharedMemoryNativeHandle(HLERequestContext& ctx) { 231Result IPlatformServiceManager::GetSharedMemoryNativeHandle(
232 OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_native_handle) {
252 // Map backing memory for the font data 233 // Map backing memory for the font data
253 LOG_DEBUG(Service_NS, "called"); 234 LOG_DEBUG(Service_NS, "called");
254 235
@@ -256,50 +237,37 @@ void IPlatformServiceManager::GetSharedMemoryNativeHandle(HLERequestContext& ctx
256 std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(), 237 std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(),
257 impl->shared_font->size()); 238 impl->shared_font->size());
258 239
259 IPC::ResponseBuilder rb{ctx, 2, 1}; 240 // FIXME: this shouldn't belong to the kernel
260 rb.Push(ResultSuccess); 241 *out_shared_memory_native_handle = &kernel.GetFontSharedMem();
261 rb.PushCopyObjects(&kernel.GetFontSharedMem()); 242 R_SUCCEED();
262} 243}
263 244
264void IPlatformServiceManager::GetSharedFontInOrderOfPriority(HLERequestContext& ctx) { 245Result IPlatformServiceManager::GetSharedFontInOrderOfPriority(
246 OutArray<u32, BufferAttr_HipcMapAlias> out_font_codes,
247 OutArray<u32, BufferAttr_HipcMapAlias> out_font_offsets,
248 OutArray<u32, BufferAttr_HipcMapAlias> out_font_sizes, Out<bool> out_fonts_are_loaded,
249 Out<u32> out_font_count, Set::LanguageCode language_code) {
250 LOG_DEBUG(Service_NS, "called, language_code={:#x}", language_code);
251
265 // The maximum number of elements that can be returned is 6. Regardless of the available fonts 252 // The maximum number of elements that can be returned is 6. Regardless of the available fonts
266 // or buffer size. 253 // or buffer size.
267 constexpr std::size_t MaxElementCount = 6; 254 constexpr size_t MaxElementCount = 6;
268 IPC::RequestParser rp{ctx};
269 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
270 const std::size_t font_codes_count =
271 std::min(MaxElementCount, ctx.GetWriteBufferNumElements<u32>(0));
272 const std::size_t font_offsets_count =
273 std::min(MaxElementCount, ctx.GetWriteBufferNumElements<u32>(1));
274 const std::size_t font_sizes_count =
275 std::min(MaxElementCount, ctx.GetWriteBufferNumElements<u32>(2));
276 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
277
278 IPC::ResponseBuilder rb{ctx, 4};
279 std::vector<u32> font_codes;
280 std::vector<u32> font_offsets;
281 std::vector<u32> font_sizes;
282 255
283 // TODO(ogniK): Have actual priority order 256 // TODO(ogniK): Have actual priority order
284 for (std::size_t i = 0; i < impl->shared_font_regions.size(); i++) { 257 const auto max_size = std::min({MaxElementCount, out_font_codes.size(), out_font_offsets.size(),
285 font_codes.push_back(static_cast<u32>(i)); 258 out_font_sizes.size(), impl->shared_font_regions.size()});
286 auto region = impl->GetSharedFontRegion(i);
287 font_offsets.push_back(region.offset);
288 font_sizes.push_back(region.size);
289 }
290 259
291 // Resize buffers if game requests smaller size output 260 for (size_t i = 0; i < max_size; i++) {
292 font_codes.resize(std::min(font_codes.size(), font_codes_count)); 261 auto region = impl->GetSharedFontRegion(i);
293 font_offsets.resize(std::min(font_offsets.size(), font_offsets_count));
294 font_sizes.resize(std::min(font_sizes.size(), font_sizes_count));
295 262
296 ctx.WriteBuffer(font_codes, 0); 263 out_font_codes[i] = static_cast<u32>(i);
297 ctx.WriteBuffer(font_offsets, 1); 264 out_font_offsets[i] = region.offset;
298 ctx.WriteBuffer(font_sizes, 2); 265 out_font_sizes[i] = region.size;
266 }
299 267
300 rb.Push(ResultSuccess); 268 *out_fonts_are_loaded = true;
301 rb.Push<u8>(static_cast<u8>(LoadState::Done)); // Fonts Loaded 269 *out_font_count = static_cast<u32>(max_size);
302 rb.Push<u32>(static_cast<u32>(font_codes.size())); 270 R_SUCCEED();
303} 271}
304 272
305} // namespace Service::NS 273} // namespace Service::NS
diff --git a/src/core/hle/service/ns/iplatform_service_manager.h b/src/core/hle/service/ns/platform_service_manager.h
index 03071e02b..b82c385a6 100644
--- a/src/core/hle/service/ns/iplatform_service_manager.h
+++ b/src/core/hle/service/ns/platform_service_manager.h
@@ -5,7 +5,9 @@
5 5
6#include <memory> 6#include <memory>
7#include <vector> 7#include <vector>
8#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10#include "core/hle/service/set/settings_types.h"
9 11
10namespace Service { 12namespace Service {
11 13
@@ -23,6 +25,20 @@ enum class FontArchives : u64 {
23 ChineseSimple = 0x0100000000000814, 25 ChineseSimple = 0x0100000000000814,
24}; 26};
25 27
28enum class SharedFontType : u32 {
29 JapanUSEuropeStandard = 0,
30 ChineseSimplified = 1,
31 ExtendedChineseSimplified = 2,
32 ChineseTraditional = 3,
33 KoreanHangul = 4,
34 NintendoExtended = 5,
35};
36
37enum class LoadState : u32 {
38 Loading = 0,
39 Loaded = 1,
40};
41
26constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ 42constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{
27 std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), 43 std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"),
28 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), 44 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"),
@@ -42,12 +58,17 @@ public:
42 ~IPlatformServiceManager() override; 58 ~IPlatformServiceManager() override;
43 59
44private: 60private:
45 void RequestLoad(HLERequestContext& ctx); 61 Result RequestLoad(SharedFontType type);
46 void GetLoadState(HLERequestContext& ctx); 62 Result GetLoadState(Out<LoadState> out_load_state, SharedFontType type);
47 void GetSize(HLERequestContext& ctx); 63 Result GetSize(Out<u32> out_size, SharedFontType type);
48 void GetSharedMemoryAddressOffset(HLERequestContext& ctx); 64 Result GetSharedMemoryAddressOffset(Out<u32> out_shared_memory_offset, SharedFontType type);
49 void GetSharedMemoryNativeHandle(HLERequestContext& ctx); 65 Result GetSharedMemoryNativeHandle(
50 void GetSharedFontInOrderOfPriority(HLERequestContext& ctx); 66 OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_native_handle);
67 Result GetSharedFontInOrderOfPriority(OutArray<u32, BufferAttr_HipcMapAlias> out_font_codes,
68 OutArray<u32, BufferAttr_HipcMapAlias> out_font_offsets,
69 OutArray<u32, BufferAttr_HipcMapAlias> out_font_sizes,
70 Out<bool> out_fonts_are_loaded, Out<u32> out_font_count,
71 Set::LanguageCode language_code);
51 72
52 struct Impl; 73 struct Impl;
53 std::unique_ptr<Impl> impl; 74 std::unique_ptr<Impl> impl;
diff --git a/src/core/hle/service/ns/query_service.cpp b/src/core/hle/service/ns/query_service.cpp
new file mode 100644
index 000000000..138400541
--- /dev/null
+++ b/src/core/hle/service/ns/query_service.cpp
@@ -0,0 +1,56 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "common/uuid.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/ns/query_service.h"
8#include "core/hle/service/service.h"
9
10namespace Service::NS {
11
12IQueryService::IQueryService(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, nullptr, "QueryAppletEvent"},
16 {1, nullptr, "QueryPlayStatistics"},
17 {2, nullptr, "QueryPlayStatisticsByUserAccountId"},
18 {3, nullptr, "QueryPlayStatisticsByNetworkServiceAccountId"},
19 {4, nullptr, "QueryPlayStatisticsByApplicationId"},
20 {5, D<&IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId>, "QueryPlayStatisticsByApplicationIdAndUserAccountId"},
21 {6, nullptr, "QueryPlayStatisticsByApplicationIdAndNetworkServiceAccountId"},
22 {7, nullptr, "QueryLastPlayTimeV0"},
23 {8, nullptr, "QueryPlayEvent"},
24 {9, nullptr, "GetAvailablePlayEventRange"},
25 {10, nullptr, "QueryAccountEvent"},
26 {11, nullptr, "QueryAccountPlayEvent"},
27 {12, nullptr, "GetAvailableAccountPlayEventRange"},
28 {13, nullptr, "QueryApplicationPlayStatisticsForSystemV0"},
29 {14, nullptr, "QueryRecentlyPlayedApplication"},
30 {15, nullptr, "GetRecentlyPlayedApplicationUpdateEvent"},
31 {16, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystemV0"},
32 {17, nullptr, "QueryLastPlayTime"},
33 {18, nullptr, "QueryApplicationPlayStatisticsForSystem"},
34 {19, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystem"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39}
40
41IQueryService::~IQueryService() = default;
42
43Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId(
44 Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id) {
45 // TODO(German77): Read statistics of the game
46 *out_play_statistics = {
47 .application_id = application_id,
48 .total_launches = 1,
49 };
50
51 LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id={:016X}, account_id={}",
52 unknown, application_id, account_id.uuid.FormattedString());
53 R_SUCCEED();
54}
55
56} // namespace Service::NS
diff --git a/src/core/hle/service/ns/pdm_qry.h b/src/core/hle/service/ns/query_service.h
index c98e01660..c4c82b752 100644
--- a/src/core/hle/service/ns/pdm_qry.h
+++ b/src/core/hle/service/ns/query_service.h
@@ -3,6 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/uuid.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/ns/ns_types.h"
6#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
7 10
8namespace Service::NS { 11namespace Service::NS {
@@ -20,13 +23,14 @@ struct PlayStatistics {
20}; 23};
21static_assert(sizeof(PlayStatistics) == 0x28, "PlayStatistics is an invalid size"); 24static_assert(sizeof(PlayStatistics) == 0x28, "PlayStatistics is an invalid size");
22 25
23class PDM_QRY final : public ServiceFramework<PDM_QRY> { 26class IQueryService final : public ServiceFramework<IQueryService> {
24public: 27public:
25 explicit PDM_QRY(Core::System& system_); 28 explicit IQueryService(Core::System& system_);
26 ~PDM_QRY() override; 29 ~IQueryService() override;
27 30
28private: 31private:
29 void QueryPlayStatisticsByApplicationIdAndUserAccountId(HLERequestContext& ctx); 32 Result QueryPlayStatisticsByApplicationIdAndUserAccountId(
33 Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id);
30}; 34};
31 35
32} // namespace Service::NS 36} // namespace Service::NS
diff --git a/src/core/hle/service/ns/read_only_application_control_data_interface.cpp b/src/core/hle/service/ns/read_only_application_control_data_interface.cpp
new file mode 100644
index 000000000..9b2ca94a4
--- /dev/null
+++ b/src/core/hle/service/ns/read_only_application_control_data_interface.cpp
@@ -0,0 +1,122 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "core/file_sys/control_metadata.h"
6#include "core/file_sys/patch_manager.h"
7#include "core/file_sys/vfs/vfs.h"
8#include "core/hle/service/cmif_serialization.h"
9#include "core/hle/service/ns/language.h"
10#include "core/hle/service/ns/ns_results.h"
11#include "core/hle/service/ns/read_only_application_control_data_interface.h"
12#include "core/hle/service/set/settings_server.h"
13
14namespace Service::NS {
15
16IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
17 Core::System& system_)
18 : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData>, "GetApplicationControlData"},
22 {1, D<&IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"},
23 {2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"},
24 {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
25 {4, nullptr, "SelectApplicationDesiredLanguage"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default;
33
34Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
35 OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size,
36 ApplicationControlSource application_control_source, u64 application_id) {
37 LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}",
38 application_control_source, application_id);
39
40 const FileSys::PatchManager pm{application_id, system.GetFileSystemController(),
41 system.GetContentProvider()};
42 const auto control = pm.GetControlMetadata();
43 const auto size = out_buffer.size();
44
45 const auto icon_size = control.second ? control.second->GetSize() : 0;
46 const auto total_size = sizeof(FileSys::RawNACP) + icon_size;
47
48 if (size < total_size) {
49 LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
50 size);
51 R_THROW(ResultUnknown);
52 }
53
54 if (control.first != nullptr) {
55 const auto bytes = control.first->GetRawBytes();
56 std::memcpy(out_buffer.data(), bytes.data(), bytes.size());
57 } else {
58 LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero",
59 application_id);
60 std::memset(out_buffer.data(), 0, sizeof(FileSys::RawNACP));
61 }
62
63 if (control.second != nullptr) {
64 control.second->Read(out_buffer.data() + sizeof(FileSys::RawNACP), icon_size);
65 } else {
66 LOG_WARNING(Service_NS, "missing icon data for application_id={:016X}", application_id);
67 }
68
69 *out_actual_size = static_cast<u32>(total_size);
70 R_SUCCEED();
71}
72
73Result IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage(
74 Out<ApplicationLanguage> out_desired_language, u32 supported_languages) {
75 LOG_INFO(Service_NS, "called with supported_languages={:08X}", supported_languages);
76
77 // Get language code from settings
78 const auto language_code =
79 Set::GetLanguageCodeFromIndex(static_cast<s32>(Settings::values.language_index.GetValue()));
80
81 // Convert to application language, get priority list
82 const auto application_language = ConvertToApplicationLanguage(language_code);
83 if (application_language == std::nullopt) {
84 LOG_ERROR(Service_NS, "Could not convert application language! language_code={}",
85 language_code);
86 R_THROW(Service::NS::ResultApplicationLanguageNotFound);
87 }
88 const auto priority_list = GetApplicationLanguagePriorityList(*application_language);
89 if (!priority_list) {
90 LOG_ERROR(Service_NS,
91 "Could not find application language priorities! application_language={}",
92 *application_language);
93 R_THROW(Service::NS::ResultApplicationLanguageNotFound);
94 }
95
96 // Try to find a valid language.
97 for (const auto lang : *priority_list) {
98 const auto supported_flag = GetSupportedLanguageFlag(lang);
99 if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
100 *out_desired_language = lang;
101 R_SUCCEED();
102 }
103 }
104
105 LOG_ERROR(Service_NS, "Could not find a valid language! supported_languages={:08X}",
106 supported_languages);
107 R_THROW(Service::NS::ResultApplicationLanguageNotFound);
108}
109
110Result IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode(
111 Out<u64> out_language_code, ApplicationLanguage application_language) {
112 const auto language_code = ConvertToLanguageCode(application_language);
113 if (language_code == std::nullopt) {
114 LOG_ERROR(Service_NS, "Language not found! application_language={}", application_language);
115 R_THROW(Service::NS::ResultApplicationLanguageNotFound);
116 }
117
118 *out_language_code = static_cast<u64>(*language_code);
119 R_SUCCEED();
120}
121
122} // namespace Service::NS
diff --git a/src/core/hle/service/ns/read_only_application_control_data_interface.h b/src/core/hle/service/ns/read_only_application_control_data_interface.h
new file mode 100644
index 000000000..ac099435a
--- /dev/null
+++ b/src/core/hle/service/ns/read_only_application_control_data_interface.h
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/ns/language.h"
8#include "core/hle/service/ns/ns_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::NS {
12
13class IReadOnlyApplicationControlDataInterface final
14 : public ServiceFramework<IReadOnlyApplicationControlDataInterface> {
15public:
16 explicit IReadOnlyApplicationControlDataInterface(Core::System& system_);
17 ~IReadOnlyApplicationControlDataInterface() override;
18
19public:
20 Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
21 Out<u32> out_actual_size,
22 ApplicationControlSource application_control_source,
23 u64 application_id);
24 Result GetApplicationDesiredLanguage(Out<ApplicationLanguage> out_desired_language,
25 u32 supported_languages);
26 Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code,
27 ApplicationLanguage application_language);
28};
29
30} // namespace Service::NS
diff --git a/src/core/hle/service/ns/read_only_application_record_interface.cpp b/src/core/hle/service/ns/read_only_application_record_interface.cpp
new file mode 100644
index 000000000..816a1e1dc
--- /dev/null
+++ b/src/core/hle/service/ns/read_only_application_record_interface.cpp
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ns/read_only_application_record_interface.h"
6
7namespace Service::NS {
8
9IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::System& system_)
10 : ServiceFramework{system_, "IReadOnlyApplicationRecordInterface"} {
11 static const FunctionInfo functions[] = {
12 {0, D<&IReadOnlyApplicationRecordInterface::HasApplicationRecord>, "HasApplicationRecord"},
13 {1, nullptr, "NotifyApplicationFailure"},
14 {2, D<&IReadOnlyApplicationRecordInterface::IsDataCorruptedResult>,
15 "IsDataCorruptedResult"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IReadOnlyApplicationRecordInterface::~IReadOnlyApplicationRecordInterface() = default;
23
24Result IReadOnlyApplicationRecordInterface::HasApplicationRecord(
25 Out<bool> out_has_application_record, u64 program_id) {
26 LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:016X}", program_id);
27 *out_has_application_record = true;
28 R_SUCCEED();
29}
30
31Result IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(
32 Out<bool> out_is_data_corrupted_result, Result result) {
33 LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue());
34 *out_is_data_corrupted_result = false;
35 R_SUCCEED();
36}
37
38} // namespace Service::NS
diff --git a/src/core/hle/service/ns/read_only_application_record_interface.h b/src/core/hle/service/ns/read_only_application_record_interface.h
new file mode 100644
index 000000000..d06e8f5e6
--- /dev/null
+++ b/src/core/hle/service/ns/read_only_application_record_interface.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::NS {
10
11class IReadOnlyApplicationRecordInterface final
12 : public ServiceFramework<IReadOnlyApplicationRecordInterface> {
13public:
14 explicit IReadOnlyApplicationRecordInterface(Core::System& system_);
15 ~IReadOnlyApplicationRecordInterface() override;
16
17private:
18 Result HasApplicationRecord(Out<bool> out_has_application_record, u64 program_id);
19 Result IsDataCorruptedResult(Out<bool> out_is_data_corrupted_result, Result result);
20};
21
22} // namespace Service::NS
diff --git a/src/core/hle/service/ns/service_getter_interface.cpp b/src/core/hle/service/ns/service_getter_interface.cpp
new file mode 100644
index 000000000..1a3dd7166
--- /dev/null
+++ b/src/core/hle/service/ns/service_getter_interface.cpp
@@ -0,0 +1,120 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ns/account_proxy_interface.h"
6#include "core/hle/service/ns/application_manager_interface.h"
7#include "core/hle/service/ns/application_version_interface.h"
8#include "core/hle/service/ns/content_management_interface.h"
9#include "core/hle/service/ns/document_interface.h"
10#include "core/hle/service/ns/download_task_interface.h"
11#include "core/hle/service/ns/dynamic_rights_interface.h"
12#include "core/hle/service/ns/ecommerce_interface.h"
13#include "core/hle/service/ns/factory_reset_interface.h"
14#include "core/hle/service/ns/read_only_application_control_data_interface.h"
15#include "core/hle/service/ns/read_only_application_record_interface.h"
16#include "core/hle/service/ns/service_getter_interface.h"
17
18namespace Service::NS {
19
20IServiceGetterInterface::IServiceGetterInterface(Core::System& system_, const char* name)
21 : ServiceFramework{system_, name} {
22 // clang-format off
23 static const FunctionInfo functions[] = {
24 {7988, D<&IServiceGetterInterface::GetDynamicRightsInterface>, "GetDynamicRightsInterface"},
25 {7989, D<&IServiceGetterInterface::GetReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"},
26 {7991, D<&IServiceGetterInterface::GetReadOnlyApplicationRecordInterface>, "GetReadOnlyApplicationRecordInterface"},
27 {7992, D<&IServiceGetterInterface::GetECommerceInterface>, "GetECommerceInterface"},
28 {7993, D<&IServiceGetterInterface::GetApplicationVersionInterface>, "GetApplicationVersionInterface"},
29 {7994, D<&IServiceGetterInterface::GetFactoryResetInterface>, "GetFactoryResetInterface"},
30 {7995, D<&IServiceGetterInterface::GetAccountProxyInterface>, "GetAccountProxyInterface"},
31 {7996, D<&IServiceGetterInterface::GetApplicationManagerInterface>, "GetApplicationManagerInterface"},
32 {7997, D<&IServiceGetterInterface::GetDownloadTaskInterface>, "GetDownloadTaskInterface"},
33 {7998, D<&IServiceGetterInterface::GetContentManagementInterface>, "GetContentManagementInterface"},
34 {7999, D<&IServiceGetterInterface::GetDocumentInterface>, "GetDocumentInterface"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39}
40
41IServiceGetterInterface::~IServiceGetterInterface() = default;
42
43Result IServiceGetterInterface::GetDynamicRightsInterface(
44 Out<SharedPointer<IDynamicRightsInterface>> out_interface) {
45 LOG_DEBUG(Service_NS, "called");
46 *out_interface = std::make_shared<IDynamicRightsInterface>(system);
47 R_SUCCEED();
48}
49
50Result IServiceGetterInterface::GetReadOnlyApplicationControlDataInterface(
51 Out<SharedPointer<IReadOnlyApplicationControlDataInterface>> out_interface) {
52 LOG_DEBUG(Service_NS, "called");
53 *out_interface = std::make_shared<IReadOnlyApplicationControlDataInterface>(system);
54 R_SUCCEED();
55}
56
57Result IServiceGetterInterface::GetReadOnlyApplicationRecordInterface(
58 Out<SharedPointer<IReadOnlyApplicationRecordInterface>> out_interface) {
59 LOG_DEBUG(Service_NS, "called");
60 *out_interface = std::make_shared<IReadOnlyApplicationRecordInterface>(system);
61 R_SUCCEED();
62}
63
64Result IServiceGetterInterface::GetECommerceInterface(
65 Out<SharedPointer<IECommerceInterface>> out_interface) {
66 LOG_DEBUG(Service_NS, "called");
67 *out_interface = std::make_shared<IECommerceInterface>(system);
68 R_SUCCEED();
69}
70
71Result IServiceGetterInterface::GetApplicationVersionInterface(
72 Out<SharedPointer<IApplicationVersionInterface>> out_interface) {
73 LOG_DEBUG(Service_NS, "called");
74 *out_interface = std::make_shared<IApplicationVersionInterface>(system);
75 R_SUCCEED();
76}
77
78Result IServiceGetterInterface::GetFactoryResetInterface(
79 Out<SharedPointer<IFactoryResetInterface>> out_interface) {
80 LOG_DEBUG(Service_NS, "called");
81 *out_interface = std::make_shared<IFactoryResetInterface>(system);
82 R_SUCCEED();
83}
84
85Result IServiceGetterInterface::GetAccountProxyInterface(
86 Out<SharedPointer<IAccountProxyInterface>> out_interface) {
87 LOG_DEBUG(Service_NS, "called");
88 *out_interface = std::make_shared<IAccountProxyInterface>(system);
89 R_SUCCEED();
90}
91
92Result IServiceGetterInterface::GetApplicationManagerInterface(
93 Out<SharedPointer<IApplicationManagerInterface>> out_interface) {
94 LOG_DEBUG(Service_NS, "called");
95 *out_interface = std::make_shared<IApplicationManagerInterface>(system);
96 R_SUCCEED();
97}
98
99Result IServiceGetterInterface::GetDownloadTaskInterface(
100 Out<SharedPointer<IDownloadTaskInterface>> out_interface) {
101 LOG_DEBUG(Service_NS, "called");
102 *out_interface = std::make_shared<IDownloadTaskInterface>(system);
103 R_SUCCEED();
104}
105
106Result IServiceGetterInterface::GetContentManagementInterface(
107 Out<SharedPointer<IContentManagementInterface>> out_interface) {
108 LOG_DEBUG(Service_NS, "called");
109 *out_interface = std::make_shared<IContentManagementInterface>(system);
110 R_SUCCEED();
111}
112
113Result IServiceGetterInterface::GetDocumentInterface(
114 Out<SharedPointer<IDocumentInterface>> out_interface) {
115 LOG_DEBUG(Service_NS, "called");
116 *out_interface = std::make_shared<IDocumentInterface>(system);
117 R_SUCCEED();
118}
119
120} // namespace Service::NS
diff --git a/src/core/hle/service/ns/service_getter_interface.h b/src/core/hle/service/ns/service_getter_interface.h
new file mode 100644
index 000000000..bbc18d444
--- /dev/null
+++ b/src/core/hle/service/ns/service_getter_interface.h
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::NS {
10
11class IDynamicRightsInterface;
12class IReadOnlyApplicationControlDataInterface;
13class IReadOnlyApplicationRecordInterface;
14class IECommerceInterface;
15class IApplicationVersionInterface;
16class IFactoryResetInterface;
17class IAccountProxyInterface;
18class IApplicationManagerInterface;
19class IDownloadTaskInterface;
20class IContentManagementInterface;
21class IDocumentInterface;
22
23class IServiceGetterInterface : public ServiceFramework<IServiceGetterInterface> {
24public:
25 explicit IServiceGetterInterface(Core::System& system_, const char* name);
26 ~IServiceGetterInterface() override;
27
28public:
29 Result GetDynamicRightsInterface(Out<SharedPointer<IDynamicRightsInterface>> out_interface);
30 Result GetReadOnlyApplicationControlDataInterface(
31 Out<SharedPointer<IReadOnlyApplicationControlDataInterface>> out_interface);
32 Result GetReadOnlyApplicationRecordInterface(
33 Out<SharedPointer<IReadOnlyApplicationRecordInterface>> out_interface);
34 Result GetECommerceInterface(Out<SharedPointer<IECommerceInterface>> out_interface);
35 Result GetApplicationVersionInterface(
36 Out<SharedPointer<IApplicationVersionInterface>> out_interface);
37 Result GetFactoryResetInterface(Out<SharedPointer<IFactoryResetInterface>> out_interface);
38 Result GetAccountProxyInterface(Out<SharedPointer<IAccountProxyInterface>> out_interface);
39 Result GetApplicationManagerInterface(
40 Out<SharedPointer<IApplicationManagerInterface>> out_interface);
41 Result GetDownloadTaskInterface(Out<SharedPointer<IDownloadTaskInterface>> out_interface);
42 Result GetContentManagementInterface(
43 Out<SharedPointer<IContentManagementInterface>> out_interface);
44 Result GetDocumentInterface(Out<SharedPointer<IDocumentInterface>> out_interface);
45};
46
47} // namespace Service::NS
diff --git a/src/core/hle/service/ns/system_update_control.cpp b/src/core/hle/service/ns/system_update_control.cpp
new file mode 100644
index 000000000..f5f5cfd90
--- /dev/null
+++ b/src/core/hle/service/ns/system_update_control.cpp
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ns/system_update_control.h"
6
7namespace Service::NS {
8
9ISystemUpdateControl::ISystemUpdateControl(Core::System& system_)
10 : ServiceFramework{system_, "ISystemUpdateControl"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "HasDownloaded"},
14 {1, nullptr, "RequestCheckLatestUpdate"},
15 {2, nullptr, "RequestDownloadLatestUpdate"},
16 {3, nullptr, "GetDownloadProgress"},
17 {4, nullptr, "ApplyDownloadedUpdate"},
18 {5, nullptr, "RequestPrepareCardUpdate"},
19 {6, nullptr, "GetPrepareCardUpdateProgress"},
20 {7, nullptr, "HasPreparedCardUpdate"},
21 {8, nullptr, "ApplyCardUpdate"},
22 {9, nullptr, "GetDownloadedEulaDataSize"},
23 {10, nullptr, "GetDownloadedEulaData"},
24 {11, nullptr, "SetupCardUpdate"},
25 {12, nullptr, "GetPreparedCardUpdateEulaDataSize"},
26 {13, nullptr, "GetPreparedCardUpdateEulaData"},
27 {14, nullptr, "SetupCardUpdateViaSystemUpdater"},
28 {15, nullptr, "HasReceived"},
29 {16, nullptr, "RequestReceiveSystemUpdate"},
30 {17, nullptr, "GetReceiveProgress"},
31 {18, nullptr, "ApplyReceivedUpdate"},
32 {19, nullptr, "GetReceivedEulaDataSize"},
33 {20, nullptr, "GetReceivedEulaData"},
34 {21, nullptr, "SetupToReceiveSystemUpdate"},
35 {22, nullptr, "RequestCheckLatestUpdateIncludesRebootlessUpdate"},
36 };
37 // clang-format on
38
39 RegisterHandlers(functions);
40}
41
42ISystemUpdateControl::~ISystemUpdateControl() = default;
43
44} // namespace Service::NS
diff --git a/src/core/hle/service/ns/system_update_control.h b/src/core/hle/service/ns/system_update_control.h
new file mode 100644
index 000000000..a30a09000
--- /dev/null
+++ b/src/core/hle/service/ns/system_update_control.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::NS {
9
10class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> {
11public:
12 explicit ISystemUpdateControl(Core::System& system_);
13 ~ISystemUpdateControl() override;
14};
15
16} // namespace Service::NS
diff --git a/src/core/hle/service/ns/system_update_interface.cpp b/src/core/hle/service/ns/system_update_interface.cpp
new file mode 100644
index 000000000..7e22ca3db
--- /dev/null
+++ b/src/core/hle/service/ns/system_update_interface.cpp
@@ -0,0 +1,61 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ns/system_update_control.h"
6#include "core/hle/service/ns/system_update_interface.h"
7
8namespace Service::NS {
9
10ISystemUpdateInterface::ISystemUpdateInterface(Core::System& system_)
11 : ServiceFramework{system_, "ns:su"}, service_context{system_, "ns:su"},
12 update_notification_event{service_context} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, D<&ISystemUpdateInterface::GetBackgroundNetworkUpdateState>, "GetBackgroundNetworkUpdateState"},
16 {1, D<&ISystemUpdateInterface::OpenSystemUpdateControl>, "OpenSystemUpdateControl"},
17 {2, nullptr, "NotifyExFatDriverRequired"},
18 {3, nullptr, "ClearExFatDriverStatusForDebug"},
19 {4, nullptr, "RequestBackgroundNetworkUpdate"},
20 {5, nullptr, "NotifyBackgroundNetworkUpdate"},
21 {6, nullptr, "NotifyExFatDriverDownloadedForDebug"},
22 {9, D<&ISystemUpdateInterface::GetSystemUpdateNotificationEventForContentDelivery>, "GetSystemUpdateNotificationEventForContentDelivery"},
23 {10, nullptr, "NotifySystemUpdateForContentDelivery"},
24 {11, nullptr, "PrepareShutdown"},
25 {12, nullptr, "Unknown12"},
26 {13, nullptr, "Unknown13"},
27 {14, nullptr, "Unknown14"},
28 {15, nullptr, "Unknown15"},
29 {16, nullptr, "DestroySystemUpdateTask"},
30 {17, nullptr, "RequestSendSystemUpdate"},
31 {18, nullptr, "GetSendSystemUpdateProgress"},
32 };
33 // clang-format on
34
35 RegisterHandlers(functions);
36}
37
38ISystemUpdateInterface::~ISystemUpdateInterface() = default;
39
40Result ISystemUpdateInterface::GetBackgroundNetworkUpdateState(
41 Out<BackgroundNetworkUpdateState> out_background_network_update_state) {
42 LOG_WARNING(Service_AM, "(STUBBED) called");
43 *out_background_network_update_state = BackgroundNetworkUpdateState::None;
44 R_SUCCEED();
45}
46
47Result ISystemUpdateInterface::OpenSystemUpdateControl(
48 Out<SharedPointer<ISystemUpdateControl>> out_system_update_control) {
49 LOG_WARNING(Service_NS, "(STUBBED) called");
50 *out_system_update_control = std::make_shared<ISystemUpdateControl>(system);
51 R_SUCCEED();
52}
53
54Result ISystemUpdateInterface::GetSystemUpdateNotificationEventForContentDelivery(
55 OutCopyHandle<Kernel::KReadableEvent> out_event) {
56 LOG_WARNING(Service_NS, "(STUBBED) called");
57 *out_event = update_notification_event.GetHandle();
58 R_SUCCEED();
59}
60
61} // namespace Service::NS
diff --git a/src/core/hle/service/ns/system_update_interface.h b/src/core/hle/service/ns/system_update_interface.h
new file mode 100644
index 000000000..36a2880ec
--- /dev/null
+++ b/src/core/hle/service/ns/system_update_interface.h
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/ns/ns_types.h"
9#include "core/hle/service/os/event.h"
10#include "core/hle/service/service.h"
11
12namespace Kernel {
13class KReadableEvent;
14}
15
16namespace Service::NS {
17
18class ISystemUpdateControl;
19
20class ISystemUpdateInterface final : public ServiceFramework<ISystemUpdateInterface> {
21public:
22 explicit ISystemUpdateInterface(Core::System& system_);
23 ~ISystemUpdateInterface() override;
24
25private:
26 Result GetBackgroundNetworkUpdateState(
27 Out<BackgroundNetworkUpdateState> out_background_network_update_state);
28 Result OpenSystemUpdateControl(
29 Out<SharedPointer<ISystemUpdateControl>> out_system_update_control);
30 Result GetSystemUpdateNotificationEventForContentDelivery(
31 OutCopyHandle<Kernel::KReadableEvent> out_event);
32
33private:
34 KernelHelpers::ServiceContext service_context;
35 Event update_notification_event;
36};
37
38} // namespace Service::NS
diff --git a/src/core/hle/service/ns/vulnerability_manager_interface.cpp b/src/core/hle/service/ns/vulnerability_manager_interface.cpp
new file mode 100644
index 000000000..69c21fb89
--- /dev/null
+++ b/src/core/hle/service/ns/vulnerability_manager_interface.cpp
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ns/vulnerability_manager_interface.h"
6
7namespace Service::NS {
8
9IVulnerabilityManagerInterface::IVulnerabilityManagerInterface(Core::System& system_)
10 : ServiceFramework{system_, "ns:vm"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {1200, D<&IVulnerabilityManagerInterface::NeedsUpdateVulnerability>, "NeedsUpdateVulnerability"},
14 {1201, nullptr, "UpdateSafeSystemVersionForDebug"},
15 {1202, nullptr, "GetSafeSystemVersion"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IVulnerabilityManagerInterface::~IVulnerabilityManagerInterface() = default;
23
24Result IVulnerabilityManagerInterface::NeedsUpdateVulnerability(
25 Out<bool> out_needs_update_vulnerability) {
26 LOG_WARNING(Service_NS, "(STUBBED) called");
27 *out_needs_update_vulnerability = false;
28 R_SUCCEED();
29}
30
31} // namespace Service::NS
diff --git a/src/core/hle/service/ns/vulnerability_manager_interface.h b/src/core/hle/service/ns/vulnerability_manager_interface.h
new file mode 100644
index 000000000..c689cf7ec
--- /dev/null
+++ b/src/core/hle/service/ns/vulnerability_manager_interface.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::NS {
10
11class IVulnerabilityManagerInterface final
12 : public ServiceFramework<IVulnerabilityManagerInterface> {
13public:
14 explicit IVulnerabilityManagerInterface(Core::System& system_);
15 ~IVulnerabilityManagerInterface() override;
16
17private:
18 Result NeedsUpdateVulnerability(Out<bool> out_needs_update_vulnerability);
19};
20
21} // namespace Service::NS
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 250d01de3..0265d55f2 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -92,11 +92,11 @@ NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_a
92 92
93 bool must_unmark_fail = !is_allocation; 93 bool must_unmark_fail = !is_allocation;
94 const u32 event_id = params.value.raw; 94 const u32 event_id = params.value.raw;
95 SCOPE_EXIT({ 95 SCOPE_EXIT {
96 if (must_unmark_fail) { 96 if (must_unmark_fail) {
97 events[event_id].fails = 0; 97 events[event_id].fails = 0;
98 } 98 }
99 }); 99 };
100 100
101 const u32 fence_id = static_cast<u32>(params.fence.id); 101 const u32 fence_id = static_cast<u32>(params.fence.id);
102 102
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index cb256e5b4..03eb507b9 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -42,7 +42,7 @@ void EventInterface::FreeEvent(Kernel::KEvent* event) {
42 module.service_context.CloseEvent(event); 42 module.service_context.CloseEvent(event);
43} 43}
44 44
45void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { 45void LoopProcess(Core::System& system) {
46 auto server_manager = std::make_unique<ServerManager>(system); 46 auto server_manager = std::make_unique<ServerManager>(system);
47 auto module = std::make_shared<Module>(system); 47 auto module = std::make_shared<Module>(system);
48 const auto NvdrvInterfaceFactoryForApplication = [&, module] { 48 const auto NvdrvInterfaceFactoryForApplication = [&, module] {
@@ -62,7 +62,6 @@ void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
62 server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules); 62 server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules);
63 server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting); 63 server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting);
64 server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system)); 64 server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system));
65 nvnflinger.SetNVDrvInstance(module);
66 ServerManager::RunServer(std::move(server_manager)); 65 ServerManager::RunServer(std::move(server_manager));
67} 66}
68 67
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index c594f0e5e..b76f81e59 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -10,13 +10,11 @@
10#include <span> 10#include <span>
11#include <string> 11#include <string>
12#include <unordered_map> 12#include <unordered_map>
13#include <vector>
14 13
15#include "common/common_types.h" 14#include "common/common_types.h"
16#include "core/hle/service/kernel_helpers.h" 15#include "core/hle/service/kernel_helpers.h"
17#include "core/hle/service/nvdrv/core/container.h" 16#include "core/hle/service/nvdrv/core/container.h"
18#include "core/hle/service/nvdrv/nvdata.h" 17#include "core/hle/service/nvdrv/nvdata.h"
19#include "core/hle/service/nvnflinger/ui/fence.h"
20#include "core/hle/service/service.h" 18#include "core/hle/service/service.h"
21 19
22namespace Core { 20namespace Core {
@@ -27,10 +25,6 @@ namespace Kernel {
27class KEvent; 25class KEvent;
28} 26}
29 27
30namespace Service::Nvnflinger {
31class Nvnflinger;
32}
33
34namespace Service::Nvidia { 28namespace Service::Nvidia {
35 29
36namespace NvCore { 30namespace NvCore {
@@ -99,7 +93,6 @@ public:
99 93
100private: 94private:
101 friend class EventInterface; 95 friend class EventInterface;
102 friend class Service::Nvnflinger::Nvnflinger;
103 96
104 /// Manages syncpoints on the host 97 /// Manages syncpoints on the host
105 NvCore::Container container; 98 NvCore::Container container;
@@ -118,6 +111,6 @@ private:
118 std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders; 111 std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders;
119}; 112};
120 113
121void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system); 114void LoopProcess(Core::System& system);
122 115
123} // namespace Service::Nvidia 116} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index ffe72f281..258970fd5 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -154,10 +154,10 @@ void NVDRV::Close(HLERequestContext& ctx) {
154void NVDRV::Initialize(HLERequestContext& ctx) { 154void NVDRV::Initialize(HLERequestContext& ctx) {
155 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 155 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
156 IPC::ResponseBuilder rb{ctx, 3}; 156 IPC::ResponseBuilder rb{ctx, 3};
157 SCOPE_EXIT({ 157 SCOPE_EXIT {
158 rb.Push(ResultSuccess); 158 rb.Push(ResultSuccess);
159 rb.PushEnum(NvResult::Success); 159 rb.PushEnum(NvResult::Success);
160 }); 160 };
161 161
162 if (is_initialized) { 162 if (is_initialized) {
163 // No need to initialize again 163 // No need to initialize again
@@ -263,8 +263,10 @@ NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char*
263} 263}
264 264
265NVDRV::~NVDRV() { 265NVDRV::~NVDRV() {
266 auto& container = nvdrv->GetContainer(); 266 if (is_initialized) {
267 container.CloseSession(session_id); 267 auto& container = nvdrv->GetContainer();
268 container.CloseSession(session_id);
269 }
268} 270}
269 271
270} // namespace Service::Nvidia 272} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h
index f2195ae1e..c72f92597 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.h
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.h
@@ -16,6 +16,10 @@ public:
16 explicit NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name); 16 explicit NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name);
17 ~NVDRV() override; 17 ~NVDRV() override;
18 18
19 std::shared_ptr<Module> GetModule() const {
20 return nvdrv;
21 }
22
19private: 23private:
20 void Open(HLERequestContext& ctx); 24 void Open(HLERequestContext& ctx);
21 void Ioctl1(HLERequestContext& ctx); 25 void Ioctl1(HLERequestContext& ctx);
diff --git a/src/core/hle/service/nvnflinger/binder.h b/src/core/hle/service/nvnflinger/binder.h
index 179938192..124accb94 100644
--- a/src/core/hle/service/nvnflinger/binder.h
+++ b/src/core/hle/service/nvnflinger/binder.h
@@ -20,29 +20,12 @@ class HLERequestContext;
20 20
21namespace Service::android { 21namespace Service::android {
22 22
23enum class TransactionId {
24 RequestBuffer = 1,
25 SetBufferCount = 2,
26 DequeueBuffer = 3,
27 DetachBuffer = 4,
28 DetachNextBuffer = 5,
29 AttachBuffer = 6,
30 QueueBuffer = 7,
31 CancelBuffer = 8,
32 Query = 9,
33 Connect = 10,
34 Disconnect = 11,
35 AllocateBuffers = 13,
36 SetPreallocatedBuffer = 14,
37 GetBufferHistory = 17,
38};
39
40class IBinder { 23class IBinder {
41public: 24public:
42 virtual ~IBinder() = default; 25 virtual ~IBinder() = default;
43 virtual void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data, 26 virtual void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
44 std::span<u8> parcel_reply) = 0; 27 u32 flags) = 0;
45 virtual Kernel::KReadableEvent& GetNativeHandle() = 0; 28 virtual Kernel::KReadableEvent* GetNativeHandle(u32 type_id) = 0;
46}; 29};
47 30
48} // namespace Service::android 31} // namespace Service::android
diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
index cf151ea3a..123507123 100644
--- a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
@@ -12,7 +12,7 @@
12 12
13namespace Service::android { 13namespace Service::android {
14 14
15BufferItemConsumer::BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer_) 15BufferItemConsumer::BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer_)
16 : ConsumerBase{std::move(consumer_)} {} 16 : ConsumerBase{std::move(consumer_)} {}
17 17
18Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, 18Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.h b/src/core/hle/service/nvnflinger/buffer_item_consumer.h
index e0c6b3604..9f95c9280 100644
--- a/src/core/hle/service/nvnflinger/buffer_item_consumer.h
+++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.h
@@ -19,7 +19,7 @@ class BufferItem;
19 19
20class BufferItemConsumer final : public ConsumerBase { 20class BufferItemConsumer final : public ConsumerBase {
21public: 21public:
22 explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer); 22 explicit BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer);
23 Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, 23 Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
24 bool wait_for_fence = true); 24 bool wait_for_fence = true);
25 Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence); 25 Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence);
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
index bbe8e06d4..3bc23aa97 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
@@ -4,12 +4,13 @@
4// Parts of this implementation were based on: 4// Parts of this implementation were based on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp 5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
6 6
7#include "common/assert.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "core/hle/service/nvnflinger/buffer_item.h" 9#include "core/hle/service/nvnflinger/buffer_item.h"
9#include "core/hle/service/nvnflinger/buffer_queue_consumer.h" 10#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
10#include "core/hle/service/nvnflinger/buffer_queue_core.h" 11#include "core/hle/service/nvnflinger/buffer_queue_core.h"
12#include "core/hle/service/nvnflinger/parcel.h"
11#include "core/hle/service/nvnflinger/producer_listener.h" 13#include "core/hle/service/nvnflinger/producer_listener.h"
12#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
13 14
14namespace Service::android { 15namespace Service::android {
15 16
@@ -254,4 +255,77 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
254 return Status::NoError; 255 return Status::NoError;
255} 256}
256 257
258void BufferQueueConsumer::Transact(u32 code, std::span<const u8> parcel_data,
259 std::span<u8> parcel_reply, u32 flags) {
260 // Values used by BnGraphicBufferConsumer onTransact
261 enum class TransactionId {
262 AcquireBuffer = 1,
263 DetachBuffer = 2,
264 AttachBuffer = 3,
265 ReleaseBuffer = 4,
266 ConsumerConnect = 5,
267 ConsumerDisconnect = 6,
268 GetReleasedBuffers = 7,
269 SetDefaultBufferSize = 8,
270 SetDefaultMaxBufferCount = 9,
271 DisableAsyncBuffer = 10,
272 SetMaxAcquiredBufferCount = 11,
273 SetConsumerName = 12,
274 SetDefaultBufferFormat = 13,
275 SetConsumerUsageBits = 14,
276 SetTransformHint = 15,
277 GetSidebandStream = 16,
278 Unknown18 = 18,
279 Unknown20 = 20,
280 };
281
282 Status status{Status::NoError};
283 InputParcel parcel_in{parcel_data};
284 OutputParcel parcel_out{};
285
286 switch (static_cast<TransactionId>(code)) {
287 case TransactionId::AcquireBuffer: {
288 BufferItem item;
289 const s64 present_when = parcel_in.Read<s64>();
290
291 status = AcquireBuffer(&item, std::chrono::nanoseconds{present_when});
292
293 // TODO: can't write this directly, needs a flattener for the sp<GraphicBuffer>
294 // parcel_out.WriteFlattened(item);
295 UNREACHABLE();
296 }
297 case TransactionId::ReleaseBuffer: {
298 const s32 slot = parcel_in.Read<s32>();
299 const u64 frame_number = parcel_in.Read<u64>();
300 const auto release_fence = parcel_in.ReadFlattened<Fence>();
301
302 status = ReleaseBuffer(slot, frame_number, release_fence);
303
304 break;
305 }
306 case TransactionId::GetReleasedBuffers: {
307 u64 slot_mask = 0;
308
309 status = GetReleasedBuffers(&slot_mask);
310
311 parcel_out.Write(slot_mask);
312 break;
313 }
314 default:
315 ASSERT_MSG(false, "called, code={} flags={}", code, flags);
316 break;
317 }
318
319 parcel_out.Write(status);
320
321 const auto serialized = parcel_out.Serialize();
322 std::memcpy(parcel_reply.data(), serialized.data(),
323 std::min(parcel_reply.size(), serialized.size()));
324}
325
326Kernel::KReadableEvent* BufferQueueConsumer::GetNativeHandle(u32 type_id) {
327 ASSERT_MSG(false, "called, type_id={}", type_id);
328 return nullptr;
329}
330
257} // namespace Service::android 331} // namespace Service::android
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
index 0a61e8dbd..a9226f1c3 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
@@ -10,6 +10,7 @@
10#include <memory> 10#include <memory>
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/hle/service/nvnflinger/binder.h"
13#include "core/hle/service/nvnflinger/buffer_queue_defs.h" 14#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
14#include "core/hle/service/nvnflinger/status.h" 15#include "core/hle/service/nvnflinger/status.h"
15 16
@@ -19,10 +20,10 @@ class BufferItem;
19class BufferQueueCore; 20class BufferQueueCore;
20class IConsumerListener; 21class IConsumerListener;
21 22
22class BufferQueueConsumer final { 23class BufferQueueConsumer final : public IBinder {
23public: 24public:
24 explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_); 25 explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
25 ~BufferQueueConsumer(); 26 ~BufferQueueConsumer() override;
26 27
27 Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); 28 Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
28 Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); 29 Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
@@ -30,6 +31,11 @@ public:
30 Status Disconnect(); 31 Status Disconnect();
31 Status GetReleasedBuffers(u64* out_slot_mask); 32 Status GetReleasedBuffers(u64* out_slot_mask);
32 33
34 void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
35 u32 flags) override;
36
37 Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
38
33private: 39private:
34 std::shared_ptr<BufferQueueCore> core; 40 std::shared_ptr<BufferQueueCore> core;
35 BufferQueueDefs::SlotsType& slots; 41 BufferQueueDefs::SlotsType& slots;
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index ec83beb9b..9e5091eeb 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -6,12 +6,9 @@
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/settings.h"
10#include "core/core.h"
11#include "core/hle/kernel/k_event.h" 9#include "core/hle/kernel/k_event.h"
12#include "core/hle/kernel/k_readable_event.h" 10#include "core/hle/kernel/k_readable_event.h"
13#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
14#include "core/hle/service/hle_ipc.h"
15#include "core/hle/service/kernel_helpers.h" 12#include "core/hle/service/kernel_helpers.h"
16#include "core/hle/service/nvnflinger/buffer_queue_core.h" 13#include "core/hle/service/nvnflinger/buffer_queue_core.h"
17#include "core/hle/service/nvnflinger/buffer_queue_producer.h" 14#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
@@ -19,7 +16,6 @@
19#include "core/hle/service/nvnflinger/parcel.h" 16#include "core/hle/service/nvnflinger/parcel.h"
20#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 17#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
21#include "core/hle/service/nvnflinger/window.h" 18#include "core/hle/service/nvnflinger/window.h"
22#include "core/hle/service/vi/vi.h"
23 19
24namespace Service::android { 20namespace Service::android {
25 21
@@ -807,13 +803,31 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
807 return Status::NoError; 803 return Status::NoError;
808} 804}
809 805
810void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<const u8> parcel_data, 806void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
811 std::span<u8> parcel_reply) { 807 std::span<u8> parcel_reply, u32 flags) {
808 // Values used by BnGraphicBufferProducer onTransact
809 enum class TransactionId {
810 RequestBuffer = 1,
811 SetBufferCount = 2,
812 DequeueBuffer = 3,
813 DetachBuffer = 4,
814 DetachNextBuffer = 5,
815 AttachBuffer = 6,
816 QueueBuffer = 7,
817 CancelBuffer = 8,
818 Query = 9,
819 Connect = 10,
820 Disconnect = 11,
821 AllocateBuffers = 13,
822 SetPreallocatedBuffer = 14,
823 GetBufferHistory = 17,
824 };
825
812 Status status{Status::NoError}; 826 Status status{Status::NoError};
813 InputParcel parcel_in{parcel_data}; 827 InputParcel parcel_in{parcel_data};
814 OutputParcel parcel_out{}; 828 OutputParcel parcel_out{};
815 829
816 switch (code) { 830 switch (static_cast<TransactionId>(code)) {
817 case TransactionId::Connect: { 831 case TransactionId::Connect: {
818 const auto enable_listener = parcel_in.Read<bool>(); 832 const auto enable_listener = parcel_in.Read<bool>();
819 const auto api = parcel_in.Read<NativeWindowApi>(); 833 const auto api = parcel_in.Read<NativeWindowApi>();
@@ -923,8 +937,8 @@ void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<cons
923 std::min(parcel_reply.size(), serialized.size())); 937 std::min(parcel_reply.size(), serialized.size()));
924} 938}
925 939
926Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() { 940Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) {
927 return buffer_wait_event->GetReadableEvent(); 941 return &buffer_wait_event->GetReadableEvent();
928} 942}
929 943
930} // namespace Service::android 944} // namespace Service::android
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
index 4682b0f84..048523514 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
@@ -45,12 +45,12 @@ public:
45 explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, 45 explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_,
46 std::shared_ptr<BufferQueueCore> buffer_queue_core_, 46 std::shared_ptr<BufferQueueCore> buffer_queue_core_,
47 Service::Nvidia::NvCore::NvMap& nvmap_); 47 Service::Nvidia::NvCore::NvMap& nvmap_);
48 ~BufferQueueProducer(); 48 ~BufferQueueProducer() override;
49 49
50 void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data, 50 void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
51 std::span<u8> parcel_reply) override; 51 u32 flags) override;
52 52
53 Kernel::KReadableEvent& GetNativeHandle() override; 53 Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
54 54
55public: 55public:
56 Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf); 56 Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf);
diff --git a/src/core/hle/service/nvnflinger/consumer_base.cpp b/src/core/hle/service/nvnflinger/consumer_base.cpp
index 1059e72bf..e360ebfd8 100644
--- a/src/core/hle/service/nvnflinger/consumer_base.cpp
+++ b/src/core/hle/service/nvnflinger/consumer_base.cpp
@@ -14,7 +14,7 @@
14 14
15namespace Service::android { 15namespace Service::android {
16 16
17ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_) 17ConsumerBase::ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_)
18 : consumer{std::move(consumer_)} {} 18 : consumer{std::move(consumer_)} {}
19 19
20ConsumerBase::~ConsumerBase() { 20ConsumerBase::~ConsumerBase() {
diff --git a/src/core/hle/service/nvnflinger/consumer_base.h b/src/core/hle/service/nvnflinger/consumer_base.h
index ea3e9e97a..b29c16f86 100644
--- a/src/core/hle/service/nvnflinger/consumer_base.h
+++ b/src/core/hle/service/nvnflinger/consumer_base.h
@@ -27,7 +27,7 @@ public:
27 void Abandon(); 27 void Abandon();
28 28
29protected: 29protected:
30 explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); 30 explicit ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_);
31 ~ConsumerBase() override; 31 ~ConsumerBase() override;
32 32
33 void OnFrameAvailable(const BufferItem& item) override; 33 void OnFrameAvailable(const BufferItem& item) override;
@@ -54,7 +54,7 @@ protected:
54 54
55 bool is_abandoned{}; 55 bool is_abandoned{};
56 56
57 std::unique_ptr<BufferQueueConsumer> consumer; 57 std::shared_ptr<BufferQueueConsumer> consumer;
58 58
59 mutable std::mutex mutex; 59 mutable std::mutex mutex;
60}; 60};
diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h
new file mode 100644
index 000000000..40aa59787
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/display.h
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
7#include "core/hle/service/nvnflinger/hwc_layer.h"
8
9namespace Service::Nvnflinger {
10
11struct Layer {
12 explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
13 s32 consumer_id_)
14 : buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_),
15 blending(LayerBlending::None), visible(true) {}
16 ~Layer() {
17 buffer_item_consumer->Abandon();
18 }
19
20 std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer;
21 s32 consumer_id;
22 LayerBlending blending;
23 bool visible;
24};
25
26struct LayerStack {
27 std::vector<std::shared_ptr<Layer>> layers;
28
29 std::shared_ptr<Layer> FindLayer(s32 consumer_id) {
30 for (auto& layer : layers) {
31 if (layer->consumer_id == consumer_id) {
32 return layer;
33 }
34 }
35
36 return nullptr;
37 }
38
39 bool HasLayers() {
40 return !layers.empty();
41 }
42};
43
44struct Display {
45 explicit Display(u64 id_) {
46 id = id_;
47 }
48
49 u64 id;
50 LayerStack stack;
51};
52
53} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp
index be7eb97a3..f2dfe85a9 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.cpp
+++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp
@@ -10,8 +10,6 @@
10#include "core/hle/service/nvnflinger/hardware_composer.h" 10#include "core/hle/service/nvnflinger/hardware_composer.h"
11#include "core/hle/service/nvnflinger/hwc_layer.h" 11#include "core/hle/service/nvnflinger/hwc_layer.h"
12#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 12#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
13#include "core/hle/service/vi/display/vi_display.h"
14#include "core/hle/service/vi/layer/vi_layer.h"
15 13
16namespace Service::Nvnflinger { 14namespace Service::Nvnflinger {
17 15
@@ -44,7 +42,7 @@ s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) {
44HardwareComposer::HardwareComposer() = default; 42HardwareComposer::HardwareComposer() = default;
45HardwareComposer::~HardwareComposer() = default; 43HardwareComposer::~HardwareComposer() = default;
46 44
47u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, 45u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
48 Nvidia::Devices::nvdisp_disp0& nvdisp) { 46 Nvidia::Devices::nvdisp_disp0& nvdisp) {
49 boost::container::small_vector<HwcLayer, 2> composition_stack; 47 boost::container::small_vector<HwcLayer, 2> composition_stack;
50 48
@@ -56,12 +54,11 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
56 bool has_acquired_buffer{}; 54 bool has_acquired_buffer{};
57 55
58 // Acquire all necessary framebuffers. 56 // Acquire all necessary framebuffers.
59 for (size_t i = 0; i < display.GetNumLayers(); i++) { 57 for (auto& layer : display.stack.layers) {
60 auto& layer = display.GetLayer(i); 58 auto consumer_id = layer->consumer_id;
61 auto layer_id = layer.GetLayerId();
62 59
63 // Try to fetch the framebuffer (either new or stale). 60 // Try to fetch the framebuffer (either new or stale).
64 const auto result = this->CacheFramebufferLocked(layer, layer_id); 61 const auto result = this->CacheFramebufferLocked(*layer, consumer_id);
65 62
66 // If we failed, skip this layer. 63 // If we failed, skip this layer.
67 if (result == CacheStatus::NoBufferAvailable) { 64 if (result == CacheStatus::NoBufferAvailable) {
@@ -73,24 +70,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
73 has_acquired_buffer = true; 70 has_acquired_buffer = true;
74 } 71 }
75 72
76 const auto& buffer = m_framebuffers[layer_id]; 73 const auto& buffer = m_framebuffers[consumer_id];
77 const auto& item = buffer.item; 74 const auto& item = buffer.item;
78 const auto& igbp_buffer = *item.graphic_buffer; 75 const auto& igbp_buffer = *item.graphic_buffer;
79 76
80 // TODO: get proper Z-index from layer 77 // TODO: get proper Z-index from layer
81 composition_stack.emplace_back(HwcLayer{ 78 if (layer->visible) {
82 .buffer_handle = igbp_buffer.BufferId(), 79 composition_stack.emplace_back(HwcLayer{
83 .offset = igbp_buffer.Offset(), 80 .buffer_handle = igbp_buffer.BufferId(),
84 .format = igbp_buffer.ExternalFormat(), 81 .offset = igbp_buffer.Offset(),
85 .width = igbp_buffer.Width(), 82 .format = igbp_buffer.ExternalFormat(),
86 .height = igbp_buffer.Height(), 83 .width = igbp_buffer.Width(),
87 .stride = igbp_buffer.Stride(), 84 .height = igbp_buffer.Height(),
88 .z_index = 0, 85 .stride = igbp_buffer.Stride(),
89 .blending = layer.GetBlending(), 86 .z_index = 0,
90 .transform = static_cast<android::BufferTransformFlags>(item.transform), 87 .blending = layer->blending,
91 .crop_rect = item.crop, 88 .transform = static_cast<android::BufferTransformFlags>(item.transform),
92 .acquire_fence = item.fence, 89 .crop_rect = item.crop,
93 }); 90 .acquire_fence = item.fence,
91 });
92 }
94 93
95 // We need to compose again either before this frame is supposed to 94 // We need to compose again either before this frame is supposed to
96 // be released, or exactly on the vsync period it should be released. 95 // be released, or exactly on the vsync period it should be released.
@@ -135,10 +134,10 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
135 continue; 134 continue;
136 } 135 }
137 136
138 if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { 137 if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) {
139 // TODO: support release fence 138 // TODO: support release fence
140 // This is needed to prevent screen tearing 139 // This is needed to prevent screen tearing
141 layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); 140 layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
142 framebuffer.is_acquired = false; 141 framebuffer.is_acquired = false;
143 } 142 }
144 } 143 }
@@ -146,26 +145,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
146 return frame_advance; 145 return frame_advance;
147} 146}
148 147
149void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { 148void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) {
150 // Check if we are tracking a slot with this layer_id. 149 // Check if we are tracking a slot with this consumer_id.
151 const auto it = m_framebuffers.find(layer_id); 150 const auto it = m_framebuffers.find(consumer_id);
152 if (it == m_framebuffers.end()) { 151 if (it == m_framebuffers.end()) {
153 return; 152 return;
154 } 153 }
155 154
156 // Try to release the buffer item. 155 // Try to release the buffer item.
157 auto* const layer = display.FindLayer(layer_id); 156 const auto layer = display.stack.FindLayer(consumer_id);
158 if (layer && it->second.is_acquired) { 157 if (layer && it->second.is_acquired) {
159 layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence()); 158 layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence());
160 } 159 }
161 160
162 // Erase the slot. 161 // Erase the slot.
163 m_framebuffers.erase(it); 162 m_framebuffers.erase(it);
164} 163}
165 164
166bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) { 165bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer) {
167 // Attempt the update. 166 // Attempt the update.
168 const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false); 167 const auto status = layer.buffer_item_consumer->AcquireBuffer(&framebuffer.item, {}, false);
169 if (status != android::Status::NoError) { 168 if (status != android::Status::NoError) {
170 return false; 169 return false;
171 } 170 }
@@ -178,10 +177,10 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer
178 return true; 177 return true;
179} 178}
180 179
181HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer, 180HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(Layer& layer,
182 LayerId layer_id) { 181 ConsumerId consumer_id) {
183 // Check if this framebuffer is already present. 182 // Check if this framebuffer is already present.
184 const auto it = m_framebuffers.find(layer_id); 183 const auto it = m_framebuffers.find(consumer_id);
185 if (it != m_framebuffers.end()) { 184 if (it != m_framebuffers.end()) {
186 // If it's currently still acquired, we are done. 185 // If it's currently still acquired, we are done.
187 if (it->second.is_acquired) { 186 if (it->second.is_acquired) {
@@ -203,7 +202,7 @@ HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer
203 202
204 if (this->TryAcquireFramebufferLocked(layer, framebuffer)) { 203 if (this->TryAcquireFramebufferLocked(layer, framebuffer)) {
205 // Move the buffer item into a new slot. 204 // Move the buffer item into a new slot.
206 m_framebuffers.emplace(layer_id, std::move(framebuffer)); 205 m_framebuffers.emplace(consumer_id, std::move(framebuffer));
207 206
208 // We succeeded. 207 // We succeeded.
209 return CacheStatus::BufferAcquired; 208 return CacheStatus::BufferAcquired;
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h
index 28392c512..c5b830468 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.h
+++ b/src/core/hle/service/nvnflinger/hardware_composer.h
@@ -3,35 +3,29 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <memory>
7#include <boost/container/flat_map.hpp> 6#include <boost/container/flat_map.hpp>
8 7
9#include "core/hle/service/nvnflinger/buffer_item.h" 8#include "core/hle/service/nvnflinger/buffer_item.h"
9#include "core/hle/service/nvnflinger/display.h"
10 10
11namespace Service::Nvidia::Devices { 11namespace Service::Nvidia::Devices {
12class nvdisp_disp0; 12class nvdisp_disp0;
13} 13}
14 14
15namespace Service::VI {
16class Display;
17class Layer;
18} // namespace Service::VI
19
20namespace Service::Nvnflinger { 15namespace Service::Nvnflinger {
21 16
22using LayerId = u64; 17using ConsumerId = s32;
23 18
24class HardwareComposer { 19class HardwareComposer {
25public: 20public:
26 explicit HardwareComposer(); 21 explicit HardwareComposer();
27 ~HardwareComposer(); 22 ~HardwareComposer();
28 23
29 u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, 24 u32 ComposeLocked(f32* out_speed_scale, Display& display,
30 Nvidia::Devices::nvdisp_disp0& nvdisp); 25 Nvidia::Devices::nvdisp_disp0& nvdisp);
31 void RemoveLayerLocked(VI::Display& display, LayerId layer_id); 26 void RemoveLayerLocked(Display& display, ConsumerId consumer_id);
32 27
33private: 28private:
34 // TODO: do we want to track frame number in vi instead?
35 u64 m_frame_number{0}; 29 u64 m_frame_number{0};
36 30
37private: 31private:
@@ -49,11 +43,11 @@ private:
49 CachedBufferReused, 43 CachedBufferReused,
50 }; 44 };
51 45
52 boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{}; 46 boost::container::flat_map<ConsumerId, Framebuffer> m_framebuffers{};
53 47
54private: 48private:
55 bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer); 49 bool TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer);
56 CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id); 50 CacheStatus CacheFramebufferLocked(Layer& layer, ConsumerId consumer_id);
57}; 51};
58 52
59} // namespace Service::Nvnflinger 53} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/vi/hos_binder_driver.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp
index ba0317245..8629a2e89 100644
--- a/src/core/hle/service/vi/hos_binder_driver.cpp
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp
@@ -3,13 +3,16 @@
3 3
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/binder.h" 5#include "core/hle/service/nvnflinger/binder.h"
6#include "core/hle/service/nvnflinger/hos_binder_driver.h"
6#include "core/hle/service/nvnflinger/hos_binder_driver_server.h" 7#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
7#include "core/hle/service/vi/hos_binder_driver.h"
8 8
9namespace Service::VI { 9namespace Service::Nvnflinger {
10 10
11IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server) 11IHOSBinderDriver::IHOSBinderDriver(Core::System& system_,
12 : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server) { 12 std::shared_ptr<HosBinderDriverServer> server,
13 std::shared_ptr<SurfaceFlinger> surface_flinger)
14 : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server),
15 m_surface_flinger(surface_flinger) {
13 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
14 {0, C<&IHOSBinderDriver::TransactParcel>, "TransactParcel"}, 17 {0, C<&IHOSBinderDriver::TransactParcel>, "TransactParcel"},
15 {1, C<&IHOSBinderDriver::AdjustRefcount>, "AdjustRefcount"}, 18 {1, C<&IHOSBinderDriver::AdjustRefcount>, "AdjustRefcount"},
@@ -21,13 +24,18 @@ IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderD
21 24
22IHOSBinderDriver::~IHOSBinderDriver() = default; 25IHOSBinderDriver::~IHOSBinderDriver() = default;
23 26
24Result IHOSBinderDriver::TransactParcel(s32 binder_id, android::TransactionId transaction_id, 27Result IHOSBinderDriver::TransactParcel(s32 binder_id, u32 transaction_id,
25 InBuffer<BufferAttr_HipcMapAlias> parcel_data, 28 InBuffer<BufferAttr_HipcMapAlias> parcel_data,
26 OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, 29 OutBuffer<BufferAttr_HipcMapAlias> parcel_reply,
27 u32 flags) { 30 u32 flags) {
28 LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id, 31 LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id,
29 flags); 32 flags);
30 m_server.TryGetProducer(binder_id)->Transact(transaction_id, flags, parcel_data, parcel_reply); 33
34 const auto binder = m_server->TryGetBinder(binder_id);
35 R_SUCCEED_IF(binder == nullptr);
36
37 binder->Transact(transaction_id, parcel_data, parcel_reply, flags);
38
31 R_SUCCEED(); 39 R_SUCCEED();
32} 40}
33 41
@@ -39,15 +47,20 @@ Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) {
39Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id, 47Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id,
40 OutCopyHandle<Kernel::KReadableEvent> out_handle) { 48 OutCopyHandle<Kernel::KReadableEvent> out_handle) {
41 LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id); 49 LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id);
42 *out_handle = &m_server.TryGetProducer(binder_id)->GetNativeHandle(); 50
51 const auto binder = m_server->TryGetBinder(binder_id);
52 R_UNLESS(binder != nullptr, ResultUnknown);
53
54 *out_handle = binder->GetNativeHandle(type_id);
55
43 R_SUCCEED(); 56 R_SUCCEED();
44} 57}
45 58
46Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id, 59Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, u32 transaction_id,
47 InBuffer<BufferAttr_HipcAutoSelect> parcel_data, 60 InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
48 OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, 61 OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply,
49 u32 flags) { 62 u32 flags) {
50 R_RETURN(this->TransactParcel(binder_id, transaction_id, parcel_data, parcel_reply, flags)); 63 R_RETURN(this->TransactParcel(binder_id, transaction_id, parcel_data, parcel_reply, flags));
51} 64}
52 65
53} // namespace Service::VI 66} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/vi/hos_binder_driver.h b/src/core/hle/service/nvnflinger/hos_binder_driver.h
index ed6e8cdbe..b7fb07bd2 100644
--- a/src/core/hle/service/vi/hos_binder_driver.h
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver.h
@@ -2,29 +2,45 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/cmif_types.h" 4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/nvnflinger/binder.h"
6#include "core/hle/service/service.h" 5#include "core/hle/service/service.h"
7 6
8namespace Service::VI { 7namespace Kernel {
8class KReadableEvent;
9}
10
11namespace Service::Nvnflinger {
12
13class HosBinderDriverServer;
14class SurfaceFlinger;
9 15
10class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { 16class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
11public: 17public:
12 explicit IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server); 18 explicit IHOSBinderDriver(Core::System& system_, std::shared_ptr<HosBinderDriverServer> server,
19 std::shared_ptr<SurfaceFlinger> surface_flinger);
13 ~IHOSBinderDriver() override; 20 ~IHOSBinderDriver() override;
14 21
22 std::shared_ptr<SurfaceFlinger> GetSurfaceFlinger() {
23 return m_surface_flinger;
24 }
25
26 std::shared_ptr<HosBinderDriverServer> GetServer() {
27 return m_server;
28 }
29
15private: 30private:
16 Result TransactParcel(s32 binder_id, android::TransactionId transaction_id, 31 Result TransactParcel(s32 binder_id, u32 transaction_id,
17 InBuffer<BufferAttr_HipcMapAlias> parcel_data, 32 InBuffer<BufferAttr_HipcMapAlias> parcel_data,
18 OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags); 33 OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags);
19 Result AdjustRefcount(s32 binder_id, s32 addval, s32 type); 34 Result AdjustRefcount(s32 binder_id, s32 addval, s32 type);
20 Result GetNativeHandle(s32 binder_id, u32 type_id, 35 Result GetNativeHandle(s32 binder_id, u32 type_id,
21 OutCopyHandle<Kernel::KReadableEvent> out_handle); 36 OutCopyHandle<Kernel::KReadableEvent> out_handle);
22 Result TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id, 37 Result TransactParcelAuto(s32 binder_id, u32 transaction_id,
23 InBuffer<BufferAttr_HipcAutoSelect> parcel_data, 38 InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
24 OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags); 39 OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags);
25 40
26private: 41private:
27 Nvnflinger::HosBinderDriverServer& m_server; 42 const std::shared_ptr<HosBinderDriverServer> m_server;
43 const std::shared_ptr<SurfaceFlinger> m_surface_flinger;
28}; 44};
29 45
30} // namespace Service::VI 46} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
index b86a79ec9..29addda44 100644
--- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
@@ -8,26 +8,30 @@
8 8
9namespace Service::Nvnflinger { 9namespace Service::Nvnflinger {
10 10
11HosBinderDriverServer::HosBinderDriverServer(Core::System& system_) 11HosBinderDriverServer::HosBinderDriverServer() = default;
12 : service_context(system_, "HosBinderDriverServer") {} 12HosBinderDriverServer::~HosBinderDriverServer() = default;
13 13
14HosBinderDriverServer::~HosBinderDriverServer() {} 14s32 HosBinderDriverServer::RegisterBinder(std::shared_ptr<android::IBinder>&& binder) {
15
16u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) {
17 std::scoped_lock lk{lock}; 15 std::scoped_lock lk{lock};
18 16
19 last_id++; 17 last_id++;
20 18
21 producers[last_id] = std::move(binder); 19 binders[last_id] = std::move(binder);
22 20
23 return last_id; 21 return last_id;
24} 22}
25 23
26android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) { 24void HosBinderDriverServer::UnregisterBinder(s32 binder_id) {
25 std::scoped_lock lk{lock};
26
27 binders.erase(binder_id);
28}
29
30std::shared_ptr<android::IBinder> HosBinderDriverServer::TryGetBinder(s32 id) const {
27 std::scoped_lock lk{lock}; 31 std::scoped_lock lk{lock};
28 32
29 if (auto search = producers.find(id); search != producers.end()) { 33 if (auto search = binders.find(id); search != binders.end()) {
30 return search->second.get(); 34 return search->second;
31 } 35 }
32 36
33 return {}; 37 return {};
diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h
index 58bb9469a..d72b50833 100644
--- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h
@@ -8,7 +8,6 @@
8#include <unordered_map> 8#include <unordered_map>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/service/kernel_helpers.h"
12#include "core/hle/service/nvnflinger/binder.h" 11#include "core/hle/service/nvnflinger/binder.h"
13 12
14namespace Core { 13namespace Core {
@@ -19,19 +18,18 @@ namespace Service::Nvnflinger {
19 18
20class HosBinderDriverServer final { 19class HosBinderDriverServer final {
21public: 20public:
22 explicit HosBinderDriverServer(Core::System& system_); 21 explicit HosBinderDriverServer();
23 ~HosBinderDriverServer(); 22 ~HosBinderDriverServer();
24 23
25 u64 RegisterProducer(std::unique_ptr<android::IBinder>&& binder); 24 s32 RegisterBinder(std::shared_ptr<android::IBinder>&& binder);
25 void UnregisterBinder(s32 binder_id);
26 26
27 android::IBinder* TryGetProducer(u64 id); 27 std::shared_ptr<android::IBinder> TryGetBinder(s32 id) const;
28 28
29private: 29private:
30 KernelHelpers::ServiceContext service_context; 30 std::unordered_map<s32, std::shared_ptr<android::IBinder>> binders;
31 31 mutable std::mutex lock;
32 std::unordered_map<u64, std::unique_ptr<android::IBinder>> producers; 32 s32 last_id{};
33 std::mutex lock;
34 u64 last_id{};
35}; 33};
36 34
37} // namespace Service::Nvnflinger 35} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index 687ccc9f9..9e3b68b8a 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -1,335 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include <algorithm>
5#include <optional>
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "common/microprofile.h"
10#include "common/scope_exit.h"
11#include "common/settings.h"
12#include "common/thread.h"
13#include "core/core.h" 4#include "core/core.h"
14#include "core/core_timing.h" 5#include "core/hle/service/nvnflinger/hos_binder_driver.h"
15#include "core/hle/kernel/k_readable_event.h"
16#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
17#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
19#include "core/hle/service/nvnflinger/buffer_queue_core.h"
20#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
21#include "core/hle/service/nvnflinger/hardware_composer.h"
22#include "core/hle/service/nvnflinger/hos_binder_driver_server.h" 6#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
23#include "core/hle/service/nvnflinger/nvnflinger.h" 7#include "core/hle/service/nvnflinger/nvnflinger.h"
24#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 8#include "core/hle/service/nvnflinger/surface_flinger.h"
25#include "core/hle/service/vi/display/vi_display.h" 9#include "core/hle/service/server_manager.h"
26#include "core/hle/service/vi/layer/vi_layer.h" 10#include "core/hle/service/sm/sm.h"
27#include "core/hle/service/vi/vi_results.h"
28#include "video_core/gpu.h"
29#include "video_core/host1x/host1x.h"
30#include "video_core/host1x/syncpoint_manager.h"
31 11
32namespace Service::Nvnflinger { 12namespace Service::Nvnflinger {
33 13
34constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60}; 14void LoopProcess(Core::System& system) {
35 15 const auto binder_server = std::make_shared<HosBinderDriverServer>();
36void Nvnflinger::SplitVSync(std::stop_token stop_token) { 16 const auto surface_flinger = std::make_shared<SurfaceFlinger>(system, *binder_server);
37 system.RegisterHostThread();
38 std::string name = "VSyncThread";
39 MicroProfileOnThreadCreate(name.c_str());
40
41 // Cleanup
42 SCOPE_EXIT({ MicroProfileOnThreadExit(); });
43
44 Common::SetCurrentThreadName(name.c_str());
45 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
46
47 while (!stop_token.stop_requested()) {
48 vsync_signal.Wait();
49
50 const auto lock_guard = Lock();
51
52 if (!is_abandoned) {
53 Compose();
54 }
55 }
56}
57
58Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
59 : system(system_), service_context(system_, "nvnflinger"),
60 hos_binder_driver_server(hos_binder_driver_server_) {
61 displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system);
62 displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system);
63 displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system);
64 displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system);
65 displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system);
66 guard = std::make_shared<std::mutex>();
67
68 // Schedule the screen composition events
69 multi_composition_event = Core::Timing::CreateEvent(
70 "ScreenComposition",
71 [this](s64 time,
72 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
73 vsync_signal.Set();
74 return std::chrono::nanoseconds(GetNextTicks());
75 });
76
77 single_composition_event = Core::Timing::CreateEvent(
78 "ScreenComposition",
79 [this](s64 time,
80 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
81 const auto lock_guard = Lock();
82 Compose();
83
84 return std::chrono::nanoseconds(GetNextTicks());
85 });
86
87 if (system.IsMulticore()) {
88 system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, multi_composition_event);
89 vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
90 } else {
91 system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, single_composition_event);
92 }
93}
94
95Nvnflinger::~Nvnflinger() {
96 if (system.IsMulticore()) {
97 system.CoreTiming().UnscheduleEvent(multi_composition_event);
98 vsync_thread.request_stop();
99 vsync_signal.Set();
100 } else {
101 system.CoreTiming().UnscheduleEvent(single_composition_event);
102 }
103
104 ShutdownLayers();
105
106 if (nvdrv) {
107 nvdrv->Close(disp_fd);
108 }
109}
110
111void Nvnflinger::ShutdownLayers() {
112 // Abandon consumers.
113 {
114 const auto lock_guard = Lock();
115 for (auto& display : displays) {
116 display.Abandon();
117 }
118
119 is_abandoned = true;
120 }
121
122 // Join the vsync thread, if it exists.
123 vsync_thread = {};
124}
125
126void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
127 nvdrv = std::move(instance);
128 disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {});
129}
130
131std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) {
132 const auto lock_guard = Lock();
133
134 LOG_DEBUG(Service_Nvnflinger, "Opening \"{}\" display", name);
135
136 const auto itr =
137 std::find_if(displays.begin(), displays.end(),
138 [&](const VI::Display& display) { return display.GetName() == name; });
139
140 if (itr == displays.end()) {
141 return std::nullopt;
142 }
143
144 return itr->GetID();
145}
146
147bool Nvnflinger::CloseDisplay(u64 display_id) {
148 const auto lock_guard = Lock();
149 auto* const display = FindDisplay(display_id);
150
151 if (display == nullptr) {
152 return false;
153 }
154
155 display->Reset();
156
157 return true;
158}
159
160std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) {
161 const auto lock_guard = Lock();
162 auto* const display = FindDisplay(display_id);
163
164 if (display == nullptr) {
165 return std::nullopt;
166 }
167
168 const u64 layer_id = next_layer_id++;
169 CreateLayerAtId(*display, layer_id, blending);
170 return layer_id;
171}
172
173void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) {
174 const auto buffer_id = next_buffer_queue_id++;
175 display.CreateLayer(layer_id, buffer_id, nvdrv->container);
176 display.FindLayer(layer_id)->SetBlending(blending);
177}
178
179bool Nvnflinger::OpenLayer(u64 layer_id) {
180 const auto lock_guard = Lock();
181
182 for (auto& display : displays) {
183 if (auto* layer = display.FindLayer(layer_id); layer) {
184 return layer->Open();
185 }
186 }
187
188 return false;
189}
190
191bool Nvnflinger::CloseLayer(u64 layer_id) {
192 const auto lock_guard = Lock();
193
194 for (auto& display : displays) {
195 if (auto* layer = display.FindLayer(layer_id); layer) {
196 return layer->Close();
197 }
198 }
199
200 return false;
201}
202
203void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) {
204 const auto lock_guard = Lock();
205
206 for (auto& display : displays) {
207 if (auto* layer = display.FindLayer(layer_id); layer) {
208 layer->SetVisibility(visible);
209 }
210 }
211}
212
213void Nvnflinger::DestroyLayer(u64 layer_id) {
214 const auto lock_guard = Lock();
215
216 for (auto& display : displays) {
217 display.DestroyLayer(layer_id);
218 }
219}
220
221std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
222 const auto lock_guard = Lock();
223 const auto* const layer = FindLayer(display_id, layer_id);
224
225 if (layer == nullptr) {
226 return std::nullopt;
227 }
228
229 return layer->GetBinderId();
230}
231
232Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id) {
233 const auto lock_guard = Lock();
234 auto* const display = FindDisplay(display_id);
235
236 if (display == nullptr) {
237 return VI::ResultNotFound;
238 }
239
240 *out_vsync_event = display->GetVSyncEvent();
241 return ResultSuccess;
242}
243
244VI::Display* Nvnflinger::FindDisplay(u64 display_id) {
245 const auto itr =
246 std::find_if(displays.begin(), displays.end(),
247 [&](const VI::Display& display) { return display.GetID() == display_id; });
248
249 if (itr == displays.end()) {
250 return nullptr;
251 }
252
253 return &*itr;
254}
255
256const VI::Display* Nvnflinger::FindDisplay(u64 display_id) const {
257 const auto itr =
258 std::find_if(displays.begin(), displays.end(),
259 [&](const VI::Display& display) { return display.GetID() == display_id; });
260
261 if (itr == displays.end()) {
262 return nullptr;
263 }
264
265 return &*itr;
266}
267
268VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) {
269 auto* const display = FindDisplay(display_id);
270
271 if (display == nullptr) {
272 return nullptr;
273 }
274
275 return display->FindLayer(layer_id);
276}
277
278void Nvnflinger::Compose() {
279 for (auto& display : displays) {
280 // Trigger vsync for this display at the end of drawing
281 SCOPE_EXIT({ display.SignalVSyncEvent(); });
282
283 // Don't do anything for displays without layers.
284 if (!display.HasLayers()) {
285 continue;
286 }
287
288 if (!system.IsPoweredOn()) {
289 return; // We are likely shutting down
290 }
291
292 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
293 ASSERT(nvdisp);
294
295 swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp);
296 }
297}
298
299s64 Nvnflinger::GetNextTicks() const {
300 const auto& settings = Settings::values;
301 auto speed_scale = 1.f;
302 if (settings.use_multi_core.GetValue()) {
303 if (settings.use_speed_limit.GetValue()) {
304 // Scales the speed based on speed_limit setting on MC. SC is handled by
305 // SpeedLimiter::DoSpeedLimiting.
306 speed_scale = 100.f / settings.speed_limit.GetValue();
307 } else {
308 // Run at unlocked framerate.
309 speed_scale = 0.01f;
310 }
311 }
312
313 // Adjust by speed limit determined during composition.
314 speed_scale /= compose_speed_scale;
315
316 if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
317 // Run at intended presentation rate during video playback.
318 speed_scale = 1.f;
319 }
320
321 const f32 effective_fps = 60.f / static_cast<f32>(swap_interval);
322 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
323}
324
325FbShareBufferManager& Nvnflinger::GetSystemBufferManager() {
326 const auto lock_guard = Lock();
327
328 if (!system_buffer_manager) {
329 system_buffer_manager = std::make_unique<FbShareBufferManager>(system, *this, nvdrv);
330 }
331 17
332 return *system_buffer_manager; 18 auto server_manager = std::make_unique<ServerManager>(system);
19 server_manager->RegisterNamedService(
20 "dispdrv", std::make_shared<IHOSBinderDriver>(system, binder_server, surface_flinger));
21 ServerManager::RunServer(std::move(server_manager));
333} 22}
334 23
335} // namespace Service::Nvnflinger 24} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index 4cf4f069d..5c41f3013 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -3,170 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <list> 6namespace Core {
7#include <memory> 7class System;
8#include <mutex> 8}
9#include <optional>
10#include <thread>
11#include <vector>
12
13#include "common/common_types.h"
14#include "common/polyfill_thread.h"
15#include "common/thread.h"
16#include "core/hle/result.h"
17#include "core/hle/service/kernel_helpers.h"
18#include "core/hle/service/nvnflinger/hwc_layer.h"
19
20namespace Common {
21class Event;
22} // namespace Common
23
24namespace Core::Timing {
25class CoreTiming;
26struct EventType;
27} // namespace Core::Timing
28
29namespace Kernel {
30class KReadableEvent;
31} // namespace Kernel
32
33namespace Service::Nvidia {
34class Module;
35} // namespace Service::Nvidia
36
37namespace Service::VI {
38class Display;
39class Layer;
40} // namespace Service::VI
41
42namespace Service::android {
43class BufferQueueCore;
44class BufferQueueProducer;
45} // namespace Service::android
46 9
47namespace Service::Nvnflinger { 10namespace Service::Nvnflinger {
48 11
49class FbShareBufferManager; 12void LoopProcess(Core::System& system);
50class HardwareComposer;
51class HosBinderDriverServer;
52
53class Nvnflinger final {
54public:
55 explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
56 ~Nvnflinger();
57
58 void ShutdownLayers();
59
60 /// Sets the NVDrv module instance to use to send buffers to the GPU.
61 void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);
62
63 /// Opens the specified display and returns the ID.
64 ///
65 /// If an invalid display name is provided, then an empty optional is returned.
66 [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name);
67
68 /// Closes the specified display by its ID.
69 ///
70 /// Returns false if an invalid display ID is provided.
71 [[nodiscard]] bool CloseDisplay(u64 display_id);
72
73 /// Creates a layer on the specified display and returns the layer ID.
74 ///
75 /// If an invalid display ID is specified, then an empty optional is returned.
76 [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id,
77 LayerBlending blending = LayerBlending::None);
78
79 /// Opens a layer on all displays for the given layer ID.
80 bool OpenLayer(u64 layer_id);
81
82 /// Closes a layer on all displays for the given layer ID.
83 bool CloseLayer(u64 layer_id);
84
85 /// Makes a layer visible on all displays for the given layer ID.
86 void SetLayerVisibility(u64 layer_id, bool visible);
87
88 /// Destroys the given layer ID.
89 void DestroyLayer(u64 layer_id);
90
91 /// Finds the buffer queue ID of the specified layer in the specified display.
92 ///
93 /// If an invalid display ID or layer ID is provided, then an empty optional is returned.
94 [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id);
95
96 /// Gets the vsync event for the specified display.
97 ///
98 /// If an invalid display ID is provided, then VI::ResultNotFound is returned.
99 /// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned.
100 [[nodiscard]] Result FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id);
101
102 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
103 /// finished.
104 void Compose();
105
106 [[nodiscard]] s64 GetNextTicks() const;
107
108 FbShareBufferManager& GetSystemBufferManager();
109
110private:
111 struct Layer {
112 std::unique_ptr<android::BufferQueueCore> core;
113 std::unique_ptr<android::BufferQueueProducer> producer;
114 };
115
116 friend class FbShareBufferManager;
117
118private:
119 [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
120 return std::unique_lock{*guard};
121 }
122
123 /// Finds the display identified by the specified ID.
124 [[nodiscard]] VI::Display* FindDisplay(u64 display_id);
125
126 /// Finds the display identified by the specified ID.
127 [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const;
128
129 /// Finds the layer identified by the specified ID in the desired display.
130 [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
131
132 /// Creates a layer with the specified layer ID in the desired display.
133 void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending);
134
135 void SplitVSync(std::stop_token stop_token);
136
137 std::shared_ptr<Nvidia::Module> nvdrv;
138 s32 disp_fd;
139
140 std::list<VI::Display> displays;
141
142 /// Id to use for the next layer that is created, this counter is shared among all displays.
143 u64 next_layer_id = 1;
144 /// Id to use for the next buffer queue that is created, this counter is shared among all
145 /// layers.
146 u32 next_buffer_queue_id = 1;
147
148 s32 swap_interval = 1;
149 f32 compose_speed_scale = 1.0f;
150
151 bool is_abandoned = false;
152
153 /// Event that handles screen composition.
154 std::shared_ptr<Core::Timing::EventType> multi_composition_event;
155 std::shared_ptr<Core::Timing::EventType> single_composition_event;
156
157 std::unique_ptr<FbShareBufferManager> system_buffer_manager;
158
159 std::shared_ptr<std::mutex> guard;
160
161 Core::System& system;
162
163 Common::Event vsync_signal;
164
165 std::jthread vsync_thread;
166
167 KernelHelpers::ServiceContext service_context;
168
169 HosBinderDriverServer& hos_binder_driver_server;
170};
171 13
172} // namespace Service::Nvnflinger 14} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp
new file mode 100644
index 000000000..8362b65e5
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp
@@ -0,0 +1,139 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
6#include "core/hle/service/nvdrv/nvdrv_interface.h"
7#include "core/hle/service/nvnflinger/display.h"
8#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
9#include "core/hle/service/nvnflinger/surface_flinger.h"
10#include "core/hle/service/sm/sm.h"
11
12#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
13#include "core/hle/service/nvnflinger/buffer_queue_core.h"
14#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
15
16namespace Service::Nvnflinger {
17
18SurfaceFlinger::SurfaceFlinger(Core::System& system, HosBinderDriverServer& server)
19 : m_system(system), m_server(server), m_context(m_system, "SurfaceFlinger") {
20 nvdrv = m_system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
21 disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {});
22}
23
24SurfaceFlinger::~SurfaceFlinger() {
25 nvdrv->Close(disp_fd);
26}
27
28void SurfaceFlinger::AddDisplay(u64 display_id) {
29 m_displays.emplace_back(display_id);
30}
31
32void SurfaceFlinger::RemoveDisplay(u64 display_id) {
33 std::erase_if(m_displays, [&](auto& display) { return display.id == display_id; });
34}
35
36bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
37 u64 display_id) {
38 auto* const display = this->FindDisplay(display_id);
39 if (!display || !display->stack.HasLayers()) {
40 return false;
41 }
42
43 *out_swap_interval =
44 m_composer.ComposeLocked(out_compose_speed_scale, *display,
45 *nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd));
46 return true;
47}
48
49void SurfaceFlinger::CreateLayer(s32 consumer_binder_id) {
50 auto binder = std::static_pointer_cast<android::BufferQueueConsumer>(
51 m_server.TryGetBinder(consumer_binder_id));
52 if (!binder) {
53 return;
54 }
55
56 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder));
57 buffer_item_consumer->Connect(false);
58
59 m_layers.layers.emplace_back(
60 std::make_shared<Layer>(std::move(buffer_item_consumer), consumer_binder_id));
61}
62
63void SurfaceFlinger::DestroyLayer(s32 consumer_binder_id) {
64 std::erase_if(m_layers.layers,
65 [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
66}
67
68void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) {
69 auto* const display = this->FindDisplay(display_id);
70 auto layer = this->FindLayer(consumer_binder_id);
71
72 if (!display || !layer) {
73 return;
74 }
75
76 display->stack.layers.emplace_back(std::move(layer));
77}
78
79void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) {
80 auto* const display = this->FindDisplay(display_id);
81 if (!display) {
82 return;
83 }
84
85 m_composer.RemoveLayerLocked(*display, consumer_binder_id);
86 std::erase_if(display->stack.layers,
87 [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
88}
89
90void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) {
91 if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
92 layer->visible = visible;
93 return;
94 }
95}
96
97void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) {
98 if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
99 layer->blending = blending;
100 return;
101 }
102}
103
104Display* SurfaceFlinger::FindDisplay(u64 display_id) {
105 for (auto& display : m_displays) {
106 if (display.id == display_id) {
107 return &display;
108 }
109 }
110
111 return nullptr;
112}
113
114std::shared_ptr<Layer> SurfaceFlinger::FindLayer(s32 consumer_binder_id) {
115 for (auto& layer : m_layers.layers) {
116 if (layer->consumer_id == consumer_binder_id) {
117 return layer;
118 }
119 }
120
121 return nullptr;
122}
123
124void SurfaceFlinger::CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id) {
125 auto& nvmap = nvdrv->GetContainer().GetNvMapFile();
126 auto core = std::make_shared<android::BufferQueueCore>();
127 auto producer = std::make_shared<android::BufferQueueProducer>(m_context, core, nvmap);
128 auto consumer = std::make_shared<android::BufferQueueConsumer>(core);
129
130 *out_consumer_binder_id = m_server.RegisterBinder(std::move(consumer));
131 *out_producer_binder_id = m_server.RegisterBinder(std::move(producer));
132}
133
134void SurfaceFlinger::DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id) {
135 m_server.UnregisterBinder(producer_binder_id);
136 m_server.UnregisterBinder(consumer_binder_id);
137}
138
139} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h
new file mode 100644
index 000000000..406281c83
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/surface_flinger.h
@@ -0,0 +1,69 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <vector>
7
8#include "common/common_types.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/nvnflinger/hardware_composer.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::Nvidia {
17class Module;
18}
19
20// TODO: ISurfaceComposer
21// TODO: ISurfaceComposerClient
22
23namespace Service::Nvnflinger {
24
25struct Display;
26class HosBinderDriverServer;
27enum class LayerBlending : u32;
28struct Layer;
29
30class SurfaceFlinger {
31public:
32 explicit SurfaceFlinger(Core::System& system, HosBinderDriverServer& server);
33 ~SurfaceFlinger();
34
35 void AddDisplay(u64 display_id);
36 void RemoveDisplay(u64 display_id);
37 bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
38
39 void CreateLayer(s32 consumer_binder_id);
40 void DestroyLayer(s32 consumer_binder_id);
41
42 void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id);
43 void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id);
44
45 void SetLayerVisibility(s32 consumer_binder_id, bool visible);
46 void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
47
48private:
49 Display* FindDisplay(u64 display_id);
50 std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
51
52public:
53 // TODO: these don't belong here
54 void CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id);
55 void DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id);
56
57private:
58 Core::System& m_system;
59 HosBinderDriverServer& m_server;
60 KernelHelpers::ServiceContext m_context;
61
62 std::vector<Display> m_displays;
63 LayerStack m_layers;
64 std::shared_ptr<Nvidia::Module> nvdrv;
65 s32 disp_fd;
66 HardwareComposer m_composer;
67};
68
69} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/psc/time/static.cpp b/src/core/hle/service/psc/time/static.cpp
index 24b85cc61..9a0adb295 100644
--- a/src/core/hle/service/psc/time/static.cpp
+++ b/src/core/hle/service/psc/time/static.cpp
@@ -144,7 +144,9 @@ Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
144 144
145Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( 145Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
146 Out<bool> out_is_enabled) { 146 Out<bool> out_is_enabled) {
147 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled); }); 147 SCOPE_EXIT {
148 LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled);
149 };
148 150
149 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); 151 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
150 152
@@ -180,7 +182,9 @@ Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
180} 182}
181 183
182Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { 184Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
183 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); 185 SCOPE_EXIT {
186 LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
187 };
184 188
185 *out_is_sufficient = m_network_system_clock.IsAccuracySufficient(); 189 *out_is_sufficient = m_network_system_clock.IsAccuracySufficient();
186 190
@@ -189,7 +193,9 @@ Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> o
189 193
190Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 194Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
191 Out<SteadyClockTimePoint> out_time_point) { 195 Out<SteadyClockTimePoint> out_time_point) {
192 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 196 SCOPE_EXIT {
197 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
198 };
193 199
194 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); 200 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
195 201
@@ -200,7 +206,9 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
200 206
201Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( 207Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
202 Out<s64> out_time, const SystemClockContext& context) { 208 Out<s64> out_time, const SystemClockContext& context) {
203 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); 209 SCOPE_EXIT {
210 LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
211 };
204 212
205 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized); 213 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
206 214
@@ -219,8 +227,9 @@ Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
219} 227}
220 228
221Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) { 229Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) {
222 SCOPE_EXIT( 230 SCOPE_EXIT {
223 { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); 231 LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
232 };
224 233
225 SystemClockContext user_context{}; 234 SystemClockContext user_context{};
226 R_TRY(m_user_system_clock.GetContext(user_context)); 235 R_TRY(m_user_system_clock.GetContext(user_context));
@@ -234,11 +243,11 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType t
234Result StaticService::GetClockSnapshotFromSystemClockContext( 243Result StaticService::GetClockSnapshotFromSystemClockContext(
235 TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context, 244 TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context,
236 const SystemClockContext& network_context) { 245 const SystemClockContext& network_context) {
237 SCOPE_EXIT({ 246 SCOPE_EXIT {
238 LOG_DEBUG(Service_Time, 247 LOG_DEBUG(Service_Time,
239 "called. type={} user_context={} network_context={} out_snapshot={}", type, 248 "called. type={} user_context={} network_context={} out_snapshot={}", type,
240 user_context, network_context, *out_snapshot); 249 user_context, network_context, *out_snapshot);
241 }); 250 };
242 251
243 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); 252 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
244} 253}
@@ -246,9 +255,9 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
246Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference, 255Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
247 InClockSnapshot a, 256 InClockSnapshot a,
248 InClockSnapshot b) { 257 InClockSnapshot b) {
249 SCOPE_EXIT({ 258 SCOPE_EXIT {
250 LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference); 259 LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference);
251 }); 260 };
252 261
253 auto diff_s = 262 auto diff_s =
254 std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset); 263 std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset);
@@ -276,7 +285,9 @@ Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64>
276 285
277Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, 286Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
278 InClockSnapshot b) { 287 InClockSnapshot b) {
279 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 288 SCOPE_EXIT {
289 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
290 };
280 291
281 s64 time_s{}; 292 s64 time_s{};
282 auto res = 293 auto res =
diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp
index 948610a2b..78dcf532c 100644
--- a/src/core/hle/service/psc/time/steady_clock.cpp
+++ b/src/core/hle/service/psc/time/steady_clock.cpp
@@ -29,7 +29,9 @@ SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> man
29} 29}
30 30
31Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) { 31Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) {
32 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 32 SCOPE_EXIT {
33 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
34 };
33 35
34 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 36 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
35 ResultClockUninitialized); 37 ResultClockUninitialized);
@@ -38,7 +40,9 @@ Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point
38} 40}
39 41
40Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) { 42Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) {
41 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset); }); 43 SCOPE_EXIT {
44 LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset);
45 };
42 46
43 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 47 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
44 ResultClockUninitialized); 48 ResultClockUninitialized);
@@ -59,7 +63,9 @@ Result SteadyClock::SetTestOffset(s64 test_offset) {
59} 63}
60 64
61Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) { 65Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
62 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); 66 SCOPE_EXIT {
67 LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value);
68 };
63 69
64 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 70 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
65 ResultClockUninitialized); 71 ResultClockUninitialized);
@@ -68,7 +74,9 @@ Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
68} 74}
69 75
70Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) { 76Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
71 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected); }); 77 SCOPE_EXIT {
78 LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected);
79 };
72 80
73 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 81 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
74 ResultClockUninitialized); 82 ResultClockUninitialized);
@@ -78,7 +86,9 @@ Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
78} 86}
79 87
80Result SteadyClock::GetSetupResultValue(Out<Result> out_result) { 88Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
81 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); }); 89 SCOPE_EXIT {
90 LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw);
91 };
82 92
83 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 93 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
84 ResultClockUninitialized); 94 ResultClockUninitialized);
@@ -88,8 +98,9 @@ Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
88} 98}
89 99
90Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) { 100Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) {
91 SCOPE_EXIT( 101 SCOPE_EXIT {
92 { LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset); }); 102 LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset);
103 };
93 104
94 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 105 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
95 ResultClockUninitialized); 106 ResultClockUninitialized);
diff --git a/src/core/hle/service/psc/time/system_clock.cpp b/src/core/hle/service/psc/time/system_clock.cpp
index b4e9264d8..9f841d8e0 100644
--- a/src/core/hle/service/psc/time/system_clock.cpp
+++ b/src/core/hle/service/psc/time/system_clock.cpp
@@ -26,7 +26,9 @@ SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, boo
26} 26}
27 27
28Result SystemClock::GetCurrentTime(Out<s64> out_time) { 28Result SystemClock::GetCurrentTime(Out<s64> out_time) {
29 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time={}", *out_time); }); 29 SCOPE_EXIT {
30 LOG_DEBUG(Service_Time, "called. out_time={}", *out_time);
31 };
30 32
31 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 33 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
32 ResultClockUninitialized); 34 ResultClockUninitialized);
@@ -45,7 +47,9 @@ Result SystemClock::SetCurrentTime(s64 time) {
45} 47}
46 48
47Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) { 49Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) {
48 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_context={}", *out_context); }); 50 SCOPE_EXIT {
51 LOG_DEBUG(Service_Time, "called. out_context={}", *out_context);
52 };
49 53
50 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 54 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
51 ResultClockUninitialized); 55 ResultClockUninitialized);
diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp
index 2f80030a4..9e0674f27 100644
--- a/src/core/hle/service/psc/time/time_zone_service.cpp
+++ b/src/core/hle/service/psc/time/time_zone_service.cpp
@@ -37,7 +37,9 @@ TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore&
37} 37}
38 38
39Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) { 39Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) {
40 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); }); 40 SCOPE_EXIT {
41 LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name);
42 };
41 43
42 R_RETURN(m_time_zone.GetLocationName(*out_location_name)); 44 R_RETURN(m_time_zone.GetLocationName(*out_location_name));
43} 45}
@@ -50,7 +52,9 @@ Result TimeZoneService::SetDeviceLocationName(const LocationName& location_name)
50} 52}
51 53
52Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { 54Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
53 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); }); 55 SCOPE_EXIT {
56 LOG_DEBUG(Service_Time, "called. out_count={}", *out_count);
57 };
54 58
55 R_RETURN(m_time_zone.GetTotalLocationCount(*out_count)); 59 R_RETURN(m_time_zone.GetTotalLocationCount(*out_count));
56} 60}
@@ -69,17 +73,19 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, const LocationName& l
69} 73}
70 74
71Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) { 75Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) {
72 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); }); 76 SCOPE_EXIT {
77 LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version);
78 };
73 79
74 R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version)); 80 R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version));
75} 81}
76 82
77Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( 83Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
78 Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) { 84 Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) {
79 SCOPE_EXIT({ 85 SCOPE_EXIT {
80 LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}", 86 LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}",
81 *out_location_name, *out_time_point); 87 *out_location_name, *out_time_point);
82 }); 88 };
83 89
84 R_TRY(m_time_zone.GetLocationName(*out_location_name)); 90 R_TRY(m_time_zone.GetLocationName(*out_location_name));
85 R_RETURN(m_time_zone.GetTimePoint(*out_time_point)); 91 R_RETURN(m_time_zone.GetTimePoint(*out_time_point));
@@ -116,10 +122,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
116Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time, 122Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time,
117 Out<CalendarAdditionalInfo> out_additional_info, s64 time, 123 Out<CalendarAdditionalInfo> out_additional_info, s64 time,
118 InRule rule) { 124 InRule rule) {
119 SCOPE_EXIT({ 125 SCOPE_EXIT {
120 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 126 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
121 *out_calendar_time, *out_additional_info); 127 *out_calendar_time, *out_additional_info);
122 }); 128 };
123 129
124 R_RETURN( 130 R_RETURN(
125 m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get())); 131 m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get()));
@@ -128,10 +134,10 @@ Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time,
128Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time, 134Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time,
129 Out<CalendarAdditionalInfo> out_additional_info, 135 Out<CalendarAdditionalInfo> out_additional_info,
130 s64 time) { 136 s64 time) {
131 SCOPE_EXIT({ 137 SCOPE_EXIT {
132 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 138 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
133 *out_calendar_time, *out_additional_info); 139 *out_calendar_time, *out_additional_info);
134 }); 140 };
135 141
136 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time)); 142 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time));
137} 143}
@@ -139,11 +145,11 @@ Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_
139Result TimeZoneService::ToPosixTime(Out<u32> out_count, 145Result TimeZoneService::ToPosixTime(Out<u32> out_count,
140 OutArray<s64, BufferAttr_HipcPointer> out_times, 146 OutArray<s64, BufferAttr_HipcPointer> out_times,
141 const CalendarTime& calendar_time, InRule rule) { 147 const CalendarTime& calendar_time, InRule rule) {
142 SCOPE_EXIT({ 148 SCOPE_EXIT {
143 LOG_DEBUG(Service_Time, 149 LOG_DEBUG(Service_Time,
144 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", 150 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
145 calendar_time, *out_count, out_times[0], out_times[1]); 151 calendar_time, *out_count, out_times[0], out_times[1]);
146 }); 152 };
147 153
148 R_RETURN( 154 R_RETURN(
149 m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule)); 155 m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule));
@@ -152,11 +158,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
152Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, 158Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count,
153 OutArray<s64, BufferAttr_HipcPointer> out_times, 159 OutArray<s64, BufferAttr_HipcPointer> out_times,
154 const CalendarTime& calendar_time) { 160 const CalendarTime& calendar_time) {
155 SCOPE_EXIT({ 161 SCOPE_EXIT {
156 LOG_DEBUG(Service_Time, 162 LOG_DEBUG(Service_Time,
157 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", 163 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
158 calendar_time, *out_count, out_times[0], out_times[1]); 164 calendar_time, *out_count, out_times[0], out_times[1]);
159 }); 165 };
160 166
161 R_RETURN( 167 R_RETURN(
162 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time)); 168 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time));
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index 8c7f94c8c..0b41bbcb9 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -177,10 +177,10 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,
177 Kernel::KPort::Register(m_system.Kernel(), port); 177 Kernel::KPort::Register(m_system.Kernel(), port);
178 178
179 // Ensure that our reference to the port is closed if we fail to register it. 179 // Ensure that our reference to the port is closed if we fail to register it.
180 SCOPE_EXIT({ 180 SCOPE_EXIT {
181 port->GetClientPort().Close(); 181 port->GetClientPort().Close();
182 port->GetServerPort().Close(); 182 port->GetServerPort().Close();
183 }); 183 };
184 184
185 // Register the object name with the kernel. 185 // Register the object name with the kernel.
186 R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()), 186 R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()),
@@ -237,7 +237,9 @@ void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_thre
237} 237}
238 238
239Result ServerManager::LoopProcess() { 239Result ServerManager::LoopProcess() {
240 SCOPE_EXIT({ m_stopped.Set(); }); 240 SCOPE_EXIT {
241 m_stopped.Set();
242 };
241 243
242 R_RETURN(this->LoopProcessImpl()); 244 R_RETURN(this->LoopProcessImpl());
243} 245}
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index fbdf217ba..ce5e3b5b4 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -7,68 +7,10 @@
7#include "common/settings.h" 7#include "common/settings.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/ipc.h" 9#include "core/hle/ipc.h"
10#include "core/hle/kernel/k_process.h"
11#include "core/hle/kernel/k_server_port.h"
12#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
13#include "core/hle/service/acc/acc.h"
14#include "core/hle/service/am/am.h"
15#include "core/hle/service/aoc/aoc_u.h"
16#include "core/hle/service/apm/apm.h"
17#include "core/hle/service/audio/audio.h"
18#include "core/hle/service/bcat/bcat.h"
19#include "core/hle/service/bpc/bpc.h"
20#include "core/hle/service/btdrv/btdrv.h"
21#include "core/hle/service/btm/btm.h"
22#include "core/hle/service/caps/caps.h"
23#include "core/hle/service/erpt/erpt.h"
24#include "core/hle/service/es/es.h"
25#include "core/hle/service/eupld/eupld.h"
26#include "core/hle/service/fatal/fatal.h"
27#include "core/hle/service/fgm/fgm.h"
28#include "core/hle/service/filesystem/filesystem.h"
29#include "core/hle/service/friend/friend.h"
30#include "core/hle/service/glue/glue.h"
31#include "core/hle/service/grc/grc.h"
32#include "core/hle/service/hid/hid.h"
33#include "core/hle/service/ipc_helpers.h" 11#include "core/hle/service/ipc_helpers.h"
34#include "core/hle/service/jit/jit.h"
35#include "core/hle/service/lbl/lbl.h"
36#include "core/hle/service/ldn/ldn.h"
37#include "core/hle/service/ldr/ldr.h"
38#include "core/hle/service/lm/lm.h"
39#include "core/hle/service/mig/mig.h"
40#include "core/hle/service/mii/mii.h"
41#include "core/hle/service/mm/mm_u.h"
42#include "core/hle/service/mnpp/mnpp_app.h"
43#include "core/hle/service/ncm/ncm.h"
44#include "core/hle/service/nfc/nfc.h"
45#include "core/hle/service/nfp/nfp.h"
46#include "core/hle/service/ngc/ngc.h"
47#include "core/hle/service/nifm/nifm.h"
48#include "core/hle/service/nim/nim.h"
49#include "core/hle/service/npns/npns.h"
50#include "core/hle/service/ns/ns.h"
51#include "core/hle/service/nvdrv/nvdrv.h"
52#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
53#include "core/hle/service/nvnflinger/nvnflinger.h"
54#include "core/hle/service/olsc/olsc.h"
55#include "core/hle/service/omm/omm.h"
56#include "core/hle/service/pcie/pcie.h"
57#include "core/hle/service/pctl/pctl_module.h"
58#include "core/hle/service/pcv/pcv.h"
59#include "core/hle/service/pm/pm.h"
60#include "core/hle/service/prepo/prepo.h"
61#include "core/hle/service/psc/psc.h"
62#include "core/hle/service/ptm/ptm.h"
63#include "core/hle/service/ro/ro.h"
64#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
65#include "core/hle/service/set/settings.h"
66#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
67#include "core/hle/service/sockets/sockets.h"
68#include "core/hle/service/spl/spl_module.h"
69#include "core/hle/service/ssl/ssl.h"
70#include "core/hle/service/usb/usb.h"
71#include "core/hle/service/vi/vi.h"
72#include "core/reporter.h" 14#include "core/reporter.h"
73 15
74namespace Service { 16namespace Service {
@@ -209,82 +151,4 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
209 return result; 151 return result;
210} 152}
211 153
212/// Initialize Services
213Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
214 : hos_binder_driver_server{std::make_unique<Nvnflinger::HosBinderDriverServer>(system)},
215 nv_flinger{std::make_unique<Nvnflinger::Nvnflinger>(system, *hos_binder_driver_server)} {
216
217 auto& kernel = system.Kernel();
218
219 // Nvnflinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
220 // here and pass it into the respective InstallInterfaces functions.
221 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
222
223 // clang-format off
224 kernel.RunOnHostCoreProcess("audio", [&] { Audio::LoopProcess(system); }).detach();
225 kernel.RunOnHostCoreProcess("FS", [&] { FileSystem::LoopProcess(system); }).detach();
226 kernel.RunOnHostCoreProcess("jit", [&] { JIT::LoopProcess(system); }).detach();
227 kernel.RunOnHostCoreProcess("ldn", [&] { LDN::LoopProcess(system); }).detach();
228 kernel.RunOnHostCoreProcess("Loader", [&] { LDR::LoopProcess(system); }).detach();
229 kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(*nv_flinger, system); }).detach();
230 kernel.RunOnHostCoreProcess("bsdsocket", [&] { Sockets::LoopProcess(system); }).detach();
231 kernel.RunOnHostCoreProcess("vi", [&] { VI::LoopProcess(system, *nv_flinger, *hos_binder_driver_server); }).detach();
232
233 kernel.RunOnGuestCoreProcess("sm", [&] { SM::LoopProcess(system); });
234 kernel.RunOnGuestCoreProcess("account", [&] { Account::LoopProcess(system); });
235 kernel.RunOnGuestCoreProcess("am", [&] { AM::LoopProcess(*nv_flinger, system); });
236 kernel.RunOnGuestCoreProcess("aoc", [&] { AOC::LoopProcess(system); });
237 kernel.RunOnGuestCoreProcess("apm", [&] { APM::LoopProcess(system); });
238 kernel.RunOnGuestCoreProcess("bcat", [&] { BCAT::LoopProcess(system); });
239 kernel.RunOnGuestCoreProcess("bpc", [&] { BPC::LoopProcess(system); });
240 kernel.RunOnGuestCoreProcess("btdrv", [&] { BtDrv::LoopProcess(system); });
241 kernel.RunOnGuestCoreProcess("btm", [&] { BTM::LoopProcess(system); });
242 kernel.RunOnGuestCoreProcess("capsrv", [&] { Capture::LoopProcess(system); });
243 kernel.RunOnGuestCoreProcess("erpt", [&] { ERPT::LoopProcess(system); });
244 kernel.RunOnGuestCoreProcess("es", [&] { ES::LoopProcess(system); });
245 kernel.RunOnGuestCoreProcess("eupld", [&] { EUPLD::LoopProcess(system); });
246 kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); });
247 kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); });
248 kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); });
249 // glue depends on settings and psc, so they must come first
250 kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
251 kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
252 kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); });
253 kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); });
254 kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); });
255 kernel.RunOnGuestCoreProcess("lbl", [&] { LBL::LoopProcess(system); });
256 kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); });
257 kernel.RunOnGuestCoreProcess("mig", [&] { Migration::LoopProcess(system); });
258 kernel.RunOnGuestCoreProcess("mii", [&] { Mii::LoopProcess(system); });
259 kernel.RunOnGuestCoreProcess("mm", [&] { MM::LoopProcess(system); });
260 kernel.RunOnGuestCoreProcess("mnpp", [&] { MNPP::LoopProcess(system); });
261 kernel.RunOnGuestCoreProcess("NCM", [&] { NCM::LoopProcess(system); });
262 kernel.RunOnGuestCoreProcess("nfc", [&] { NFC::LoopProcess(system); });
263 kernel.RunOnGuestCoreProcess("nfp", [&] { NFP::LoopProcess(system); });
264 kernel.RunOnGuestCoreProcess("ngc", [&] { NGC::LoopProcess(system); });
265 kernel.RunOnGuestCoreProcess("nifm", [&] { NIFM::LoopProcess(system); });
266 kernel.RunOnGuestCoreProcess("nim", [&] { NIM::LoopProcess(system); });
267 kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); });
268 kernel.RunOnGuestCoreProcess("ns", [&] { NS::LoopProcess(system); });
269 kernel.RunOnGuestCoreProcess("olsc", [&] { OLSC::LoopProcess(system); });
270 kernel.RunOnGuestCoreProcess("omm", [&] { OMM::LoopProcess(system); });
271 kernel.RunOnGuestCoreProcess("pcie", [&] { PCIe::LoopProcess(system); });
272 kernel.RunOnGuestCoreProcess("pctl", [&] { PCTL::LoopProcess(system); });
273 kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); });
274 kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); });
275 kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
276 kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); });
277 kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); });
278 kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); });
279 kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); });
280 kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); });
281 // clang-format on
282}
283
284Services::~Services() = default;
285
286void Services::KillNVNFlinger() {
287 nv_flinger->ShutdownLayers();
288}
289
290} // namespace Service 154} // namespace Service
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 22d1343d5..36aae1c79 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -28,11 +28,6 @@ namespace FileSystem {
28class FileSystemController; 28class FileSystemController;
29} 29}
30 30
31namespace Nvnflinger {
32class HosBinderDriverServer;
33class Nvnflinger;
34} // namespace Nvnflinger
35
36namespace SM { 31namespace SM {
37class ServiceManager; 32class ServiceManager;
38} 33}
@@ -236,20 +231,4 @@ private:
236 } 231 }
237}; 232};
238 233
239/**
240 * The purpose of this class is to own any objects that need to be shared across the other service
241 * implementations. Will be torn down when the global system instance is shutdown.
242 */
243class Services final {
244public:
245 explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
246 ~Services();
247
248 void KillNVNFlinger();
249
250private:
251 std::unique_ptr<Nvnflinger::HosBinderDriverServer> hos_binder_driver_server;
252 std::unique_ptr<Nvnflinger::Nvnflinger> nv_flinger;
253};
254
255} // namespace Service 234} // namespace Service
diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp
new file mode 100644
index 000000000..d6c6eff50
--- /dev/null
+++ b/src/core/hle/service/services.cpp
@@ -0,0 +1,136 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/services.h"
5
6#include "core/hle/service/acc/acc.h"
7#include "core/hle/service/am/am.h"
8#include "core/hle/service/aoc/aoc_u.h"
9#include "core/hle/service/apm/apm.h"
10#include "core/hle/service/audio/audio.h"
11#include "core/hle/service/bcat/bcat.h"
12#include "core/hle/service/bpc/bpc.h"
13#include "core/hle/service/btdrv/btdrv.h"
14#include "core/hle/service/btm/btm.h"
15#include "core/hle/service/caps/caps.h"
16#include "core/hle/service/erpt/erpt.h"
17#include "core/hle/service/es/es.h"
18#include "core/hle/service/eupld/eupld.h"
19#include "core/hle/service/fatal/fatal.h"
20#include "core/hle/service/fgm/fgm.h"
21#include "core/hle/service/filesystem/filesystem.h"
22#include "core/hle/service/friend/friend.h"
23#include "core/hle/service/glue/glue.h"
24#include "core/hle/service/grc/grc.h"
25#include "core/hle/service/hid/hid.h"
26#include "core/hle/service/ipc_helpers.h"
27#include "core/hle/service/jit/jit.h"
28#include "core/hle/service/lbl/lbl.h"
29#include "core/hle/service/ldn/ldn.h"
30#include "core/hle/service/ldr/ldr.h"
31#include "core/hle/service/lm/lm.h"
32#include "core/hle/service/mig/mig.h"
33#include "core/hle/service/mii/mii.h"
34#include "core/hle/service/mm/mm_u.h"
35#include "core/hle/service/mnpp/mnpp_app.h"
36#include "core/hle/service/ncm/ncm.h"
37#include "core/hle/service/nfc/nfc.h"
38#include "core/hle/service/nfp/nfp.h"
39#include "core/hle/service/ngc/ngc.h"
40#include "core/hle/service/nifm/nifm.h"
41#include "core/hle/service/nim/nim.h"
42#include "core/hle/service/npns/npns.h"
43#include "core/hle/service/ns/ns.h"
44#include "core/hle/service/nvdrv/nvdrv.h"
45#include "core/hle/service/nvnflinger/nvnflinger.h"
46#include "core/hle/service/olsc/olsc.h"
47#include "core/hle/service/omm/omm.h"
48#include "core/hle/service/pcie/pcie.h"
49#include "core/hle/service/pctl/pctl_module.h"
50#include "core/hle/service/pcv/pcv.h"
51#include "core/hle/service/pm/pm.h"
52#include "core/hle/service/prepo/prepo.h"
53#include "core/hle/service/psc/psc.h"
54#include "core/hle/service/ptm/ptm.h"
55#include "core/hle/service/ro/ro.h"
56#include "core/hle/service/service.h"
57#include "core/hle/service/set/settings.h"
58#include "core/hle/service/sm/sm.h"
59#include "core/hle/service/sockets/sockets.h"
60#include "core/hle/service/spl/spl_module.h"
61#include "core/hle/service/ssl/ssl.h"
62#include "core/hle/service/usb/usb.h"
63#include "core/hle/service/vi/vi.h"
64
65namespace Service {
66
67Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
68 std::stop_token token) {
69 auto& kernel = system.Kernel();
70
71 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
72
73 // clang-format off
74 kernel.RunOnHostCoreProcess("audio", [&] { Audio::LoopProcess(system); }).detach();
75 kernel.RunOnHostCoreProcess("FS", [&] { FileSystem::LoopProcess(system); }).detach();
76 kernel.RunOnHostCoreProcess("jit", [&] { JIT::LoopProcess(system); }).detach();
77 kernel.RunOnHostCoreProcess("ldn", [&] { LDN::LoopProcess(system); }).detach();
78 kernel.RunOnHostCoreProcess("Loader", [&] { LDR::LoopProcess(system); }).detach();
79 kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(system); }).detach();
80 kernel.RunOnHostCoreProcess("bsdsocket", [&] { Sockets::LoopProcess(system); }).detach();
81 kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach();
82
83 kernel.RunOnGuestCoreProcess("sm", [&] { SM::LoopProcess(system); });
84 kernel.RunOnGuestCoreProcess("account", [&] { Account::LoopProcess(system); });
85 kernel.RunOnGuestCoreProcess("am", [&] { AM::LoopProcess(system); });
86 kernel.RunOnGuestCoreProcess("aoc", [&] { AOC::LoopProcess(system); });
87 kernel.RunOnGuestCoreProcess("apm", [&] { APM::LoopProcess(system); });
88 kernel.RunOnGuestCoreProcess("bcat", [&] { BCAT::LoopProcess(system); });
89 kernel.RunOnGuestCoreProcess("bpc", [&] { BPC::LoopProcess(system); });
90 kernel.RunOnGuestCoreProcess("btdrv", [&] { BtDrv::LoopProcess(system); });
91 kernel.RunOnGuestCoreProcess("btm", [&] { BTM::LoopProcess(system); });
92 kernel.RunOnGuestCoreProcess("capsrv", [&] { Capture::LoopProcess(system); });
93 kernel.RunOnGuestCoreProcess("erpt", [&] { ERPT::LoopProcess(system); });
94 kernel.RunOnGuestCoreProcess("es", [&] { ES::LoopProcess(system); });
95 kernel.RunOnGuestCoreProcess("eupld", [&] { EUPLD::LoopProcess(system); });
96 kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); });
97 kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); });
98 kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); });
99 kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
100 kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
101 kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); });
102 kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); });
103 kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); });
104 kernel.RunOnGuestCoreProcess("lbl", [&] { LBL::LoopProcess(system); });
105 kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); });
106 kernel.RunOnGuestCoreProcess("mig", [&] { Migration::LoopProcess(system); });
107 kernel.RunOnGuestCoreProcess("mii", [&] { Mii::LoopProcess(system); });
108 kernel.RunOnGuestCoreProcess("mm", [&] { MM::LoopProcess(system); });
109 kernel.RunOnGuestCoreProcess("mnpp", [&] { MNPP::LoopProcess(system); });
110 kernel.RunOnGuestCoreProcess("nvnflinger", [&] { Nvnflinger::LoopProcess(system); });
111 kernel.RunOnGuestCoreProcess("NCM", [&] { NCM::LoopProcess(system); });
112 kernel.RunOnGuestCoreProcess("nfc", [&] { NFC::LoopProcess(system); });
113 kernel.RunOnGuestCoreProcess("nfp", [&] { NFP::LoopProcess(system); });
114 kernel.RunOnGuestCoreProcess("ngc", [&] { NGC::LoopProcess(system); });
115 kernel.RunOnGuestCoreProcess("nifm", [&] { NIFM::LoopProcess(system); });
116 kernel.RunOnGuestCoreProcess("nim", [&] { NIM::LoopProcess(system); });
117 kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); });
118 kernel.RunOnGuestCoreProcess("ns", [&] { NS::LoopProcess(system); });
119 kernel.RunOnGuestCoreProcess("olsc", [&] { OLSC::LoopProcess(system); });
120 kernel.RunOnGuestCoreProcess("omm", [&] { OMM::LoopProcess(system); });
121 kernel.RunOnGuestCoreProcess("pcie", [&] { PCIe::LoopProcess(system); });
122 kernel.RunOnGuestCoreProcess("pctl", [&] { PCTL::LoopProcess(system); });
123 kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); });
124 kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); });
125 kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
126 kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); });
127 kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); });
128 kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); });
129 kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); });
130 kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); });
131 // clang-format on
132}
133
134Services::~Services() = default;
135
136} // namespace Service
diff --git a/src/core/hle/service/services.h b/src/core/hle/service/services.h
new file mode 100644
index 000000000..a99fa1e53
--- /dev/null
+++ b/src/core/hle/service/services.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/polyfill_thread.h"
7#include "core/hle/service/sm/sm.h"
8
9namespace Service {
10
11/**
12 * The purpose of this class is to own any objects that need to be shared across the other service
13 * implementations. Will be torn down when the global system instance is shutdown.
14 */
15class Services final {
16public:
17 explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
18 std::stop_token token);
19 ~Services();
20};
21
22} // namespace Service
diff --git a/src/core/hle/service/vi/application_display_service.cpp b/src/core/hle/service/vi/application_display_service.cpp
index 78229e30f..6b0bcb536 100644
--- a/src/core/hle/service/vi/application_display_service.cpp
+++ b/src/core/hle/service/vi/application_display_service.cpp
@@ -2,22 +2,21 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/nvnflinger.h" 5#include "core/hle/service/nvnflinger/hos_binder_driver.h"
6#include "core/hle/service/nvnflinger/parcel.h" 6#include "core/hle/service/nvnflinger/parcel.h"
7#include "core/hle/service/os/event.h"
7#include "core/hle/service/vi/application_display_service.h" 8#include "core/hle/service/vi/application_display_service.h"
8#include "core/hle/service/vi/hos_binder_driver.h" 9#include "core/hle/service/vi/container.h"
9#include "core/hle/service/vi/manager_display_service.h" 10#include "core/hle/service/vi/manager_display_service.h"
10#include "core/hle/service/vi/system_display_service.h" 11#include "core/hle/service/vi/system_display_service.h"
11#include "core/hle/service/vi/vi_results.h" 12#include "core/hle/service/vi/vi_results.h"
12 13
13namespace Service::VI { 14namespace Service::VI {
14 15
15IApplicationDisplayService::IApplicationDisplayService( 16IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
16 Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, 17 std::shared_ptr<Container> container)
17 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) 18 : ServiceFramework{system_, "IApplicationDisplayService"},
18 : ServiceFramework{system_, "IApplicationDisplayService"}, m_nvnflinger{nvnflinger}, 19 m_container{std::move(container)}, m_context{system, "IApplicationDisplayService"} {
19 m_hos_binder_driver_server{hos_binder_driver_server} {
20
21 // clang-format off 20 // clang-format off
22 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
23 {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"}, 22 {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"},
@@ -48,38 +47,41 @@ IApplicationDisplayService::IApplicationDisplayService(
48} 47}
49 48
50IApplicationDisplayService::~IApplicationDisplayService() { 49IApplicationDisplayService::~IApplicationDisplayService() {
50 for (auto& [display_id, event] : m_display_vsync_events) {
51 m_container->UnlinkVsyncEvent(display_id, &event);
52 }
53 for (const auto layer_id : m_open_layer_ids) {
54 m_container->CloseLayer(layer_id);
55 }
51 for (const auto layer_id : m_stray_layer_ids) { 56 for (const auto layer_id : m_stray_layer_ids) {
52 m_nvnflinger.DestroyLayer(layer_id); 57 m_container->DestroyStrayLayer(layer_id);
53 } 58 }
54} 59}
55 60
56Result IApplicationDisplayService::GetRelayService( 61Result IApplicationDisplayService::GetRelayService(
57 Out<SharedPointer<IHOSBinderDriver>> out_relay_service) { 62 Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service) {
58 LOG_WARNING(Service_VI, "(STUBBED) called"); 63 LOG_WARNING(Service_VI, "(STUBBED) called");
59 *out_relay_service = std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server); 64 R_RETURN(m_container->GetBinderDriver(out_relay_service));
60 R_SUCCEED();
61} 65}
62 66
63Result IApplicationDisplayService::GetSystemDisplayService( 67Result IApplicationDisplayService::GetSystemDisplayService(
64 Out<SharedPointer<ISystemDisplayService>> out_system_display_service) { 68 Out<SharedPointer<ISystemDisplayService>> out_system_display_service) {
65 LOG_WARNING(Service_VI, "(STUBBED) called"); 69 LOG_WARNING(Service_VI, "(STUBBED) called");
66 *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_nvnflinger); 70 *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_container);
67 R_SUCCEED(); 71 R_SUCCEED();
68} 72}
69 73
70Result IApplicationDisplayService::GetManagerDisplayService( 74Result IApplicationDisplayService::GetManagerDisplayService(
71 Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) { 75 Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) {
72 LOG_WARNING(Service_VI, "(STUBBED) called"); 76 LOG_WARNING(Service_VI, "(STUBBED) called");
73 *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_nvnflinger); 77 *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_container);
74 R_SUCCEED(); 78 R_SUCCEED();
75} 79}
76 80
77Result IApplicationDisplayService::GetIndirectDisplayTransactionService( 81Result IApplicationDisplayService::GetIndirectDisplayTransactionService(
78 Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service) { 82 Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service) {
79 LOG_WARNING(Service_VI, "(STUBBED) called"); 83 LOG_WARNING(Service_VI, "(STUBBED) called");
80 *out_indirect_display_transaction_service = 84 R_RETURN(m_container->GetBinderDriver(out_indirect_display_transaction_service));
81 std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server);
82 R_SUCCEED();
83} 85}
84 86
85Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) { 87Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) {
@@ -89,14 +91,7 @@ Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayN
89 ASSERT_MSG(strcmp(display_name.data(), "Default") == 0, 91 ASSERT_MSG(strcmp(display_name.data(), "Default") == 0,
90 "Non-default displays aren't supported yet"); 92 "Non-default displays aren't supported yet");
91 93
92 const auto display_id = m_nvnflinger.OpenDisplay(display_name.data()); 94 R_RETURN(m_container->OpenDisplay(out_display_id, display_name));
93 if (!display_id) {
94 LOG_ERROR(Service_VI, "Display not found! display_name={}", display_name.data());
95 R_THROW(VI::ResultNotFound);
96 }
97
98 *out_display_id = *display_id;
99 R_SUCCEED();
100} 95}
101 96
102Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) { 97Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) {
@@ -106,8 +101,7 @@ Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) {
106 101
107Result IApplicationDisplayService::CloseDisplay(u64 display_id) { 102Result IApplicationDisplayService::CloseDisplay(u64 display_id) {
108 LOG_DEBUG(Service_VI, "called"); 103 LOG_DEBUG(Service_VI, "called");
109 R_SUCCEED_IF(m_nvnflinger.CloseDisplay(display_id)); 104 R_RETURN(m_container->CloseDisplay(display_id));
110 R_THROW(ResultUnknown);
111} 105}
112 106
113Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) { 107Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) {
@@ -168,25 +162,19 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size,
168 162
169 LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid); 163 LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid);
170 164
171 const auto display_id = m_nvnflinger.OpenDisplay(display_name.data()); 165 u64 display_id;
172 if (!display_id) { 166 R_TRY(m_container->OpenDisplay(&display_id, display_name));
173 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
174 R_THROW(VI::ResultNotFound);
175 }
176 167
177 const auto buffer_queue_id = m_nvnflinger.FindBufferQueueId(*display_id, layer_id); 168 s32 producer_binder_id;
178 if (!buffer_queue_id) { 169 R_TRY(m_container->OpenLayer(&producer_binder_id, layer_id, aruid.pid));
179 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
180 R_THROW(VI::ResultNotFound);
181 }
182 170
183 if (!m_nvnflinger.OpenLayer(layer_id)) { 171 {
184 LOG_WARNING(Service_VI, "Tried to open layer which was already open"); 172 std::scoped_lock lk{m_lock};
185 R_THROW(VI::ResultOperationFailed); 173 m_open_layer_ids.insert(layer_id);
186 } 174 }
187 175
188 android::OutputParcel parcel; 176 android::OutputParcel parcel;
189 parcel.WriteInterface(NativeWindow{*buffer_queue_id}); 177 parcel.WriteInterface(NativeWindow{producer_binder_id});
190 178
191 const auto buffer = parcel.Serialize(); 179 const auto buffer = parcel.Serialize();
192 std::memcpy(out_native_window.data(), buffer.data(), 180 std::memcpy(out_native_window.data(), buffer.data(),
@@ -199,12 +187,13 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size,
199Result IApplicationDisplayService::CloseLayer(u64 layer_id) { 187Result IApplicationDisplayService::CloseLayer(u64 layer_id) {
200 LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id); 188 LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
201 189
202 if (!m_nvnflinger.CloseLayer(layer_id)) { 190 {
203 LOG_WARNING(Service_VI, "Tried to close layer which was not open"); 191 std::scoped_lock lk{m_lock};
204 R_THROW(VI::ResultOperationFailed); 192 R_UNLESS(m_open_layer_ids.contains(layer_id), VI::ResultNotFound);
193 m_open_layer_ids.erase(layer_id);
205 } 194 }
206 195
207 R_SUCCEED(); 196 R_RETURN(m_container->CloseLayer(layer_id));
208} 197}
209 198
210Result IApplicationDisplayService::CreateStrayLayer( 199Result IApplicationDisplayService::CreateStrayLayer(
@@ -212,27 +201,19 @@ Result IApplicationDisplayService::CreateStrayLayer(
212 u32 flags, u64 display_id) { 201 u32 flags, u64 display_id) {
213 LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id); 202 LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id);
214 203
215 const auto layer_id = m_nvnflinger.CreateLayer(display_id); 204 s32 producer_binder_id;
216 if (!layer_id) { 205 R_TRY(m_container->CreateStrayLayer(&producer_binder_id, out_layer_id, display_id));
217 LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
218 R_THROW(VI::ResultNotFound);
219 }
220 206
221 m_stray_layer_ids.push_back(*layer_id); 207 std::scoped_lock lk{m_lock};
222 const auto buffer_queue_id = m_nvnflinger.FindBufferQueueId(display_id, *layer_id); 208 m_stray_layer_ids.insert(*out_layer_id);
223 if (!buffer_queue_id) {
224 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
225 R_THROW(VI::ResultNotFound);
226 }
227 209
228 android::OutputParcel parcel; 210 android::OutputParcel parcel;
229 parcel.WriteInterface(NativeWindow{*buffer_queue_id}); 211 parcel.WriteInterface(NativeWindow{producer_binder_id});
230 212
231 const auto buffer = parcel.Serialize(); 213 const auto buffer = parcel.Serialize();
232 std::memcpy(out_native_window.data(), buffer.data(), 214 std::memcpy(out_native_window.data(), buffer.data(),
233 std::min(out_native_window.size(), buffer.size())); 215 std::min(out_native_window.size(), buffer.size()));
234 216
235 *out_layer_id = *layer_id;
236 *out_size = buffer.size(); 217 *out_size = buffer.size();
237 218
238 R_SUCCEED(); 219 R_SUCCEED();
@@ -240,25 +221,27 @@ Result IApplicationDisplayService::CreateStrayLayer(
240 221
241Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) { 222Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) {
242 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id); 223 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id);
243 m_nvnflinger.DestroyLayer(layer_id); 224
244 R_SUCCEED(); 225 {
226 std::scoped_lock lk{m_lock};
227 R_UNLESS(m_stray_layer_ids.contains(layer_id), VI::ResultNotFound);
228 m_stray_layer_ids.erase(layer_id);
229 }
230
231 R_RETURN(m_container->DestroyStrayLayer(layer_id));
245} 232}
246 233
247Result IApplicationDisplayService::GetDisplayVsyncEvent( 234Result IApplicationDisplayService::GetDisplayVsyncEvent(
248 OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) { 235 OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) {
249 LOG_DEBUG(Service_VI, "called. display_id={}", display_id); 236 LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
250 237
251 const auto result = m_nvnflinger.FindVsyncEvent(out_vsync_event, display_id); 238 std::scoped_lock lk{m_lock};
252 if (result != ResultSuccess) {
253 if (result == ResultNotFound) {
254 LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
255 }
256 239
257 R_THROW(result); 240 auto [it, created] = m_display_vsync_events.emplace(display_id, m_context);
258 } 241 R_UNLESS(created, VI::ResultPermissionDenied);
259 242
260 R_UNLESS(!m_vsync_event_fetched, VI::ResultPermissionDenied); 243 m_container->LinkVsyncEvent(display_id, &it->second);
261 m_vsync_event_fetched = true; 244 *out_vsync_event = it->second.GetHandle();
262 245
263 R_SUCCEED(); 246 R_SUCCEED();
264} 247}
diff --git a/src/core/hle/service/vi/application_display_service.h b/src/core/hle/service/vi/application_display_service.h
index 5dff4bb31..1bdeb8f84 100644
--- a/src/core/hle/service/vi/application_display_service.h
+++ b/src/core/hle/service/vi/application_display_service.h
@@ -1,7 +1,12 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <map>
5#include <set>
6
4#include "core/hle/service/cmif_types.h" 7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/os/event.h"
5#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
6#include "core/hle/service/vi/vi_types.h" 11#include "core/hle/service/vi/vi_types.h"
7 12
@@ -9,26 +14,33 @@ namespace Kernel {
9class KReadableEvent; 14class KReadableEvent;
10} 15}
11 16
17namespace Service::Nvnflinger {
18class IHOSBinderDriver;
19}
20
12namespace Service::VI { 21namespace Service::VI {
13 22
14class IHOSBinderDriver; 23class Container;
15class IManagerDisplayService; 24class IManagerDisplayService;
16class ISystemDisplayService; 25class ISystemDisplayService;
17 26
18class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { 27class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
19public: 28public:
20 IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, 29 IApplicationDisplayService(Core::System& system_, std::shared_ptr<Container> container);
21 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
22 ~IApplicationDisplayService() override; 30 ~IApplicationDisplayService() override;
23 31
24private: 32 std::shared_ptr<Container> GetContainer() const {
25 Result GetRelayService(Out<SharedPointer<IHOSBinderDriver>> out_relay_service); 33 return m_container;
34 }
35
36public:
37 Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service);
26 Result GetSystemDisplayService( 38 Result GetSystemDisplayService(
27 Out<SharedPointer<ISystemDisplayService>> out_system_display_service); 39 Out<SharedPointer<ISystemDisplayService>> out_system_display_service);
28 Result GetManagerDisplayService( 40 Result GetManagerDisplayService(
29 Out<SharedPointer<IManagerDisplayService>> out_manager_display_service); 41 Out<SharedPointer<IManagerDisplayService>> out_manager_display_service);
30 Result GetIndirectDisplayTransactionService( 42 Result GetIndirectDisplayTransactionService(
31 Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service); 43 Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service);
32 Result OpenDisplay(Out<u64> out_display_id, DisplayName display_name); 44 Result OpenDisplay(Out<u64> out_display_id, DisplayName display_name);
33 Result OpenDefaultDisplay(Out<u64> out_display_id); 45 Result OpenDefaultDisplay(Out<u64> out_display_id);
34 Result CloseDisplay(u64 display_id); 46 Result CloseDisplay(u64 display_id);
@@ -56,9 +68,13 @@ private:
56 s64 width, s64 height); 68 s64 width, s64 height);
57 69
58private: 70private:
59 Nvnflinger::Nvnflinger& m_nvnflinger; 71 const std::shared_ptr<Container> m_container;
60 Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server; 72
61 std::vector<u64> m_stray_layer_ids; 73 KernelHelpers::ServiceContext m_context;
74 std::mutex m_lock{};
75 std::set<u64> m_open_layer_ids{};
76 std::set<u64> m_stray_layer_ids{};
77 std::map<u64, Event> m_display_vsync_events{};
62 bool m_vsync_event_fetched{false}; 78 bool m_vsync_event_fetched{false};
63}; 79};
64 80
diff --git a/src/core/hle/service/vi/application_root_service.cpp b/src/core/hle/service/vi/application_root_service.cpp
index 7af7f062c..7f35a048d 100644
--- a/src/core/hle/service/vi/application_root_service.cpp
+++ b/src/core/hle/service/vi/application_root_service.cpp
@@ -4,17 +4,16 @@
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/vi/application_display_service.h" 5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/application_root_service.h" 6#include "core/hle/service/vi/application_root_service.h"
7#include "core/hle/service/vi/container.h"
7#include "core/hle/service/vi/service_creator.h" 8#include "core/hle/service/vi/service_creator.h"
8#include "core/hle/service/vi/vi.h" 9#include "core/hle/service/vi/vi.h"
9#include "core/hle/service/vi/vi_types.h" 10#include "core/hle/service/vi/vi_types.h"
10 11
11namespace Service::VI { 12namespace Service::VI {
12 13
13IApplicationRootService::IApplicationRootService( 14IApplicationRootService::IApplicationRootService(Core::System& system_,
14 Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, 15 std::shared_ptr<Container> container)
15 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) 16 : ServiceFramework{system_, "vi:u"}, m_container{std::move(container)} {
16 : ServiceFramework{system_, "vi:u"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
17 hos_binder_driver_server} {
18 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
19 {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"}, 18 {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"},
20 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 19 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -27,8 +26,8 @@ IApplicationRootService::~IApplicationRootService() = default;
27Result IApplicationRootService::GetDisplayService( 26Result IApplicationRootService::GetDisplayService(
28 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { 27 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
29 LOG_DEBUG(Service_VI, "called"); 28 LOG_DEBUG(Service_VI, "called");
30 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger, 29 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
31 m_hos_binder_driver_server, Permission::User, policy)); 30 Permission::User, policy));
32} 31}
33 32
34} // namespace Service::VI 33} // namespace Service::VI
diff --git a/src/core/hle/service/vi/application_root_service.h b/src/core/hle/service/vi/application_root_service.h
index 9dbf28cb4..15aa4483d 100644
--- a/src/core/hle/service/vi/application_root_service.h
+++ b/src/core/hle/service/vi/application_root_service.h
@@ -10,20 +10,15 @@ namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Service::Nvnflinger {
14class HosBinderDriverServer;
15class Nvnflinger;
16} // namespace Service::Nvnflinger
17
18namespace Service::VI { 13namespace Service::VI {
19 14
15class Container;
20class IApplicationDisplayService; 16class IApplicationDisplayService;
21enum class Policy : u32; 17enum class Policy : u32;
22 18
23class IApplicationRootService final : public ServiceFramework<IApplicationRootService> { 19class IApplicationRootService final : public ServiceFramework<IApplicationRootService> {
24public: 20public:
25 explicit IApplicationRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, 21 explicit IApplicationRootService(Core::System& system_, std::shared_ptr<Container> container);
26 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
27 ~IApplicationRootService() override; 22 ~IApplicationRootService() override;
28 23
29private: 24private:
@@ -32,8 +27,7 @@ private:
32 Policy policy); 27 Policy policy);
33 28
34private: 29private:
35 Nvnflinger::Nvnflinger& m_nvnflinger; 30 const std::shared_ptr<Container> m_container;
36 Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
37}; 31};
38 32
39} // namespace Service::VI 33} // namespace Service::VI
diff --git a/src/core/hle/service/vi/conductor.cpp b/src/core/hle/service/vi/conductor.cpp
new file mode 100644
index 000000000..c8ce4fca0
--- /dev/null
+++ b/src/core/hle/service/vi/conductor.cpp
@@ -0,0 +1,114 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/hle/service/vi/conductor.h"
8#include "core/hle/service/vi/container.h"
9#include "core/hle/service/vi/display_list.h"
10#include "core/hle/service/vi/vsync_manager.h"
11
12constexpr auto FrameNs = std::chrono::nanoseconds{1000000000 / 60};
13
14namespace Service::VI {
15
16Conductor::Conductor(Core::System& system, Container& container, DisplayList& displays)
17 : m_system(system), m_container(container) {
18 displays.ForEachDisplay([&](Display& display) {
19 m_vsync_managers.insert({display.GetId(), VsyncManager{}});
20 });
21
22 if (system.IsMulticore()) {
23 m_event = Core::Timing::CreateEvent(
24 "ScreenComposition",
25 [this](s64 time,
26 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
27 m_signal.Set();
28 return std::chrono::nanoseconds(this->GetNextTicks());
29 });
30
31 system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
32 m_thread = std::jthread([this](std::stop_token token) { this->VsyncThread(token); });
33 } else {
34 m_event = Core::Timing::CreateEvent(
35 "ScreenComposition",
36 [this](s64 time,
37 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
38 this->ProcessVsync();
39 return std::chrono::nanoseconds(this->GetNextTicks());
40 });
41
42 system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
43 }
44}
45
46Conductor::~Conductor() {
47 m_system.CoreTiming().UnscheduleEvent(m_event);
48
49 if (m_system.IsMulticore()) {
50 m_thread.request_stop();
51 m_signal.Set();
52 }
53}
54
55void Conductor::LinkVsyncEvent(u64 display_id, Event* event) {
56 if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) {
57 it->second.LinkVsyncEvent(event);
58 }
59}
60
61void Conductor::UnlinkVsyncEvent(u64 display_id, Event* event) {
62 if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) {
63 it->second.UnlinkVsyncEvent(event);
64 }
65}
66
67void Conductor::ProcessVsync() {
68 for (auto& [display_id, manager] : m_vsync_managers) {
69 m_container.ComposeOnDisplay(&m_swap_interval, &m_compose_speed_scale, display_id);
70 manager.SignalVsync();
71 }
72}
73
74void Conductor::VsyncThread(std::stop_token token) {
75 Common::SetCurrentThreadName("VSyncThread");
76
77 while (!token.stop_requested()) {
78 m_signal.Wait();
79
80 if (m_system.IsShuttingDown()) {
81 return;
82 }
83
84 this->ProcessVsync();
85 }
86}
87
88s64 Conductor::GetNextTicks() const {
89 const auto& settings = Settings::values;
90 auto speed_scale = 1.f;
91 if (settings.use_multi_core.GetValue()) {
92 if (settings.use_speed_limit.GetValue()) {
93 // Scales the speed based on speed_limit setting on MC. SC is handled by
94 // SpeedLimiter::DoSpeedLimiting.
95 speed_scale = 100.f / settings.speed_limit.GetValue();
96 } else {
97 // Run at unlocked framerate.
98 speed_scale = 0.01f;
99 }
100 }
101
102 // Adjust by speed limit determined during composition.
103 speed_scale /= m_compose_speed_scale;
104
105 if (m_system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
106 // Run at intended presentation rate during video playback.
107 speed_scale = 1.f;
108 }
109
110 const f32 effective_fps = 60.f / static_cast<f32>(m_swap_interval);
111 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
112}
113
114} // namespace Service::VI
diff --git a/src/core/hle/service/vi/conductor.h b/src/core/hle/service/vi/conductor.h
new file mode 100644
index 000000000..52e3595d2
--- /dev/null
+++ b/src/core/hle/service/vi/conductor.h
@@ -0,0 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <unordered_map>
8
9#include "common/common_types.h"
10#include "common/polyfill_thread.h"
11#include "common/thread.h"
12
13namespace Core {
14class System;
15}
16
17namespace Core::Timing {
18struct EventType;
19}
20
21namespace Service {
22class Event;
23}
24
25namespace Service::VI {
26
27class Container;
28class DisplayList;
29class VsyncManager;
30
31class Conductor {
32public:
33 explicit Conductor(Core::System& system, Container& container, DisplayList& displays);
34 ~Conductor();
35
36 void LinkVsyncEvent(u64 display_id, Event* event);
37 void UnlinkVsyncEvent(u64 display_id, Event* event);
38
39private:
40 void ProcessVsync();
41 void VsyncThread(std::stop_token token);
42 s64 GetNextTicks() const;
43
44private:
45 Core::System& m_system;
46 Container& m_container;
47 std::unordered_map<u64, VsyncManager> m_vsync_managers;
48 std::shared_ptr<Core::Timing::EventType> m_event;
49 Common::Event m_signal;
50 std::jthread m_thread;
51
52private:
53 s32 m_swap_interval = 1;
54 f32 m_compose_speed_scale = 1.0f;
55};
56
57} // namespace Service::VI
diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp
new file mode 100644
index 000000000..9074f4ae0
--- /dev/null
+++ b/src/core/hle/service/vi/container.cpp
@@ -0,0 +1,226 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/nvdrv/nvdrv_interface.h"
6#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
7#include "core/hle/service/nvnflinger/hos_binder_driver.h"
8#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
9#include "core/hle/service/nvnflinger/surface_flinger.h"
10#include "core/hle/service/sm/sm.h"
11#include "core/hle/service/vi/container.h"
12#include "core/hle/service/vi/vi_results.h"
13
14namespace Service::VI {
15
16Container::Container(Core::System& system) {
17 m_displays.CreateDisplay(DisplayName{"Default"});
18 m_displays.CreateDisplay(DisplayName{"External"});
19 m_displays.CreateDisplay(DisplayName{"Edid"});
20 m_displays.CreateDisplay(DisplayName{"Internal"});
21 m_displays.CreateDisplay(DisplayName{"Null"});
22
23 m_binder_driver =
24 system.ServiceManager().GetService<Nvnflinger::IHOSBinderDriver>("dispdrv", true);
25 m_surface_flinger = m_binder_driver->GetSurfaceFlinger();
26
27 const auto nvdrv =
28 system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
29 m_shared_buffer_manager.emplace(system, *this, nvdrv);
30
31 m_displays.ForEachDisplay(
32 [&](auto& display) { m_surface_flinger->AddDisplay(display.GetId()); });
33
34 m_conductor.emplace(system, *this, m_displays);
35}
36
37Container::~Container() {
38 this->OnTerminate();
39}
40
41void Container::OnTerminate() {
42 std::scoped_lock lk{m_lock};
43
44 m_is_shut_down = true;
45
46 m_layers.ForEachLayer([&](auto& layer) { this->DestroyLayerLocked(layer.GetId()); });
47
48 m_displays.ForEachDisplay(
49 [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); });
50}
51
52SharedBufferManager* Container::GetSharedBufferManager() {
53 return std::addressof(*m_shared_buffer_manager);
54}
55
56Result Container::GetBinderDriver(
57 std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver) {
58 *out_binder_driver = m_binder_driver;
59 R_SUCCEED();
60}
61
62Result Container::GetLayerProducerHandle(
63 std::shared_ptr<android::BufferQueueProducer>* out_producer, u64 layer_id) {
64 std::scoped_lock lk{m_lock};
65
66 auto* const layer = m_layers.GetLayerById(layer_id);
67 R_UNLESS(layer != nullptr, VI::ResultNotFound);
68
69 const auto binder = m_binder_driver->GetServer()->TryGetBinder(layer->GetProducerBinderId());
70 R_UNLESS(binder != nullptr, VI::ResultNotFound);
71
72 *out_producer = std::static_pointer_cast<android::BufferQueueProducer>(binder);
73 R_SUCCEED();
74}
75
76Result Container::OpenDisplay(u64* out_display_id, const DisplayName& display_name) {
77 auto* const display = m_displays.GetDisplayByName(display_name);
78 R_UNLESS(display != nullptr, VI::ResultNotFound);
79
80 *out_display_id = display->GetId();
81 R_SUCCEED();
82}
83
84Result Container::CloseDisplay(u64 display_id) {
85 R_SUCCEED();
86}
87
88Result Container::CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid) {
89 std::scoped_lock lk{m_lock};
90 R_RETURN(this->CreateLayerLocked(out_layer_id, display_id, owner_aruid));
91}
92
93Result Container::DestroyManagedLayer(u64 layer_id) {
94 std::scoped_lock lk{m_lock};
95
96 // Try to close, if open, but don't fail if not.
97 this->CloseLayerLocked(layer_id);
98
99 R_RETURN(this->DestroyLayerLocked(layer_id));
100}
101
102Result Container::OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
103 std::scoped_lock lk{m_lock};
104 R_RETURN(this->OpenLayerLocked(out_producer_binder_id, layer_id, aruid));
105}
106
107Result Container::CloseLayer(u64 layer_id) {
108 std::scoped_lock lk{m_lock};
109 R_RETURN(this->CloseLayerLocked(layer_id));
110}
111
112Result Container::SetLayerVisibility(u64 layer_id, bool visible) {
113 std::scoped_lock lk{m_lock};
114
115 auto* const layer = m_layers.GetLayerById(layer_id);
116 R_UNLESS(layer != nullptr, VI::ResultNotFound);
117
118 m_surface_flinger->SetLayerVisibility(layer->GetConsumerBinderId(), visible);
119 R_SUCCEED();
120}
121
122Result Container::SetLayerBlending(u64 layer_id, bool enabled) {
123 std::scoped_lock lk{m_lock};
124
125 auto* const layer = m_layers.GetLayerById(layer_id);
126 R_UNLESS(layer != nullptr, VI::ResultNotFound);
127
128 m_surface_flinger->SetLayerBlending(layer->GetConsumerBinderId(),
129 enabled ? Nvnflinger::LayerBlending::Coverage
130 : Nvnflinger::LayerBlending::None);
131 R_SUCCEED();
132}
133
134void Container::LinkVsyncEvent(u64 display_id, Event* event) {
135 std::scoped_lock lk{m_lock};
136 m_conductor->LinkVsyncEvent(display_id, event);
137}
138
139void Container::UnlinkVsyncEvent(u64 display_id, Event* event) {
140 std::scoped_lock lk{m_lock};
141 m_conductor->UnlinkVsyncEvent(display_id, event);
142}
143
144Result Container::CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id) {
145 std::scoped_lock lk{m_lock};
146 R_TRY(this->CreateLayerLocked(out_layer_id, display_id, {}));
147 R_RETURN(this->OpenLayerLocked(out_producer_binder_id, *out_layer_id, {}));
148}
149
150Result Container::DestroyStrayLayer(u64 layer_id) {
151 std::scoped_lock lk{m_lock};
152 R_TRY(this->CloseLayerLocked(layer_id));
153 R_RETURN(this->DestroyLayerLocked(layer_id));
154}
155
156Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid) {
157 auto* const display = m_displays.GetDisplayById(display_id);
158 R_UNLESS(display != nullptr, VI::ResultNotFound);
159
160 s32 consumer_binder_id, producer_binder_id;
161 m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
162
163 auto* const layer =
164 m_layers.CreateLayer(owner_aruid, display, consumer_binder_id, producer_binder_id);
165 R_UNLESS(layer != nullptr, VI::ResultNotFound);
166
167 m_surface_flinger->CreateLayer(consumer_binder_id);
168
169 *out_layer_id = layer->GetId();
170 R_SUCCEED();
171}
172
173Result Container::DestroyLayerLocked(u64 layer_id) {
174 auto* const layer = m_layers.GetLayerById(layer_id);
175 R_UNLESS(layer != nullptr, VI::ResultNotFound);
176
177 m_surface_flinger->DestroyLayer(layer->GetConsumerBinderId());
178 m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
179 layer->GetProducerBinderId());
180 m_layers.DestroyLayer(layer_id);
181
182 R_SUCCEED();
183}
184
185Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
186 R_UNLESS(!m_is_shut_down, VI::ResultOperationFailed);
187
188 auto* const layer = m_layers.GetLayerById(layer_id);
189 R_UNLESS(layer != nullptr, VI::ResultNotFound);
190 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed);
191 R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied);
192
193 layer->Open();
194
195 if (auto* display = layer->GetDisplay(); display != nullptr) {
196 m_surface_flinger->AddLayerToDisplayStack(display->GetId(), layer->GetConsumerBinderId());
197 }
198
199 *out_producer_binder_id = layer->GetProducerBinderId();
200
201 R_SUCCEED();
202}
203
204Result Container::CloseLayerLocked(u64 layer_id) {
205 auto* const layer = m_layers.GetLayerById(layer_id);
206 R_UNLESS(layer != nullptr, VI::ResultNotFound);
207 R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed);
208
209 if (auto* display = layer->GetDisplay(); display != nullptr) {
210 m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(),
211 layer->GetConsumerBinderId());
212 }
213
214 layer->Close();
215
216 R_SUCCEED();
217}
218
219bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
220 u64 display_id) {
221 std::scoped_lock lk{m_lock};
222 return m_surface_flinger->ComposeDisplay(out_swap_interval, out_compose_speed_scale,
223 display_id);
224}
225
226} // namespace Service::VI
diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h
new file mode 100644
index 000000000..5eac4d77d
--- /dev/null
+++ b/src/core/hle/service/vi/container.h
@@ -0,0 +1,89 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <mutex>
8#include <optional>
9
10#include "core/hle/service/vi/conductor.h"
11#include "core/hle/service/vi/display_list.h"
12#include "core/hle/service/vi/layer_list.h"
13#include "core/hle/service/vi/shared_buffer_manager.h"
14
15union Result;
16
17namespace Service::android {
18class BufferQueueProducer;
19}
20
21namespace Service::Nvnflinger {
22class IHOSBinderDriver;
23class SurfaceFlinger;
24} // namespace Service::Nvnflinger
25
26namespace Service {
27class Event;
28}
29
30namespace Service::VI {
31
32class SharedBufferManager;
33
34class Container {
35public:
36 explicit Container(Core::System& system);
37 ~Container();
38
39 void OnTerminate();
40
41 SharedBufferManager* GetSharedBufferManager();
42
43 Result GetBinderDriver(std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver);
44 Result GetLayerProducerHandle(std::shared_ptr<android::BufferQueueProducer>* out_producer,
45 u64 layer_id);
46
47 Result OpenDisplay(u64* out_display_id, const DisplayName& display_name);
48 Result CloseDisplay(u64 display_id);
49
50 // Managed layers are created by the interaction between am and ommdisp
51 // on behalf of an applet. Their lifetime ends with the lifetime of the
52 // applet's ISelfController.
53 Result CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid);
54 Result DestroyManagedLayer(u64 layer_id);
55 Result OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
56 Result CloseLayer(u64 layer_id);
57
58 // Stray layers are created by non-applet sysmodules. Their lifetime ends
59 // with the lifetime of the IApplicationDisplayService which created them.
60 Result CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id);
61 Result DestroyStrayLayer(u64 layer_id);
62
63 Result SetLayerVisibility(u64 layer_id, bool visible);
64 Result SetLayerBlending(u64 layer_id, bool enabled);
65
66 void LinkVsyncEvent(u64 display_id, Event* event);
67 void UnlinkVsyncEvent(u64 display_id, Event* event);
68
69private:
70 Result CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid);
71 Result DestroyLayerLocked(u64 layer_id);
72 Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
73 Result CloseLayerLocked(u64 layer_id);
74
75public:
76 bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
77
78private:
79 std::mutex m_lock{};
80 DisplayList m_displays{};
81 LayerList m_layers{};
82 std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_driver{};
83 std::shared_ptr<Nvnflinger::SurfaceFlinger> m_surface_flinger{};
84 std::optional<SharedBufferManager> m_shared_buffer_manager{};
85 std::optional<Conductor> m_conductor{};
86 bool m_is_shut_down{};
87};
88
89} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display.h b/src/core/hle/service/vi/display.h
new file mode 100644
index 000000000..fceda75e3
--- /dev/null
+++ b/src/core/hle/service/vi/display.h
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/vi/vi_types.h"
7
8namespace Service::VI {
9
10class Display {
11public:
12 constexpr Display() = default;
13
14 void Initialize(u64 id, const DisplayName& display_name) {
15 m_id = id;
16 m_display_name = display_name;
17 m_is_initialized = true;
18 }
19
20 void Finalize() {
21 m_id = {};
22 m_display_name = {};
23 m_is_initialized = {};
24 }
25
26 u64 GetId() const {
27 return m_id;
28 }
29
30 const DisplayName& GetDisplayName() const {
31 return m_display_name;
32 }
33
34 bool IsInitialized() const {
35 return m_is_initialized;
36 }
37
38private:
39 u64 m_id{};
40 DisplayName m_display_name{};
41 bool m_is_initialized{};
42};
43
44} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
deleted file mode 100644
index 7f2af9acc..000000000
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <utility>
6
7#include <fmt/format.h>
8
9#include "common/assert.h"
10#include "core/core.h"
11#include "core/hle/kernel/k_event.h"
12#include "core/hle/kernel/k_readable_event.h"
13#include "core/hle/service/kernel_helpers.h"
14#include "core/hle/service/nvdrv/core/container.h"
15#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
16#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
17#include "core/hle/service/nvnflinger/buffer_queue_core.h"
18#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
19#include "core/hle/service/nvnflinger/hardware_composer.h"
20#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
21#include "core/hle/service/vi/display/vi_display.h"
22#include "core/hle/service/vi/layer/vi_layer.h"
23#include "core/hle/service/vi/vi_results.h"
24
25namespace Service::VI {
26
27struct BufferQueue {
28 std::shared_ptr<android::BufferQueueCore> core;
29 std::unique_ptr<android::BufferQueueProducer> producer;
30 std::unique_ptr<android::BufferQueueConsumer> consumer;
31};
32
33static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context,
34 Service::Nvidia::NvCore::NvMap& nvmap) {
35 auto buffer_queue_core = std::make_shared<android::BufferQueueCore>();
36 return {
37 buffer_queue_core,
38 std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap),
39 std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
40}
41
42Display::Display(u64 id, std::string name_,
43 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_,
44 KernelHelpers::ServiceContext& service_context_, Core::System& system_)
45 : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
46 service_context{service_context_} {
47 hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>();
48 vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
49}
50
51Display::~Display() {
52 service_context.CloseEvent(vsync_event);
53}
54
55Layer& Display::GetLayer(std::size_t index) {
56 size_t i = 0;
57 for (auto& layer : layers) {
58 if (!layer->IsOpen() || !layer->IsVisible()) {
59 continue;
60 }
61
62 if (i == index) {
63 return *layer;
64 }
65
66 i++;
67 }
68
69 UNREACHABLE();
70}
71
72size_t Display::GetNumLayers() const {
73 return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); });
74}
75
76Kernel::KReadableEvent* Display::GetVSyncEvent() {
77 return &vsync_event->GetReadableEvent();
78}
79
80void Display::SignalVSyncEvent() {
81 vsync_event->Signal();
82}
83
84void Display::CreateLayer(u64 layer_id, u32 binder_id,
85 Service::Nvidia::NvCore::Container& nv_core) {
86 auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile());
87
88 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));
89 buffer_item_consumer->Connect(false);
90
91 layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer,
92 std::move(buffer_item_consumer)));
93
94 if (is_abandoned) {
95 this->FindLayer(layer_id)->GetConsumer().Abandon();
96 }
97
98 hos_binder_driver_server.RegisterProducer(std::move(producer));
99}
100
101void Display::DestroyLayer(u64 layer_id) {
102 if (auto* layer = this->FindLayer(layer_id); layer != nullptr) {
103 layer->GetConsumer().Abandon();
104 }
105
106 std::erase_if(layers,
107 [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
108}
109
110void Display::Abandon() {
111 for (auto& layer : layers) {
112 layer->GetConsumer().Abandon();
113 }
114 is_abandoned = true;
115}
116
117Layer* Display::FindLayer(u64 layer_id) {
118 const auto itr =
119 std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
120 return layer->GetLayerId() == layer_id;
121 });
122
123 if (itr == layers.end()) {
124 return nullptr;
125 }
126
127 return itr->get();
128}
129
130const Layer* Display::FindLayer(u64 layer_id) const {
131 const auto itr =
132 std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
133 return layer->GetLayerId() == layer_id;
134 });
135
136 if (itr == layers.end()) {
137 return nullptr;
138 }
139
140 return itr->get();
141}
142
143} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
deleted file mode 100644
index 220292cff..000000000
--- a/src/core/hle/service/vi/display/vi_display.h
+++ /dev/null
@@ -1,143 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <string>
8#include <vector>
9
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12#include "core/hle/result.h"
13
14namespace Core {
15class System;
16}
17
18namespace Kernel {
19class KEvent;
20class KReadableEvent;
21} // namespace Kernel
22
23namespace Service::android {
24class BufferQueueProducer;
25}
26
27namespace Service::KernelHelpers {
28class ServiceContext;
29}
30
31namespace Service::Nvnflinger {
32class HardwareComposer;
33class HosBinderDriverServer;
34} // namespace Service::Nvnflinger
35
36namespace Service::Nvidia::NvCore {
37class Container;
38class NvMap;
39} // namespace Service::Nvidia::NvCore
40
41namespace Service::VI {
42
43class Layer;
44
45/// Represents a single display type
46class Display {
47public:
48 YUZU_NON_COPYABLE(Display);
49 YUZU_NON_MOVEABLE(Display);
50
51 /// Constructs a display with a given unique ID and name.
52 ///
53 /// @param id The unique ID for this display.
54 /// @param hos_binder_driver_server_ Nvnflinger HOSBinderDriver server instance.
55 /// @param service_context_ The ServiceContext for the owning service.
56 /// @param name_ The name for this display.
57 /// @param system_ The global system instance.
58 ///
59 Display(u64 id, std::string name_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_,
60 KernelHelpers::ServiceContext& service_context_, Core::System& system_);
61 ~Display();
62
63 /// Gets the unique ID assigned to this display.
64 u64 GetID() const {
65 return display_id;
66 }
67
68 /// Gets the name of this display
69 const std::string& GetName() const {
70 return name;
71 }
72
73 /// Whether or not this display has any layers added to it.
74 bool HasLayers() const {
75 return GetNumLayers() > 0;
76 }
77
78 /// Gets a layer for this display based off an index.
79 Layer& GetLayer(std::size_t index);
80
81 std::size_t GetNumLayers() const;
82
83 /// Gets the internal vsync event.
84 Kernel::KReadableEvent* GetVSyncEvent();
85
86 /// Signals the internal vsync event.
87 void SignalVSyncEvent();
88
89 /// Creates and adds a layer to this display with the given ID.
90 ///
91 /// @param layer_id The ID to assign to the created layer.
92 /// @param binder_id The ID assigned to the buffer queue.
93 ///
94 void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core);
95
96 /// Removes a layer from this display with the given ID.
97 ///
98 /// @param layer_id The ID assigned to the layer to destroy.
99 ///
100 void DestroyLayer(u64 layer_id);
101
102 /// Resets the display for a new connection.
103 void Reset() {
104 layers.clear();
105 }
106
107 void Abandon();
108
109 /// Attempts to find a layer with the given ID.
110 ///
111 /// @param layer_id The layer ID.
112 ///
113 /// @returns If found, the Layer instance with the given ID.
114 /// If not found, then nullptr is returned.
115 ///
116 Layer* FindLayer(u64 layer_id);
117
118 /// Attempts to find a layer with the given ID.
119 ///
120 /// @param layer_id The layer ID.
121 ///
122 /// @returns If found, the Layer instance with the given ID.
123 /// If not found, then nullptr is returned.
124 ///
125 const Layer* FindLayer(u64 layer_id) const;
126
127 Nvnflinger::HardwareComposer& GetComposer() const {
128 return *hardware_composer;
129 }
130
131private:
132 u64 display_id;
133 std::string name;
134 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
135 KernelHelpers::ServiceContext& service_context;
136
137 std::vector<std::unique_ptr<Layer>> layers;
138 std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer;
139 Kernel::KEvent* vsync_event{};
140 bool is_abandoned{};
141};
142
143} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display_list.h b/src/core/hle/service/vi/display_list.h
new file mode 100644
index 000000000..f710ac472
--- /dev/null
+++ b/src/core/hle/service/vi/display_list.h
@@ -0,0 +1,83 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <cstring>
7
8#include "core/hle/service/vi/display.h"
9
10namespace Service::VI {
11
12class DisplayList {
13public:
14 constexpr DisplayList() = default;
15
16 bool CreateDisplay(const DisplayName& name) {
17 Display* const display = this->GetFreeDisplay();
18 if (!display) {
19 return false;
20 }
21
22 display->Initialize(m_next_id++, name);
23 return true;
24 }
25
26 bool DestroyDisplay(u64 display_id) {
27 Display* display = this->GetDisplayById(display_id);
28 if (!display) {
29 return false;
30 }
31
32 display->Finalize();
33 return true;
34 }
35
36 Display* GetDisplayByName(const DisplayName& name) {
37 for (auto& display : m_displays) {
38 if (display.IsInitialized() &&
39 std::strncmp(name.data(), display.GetDisplayName().data(), sizeof(DisplayName)) ==
40 0) {
41 return &display;
42 }
43 }
44
45 return nullptr;
46 }
47
48 Display* GetDisplayById(u64 display_id) {
49 for (auto& display : m_displays) {
50 if (display.IsInitialized() && display.GetId() == display_id) {
51 return &display;
52 }
53 }
54
55 return nullptr;
56 }
57
58 template <typename F>
59 void ForEachDisplay(F&& cb) {
60 for (auto& display : m_displays) {
61 if (display.IsInitialized()) {
62 cb(display);
63 }
64 }
65 }
66
67private:
68 Display* GetFreeDisplay() {
69 for (auto& display : m_displays) {
70 if (!display.IsInitialized()) {
71 return &display;
72 }
73 }
74
75 return nullptr;
76 }
77
78private:
79 std::array<Display, 8> m_displays{};
80 u64 m_next_id{};
81};
82
83} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer.h b/src/core/hle/service/vi/layer.h
new file mode 100644
index 000000000..e4c9c9864
--- /dev/null
+++ b/src/core/hle/service/vi/layer.h
@@ -0,0 +1,81 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::VI {
9
10class Display;
11
12class Layer {
13public:
14 constexpr Layer() = default;
15
16 void Initialize(u64 id, u64 owner_aruid, Display* display, s32 consumer_binder_id,
17 s32 producer_binder_id) {
18 m_id = id;
19 m_owner_aruid = owner_aruid;
20 m_display = display;
21 m_consumer_binder_id = consumer_binder_id;
22 m_producer_binder_id = producer_binder_id;
23 m_is_initialized = true;
24 }
25
26 void Finalize() {
27 m_id = {};
28 m_owner_aruid = {};
29 m_display = {};
30 m_consumer_binder_id = {};
31 m_producer_binder_id = {};
32 m_is_initialized = {};
33 }
34
35 void Open() {
36 m_is_open = true;
37 }
38
39 void Close() {
40 m_is_open = false;
41 }
42
43 u64 GetId() const {
44 return m_id;
45 }
46
47 u64 GetOwnerAruid() const {
48 return m_owner_aruid;
49 }
50
51 Display* GetDisplay() const {
52 return m_display;
53 }
54
55 s32 GetConsumerBinderId() const {
56 return m_consumer_binder_id;
57 }
58
59 s32 GetProducerBinderId() const {
60 return m_producer_binder_id;
61 }
62
63 bool IsInitialized() const {
64 return m_is_initialized;
65 }
66
67 bool IsOpen() const {
68 return m_is_open;
69 }
70
71private:
72 u64 m_id{};
73 u64 m_owner_aruid{};
74 Display* m_display{};
75 s32 m_consumer_binder_id{};
76 s32 m_producer_binder_id{};
77 bool m_is_initialized{};
78 bool m_is_open{};
79};
80
81} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
deleted file mode 100644
index eca35d82a..000000000
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/nvnflinger/hwc_layer.h"
5#include "core/hle/service/vi/layer/vi_layer.h"
6
7namespace Service::VI {
8
9Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
10 android::BufferQueueProducer& binder_,
11 std::shared_ptr<android::BufferItemConsumer>&& consumer_)
12 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
13 consumer_)},
14 blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {}
15
16Layer::~Layer() = default;
17
18} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
deleted file mode 100644
index 14e229903..000000000
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ /dev/null
@@ -1,118 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <utility>
8
9#include "common/common_types.h"
10
11namespace Service::android {
12class BufferItemConsumer;
13class BufferQueueCore;
14class BufferQueueProducer;
15} // namespace Service::android
16
17namespace Service::Nvnflinger {
18enum class LayerBlending : u32;
19}
20
21namespace Service::VI {
22
23/// Represents a single display layer.
24class Layer {
25public:
26 /// Constructs a layer with a given ID and buffer queue.
27 ///
28 /// @param layer_id_ The ID to assign to this layer.
29 /// @param binder_id_ The binder ID to assign to this layer.
30 /// @param binder_ The buffer producer queue for this layer to use.
31 ///
32 Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
33 android::BufferQueueProducer& binder_,
34 std::shared_ptr<android::BufferItemConsumer>&& consumer_);
35 ~Layer();
36
37 Layer(const Layer&) = delete;
38 Layer& operator=(const Layer&) = delete;
39
40 Layer(Layer&&) = default;
41 Layer& operator=(Layer&&) = delete;
42
43 /// Gets the ID for this layer.
44 u64 GetLayerId() const {
45 return layer_id;
46 }
47
48 /// Gets the binder ID for this layer.
49 u32 GetBinderId() const {
50 return binder_id;
51 }
52
53 /// Gets a reference to the buffer queue this layer is using.
54 android::BufferQueueProducer& GetBufferQueue() {
55 return binder;
56 }
57
58 /// Gets a const reference to the buffer queue this layer is using.
59 const android::BufferQueueProducer& GetBufferQueue() const {
60 return binder;
61 }
62
63 android::BufferItemConsumer& GetConsumer() {
64 return *consumer;
65 }
66
67 const android::BufferItemConsumer& GetConsumer() const {
68 return *consumer;
69 }
70
71 android::BufferQueueCore& Core() {
72 return core;
73 }
74
75 const android::BufferQueueCore& Core() const {
76 return core;
77 }
78
79 bool IsVisible() const {
80 return visible;
81 }
82
83 void SetVisibility(bool v) {
84 visible = v;
85 }
86
87 bool IsOpen() const {
88 return open;
89 }
90
91 bool Close() {
92 return std::exchange(open, false);
93 }
94
95 bool Open() {
96 return !std::exchange(open, true);
97 }
98
99 Nvnflinger::LayerBlending GetBlending() {
100 return blending;
101 }
102
103 void SetBlending(Nvnflinger::LayerBlending b) {
104 blending = b;
105 }
106
107private:
108 const u64 layer_id;
109 const u32 binder_id;
110 android::BufferQueueCore& core;
111 android::BufferQueueProducer& binder;
112 std::shared_ptr<android::BufferItemConsumer> consumer;
113 Service::Nvnflinger::LayerBlending blending;
114 bool open;
115 bool visible;
116};
117
118} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer_list.h b/src/core/hle/service/vi/layer_list.h
new file mode 100644
index 000000000..4afca6f40
--- /dev/null
+++ b/src/core/hle/service/vi/layer_list.h
@@ -0,0 +1,71 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/vi/layer.h"
7
8namespace Service::VI {
9
10class LayerList {
11public:
12 constexpr LayerList() = default;
13
14 Layer* CreateLayer(u64 owner_aruid, Display* display, s32 consumer_binder_id,
15 s32 producer_binder_id) {
16 Layer* const layer = GetFreeLayer();
17 if (!layer) {
18 return nullptr;
19 }
20
21 layer->Initialize(++m_next_id, owner_aruid, display, consumer_binder_id,
22 producer_binder_id);
23 return layer;
24 }
25
26 bool DestroyLayer(u64 layer_id) {
27 Layer* const layer = GetLayerById(layer_id);
28 if (!layer) {
29 return false;
30 }
31
32 layer->Finalize();
33 return true;
34 }
35
36 Layer* GetLayerById(u64 layer_id) {
37 for (auto& layer : m_layers) {
38 if (layer.IsInitialized() && layer.GetId() == layer_id) {
39 return &layer;
40 }
41 }
42
43 return nullptr;
44 }
45
46 template <typename F>
47 void ForEachLayer(F&& cb) {
48 for (auto& layer : m_layers) {
49 if (layer.IsInitialized()) {
50 cb(layer);
51 }
52 }
53 }
54
55private:
56 Layer* GetFreeLayer() {
57 for (auto& layer : m_layers) {
58 if (!layer.IsInitialized()) {
59 return &layer;
60 }
61 }
62
63 return nullptr;
64 }
65
66private:
67 std::array<Layer, 8> m_layers{};
68 u64 m_next_id{};
69};
70
71} // namespace Service::VI
diff --git a/src/core/hle/service/vi/manager_display_service.cpp b/src/core/hle/service/vi/manager_display_service.cpp
index 17f2f3b8f..9f856282e 100644
--- a/src/core/hle/service/vi/manager_display_service.cpp
+++ b/src/core/hle/service/vi/manager_display_service.cpp
@@ -2,22 +2,21 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/nvnflinger.h" 5#include "core/hle/service/vi/container.h"
6#include "core/hle/service/vi/manager_display_service.h" 6#include "core/hle/service/vi/manager_display_service.h"
7#include "core/hle/service/vi/vi_results.h"
8 7
9namespace Service::VI { 8namespace Service::VI {
10 9
11IManagerDisplayService::IManagerDisplayService(Core::System& system_, 10IManagerDisplayService::IManagerDisplayService(Core::System& system_,
12 Nvnflinger::Nvnflinger& nvnflinger) 11 std::shared_ptr<Container> container)
13 : ServiceFramework{system_, "IManagerDisplayService"}, m_nvnflinger{nvnflinger} { 12 : ServiceFramework{system_, "IManagerDisplayService"}, m_container{std::move(container)} {
14 // clang-format off 13 // clang-format off
15 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
16 {200, nullptr, "AllocateProcessHeapBlock"}, 15 {200, nullptr, "AllocateProcessHeapBlock"},
17 {201, nullptr, "FreeProcessHeapBlock"}, 16 {201, nullptr, "FreeProcessHeapBlock"},
18 {1102, nullptr, "GetDisplayResolution"}, 17 {1102, nullptr, "GetDisplayResolution"},
19 {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"}, 18 {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"},
20 {2011, nullptr, "DestroyManagedLayer"}, 19 {2011, C<&IManagerDisplayService::DestroyManagedLayer>, "DestroyManagedLayer"},
21 {2012, nullptr, "CreateStrayLayer"}, 20 {2012, nullptr, "CreateStrayLayer"},
22 {2050, nullptr, "CreateIndirectLayer"}, 21 {2050, nullptr, "CreateIndirectLayer"},
23 {2051, nullptr, "DestroyIndirectLayer"}, 22 {2051, nullptr, "DestroyIndirectLayer"},
@@ -102,19 +101,30 @@ IManagerDisplayService::IManagerDisplayService(Core::System& system_,
102 101
103IManagerDisplayService::~IManagerDisplayService() = default; 102IManagerDisplayService::~IManagerDisplayService() = default;
104 103
105Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, 104Result IManagerDisplayService::CreateSharedLayerSession(Kernel::KProcess* owner_process,
106 u64 display_id, AppletResourceUserId aruid) { 105 u64* out_buffer_id, u64* out_layer_handle,
107 LOG_WARNING(Service_VI, "(STUBBED) called. unknown={}, display={}, aruid={}", unknown, 106 u64 display_id, bool enable_blending) {
108 display_id, aruid.pid); 107 R_RETURN(m_container->GetSharedBufferManager()->CreateSession(
108 owner_process, out_buffer_id, out_layer_handle, display_id, enable_blending));
109}
109 110
110 const auto layer_id = m_nvnflinger.CreateLayer(display_id); 111void IManagerDisplayService::DestroySharedLayerSession(Kernel::KProcess* owner_process) {
111 if (!layer_id) { 112 m_container->GetSharedBufferManager()->DestroySession(owner_process);
112 LOG_ERROR(Service_VI, "Layer not found! display={}", display_id); 113}
113 R_THROW(VI::ResultNotFound);
114 }
115 114
116 *out_layer_id = *layer_id; 115Result IManagerDisplayService::SetLayerBlending(bool enabled, u64 layer_id) {
117 R_SUCCEED(); 116 R_RETURN(m_container->SetLayerBlending(layer_id, enabled));
117}
118
119Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id,
120 AppletResourceUserId aruid) {
121 LOG_DEBUG(Service_VI, "called. flags={}, display={}, aruid={}", flags, display_id, aruid.pid);
122 R_RETURN(m_container->CreateManagedLayer(out_layer_id, display_id, aruid.pid));
123}
124
125Result IManagerDisplayService::DestroyManagedLayer(u64 layer_id) {
126 LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
127 R_RETURN(m_container->DestroyManagedLayer(layer_id));
118} 128}
119 129
120Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) { 130Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) {
@@ -123,8 +133,8 @@ Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) {
123} 133}
124 134
125Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) { 135Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
126 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id={}, visible={}", layer_id, visible); 136 LOG_DEBUG(Service_VI, "called, layer_id={}, visible={}", layer_id, visible);
127 R_SUCCEED(); 137 R_RETURN(m_container->SetLayerVisibility(layer_id, visible));
128} 138}
129 139
130} // namespace Service::VI 140} // namespace Service::VI
diff --git a/src/core/hle/service/vi/manager_display_service.h b/src/core/hle/service/vi/manager_display_service.h
index 60e646ee0..b1bdf7f41 100644
--- a/src/core/hle/service/vi/manager_display_service.h
+++ b/src/core/hle/service/vi/manager_display_service.h
@@ -4,21 +4,34 @@
4#include "core/hle/service/cmif_types.h" 4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h" 5#include "core/hle/service/service.h"
6 6
7namespace Kernel {
8class KProcess;
9}
10
7namespace Service::VI { 11namespace Service::VI {
8 12
13class Container;
14
9class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { 15class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
10public: 16public:
11 explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger); 17 explicit IManagerDisplayService(Core::System& system_, std::shared_ptr<Container> container);
12 ~IManagerDisplayService() override; 18 ~IManagerDisplayService() override;
13 19
14private: 20 Result CreateSharedLayerSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
15 Result CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, u64 display_id, 21 u64* out_layer_handle, u64 display_id, bool enable_blending);
22 void DestroySharedLayerSession(Kernel::KProcess* owner_process);
23
24 Result SetLayerBlending(bool enabled, u64 layer_id);
25
26public:
27 Result CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id,
16 AppletResourceUserId aruid); 28 AppletResourceUserId aruid);
29 Result DestroyManagedLayer(u64 layer_id);
17 Result AddToLayerStack(u32 stack_id, u64 layer_id); 30 Result AddToLayerStack(u32 stack_id, u64 layer_id);
18 Result SetLayerVisibility(bool visible, u64 layer_id); 31 Result SetLayerVisibility(bool visible, u64 layer_id);
19 32
20private: 33private:
21 Nvnflinger::Nvnflinger& m_nvnflinger; 34 const std::shared_ptr<Container> m_container;
22}; 35};
23 36
24} // namespace Service::VI 37} // namespace Service::VI
diff --git a/src/core/hle/service/vi/manager_root_service.cpp b/src/core/hle/service/vi/manager_root_service.cpp
index a7eee4f04..0f16a15b4 100644
--- a/src/core/hle/service/vi/manager_root_service.cpp
+++ b/src/core/hle/service/vi/manager_root_service.cpp
@@ -2,7 +2,9 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/hos_binder_driver.h"
5#include "core/hle/service/vi/application_display_service.h" 6#include "core/hle/service/vi/application_display_service.h"
7#include "core/hle/service/vi/container.h"
6#include "core/hle/service/vi/manager_root_service.h" 8#include "core/hle/service/vi/manager_root_service.h"
7#include "core/hle/service/vi/service_creator.h" 9#include "core/hle/service/vi/service_creator.h"
8#include "core/hle/service/vi/vi.h" 10#include "core/hle/service/vi/vi.h"
@@ -10,11 +12,9 @@
10 12
11namespace Service::VI { 13namespace Service::VI {
12 14
13IManagerRootService::IManagerRootService( 15IManagerRootService::IManagerRootService(Core::System& system_,
14 Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, 16 std::shared_ptr<Container> container)
15 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) 17 : ServiceFramework{system_, "vi:m"}, m_container{std::move(container)} {
16 : ServiceFramework{system_, "vi:m"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
17 hos_binder_driver_server} {
18 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
19 {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"}, 19 {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"},
20 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 20 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -31,8 +31,8 @@ IManagerRootService::~IManagerRootService() = default;
31Result IManagerRootService::GetDisplayService( 31Result IManagerRootService::GetDisplayService(
32 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { 32 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
33 LOG_DEBUG(Service_VI, "called"); 33 LOG_DEBUG(Service_VI, "called");
34 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger, 34 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
35 m_hos_binder_driver_server, Permission::Manager, policy)); 35 Permission::Manager, policy));
36} 36}
37 37
38} // namespace Service::VI 38} // namespace Service::VI
diff --git a/src/core/hle/service/vi/manager_root_service.h b/src/core/hle/service/vi/manager_root_service.h
index e6cb77aeb..77cd32869 100644
--- a/src/core/hle/service/vi/manager_root_service.h
+++ b/src/core/hle/service/vi/manager_root_service.h
@@ -10,29 +10,23 @@ namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Service::Nvnflinger {
14class HosBinderDriverServer;
15class Nvnflinger;
16} // namespace Service::Nvnflinger
17
18namespace Service::VI { 13namespace Service::VI {
19 14
15class Container;
20class IApplicationDisplayService; 16class IApplicationDisplayService;
21enum class Policy : u32; 17enum class Policy : u32;
22 18
23class IManagerRootService final : public ServiceFramework<IManagerRootService> { 19class IManagerRootService final : public ServiceFramework<IManagerRootService> {
24public: 20public:
25 explicit IManagerRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, 21 explicit IManagerRootService(Core::System& system_, std::shared_ptr<Container> container);
26 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
27 ~IManagerRootService() override; 22 ~IManagerRootService() override;
28 23
29private:
30 Result GetDisplayService( 24 Result GetDisplayService(
31 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, 25 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
32 Policy policy); 26 Policy policy);
33 27
34 Nvnflinger::Nvnflinger& m_nvnflinger; 28private:
35 Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server; 29 const std::shared_ptr<Container> m_container;
36}; 30};
37 31
38} // namespace Service::VI 32} // namespace Service::VI
diff --git a/src/core/hle/service/vi/service_creator.cpp b/src/core/hle/service/vi/service_creator.cpp
index 1de9d61a4..2b8e5f957 100644
--- a/src/core/hle/service/vi/service_creator.cpp
+++ b/src/core/hle/service/vi/service_creator.cpp
@@ -22,8 +22,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
22 22
23Result GetApplicationDisplayService( 23Result GetApplicationDisplayService(
24 std::shared_ptr<IApplicationDisplayService>* out_application_display_service, 24 std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
25 Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, 25 Core::System& system, std::shared_ptr<Container> container, Permission permission,
26 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission,
27 Policy policy) { 26 Policy policy) {
28 27
29 if (!IsValidServiceAccess(permission, policy)) { 28 if (!IsValidServiceAccess(permission, policy)) {
@@ -32,7 +31,7 @@ Result GetApplicationDisplayService(
32 } 31 }
33 32
34 *out_application_display_service = 33 *out_application_display_service =
35 std::make_shared<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server); 34 std::make_shared<IApplicationDisplayService>(system, std::move(container));
36 R_SUCCEED(); 35 R_SUCCEED();
37} 36}
38 37
diff --git a/src/core/hle/service/vi/service_creator.h b/src/core/hle/service/vi/service_creator.h
index 8963bcd26..c6ba1797d 100644
--- a/src/core/hle/service/vi/service_creator.h
+++ b/src/core/hle/service/vi/service_creator.h
@@ -11,23 +11,18 @@ namespace Core {
11class System; 11class System;
12} 12}
13 13
14namespace Service::Nvnflinger {
15class HosBinderDriverServer;
16class Nvnflinger;
17} // namespace Service::Nvnflinger
18
19union Result; 14union Result;
20 15
21namespace Service::VI { 16namespace Service::VI {
22 17
18class Container;
23class IApplicationDisplayService; 19class IApplicationDisplayService;
24enum class Permission; 20enum class Permission;
25enum class Policy : u32; 21enum class Policy : u32;
26 22
27Result GetApplicationDisplayService( 23Result GetApplicationDisplayService(
28 std::shared_ptr<IApplicationDisplayService>* out_application_display_service, 24 std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
29 Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, 25 Core::System& system, std::shared_ptr<Container> container, Permission permission,
30 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission,
31 Policy policy); 26 Policy policy);
32 27
33} // namespace Service::VI 28} // namespace Service::VI
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp
index 90f7248a0..12cba16fa 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/vi/shared_buffer_manager.cpp
@@ -9,15 +9,15 @@
9#include "core/hle/service/nvdrv/devices/nvmap.h" 9#include "core/hle/service/nvdrv/devices/nvmap.h"
10#include "core/hle/service/nvdrv/nvdrv.h" 10#include "core/hle/service/nvdrv/nvdrv.h"
11#include "core/hle/service/nvnflinger/buffer_queue_producer.h" 11#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
12#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
13#include "core/hle/service/nvnflinger/pixel_format.h" 12#include "core/hle/service/nvnflinger/pixel_format.h"
14#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 13#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
15#include "core/hle/service/vi/layer/vi_layer.h" 14#include "core/hle/service/vi/container.h"
15#include "core/hle/service/vi/shared_buffer_manager.h"
16#include "core/hle/service/vi/vi_results.h" 16#include "core/hle/service/vi/vi_results.h"
17#include "video_core/gpu.h" 17#include "video_core/gpu.h"
18#include "video_core/host1x/host1x.h" 18#include "video_core/host1x/host1x.h"
19 19
20namespace Service::Nvnflinger { 20namespace Service::VI {
21 21
22namespace { 22namespace {
23 23
@@ -26,7 +26,6 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_
26 using Core::Memory::YUZU_PAGESIZE; 26 using Core::Memory::YUZU_PAGESIZE;
27 27
28 // Allocate memory for the system shared buffer. 28 // Allocate memory for the system shared buffer.
29 // FIXME: This memory belongs to vi's .data section.
30 auto& kernel = system.Kernel(); 29 auto& kernel = system.Kernel();
31 30
32 // Hold a temporary page group reference while we try to map it. 31 // Hold a temporary page group reference while we try to map it.
@@ -204,15 +203,15 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han
204 203
205} // namespace 204} // namespace
206 205
207FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& flinger, 206SharedBufferManager::SharedBufferManager(Core::System& system, Container& container,
208 std::shared_ptr<Nvidia::Module> nvdrv) 207 std::shared_ptr<Nvidia::Module> nvdrv)
209 : m_system(system), m_flinger(flinger), m_nvdrv(std::move(nvdrv)) {} 208 : m_system(system), m_container(container), m_nvdrv(std::move(nvdrv)) {}
210 209
211FbShareBufferManager::~FbShareBufferManager() = default; 210SharedBufferManager::~SharedBufferManager() = default;
212 211
213Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, 212Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
214 u64* out_layer_handle, u64 display_id, 213 u64* out_layer_handle, u64 display_id,
215 LayerBlending blending) { 214 bool enable_blending) {
216 std::scoped_lock lk{m_guard}; 215 std::scoped_lock lk{m_guard};
217 216
218 // Ensure we haven't already created. 217 // Ensure we haven't already created.
@@ -237,7 +236,7 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
237 owner_process, m_system)); 236 owner_process, m_system));
238 237
239 // Create new session. 238 // Create new session.
240 auto [it, was_emplaced] = m_sessions.emplace(aruid, FbShareSession{}); 239 auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{});
241 auto& session = it->second; 240 auto& session = it->second;
242 241
243 auto& container = m_nvdrv->GetContainer(); 242 auto& container = m_nvdrv->GetContainer();
@@ -249,17 +248,18 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
249 session.nvmap_fd, map_address, SharedBufferSize)); 248 session.nvmap_fd, map_address, SharedBufferSize));
250 249
251 // Create and open a layer for the display. 250 // Create and open a layer for the display.
252 session.layer_id = m_flinger.CreateLayer(m_display_id, blending).value(); 251 s32 producer_binder_id;
253 m_flinger.OpenLayer(session.layer_id); 252 R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id),
253 std::addressof(session.layer_id), display_id));
254 254
255 // Get the layer. 255 // Configure blending.
256 VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id); 256 R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
257 ASSERT(layer != nullptr);
258 257
259 // Get the producer and set preallocated buffers. 258 // Get the producer and set preallocated buffers.
260 auto& producer = layer->GetBufferQueue(); 259 std::shared_ptr<android::BufferQueueProducer> producer;
261 MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle); 260 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id));
262 MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle); 261 MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle);
262 MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle);
263 263
264 // Assign outputs. 264 // Assign outputs.
265 *out_buffer_id = m_buffer_id; 265 *out_buffer_id = m_buffer_id;
@@ -269,7 +269,7 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
269 R_SUCCEED(); 269 R_SUCCEED();
270} 270}
271 271
272void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) { 272void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) {
273 std::scoped_lock lk{m_guard}; 273 std::scoped_lock lk{m_guard};
274 274
275 if (m_buffer_id == 0) { 275 if (m_buffer_id == 0) {
@@ -285,7 +285,7 @@ void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) {
285 auto& session = it->second; 285 auto& session = it->second;
286 286
287 // Destroy the layer. 287 // Destroy the layer.
288 m_flinger.DestroyLayer(session.layer_id); 288 m_container.DestroyStrayLayer(session.layer_id);
289 289
290 // Close nvmap handle. 290 // Close nvmap handle.
291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); 291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
@@ -301,11 +301,11 @@ void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) {
301 m_sessions.erase(it); 301 m_sessions.erase(it);
302} 302}
303 303
304Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, 304Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
305 s32* out_nvmap_handle, 305 s32* out_nvmap_handle,
306 SharedMemoryPoolLayout* out_pool_layout, 306 SharedMemoryPoolLayout* out_pool_layout,
307 u64 buffer_id, 307 u64 buffer_id,
308 u64 applet_resource_user_id) { 308 u64 applet_resource_user_id) {
309 std::scoped_lock lk{m_guard}; 309 std::scoped_lock lk{m_guard};
310 310
311 R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); 311 R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
@@ -319,36 +319,18 @@ Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
319 R_SUCCEED(); 319 R_SUCCEED();
320} 320}
321 321
322Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) { 322Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
323 // Ensure the layer id is valid. 323 std::array<s32, 4>& out_slot_indexes,
324 R_UNLESS(layer_id > 0, VI::ResultNotFound); 324 s64* out_target_slot, u64 layer_id) {
325
326 // Get the layer.
327 VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id);
328 R_UNLESS(layer != nullptr, VI::ResultNotFound);
329
330 // We succeeded.
331 *out_layer = layer;
332 R_SUCCEED();
333}
334
335Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
336 std::array<s32, 4>& out_slot_indexes,
337 s64* out_target_slot, u64 layer_id) {
338 std::scoped_lock lk{m_guard};
339
340 // Get the layer.
341 VI::Layer* layer;
342 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
343
344 // Get the producer. 325 // Get the producer.
345 auto& producer = layer->GetBufferQueue(); 326 std::shared_ptr<android::BufferQueueProducer> producer;
327 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
346 328
347 // Get the next buffer from the producer. 329 // Get the next buffer from the producer.
348 s32 slot; 330 s32 slot;
349 R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, 331 R_UNLESS(producer->DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0,
350 SharedBufferWidth, SharedBufferHeight, 332 SharedBufferWidth, SharedBufferHeight,
351 SharedBufferBlockLinearFormat, 0) == android::Status::NoError, 333 SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
352 VI::ResultOperationFailed); 334 VI::ResultOperationFailed);
353 335
354 // Assign remaining outputs. 336 // Assign remaining outputs.
@@ -359,27 +341,22 @@ Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
359 R_SUCCEED(); 341 R_SUCCEED();
360} 342}
361 343
362Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, 344Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
363 Common::Rectangle<s32> crop_region, 345 Common::Rectangle<s32> crop_region,
364 u32 transform, s32 swap_interval, 346 u32 transform, s32 swap_interval, u64 layer_id,
365 u64 layer_id, s64 slot) { 347 s64 slot) {
366 std::scoped_lock lk{m_guard};
367
368 // Get the layer.
369 VI::Layer* layer;
370 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
371
372 // Get the producer. 348 // Get the producer.
373 auto& producer = layer->GetBufferQueue(); 349 std::shared_ptr<android::BufferQueueProducer> producer;
350 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
374 351
375 // Request to queue the buffer. 352 // Request to queue the buffer.
376 std::shared_ptr<android::GraphicBuffer> buffer; 353 std::shared_ptr<android::GraphicBuffer> buffer;
377 R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == 354 R_UNLESS(producer->RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
378 android::Status::NoError, 355 android::Status::NoError,
379 VI::ResultOperationFailed); 356 VI::ResultOperationFailed);
380 357
381 ON_RESULT_FAILURE { 358 ON_RESULT_FAILURE {
382 producer.CancelBuffer(static_cast<s32>(slot), fence); 359 producer->CancelBuffer(static_cast<s32>(slot), fence);
383 }; 360 };
384 361
385 // Queue the buffer to the producer. 362 // Queue the buffer to the producer.
@@ -389,7 +366,7 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
389 input.fence = fence; 366 input.fence = fence;
390 input.transform = static_cast<android::NativeWindowTransform>(transform); 367 input.transform = static_cast<android::NativeWindowTransform>(transform);
391 input.swap_interval = swap_interval; 368 input.swap_interval = swap_interval;
392 R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == 369 R_UNLESS(producer->QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
393 android::Status::NoError, 370 android::Status::NoError,
394 VI::ResultOperationFailed); 371 VI::ResultOperationFailed);
395 372
@@ -397,25 +374,32 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
397 R_SUCCEED(); 374 R_SUCCEED();
398} 375}
399 376
400Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, 377Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
401 u64 layer_id) { 378 // Get the producer.
402 std::scoped_lock lk{m_guard}; 379 std::shared_ptr<android::BufferQueueProducer> producer;
380 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
403 381
404 // Get the layer. 382 // Cancel.
405 VI::Layer* layer; 383 producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence());
406 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); 384
385 // We succeeded.
386 R_SUCCEED();
387}
407 388
389Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
390 u64 layer_id) {
408 // Get the producer. 391 // Get the producer.
409 auto& producer = layer->GetBufferQueue(); 392 std::shared_ptr<android::BufferQueueProducer> producer;
393 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
410 394
411 // Set the event. 395 // Set the event.
412 *out_event = std::addressof(producer.GetNativeHandle()); 396 *out_event = producer->GetNativeHandle({});
413 397
414 // We succeeded. 398 // We succeeded.
415 R_SUCCEED(); 399 R_SUCCEED();
416} 400}
417 401
418Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { 402Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
419 std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); 403 std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
420 Common::ScratchBuffer<u32> scratch; 404 Common::ScratchBuffer<u32> scratch;
421 405
@@ -444,4 +428,4 @@ Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32
444 R_SUCCEED(); 428 R_SUCCEED();
445} 429}
446 430
447} // namespace Service::Nvnflinger 431} // namespace Service::VI
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/vi/shared_buffer_manager.h
index b79a7d23a..7c9bb7199 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
+++ b/src/core/hle/service/vi/shared_buffer_manager.h
@@ -8,15 +8,27 @@
8#include "common/math_util.h" 8#include "common/math_util.h"
9#include "core/hle/service/nvdrv/core/container.h" 9#include "core/hle/service/nvdrv/core/container.h"
10#include "core/hle/service/nvdrv/nvdata.h" 10#include "core/hle/service/nvdrv/nvdata.h"
11#include "core/hle/service/nvnflinger/hwc_layer.h"
12#include "core/hle/service/nvnflinger/nvnflinger.h" 11#include "core/hle/service/nvnflinger/nvnflinger.h"
13#include "core/hle/service/nvnflinger/ui/fence.h" 12#include "core/hle/service/nvnflinger/ui/fence.h"
14 13
15namespace Kernel { 14namespace Kernel {
16class KPageGroup; 15class KPageGroup;
16class KReadableEvent;
17} // namespace Kernel
18
19namespace Service::android {
20class BufferQueueProducer;
21}
22
23namespace Service::Nvidia {
24class Module;
17} 25}
18 26
19namespace Service::Nvnflinger { 27union Result;
28
29namespace Service::VI {
30
31class Container;
20 32
21struct SharedMemorySlot { 33struct SharedMemorySlot {
22 u64 buffer_offset; 34 u64 buffer_offset;
@@ -32,17 +44,17 @@ struct SharedMemoryPoolLayout {
32}; 44};
33static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); 45static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
34 46
35struct FbShareSession; 47struct SharedBufferSession;
36 48
37class FbShareBufferManager final { 49class SharedBufferManager final {
38public: 50public:
39 explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger, 51 explicit SharedBufferManager(Core::System& system, Container& container,
40 std::shared_ptr<Nvidia::Module> nvdrv); 52 std::shared_ptr<Nvidia::Module> nvdrv);
41 ~FbShareBufferManager(); 53 ~SharedBufferManager();
42 54
43 Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, 55 Result CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
44 u64 display_id, LayerBlending blending); 56 u64 display_id, bool enable_blending);
45 void Finalize(Kernel::KProcess* owner_process); 57 void DestroySession(Kernel::KProcess* owner_process);
46 58
47 Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, 59 Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
48 SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, 60 SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
@@ -51,32 +63,30 @@ public:
51 s64* out_target_slot, u64 layer_id); 63 s64* out_target_slot, u64 layer_id);
52 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, 64 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
53 u32 transform, s32 swap_interval, u64 layer_id, s64 slot); 65 u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
66 Result CancelSharedFrameBuffer(u64 layer_id, s64 slot);
54 Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); 67 Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
55 68
56 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index); 69 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
57 70
58private: 71private:
59 Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
60
61private:
62 u64 m_next_buffer_id = 1; 72 u64 m_next_buffer_id = 1;
63 u64 m_display_id = 0; 73 u64 m_display_id = 0;
64 u64 m_buffer_id = 0; 74 u64 m_buffer_id = 0;
65 SharedMemoryPoolLayout m_pool_layout = {}; 75 SharedMemoryPoolLayout m_pool_layout = {};
66 std::map<u64, FbShareSession> m_sessions; 76 std::map<u64, SharedBufferSession> m_sessions;
67 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; 77 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
68 78
69 std::mutex m_guard; 79 std::mutex m_guard;
70 Core::System& m_system; 80 Core::System& m_system;
71 Nvnflinger& m_flinger; 81 Container& m_container;
72 std::shared_ptr<Nvidia::Module> m_nvdrv; 82 const std::shared_ptr<Nvidia::Module> m_nvdrv;
73}; 83};
74 84
75struct FbShareSession { 85struct SharedBufferSession {
76 Nvidia::DeviceFD nvmap_fd = {}; 86 Nvidia::DeviceFD nvmap_fd = {};
77 Nvidia::NvCore::SessionId session_id = {}; 87 Nvidia::NvCore::SessionId session_id = {};
78 u64 layer_id = {}; 88 u64 layer_id = {};
79 u32 buffer_nvmap_handle = 0; 89 u32 buffer_nvmap_handle = 0;
80}; 90};
81 91
82} // namespace Service::Nvnflinger 92} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_display_service.cpp b/src/core/hle/service/vi/system_display_service.cpp
index 1e1cfc817..c3c50b07b 100644
--- a/src/core/hle/service/vi/system_display_service.cpp
+++ b/src/core/hle/service/vi/system_display_service.cpp
@@ -3,15 +3,15 @@
3 3
4#include "common/settings.h" 4#include "common/settings.h"
5#include "core/hle/service/cmif_serialization.h" 5#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" 6#include "core/hle/service/vi/container.h"
7#include "core/hle/service/vi/system_display_service.h" 7#include "core/hle/service/vi/system_display_service.h"
8#include "core/hle/service/vi/vi_types.h" 8#include "core/hle/service/vi/vi_types.h"
9 9
10namespace Service::VI { 10namespace Service::VI {
11 11
12ISystemDisplayService::ISystemDisplayService(Core::System& system_, 12ISystemDisplayService::ISystemDisplayService(Core::System& system_,
13 Nvnflinger::Nvnflinger& nvnflinger) 13 std::shared_ptr<Container> container)
14 : ServiceFramework{system_, "ISystemDisplayService"}, m_nvnflinger{nvnflinger} { 14 : ServiceFramework{system_, "ISystemDisplayService"}, m_container{std::move(container)} {
15 // clang-format off 15 // clang-format off
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {1200, nullptr, "GetZOrderCountMin"}, 17 {1200, nullptr, "GetZOrderCountMin"},
@@ -29,7 +29,7 @@ ISystemDisplayService::ISystemDisplayService(Core::System& system_,
29 {2400, nullptr, "OpenIndirectLayer"}, 29 {2400, nullptr, "OpenIndirectLayer"},
30 {2401, nullptr, "CloseIndirectLayer"}, 30 {2401, nullptr, "CloseIndirectLayer"},
31 {2402, nullptr, "FlipIndirectLayer"}, 31 {2402, nullptr, "FlipIndirectLayer"},
32 {3000, nullptr, "ListDisplayModes"}, 32 {3000, C<&ISystemDisplayService::ListDisplayModes>, "ListDisplayModes"},
33 {3001, nullptr, "ListDisplayRgbRanges"}, 33 {3001, nullptr, "ListDisplayRgbRanges"},
34 {3002, nullptr, "ListDisplayContentTypes"}, 34 {3002, nullptr, "ListDisplayContentTypes"},
35 {3200, C<&ISystemDisplayService::GetDisplayMode>, "GetDisplayMode"}, 35 {3200, C<&ISystemDisplayService::GetDisplayMode>, "GetDisplayMode"},
@@ -59,7 +59,7 @@ ISystemDisplayService::ISystemDisplayService(Core::System& system_,
59 {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"}, 59 {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"},
60 {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"}, 60 {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"},
61 {8257, nullptr, "FillSharedFrameBufferColor"}, 61 {8257, nullptr, "FillSharedFrameBufferColor"},
62 {8258, nullptr, "CancelSharedFrameBuffer"}, 62 {8258, C<&ISystemDisplayService::CancelSharedFrameBuffer>, "CancelSharedFrameBuffer"},
63 {9000, nullptr, "GetDp2hdmiController"}, 63 {9000, nullptr, "GetDp2hdmiController"},
64 }; 64 };
65 // clang-format on 65 // clang-format on
@@ -80,31 +80,50 @@ Result ISystemDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
80 R_SUCCEED(); 80 R_SUCCEED();
81} 81}
82 82
83Result ISystemDisplayService::GetDisplayMode(Out<u32> out_width, Out<u32> out_height, 83Result ISystemDisplayService::ListDisplayModes(
84 Out<f32> out_refresh_rate, Out<u32> out_unknown) { 84 Out<u64> out_count, u64 display_id,
85 LOG_WARNING(Service_VI, "(STUBBED) called"); 85 OutArray<DisplayMode, BufferAttr_HipcMapAlias> out_display_modes) {
86 LOG_WARNING(Service_VI, "(STUBBED) called, display_id={}", display_id);
87
88 if (!out_display_modes.empty()) {
89 out_display_modes[0] = {
90 .width = 1920,
91 .height = 1080,
92 .refresh_rate = 60.f,
93 .unknown = {},
94 };
95 *out_count = 1;
96 } else {
97 *out_count = 0;
98 }
99
100 R_SUCCEED();
101}
102
103Result ISystemDisplayService::GetDisplayMode(Out<DisplayMode> out_display_mode, u64 display_id) {
104 LOG_WARNING(Service_VI, "(STUBBED) called, display_id={}", display_id);
86 105
87 if (Settings::IsDockedMode()) { 106 if (Settings::IsDockedMode()) {
88 *out_width = static_cast<u32>(DisplayResolution::DockedWidth); 107 out_display_mode->width = static_cast<u32>(DisplayResolution::DockedWidth);
89 *out_height = static_cast<u32>(DisplayResolution::DockedHeight); 108 out_display_mode->height = static_cast<u32>(DisplayResolution::DockedHeight);
90 } else { 109 } else {
91 *out_width = static_cast<u32>(DisplayResolution::UndockedWidth); 110 out_display_mode->width = static_cast<u32>(DisplayResolution::UndockedWidth);
92 *out_height = static_cast<u32>(DisplayResolution::UndockedHeight); 111 out_display_mode->height = static_cast<u32>(DisplayResolution::UndockedHeight);
93 } 112 }
94 113
95 *out_refresh_rate = 60.f; // This wouldn't seem to be correct for 30 fps games. 114 out_display_mode->refresh_rate = 60.f; // This wouldn't seem to be correct for 30 fps games.
96 *out_unknown = 0; 115 out_display_mode->unknown = 0;
97 116
98 R_SUCCEED(); 117 R_SUCCEED();
99} 118}
100 119
101Result ISystemDisplayService::GetSharedBufferMemoryHandleId( 120Result ISystemDisplayService::GetSharedBufferMemoryHandleId(
102 Out<s32> out_nvmap_handle, Out<u64> out_size, 121 Out<s32> out_nvmap_handle, Out<u64> out_size,
103 OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, 122 OutLargeData<SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, u64 buffer_id,
104 u64 buffer_id, ClientAppletResourceUserId aruid) { 123 ClientAppletResourceUserId aruid) {
105 LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid); 124 LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid);
106 125
107 R_RETURN(m_nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId( 126 R_RETURN(m_container->GetSharedBufferManager()->GetSharedBufferMemoryHandleId(
108 out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid)); 127 out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid));
109} 128}
110 129
@@ -122,7 +141,7 @@ Result ISystemDisplayService::AcquireSharedFrameBuffer(Out<android::Fence> out_f
122 Out<std::array<s32, 4>> out_slots, 141 Out<std::array<s32, 4>> out_slots,
123 Out<s64> out_target_slot, u64 layer_id) { 142 Out<s64> out_target_slot, u64 layer_id) {
124 LOG_DEBUG(Service_VI, "called"); 143 LOG_DEBUG(Service_VI, "called");
125 R_RETURN(m_nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer( 144 R_RETURN(m_container->GetSharedBufferManager()->AcquireSharedFrameBuffer(
126 out_fence, *out_slots, out_target_slot, layer_id)); 145 out_fence, *out_slots, out_target_slot, layer_id));
127} 146}
128 147
@@ -131,15 +150,20 @@ Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
131 u32 window_transform, s32 swap_interval, 150 u32 window_transform, s32 swap_interval,
132 u64 layer_id, s64 surface_id) { 151 u64 layer_id, s64 surface_id) {
133 LOG_DEBUG(Service_VI, "called"); 152 LOG_DEBUG(Service_VI, "called");
134 R_RETURN(m_nvnflinger.GetSystemBufferManager().PresentSharedFrameBuffer( 153 R_RETURN(m_container->GetSharedBufferManager()->PresentSharedFrameBuffer(
135 fence, crop_region, window_transform, swap_interval, layer_id, surface_id)); 154 fence, crop_region, window_transform, swap_interval, layer_id, surface_id));
136} 155}
137 156
138Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent( 157Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent(
139 OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) { 158 OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) {
140 LOG_DEBUG(Service_VI, "called"); 159 LOG_DEBUG(Service_VI, "called");
141 R_RETURN(m_nvnflinger.GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent(out_event, 160 R_RETURN(m_container->GetSharedBufferManager()->GetSharedFrameBufferAcquirableEvent(out_event,
142 layer_id)); 161 layer_id));
162}
163
164Result ISystemDisplayService::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
165 LOG_DEBUG(Service_VI, "called");
166 R_RETURN(m_container->GetSharedBufferManager()->CancelSharedFrameBuffer(layer_id, slot));
143} 167}
144 168
145} // namespace Service::VI 169} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_display_service.h b/src/core/hle/service/vi/system_display_service.h
index cfcb196fd..7228d826e 100644
--- a/src/core/hle/service/vi/system_display_service.h
+++ b/src/core/hle/service/vi/system_display_service.h
@@ -5,27 +5,28 @@
5#include "core/hle/service/cmif_types.h" 5#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/nvnflinger/ui/fence.h" 6#include "core/hle/service/nvnflinger/ui/fence.h"
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8#include "core/hle/service/vi/shared_buffer_manager.h"
9namespace Service::Nvnflinger {
10struct SharedMemoryPoolLayout;
11}
12 9
13namespace Service::VI { 10namespace Service::VI {
11struct DisplayMode;
12
13class Container;
14 14
15class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { 15class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
16public: 16public:
17 explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger); 17 explicit ISystemDisplayService(Core::System& system_, std::shared_ptr<Container> container);
18 ~ISystemDisplayService() override; 18 ~ISystemDisplayService() override;
19 19
20private: 20private:
21 Result SetLayerZ(u32 z_value, u64 layer_id); 21 Result SetLayerZ(u32 z_value, u64 layer_id);
22 Result SetLayerVisibility(bool visible, u64 layer_id); 22 Result SetLayerVisibility(bool visible, u64 layer_id);
23 Result GetDisplayMode(Out<u32> out_width, Out<u32> out_height, Out<f32> out_refresh_rate, 23 Result ListDisplayModes(Out<u64> out_count, u64 display_id,
24 Out<u32> out_unknown); 24 OutArray<DisplayMode, BufferAttr_HipcMapAlias> out_display_modes);
25 Result GetDisplayMode(Out<DisplayMode> out_display_mode, u64 display_id);
25 26
26 Result GetSharedBufferMemoryHandleId( 27 Result GetSharedBufferMemoryHandleId(
27 Out<s32> out_nvmap_handle, Out<u64> out_size, 28 Out<s32> out_nvmap_handle, Out<u64> out_size,
28 OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, 29 OutLargeData<SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
29 u64 buffer_id, ClientAppletResourceUserId aruid); 30 u64 buffer_id, ClientAppletResourceUserId aruid);
30 Result OpenSharedLayer(u64 layer_id); 31 Result OpenSharedLayer(u64 layer_id);
31 Result ConnectSharedLayer(u64 layer_id); 32 Result ConnectSharedLayer(u64 layer_id);
@@ -37,9 +38,10 @@ private:
37 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, 38 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
38 u32 window_transform, s32 swap_interval, u64 layer_id, 39 u32 window_transform, s32 swap_interval, u64 layer_id,
39 s64 surface_id); 40 s64 surface_id);
41 Result CancelSharedFrameBuffer(u64 layer_id, s64 slot);
40 42
41private: 43private:
42 Nvnflinger::Nvnflinger& m_nvnflinger; 44 const std::shared_ptr<Container> m_container;
43}; 45};
44 46
45} // namespace Service::VI 47} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_root_service.cpp b/src/core/hle/service/vi/system_root_service.cpp
index 8789b4cfb..3489727d8 100644
--- a/src/core/hle/service/vi/system_root_service.cpp
+++ b/src/core/hle/service/vi/system_root_service.cpp
@@ -3,6 +3,7 @@
3 3
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/vi/application_display_service.h" 5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/container.h"
6#include "core/hle/service/vi/service_creator.h" 7#include "core/hle/service/vi/service_creator.h"
7#include "core/hle/service/vi/system_root_service.h" 8#include "core/hle/service/vi/system_root_service.h"
8#include "core/hle/service/vi/vi.h" 9#include "core/hle/service/vi/vi.h"
@@ -10,10 +11,8 @@
10 11
11namespace Service::VI { 12namespace Service::VI {
12 13
13ISystemRootService::ISystemRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, 14ISystemRootService::ISystemRootService(Core::System& system_, std::shared_ptr<Container> container)
14 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) 15 : ServiceFramework{system_, "vi:s"}, m_container{std::move(container)} {
15 : ServiceFramework{system_, "vi:s"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
16 hos_binder_driver_server} {
17 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
18 {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"}, 17 {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"},
19 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 18 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -26,8 +25,8 @@ ISystemRootService::~ISystemRootService() = default;
26Result ISystemRootService::GetDisplayService( 25Result ISystemRootService::GetDisplayService(
27 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { 26 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
28 LOG_DEBUG(Service_VI, "called"); 27 LOG_DEBUG(Service_VI, "called");
29 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger, 28 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
30 m_hos_binder_driver_server, Permission::System, policy)); 29 Permission::System, policy));
31} 30}
32 31
33} // namespace Service::VI 32} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_root_service.h b/src/core/hle/service/vi/system_root_service.h
index 2c547faa5..9d5aa53d3 100644
--- a/src/core/hle/service/vi/system_root_service.h
+++ b/src/core/hle/service/vi/system_root_service.h
@@ -10,20 +10,15 @@ namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Service::Nvnflinger {
14class HosBinderDriverServer;
15class Nvnflinger;
16} // namespace Service::Nvnflinger
17
18namespace Service::VI { 13namespace Service::VI {
19 14
15class Container;
20class IApplicationDisplayService; 16class IApplicationDisplayService;
21enum class Policy : u32; 17enum class Policy : u32;
22 18
23class ISystemRootService final : public ServiceFramework<ISystemRootService> { 19class ISystemRootService final : public ServiceFramework<ISystemRootService> {
24public: 20public:
25 explicit ISystemRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, 21 explicit ISystemRootService(Core::System& system_, std::shared_ptr<Container> container);
26 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
27 ~ISystemRootService() override; 22 ~ISystemRootService() override;
28 23
29private: 24private:
@@ -31,8 +26,7 @@ private:
31 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, 26 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
32 Policy policy); 27 Policy policy);
33 28
34 Nvnflinger::Nvnflinger& m_nvnflinger; 29 const std::shared_ptr<Container> m_container;
35 Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
36}; 30};
37 31
38} // namespace Service::VI 32} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 304e589b7..b388efaf6 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -1,25 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/core.h"
4#include "core/hle/service/server_manager.h" 5#include "core/hle/service/server_manager.h"
5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/application_root_service.h" 6#include "core/hle/service/vi/application_root_service.h"
7#include "core/hle/service/vi/container.h"
7#include "core/hle/service/vi/manager_root_service.h" 8#include "core/hle/service/vi/manager_root_service.h"
8#include "core/hle/service/vi/system_root_service.h" 9#include "core/hle/service/vi/system_root_service.h"
9#include "core/hle/service/vi/vi.h" 10#include "core/hle/service/vi/vi.h"
10 11
11namespace Service::VI { 12namespace Service::VI {
12 13
13void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, 14void LoopProcess(Core::System& system, std::stop_token token) {
14 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) { 15 const auto container = std::make_shared<Container>(system);
16
15 auto server_manager = std::make_unique<ServerManager>(system); 17 auto server_manager = std::make_unique<ServerManager>(system);
16 18
17 server_manager->RegisterNamedService("vi:m", std::make_shared<IManagerRootService>( 19 server_manager->RegisterNamedService("vi:m",
18 system, nvnflinger, hos_binder_driver_server)); 20 std::make_shared<IManagerRootService>(system, container));
21 server_manager->RegisterNamedService("vi:s",
22 std::make_shared<ISystemRootService>(system, container));
19 server_manager->RegisterNamedService( 23 server_manager->RegisterNamedService(
20 "vi:s", std::make_shared<ISystemRootService>(system, nvnflinger, hos_binder_driver_server)); 24 "vi:u", std::make_shared<IApplicationRootService>(system, container));
21 server_manager->RegisterNamedService("vi:u", std::make_shared<IApplicationRootService>( 25
22 system, nvnflinger, hos_binder_driver_server)); 26 std::stop_callback cb(token, [=] { container->OnTerminate(); });
27
23 ServerManager::RunServer(std::move(server_manager)); 28 ServerManager::RunServer(std::move(server_manager));
24} 29}
25 30
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 8e681370d..7c1f350d8 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -3,18 +3,14 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/polyfill_thread.h"
7
6namespace Core { 8namespace Core {
7class System; 9class System;
8} 10}
9 11
10namespace Service::Nvnflinger {
11class HosBinderDriverServer;
12class Nvnflinger;
13} // namespace Service::Nvnflinger
14
15namespace Service::VI { 12namespace Service::VI {
16 13
17void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, 14void LoopProcess(Core::System& system, std::stop_token token);
18 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
19 15
20} // namespace Service::VI 16} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_types.h b/src/core/hle/service/vi/vi_types.h
index 91e4b380c..95ff66358 100644
--- a/src/core/hle/service/vi/vi_types.h
+++ b/src/core/hle/service/vi/vi_types.h
@@ -66,9 +66,17 @@ struct DisplayInfo {
66}; 66};
67static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); 67static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
68 68
69struct DisplayMode {
70 u32 width;
71 u32 height;
72 f32 refresh_rate;
73 u32 unknown;
74};
75static_assert(sizeof(DisplayMode) == 0x10, "DisplayMode has wrong size");
76
69class NativeWindow final { 77class NativeWindow final {
70public: 78public:
71 constexpr explicit NativeWindow(u32 id_) : id{id_} {} 79 constexpr explicit NativeWindow(s32 id_) : id{static_cast<u64>(id_)} {}
72 constexpr explicit NativeWindow(const NativeWindow& other) = default; 80 constexpr explicit NativeWindow(const NativeWindow& other) = default;
73 81
74private: 82private:
diff --git a/src/core/hle/service/vi/vsync_manager.cpp b/src/core/hle/service/vi/vsync_manager.cpp
new file mode 100644
index 000000000..bdc4dfa96
--- /dev/null
+++ b/src/core/hle/service/vi/vsync_manager.cpp
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/os/event.h"
5#include "core/hle/service/vi/vsync_manager.h"
6
7namespace Service::VI {
8
9VsyncManager::VsyncManager() = default;
10VsyncManager::~VsyncManager() = default;
11
12void VsyncManager::SignalVsync() {
13 for (auto* event : m_vsync_events) {
14 event->Signal();
15 }
16}
17
18void VsyncManager::LinkVsyncEvent(Event* event) {
19 m_vsync_events.insert(event);
20}
21
22void VsyncManager::UnlinkVsyncEvent(Event* event) {
23 m_vsync_events.erase(event);
24}
25
26} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vsync_manager.h b/src/core/hle/service/vi/vsync_manager.h
new file mode 100644
index 000000000..5d45bb5ee
--- /dev/null
+++ b/src/core/hle/service/vi/vsync_manager.h
@@ -0,0 +1,29 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8namespace Service {
9class Event;
10}
11
12namespace Service::VI {
13
14class DisplayList;
15
16class VsyncManager {
17public:
18 explicit VsyncManager();
19 ~VsyncManager();
20
21 void SignalVsync();
22 void LinkVsyncEvent(Event* event);
23 void UnlinkVsyncEvent(Event* event);
24
25private:
26 std::set<Event*> m_vsync_events;
27};
28
29} // namespace Service::VI
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 2a32b1276..de27ec49e 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -118,7 +118,9 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function<bool(size_t, size_t)>
118 mbedtls_sha256_starts_ret(&ctx, 0); 118 mbedtls_sha256_starts_ret(&ctx, 0);
119 119
120 // Ensure we maintain a clean state on exit. 120 // Ensure we maintain a clean state on exit.
121 SCOPE_EXIT({ mbedtls_sha256_free(&ctx); }); 121 SCOPE_EXIT {
122 mbedtls_sha256_free(&ctx);
123 };
122 124
123 // Declare counters. 125 // Declare counters.
124 const size_t total_size = file->GetSize(); 126 const size_t total_size = file->GetSize();
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index e10a4601e..8775369a4 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -831,11 +831,11 @@ struct Memory::Impl {
831 if (core == sys_core) [[unlikely]] { 831 if (core == sys_core) [[unlikely]] {
832 sys_core_guard.lock(); 832 sys_core_guard.lock();
833 } 833 }
834 SCOPE_EXIT({ 834 SCOPE_EXIT {
835 if (core == sys_core) [[unlikely]] { 835 if (core == sys_core) [[unlikely]] {
836 sys_core_guard.unlock(); 836 sys_core_guard.unlock();
837 } 837 }
838 }); 838 };
839 gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { 839 gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) {
840 auto& current_area = rasterizer_write_areas[core]; 840 auto& current_area = rasterizer_write_areas[core];
841 PAddr subaddress = address >> YUZU_PAGEBITS; 841 PAddr subaddress = address >> YUZU_PAGEBITS;
@@ -866,11 +866,11 @@ struct Memory::Impl {
866 if (core == sys_core) [[unlikely]] { 866 if (core == sys_core) [[unlikely]] {
867 sys_core_guard.lock(); 867 sys_core_guard.lock();
868 } 868 }
869 SCOPE_EXIT({ 869 SCOPE_EXIT {
870 if (core == sys_core) [[unlikely]] { 870 if (core == sys_core) [[unlikely]] {
871 sys_core_guard.unlock(); 871 sys_core_guard.unlock();
872 } 872 }
873 }); 873 };
874 auto& gpu = system.GPU(); 874 auto& gpu = system.GPU();
875 gpu_device_memory->ApplyOpOnPointer( 875 gpu_device_memory->ApplyOpOnPointer(
876 p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); }); 876 p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index f7097d01d..caceeec4f 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -224,12 +224,12 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
224 // If we've ever seen a decode failure, return false. 224 // If we've ever seen a decode failure, return false.
225 bool valid = decode_success; 225 bool valid = decode_success;
226 CheatVmOpcode opcode = {}; 226 CheatVmOpcode opcode = {};
227 SCOPE_EXIT({ 227 SCOPE_EXIT {
228 decode_success &= valid; 228 decode_success &= valid;
229 if (valid) { 229 if (valid) {
230 out = opcode; 230 out = opcode;
231 } 231 }
232 }); 232 };
233 233
234 // Helper function for getting instruction dwords. 234 // Helper function for getting instruction dwords.
235 const auto GetNextDword = [&] { 235 const auto GetNextDword = [&] {
diff --git a/src/hid_core/frontend/emulated_controller.cpp b/src/hid_core/frontend/emulated_controller.cpp
index d9d278fa3..5cd26819c 100644
--- a/src/hid_core/frontend/emulated_controller.cpp
+++ b/src/hid_core/frontend/emulated_controller.cpp
@@ -933,8 +933,9 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
933 if (index >= controller.stick_values.size()) { 933 if (index >= controller.stick_values.size()) {
934 return; 934 return;
935 } 935 }
936 auto trigger_guard = 936 auto trigger_guard = SCOPE_GUARD {
937 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); }); 937 TriggerOnChange(ControllerTriggerType::Stick, !is_configuring);
938 };
938 std::scoped_lock lock{mutex}; 939 std::scoped_lock lock{mutex};
939 const auto stick_value = TransformToStick(callback); 940 const auto stick_value = TransformToStick(callback);
940 941
@@ -989,8 +990,9 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
989 if (index >= controller.trigger_values.size()) { 990 if (index >= controller.trigger_values.size()) {
990 return; 991 return;
991 } 992 }
992 auto trigger_guard = 993 auto trigger_guard = SCOPE_GUARD {
993 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); }); 994 TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring);
995 };
994 std::scoped_lock lock{mutex}; 996 std::scoped_lock lock{mutex};
995 const auto trigger_value = TransformToTrigger(callback); 997 const auto trigger_value = TransformToTrigger(callback);
996 998
@@ -1036,7 +1038,9 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
1036 if (index >= controller.motion_values.size()) { 1038 if (index >= controller.motion_values.size()) {
1037 return; 1039 return;
1038 } 1040 }
1039 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); }); 1041 SCOPE_EXIT {
1042 TriggerOnChange(ControllerTriggerType::Motion, !is_configuring);
1043 };
1040 std::scoped_lock lock{mutex}; 1044 std::scoped_lock lock{mutex};
1041 auto& raw_status = controller.motion_values[index].raw_status; 1045 auto& raw_status = controller.motion_values[index].raw_status;
1042 auto& emulated = controller.motion_values[index].emulated; 1046 auto& emulated = controller.motion_values[index].emulated;
@@ -1070,8 +1074,9 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
1070 if (index >= controller.color_values.size()) { 1074 if (index >= controller.color_values.size()) {
1071 return; 1075 return;
1072 } 1076 }
1073 auto trigger_guard = 1077 auto trigger_guard = SCOPE_GUARD {
1074 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); }); 1078 TriggerOnChange(ControllerTriggerType::Color, !is_configuring);
1079 };
1075 std::scoped_lock lock{mutex}; 1080 std::scoped_lock lock{mutex};
1076 controller.color_values[index] = TransformToColor(callback); 1081 controller.color_values[index] = TransformToColor(callback);
1077 1082
@@ -1120,7 +1125,9 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
1120 if (index >= controller.battery_values.size()) { 1125 if (index >= controller.battery_values.size()) {
1121 return; 1126 return;
1122 } 1127 }
1123 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); }); 1128 SCOPE_EXIT {
1129 TriggerOnChange(ControllerTriggerType::Battery, !is_configuring);
1130 };
1124 std::scoped_lock lock{mutex}; 1131 std::scoped_lock lock{mutex};
1125 controller.battery_values[index] = TransformToBattery(callback); 1132 controller.battery_values[index] = TransformToBattery(callback);
1126 1133
@@ -1183,7 +1190,9 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
1183} 1190}
1184 1191
1185void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { 1192void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
1186 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); }); 1193 SCOPE_EXIT {
1194 TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring);
1195 };
1187 std::scoped_lock lock{mutex}; 1196 std::scoped_lock lock{mutex};
1188 controller.camera_values = TransformToCamera(callback); 1197 controller.camera_values = TransformToCamera(callback);
1189 1198
@@ -1198,7 +1207,9 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback
1198} 1207}
1199 1208
1200void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) { 1209void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
1201 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); }); 1210 SCOPE_EXIT {
1211 TriggerOnChange(ControllerTriggerType::RingController, !is_configuring);
1212 };
1202 std::scoped_lock lock{mutex}; 1213 std::scoped_lock lock{mutex};
1203 const auto force_value = TransformToStick(callback); 1214 const auto force_value = TransformToStick(callback);
1204 1215
@@ -1212,7 +1223,9 @@ void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& call
1212} 1223}
1213 1224
1214void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { 1225void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
1215 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); }); 1226 SCOPE_EXIT {
1227 TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring);
1228 };
1216 std::scoped_lock lock{mutex}; 1229 std::scoped_lock lock{mutex};
1217 controller.nfc_values = TransformToNfc(callback); 1230 controller.nfc_values = TransformToNfc(callback);
1218 1231
@@ -1685,8 +1698,9 @@ void EmulatedController::Connect(bool use_temporary_value) {
1685 return; 1698 return;
1686 } 1699 }
1687 1700
1688 auto trigger_guard = 1701 auto trigger_guard = SCOPE_GUARD {
1689 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); }); 1702 TriggerOnChange(ControllerTriggerType::Connected, !is_configuring);
1703 };
1690 std::scoped_lock lock{connect_mutex, mutex}; 1704 std::scoped_lock lock{connect_mutex, mutex};
1691 if (is_configuring) { 1705 if (is_configuring) {
1692 tmp_is_connected = true; 1706 tmp_is_connected = true;
@@ -1701,8 +1715,9 @@ void EmulatedController::Connect(bool use_temporary_value) {
1701} 1715}
1702 1716
1703void EmulatedController::Disconnect() { 1717void EmulatedController::Disconnect() {
1704 auto trigger_guard = 1718 auto trigger_guard = SCOPE_GUARD {
1705 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); }); 1719 TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring);
1720 };
1706 std::scoped_lock lock{connect_mutex, mutex}; 1721 std::scoped_lock lock{connect_mutex, mutex};
1707 if (is_configuring) { 1722 if (is_configuring) {
1708 tmp_is_connected = false; 1723 tmp_is_connected = false;
@@ -1738,8 +1753,9 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c
1738} 1753}
1739 1754
1740void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { 1755void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
1741 auto trigger_guard = 1756 auto trigger_guard = SCOPE_GUARD {
1742 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); }); 1757 TriggerOnChange(ControllerTriggerType::Type, !is_configuring);
1758 };
1743 std::scoped_lock lock{mutex, npad_mutex}; 1759 std::scoped_lock lock{mutex, npad_mutex};
1744 1760
1745 if (is_configuring) { 1761 if (is_configuring) {
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index c9f903213..0dd1c958a 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -268,7 +268,9 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
268} 268}
269 269
270Common::Input::DriverResult JoyconDriver::SetPollingMode() { 270Common::Input::DriverResult JoyconDriver::SetPollingMode() {
271 SCOPE_EXIT({ disable_input_thread = false; }); 271 SCOPE_EXIT {
272 disable_input_thread = false;
273 };
272 disable_input_thread = true; 274 disable_input_thread = true;
273 275
274 rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); 276 rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 0031fa5fb..3f9698d6b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -261,7 +261,9 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
261 case Stage::Geometry: 261 case Stage::Geometry:
262 execution_model = spv::ExecutionModel::Geometry; 262 execution_model = spv::ExecutionModel::Geometry;
263 ctx.AddCapability(spv::Capability::Geometry); 263 ctx.AddCapability(spv::Capability::Geometry);
264 ctx.AddCapability(spv::Capability::GeometryStreams); 264 if (ctx.profile.support_geometry_streams) {
265 ctx.AddCapability(spv::Capability::GeometryStreams);
266 }
265 switch (ctx.runtime_info.input_topology) { 267 switch (ctx.runtime_info.input_topology) {
266 case InputTopology::Points: 268 case InputTopology::Points:
267 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints); 269 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 44281e407..945cdb42b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -60,11 +60,10 @@ public:
60 Add(spv::ImageOperandsMask::ConstOffsets, offsets); 60 Add(spv::ImageOperandsMask::ConstOffsets, offsets);
61 } 61 }
62 62
63 explicit ImageOperands(EmitContext& ctx, const IR::Value& offset, Id lod, Id ms) { 63 explicit ImageOperands(Id lod, Id ms) {
64 if (Sirit::ValidId(lod)) { 64 if (Sirit::ValidId(lod)) {
65 Add(spv::ImageOperandsMask::Lod, lod); 65 Add(spv::ImageOperandsMask::Lod, lod);
66 } 66 }
67 AddOffset(ctx, offset, ImageFetchOffsetAllowed);
68 if (Sirit::ValidId(ms)) { 67 if (Sirit::ValidId(ms)) {
69 Add(spv::ImageOperandsMask::Sample, ms); 68 Add(spv::ImageOperandsMask::Sample, ms);
70 } 69 }
@@ -312,6 +311,43 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info,
312 return coords; 311 return coords;
313 } 312 }
314} 313}
314
315void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, Id& coords,
316 Id offset) {
317 if (!Sirit::ValidId(offset)) {
318 return;
319 }
320
321 Id result_type{};
322 switch (info.type) {
323 case TextureType::Buffer:
324 case TextureType::Color1D: {
325 result_type = ctx.U32[1];
326 break;
327 }
328 case TextureType::ColorArray1D:
329 offset = ctx.OpCompositeConstruct(ctx.U32[2], offset, ctx.u32_zero_value);
330 [[fallthrough]];
331 case TextureType::Color2D:
332 case TextureType::Color2DRect: {
333 result_type = ctx.U32[2];
334 break;
335 }
336 case TextureType::ColorArray2D:
337 offset = ctx.OpCompositeConstruct(ctx.U32[3], ctx.OpCompositeExtract(ctx.U32[1], coords, 0),
338 ctx.OpCompositeExtract(ctx.U32[1], coords, 1),
339 ctx.u32_zero_value);
340 [[fallthrough]];
341 case TextureType::Color3D: {
342 result_type = ctx.U32[3];
343 break;
344 }
345 case TextureType::ColorCube:
346 case TextureType::ColorArrayCube:
347 return;
348 }
349 coords = ctx.OpIAdd(result_type, coords, offset);
350}
315} // Anonymous namespace 351} // Anonymous namespace
316 352
317Id EmitBindlessImageSampleImplicitLod(EmitContext&) { 353Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
@@ -494,9 +530,10 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
494 operands.Span()); 530 operands.Span());
495} 531}
496 532
497Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 533Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
498 const IR::Value& offset, Id lod, Id ms) { 534 Id lod, Id ms) {
499 const auto info{inst->Flags<IR::TextureInstInfo>()}; 535 const auto info{inst->Flags<IR::TextureInstInfo>()};
536 AddOffsetToCoordinates(ctx, info, coords, offset);
500 if (info.type == TextureType::Buffer) { 537 if (info.type == TextureType::Buffer) {
501 lod = Id{}; 538 lod = Id{};
502 } 539 }
@@ -504,7 +541,7 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
504 // This image is multisampled, lod must be implicit 541 // This image is multisampled, lod must be implicit
505 lod = Id{}; 542 lod = Id{};
506 } 543 }
507 const ImageOperands operands(ctx, offset, lod, ms); 544 const ImageOperands operands(lod, ms);
508 return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], 545 return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
509 TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); 546 TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
510} 547}
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index 08fcabd58..5c01b1012 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -537,8 +537,8 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id
537 const IR::Value& offset, const IR::Value& offset2); 537 const IR::Value& offset, const IR::Value& offset2);
538Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 538Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
539 const IR::Value& offset, const IR::Value& offset2, Id dref); 539 const IR::Value& offset, const IR::Value& offset2, Id dref);
540Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 540Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
541 const IR::Value& offset, Id lod, Id ms); 541 Id lod, Id ms);
542Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, 542Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
543 const IR::Value& skip_mips); 543 const IR::Value& skip_mips);
544Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); 544Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
index 9f7b6bb4b..f60da758e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
@@ -129,7 +129,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { 129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) {
130 ConvertDepthMode(ctx); 130 ConvertDepthMode(ctx);
131 } 131 }
132 if (stream.IsImmediate()) { 132 if (!ctx.profile.support_geometry_streams) {
133 throw NotImplementedException("Geometry streams");
134 } else if (stream.IsImmediate()) {
133 ctx.OpEmitStreamVertex(ctx.Def(stream)); 135 ctx.OpEmitStreamVertex(ctx.Def(stream));
134 } else { 136 } else {
135 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 137 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
@@ -140,7 +142,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
140} 142}
141 143
142void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { 144void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
143 if (stream.IsImmediate()) { 145 if (!ctx.profile.support_geometry_streams) {
146 throw NotImplementedException("Geometry streams");
147 } else if (stream.IsImmediate()) {
144 ctx.OpEndStreamPrimitive(ctx.Def(stream)); 148 ctx.OpEndStreamPrimitive(ctx.Def(stream));
145 } else { 149 } else {
146 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 150 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 7578d41cc..90e46bb1b 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -44,6 +44,7 @@ struct Profile {
44 bool support_gl_derivative_control{}; 44 bool support_gl_derivative_control{};
45 bool support_scaled_attributes{}; 45 bool support_scaled_attributes{};
46 bool support_multi_viewport{}; 46 bool support_multi_viewport{};
47 bool support_geometry_streams{};
47 48
48 bool warp_size_potentially_larger_than_guest{}; 49 bool warp_size_potentially_larger_than_guest{};
49 50
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 6d3d933c5..ed7a5b27e 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -35,7 +35,7 @@ BufferCache<P>::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R
35 const s64 min_spacing_critical = device_local_memory - 512_MiB; 35 const s64 min_spacing_critical = device_local_memory - 512_MiB;
36 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD); 36 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
37 const s64 min_vacancy_expected = (6 * mem_threshold) / 10; 37 const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
38 const s64 min_vacancy_critical = (3 * mem_threshold) / 10; 38 const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
39 minimum_memory = static_cast<u64>( 39 minimum_memory = static_cast<u64>(
40 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected), 40 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
41 DEFAULT_EXPECTED_MEMORY)); 41 DEFAULT_EXPECTED_MEMORY));
@@ -1130,7 +1130,7 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
1130 channel_state->vertex_buffers[index] = NULL_BINDING; 1130 channel_state->vertex_buffers[index] = NULL_BINDING;
1131 return; 1131 return;
1132 } 1132 }
1133 if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) { 1133 if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || size >= 64_MiB) {
1134 size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size)); 1134 size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
1135 } 1135 }
1136 const BufferId buffer_id = FindBuffer(*device_addr, size); 1136 const BufferId buffer_id = FindBuffer(*device_addr, size);
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index a94e1f043..0d47b032c 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -291,7 +291,9 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
291} 291}
292 292
293void Maxwell3D::ConsumeSinkImpl() { 293void Maxwell3D::ConsumeSinkImpl() {
294 SCOPE_EXIT({ method_sink.clear(); }); 294 SCOPE_EXIT {
295 method_sink.clear();
296 };
295 const auto control = shadow_state.shadow_ram_control; 297 const auto control = shadow_state.shadow_ram_control;
296 if (control == Regs::ShadowRamControl::Track || 298 if (control == Regs::ShadowRamControl::Track ||
297 control == Regs::ShadowRamControl::TrackWithFilter) { 299 control == Regs::ShadowRamControl::TrackWithFilter) {
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index c3eda6893..2135f1f2d 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -197,7 +197,9 @@ private:
197 MicroProfileOnThreadCreate(name.c_str()); 197 MicroProfileOnThreadCreate(name.c_str());
198 198
199 // Cleanup 199 // Cleanup
200 SCOPE_EXIT({ MicroProfileOnThreadExit(); }); 200 SCOPE_EXIT {
201 MicroProfileOnThreadExit();
202 };
201 203
202 Common::SetCurrentThreadName(name.c_str()); 204 Common::SetCurrentThreadName(name.c_str());
203 Common::SetCurrentThreadPriority(Common::ThreadPriority::High); 205 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 58d8110b8..477e11457 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -22,7 +22,9 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
22 Tegra::Control::Scheduler& scheduler, SynchState& state) { 22 Tegra::Control::Scheduler& scheduler, SynchState& state) {
23 std::string name = "GPU"; 23 std::string name = "GPU";
24 MicroProfileOnThreadCreate(name.c_str()); 24 MicroProfileOnThreadCreate(name.c_str());
25 SCOPE_EXIT({ MicroProfileOnThreadExit(); }); 25 SCOPE_EXIT {
26 MicroProfileOnThreadExit();
27 };
26 28
27 Common::SetCurrentThreadName(name.c_str()); 29 Common::SetCurrentThreadName(name.c_str());
28 Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); 30 Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
index 96686da59..1003cd38d 100644
--- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp
+++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
@@ -273,10 +273,10 @@ DeinterlaceFilter::DeinterlaceFilter(const Frame& frame) {
273 const AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); 273 const AVFilter* buffer_sink = avfilter_get_by_name("buffersink");
274 AVFilterInOut* inputs = avfilter_inout_alloc(); 274 AVFilterInOut* inputs = avfilter_inout_alloc();
275 AVFilterInOut* outputs = avfilter_inout_alloc(); 275 AVFilterInOut* outputs = avfilter_inout_alloc();
276 SCOPE_EXIT({ 276 SCOPE_EXIT {
277 avfilter_inout_free(&inputs); 277 avfilter_inout_free(&inputs);
278 avfilter_inout_free(&outputs); 278 avfilter_inout_free(&outputs);
279 }); 279 };
280 280
281 // Don't know how to get the accurate time_base but it doesn't matter for yadif filter 281 // Don't know how to get the accurate time_base but it doesn't matter for yadif filter
282 // so just use 1/1 to make buffer filter happy 282 // so just use 1/1 to make buffer filter happy
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index 46e853e04..fb529f88b 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -92,12 +92,12 @@ public:
92 92
93private: 93private:
94 void Fallback(const std::vector<u32>& parameters) { 94 void Fallback(const std::vector<u32>& parameters) {
95 SCOPE_EXIT({ 95 SCOPE_EXIT {
96 if (extended) { 96 if (extended) {
97 maxwell3d.engine_state = Maxwell3D::EngineHint::None; 97 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
98 maxwell3d.replace_table.clear(); 98 maxwell3d.replace_table.clear();
99 } 99 }
100 }); 100 };
101 maxwell3d.RefreshParameters(); 101 maxwell3d.RefreshParameters();
102 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); 102 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
103 103
@@ -281,12 +281,12 @@ public:
281 281
282private: 282private:
283 void Fallback(const std::vector<u32>& parameters) { 283 void Fallback(const std::vector<u32>& parameters) {
284 SCOPE_EXIT({ 284 SCOPE_EXIT {
285 // Clean everything. 285 // Clean everything.
286 maxwell3d.regs.vertex_id_base = 0x0; 286 maxwell3d.regs.vertex_id_base = 0x0;
287 maxwell3d.engine_state = Maxwell3D::EngineHint::None; 287 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
288 maxwell3d.replace_table.clear(); 288 maxwell3d.replace_table.clear();
289 }); 289 };
290 maxwell3d.RefreshParameters(); 290 maxwell3d.RefreshParameters();
291 const u32 start_indirect = parameters[0]; 291 const u32 start_indirect = parameters[0];
292 const u32 end_indirect = parameters[1]; 292 const u32 end_indirect = parameters[1];
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index b42fb110c..16af8e6bd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -230,7 +230,9 @@ template <typename Func>
230void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { 230void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
231 MICROPROFILE_SCOPE(OpenGL_Drawing); 231 MICROPROFILE_SCOPE(OpenGL_Drawing);
232 232
233 SCOPE_EXIT({ gpu.TickWork(); }); 233 SCOPE_EXIT {
234 gpu.TickWork();
235 };
234 gpu_memory->FlushCaching(); 236 gpu_memory->FlushCaching();
235 237
236 GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; 238 GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
@@ -355,7 +357,9 @@ void RasterizerOpenGL::DrawIndirect() {
355void RasterizerOpenGL::DrawTexture() { 357void RasterizerOpenGL::DrawTexture() {
356 MICROPROFILE_SCOPE(OpenGL_Drawing); 358 MICROPROFILE_SCOPE(OpenGL_Drawing);
357 359
358 SCOPE_EXIT({ gpu.TickWork(); }); 360 SCOPE_EXIT {
361 gpu.TickWork();
362 };
359 363
360 texture_cache.SynchronizeGraphicsDescriptors(); 364 texture_cache.SynchronizeGraphicsDescriptors();
361 texture_cache.UpdateRenderTargets(false); 365 texture_cache.UpdateRenderTargets(false);
diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp
index 3847a9a13..4e41afe5b 100644
--- a/src/video_core/renderer_vulkan/present/layer.cpp
+++ b/src/video_core/renderer_vulkan/present/layer.cpp
@@ -82,7 +82,9 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants,
82 // Finish any pending renderpass 82 // Finish any pending renderpass
83 scheduler.RequestOutsideRenderPassOperationContext(); 83 scheduler.RequestOutsideRenderPassOperationContext();
84 scheduler.Wait(resource_ticks[image_index]); 84 scheduler.Wait(resource_ticks[image_index]);
85 SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); }); 85 SCOPE_EXIT {
86 resource_ticks[image_index] = scheduler.CurrentTick();
87 };
86 88
87 if (!use_accelerated) { 89 if (!use_accelerated) {
88 UpdateRawImage(framebuffer, image_index); 90 UpdateRawImage(framebuffer, image_index);
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index d50417116..c553f5b3d 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -144,7 +144,9 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
144 return; 144 return;
145 } 145 }
146 146
147 SCOPE_EXIT({ render_window.OnFrameDisplayed(); }); 147 SCOPE_EXIT {
148 render_window.OnFrameDisplayed();
149 };
148 150
149 RenderAppletCaptureLayer(framebuffers); 151 RenderAppletCaptureLayer(framebuffers);
150 152
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 20f7a9702..d34b585d6 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -352,6 +352,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
352 .support_native_ndc = device.IsExtDepthClipControlSupported(), 352 .support_native_ndc = device.IsExtDepthClipControlSupported(),
353 .support_scaled_attributes = !device.MustEmulateScaledFormats(), 353 .support_scaled_attributes = !device.MustEmulateScaledFormats(),
354 .support_multi_viewport = device.SupportsMultiViewport(), 354 .support_multi_viewport = device.SupportsMultiViewport(),
355 .support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
355 356
356 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), 357 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
357 358
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index aa0a027bb..74f9f099e 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -196,7 +196,9 @@ template <typename Func>
196void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { 196void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
197 MICROPROFILE_SCOPE(Vulkan_Drawing); 197 MICROPROFILE_SCOPE(Vulkan_Drawing);
198 198
199 SCOPE_EXIT({ gpu.TickWork(); }); 199 SCOPE_EXIT {
200 gpu.TickWork();
201 };
200 FlushWork(); 202 FlushWork();
201 gpu_memory->FlushCaching(); 203 gpu_memory->FlushCaching();
202 204
@@ -288,7 +290,9 @@ void RasterizerVulkan::DrawIndirect() {
288void RasterizerVulkan::DrawTexture() { 290void RasterizerVulkan::DrawTexture() {
289 MICROPROFILE_SCOPE(Vulkan_Drawing); 291 MICROPROFILE_SCOPE(Vulkan_Drawing);
290 292
291 SCOPE_EXIT({ gpu.TickWork(); }); 293 SCOPE_EXIT {
294 gpu.TickWork();
295 };
292 FlushWork(); 296 FlushWork();
293 297
294 query_cache.NotifySegment(true); 298 query_cache.NotifySegment(true);
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 5b3c7aa5a..9055b1b92 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -3,6 +3,7 @@
3 3
4#include "common/common_types.h" 4#include "common/common_types.h"
5#include "common/math_util.h" 5#include "common/math_util.h"
6#include "common/settings.h"
6#include "video_core/surface.h" 7#include "video_core/surface.h"
7 8
8namespace VideoCore::Surface { 9namespace VideoCore::Surface {
@@ -400,11 +401,20 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
400 return {DefaultBlockWidth(format), DefaultBlockHeight(format)}; 401 return {DefaultBlockWidth(format), DefaultBlockHeight(format)};
401} 402}
402 403
403u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format) { 404u64 TranscodedAstcSize(u64 base_size, PixelFormat format) {
404 constexpr u64 RGBA8_PIXEL_SIZE = 4; 405 constexpr u64 RGBA8_PIXEL_SIZE = 4;
405 const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) * 406 const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) *
406 static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE; 407 static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
407 return (base_size * base_block_size) / BytesPerBlock(format); 408 const u64 uncompressed_size = (base_size * base_block_size) / BytesPerBlock(format);
409
410 switch (Settings::values.astc_recompression.GetValue()) {
411 case Settings::AstcRecompression::Bc1:
412 return uncompressed_size / 8;
413 case Settings::AstcRecompression::Bc3:
414 return uncompressed_size / 4;
415 default:
416 return uncompressed_size;
417 }
408} 418}
409 419
410} // namespace VideoCore::Surface 420} // namespace VideoCore::Surface
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index a5e8e2f62..ec9cd2fbf 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -517,6 +517,6 @@ size_t PixelComponentSizeBitsInteger(PixelFormat format);
517 517
518std::pair<u32, u32> GetASTCBlockSize(PixelFormat format); 518std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
519 519
520u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format); 520u64 TranscodedAstcSize(u64 base_size, PixelFormat format);
521 521
522} // namespace VideoCore::Surface 522} // namespace VideoCore::Surface
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 01c3561c9..53b4876f2 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -55,7 +55,7 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
55 const s64 min_spacing_critical = device_local_memory - 512_MiB; 55 const s64 min_spacing_critical = device_local_memory - 512_MiB;
56 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD); 56 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
57 const s64 min_vacancy_expected = (6 * mem_threshold) / 10; 57 const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
58 const s64 min_vacancy_critical = (3 * mem_threshold) / 10; 58 const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
59 expected_memory = static_cast<u64>( 59 expected_memory = static_cast<u64>(
60 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected), 60 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
61 DEFAULT_EXPECTED_MEMORY)); 61 DEFAULT_EXPECTED_MEMORY));
@@ -1979,7 +1979,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
1979 if ((IsPixelFormatASTC(image.info.format) && 1979 if ((IsPixelFormatASTC(image.info.format) &&
1980 True(image.flags & ImageFlagBits::AcceleratedUpload)) || 1980 True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
1981 True(image.flags & ImageFlagBits::Converted)) { 1981 True(image.flags & ImageFlagBits::Converted)) {
1982 tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format); 1982 tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
1983 } 1983 }
1984 total_used_memory += Common::AlignUp(tentative_size, 1024); 1984 total_used_memory += Common::AlignUp(tentative_size, 1024);
1985 image.lru_index = lru_cache.Insert(image_id, frame_tick); 1985 image.lru_index = lru_cache.Insert(image_id, frame_tick);
@@ -2149,7 +2149,7 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
2149 if ((IsPixelFormatASTC(image.info.format) && 2149 if ((IsPixelFormatASTC(image.info.format) &&
2150 True(image.flags & ImageFlagBits::AcceleratedUpload)) || 2150 True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
2151 True(image.flags & ImageFlagBits::Converted)) { 2151 True(image.flags & ImageFlagBits::Converted)) {
2152 tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format); 2152 tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
2153 } 2153 }
2154 total_used_memory -= Common::AlignUp(tentative_size, 1024); 2154 total_used_memory -= Common::AlignUp(tentative_size, 1024);
2155 const GPUVAddr gpu_addr = image.gpu_addr; 2155 const GPUVAddr gpu_addr = image.gpu_addr;
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
index 5fa0d9620..f41c3e506 100644
--- a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
+++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
@@ -116,7 +116,9 @@ void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump,
116 LOG_ERROR(Render_Vulkan, "Failed to create decoder"); 116 LOG_ERROR(Render_Vulkan, "Failed to create decoder");
117 return; 117 return;
118 } 118 }
119 SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); }); 119 SCOPE_EXIT {
120 GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder);
121 };
120 122
121 u32 json_size = 0; 123 u32 json_size = 0;
122 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON( 124 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON(
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index a2ec26697..e3abe8ddf 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -499,6 +499,11 @@ public:
499 return extensions.transform_feedback; 499 return extensions.transform_feedback;
500 } 500 }
501 501
502 /// Returns true if the device supports VK_EXT_transform_feedback properly.
503 bool AreTransformFeedbackGeometryStreamsSupported() const {
504 return features.transform_feedback.geometryStreams;
505 }
506
502 /// Returns true if the device supports VK_EXT_custom_border_color. 507 /// Returns true if the device supports VK_EXT_custom_border_color.
503 bool IsExtCustomBorderColorSupported() const { 508 bool IsExtCustomBorderColorSupported() const {
504 return extensions.custom_border_color; 509 return extensions.custom_border_color;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 0d16bfd65..b2ae3db52 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -646,10 +646,10 @@ void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParamete
646 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) { 646 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) {
647 cabinet_applet = 647 cabinet_applet =
648 new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); 648 new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device);
649 SCOPE_EXIT({ 649 SCOPE_EXIT {
650 cabinet_applet->deleteLater(); 650 cabinet_applet->deleteLater();
651 cabinet_applet = nullptr; 651 cabinet_applet = nullptr;
652 }); 652 };
653 653
654 cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | 654 cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
655 Qt::WindowTitleHint | Qt::WindowSystemMenuHint); 655 Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
@@ -673,10 +673,10 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
673 const Core::Frontend::ControllerParameters& parameters) { 673 const Core::Frontend::ControllerParameters& parameters) {
674 controller_applet = 674 controller_applet =
675 new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); 675 new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system);
676 SCOPE_EXIT({ 676 SCOPE_EXIT {
677 controller_applet->deleteLater(); 677 controller_applet->deleteLater();
678 controller_applet = nullptr; 678 controller_applet = nullptr;
679 }); 679 };
680 680
681 controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | 681 controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint |
682 Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | 682 Qt::WindowStaysOnTopHint | Qt::WindowTitleHint |
@@ -703,10 +703,10 @@ void GMainWindow::ControllerSelectorRequestExit() {
703void GMainWindow::ProfileSelectorSelectProfile( 703void GMainWindow::ProfileSelectorSelectProfile(
704 const Core::Frontend::ProfileSelectParameters& parameters) { 704 const Core::Frontend::ProfileSelectParameters& parameters) {
705 profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); 705 profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters);
706 SCOPE_EXIT({ 706 SCOPE_EXIT {
707 profile_select_applet->deleteLater(); 707 profile_select_applet->deleteLater();
708 profile_select_applet = nullptr; 708 profile_select_applet = nullptr;
709 }); 709 };
710 710
711 profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | 711 profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint |
712 Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | 712 Qt::WindowStaysOnTopHint | Qt::WindowTitleHint |
@@ -1604,6 +1604,7 @@ void GMainWindow::ConnectMenuEvents() {
1604 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); 1604 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
1605 connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); 1605 connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
1606 connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware); 1606 connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
1607 connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
1607 connect_menu(ui->action_About, &GMainWindow::OnAbout); 1608 connect_menu(ui->action_About, &GMainWindow::OnAbout);
1608} 1609}
1609 1610
@@ -1633,6 +1634,7 @@ void GMainWindow::UpdateMenuState() {
1633 } 1634 }
1634 1635
1635 ui->action_Install_Firmware->setEnabled(!emulation_running); 1636 ui->action_Install_Firmware->setEnabled(!emulation_running);
1637 ui->action_Install_Keys->setEnabled(!emulation_running);
1636 1638
1637 for (QAction* action : applet_actions) { 1639 for (QAction* action : applet_actions) {
1638 action->setEnabled(is_firmware_available && !emulation_running); 1640 action->setEnabled(is_firmware_available && !emulation_running);
@@ -2885,17 +2887,19 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
2885 LOG_ERROR(Frontend, "CoInitialize failed"); 2887 LOG_ERROR(Frontend, "CoInitialize failed");
2886 return false; 2888 return false;
2887 } 2889 }
2888 SCOPE_EXIT({ CoUninitialize(); }); 2890 SCOPE_EXIT {
2891 CoUninitialize();
2892 };
2889 IShellLinkW* ps1 = nullptr; 2893 IShellLinkW* ps1 = nullptr;
2890 IPersistFile* persist_file = nullptr; 2894 IPersistFile* persist_file = nullptr;
2891 SCOPE_EXIT({ 2895 SCOPE_EXIT {
2892 if (persist_file != nullptr) { 2896 if (persist_file != nullptr) {
2893 persist_file->Release(); 2897 persist_file->Release();
2894 } 2898 }
2895 if (ps1 != nullptr) { 2899 if (ps1 != nullptr) {
2896 ps1->Release(); 2900 ps1->Release();
2897 } 2901 }
2898 }); 2902 };
2899 HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, 2903 HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
2900 reinterpret_cast<void**>(&ps1)); 2904 reinterpret_cast<void**>(&ps1));
2901 if (FAILED(hres)) { 2905 if (FAILED(hres)) {
@@ -3520,10 +3524,10 @@ void GMainWindow::OnSaveConfig() {
3520void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { 3524void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
3521 error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, 3525 error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{},
3522 tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); 3526 tr("OK"), Qt::AlignLeft | Qt::AlignVCenter);
3523 SCOPE_EXIT({ 3527 SCOPE_EXIT {
3524 error_applet->deleteLater(); 3528 error_applet->deleteLater();
3525 error_applet = nullptr; 3529 error_applet = nullptr;
3526 }); 3530 };
3527 error_applet->exec(); 3531 error_applet->exec();
3528 3532
3529 emit ErrorDisplayFinished(); 3533 emit ErrorDisplayFinished();
@@ -4167,9 +4171,8 @@ void GMainWindow::OnInstallFirmware() {
4167 return; 4171 return;
4168 } 4172 }
4169 4173
4170 QString firmware_source_location = 4174 const QString firmware_source_location = QFileDialog::getExistingDirectory(
4171 QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"), 4175 this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
4172 QString::fromStdString(""), QFileDialog::ShowDirsOnly);
4173 if (firmware_source_location.isEmpty()) { 4176 if (firmware_source_location.isEmpty()) {
4174 return; 4177 return;
4175 } 4178 }
@@ -4200,8 +4203,9 @@ void GMainWindow::OnInstallFirmware() {
4200 std::vector<std::filesystem::path> out; 4203 std::vector<std::filesystem::path> out;
4201 const Common::FS::DirEntryCallable callback = 4204 const Common::FS::DirEntryCallable callback =
4202 [&out](const std::filesystem::directory_entry& entry) { 4205 [&out](const std::filesystem::directory_entry& entry) {
4203 if (entry.path().has_extension() && entry.path().extension() == ".nca") 4206 if (entry.path().has_extension() && entry.path().extension() == ".nca") {
4204 out.emplace_back(entry.path()); 4207 out.emplace_back(entry.path());
4208 }
4205 4209
4206 return true; 4210 return true;
4207 }; 4211 };
@@ -4233,7 +4237,6 @@ void GMainWindow::OnInstallFirmware() {
4233 auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); 4237 auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
4234 4238
4235 bool success = true; 4239 bool success = true;
4236 bool cancelled = false;
4237 int i = 0; 4240 int i = 0;
4238 for (const auto& firmware_src_path : out) { 4241 for (const auto& firmware_src_path : out) {
4239 i++; 4242 i++;
@@ -4248,24 +4251,22 @@ void GMainWindow::OnInstallFirmware() {
4248 success = false; 4251 success = false;
4249 } 4252 }
4250 4253
4251 if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) { 4254 if (QtProgressCallback(
4252 success = false; 4255 100, 20 + static_cast<int>(((i) / static_cast<float>(out.size())) * 70.0))) {
4253 cancelled = true; 4256 progress.close();
4254 break; 4257 QMessageBox::warning(
4258 this, tr("Firmware install failed"),
4259 tr("Firmware installation cancelled, firmware may be in bad state, "
4260 "restart yuzu or re-install firmware."));
4261 return;
4255 } 4262 }
4256 } 4263 }
4257 4264
4258 if (!success && !cancelled) { 4265 if (!success) {
4259 progress.close(); 4266 progress.close();
4260 QMessageBox::critical(this, tr("Firmware install failed"), 4267 QMessageBox::critical(this, tr("Firmware install failed"),
4261 tr("One or more firmware files failed to copy into NAND.")); 4268 tr("One or more firmware files failed to copy into NAND."));
4262 return; 4269 return;
4263 } else if (cancelled) {
4264 progress.close();
4265 QMessageBox::warning(this, tr("Firmware install failed"),
4266 tr("Firmware installation cancelled, firmware may be in bad state, "
4267 "restart yuzu or re-install firmware."));
4268 return;
4269 } 4270 }
4270 4271
4271 // Re-scan VFS for the newly placed firmware files. 4272 // Re-scan VFS for the newly placed firmware files.
@@ -4293,6 +4294,84 @@ void GMainWindow::OnInstallFirmware() {
4293 OnCheckFirmwareDecryption(); 4294 OnCheckFirmwareDecryption();
4294} 4295}
4295 4296
4297void GMainWindow::OnInstallDecryptionKeys() {
4298 // Don't do this while emulation is running.
4299 if (emu_thread != nullptr && emu_thread->IsRunning()) {
4300 return;
4301 }
4302
4303 const QString key_source_location = QFileDialog::getOpenFileName(
4304 this, tr("Select Dumped Keys Location"), {}, QStringLiteral("prod.keys (prod.keys)"), {},
4305 QFileDialog::ReadOnly);
4306 if (key_source_location.isEmpty()) {
4307 return;
4308 }
4309
4310 // Verify that it contains prod.keys, title.keys and optionally, key_retail.bin
4311 LOG_INFO(Frontend, "Installing key files from {}", key_source_location.toStdString());
4312
4313 const std::filesystem::path prod_key_path = key_source_location.toStdString();
4314 const std::filesystem::path key_source_path = prod_key_path.parent_path();
4315 if (!Common::FS::IsDir(key_source_path)) {
4316 return;
4317 }
4318
4319 bool prod_keys_found = false;
4320 std::vector<std::filesystem::path> source_key_files;
4321
4322 if (Common::FS::Exists(prod_key_path)) {
4323 prod_keys_found = true;
4324 source_key_files.emplace_back(prod_key_path);
4325 }
4326
4327 if (Common::FS::Exists(key_source_path / "title.keys")) {
4328 source_key_files.emplace_back(key_source_path / "title.keys");
4329 }
4330
4331 if (Common::FS::Exists(key_source_path / "key_retail.bin")) {
4332 source_key_files.emplace_back(key_source_path / "key_retail.bin");
4333 }
4334
4335 // There should be at least prod.keys.
4336 if (source_key_files.empty() || !prod_keys_found) {
4337 QMessageBox::warning(this, tr("Decryption Keys install failed"),
4338 tr("prod.keys is a required decryption key file."));
4339 return;
4340 }
4341
4342 const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
4343 for (auto key_file : source_key_files) {
4344 std::filesystem::path destination_key_file = yuzu_keys_dir / key_file.filename();
4345 if (!std::filesystem::copy_file(key_file, destination_key_file,
4346 std::filesystem::copy_options::overwrite_existing)) {
4347 LOG_ERROR(Frontend, "Failed to copy file {} to {}", key_file.string(),
4348 destination_key_file.string());
4349 QMessageBox::critical(this, tr("Decryption Keys install failed"),
4350 tr("One or more keys failed to copy."));
4351 return;
4352 }
4353 }
4354
4355 // Reinitialize the key manager, re-read the vfs (for update/dlc files),
4356 // and re-populate the game list in the UI if the user has already added
4357 // game folders.
4358 Core::Crypto::KeyManager::Instance().ReloadKeys();
4359 system->GetFileSystemController().CreateFactories(*vfs);
4360 game_list->PopulateAsync(UISettings::values.game_dirs);
4361
4362 if (ContentManager::AreKeysPresent()) {
4363 QMessageBox::information(this, tr("Decryption Keys install succeeded"),
4364 tr("Decryption Keys were successfully installed"));
4365 } else {
4366 QMessageBox::critical(
4367 this, tr("Decryption Keys install failed"),
4368 tr("Decryption Keys failed to initialize. Check that your dumping tools are "
4369 "up to date and re-dump keys."));
4370 }
4371
4372 OnCheckFirmwareDecryption();
4373}
4374
4296void GMainWindow::OnAbout() { 4375void GMainWindow::OnAbout() {
4297 AboutDialog aboutDialog(this); 4376 AboutDialog aboutDialog(this);
4298 aboutDialog.exec(); 4377 aboutDialog.exec();
@@ -5192,7 +5271,9 @@ int main(int argc, char* argv[]) {
5192 5271
5193 Common::DetachedTasks detached_tasks; 5272 Common::DetachedTasks detached_tasks;
5194 MicroProfileOnThreadCreate("Frontend"); 5273 MicroProfileOnThreadCreate("Frontend");
5195 SCOPE_EXIT({ MicroProfileShutdown(); }); 5274 SCOPE_EXIT {
5275 MicroProfileShutdown();
5276 };
5196 5277
5197 Common::ConfigureNvidiaEnvironmentFlags(); 5278 Common::ConfigureNvidiaEnvironmentFlags();
5198 5279
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 1f0e35c67..fce643f3f 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -381,6 +381,7 @@ private slots:
381 void OnOpenYuzuFolder(); 381 void OnOpenYuzuFolder();
382 void OnVerifyInstalledContents(); 382 void OnVerifyInstalledContents();
383 void OnInstallFirmware(); 383 void OnInstallFirmware();
384 void OnInstallDecryptionKeys();
384 void OnAbout(); 385 void OnAbout();
385 void OnToggleFilterBar(); 386 void OnToggleFilterBar();
386 void OnToggleStatusBar(); 387 void OnToggleStatusBar();
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 6ff444a22..85dc1f2f6 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -165,8 +165,9 @@
165 <addaction name="separator"/> 165 <addaction name="separator"/>
166 <addaction name="action_Configure_Tas"/> 166 <addaction name="action_Configure_Tas"/>
167 </widget> 167 </widget>
168 <addaction name="action_Verify_installed_contents"/> 168 <addaction name="action_Install_Keys"/>
169 <addaction name="action_Install_Firmware"/> 169 <addaction name="action_Install_Firmware"/>
170 <addaction name="action_Verify_installed_contents"/>
170 <addaction name="separator"/> 171 <addaction name="separator"/>
171 <addaction name="menu_cabinet_applet"/> 172 <addaction name="menu_cabinet_applet"/>
172 <addaction name="action_Load_Album"/> 173 <addaction name="action_Load_Album"/>
@@ -469,6 +470,11 @@
469 <string>Install Firmware</string> 470 <string>Install Firmware</string>
470 </property> 471 </property>
471 </action> 472 </action>
473 <action name="action_Install_Keys">
474 <property name="text">
475 <string>Install Decryption Keys</string>
476 </property>
477 </action>
472 </widget> 478 </widget>
473 <resources> 479 <resources>
474 <include location="yuzu.qrc"/> 480 <include location="yuzu.qrc"/>
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 3b321dad1..8a8cdbc44 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -327,7 +327,9 @@ int main(int argc, char** argv) {
327#endif 327#endif
328 328
329 MicroProfileOnThreadCreate("EmuThread"); 329 MicroProfileOnThreadCreate("EmuThread");
330 SCOPE_EXIT({ MicroProfileShutdown(); }); 330 SCOPE_EXIT {
331 MicroProfileShutdown();
332 };
331 333
332 Common::ConfigureNvidiaEnvironmentFlags(); 334 Common::ConfigureNvidiaEnvironmentFlags();
333 335