summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/scripts/linux/docker.sh8
-rw-r--r--.ci/scripts/linux/upload.sh2
-rw-r--r--CMakeLists.txt30
-rw-r--r--externals/CMakeLists.txt12
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/common/parent_of_member.h3
-rw-r--r--src/common/settings.cpp9
-rw-r--r--src/common/settings.h10
-rw-r--r--src/common/tree.h13
-rw-r--r--src/core/CMakeLists.txt26
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp12
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp12
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h2
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.cpp4
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.h2
-rw-r--r--src/core/core.cpp5
-rw-r--r--src/core/cpu_manager.cpp2
-rw-r--r--src/core/cpu_manager.h2
-rw-r--r--src/core/crypto/ctr_encryption_layer.cpp4
-rw-r--r--src/core/crypto/ctr_encryption_layer.h2
-rw-r--r--src/core/crypto/key_manager.cpp2
-rw-r--r--src/core/file_sys/nca_metadata.cpp8
-rw-r--r--src/core/file_sys/nca_metadata.h4
-rw-r--r--src/core/file_sys/registered_cache.cpp7
-rw-r--r--src/core/file_sys/registered_cache.h1
-rw-r--r--src/core/file_sys/submission_package.cpp4
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/vfs_concat.cpp8
-rw-r--r--src/core/file_sys/vfs_concat.h4
-rw-r--r--src/core/file_sys/vfs_layered.cpp4
-rw-r--r--src/core/file_sys/vfs_layered.h2
-rw-r--r--src/core/file_sys/vfs_libzip.cpp9
-rw-r--r--src/core/file_sys/vfs_static.h6
-rw-r--r--src/core/file_sys/vfs_vector.cpp4
-rw-r--r--src/core/file_sys/vfs_vector.h4
-rw-r--r--src/core/frontend/emu_window.cpp2
-rw-r--r--src/core/hle/ipc.h17
-rw-r--r--src/core/hle/ipc_helpers.h99
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp4
-rw-r--r--src/core/hle/kernel/global_scheduler_context.h2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp171
-rw-r--r--src/core/hle/kernel/hle_ipc.h152
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp10
-rw-r--r--src/core/hle/kernel/k_client_port.cpp2
-rw-r--r--src/core/hle/kernel/k_client_port.h3
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h3
-rw-r--r--src/core/hle/kernel/k_linked_list.h8
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.cpp4
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.h2
-rw-r--r--src/core/hle/kernel/k_page_linked_list.h2
-rw-r--r--src/core/hle/kernel/k_page_table.cpp10
-rw-r--r--src/core/hle/kernel/k_page_table.h2
-rw-r--r--src/core/hle/kernel/k_port.cpp7
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp2
-rw-r--r--src/core/hle/kernel/k_scheduler.h2
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h4
-rw-r--r--src/core/hle/kernel/k_server_port.h16
-rw-r--r--src/core/hle/kernel/k_server_session.cpp35
-rw-r--r--src/core/hle/kernel/k_server_session.h36
-rw-r--r--src/core/hle/kernel/k_session.h4
-rw-r--r--src/core/hle/kernel/k_slab_heap.h154
-rw-r--r--src/core/hle/kernel/k_thread_queue.h2
-rw-r--r--src/core/hle/kernel/k_transfer_memory.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp21
-rw-r--r--src/core/hle/kernel/kernel.h18
-rw-r--r--src/core/hle/kernel/physical_core.cpp8
-rw-r--r--src/core/hle/kernel/physical_core.h4
-rw-r--r--src/core/hle/kernel/service_thread.cpp14
-rw-r--r--src/core/hle/kernel/svc.cpp13
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/am/am.cpp14
-rw-r--r--src/core/hle/service/apm/controller.cpp10
-rw-r--r--src/core/hle/service/apm/controller.h2
-rw-r--r--src/core/hle/service/audio/audren_u.cpp44
-rw-r--r--src/core/hle/service/audio/audren_u.h2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp8
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp13
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h2
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp47
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h24
-rw-r--r--src/core/hle/service/mii/manager.h2
-rw-r--r--src/core/hle/service/mii/mii.cpp4
-rw-r--r--src/core/hle/service/nifm/nifm.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h12
-rw-r--r--src/core/hle/service/nvdrv/syncpoint_manager.cpp2
-rw-r--r--src/core/hle/service/nvdrv/syncpoint_manager.h2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp4
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h2
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp32
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h12
-rw-r--r--src/core/hle/service/pctl/pctl.cpp4
-rw-r--r--src/core/hle/service/pctl/pctl.h2
-rw-r--r--src/core/hle/service/pm/pm.cpp12
-rw-r--r--src/core/hle/service/service.cpp59
-rw-r--r--src/core/hle/service/service.h47
-rw-r--r--src/core/hle/service/sm/controller.cpp41
-rw-r--r--src/core/hle/service/sm/sm.cpp119
-rw-r--r--src/core/hle/service/sm/sm.h12
-rw-r--r--src/core/hle/service/ssl/ssl.cpp2
-rw-r--r--src/core/hle/service/time/ephemeral_network_system_clock_core.h4
-rw-r--r--src/core/hle/service/time/local_system_clock_context_writer.h4
-rw-r--r--src/core/hle/service/time/network_system_clock_context_writer.h4
-rw-r--r--src/core/hle/service/time/standard_local_system_clock_core.h4
-rw-r--r--src/core/hle/service/time/standard_network_system_clock_core.h10
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.cpp22
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.h8
-rw-r--r--src/core/hle/service/time/system_clock_core.cpp4
-rw-r--r--src/core/hle/service/time/system_clock_core.h2
-rw-r--r--src/core/hle/service/time/time_manager.cpp2
-rw-r--r--src/core/hle/service/time/time_manager.h2
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp2
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h2
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp4
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.h2
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp4
-rw-r--r--src/core/hle/service/vi/display/vi_display.h8
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp2
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h4
-rw-r--r--src/core/hle/service/vi/vi.cpp24
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp23
-rw-r--r--src/core/loader/deconstructed_rom_directory.h4
-rw-r--r--src/core/loader/loader.cpp2
-rw-r--r--src/core/loader/loader.h2
-rw-r--r--src/core/memory.cpp21
-rw-r--r--src/core/memory.h9
-rw-r--r--src/core/memory/cheat_engine.cpp14
-rw-r--r--src/core/memory/cheat_engine.h8
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp3
-rw-r--r--src/core/memory/dmnt_cheat_vm.h2
-rw-r--r--src/core/perf_stats.cpp14
-rw-r--r--src/core/perf_stats.h11
-rw-r--r--src/core/reporter.cpp2
-rw-r--r--src/core/reporter.h2
-rw-r--r--src/input_common/main.cpp5
-rw-r--r--src/input_common/sdl/sdl.h3
-rw-r--r--src/input_common/sdl/sdl_impl.cpp153
-rw-r--r--src/input_common/sdl/sdl_impl.h1
-rw-r--r--src/input_common/udp/client.cpp23
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h5
-rw-r--r--src/video_core/gpu.cpp5
-rw-r--r--src/video_core/gpu.h2
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h8
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp1
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp26
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h10
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp38
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h5
-rw-r--r--src/video_core/texture_cache/texture_cache.h57
-rw-r--r--src/video_core/texture_cache/types.h7
-rw-r--r--src/yuzu/about_dialog.cpp16
-rw-r--r--src/yuzu/aboutdialog.ui2
-rw-r--r--src/yuzu/applets/software_keyboard.cpp16
-rw-r--r--src/yuzu/configuration/config.cpp72
-rw-r--r--src/yuzu/configuration/config.h1
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp58
-rw-r--r--src/yuzu/configuration/configuration_shared.h34
-rw-r--r--src/yuzu/configuration/configure_audio.cpp10
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp86
-rw-r--r--src/yuzu/configuration/configure_cpu.h10
-rw-r--r--src/yuzu/configuration/configure_cpu.ui90
-rw-r--r--src/yuzu/configuration/configure_debug.ui10
-rw-r--r--src/yuzu/configuration/configure_general.cpp12
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp42
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp46
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp8
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp1
-rw-r--r--src/yuzu/configuration/configure_per_game.ui11
-rw-r--r--src/yuzu/configuration/configure_system.cpp72
-rw-r--r--src/yuzu/main.cpp56
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
179 files changed, 1619 insertions, 1261 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh
index 1af5ded3d..9b451d3ab 100755
--- a/.ci/scripts/linux/docker.sh
+++ b/.ci/scripts/linux/docker.sh
@@ -30,10 +30,10 @@ make install DESTDIR=AppDir
30rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester 30rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
31 31
32# Download tools needed to build an AppImage 32# Download tools needed to build an AppImage
33wget -nc https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage 33wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-x86_64.AppImage
34wget -nc https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage 34wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-plugin-qt-x86_64.AppImage
35wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/AppRun-patched-x86_64 35wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/AppRun-patched-x86_64
36wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/exec-x86_64.so 36wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/exec-x86_64.so
37# Set executable bit 37# Set executable bit
38chmod 755 \ 38chmod 755 \
39 AppRun-patched-x86_64 \ 39 AppRun-patched-x86_64 \
diff --git a/.ci/scripts/linux/upload.sh b/.ci/scripts/linux/upload.sh
index b2ea07388..208cd0d04 100644
--- a/.ci/scripts/linux/upload.sh
+++ b/.ci/scripts/linux/upload.sh
@@ -21,7 +21,7 @@ cp build/bin/yuzu "$DIR_NAME"
21# Build an AppImage 21# Build an AppImage
22cd build 22cd build
23 23
24wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage 24wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/appimagetool-x86_64.AppImage
25chmod 755 appimagetool-x86_64.AppImage 25chmod 755 appimagetool-x86_64.AppImage
26 26
27if [ "${RELEASE_NAME}" = "mainline" ]; then 27if [ "${RELEASE_NAME}" = "mainline" ]; then
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c8e9ebf8a..3faa2b5ac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,8 @@ project(yuzu)
12# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON 12# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
13option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) 13option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
14CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF) 14CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
15# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
16CMAKE_DEPENDENT_OPTION(YUZU_ALLOW_SYSTEM_SDL2 "Try using system SDL2 before fallling back to one from externals" NOT UNIX "ENABLE_SDL2" OFF)
15 17
16option(ENABLE_QT "Enable the Qt frontend" ON) 18option(ENABLE_QT "Enable the Qt frontend" ON)
17option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) 19option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
@@ -292,20 +294,24 @@ if (ENABLE_SDL2)
292 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}") 294 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
293 target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}") 295 target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
294 else() 296 else()
295 find_package(SDL2 2.0.15 QUIET) 297 if (YUZU_ALLOW_SYSTEM_SDL2)
296 298 find_package(SDL2 2.0.15 QUIET)
297 if (SDL2_FOUND) 299
298 # Some installations don't set SDL2_LIBRARIES 300 if (SDL2_FOUND)
299 if("${SDL2_LIBRARIES}" STREQUAL "") 301 # Some installations don't set SDL2_LIBRARIES
300 message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2") 302 if("${SDL2_LIBRARIES}" STREQUAL "")
301 set(SDL2_LIBRARIES "SDL2::SDL2") 303 message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
304 set(SDL2_LIBRARIES "SDL2::SDL2")
305 endif()
306
307 include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
308 add_library(SDL2 INTERFACE)
309 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
310 else()
311 message(STATUS "SDL2 2.0.15 or newer not found, falling back to externals.")
302 endif() 312 endif()
303
304 include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
305 add_library(SDL2 INTERFACE)
306 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
307 else() 313 else()
308 message(STATUS "SDL2 2.0.15 or newer not found, falling back to externals.") 314 message(STATUS "Using SDL2 from externals.")
309 endif() 315 endif()
310 endif() 316 endif()
311endif() 317endif()
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index e280e53d7..fe1c088ca 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -47,8 +47,20 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
47 47
48# SDL2 48# SDL2
49if (NOT SDL2_FOUND AND ENABLE_SDL2) 49if (NOT SDL2_FOUND AND ENABLE_SDL2)
50 # Yuzu itself needs: Events Joystick Haptic Sensor Timers
51 # Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
52 set(SDL_UNUSED_SUBSYSTEMS
53 Atomic Audio Render Power Threads
54 File CPUinfo Filesystem Locale)
55 foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
56 string(TOUPPER ${_SUB} _OPT)
57 option(SDL_${_OPT} "" OFF)
58 endforeach()
59
50 set(SDL_STATIC ON) 60 set(SDL_STATIC ON)
51 set(SDL_SHARED OFF) 61 set(SDL_SHARED OFF)
62 option(HIDAPI "" ON)
63
52 add_subdirectory(SDL EXCLUDE_FROM_ALL) 64 add_subdirectory(SDL EXCLUDE_FROM_ALL)
53 add_library(SDL2 ALIAS SDL2-static) 65 add_library(SDL2 ALIAS SDL2-static)
54endif() 66endif()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8bd7e5f72..f30dd49a3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -54,6 +54,7 @@ if (MSVC)
54 /we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect 54 /we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
55 /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? 55 /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
56 /we4555 # Expression has no effect; expected expression with side-effect 56 /we4555 # Expression has no effect; expected expression with side-effect
57 /we4715 # 'function': not all control paths return a value
57 /we4834 # Discarding return value of function with 'nodiscard' attribute 58 /we4834 # Discarding return value of function with 'nodiscard' attribute
58 /we5038 # data member 'member1' will be initialized after data member 'member2' 59 /we5038 # data member 'member1' will be initialized after data member 'member2'
59 ) 60 )
diff --git a/src/common/parent_of_member.h b/src/common/parent_of_member.h
index e0f8ab5c8..58c70b0e7 100644
--- a/src/common/parent_of_member.h
+++ b/src/common/parent_of_member.h
@@ -109,7 +109,8 @@ struct OffsetOfCalculator {
109 } 109 }
110 } 110 }
111 111
112 return (next - start) * sizeof(MemberType) + Offset; 112 return static_cast<ptrdiff_t>(static_cast<size_t>(next - start) * sizeof(MemberType) +
113 Offset);
113 } 114 }
114 115
115 static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) { 116 static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 702b6598d..e29cbf506 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -42,7 +42,7 @@ void LogSettings() {
42 log_setting("System_RegionIndex", values.region_index.GetValue()); 42 log_setting("System_RegionIndex", values.region_index.GetValue());
43 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); 43 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
44 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); 44 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
45 log_setting("CPU_Accuracy", values.cpu_accuracy); 45 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
46 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); 46 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());
47 log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue()); 47 log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue());
48 log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); 48 log_setting("Renderer_FrameLimit", values.frame_limit.GetValue());
@@ -106,6 +106,12 @@ void RestoreGlobalState(bool is_powered_on) {
106 // Core 106 // Core
107 values.use_multi_core.SetGlobal(true); 107 values.use_multi_core.SetGlobal(true);
108 108
109 // CPU
110 values.cpu_accuracy.SetGlobal(true);
111 values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
112 values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
113 values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
114
109 // Renderer 115 // Renderer
110 values.renderer_backend.SetGlobal(true); 116 values.renderer_backend.SetGlobal(true);
111 values.vulkan_device.SetGlobal(true); 117 values.vulkan_device.SetGlobal(true);
@@ -130,7 +136,6 @@ void RestoreGlobalState(bool is_powered_on) {
130 values.region_index.SetGlobal(true); 136 values.region_index.SetGlobal(true);
131 values.time_zone_index.SetGlobal(true); 137 values.time_zone_index.SetGlobal(true);
132 values.rng_seed.SetGlobal(true); 138 values.rng_seed.SetGlobal(true);
133 values.custom_rtc.SetGlobal(true);
134 values.sound_index.SetGlobal(true); 139 values.sound_index.SetGlobal(true);
135 140
136 // Controls 141 // Controls
diff --git a/src/common/settings.h b/src/common/settings.h
index d39b4aa45..48085b9a9 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -115,7 +115,7 @@ struct Values {
115 Setting<bool> use_multi_core; 115 Setting<bool> use_multi_core;
116 116
117 // Cpu 117 // Cpu
118 CPUAccuracy cpu_accuracy; 118 Setting<CPUAccuracy> cpu_accuracy;
119 119
120 bool cpuopt_page_tables; 120 bool cpuopt_page_tables;
121 bool cpuopt_block_linking; 121 bool cpuopt_block_linking;
@@ -126,9 +126,9 @@ struct Values {
126 bool cpuopt_misc_ir; 126 bool cpuopt_misc_ir;
127 bool cpuopt_reduce_misalign_checks; 127 bool cpuopt_reduce_misalign_checks;
128 128
129 bool cpuopt_unsafe_unfuse_fma; 129 Setting<bool> cpuopt_unsafe_unfuse_fma;
130 bool cpuopt_unsafe_reduce_fp_error; 130 Setting<bool> cpuopt_unsafe_reduce_fp_error;
131 bool cpuopt_unsafe_inaccurate_nan; 131 Setting<bool> cpuopt_unsafe_inaccurate_nan;
132 132
133 // Renderer 133 // Renderer
134 Setting<RendererBackend> renderer_backend; 134 Setting<RendererBackend> renderer_backend;
@@ -157,7 +157,7 @@ struct Values {
157 // System 157 // System
158 Setting<std::optional<u32>> rng_seed; 158 Setting<std::optional<u32>> rng_seed;
159 // Measured in seconds since epoch 159 // Measured in seconds since epoch
160 Setting<std::optional<std::chrono::seconds>> custom_rtc; 160 std::optional<std::chrono::seconds> custom_rtc;
161 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` 161 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
162 std::chrono::seconds custom_rtc_differential; 162 std::chrono::seconds custom_rtc_differential;
163 163
diff --git a/src/common/tree.h b/src/common/tree.h
index 3da49e422..18faa4a48 100644
--- a/src/common/tree.h
+++ b/src/common/tree.h
@@ -43,6 +43,8 @@
43 * The maximum height of a red-black tree is 2lg (n+1). 43 * The maximum height of a red-black tree is 2lg (n+1).
44 */ 44 */
45 45
46#include "common/assert.h"
47
46namespace Common { 48namespace Common {
47template <typename T> 49template <typename T>
48class RBHead { 50class RBHead {
@@ -322,9 +324,13 @@ void RB_INSERT_COLOR(RBHead<Node>* head, Node* elm) {
322template <typename Node> 324template <typename Node>
323void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) { 325void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) {
324 Node* tmp; 326 Node* tmp;
325 while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root()) { 327 while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root() && parent != nullptr) {
326 if (RB_LEFT(parent) == elm) { 328 if (RB_LEFT(parent) == elm) {
327 tmp = RB_RIGHT(parent); 329 tmp = RB_RIGHT(parent);
330 if (!tmp) {
331 ASSERT_MSG(false, "tmp is invalid!");
332 break;
333 }
328 if (RB_IS_RED(tmp)) { 334 if (RB_IS_RED(tmp)) {
329 RB_SET_BLACKRED(tmp, parent); 335 RB_SET_BLACKRED(tmp, parent);
330 RB_ROTATE_LEFT(head, parent, tmp); 336 RB_ROTATE_LEFT(head, parent, tmp);
@@ -366,6 +372,11 @@ void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) {
366 tmp = RB_LEFT(parent); 372 tmp = RB_LEFT(parent);
367 } 373 }
368 374
375 if (!tmp) {
376 ASSERT_MSG(false, "tmp is invalid!");
377 break;
378 }
379
369 if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) && 380 if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) &&
370 (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) { 381 (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) {
371 RB_SET_COLOR(tmp, EntryColor::Red); 382 RB_SET_COLOR(tmp, EntryColor::Red);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 83da30418..efb851f5a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -651,20 +651,17 @@ endif()
651 651
652if (MSVC) 652if (MSVC)
653 target_compile_options(core PRIVATE 653 target_compile_options(core PRIVATE
654 # 'expression' : signed/unsigned mismatch 654 /we4018 # 'expression' : signed/unsigned mismatch
655 /we4018 655 /we4244 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
656 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point) 656 /we4245 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
657 /we4244 657 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
658 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch 658 /we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
659 /we4245 659 /we4305 # 'context' : truncation from 'type1' to 'type2'
660 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 660 /we4456 # Declaration of 'identifier' hides previous local declaration
661 /we4254 661 /we4457 # Declaration of 'identifier' hides function parameter
662 # 'var' : conversion from 'size_t' to 'type', possible loss of data 662 /we4458 # Declaration of 'identifier' hides class member
663 /we4267 663 /we4459 # Declaration of 'identifier' hides global declaration
664 # 'context' : truncation from 'type1' to 'type2' 664 /we4715 # 'function' : not all control paths return a value
665 /we4305
666 # 'function' : not all control paths return a value
667 /we4715
668 ) 665 )
669else() 666else()
670 target_compile_options(core PRIVATE 667 target_compile_options(core PRIVATE
@@ -672,6 +669,7 @@ else()
672 -Werror=ignored-qualifiers 669 -Werror=ignored-qualifiers
673 -Werror=implicit-fallthrough 670 -Werror=implicit-fallthrough
674 -Werror=sign-compare 671 -Werror=sign-compare
672 -Werror=shadow
675 673
676 $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> 674 $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
677 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> 675 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 42a37e84f..93d43e22e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -24,7 +24,7 @@ namespace Core {
24 24
25class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { 25class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
26public: 26public:
27 explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent) : parent(parent) {} 27 explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) : parent{parent_} {}
28 28
29 u8 MemoryRead8(u32 vaddr) override { 29 u8 MemoryRead8(u32 vaddr) override {
30 return parent.system.Memory().Read8(vaddr); 30 return parent.system.Memory().Read8(vaddr);
@@ -142,7 +142,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
142 config.far_code_offset = 256 * 1024 * 1024; 142 config.far_code_offset = 256 * 1024 * 1024;
143 143
144 // Safe optimizations 144 // Safe optimizations
145 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { 145 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
146 if (!Settings::values.cpuopt_page_tables) { 146 if (!Settings::values.cpuopt_page_tables) {
147 config.page_table = nullptr; 147 config.page_table = nullptr;
148 } 148 }
@@ -170,15 +170,15 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
170 } 170 }
171 171
172 // Unsafe optimizations 172 // Unsafe optimizations
173 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) { 173 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
174 config.unsafe_optimizations = true; 174 config.unsafe_optimizations = true;
175 if (Settings::values.cpuopt_unsafe_unfuse_fma) { 175 if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
176 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 176 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
177 } 177 }
178 if (Settings::values.cpuopt_unsafe_reduce_fp_error) { 178 if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
179 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; 179 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
180 } 180 }
181 if (Settings::values.cpuopt_unsafe_inaccurate_nan) { 181 if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
182 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 182 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
183 } 183 }
184 } 184 }
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 653bb7a77..08fa85904 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -27,7 +27,7 @@ using Vector = Dynarmic::A64::Vector;
27 27
28class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { 28class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
29public: 29public:
30 explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent) : parent(parent) {} 30 explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) : parent{parent_} {}
31 31
32 u8 MemoryRead8(u64 vaddr) override { 32 u8 MemoryRead8(u64 vaddr) override {
33 return parent.system.Memory().Read8(vaddr); 33 return parent.system.Memory().Read8(vaddr);
@@ -182,7 +182,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
182 config.far_code_offset = 256 * 1024 * 1024; 182 config.far_code_offset = 256 * 1024 * 1024;
183 183
184 // Safe optimizations 184 // Safe optimizations
185 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { 185 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
186 if (!Settings::values.cpuopt_page_tables) { 186 if (!Settings::values.cpuopt_page_tables) {
187 config.page_table = nullptr; 187 config.page_table = nullptr;
188 } 188 }
@@ -210,15 +210,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
210 } 210 }
211 211
212 // Unsafe optimizations 212 // Unsafe optimizations
213 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) { 213 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
214 config.unsafe_optimizations = true; 214 config.unsafe_optimizations = true;
215 if (Settings::values.cpuopt_unsafe_unfuse_fma) { 215 if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
216 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 216 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
217 } 217 }
218 if (Settings::values.cpuopt_unsafe_reduce_fp_error) { 218 if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
219 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; 219 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
220 } 220 }
221 if (Settings::values.cpuopt_unsafe_inaccurate_nan) { 221 if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
222 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 222 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
223 } 223 }
224 } 224 }
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index dc6f4af3a..8597beddf 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -18,7 +18,7 @@ class DynarmicCP15 final : public Dynarmic::A32::Coprocessor {
18public: 18public:
19 using CoprocReg = Dynarmic::A32::CoprocReg; 19 using CoprocReg = Dynarmic::A32::CoprocReg;
20 20
21 explicit DynarmicCP15(ARM_Dynarmic_32& parent) : parent(parent) {} 21 explicit DynarmicCP15(ARM_Dynarmic_32& parent_) : parent{parent_} {}
22 22
23 std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, 23 std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd,
24 CoprocReg CRn, CoprocReg CRm, 24 CoprocReg CRn, CoprocReg CRm,
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp b/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
index 4e209f6a5..9426a3edf 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
+++ b/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
@@ -9,8 +9,8 @@
9 9
10namespace Core { 10namespace Core {
11 11
12DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count) 12DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_)
13 : monitor(core_count), memory{memory} {} 13 : monitor{core_count_}, memory{memory_} {}
14 14
15DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; 15DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
16 16
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.h b/src/core/arm/dynarmic/arm_exclusive_monitor.h
index 964f4a55d..f9f056a59 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/arm_exclusive_monitor.h
@@ -22,7 +22,7 @@ namespace Core {
22 22
23class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 23class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
24public: 24public:
25 explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count); 25 explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_);
26 ~DynarmicExclusiveMonitor() override; 26 ~DynarmicExclusiveMonitor() override;
27 27
28 u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override; 28 u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 434bf3262..826a00ad6 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -173,7 +173,7 @@ struct System::Impl {
173 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 173 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
174 std::chrono::system_clock::now().time_since_epoch()); 174 std::chrono::system_clock::now().time_since_epoch());
175 Settings::values.custom_rtc_differential = 175 Settings::values.custom_rtc_differential =
176 Settings::values.custom_rtc.GetValue().value_or(current_time) - current_time; 176 Settings::values.custom_rtc.value_or(current_time) - current_time;
177 177
178 // Create a default fs if one doesn't already exist. 178 // Create a default fs if one doesn't already exist.
179 if (virtual_filesystem == nullptr) 179 if (virtual_filesystem == nullptr)
@@ -289,7 +289,8 @@ struct System::Impl {
289 289
290 telemetry_session->AddField(performance, "Shutdown_EmulationSpeed", 290 telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
291 perf_results.emulation_speed * 100.0); 291 perf_results.emulation_speed * 100.0);
292 telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps); 292 telemetry_session->AddField(performance, "Shutdown_Framerate",
293 perf_results.average_game_fps);
293 telemetry_session->AddField(performance, "Shutdown_Frametime", 294 telemetry_session->AddField(performance, "Shutdown_Frametime",
294 perf_results.frametime * 1000.0); 295 perf_results.frametime * 1000.0);
295 telemetry_session->AddField(performance, "Mean_Frametime_MS", 296 telemetry_session->AddField(performance, "Mean_Frametime_MS",
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index bdb374792..7e195346b 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -18,7 +18,7 @@
18 18
19namespace Core { 19namespace Core {
20 20
21CpuManager::CpuManager(System& system) : system{system} {} 21CpuManager::CpuManager(System& system_) : system{system_} {}
22CpuManager::~CpuManager() = default; 22CpuManager::~CpuManager() = default;
23 23
24void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) { 24void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) {
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index 9817017c0..140263b09 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -25,7 +25,7 @@ class System;
25 25
26class CpuManager { 26class CpuManager {
27public: 27public:
28 explicit CpuManager(System& system); 28 explicit CpuManager(System& system_);
29 CpuManager(const CpuManager&) = delete; 29 CpuManager(const CpuManager&) = delete;
30 CpuManager(CpuManager&&) = delete; 30 CpuManager(CpuManager&&) = delete;
31 31
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp
index 5c84bb0a4..1231da8e3 100644
--- a/src/core/crypto/ctr_encryption_layer.cpp
+++ b/src/core/crypto/ctr_encryption_layer.cpp
@@ -10,8 +10,8 @@
10namespace Core::Crypto { 10namespace Core::Crypto {
11 11
12CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, 12CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
13 std::size_t base_offset) 13 std::size_t base_offset_)
14 : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR) {} 14 : EncryptionLayer(std::move(base_)), base_offset(base_offset_), cipher(key_, Mode::CTR) {}
15 15
16std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const { 16std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
17 if (length == 0) 17 if (length == 0)
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h
index a2429f001..f86f01b6f 100644
--- a/src/core/crypto/ctr_encryption_layer.h
+++ b/src/core/crypto/ctr_encryption_layer.h
@@ -17,7 +17,7 @@ class CTREncryptionLayer : public EncryptionLayer {
17public: 17public:
18 using IVData = std::array<u8, 16>; 18 using IVData = std::array<u8, 16>;
19 19
20 CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset); 20 CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, std::size_t base_offset_);
21 21
22 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 22 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
23 23
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 070ed439e..a4b739c63 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -458,7 +458,7 @@ static std::array<u8, size> operator^(const std::array<u8, size>& lhs,
458 const std::array<u8, size>& rhs) { 458 const std::array<u8, size>& rhs) {
459 std::array<u8, size> out; 459 std::array<u8, size> out;
460 std::transform(lhs.begin(), lhs.end(), rhs.begin(), out.begin(), 460 std::transform(lhs.begin(), lhs.end(), rhs.begin(), out.begin(),
461 [](u8 lhs, u8 rhs) { return u8(lhs ^ rhs); }); 461 [](u8 lhs_elem, u8 rhs_elem) { return u8(lhs_elem ^ rhs_elem); });
462 return out; 462 return out;
463} 463}
464 464
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 3596541b2..f5cb4aa8c 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -39,10 +39,10 @@ CNMT::CNMT(VirtualFile file) {
39 } 39 }
40} 40}
41 41
42CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, 42CNMT::CNMT(CNMTHeader header_, OptionalHeader opt_header_,
43 std::vector<MetaRecord> meta_records) 43 std::vector<ContentRecord> content_records_, std::vector<MetaRecord> meta_records_)
44 : header(std::move(header)), opt_header(std::move(opt_header)), 44 : header(std::move(header_)), opt_header(std::move(opt_header_)),
45 content_records(std::move(content_records)), meta_records(std::move(meta_records)) {} 45 content_records(std::move(content_records_)), meta_records(std::move(meta_records_)) {}
46 46
47CNMT::~CNMT() = default; 47CNMT::~CNMT() = default;
48 48
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index 53535e5f5..ce1138a17 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -87,8 +87,8 @@ static_assert(sizeof(CNMTHeader) == 0x20, "CNMTHeader has incorrect size.");
87class CNMT { 87class CNMT {
88public: 88public:
89 explicit CNMT(VirtualFile file); 89 explicit CNMT(VirtualFile file);
90 CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, 90 CNMT(CNMTHeader header_, OptionalHeader opt_header_,
91 std::vector<MetaRecord> meta_records); 91 std::vector<ContentRecord> content_records_, std::vector<MetaRecord> meta_records_);
92 ~CNMT(); 92 ~CNMT();
93 93
94 u64 GetTitleID() const; 94 u64 GetTitleID() const;
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 1fb66874e..b0cb65952 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -12,6 +12,7 @@
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "core/crypto/key_manager.h" 13#include "core/crypto/key_manager.h"
14#include "core/file_sys/card_image.h" 14#include "core/file_sys/card_image.h"
15#include "core/file_sys/common_funcs.h"
15#include "core/file_sys/content_archive.h" 16#include "core/file_sys/content_archive.h"
16#include "core/file_sys/nca_metadata.h" 17#include "core/file_sys/nca_metadata.h"
17#include "core/file_sys/registered_cache.h" 18#include "core/file_sys/registered_cache.h"
@@ -592,6 +593,12 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
592 const CNMT cnmt(cnmt_file); 593 const CNMT cnmt(cnmt_file);
593 594
594 const auto title_id = cnmt.GetTitleID(); 595 const auto title_id = cnmt.GetTitleID();
596 const auto version = cnmt.GetTitleVersion();
597
598 if (title_id == GetBaseTitleID(title_id) && version == 0) {
599 return InstallResult::ErrorBaseInstall;
600 }
601
595 const auto result = RemoveExistingEntry(title_id); 602 const auto result = RemoveExistingEntry(title_id);
596 603
597 // Install Metadata File 604 // Install Metadata File
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index b31630014..d042aef90 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -38,6 +38,7 @@ enum class InstallResult {
38 ErrorAlreadyExists, 38 ErrorAlreadyExists,
39 ErrorCopyFailed, 39 ErrorCopyFailed,
40 ErrorMetaFailed, 40 ErrorMetaFailed,
41 ErrorBaseInstall,
41}; 42};
42 43
43struct ContentProviderEntry { 44struct ContentProviderEntry {
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 80e560970..d51d469e3 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -20,8 +20,8 @@
20 20
21namespace FileSys { 21namespace FileSys {
22 22
23NSP::NSP(VirtualFile file_, std::size_t program_index) 23NSP::NSP(VirtualFile file_, std::size_t program_index_)
24 : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success}, 24 : file(std::move(file_)), program_index(program_index_), status{Loader::ResultStatus::Success},
25 pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { 25 pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
26 if (pfs->GetStatus() != Loader::ResultStatus::Success) { 26 if (pfs->GetStatus() != Loader::ResultStatus::Success) {
27 status = pfs->GetStatus(); 27 status = pfs->GetStatus();
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 54581a6f3..ecb3b6f15 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -27,7 +27,7 @@ enum class ContentRecordType : u8;
27 27
28class NSP : public ReadOnlyVfsDirectory { 28class NSP : public ReadOnlyVfsDirectory {
29public: 29public:
30 explicit NSP(VirtualFile file, std::size_t program_index = 0); 30 explicit NSP(VirtualFile file_, std::size_t program_index_ = 0);
31 ~NSP() override; 31 ~NSP() override;
32 32
33 Loader::ResultStatus GetStatus() const; 33 Loader::ResultStatus GetStatus() const;
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index 619081502..5f8c09124 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -23,8 +23,8 @@ static bool VerifyConcatenationMapContinuity(const std::multimap<u64, VirtualFil
23 return map.begin()->first == 0; 23 return map.begin()->first == 0;
24} 24}
25 25
26ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) 26ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name_)
27 : name(std::move(name)) { 27 : name(std::move(name_)) {
28 std::size_t next_offset = 0; 28 std::size_t next_offset = 0;
29 for (const auto& file : files_) { 29 for (const auto& file : files_) {
30 files.emplace(next_offset, file); 30 files.emplace(next_offset, file);
@@ -32,8 +32,8 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s
32 } 32 }
33} 33}
34 34
35ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name) 35ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name_)
36 : files(std::move(files_)), name(std::move(name)) { 36 : files(std::move(files_)), name(std::move(name_)) {
37 ASSERT(VerifyConcatenationMapContinuity(files)); 37 ASSERT(VerifyConcatenationMapContinuity(files));
38} 38}
39 39
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 3397d32cd..cd32960a5 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -14,8 +14,8 @@ namespace FileSys {
14// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently 14// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
15// read-only. 15// read-only.
16class ConcatenatedVfsFile : public VfsFile { 16class ConcatenatedVfsFile : public VfsFile {
17 ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); 17 explicit ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name_);
18 ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name); 18 explicit ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name_);
19 19
20public: 20public:
21 ~ConcatenatedVfsFile() override; 21 ~ConcatenatedVfsFile() override;
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index 192740058..e093c4db2 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -8,8 +8,8 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name) 11LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs_, std::string name_)
12 : dirs(std::move(dirs)), name(std::move(name)) {} 12 : dirs(std::move(dirs_)), name(std::move(name_)) {}
13 13
14LayeredVfsDirectory::~LayeredVfsDirectory() = default; 14LayeredVfsDirectory::~LayeredVfsDirectory() = default;
15 15
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h
index cb4b32e91..cd6baf28c 100644
--- a/src/core/file_sys/vfs_layered.h
+++ b/src/core/file_sys/vfs_layered.h
@@ -13,7 +13,7 @@ namespace FileSys {
13// one and falling back to the one after. The highest priority directory (overwrites all others) 13// one and falling back to the one after. The highest priority directory (overwrites all others)
14// should be element 0 in the dirs vector. 14// should be element 0 in the dirs vector.
15class LayeredVfsDirectory : public VfsDirectory { 15class LayeredVfsDirectory : public VfsDirectory {
16 LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); 16 explicit LayeredVfsDirectory(std::vector<VirtualDir> dirs_, std::string name_);
17 17
18public: 18public:
19 ~LayeredVfsDirectory() override; 19 ~LayeredVfsDirectory() override;
diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp
index 429d7bc8b..618eb658a 100644
--- a/src/core/file_sys/vfs_libzip.cpp
+++ b/src/core/file_sys/vfs_libzip.cpp
@@ -3,7 +3,16 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string> 5#include <string>
6
7#ifdef __GNUC__
8#pragma GCC diagnostic push
9#pragma GCC diagnostic ignored "-Wshadow"
10#endif
6#include <zip.h> 11#include <zip.h>
12#ifdef __GNUC__
13#pragma GCC diagnostic pop
14#endif
15
7#include "common/logging/backend.h" 16#include "common/logging/backend.h"
8#include "core/file_sys/vfs.h" 17#include "core/file_sys/vfs.h"
9#include "core/file_sys/vfs_libzip.h" 18#include "core/file_sys/vfs_libzip.h"
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index c840b24b9..f5b66cf71 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -14,9 +14,9 @@ namespace FileSys {
14 14
15class StaticVfsFile : public VfsFile { 15class StaticVfsFile : public VfsFile {
16public: 16public:
17 explicit StaticVfsFile(u8 value, std::size_t size = 0, std::string name = "", 17 explicit StaticVfsFile(u8 value_, std::size_t size_ = 0, std::string name_ = "",
18 VirtualDir parent = nullptr) 18 VirtualDir parent_ = nullptr)
19 : value{value}, size{size}, name{std::move(name)}, parent{std::move(parent)} {} 19 : value{value_}, size{size_}, name{std::move(name_)}, parent{std::move(parent_)} {}
20 20
21 std::string GetName() const override { 21 std::string GetName() const override {
22 return name; 22 return name;
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 1a3f06227..f64b88639 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -7,8 +7,8 @@
7#include "core/file_sys/vfs_vector.h" 7#include "core/file_sys/vfs_vector.h"
8 8
9namespace FileSys { 9namespace FileSys {
10VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) 10VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name_, VirtualDir parent_)
11 : data(std::move(initial_data)), parent(std::move(parent)), name(std::move(name)) {} 11 : data(std::move(initial_data)), parent(std::move(parent_)), name(std::move(name_)) {}
12 12
13VectorVfsFile::~VectorVfsFile() = default; 13VectorVfsFile::~VectorVfsFile() = default;
14 14
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index c10c527b6..73f180070 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -75,8 +75,8 @@ std::shared_ptr<ArrayVfsFile<Size>> MakeArrayFile(const std::array<u8, Size>& da
75// An implementation of VfsFile that is backed by a vector optionally supplied upon construction 75// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
76class VectorVfsFile : public VfsFile { 76class VectorVfsFile : public VfsFile {
77public: 77public:
78 explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name = "", 78 explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name_ = "",
79 VirtualDir parent = nullptr); 79 VirtualDir parent_ = nullptr);
80 ~VectorVfsFile() override; 80 ~VectorVfsFile() override;
81 81
82 std::string GetName() const override; 82 std::string GetName() const override;
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index cff49899a..e11ec0b0b 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -26,7 +26,7 @@ public:
26private: 26private:
27 class Device : public Input::TouchDevice { 27 class Device : public Input::TouchDevice {
28 public: 28 public:
29 explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} 29 explicit Device(std::weak_ptr<TouchState>&& touch_state_) : touch_state(touch_state_) {}
30 Input::TouchStatus GetStatus() const override { 30 Input::TouchStatus GetStatus() const override {
31 if (auto state = touch_state.lock()) { 31 if (auto state = touch_state.lock()) {
32 std::lock_guard guard{state->mutex}; 32 std::lock_guard guard{state->mutex};
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index 55b1716e4..602e12606 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -32,7 +32,8 @@ enum class CommandType : u32 {
32 Control = 5, 32 Control = 5,
33 RequestWithContext = 6, 33 RequestWithContext = 6,
34 ControlWithContext = 7, 34 ControlWithContext = 7,
35 Unspecified, 35 TIPC_Close = 15,
36 TIPC_CommandRegion = 16, // Start of TIPC commands, this is an offset.
36}; 37};
37 38
38struct CommandHeader { 39struct CommandHeader {
@@ -57,6 +58,20 @@ struct CommandHeader {
57 BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags; 58 BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags;
58 BitField<31, 1, u32> enable_handle_descriptor; 59 BitField<31, 1, u32> enable_handle_descriptor;
59 }; 60 };
61
62 bool IsTipc() const {
63 return type.Value() >= CommandType::TIPC_CommandRegion;
64 }
65
66 bool IsCloseCommand() const {
67 switch (type.Value()) {
68 case CommandType::Close:
69 case CommandType::TIPC_Close:
70 return true;
71 default:
72 return false;
73 }
74 }
60}; 75};
61static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect"); 76static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect");
62 77
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index d136be452..61bda3786 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -15,6 +15,8 @@
15#include "core/hle/ipc.h" 15#include "core/hle/ipc.h"
16#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/kernel/k_client_port.h" 17#include "core/hle/kernel/k_client_port.h"
18#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/k_resource_limit.h"
18#include "core/hle/kernel/k_session.h" 20#include "core/hle/kernel/k_session.h"
19#include "core/hle/result.h" 21#include "core/hle/result.h"
20 22
@@ -26,19 +28,19 @@ class RequestHelperBase {
26protected: 28protected:
27 Kernel::HLERequestContext* context = nullptr; 29 Kernel::HLERequestContext* context = nullptr;
28 u32* cmdbuf; 30 u32* cmdbuf;
29 ptrdiff_t index = 0; 31 u32 index = 0;
30 32
31public: 33public:
32 explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {} 34 explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {}
33 35
34 explicit RequestHelperBase(Kernel::HLERequestContext& context) 36 explicit RequestHelperBase(Kernel::HLERequestContext& ctx)
35 : context(&context), cmdbuf(context.CommandBuffer()) {} 37 : context(&ctx), cmdbuf(ctx.CommandBuffer()) {}
36 38
37 void Skip(u32 size_in_words, bool set_to_null) { 39 void Skip(u32 size_in_words, bool set_to_null) {
38 if (set_to_null) { 40 if (set_to_null) {
39 memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); 41 memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
40 } 42 }
41 index += static_cast<ptrdiff_t>(size_in_words); 43 index += size_in_words;
42 } 44 }
43 45
44 /** 46 /**
@@ -51,11 +53,11 @@ public:
51 } 53 }
52 54
53 u32 GetCurrentOffset() const { 55 u32 GetCurrentOffset() const {
54 return static_cast<u32>(index); 56 return index;
55 } 57 }
56 58
57 void SetCurrentOffset(u32 offset) { 59 void SetCurrentOffset(u32 offset) {
58 index = static_cast<ptrdiff_t>(offset); 60 index = offset;
59 } 61 }
60}; 62};
61 63
@@ -69,23 +71,21 @@ public:
69 AlwaysMoveHandles = 1, 71 AlwaysMoveHandles = 1,
70 }; 72 };
71 73
72 explicit ResponseBuilder(Kernel::HLERequestContext& ctx, u32 normal_params_size, 74 explicit ResponseBuilder(Kernel::HLERequestContext& ctx, u32 normal_params_size_,
73 u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, 75 u32 num_handles_to_copy_ = 0, u32 num_objects_to_move_ = 0,
74 Flags flags = Flags::None) 76 Flags flags = Flags::None)
75 : RequestHelperBase(ctx), normal_params_size(normal_params_size), 77 : RequestHelperBase(ctx), normal_params_size(normal_params_size_),
76 num_handles_to_copy(num_handles_to_copy), 78 num_handles_to_copy(num_handles_to_copy_),
77 num_objects_to_move(num_objects_to_move), kernel{ctx.kernel} { 79 num_objects_to_move(num_objects_to_move_), kernel{ctx.kernel} {
78 80
79 memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); 81 memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
80 82
81 ctx.ClearIncomingObjects();
82
83 IPC::CommandHeader header{}; 83 IPC::CommandHeader header{};
84 84
85 // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory 85 // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
86 // padding. 86 // padding.
87 u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; 87 u32 raw_data_size = ctx.write_size =
88 88 ctx.IsTipc() ? normal_params_size - 1 : normal_params_size;
89 u32 num_handles_to_move{}; 89 u32 num_handles_to_move{};
90 u32 num_domain_objects{}; 90 u32 num_domain_objects{};
91 const bool always_move_handles{ 91 const bool always_move_handles{
@@ -97,10 +97,19 @@ public:
97 } 97 }
98 98
99 if (ctx.Session()->IsDomain()) { 99 if (ctx.Session()->IsDomain()) {
100 raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; 100 raw_data_size +=
101 static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
102 ctx.write_size += num_domain_objects;
101 } 103 }
102 104
103 header.data_size.Assign(static_cast<u32>(raw_data_size)); 105 if (ctx.IsTipc()) {
106 header.type.Assign(ctx.GetCommandType());
107 } else {
108 raw_data_size += static_cast<u32>(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 +
109 normal_params_size);
110 }
111
112 header.data_size.Assign(raw_data_size);
104 if (num_handles_to_copy || num_handles_to_move) { 113 if (num_handles_to_copy || num_handles_to_move) {
105 header.enable_handle_descriptor.Assign(1); 114 header.enable_handle_descriptor.Assign(1);
106 } 115 }
@@ -108,25 +117,34 @@ public:
108 117
109 if (header.enable_handle_descriptor) { 118 if (header.enable_handle_descriptor) {
110 IPC::HandleDescriptorHeader handle_descriptor_header{}; 119 IPC::HandleDescriptorHeader handle_descriptor_header{};
111 handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy); 120 handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy_);
112 handle_descriptor_header.num_handles_to_move.Assign(num_handles_to_move); 121 handle_descriptor_header.num_handles_to_move.Assign(num_handles_to_move);
113 PushRaw(handle_descriptor_header); 122 PushRaw(handle_descriptor_header);
123
124 ctx.handles_offset = index;
125
114 Skip(num_handles_to_copy + num_handles_to_move, true); 126 Skip(num_handles_to_copy + num_handles_to_move, true);
115 } 127 }
116 128
117 AlignWithPadding(); 129 if (!ctx.IsTipc()) {
130 AlignWithPadding();
118 131
119 if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) { 132 if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) {
120 IPC::DomainMessageHeader domain_header{}; 133 IPC::DomainMessageHeader domain_header{};
121 domain_header.num_objects = num_domain_objects; 134 domain_header.num_objects = num_domain_objects;
122 PushRaw(domain_header); 135 PushRaw(domain_header);
136 }
137
138 IPC::DataPayloadHeader data_payload_header{};
139 data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
140 PushRaw(data_payload_header);
123 } 141 }
124 142
125 IPC::DataPayloadHeader data_payload_header{}; 143 data_payload_index = index;
126 data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
127 PushRaw(data_payload_header);
128 144
129 datapayload_index = index; 145 ctx.data_payload_offset = index;
146 ctx.write_size += index;
147 ctx.domain_offset = static_cast<u32>(index + raw_data_size / sizeof(u32));
130 } 148 }
131 149
132 template <class T> 150 template <class T>
@@ -134,6 +152,9 @@ public:
134 if (context->Session()->IsDomain()) { 152 if (context->Session()->IsDomain()) {
135 context->AddDomainObject(std::move(iface)); 153 context->AddDomainObject(std::move(iface));
136 } else { 154 } else {
155 kernel.CurrentProcess()->GetResourceLimit()->Reserve(
156 Kernel::LimitableResource::Sessions, 1);
157
137 auto* session = Kernel::KSession::Create(kernel); 158 auto* session = Kernel::KSession::Create(kernel);
138 session->Initialize(nullptr, iface->GetServiceName()); 159 session->Initialize(nullptr, iface->GetServiceName());
139 160
@@ -147,24 +168,6 @@ public:
147 PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...)); 168 PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...));
148 } 169 }
149 170
150 void ValidateHeader() {
151 const std::size_t num_domain_objects = context->NumDomainObjects();
152 const std::size_t num_move_objects = context->NumMoveObjects();
153 ASSERT_MSG(!num_domain_objects || !num_move_objects,
154 "cannot move normal handles and domain objects");
155 ASSERT_MSG((index - datapayload_index) == normal_params_size,
156 "normal_params_size value is incorrect");
157 ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move,
158 "num_objects_to_move value is incorrect");
159 ASSERT_MSG(context->NumCopyObjects() == num_handles_to_copy,
160 "num_handles_to_copy value is incorrect");
161 }
162
163 // Validate on destruction, as there shouldn't be any case where we don't want it
164 ~ResponseBuilder() {
165 ValidateHeader();
166 }
167
168 void PushImpl(s8 value); 171 void PushImpl(s8 value);
169 void PushImpl(s16 value); 172 void PushImpl(s16 value);
170 void PushImpl(s32 value); 173 void PushImpl(s32 value);
@@ -229,14 +232,14 @@ private:
229 u32 normal_params_size{}; 232 u32 normal_params_size{};
230 u32 num_handles_to_copy{}; 233 u32 num_handles_to_copy{};
231 u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent 234 u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
232 std::ptrdiff_t datapayload_index{}; 235 u32 data_payload_index{};
233 Kernel::KernelCore& kernel; 236 Kernel::KernelCore& kernel;
234}; 237};
235 238
236/// Push /// 239/// Push ///
237 240
238inline void ResponseBuilder::PushImpl(s32 value) { 241inline void ResponseBuilder::PushImpl(s32 value) {
239 cmdbuf[index++] = static_cast<u32>(value); 242 cmdbuf[index++] = value;
240} 243}
241 244
242inline void ResponseBuilder::PushImpl(u32 value) { 245inline void ResponseBuilder::PushImpl(u32 value) {
@@ -384,7 +387,7 @@ public:
384 std::shared_ptr<T> PopIpcInterface() { 387 std::shared_ptr<T> PopIpcInterface() {
385 ASSERT(context->Session()->IsDomain()); 388 ASSERT(context->Session()->IsDomain());
386 ASSERT(context->GetDomainMessageHeader().input_object_count > 0); 389 ASSERT(context->GetDomainMessageHeader().input_object_count > 0);
387 return context->GetDomainRequestHandler<T>(Pop<u32>() - 1); 390 return context->GetDomainHandler<T>(Pop<u32>() - 1);
388 } 391 }
389}; 392};
390 393
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
index 7c87cbada..4f4e338e3 100644
--- a/src/core/hle/kernel/global_scheduler_context.cpp
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -12,8 +12,8 @@
12 12
13namespace Kernel { 13namespace Kernel {
14 14
15GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel) 15GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel_)
16 : kernel{kernel}, scheduler_lock{kernel} {} 16 : kernel{kernel_}, scheduler_lock{kernel_} {}
17 17
18GlobalSchedulerContext::~GlobalSchedulerContext() = default; 18GlobalSchedulerContext::~GlobalSchedulerContext() = default;
19 19
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
index ba8b67fd1..6f44b534f 100644
--- a/src/core/hle/kernel/global_scheduler_context.h
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -34,7 +34,7 @@ class GlobalSchedulerContext final {
34public: 34public:
35 using LockType = KAbstractSchedulerLock<KScheduler>; 35 using LockType = KAbstractSchedulerLock<KScheduler>;
36 36
37 explicit GlobalSchedulerContext(KernelCore& kernel); 37 explicit GlobalSchedulerContext(KernelCore& kernel_);
38 ~GlobalSchedulerContext(); 38 ~GlobalSchedulerContext();
39 39
40 /// Adds a new thread to the scheduler 40 /// Adds a new thread to the scheduler
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 93907f75e..9d069a78f 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -35,11 +35,11 @@ SessionRequestHandler::SessionRequestHandler() = default;
35SessionRequestHandler::~SessionRequestHandler() = default; 35SessionRequestHandler::~SessionRequestHandler() = default;
36 36
37void SessionRequestHandler::ClientConnected(KServerSession* session) { 37void SessionRequestHandler::ClientConnected(KServerSession* session) {
38 session->SetHleHandler(shared_from_this()); 38 session->SetSessionHandler(shared_from_this());
39} 39}
40 40
41void SessionRequestHandler::ClientDisconnected(KServerSession* session) { 41void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
42 session->SetHleHandler(nullptr); 42 session->SetSessionHandler(nullptr);
43} 43}
44 44
45HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, 45HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
@@ -55,7 +55,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
55 IPC::RequestParser rp(src_cmdbuf); 55 IPC::RequestParser rp(src_cmdbuf);
56 command_header = rp.PopRaw<IPC::CommandHeader>(); 56 command_header = rp.PopRaw<IPC::CommandHeader>();
57 57
58 if (command_header->type == IPC::CommandType::Close) { 58 if (command_header->IsCloseCommand()) {
59 // Close does not populate the rest of the IPC header 59 // Close does not populate the rest of the IPC header
60 return; 60 return;
61 } 61 }
@@ -64,19 +64,15 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
64 if (command_header->enable_handle_descriptor) { 64 if (command_header->enable_handle_descriptor) {
65 handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); 65 handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
66 if (handle_descriptor_header->send_current_pid) { 66 if (handle_descriptor_header->send_current_pid) {
67 rp.Skip(2, false); 67 pid = rp.Pop<u64>();
68 } 68 }
69 if (incoming) { 69 if (incoming) {
70 // Populate the object lists with the data in the IPC request. 70 // Populate the object lists with the data in the IPC request.
71 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { 71 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
72 const u32 copy_handle{rp.Pop<Handle>()}; 72 incoming_copy_handles.push_back(rp.Pop<Handle>());
73 copy_handles.push_back(copy_handle);
74 copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe());
75 } 73 }
76 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { 74 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
77 const u32 move_handle{rp.Pop<Handle>()}; 75 incoming_move_handles.push_back(rp.Pop<Handle>());
78 move_handles.push_back(move_handle);
79 move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe());
80 } 76 }
81 } else { 77 } else {
82 // For responses we just ignore the handles, they're empty and will be populated when 78 // For responses we just ignore the handles, they're empty and will be populated when
@@ -86,52 +82,56 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
86 } 82 }
87 } 83 }
88 84
89 for (unsigned i = 0; i < command_header->num_buf_x_descriptors; ++i) { 85 for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
90 buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); 86 buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
91 } 87 }
92 for (unsigned i = 0; i < command_header->num_buf_a_descriptors; ++i) { 88 for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) {
93 buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 89 buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
94 } 90 }
95 for (unsigned i = 0; i < command_header->num_buf_b_descriptors; ++i) { 91 for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) {
96 buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 92 buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
97 } 93 }
98 for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) { 94 for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) {
99 buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 95 buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
100 } 96 }
101 97
102 buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; 98 const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
103 99
104 // Padding to align to 16 bytes 100 if (!command_header->IsTipc()) {
105 rp.AlignWithPadding(); 101 // Padding to align to 16 bytes
106 102 rp.AlignWithPadding();
107 if (Session()->IsDomain() && ((command_header->type == IPC::CommandType::Request || 103
108 command_header->type == IPC::CommandType::RequestWithContext) || 104 if (Session()->IsDomain() &&
109 !incoming)) { 105 ((command_header->type == IPC::CommandType::Request ||
110 // If this is an incoming message, only CommandType "Request" has a domain header 106 command_header->type == IPC::CommandType::RequestWithContext) ||
111 // All outgoing domain messages have the domain header, if only incoming has it 107 !incoming)) {
112 if (incoming || domain_message_header) { 108 // If this is an incoming message, only CommandType "Request" has a domain header
113 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); 109 // All outgoing domain messages have the domain header, if only incoming has it
114 } else { 110 if (incoming || domain_message_header) {
115 if (Session()->IsDomain()) { 111 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
116 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); 112 } else {
113 if (Session()->IsDomain()) {
114 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
115 }
117 } 116 }
118 } 117 }
119 }
120 118
121 data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>(); 119 data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>();
122 120
123 data_payload_offset = rp.GetCurrentOffset(); 121 data_payload_offset = rp.GetCurrentOffset();
124 122
125 if (domain_message_header && domain_message_header->command == 123 if (domain_message_header &&
126 IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) { 124 domain_message_header->command ==
127 // CloseVirtualHandle command does not have SFC* or any data 125 IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) {
128 return; 126 // CloseVirtualHandle command does not have SFC* or any data
129 } 127 return;
128 }
130 129
131 if (incoming) { 130 if (incoming) {
132 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I')); 131 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I'));
133 } else { 132 } else {
134 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); 133 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
134 }
135 } 135 }
136 136
137 rp.SetCurrentOffset(buffer_c_offset); 137 rp.SetCurrentOffset(buffer_c_offset);
@@ -144,14 +144,14 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
144 IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { 144 IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
145 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); 145 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
146 } else { 146 } else {
147 unsigned num_buf_c_descriptors = 147 u32 num_buf_c_descriptors =
148 static_cast<unsigned>(command_header->buf_c_descriptor_flags.Value()) - 2; 148 static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2;
149 149
150 // This is used to detect possible underflows, in case something is broken 150 // This is used to detect possible underflows, in case something is broken
151 // with the two ifs above and the flags value is == 0 || == 1. 151 // with the two ifs above and the flags value is == 0 || == 1.
152 ASSERT(num_buf_c_descriptors < 14); 152 ASSERT(num_buf_c_descriptors < 14);
153 153
154 for (unsigned i = 0; i < num_buf_c_descriptors; ++i) { 154 for (u32 i = 0; i < num_buf_c_descriptors; ++i) {
155 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); 155 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
156 } 156 }
157 } 157 }
@@ -166,84 +166,55 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
166ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, 166ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
167 u32_le* src_cmdbuf) { 167 u32_le* src_cmdbuf) {
168 ParseCommandBuffer(handle_table, src_cmdbuf, true); 168 ParseCommandBuffer(handle_table, src_cmdbuf, true);
169 if (command_header->type == IPC::CommandType::Close) { 169
170 if (command_header->IsCloseCommand()) {
170 // Close does not populate the rest of the IPC header 171 // Close does not populate the rest of the IPC header
171 return RESULT_SUCCESS; 172 return RESULT_SUCCESS;
172 } 173 }
173 174
174 // The data_size already includes the payload header, the padding and the domain header. 175 std::copy_n(src_cmdbuf, IPC::COMMAND_BUFFER_LENGTH, cmd_buf.begin());
175 std::size_t size = data_payload_offset + command_header->data_size - 176
176 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
177 if (domain_message_header)
178 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
179 std::copy_n(src_cmdbuf, size, cmd_buf.begin());
180 return RESULT_SUCCESS; 177 return RESULT_SUCCESS;
181} 178}
182 179
183ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) { 180ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) {
181 auto current_offset = handles_offset;
184 auto& owner_process = *requesting_thread.GetOwnerProcess(); 182 auto& owner_process = *requesting_thread.GetOwnerProcess();
185 auto& handle_table = owner_process.GetHandleTable(); 183 auto& handle_table = owner_process.GetHandleTable();
186 184
187 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; 185 for (auto& object : outgoing_copy_objects) {
188 memory.ReadBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(), 186 Handle handle{};
189 dst_cmdbuf.size() * sizeof(u32)); 187 if (object) {
190 188 R_TRY(handle_table.Add(&handle, object));
191 // The header was already built in the internal command buffer. Attempt to parse it to verify
192 // the integrity and then copy it over to the target command buffer.
193 ParseCommandBuffer(handle_table, cmd_buf.data(), false);
194
195 // The data_size already includes the payload header, the padding and the domain header.
196 std::size_t size = data_payload_offset + command_header->data_size -
197 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
198 if (domain_message_header)
199 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
200
201 std::copy_n(cmd_buf.begin(), size, dst_cmdbuf.data());
202
203 if (command_header->enable_handle_descriptor) {
204 ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(),
205 "Handle descriptor bit set but no handles to translate");
206 // We write the translated handles at a specific offset in the command buffer, this space
207 // was already reserved when writing the header.
208 std::size_t current_offset =
209 (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32);
210 ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented");
211
212 ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
213 ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
214
215 // We don't make a distinction between copy and move handles when translating since HLE
216 // services don't deal with handles directly. However, the guest applications might check
217 // for specific values in each of these descriptors.
218 for (auto& object : copy_objects) {
219 ASSERT(object != nullptr);
220 R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object));
221 } 189 }
190 cmd_buf[current_offset++] = handle;
191 }
192 for (auto& object : outgoing_move_objects) {
193 Handle handle{};
194 if (object) {
195 R_TRY(handle_table.Add(&handle, object));
222 196
223 for (auto& object : move_objects) { 197 // Close our reference to the object, as it is being moved to the caller.
224 ASSERT(object != nullptr); 198 object->Close();
225 R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object));
226 } 199 }
200 cmd_buf[current_offset++] = handle;
227 } 201 }
228 202
229 // TODO(Subv): Translate the X/A/B/W buffers. 203 // Write the domain objects to the command buffer, these go after the raw untranslated data.
230 204 // TODO(Subv): This completely ignores C buffers.
231 if (Session()->IsDomain() && domain_message_header) {
232 ASSERT(domain_message_header->num_objects == domain_objects.size());
233 // Write the domain objects to the command buffer, these go after the raw untranslated data.
234 // TODO(Subv): This completely ignores C buffers.
235 std::size_t domain_offset = size - domain_message_header->num_objects;
236 205
237 for (const auto& object : domain_objects) { 206 if (Session()->IsDomain()) {
238 server_session->AppendDomainRequestHandler(object); 207 current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size());
239 dst_cmdbuf[domain_offset++] = 208 for (const auto& object : outgoing_domain_objects) {
209 server_session->AppendDomainHandler(object);
210 cmd_buf[current_offset++] =
240 static_cast<u32_le>(server_session->NumDomainRequestHandlers()); 211 static_cast<u32_le>(server_session->NumDomainRequestHandlers());
241 } 212 }
242 } 213 }
243 214
244 // Copy the translated command buffer back into the thread's command buffer area. 215 // Copy the translated command buffer back into the thread's command buffer area.
245 memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(), 216 memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(),
246 dst_cmdbuf.size() * sizeof(u32)); 217 write_size * sizeof(u32));
247 218
248 return RESULT_SUCCESS; 219 return RESULT_SUCCESS;
249} 220}
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 21e384706..b47e363cc 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -11,7 +11,8 @@
11#include <string> 11#include <string>
12#include <type_traits> 12#include <type_traits>
13#include <vector> 13#include <vector>
14#include <boost/container/small_vector.hpp> 14
15#include "common/assert.h"
15#include "common/common_types.h" 16#include "common/common_types.h"
16#include "common/concepts.h" 17#include "common/concepts.h"
17#include "common/swap.h" 18#include "common/swap.h"
@@ -66,7 +67,8 @@ public:
66 * this request (ServerSession, Originator thread, Translated command buffer, etc). 67 * this request (ServerSession, Originator thread, Translated command buffer, etc).
67 * @returns ResultCode the result code of the translate operation. 68 * @returns ResultCode the result code of the translate operation.
68 */ 69 */
69 virtual ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) = 0; 70 virtual ResultCode HandleSyncRequest(Kernel::KServerSession& session,
71 Kernel::HLERequestContext& context) = 0;
70 72
71 /** 73 /**
72 * Signals that a client has just connected to this HLE handler and keeps the 74 * Signals that a client has just connected to this HLE handler and keeps the
@@ -83,6 +85,69 @@ public:
83 void ClientDisconnected(KServerSession* session); 85 void ClientDisconnected(KServerSession* session);
84}; 86};
85 87
88using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
89
90/**
91 * Manages the underlying HLE requests for a session, and whether (or not) the session should be
92 * treated as a domain. This is managed separately from server sessions, as this state is shared
93 * when objects are cloned.
94 */
95class SessionRequestManager final {
96public:
97 SessionRequestManager() = default;
98
99 bool IsDomain() const {
100 return is_domain;
101 }
102
103 void ConvertToDomain() {
104 domain_handlers = {session_handler};
105 is_domain = true;
106 }
107
108 std::size_t DomainHandlerCount() const {
109 return domain_handlers.size();
110 }
111
112 bool HasSessionHandler() const {
113 return session_handler != nullptr;
114 }
115
116 SessionRequestHandler& SessionHandler() {
117 return *session_handler;
118 }
119
120 const SessionRequestHandler& SessionHandler() const {
121 return *session_handler;
122 }
123
124 void CloseDomainHandler(std::size_t index) {
125 if (index < DomainHandlerCount()) {
126 domain_handlers[index] = nullptr;
127 } else {
128 UNREACHABLE_MSG("Unexpected handler index {}", index);
129 }
130 }
131
132 SessionRequestHandlerPtr DomainHandler(std::size_t index) const {
133 ASSERT_MSG(index < DomainHandlerCount(), "Unexpected handler index {}", index);
134 return domain_handlers.at(index);
135 }
136
137 void AppendDomainHandler(SessionRequestHandlerPtr&& handler) {
138 domain_handlers.emplace_back(std::move(handler));
139 }
140
141 void SetSessionHandler(SessionRequestHandlerPtr&& handler) {
142 session_handler = std::move(handler);
143 }
144
145private:
146 bool is_domain{};
147 SessionRequestHandlerPtr session_handler;
148 std::vector<SessionRequestHandlerPtr> domain_handlers;
149};
150
86/** 151/**
87 * Class containing information about an in-flight IPC request being handled by an HLE service 152 * Class containing information about an in-flight IPC request being handled by an HLE service
88 * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and 153 * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and
@@ -128,15 +193,32 @@ public:
128 /// Writes data from this context back to the requesting process/thread. 193 /// Writes data from this context back to the requesting process/thread.
129 ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread); 194 ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread);
130 195
131 u32_le GetCommand() const { 196 u32_le GetHipcCommand() const {
132 return command; 197 return command;
133 } 198 }
134 199
200 u32_le GetTipcCommand() const {
201 return static_cast<u32_le>(command_header->type.Value()) -
202 static_cast<u32_le>(IPC::CommandType::TIPC_CommandRegion);
203 }
204
205 u32_le GetCommand() const {
206 return command_header->IsTipc() ? GetTipcCommand() : GetHipcCommand();
207 }
208
209 bool IsTipc() const {
210 return command_header->IsTipc();
211 }
212
135 IPC::CommandType GetCommandType() const { 213 IPC::CommandType GetCommandType() const {
136 return command_header->type; 214 return command_header->type;
137 } 215 }
138 216
139 unsigned GetDataPayloadOffset() const { 217 u64 GetPID() const {
218 return pid;
219 }
220
221 u32 GetDataPayloadOffset() const {
140 return data_payload_offset; 222 return data_payload_offset;
141 } 223 }
142 224
@@ -206,53 +288,32 @@ public:
206 bool CanWriteBuffer(std::size_t buffer_index = 0) const; 288 bool CanWriteBuffer(std::size_t buffer_index = 0) const;
207 289
208 Handle GetCopyHandle(std::size_t index) const { 290 Handle GetCopyHandle(std::size_t index) const {
209 return copy_handles.at(index); 291 return incoming_copy_handles.at(index);
210 } 292 }
211 293
212 Handle GetMoveHandle(std::size_t index) const { 294 Handle GetMoveHandle(std::size_t index) const {
213 return move_handles.at(index); 295 return incoming_move_handles.at(index);
214 } 296 }
215 297
216 void AddMoveObject(KAutoObject* object) { 298 void AddMoveObject(KAutoObject* object) {
217 move_objects.emplace_back(object); 299 outgoing_move_objects.emplace_back(object);
218 } 300 }
219 301
220 void AddCopyObject(KAutoObject* object) { 302 void AddCopyObject(KAutoObject* object) {
221 copy_objects.emplace_back(object); 303 outgoing_copy_objects.emplace_back(object);
222 } 304 }
223 305
224 void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) { 306 void AddDomainObject(SessionRequestHandlerPtr object) {
225 domain_objects.emplace_back(std::move(object)); 307 outgoing_domain_objects.emplace_back(std::move(object));
226 } 308 }
227 309
228 template <typename T> 310 template <typename T>
229 std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const { 311 std::shared_ptr<T> GetDomainHandler(std::size_t index) const {
230 return std::static_pointer_cast<T>(domain_request_handlers.at(index)); 312 return std::static_pointer_cast<T>(manager->DomainHandler(index));
231 }
232
233 void SetDomainRequestHandlers(
234 const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) {
235 domain_request_handlers = handlers;
236 }
237
238 /// Clears the list of objects so that no lingering objects are written accidentally to the
239 /// response buffer.
240 void ClearIncomingObjects() {
241 move_objects.clear();
242 copy_objects.clear();
243 domain_objects.clear();
244 }
245
246 std::size_t NumMoveObjects() const {
247 return move_objects.size();
248 } 313 }
249 314
250 std::size_t NumCopyObjects() const { 315 void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) {
251 return copy_objects.size(); 316 manager = std::move(manager_);
252 }
253
254 std::size_t NumDomainObjects() const {
255 return domain_objects.size();
256 } 317 }
257 318
258 std::string Description() const; 319 std::string Description() const;
@@ -274,12 +335,12 @@ private:
274 Kernel::KServerSession* server_session{}; 335 Kernel::KServerSession* server_session{};
275 KThread* thread; 336 KThread* thread;
276 337
277 // TODO(yuriks): Check common usage of this and optimize size accordingly 338 std::vector<Handle> incoming_move_handles;
278 boost::container::small_vector<Handle, 8> move_handles; 339 std::vector<Handle> incoming_copy_handles;
279 boost::container::small_vector<Handle, 8> copy_handles; 340
280 boost::container::small_vector<KAutoObject*, 8> move_objects; 341 std::vector<KAutoObject*> outgoing_move_objects;
281 boost::container::small_vector<KAutoObject*, 8> copy_objects; 342 std::vector<KAutoObject*> outgoing_copy_objects;
282 boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; 343 std::vector<SessionRequestHandlerPtr> outgoing_domain_objects;
283 344
284 std::optional<IPC::CommandHeader> command_header; 345 std::optional<IPC::CommandHeader> command_header;
285 std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; 346 std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header;
@@ -291,11 +352,14 @@ private:
291 std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; 352 std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors;
292 std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; 353 std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
293 354
294 unsigned data_payload_offset{};
295 unsigned buffer_c_offset{};
296 u32_le command{}; 355 u32_le command{};
356 u64 pid{};
357 u32 write_size{};
358 u32 data_payload_offset{};
359 u32 handles_offset{};
360 u32 domain_offset{};
297 361
298 std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; 362 std::shared_ptr<SessionRequestManager> manager;
299 bool is_thread_waiting{}; 363 bool is_thread_waiting{};
300 364
301 KernelCore& kernel; 365 KernelCore& kernel;
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index 69ae405e6..10edede17 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -70,14 +70,22 @@ constexpr size_t SlabCountExtraKThread = 160;
70template <typename T> 70template <typename T>
71VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address, 71VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address,
72 size_t num_objects) { 72 size_t num_objects) {
73 // TODO(bunnei): This is just a place holder. We should initialize the appropriate KSlabHeap for
74 // kernel object type T with the backing kernel memory pointer once we emulate kernel memory.
75
73 const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*)); 76 const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*));
74 VAddr start = Common::AlignUp(address, alignof(T)); 77 VAddr start = Common::AlignUp(address, alignof(T));
75 78
79 // This is intentionally empty. Once KSlabHeap is fully implemented, we can replace this with
80 // the pointer to emulated memory to pass along. Until then, KSlabHeap will just allocate/free
81 // host memory.
82 void* backing_kernel_memory{};
83
76 if (size > 0) { 84 if (size > 0) {
77 const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1); 85 const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1);
78 ASSERT(region != nullptr); 86 ASSERT(region != nullptr);
79 ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab)); 87 ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab));
80 T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size); 88 T::InitializeSlabHeap(system.Kernel(), backing_kernel_memory, size);
81 } 89 }
82 90
83 return start + size; 91 return start + size;
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp
index e14b915b9..4a12dee10 100644
--- a/src/core/hle/kernel/k_client_port.cpp
+++ b/src/core/hle/kernel/k_client_port.cpp
@@ -91,7 +91,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) {
91 // Create a new session. 91 // Create a new session.
92 KSession* session = KSession::Create(kernel); 92 KSession* session = KSession::Create(kernel);
93 if (session == nullptr) { 93 if (session == nullptr) {
94 /* Decrement the session count. */ 94 // Decrement the session count.
95 const auto prev = num_sessions--; 95 const auto prev = num_sessions--;
96 if (prev == max_sessions) { 96 if (prev == max_sessions) {
97 this->NotifyAvailable(); 97 this->NotifyAvailable();
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h
index d00ce3ddd..8501156e8 100644
--- a/src/core/hle/kernel/k_client_port.h
+++ b/src/core/hle/kernel/k_client_port.h
@@ -31,6 +31,9 @@ public:
31 const KPort* GetParent() const { 31 const KPort* GetParent() const {
32 return parent; 32 return parent;
33 } 33 }
34 KPort* GetParent() {
35 return parent;
36 }
34 37
35 s32 GetNumSessions() const { 38 s32 GetNumSessions() const {
36 return num_sessions; 39 return num_sessions;
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h
index 362d0db28..ca2e539a7 100644
--- a/src/core/hle/kernel/k_light_condition_variable.h
+++ b/src/core/hle/kernel/k_light_condition_variable.h
@@ -18,7 +18,8 @@ class KernelCore;
18 18
19class KLightConditionVariable { 19class KLightConditionVariable {
20public: 20public:
21 explicit KLightConditionVariable(KernelCore& kernel) : thread_queue(kernel), kernel(kernel) {} 21 explicit KLightConditionVariable(KernelCore& kernel_)
22 : thread_queue(kernel_), kernel(kernel_) {}
22 23
23 void Wait(KLightLock* lock, s64 timeout = -1) { 24 void Wait(KLightLock* lock, s64 timeout = -1) {
24 WaitImpl(lock, timeout); 25 WaitImpl(lock, timeout);
diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h
index 540e518cd..6adfe1e34 100644
--- a/src/core/hle/kernel/k_linked_list.h
+++ b/src/core/hle/kernel/k_linked_list.h
@@ -201,10 +201,10 @@ public:
201 } 201 }
202 202
203 iterator insert(const_iterator pos, reference ref) { 203 iterator insert(const_iterator pos, reference ref) {
204 KLinkedListNode* node = KLinkedListNode::Allocate(kernel); 204 KLinkedListNode* new_node = KLinkedListNode::Allocate(kernel);
205 ASSERT(node != nullptr); 205 ASSERT(new_node != nullptr);
206 node->Initialize(std::addressof(ref)); 206 new_node->Initialize(std::addressof(ref));
207 return iterator(BaseList::insert(pos.m_base_it, *node)); 207 return iterator(BaseList::insert(pos.m_base_it, *new_node));
208 } 208 }
209 209
210 void push_back(reference ref) { 210 void push_back(reference ref) {
diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp
index 44bfeb0d5..fc7033564 100644
--- a/src/core/hle/kernel/k_memory_block_manager.cpp
+++ b/src/core/hle/kernel/k_memory_block_manager.cpp
@@ -7,8 +7,8 @@
7 7
8namespace Kernel { 8namespace Kernel {
9 9
10KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr) 10KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr_, VAddr end_addr_)
11 : start_addr{start_addr}, end_addr{end_addr} { 11 : start_addr{start_addr_}, end_addr{end_addr_} {
12 const u64 num_pages{(end_addr - start_addr) / PageSize}; 12 const u64 num_pages{(end_addr - start_addr) / PageSize};
13 memory_block_tree.emplace_back(start_addr, num_pages, KMemoryState::Free, 13 memory_block_tree.emplace_back(start_addr, num_pages, KMemoryState::Free,
14 KMemoryPermission::None, KMemoryAttribute::None); 14 KMemoryPermission::None, KMemoryAttribute::None);
diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h
index e11cc70c8..d222da919 100644
--- a/src/core/hle/kernel/k_memory_block_manager.h
+++ b/src/core/hle/kernel/k_memory_block_manager.h
@@ -19,7 +19,7 @@ public:
19 using const_iterator = MemoryBlockTree::const_iterator; 19 using const_iterator = MemoryBlockTree::const_iterator;
20 20
21public: 21public:
22 KMemoryBlockManager(VAddr start_addr, VAddr end_addr); 22 KMemoryBlockManager(VAddr start_addr_, VAddr end_addr_);
23 23
24 iterator end() { 24 iterator end() {
25 return memory_block_tree.end(); 25 return memory_block_tree.end();
diff --git a/src/core/hle/kernel/k_page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h
index 64024d01f..dfdac5321 100644
--- a/src/core/hle/kernel/k_page_linked_list.h
+++ b/src/core/hle/kernel/k_page_linked_list.h
@@ -17,7 +17,7 @@ class KPageLinkedList final {
17public: 17public:
18 class Node final { 18 class Node final {
19 public: 19 public:
20 constexpr Node(u64 addr, std::size_t num_pages) : addr{addr}, num_pages{num_pages} {} 20 constexpr Node(u64 addr_, std::size_t num_pages_) : addr{addr_}, num_pages{num_pages_} {}
21 21
22 constexpr u64 GetAddress() const { 22 constexpr u64 GetAddress() const {
23 return addr; 23 return addr;
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index d4ce98ee3..27dbf0ebc 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -58,7 +58,7 @@ constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr
58 58
59} // namespace 59} // namespace
60 60
61KPageTable::KPageTable(Core::System& system) : system{system} {} 61KPageTable::KPageTable(Core::System& system_) : system{system_} {}
62 62
63ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, 63ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
64 bool enable_aslr, VAddr code_addr, 64 bool enable_aslr, VAddr code_addr,
@@ -906,8 +906,8 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
906 906
907 block_manager->UpdateLock( 907 block_manager->UpdateLock(
908 addr, size / PageSize, 908 addr, size / PageSize,
909 [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { 909 [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
910 block->ShareToDevice(perm); 910 block->ShareToDevice(permission);
911 }, 911 },
912 perm); 912 perm);
913 913
@@ -929,8 +929,8 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
929 929
930 block_manager->UpdateLock( 930 block_manager->UpdateLock(
931 addr, size / PageSize, 931 addr, size / PageSize,
932 [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { 932 [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
933 block->UnshareToDevice(perm); 933 block->UnshareToDevice(permission);
934 }, 934 },
935 perm); 935 perm);
936 936
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 8c2cc03eb..770c4841c 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -24,7 +24,7 @@ class KMemoryBlockManager;
24 24
25class KPageTable final : NonCopyable { 25class KPageTable final : NonCopyable {
26public: 26public:
27 explicit KPageTable(Core::System& system); 27 explicit KPageTable(Core::System& system_);
28 28
29 ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, 29 ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
30 VAddr code_addr, std::size_t code_size, 30 VAddr code_addr, std::size_t code_size,
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp
index feb2bb11f..223c0b205 100644
--- a/src/core/hle/kernel/k_port.cpp
+++ b/src/core/hle/kernel/k_port.cpp
@@ -56,11 +56,8 @@ ResultCode KPort::EnqueueSession(KServerSession* session) {
56 56
57 R_UNLESS(state == State::Normal, ResultPortClosed); 57 R_UNLESS(state == State::Normal, ResultPortClosed);
58 58
59 if (server.HasHLEHandler()) { 59 server.EnqueueSession(session);
60 server.GetHLEHandler()->ClientConnected(session); 60 server.GetSessionRequestHandler()->ClientConnected(server.AcceptSession());
61 } else {
62 server.EnqueueSession(session);
63 }
64 61
65 return RESULT_SUCCESS; 62 return RESULT_SUCCESS;
66} 63}
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index e256e9415..2f82fbcd6 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -607,7 +607,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
607 } 607 }
608} 608}
609 609
610KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) { 610KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
611 switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this); 611 switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
612 state.needs_scheduling.store(true); 612 state.needs_scheduling.store(true);
613 state.interrupt_task_thread_runnable = false; 613 state.interrupt_task_thread_runnable = false;
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 13a2414e6..12cfae919 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -30,7 +30,7 @@ class KThread;
30 30
31class KScheduler final { 31class KScheduler final {
32public: 32public:
33 explicit KScheduler(Core::System& system, s32 core_id); 33 explicit KScheduler(Core::System& system_, s32 core_id_);
34 ~KScheduler(); 34 ~KScheduler();
35 35
36 /// Reschedules to the next available thread (call after current thread is suspended) 36 /// Reschedules to the next available thread (call after current thread is suspended)
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
index b5d405744..a86af56dd 100644
--- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -17,8 +17,8 @@ namespace Kernel {
17 17
18class [[nodiscard]] KScopedSchedulerLockAndSleep { 18class [[nodiscard]] KScopedSchedulerLockAndSleep {
19public: 19public:
20 explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout) 20 explicit KScopedSchedulerLockAndSleep(KernelCore & kernel_, KThread * t, s64 timeout)
21 : kernel(kernel), thread(t), timeout_tick(timeout) { 21 : kernel(kernel_), thread(t), timeout_tick(timeout) {
22 // Lock the scheduler. 22 // Lock the scheduler.
23 kernel.GlobalSchedulerContext().scheduler_lock.Lock(); 23 kernel.GlobalSchedulerContext().scheduler_lock.Lock();
24 } 24 }
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
index e76792253..d1a757ec3 100644
--- a/src/core/hle/kernel/k_server_port.h
+++ b/src/core/hle/kernel/k_server_port.h
@@ -32,26 +32,24 @@ public:
32 explicit KServerPort(KernelCore& kernel_); 32 explicit KServerPort(KernelCore& kernel_);
33 virtual ~KServerPort() override; 33 virtual ~KServerPort() override;
34 34
35 using HLEHandler = std::shared_ptr<SessionRequestHandler>;
36
37 void Initialize(KPort* parent_, std::string&& name_); 35 void Initialize(KPort* parent_, std::string&& name_);
38 36
39 /// Whether or not this server port has an HLE handler available. 37 /// Whether or not this server port has an HLE handler available.
40 bool HasHLEHandler() const { 38 bool HasSessionRequestHandler() const {
41 return hle_handler != nullptr; 39 return session_handler != nullptr;
42 } 40 }
43 41
44 /// Gets the HLE handler for this port. 42 /// Gets the HLE handler for this port.
45 HLEHandler GetHLEHandler() const { 43 SessionRequestHandlerPtr GetSessionRequestHandler() const {
46 return hle_handler; 44 return session_handler;
47 } 45 }
48 46
49 /** 47 /**
50 * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port 48 * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
51 * will inherit a reference to this handler. 49 * will inherit a reference to this handler.
52 */ 50 */
53 void SetHleHandler(HLEHandler hle_handler_) { 51 void SetSessionHandler(SessionRequestHandlerPtr&& handler) {
54 hle_handler = std::move(hle_handler_); 52 session_handler = std::move(handler);
55 } 53 }
56 54
57 void EnqueueSession(KServerSession* pending_session); 55 void EnqueueSession(KServerSession* pending_session);
@@ -73,7 +71,7 @@ private:
73 71
74private: 72private:
75 SessionList session_list; 73 SessionList session_list;
76 HLEHandler hle_handler; 74 SessionRequestHandlerPtr session_handler;
77 KPort* parent{}; 75 KPort* parent{};
78}; 76};
79 77
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index b28cc2499..457fdfd60 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -23,7 +23,8 @@
23 23
24namespace Kernel { 24namespace Kernel {
25 25
26KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} 26KServerSession::KServerSession(KernelCore& kernel_)
27 : KSynchronizationObject{kernel_}, manager{std::make_shared<SessionRequestManager>()} {}
27 28
28KServerSession::~KServerSession() { 29KServerSession::~KServerSession() {
29 kernel.ReleaseServiceThread(service_thread); 30 kernel.ReleaseServiceThread(service_thread);
@@ -43,14 +44,8 @@ void KServerSession::Destroy() {
43} 44}
44 45
45void KServerSession::OnClientClosed() { 46void KServerSession::OnClientClosed() {
46 // We keep a shared pointer to the hle handler to keep it alive throughout 47 if (manager->HasSessionHandler()) {
47 // the call to ClientDisconnected, as ClientDisconnected invalidates the 48 manager->SessionHandler().ClientDisconnected(this);
48 // hle_handler member itself during the course of the function executing.
49 std::shared_ptr<SessionRequestHandler> handler = hle_handler;
50 if (handler) {
51 // Note that after this returns, this server session's hle_handler is
52 // invalidated (set to null).
53 handler->ClientDisconnected(this);
54 } 49 }
55} 50}
56 51
@@ -66,12 +61,12 @@ bool KServerSession::IsSignaled() const {
66 return false; 61 return false;
67} 62}
68 63
69void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { 64void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) {
70 domain_request_handlers.push_back(std::move(handler)); 65 manager->AppendDomainHandler(std::move(handler));
71} 66}
72 67
73std::size_t KServerSession::NumDomainRequestHandlers() const { 68std::size_t KServerSession::NumDomainRequestHandlers() const {
74 return domain_request_handlers.size(); 69 return manager->DomainHandlerCount();
75} 70}
76 71
77ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { 72ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
@@ -80,14 +75,14 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co
80 } 75 }
81 76
82 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs 77 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
83 context.SetDomainRequestHandlers(domain_request_handlers); 78 context.SetSessionRequestManager(manager);
84 79
85 // If there is a DomainMessageHeader, then this is CommandType "Request" 80 // If there is a DomainMessageHeader, then this is CommandType "Request"
86 const auto& domain_message_header = context.GetDomainMessageHeader(); 81 const auto& domain_message_header = context.GetDomainMessageHeader();
87 const u32 object_id{domain_message_header.object_id}; 82 const u32 object_id{domain_message_header.object_id};
88 switch (domain_message_header.command) { 83 switch (domain_message_header.command) {
89 case IPC::DomainMessageHeader::CommandType::SendMessage: 84 case IPC::DomainMessageHeader::CommandType::SendMessage:
90 if (object_id > domain_request_handlers.size()) { 85 if (object_id > manager->DomainHandlerCount()) {
91 LOG_CRITICAL(IPC, 86 LOG_CRITICAL(IPC,
92 "object_id {} is too big! This probably means a recent service call " 87 "object_id {} is too big! This probably means a recent service call "
93 "to {} needed to return a new interface!", 88 "to {} needed to return a new interface!",
@@ -95,12 +90,12 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co
95 UNREACHABLE(); 90 UNREACHABLE();
96 return RESULT_SUCCESS; // Ignore error if asserts are off 91 return RESULT_SUCCESS; // Ignore error if asserts are off
97 } 92 }
98 return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); 93 return manager->DomainHandler(object_id - 1)->HandleSyncRequest(*this, context);
99 94
100 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { 95 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
101 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); 96 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
102 97
103 domain_request_handlers[object_id - 1] = nullptr; 98 manager->CloseDomainHandler(object_id - 1);
104 99
105 IPC::ResponseBuilder rb{context, 2}; 100 IPC::ResponseBuilder rb{context, 2};
106 rb.Push(RESULT_SUCCESS); 101 rb.Push(RESULT_SUCCESS);
@@ -133,14 +128,14 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {
133 if (IsDomain() && context.HasDomainMessageHeader()) { 128 if (IsDomain() && context.HasDomainMessageHeader()) {
134 result = HandleDomainSyncRequest(context); 129 result = HandleDomainSyncRequest(context);
135 // If there is no domain header, the regular session handler is used 130 // If there is no domain header, the regular session handler is used
136 } else if (hle_handler != nullptr) { 131 } else if (manager->HasSessionHandler()) {
137 // If this ServerSession has an associated HLE handler, forward the request to it. 132 // If this ServerSession has an associated HLE handler, forward the request to it.
138 result = hle_handler->HandleSyncRequest(context); 133 result = manager->SessionHandler().HandleSyncRequest(*this, context);
139 } 134 }
140 135
141 if (convert_to_domain) { 136 if (convert_to_domain) {
142 ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); 137 ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance.");
143 domain_request_handlers = {hle_handler}; 138 manager->ConvertToDomain();
144 convert_to_domain = false; 139 convert_to_domain = false;
145 } 140 }
146 141
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index 597d76d38..dd4de2904 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -12,6 +12,7 @@
12#include <boost/intrusive/list.hpp> 12#include <boost/intrusive/list.hpp>
13 13
14#include "common/threadsafe_queue.h" 14#include "common/threadsafe_queue.h"
15#include "core/hle/kernel/hle_ipc.h"
15#include "core/hle/kernel/k_synchronization_object.h" 16#include "core/hle/kernel/k_synchronization_object.h"
16#include "core/hle/kernel/service_thread.h" 17#include "core/hle/kernel/service_thread.h"
17#include "core/hle/result.h" 18#include "core/hle/result.h"
@@ -64,8 +65,8 @@ public:
64 * instead of the regular IPC machinery. (The regular IPC machinery is currently not 65 * instead of the regular IPC machinery. (The regular IPC machinery is currently not
65 * implemented.) 66 * implemented.)
66 */ 67 */
67 void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) { 68 void SetSessionHandler(SessionRequestHandlerPtr handler) {
68 hle_handler = std::move(hle_handler_); 69 manager->SetSessionHandler(std::move(handler));
69 } 70 }
70 71
71 /** 72 /**
@@ -82,7 +83,7 @@ public:
82 83
83 /// Adds a new domain request handler to the collection of request handlers within 84 /// Adds a new domain request handler to the collection of request handlers within
84 /// this ServerSession instance. 85 /// this ServerSession instance.
85 void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); 86 void AppendDomainHandler(SessionRequestHandlerPtr handler);
86 87
87 /// Retrieves the total number of domain request handlers that have been 88 /// Retrieves the total number of domain request handlers that have been
88 /// appended to this ServerSession instance. 89 /// appended to this ServerSession instance.
@@ -90,12 +91,7 @@ public:
90 91
91 /// Returns true if the session has been converted to a domain, otherwise False 92 /// Returns true if the session has been converted to a domain, otherwise False
92 bool IsDomain() const { 93 bool IsDomain() const {
93 return !IsSession(); 94 return manager->IsDomain();
94 }
95
96 /// Returns true if this session has not been converted to a domain, otherwise false.
97 bool IsSession() const {
98 return domain_request_handlers.empty();
99 } 95 }
100 96
101 /// Converts the session to a domain at the end of the current command 97 /// Converts the session to a domain at the end of the current command
@@ -103,6 +99,21 @@ public:
103 convert_to_domain = true; 99 convert_to_domain = true;
104 } 100 }
105 101
102 /// Gets the session request manager, which forwards requests to the underlying service
103 std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() {
104 return manager;
105 }
106
107 /// Gets the session request manager, which forwards requests to the underlying service
108 const std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() const {
109 return manager;
110 }
111
112 /// Sets the session request manager, which forwards requests to the underlying service
113 void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) {
114 manager = std::move(manager_);
115 }
116
106private: 117private:
107 /// Queues a sync request from the emulated application. 118 /// Queues a sync request from the emulated application.
108 ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); 119 ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
@@ -114,11 +125,8 @@ private:
114 /// object handle. 125 /// object handle.
115 ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); 126 ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context);
116 127
117 /// This session's HLE request handler (applicable when not a domain) 128 /// This session's HLE request handlers
118 std::shared_ptr<SessionRequestHandler> hle_handler; 129 std::shared_ptr<SessionRequestManager> manager;
119
120 /// This is the list of domain request handlers (after conversion to a domain)
121 std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
122 130
123 /// When set to True, converts the session to a domain at the end of the command 131 /// When set to True, converts the session to a domain at the end of the command
124 bool convert_to_domain{}; 132 bool convert_to_domain{};
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h
index 16901e19c..a981fd1f6 100644
--- a/src/core/hle/kernel/k_session.h
+++ b/src/core/hle/kernel/k_session.h
@@ -66,6 +66,10 @@ public:
66 return port; 66 return port;
67 } 67 }
68 68
69 KClientPort* GetParent() {
70 return port;
71 }
72
69private: 73private:
70 enum class State : u8 { 74 enum class State : u8 {
71 Invalid = 0, 75 Invalid = 0,
diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h
index 5ce9a1d7c..81d472a3e 100644
--- a/src/core/hle/kernel/k_slab_heap.h
+++ b/src/core/hle/kernel/k_slab_heap.h
@@ -4,165 +4,33 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <atomic>
8
9#include "common/assert.h"
10#include "common/common_types.h"
11
12namespace Kernel { 7namespace Kernel {
13 8
14namespace impl { 9class KernelCore;
15
16class KSlabHeapImpl final : NonCopyable {
17public:
18 struct Node {
19 Node* next{};
20 };
21
22 constexpr KSlabHeapImpl() = default;
23
24 void Initialize(std::size_t size) {
25 ASSERT(head == nullptr);
26 obj_size = size;
27 }
28
29 constexpr std::size_t GetObjectSize() const {
30 return obj_size;
31 }
32
33 Node* GetHead() const {
34 return head;
35 }
36
37 void* Allocate() {
38 Node* ret = head.load();
39
40 do {
41 if (ret == nullptr) {
42 break;
43 }
44 } while (!head.compare_exchange_weak(ret, ret->next));
45
46 return ret;
47 }
48
49 void Free(void* obj) {
50 Node* node = static_cast<Node*>(obj);
51
52 Node* cur_head = head.load();
53 do {
54 node->next = cur_head;
55 } while (!head.compare_exchange_weak(cur_head, node));
56 }
57
58private:
59 std::atomic<Node*> head{};
60 std::size_t obj_size{};
61};
62
63} // namespace impl
64
65class KSlabHeapBase : NonCopyable {
66public:
67 constexpr KSlabHeapBase() = default;
68
69 constexpr bool Contains(uintptr_t addr) const {
70 return start <= addr && addr < end;
71 }
72
73 constexpr std::size_t GetSlabHeapSize() const {
74 return (end - start) / GetObjectSize();
75 }
76
77 constexpr std::size_t GetObjectSize() const {
78 return impl.GetObjectSize();
79 }
80 10
81 constexpr uintptr_t GetSlabHeapAddress() const { 11/// This is a placeholder class to manage slab heaps for kernel objects. For now, we just allocate
82 return start; 12/// these with new/delete, but this can be re-implemented later to allocate these in emulated
83 } 13/// memory.
84
85 std::size_t GetObjectIndexImpl(const void* obj) const {
86 return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize();
87 }
88
89 std::size_t GetPeakIndex() const {
90 return GetObjectIndexImpl(reinterpret_cast<const void*>(peak));
91 }
92
93 void* AllocateImpl() {
94 return impl.Allocate();
95 }
96
97 void FreeImpl(void* obj) {
98 // Don't allow freeing an object that wasn't allocated from this heap
99 ASSERT(Contains(reinterpret_cast<uintptr_t>(obj)));
100
101 impl.Free(obj);
102 }
103
104 void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) {
105 // Ensure we don't initialize a slab using null memory
106 ASSERT(memory != nullptr);
107
108 // Initialize the base allocator
109 impl.Initialize(obj_size);
110
111 // Set our tracking variables
112 const std::size_t num_obj = (memory_size / obj_size);
113 start = reinterpret_cast<uintptr_t>(memory);
114 end = start + num_obj * obj_size;
115 peak = start;
116
117 // Free the objects
118 u8* cur = reinterpret_cast<u8*>(end);
119
120 for (std::size_t i{}; i < num_obj; i++) {
121 cur -= obj_size;
122 impl.Free(cur);
123 }
124 }
125
126private:
127 using Impl = impl::KSlabHeapImpl;
128
129 Impl impl;
130 uintptr_t peak{};
131 uintptr_t start{};
132 uintptr_t end{};
133};
134 14
135template <typename T> 15template <typename T>
136class KSlabHeap final : public KSlabHeapBase { 16class KSlabHeap final : NonCopyable {
137public: 17public:
138 constexpr KSlabHeap() : KSlabHeapBase() {} 18 KSlabHeap() = default;
139 19
140 void Initialize(void* memory, std::size_t memory_size) { 20 void Initialize([[maybe_unused]] void* memory, [[maybe_unused]] std::size_t memory_size) {
141 InitializeImpl(sizeof(T), memory, memory_size); 21 // Placeholder that should initialize the backing slab heap implementation.
142 } 22 }
143 23
144 T* Allocate() { 24 T* Allocate() {
145 T* obj = static_cast<T*>(AllocateImpl()); 25 return new T();
146 if (obj != nullptr) {
147 new (obj) T();
148 }
149 return obj;
150 } 26 }
151 27
152 T* AllocateWithKernel(KernelCore& kernel) { 28 T* AllocateWithKernel(KernelCore& kernel) {
153 T* obj = static_cast<T*>(AllocateImpl()); 29 return new T(kernel);
154 if (obj != nullptr) {
155 new (obj) T(kernel);
156 }
157 return obj;
158 } 30 }
159 31
160 void Free(T* obj) { 32 void Free(T* obj) {
161 FreeImpl(obj); 33 delete obj;
162 }
163
164 constexpr std::size_t GetObjectIndex(const T* obj) const {
165 return GetObjectIndexImpl(obj);
166 } 34 }
167}; 35};
168 36
diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h
index c52eba249..35d471dc5 100644
--- a/src/core/hle/kernel/k_thread_queue.h
+++ b/src/core/hle/kernel/k_thread_queue.h
@@ -10,7 +10,7 @@ namespace Kernel {
10 10
11class KThreadQueue { 11class KThreadQueue {
12public: 12public:
13 explicit KThreadQueue(KernelCore& kernel) : kernel{kernel} {} 13 explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {}
14 14
15 bool IsEmpty() const { 15 bool IsEmpty() const {
16 return wait_list.empty(); 16 return wait_list.empty();
diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h
index 838fd2b18..c2d0f1eaf 100644
--- a/src/core/hle/kernel/k_transfer_memory.h
+++ b/src/core/hle/kernel/k_transfer_memory.h
@@ -52,7 +52,7 @@ public:
52 } 52 }
53 53
54 size_t GetSize() const { 54 size_t GetSize() const {
55 return is_initialized ? size * PageSize : 0; 55 return is_initialized ? size : 0;
56 } 56 }
57 57
58private: 58private:
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index bd4e4d350..8b55df82e 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -44,6 +44,7 @@
44#include "core/hle/kernel/time_manager.h" 44#include "core/hle/kernel/time_manager.h"
45#include "core/hle/lock.h" 45#include "core/hle/lock.h"
46#include "core/hle/result.h" 46#include "core/hle/result.h"
47#include "core/hle/service/sm/sm.h"
47#include "core/memory.h" 48#include "core/memory.h"
48 49
49MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); 50MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
@@ -656,6 +657,7 @@ struct KernelCore::Impl {
656 657
657 /// Map of named ports managed by the kernel, which can be retrieved using 658 /// Map of named ports managed by the kernel, which can be retrieved using
658 /// the ConnectToPort SVC. 659 /// the ConnectToPort SVC.
660 std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
659 NamedPortTable named_ports; 661 NamedPortTable named_ports;
660 662
661 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; 663 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
@@ -844,18 +846,17 @@ void KernelCore::PrepareReschedule(std::size_t id) {
844 // TODO: Reimplement, this 846 // TODO: Reimplement, this
845} 847}
846 848
847void KernelCore::AddNamedPort(std::string name, KClientPort* port) { 849void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) {
848 port->Open(); 850 impl->service_interface_factory.emplace(std::move(name), factory);
849 impl->named_ports.emplace(std::move(name), port);
850} 851}
851 852
852KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) { 853KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
853 return impl->named_ports.find(name); 854 auto search = impl->service_interface_factory.find(name);
854} 855 if (search == impl->service_interface_factory.end()) {
855 856 UNIMPLEMENTED();
856KernelCore::NamedPortTable::const_iterator KernelCore::FindNamedPort( 857 return {};
857 const std::string& name) const { 858 }
858 return impl->named_ports.find(name); 859 return &search->second(impl->system.ServiceManager(), impl->system);
859} 860}
860 861
861bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { 862bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 51aaccbc7..2d01e1ae0 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -27,6 +27,10 @@ class CoreTiming;
27struct EventType; 27struct EventType;
28} // namespace Core::Timing 28} // namespace Core::Timing
29 29
30namespace Service::SM {
31class ServiceManager;
32}
33
30namespace Kernel { 34namespace Kernel {
31 35
32class KClientPort; 36class KClientPort;
@@ -51,6 +55,9 @@ class ServiceThread;
51class Synchronization; 55class Synchronization;
52class TimeManager; 56class TimeManager;
53 57
58using ServiceInterfaceFactory =
59 std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
60
54namespace Init { 61namespace Init {
55struct KSlabResourceCounts; 62struct KSlabResourceCounts;
56} 63}
@@ -172,14 +179,11 @@ public:
172 179
173 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); 180 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
174 181
175 /// Adds a port to the named port table 182 /// Registers a named HLE service, passing a factory used to open a port to that service.
176 void AddNamedPort(std::string name, KClientPort* port); 183 void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
177
178 /// Finds a port within the named port table with the given name.
179 NamedPortTable::iterator FindNamedPort(const std::string& name);
180 184
181 /// Finds a port within the named port table with the given name. 185 /// Opens a port to a service previously registered with RegisterNamedService.
182 NamedPortTable::const_iterator FindNamedPort(const std::string& name) const; 186 KClientPort* CreateNamedServicePort(std::string name);
183 187
184 /// Determines whether or not the given port is a valid named port. 188 /// Determines whether or not the given port is a valid named port.
185 bool IsValidNamedPort(NamedPortTable::const_iterator port) const; 189 bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 7fea45f96..7f02d9471 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -13,10 +13,10 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, 16PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
17 Kernel::KScheduler& scheduler, Core::CPUInterrupts& interrupts) 17 Core::CPUInterrupts& interrupts_)
18 : core_index{core_index}, system{system}, scheduler{scheduler}, 18 : core_index{core_index_}, system{system_}, scheduler{scheduler_},
19 interrupts{interrupts}, guard{std::make_unique<Common::SpinLock>()} {} 19 interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} {}
20 20
21PhysicalCore::~PhysicalCore() = default; 21PhysicalCore::~PhysicalCore() = default;
22 22
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h
index f2b0911aa..901f7e3b0 100644
--- a/src/core/hle/kernel/physical_core.h
+++ b/src/core/hle/kernel/physical_core.h
@@ -28,8 +28,8 @@ namespace Kernel {
28 28
29class PhysicalCore { 29class PhysicalCore {
30public: 30public:
31 PhysicalCore(std::size_t core_index, Core::System& system, Kernel::KScheduler& scheduler, 31 PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
32 Core::CPUInterrupts& interrupts); 32 Core::CPUInterrupts& interrupts_);
33 ~PhysicalCore(); 33 ~PhysicalCore();
34 34
35 PhysicalCore(const PhysicalCore&) = delete; 35 PhysicalCore(const PhysicalCore&) = delete;
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
index 04be8a502..2ae80beca 100644
--- a/src/core/hle/kernel/service_thread.cpp
+++ b/src/core/hle/kernel/service_thread.cpp
@@ -74,21 +74,17 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session,
74 { 74 {
75 std::unique_lock lock{queue_mutex}; 75 std::unique_lock lock{queue_mutex};
76 76
77 auto* server_session{&session.GetServerSession()};
78
77 // Open a reference to the session to ensure it is not closes while the service request 79 // Open a reference to the session to ensure it is not closes while the service request
78 // completes asynchronously. 80 // completes asynchronously.
79 session.Open(); 81 server_session->Open();
80 82
81 requests.emplace([session_ptr{&session}, context{std::move(context)}]() { 83 requests.emplace([server_session, context{std::move(context)}]() {
82 // Close the reference. 84 // Close the reference.
83 SCOPE_EXIT({ session_ptr->Close(); }); 85 SCOPE_EXIT({ server_session->Close(); });
84
85 // If the session has been closed, we are done.
86 if (session_ptr->IsServerClosed()) {
87 return;
88 }
89 86
90 // Complete the service request. 87 // Complete the service request.
91 KScopedAutoObject server_session{&session_ptr->GetServerSession()};
92 server_session->CompleteSyncRequest(*context); 88 server_session->CompleteSyncRequest(*context);
93 }); 89 });
94 } 90 }
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 52011be9c..81e23f700 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -284,12 +284,11 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr po
284 auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 284 auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
285 285
286 // Find the client port. 286 // Find the client port.
287 const auto it = kernel.FindNamedPort(port_name); 287 auto port = kernel.CreateNamedServicePort(port_name);
288 if (!kernel.IsValidNamedPort(it)) { 288 if (!port) {
289 LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); 289 LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
290 return ResultNotFound; 290 return ResultNotFound;
291 } 291 }
292 auto port = it->second;
293 292
294 // Reserve a handle for the port. 293 // Reserve a handle for the port.
295 // NOTE: Nintendo really does write directly to the output handle here. 294 // NOTE: Nintendo really does write directly to the output handle here.
@@ -820,10 +819,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
820 return RESULT_SUCCESS; 819 return RESULT_SUCCESS;
821 } 820 }
822 821
823 Handle handle{}; 822 Handle resource_handle{};
824 R_TRY(handle_table.Add(&handle, resource_limit)); 823 R_TRY(handle_table.Add(&resource_handle, resource_limit));
825 824
826 *result = handle; 825 *result = resource_handle;
827 return RESULT_SUCCESS; 826 return RESULT_SUCCESS;
828 } 827 }
829 828
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 8feda7ad7..43968386f 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -56,7 +56,7 @@ enum class ErrorModule : u32 {
56 PCIe = 120, 56 PCIe = 120,
57 Friends = 121, 57 Friends = 121,
58 BCAT = 122, 58 BCAT = 122,
59 SSL = 123, 59 SSLSrv = 123,
60 Account = 124, 60 Account = 124,
61 News = 125, 61 News = 125,
62 Mii = 126, 62 Mii = 126,
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 408e441dc..234173297 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -833,7 +833,7 @@ IStorageImpl::~IStorageImpl() = default;
833 833
834class StorageDataImpl final : public IStorageImpl { 834class StorageDataImpl final : public IStorageImpl {
835public: 835public:
836 explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {} 836 explicit StorageDataImpl(std::vector<u8>&& buffer_) : buffer{std::move(buffer_)} {}
837 837
838 std::vector<u8>& GetData() override { 838 std::vector<u8>& GetData() override {
839 return buffer; 839 return buffer;
@@ -1513,9 +1513,9 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
1513 1513
1514 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), 1514 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
1515 system.GetContentProvider()}; 1515 system.GetContentProvider()};
1516 auto res = pm.GetControlMetadata(); 1516 auto metadata = pm.GetControlMetadata();
1517 if (res.first != nullptr) { 1517 if (metadata.first != nullptr) {
1518 return res; 1518 return metadata;
1519 } 1519 }
1520 1520
1521 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), 1521 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
@@ -1550,9 +1550,9 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
1550 1550
1551 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), 1551 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
1552 system.GetContentProvider()}; 1552 system.GetContentProvider()};
1553 auto res = pm.GetControlMetadata(); 1553 auto metadata = pm.GetControlMetadata();
1554 if (res.first != nullptr) { 1554 if (metadata.first != nullptr) {
1555 return res; 1555 return metadata;
1556 } 1556 }
1557 1557
1558 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), 1558 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
index 00c174bb0..8bfa7c0e4 100644
--- a/src/core/hle/service/apm/controller.cpp
+++ b/src/core/hle/service/apm/controller.cpp
@@ -15,11 +15,11 @@ namespace Service::APM {
15 15
16constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7; 16constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7;
17 17
18Controller::Controller(Core::Timing::CoreTiming& core_timing) 18Controller::Controller(Core::Timing::CoreTiming& core_timing_)
19 : core_timing{core_timing}, configs{ 19 : core_timing{core_timing_}, configs{
20 {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, 20 {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION},
21 {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, 21 {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION},
22 } {} 22 } {}
23 23
24Controller::~Controller() = default; 24Controller::~Controller() = default;
25 25
diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h
index af0c4cd34..8d48e0104 100644
--- a/src/core/hle/service/apm/controller.h
+++ b/src/core/hle/service/apm/controller.h
@@ -50,7 +50,7 @@ enum class PerformanceMode : u8 {
50// system during times of high load -- this simply maps to different PerformanceConfigs to use. 50// system during times of high load -- this simply maps to different PerformanceConfigs to use.
51class Controller { 51class Controller {
52public: 52public:
53 explicit Controller(Core::Timing::CoreTiming& core_timing); 53 explicit Controller(Core::Timing::CoreTiming& core_timing_);
54 ~Controller(); 54 ~Controller();
55 55
56 void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); 56 void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 513bd3730..ae4284adf 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -169,10 +169,9 @@ private:
169 169
170class IAudioDevice final : public ServiceFramework<IAudioDevice> { 170class IAudioDevice final : public ServiceFramework<IAudioDevice> {
171public: 171public:
172 explicit IAudioDevice(Core::System& system_, u32_le revision_num) 172 explicit IAudioDevice(Core::System& system_, Kernel::KEvent& buffer_event_, u32_le revision_)
173 : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num}, 173 : ServiceFramework{system_, "IAudioDevice"}, buffer_event{buffer_event_}, revision{
174 buffer_event{system.Kernel()}, audio_input_device_switch_event{system.Kernel()}, 174 revision_} {
175 audio_output_device_switch_event{system.Kernel()} {
176 static const FunctionInfo functions[] = { 175 static const FunctionInfo functions[] = {
177 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, 176 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
178 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, 177 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
@@ -189,18 +188,6 @@ public:
189 {13, nullptr, "GetAudioSystemMasterVolumeSetting"}, 188 {13, nullptr, "GetAudioSystemMasterVolumeSetting"},
190 }; 189 };
191 RegisterHandlers(functions); 190 RegisterHandlers(functions);
192
193 Kernel::KAutoObject::Create(std::addressof(buffer_event));
194 buffer_event.Initialize("IAudioOutBufferReleasedEvent");
195
196 // Should be similar to audio_output_device_switch_event
197 Kernel::KAutoObject::Create(std::addressof(audio_input_device_switch_event));
198 audio_input_device_switch_event.Initialize("IAudioDevice:AudioInputDeviceSwitchedEvent");
199
200 // Should only be signalled when an audio output device has been changed, example: speaker
201 // to headset
202 Kernel::KAutoObject::Create(std::addressof(audio_output_device_switch_event));
203 audio_output_device_switch_event.Initialize("IAudioDevice:AudioOutputDeviceSwitchedEvent");
204 } 191 }
205 192
206private: 193private:
@@ -310,7 +297,7 @@ private:
310 297
311 IPC::ResponseBuilder rb{ctx, 2, 1}; 298 IPC::ResponseBuilder rb{ctx, 2, 1};
312 rb.Push(RESULT_SUCCESS); 299 rb.Push(RESULT_SUCCESS);
313 rb.PushCopyObjects(audio_input_device_switch_event.GetReadableEvent()); 300 rb.PushCopyObjects(buffer_event.GetReadableEvent());
314 } 301 }
315 302
316 void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { 303 void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
@@ -318,17 +305,16 @@ private:
318 305
319 IPC::ResponseBuilder rb{ctx, 2, 1}; 306 IPC::ResponseBuilder rb{ctx, 2, 1};
320 rb.Push(RESULT_SUCCESS); 307 rb.Push(RESULT_SUCCESS);
321 rb.PushCopyObjects(audio_output_device_switch_event.GetReadableEvent()); 308 rb.PushCopyObjects(buffer_event.GetReadableEvent());
322 } 309 }
323 310
311 Kernel::KEvent& buffer_event;
324 u32_le revision = 0; 312 u32_le revision = 0;
325 Kernel::KEvent buffer_event; 313};
326 Kernel::KEvent audio_input_device_switch_event;
327 Kernel::KEvent audio_output_device_switch_event;
328 314
329}; // namespace Audio 315AudRenU::AudRenU(Core::System& system_)
316 : ServiceFramework{system_, "audren:u"}, buffer_event{system.Kernel()} {
330 317
331AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} {
332 // clang-format off 318 // clang-format off
333 static const FunctionInfo functions[] = { 319 static const FunctionInfo functions[] = {
334 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, 320 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
@@ -340,6 +326,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"}
340 // clang-format on 326 // clang-format on
341 327
342 RegisterHandlers(functions); 328 RegisterHandlers(functions);
329
330 Kernel::KAutoObject::Create(std::addressof(buffer_event));
331 buffer_event.Initialize("IAudioOutBufferReleasedEvent");
343} 332}
344 333
345AudRenU::~AudRenU() = default; 334AudRenU::~AudRenU() = default;
@@ -373,7 +362,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
373 static constexpr u64 max_perf_detail_entries = 100; 362 static constexpr u64 max_perf_detail_entries = 100;
374 363
375 // Size of the data structure representing the bulk of the voice-related state. 364 // Size of the data structure representing the bulk of the voice-related state.
376 static constexpr u64 voice_state_size = 0x100; 365 static constexpr u64 voice_state_size_bytes = 0x100;
377 366
378 // Size of the upsampler manager data structure 367 // Size of the upsampler manager data structure
379 constexpr u64 upsampler_manager_size = 0x48; 368 constexpr u64 upsampler_manager_size = 0x48;
@@ -460,7 +449,8 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
460 size += Common::AlignUp(voice_info_size * params.voice_count, info_field_alignment_size); 449 size += Common::AlignUp(voice_info_size * params.voice_count, info_field_alignment_size);
461 size += 450 size +=
462 Common::AlignUp(voice_resource_size * params.voice_count, info_field_alignment_size); 451 Common::AlignUp(voice_resource_size * params.voice_count, info_field_alignment_size);
463 size += Common::AlignUp(voice_state_size * params.voice_count, info_field_alignment_size); 452 size +=
453 Common::AlignUp(voice_state_size_bytes * params.voice_count, info_field_alignment_size);
464 return size; 454 return size;
465 }; 455 };
466 456
@@ -662,7 +652,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
662 // always assumes the initial release revision (REV1). 652 // always assumes the initial release revision (REV1).
663 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 653 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
664 rb.Push(RESULT_SUCCESS); 654 rb.Push(RESULT_SUCCESS);
665 rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1')); 655 rb.PushIpcInterface<IAudioDevice>(system, buffer_event, Common::MakeMagic('R', 'E', 'V', '1'));
666} 656}
667 657
668void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) { 658void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
@@ -684,7 +674,7 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c
684 674
685 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 675 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
686 rb.Push(RESULT_SUCCESS); 676 rb.Push(RESULT_SUCCESS);
687 rb.PushIpcInterface<IAudioDevice>(system, revision); 677 rb.PushIpcInterface<IAudioDevice>(system, buffer_event, revision);
688} 678}
689 679
690void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { 680void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 37e8b4716..0ee6f9542 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Core { 10namespace Core {
@@ -31,6 +32,7 @@ private:
31 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); 32 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
32 33
33 std::size_t audren_instance_count = 0; 34 std::size_t audren_instance_count = 0;
35 Kernel::KEvent buffer_event;
34}; 36};
35 37
36// Describes a particular audio feature that may be supported in a particular revision. 38// Describes a particular audio feature that may be supported in a particular revision.
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 19c578b3a..ee5ec8cd6 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -50,8 +50,8 @@ public:
50 Enabled, 50 Enabled,
51 }; 51 };
52 52
53 explicit OpusDecoderState(OpusDecoderPtr decoder, u32 sample_rate, u32 channel_count) 53 explicit OpusDecoderState(OpusDecoderPtr decoder_, u32 sample_rate_, u32 channel_count_)
54 : decoder{std::move(decoder)}, sample_rate{sample_rate}, channel_count{channel_count} {} 54 : decoder{std::move(decoder_)}, sample_rate{sample_rate_}, channel_count{channel_count_} {}
55 55
56 // Decodes interleaved Opus packets. Optionally allows reporting time taken to 56 // Decodes interleaved Opus packets. Optionally allows reporting time taken to
57 // perform the decoding, as well as any relevant extra behavior. 57 // perform the decoding, as well as any relevant extra behavior.
@@ -160,9 +160,9 @@ private:
160 160
161class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { 161class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
162public: 162public:
163 explicit IHardwareOpusDecoderManager(Core::System& system_, OpusDecoderState decoder_state) 163 explicit IHardwareOpusDecoderManager(Core::System& system_, OpusDecoderState decoder_state_)
164 : ServiceFramework{system_, "IHardwareOpusDecoderManager"}, decoder_state{ 164 : ServiceFramework{system_, "IHardwareOpusDecoderManager"}, decoder_state{
165 std::move(decoder_state)} { 165 std::move(decoder_state_)} {
166 // clang-format off 166 // clang-format off
167 static const FunctionInfo functions[] = { 167 static const FunctionInfo functions[] = {
168 {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"}, 168 {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"},
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index cee1774d1..d6d2f52e5 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -3,9 +3,18 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <fmt/ostream.h> 5#include <fmt/ostream.h>
6
7#ifdef __GNUC__
8#pragma GCC diagnostic push
9#pragma GCC diagnostic ignored "-Wshadow"
10#endif
6#include <httplib.h> 11#include <httplib.h>
7#include <mbedtls/sha256.h> 12#include <mbedtls/sha256.h>
8#include <nlohmann/json.hpp> 13#include <nlohmann/json.hpp>
14#ifdef __GNUC__
15#pragma GCC diagnostic pop
16#endif
17
9#include "common/hex_util.h" 18#include "common/hex_util.h"
10#include "common/logging/backend.h" 19#include "common/logging/backend.h"
11#include "common/logging/log.h" 20#include "common/logging/log.h"
@@ -178,8 +187,8 @@ bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest,
178 187
179class Boxcat::Client { 188class Boxcat::Client {
180public: 189public:
181 Client(std::string path, u64 title_id, u64 build_id) 190 Client(std::string path_, u64 title_id_, u64 build_id_)
182 : path(std::move(path)), title_id(title_id), build_id(build_id) {} 191 : path(std::move(path_)), title_id(title_id_), build_id(build_id_) {}
183 192
184 DownloadResult DownloadDataZip() { 193 DownloadResult DownloadDataZip() {
185 return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS, 194 return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS,
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp
index 8091db9d7..9d1e6db6a 100644
--- a/src/core/hle/service/hid/controllers/controller_base.cpp
+++ b/src/core/hle/service/hid/controllers/controller_base.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::HID { 7namespace Service::HID {
8 8
9ControllerBase::ControllerBase(Core::System& system) : system(system) {} 9ControllerBase::ControllerBase(Core::System& system_) : system(system_) {}
10ControllerBase::~ControllerBase() = default; 10ControllerBase::~ControllerBase() = default;
11 11
12void ControllerBase::ActivateController() { 12void ControllerBase::ActivateController() {
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index f47a9e61c..1556fb08e 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -18,7 +18,7 @@ class System;
18namespace Service::HID { 18namespace Service::HID {
19class ControllerBase { 19class ControllerBase {
20public: 20public:
21 explicit ControllerBase(Core::System& system); 21 explicit ControllerBase(Core::System& system_);
22 virtual ~ControllerBase(); 22 virtual ~ControllerBase();
23 23
24 // Called when the controller is initialized 24 // Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 9e5df3bb7..d311f754b 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -23,7 +23,7 @@ constexpr f32 Square(s32 num) {
23 return static_cast<f32>(num * num); 23 return static_cast<f32>(num * num);
24} 24}
25 25
26Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {} 26Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {}
27Controller_Gesture::~Controller_Gesture() = default; 27Controller_Gesture::~Controller_Gesture() = default;
28 28
29void Controller_Gesture::OnInit() { 29void Controller_Gesture::OnInit() {
@@ -211,15 +211,16 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Touch
211 } 211 }
212} 212}
213 213
214void Controller_Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, 214void Controller_Gesture::EndGesture(GestureProperties& gesture,
215 TouchType& type, Attribute& attributes, f32 time_difference) { 215 GestureProperties& last_gesture_props, TouchType& type,
216 Attribute& attributes, f32 time_difference) {
216 const auto& last_entry = 217 const auto& last_entry =
217 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; 218 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
218 if (last_gesture.active_points != 0) { 219 if (last_gesture_props.active_points != 0) {
219 switch (last_entry.type) { 220 switch (last_entry.type) {
220 case TouchType::Touch: 221 case TouchType::Touch:
221 if (enable_press_and_tap) { 222 if (enable_press_and_tap) {
222 SetTapEvent(gesture, last_gesture, type, attributes); 223 SetTapEvent(gesture, last_gesture_props, type, attributes);
223 return; 224 return;
224 } 225 }
225 type = TouchType::Cancel; 226 type = TouchType::Cancel;
@@ -234,7 +235,7 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture, GesturePropertie
234 force_update = true; 235 force_update = true;
235 break; 236 break;
236 case TouchType::Pan: 237 case TouchType::Pan:
237 EndPanEvent(gesture, last_gesture, type, time_difference); 238 EndPanEvent(gesture, last_gesture_props, type, time_difference);
238 break; 239 break;
239 default: 240 default:
240 break; 241 break;
@@ -246,10 +247,11 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture, GesturePropertie
246 } 247 }
247} 248}
248 249
249void Controller_Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, 250void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
250 TouchType& type, Attribute& attributes) { 251 GestureProperties& last_gesture_props, TouchType& type,
252 Attribute& attributes) {
251 type = TouchType::Tap; 253 type = TouchType::Tap;
252 gesture = last_gesture; 254 gesture = last_gesture_props;
253 force_update = true; 255 force_update = true;
254 f32 tap_time_difference = 256 f32 tap_time_difference =
255 static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); 257 static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000);
@@ -259,8 +261,9 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, GestureProperti
259 } 261 }
260} 262}
261 263
262void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, 264void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture,
263 TouchType& type, f32 time_difference) { 265 GestureProperties& last_gesture_props, TouchType& type,
266 f32 time_difference) {
264 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; 267 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
265 const auto& last_entry = 268 const auto& last_entry =
266 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; 269 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
@@ -272,13 +275,14 @@ void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GesturePrope
272 last_pan_time_difference = time_difference; 275 last_pan_time_difference = time_difference;
273 276
274 // Promote to pinch type 277 // Promote to pinch type
275 if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { 278 if (std::abs(gesture.average_distance - last_gesture_props.average_distance) >
279 pinch_threshold) {
276 type = TouchType::Pinch; 280 type = TouchType::Pinch;
277 cur_entry.scale = gesture.average_distance / last_gesture.average_distance; 281 cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance;
278 } 282 }
279 283
280 const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture.angle) / 284 const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) /
281 (1 + (gesture.angle * last_gesture.angle))); 285 (1 + (gesture.angle * last_gesture_props.angle)));
282 // Promote to rotate type 286 // Promote to rotate type
283 if (std::abs(angle_between_two_lines) > angle_threshold) { 287 if (std::abs(angle_between_two_lines) > angle_threshold) {
284 type = TouchType::Rotate; 288 type = TouchType::Rotate;
@@ -287,8 +291,9 @@ void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GesturePrope
287 } 291 }
288} 292}
289 293
290void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, 294void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
291 TouchType& type, f32 time_difference) { 295 GestureProperties& last_gesture_props, TouchType& type,
296 f32 time_difference) {
292 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; 297 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
293 const auto& last_entry = 298 const auto& last_entry =
294 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; 299 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
@@ -301,7 +306,7 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperti
301 306
302 // Set swipe event with parameters 307 // Set swipe event with parameters
303 if (curr_vel > swipe_threshold) { 308 if (curr_vel > swipe_threshold) {
304 SetSwipeEvent(gesture, last_gesture, type); 309 SetSwipeEvent(gesture, last_gesture_props, type);
305 return; 310 return;
306 } 311 }
307 312
@@ -312,13 +317,13 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperti
312 force_update = true; 317 force_update = true;
313} 318}
314 319
315void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, 320void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture,
316 TouchType& type) { 321 GestureProperties& last_gesture_props, TouchType& type) {
317 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; 322 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
318 const auto& last_entry = 323 const auto& last_entry =
319 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; 324 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
320 type = TouchType::Swipe; 325 type = TouchType::Swipe;
321 gesture = last_gesture; 326 gesture = last_gesture_props;
322 force_update = true; 327 force_update = true;
323 cur_entry.delta_x = last_entry.delta_x; 328 cur_entry.delta_x = last_entry.delta_x;
324 cur_entry.delta_y = last_entry.delta_y; 329 cur_entry.delta_y = last_entry.delta_y;
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 18110a6ad..f46e29411 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -128,32 +128,34 @@ private:
128 void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); 128 void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference);
129 129
130 // Terminates exiting gesture 130 // Terminates exiting gesture
131 void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, 131 void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
132 Attribute& attributes, f32 time_difference); 132 TouchType& type, Attribute& attributes, f32 time_difference);
133 133
134 // Set current event to a tap event 134 // Set current event to a tap event
135 void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, 135 void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
136 Attribute& attributes); 136 TouchType& type, Attribute& attributes);
137 137
138 // Calculates and set the extra parameters related to a pan event 138 // Calculates and set the extra parameters related to a pan event
139 void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, 139 void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
140 TouchType& type, f32 time_difference); 140 TouchType& type, f32 time_difference);
141 141
142 // Terminates the pan event 142 // Terminates the pan event
143 void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, 143 void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
144 f32 time_difference); 144 TouchType& type, f32 time_difference);
145 145
146 // Set current event to a swipe event 146 // Set current event to a swipe event
147 void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, 147 void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
148 TouchType& type); 148 TouchType& type);
149 149
150 // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned 150 // Returns an unused finger id, if there is no fingers available std::nullopt is returned.
151 std::optional<size_t> GetUnusedFingerID() const; 151 std::optional<size_t> GetUnusedFingerID() const;
152 152
153 /** If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no 153 /**
154 * If the touch is new it tries to assign a new finger id, if there is no fingers available no
154 * changes will be made. Updates the coordinates if the finger id it's already set. If the touch 155 * changes will be made. Updates the coordinates if the finger id it's already set. If the touch
155 * ends delays the output by one frame to set the end_touch flag before finally freeing the 156 * ends delays the output by one frame to set the end_touch flag before finally freeing the
156 * finger id */ 157 * finger id
158 */
157 size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, 159 size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input,
158 size_t finger_id); 160 size_t finger_id);
159 161
diff --git a/src/core/hle/service/mii/manager.h b/src/core/hle/service/mii/manager.h
index 2106a528a..ec7efa5f7 100644
--- a/src/core/hle/service/mii/manager.h
+++ b/src/core/hle/service/mii/manager.h
@@ -89,7 +89,7 @@ static_assert(std::has_unique_object_representations_v<MiiInfo>,
89#pragma pack(push, 4) 89#pragma pack(push, 4)
90 90
91struct MiiInfoElement { 91struct MiiInfoElement {
92 MiiInfoElement(const MiiInfo& info, Source source) : info{info}, source{source} {} 92 MiiInfoElement(const MiiInfo& info_, Source source_) : info{info_}, source{source_} {}
93 93
94 MiiInfo info{}; 94 MiiInfo info{};
95 Source source{}; 95 Source source{};
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 26be9e45b..81f150a88 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -253,8 +253,8 @@ private:
253 253
254class MiiDBModule final : public ServiceFramework<MiiDBModule> { 254class MiiDBModule final : public ServiceFramework<MiiDBModule> {
255public: 255public:
256 explicit MiiDBModule(Core::System& system_, const char* name) 256 explicit MiiDBModule(Core::System& system_, const char* name_)
257 : ServiceFramework{system_, name} { 257 : ServiceFramework{system_, name_} {
258 // clang-format off 258 // clang-format off
259 static const FunctionInfo functions[] = { 259 static const FunctionInfo functions[] = {
260 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, 260 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 94ef3983a..76e3832df 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -368,7 +368,7 @@ private:
368 }, 368 },
369 }; 369 };
370 370
371 IPC::ResponseBuilder rb{ctx, 2 + sizeof(IpConfigInfo) / sizeof(u32)}; 371 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
372 rb.Push(RESULT_SUCCESS); 372 rb.Push(RESULT_SUCCESS);
373 rb.PushRaw<IpConfigInfo>(ip_config_info); 373 rb.PushRaw<IpConfigInfo>(ip_config_info);
374 } 374 }
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index b37f023df..5b73a5a34 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -21,7 +21,7 @@ namespace Service::Nvidia::Devices {
21/// implement the ioctl interface. 21/// implement the ioctl interface.
22class nvdevice { 22class nvdevice {
23public: 23public:
24 explicit nvdevice(Core::System& system) : system{system} {} 24 explicit nvdevice(Core::System& system_) : system{system_} {}
25 virtual ~nvdevice() = default; 25 virtual ~nvdevice() = default;
26 26
27 /** 27 /**
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index bbef04a29..2cc0da124 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -52,7 +52,6 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
52 addr, offset, width, height, stride, static_cast<PixelFormat>(format), 52 addr, offset, width, height, stride, static_cast<PixelFormat>(format),
53 transform, crop_rect}; 53 transform, crop_rect};
54 54
55 system.GetPerfStats().EndGameFrame();
56 system.GetPerfStats().EndSystemFrame(); 55 system.GetPerfStats().EndSystemFrame();
57 system.GPU().SwapBuffers(&framebuffer); 56 system.GPU().SwapBuffers(&framebuffer);
58 system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs()); 57 system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 229bf6350..24e3151cb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -48,13 +48,13 @@ private:
48 public: 48 public:
49 constexpr BufferMap() = default; 49 constexpr BufferMap() = default;
50 50
51 constexpr BufferMap(GPUVAddr start_addr, std::size_t size) 51 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_)
52 : start_addr{start_addr}, end_addr{start_addr + size} {} 52 : start_addr{start_addr_}, end_addr{start_addr_ + size_} {}
53 53
54 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr, 54 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_,
55 bool is_allocated) 55 bool is_allocated_)
56 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr}, 56 : start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_},
57 is_allocated{is_allocated} {} 57 is_allocated{is_allocated_} {}
58 58
59 constexpr VAddr StartAddr() const { 59 constexpr VAddr StartAddr() const {
60 return start_addr; 60 return start_addr;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index 14d0d210a..da10f5f41 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -27,13 +27,13 @@ protected:
27 public: 27 public:
28 constexpr BufferMap() = default; 28 constexpr BufferMap() = default;
29 29
30 constexpr BufferMap(GPUVAddr start_addr, std::size_t size) 30 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_)
31 : start_addr{start_addr}, end_addr{start_addr + size} {} 31 : start_addr{start_addr_}, end_addr{start_addr_ + size_} {}
32 32
33 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr, 33 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_,
34 bool is_allocated) 34 bool is_allocated_)
35 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr}, 35 : start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_},
36 is_allocated{is_allocated} {} 36 is_allocated{is_allocated_} {}
37 37
38 constexpr VAddr StartAddr() const { 38 constexpr VAddr StartAddr() const {
39 return start_addr; 39 return start_addr;
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/syncpoint_manager.cpp
index 0151a03b7..3b6f55526 100644
--- a/src/core/hle/service/nvdrv/syncpoint_manager.cpp
+++ b/src/core/hle/service/nvdrv/syncpoint_manager.cpp
@@ -8,7 +8,7 @@
8 8
9namespace Service::Nvidia { 9namespace Service::Nvidia {
10 10
11SyncpointManager::SyncpointManager(Tegra::GPU& gpu) : gpu{gpu} {} 11SyncpointManager::SyncpointManager(Tegra::GPU& gpu_) : gpu{gpu_} {}
12 12
13SyncpointManager::~SyncpointManager() = default; 13SyncpointManager::~SyncpointManager() = default;
14 14
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.h b/src/core/hle/service/nvdrv/syncpoint_manager.h
index d395c5d0b..99f286474 100644
--- a/src/core/hle/service/nvdrv/syncpoint_manager.h
+++ b/src/core/hle/service/nvdrv/syncpoint_manager.h
@@ -18,7 +18,7 @@ namespace Service::Nvidia {
18 18
19class SyncpointManager final { 19class SyncpointManager final {
20public: 20public:
21 explicit SyncpointManager(Tegra::GPU& gpu); 21 explicit SyncpointManager(Tegra::GPU& gpu_);
22 ~SyncpointManager(); 22 ~SyncpointManager();
23 23
24 /** 24 /**
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 0b6e7430b..59ddf6298 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -13,8 +13,8 @@
13 13
14namespace Service::NVFlinger { 14namespace Service::NVFlinger {
15 15
16BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id) 16BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_)
17 : id(id), layer_id(layer_id), buffer_wait_event{kernel} { 17 : id(id_), layer_id(layer_id_), buffer_wait_event{kernel} {
18 Kernel::KAutoObject::Create(std::addressof(buffer_wait_event)); 18 Kernel::KAutoObject::Create(std::addressof(buffer_wait_event));
19 buffer_wait_event.Initialize("BufferQueue:WaitEvent"); 19 buffer_wait_event.Initialize("BufferQueue:WaitEvent");
20} 20}
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 4ec0b1506..61e337ac5 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -54,7 +54,7 @@ public:
54 NativeWindowFormat = 2, 54 NativeWindowFormat = 2,
55 }; 55 };
56 56
57 explicit BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id); 57 explicit BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_);
58 ~BufferQueue(); 58 ~BufferQueue();
59 59
60 enum class BufferTransformFlags : u32 { 60 enum class BufferTransformFlags : u32 {
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 7fb9133c7..d1dbc659b 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -61,7 +61,7 @@ void NVFlinger::SplitVSync() {
61 } 61 }
62} 62}
63 63
64NVFlinger::NVFlinger(Core::System& system) : system(system) { 64NVFlinger::NVFlinger(Core::System& system_) : system(system_) {
65 displays.emplace_back(0, "Default", system); 65 displays.emplace_back(0, "Default", system);
66 displays.emplace_back(1, "External", system); 66 displays.emplace_back(1, "External", system);
67 displays.emplace_back(2, "Edid", system); 67 displays.emplace_back(2, "Edid", system);
@@ -139,11 +139,15 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
139 } 139 }
140 140
141 const u64 layer_id = next_layer_id++; 141 const u64 layer_id = next_layer_id++;
142 CreateLayerAtId(*display, layer_id);
143 return layer_id;
144}
145
146void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
142 const u32 buffer_queue_id = next_buffer_queue_id++; 147 const u32 buffer_queue_id = next_buffer_queue_id++;
143 buffer_queues.emplace_back( 148 buffer_queues.emplace_back(
144 std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id)); 149 std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id));
145 display->CreateLayer(layer_id, *buffer_queues.back()); 150 display.CreateLayer(layer_id, *buffer_queues.back());
146 return layer_id;
147} 151}
148 152
149void NVFlinger::CloseLayer(u64 layer_id) { 153void NVFlinger::CloseLayer(u64 layer_id) {
@@ -154,9 +158,9 @@ void NVFlinger::CloseLayer(u64 layer_id) {
154 } 158 }
155} 159}
156 160
157std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const { 161std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
158 const auto lock_guard = Lock(); 162 const auto lock_guard = Lock();
159 const auto* const layer = FindLayer(display_id, layer_id); 163 const auto* const layer = FindOrCreateLayer(display_id, layer_id);
160 164
161 if (layer == nullptr) { 165 if (layer == nullptr) {
162 return std::nullopt; 166 return std::nullopt;
@@ -232,6 +236,24 @@ const VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
232 return display->FindLayer(layer_id); 236 return display->FindLayer(layer_id);
233} 237}
234 238
239VI::Layer* NVFlinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
240 auto* const display = FindDisplay(display_id);
241
242 if (display == nullptr) {
243 return nullptr;
244 }
245
246 auto* layer = display->FindLayer(layer_id);
247
248 if (layer == nullptr) {
249 LOG_DEBUG(Service, "Layer at id {} not found. Trying to create it.", layer_id);
250 CreateLayerAtId(*display, layer_id);
251 return display->FindLayer(layer_id);
252 }
253
254 return layer;
255}
256
235void NVFlinger::Compose() { 257void NVFlinger::Compose() {
236 for (auto& display : displays) { 258 for (auto& display : displays) {
237 // Trigger vsync for this display at the end of drawing 259 // Trigger vsync for this display at the end of drawing
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index b0febdaec..d80fd07ef 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -45,7 +45,7 @@ class BufferQueue;
45 45
46class NVFlinger final { 46class NVFlinger final {
47public: 47public:
48 explicit NVFlinger(Core::System& system); 48 explicit NVFlinger(Core::System& system_);
49 ~NVFlinger(); 49 ~NVFlinger();
50 50
51 /// Sets the NVDrv module instance to use to send buffers to the GPU. 51 /// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -67,7 +67,7 @@ public:
67 /// Finds the buffer queue ID of the specified layer in the specified display. 67 /// Finds the buffer queue ID of the specified layer in the specified display.
68 /// 68 ///
69 /// If an invalid display ID or layer ID is provided, then an empty optional is returned. 69 /// If an invalid display ID or layer ID is provided, then an empty optional is returned.
70 [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const; 70 [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id);
71 71
72 /// Gets the vsync event for the specified display. 72 /// Gets the vsync event for the specified display.
73 /// 73 ///
@@ -100,6 +100,14 @@ private:
100 /// Finds the layer identified by the specified ID in the desired display. 100 /// Finds the layer identified by the specified ID in the desired display.
101 [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; 101 [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
102 102
103 /// Finds the layer identified by the specified ID in the desired display,
104 /// or creates the layer if it is not found.
105 /// To be used when the system expects the specified ID to already exist.
106 [[nodiscard]] VI::Layer* FindOrCreateLayer(u64 display_id, u64 layer_id);
107
108 /// Creates a layer with the specified layer ID in the desired display.
109 void CreateLayerAtId(VI::Display& display, u64 layer_id);
110
103 static void VSyncThread(NVFlinger& nv_flinger); 111 static void VSyncThread(NVFlinger& nv_flinger);
104 112
105 void SplitVSync(); 113 void SplitVSync();
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index e4d155c86..908e0a1e3 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -7,8 +7,8 @@
7namespace Service::PCTL { 7namespace Service::PCTL {
8 8
9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name, 9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
10 Capability capability) 10 Capability capability_)
11 : Interface{system_, std::move(module_), name, capability} { 11 : Interface{system_, std::move(module_), name, capability_} {
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &PCTL::CreateService, "CreateService"}, 13 {0, &PCTL::CreateService, "CreateService"},
14 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, 14 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index fd0a1e486..ea3b97823 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -15,7 +15,7 @@ namespace Service::PCTL {
15class PCTL final : public Module::Interface { 15class PCTL final : public Module::Interface {
16public: 16public:
17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name, 17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
18 Capability capability); 18 Capability capability_);
19 ~PCTL() override; 19 ~PCTL() override;
20}; 20};
21 21
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index f4715935d..a43185c44 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -31,8 +31,8 @@ std::optional<Kernel::KProcess*> SearchProcessList(
31 31
32void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx, 32void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
33 const std::vector<Kernel::KProcess*>& process_list) { 33 const std::vector<Kernel::KProcess*>& process_list) {
34 const auto process = SearchProcessList(process_list, [](const auto& process) { 34 const auto process = SearchProcessList(process_list, [](const auto& proc) {
35 return process->GetProcessID() == Kernel::KProcess::ProcessIDMin; 35 return proc->GetProcessID() == Kernel::KProcess::ProcessIDMin;
36 }); 36 });
37 37
38 IPC::ResponseBuilder rb{ctx, 4}; 38 IPC::ResponseBuilder rb{ctx, 4};
@@ -100,8 +100,8 @@ private:
100 LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id); 100 LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id);
101 101
102 const auto process = 102 const auto process =
103 SearchProcessList(kernel.GetProcessList(), [title_id](const auto& process) { 103 SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) {
104 return process->GetTitleID() == title_id; 104 return proc->GetTitleID() == title_id;
105 }); 105 });
106 106
107 if (!process.has_value()) { 107 if (!process.has_value()) {
@@ -140,8 +140,8 @@ private:
140 140
141 LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); 141 LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
142 142
143 const auto process = SearchProcessList(process_list, [process_id](const auto& process) { 143 const auto process = SearchProcessList(process_list, [process_id](const auto& proc) {
144 return process->GetProcessID() == process_id; 144 return proc->GetProcessID() == process_id;
145 }); 145 });
146 146
147 if (!process.has_value()) { 147 if (!process.has_value()) {
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 00e683c2f..fa61a5c7b 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -107,21 +107,22 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
107 ASSERT(!port_installed); 107 ASSERT(!port_installed);
108 108
109 auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); 109 auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
110 port->SetHleHandler(shared_from_this()); 110 port->SetSessionHandler(shared_from_this());
111 port_installed = true; 111 port_installed = true;
112} 112}
113 113
114void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { 114Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
115 const auto guard = LockService(); 115 const auto guard = LockService();
116 116
117 ASSERT(!port_installed); 117 ASSERT(!port_installed);
118 118
119 auto* port = Kernel::KPort::Create(kernel); 119 auto* port = Kernel::KPort::Create(kernel);
120 port->Initialize(max_sessions, false, service_name); 120 port->Initialize(max_sessions, false, service_name);
121 port->GetServerPort().SetHleHandler(shared_from_this()); 121 port->GetServerPort().SetSessionHandler(shared_from_this());
122 kernel.AddNamedPort(service_name, &port->GetClientPort());
123 122
124 port_installed = true; 123 port_installed = true;
124
125 return port->GetClientPort();
125} 126}
126 127
127void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { 128void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
@@ -132,6 +133,16 @@ void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* function
132 } 133 }
133} 134}
134 135
136void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions,
137 std::size_t n) {
138 handlers_tipc.reserve(handlers_tipc.size() + n);
139 for (std::size_t i = 0; i < n; ++i) {
140 // Usually this array is sorted by id already, so hint to insert at the end
141 handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header,
142 functions[i]);
143 }
144}
145
135void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, 146void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx,
136 const FunctionInfoBase* info) { 147 const FunctionInfoBase* info) {
137 auto cmd_buf = ctx.CommandBuffer(); 148 auto cmd_buf = ctx.CommandBuffer();
@@ -166,33 +177,55 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
166 handler_invoker(this, info->handler_callback, ctx); 177 handler_invoker(this, info->handler_callback, ctx);
167} 178}
168 179
169ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { 180void ServiceFrameworkBase::InvokeRequestTipc(Kernel::HLERequestContext& ctx) {
181 boost::container::flat_map<u32, FunctionInfoBase>::iterator itr;
182
183 itr = handlers_tipc.find(ctx.GetCommand());
184
185 const FunctionInfoBase* info = itr == handlers_tipc.end() ? nullptr : &itr->second;
186 if (info == nullptr || info->handler_callback == nullptr) {
187 return ReportUnimplementedFunction(ctx, info);
188 }
189
190 LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
191 handler_invoker(this, info->handler_callback, ctx);
192}
193
194ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
195 Kernel::HLERequestContext& ctx) {
170 const auto guard = LockService(); 196 const auto guard = LockService();
171 197
172 switch (context.GetCommandType()) { 198 switch (ctx.GetCommandType()) {
173 case IPC::CommandType::Close: { 199 case IPC::CommandType::Close:
174 IPC::ResponseBuilder rb{context, 2}; 200 case IPC::CommandType::TIPC_Close: {
201 session.Close();
202 IPC::ResponseBuilder rb{ctx, 2};
175 rb.Push(RESULT_SUCCESS); 203 rb.Push(RESULT_SUCCESS);
176 return IPC::ERR_REMOTE_PROCESS_DEAD; 204 return IPC::ERR_REMOTE_PROCESS_DEAD;
177 } 205 }
178 case IPC::CommandType::ControlWithContext: 206 case IPC::CommandType::ControlWithContext:
179 case IPC::CommandType::Control: { 207 case IPC::CommandType::Control: {
180 system.ServiceManager().InvokeControlRequest(context); 208 system.ServiceManager().InvokeControlRequest(ctx);
181 break; 209 break;
182 } 210 }
183 case IPC::CommandType::RequestWithContext: 211 case IPC::CommandType::RequestWithContext:
184 case IPC::CommandType::Request: { 212 case IPC::CommandType::Request: {
185 InvokeRequest(context); 213 InvokeRequest(ctx);
186 break; 214 break;
187 } 215 }
188 default: 216 default:
189 UNIMPLEMENTED_MSG("command_type={}", context.GetCommandType()); 217 if (ctx.IsTipc()) {
218 InvokeRequestTipc(ctx);
219 break;
220 }
221
222 UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType());
190 } 223 }
191 224
192 // If emulation was shutdown, we are closing service threads, do not write the response back to 225 // If emulation was shutdown, we are closing service threads, do not write the response back to
193 // memory that may be shutting down as well. 226 // memory that may be shutting down as well.
194 if (system.IsPoweredOn()) { 227 if (system.IsPoweredOn()) {
195 context.WriteToOutgoingCommandBuffer(context.GetThread()); 228 ctx.WriteToOutgoingCommandBuffer(ctx.GetThread());
196 } 229 }
197 230
198 return RESULT_SUCCESS; 231 return RESULT_SUCCESS;
@@ -207,7 +240,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
207 240
208 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); 241 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
209 242
210 SM::ServiceManager::InstallInterfaces(sm, system); 243 system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory);
211 244
212 Account::InstallInterfaces(system); 245 Account::InstallInterfaces(system);
213 AM::InstallInterfaces(*sm, *nv_flinger, system); 246 AM::InstallInterfaces(*sm, *nv_flinger, system);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 884951428..4c048173b 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -21,7 +21,9 @@ class System;
21 21
22namespace Kernel { 22namespace Kernel {
23class HLERequestContext; 23class HLERequestContext;
24} 24class KClientPort;
25class KServerSession;
26} // namespace Kernel
25 27
26namespace Service { 28namespace Service {
27 29
@@ -64,12 +66,19 @@ public:
64 66
65 /// Creates a port pair and registers this service with the given ServiceManager. 67 /// Creates a port pair and registers this service with the given ServiceManager.
66 void InstallAsService(SM::ServiceManager& service_manager); 68 void InstallAsService(SM::ServiceManager& service_manager);
67 /// Creates a port pair and registers it on the kernel's global port registry. 69
68 void InstallAsNamedPort(Kernel::KernelCore& kernel); 70 /// Invokes a service request routine using the HIPC protocol.
69 /// Invokes a service request routine.
70 void InvokeRequest(Kernel::HLERequestContext& ctx); 71 void InvokeRequest(Kernel::HLERequestContext& ctx);
72
73 /// Invokes a service request routine using the HIPC protocol.
74 void InvokeRequestTipc(Kernel::HLERequestContext& ctx);
75
76 /// Creates a port pair and registers it on the kernel's global port registry.
77 Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel);
78
71 /// Handles a synchronization request for the service. 79 /// Handles a synchronization request for the service.
72 ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override; 80 ResultCode HandleSyncRequest(Kernel::KServerSession& session,
81 Kernel::HLERequestContext& context) override;
73 82
74protected: 83protected:
75 /// Member-function pointer type of SyncRequest handlers. 84 /// Member-function pointer type of SyncRequest handlers.
@@ -102,6 +111,7 @@ private:
102 ~ServiceFrameworkBase() override; 111 ~ServiceFrameworkBase() override;
103 112
104 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); 113 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
114 void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
105 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); 115 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
106 116
107 /// Identifier string used to connect to the service. 117 /// Identifier string used to connect to the service.
@@ -116,6 +126,7 @@ private:
116 /// Function used to safely up-cast pointers to the derived class before invoking a handler. 126 /// Function used to safely up-cast pointers to the derived class before invoking a handler.
117 InvokerFn* handler_invoker; 127 InvokerFn* handler_invoker;
118 boost::container::flat_map<u32, FunctionInfoBase> handlers; 128 boost::container::flat_map<u32, FunctionInfoBase> handlers;
129 boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
119 130
120 /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. 131 /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
121 Common::SpinLock lock_service; 132 Common::SpinLock lock_service;
@@ -144,17 +155,17 @@ protected:
144 /** 155 /**
145 * Constructs a FunctionInfo for a function. 156 * Constructs a FunctionInfo for a function.
146 * 157 *
147 * @param expected_header request header in the command buffer which will trigger dispatch 158 * @param expected_header_ request header in the command buffer which will trigger dispatch
148 * to this handler 159 * to this handler
149 * @param handler_callback member function in this service which will be called to handle 160 * @param handler_callback_ member function in this service which will be called to handle
150 * the request 161 * the request
151 * @param name human-friendly name for the request. Used mostly for logging purposes. 162 * @param name_ human-friendly name for the request. Used mostly for logging purposes.
152 */ 163 */
153 FunctionInfo(u32 expected_header, HandlerFnP<Self> handler_callback, const char* name) 164 FunctionInfo(u32 expected_header_, HandlerFnP<Self> handler_callback_, const char* name_)
154 : FunctionInfoBase{ 165 : FunctionInfoBase{
155 expected_header, 166 expected_header_,
156 // Type-erase member function pointer by casting it down to the base class. 167 // Type-erase member function pointer by casting it down to the base class.
157 static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback), name} {} 168 static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
158 }; 169 };
159 170
160 /** 171 /**
@@ -183,6 +194,20 @@ protected:
183 RegisterHandlersBase(functions, n); 194 RegisterHandlersBase(functions, n);
184 } 195 }
185 196
197 /// Registers handlers in the service.
198 template <std::size_t N>
199 void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) {
200 RegisterHandlersTipc(functions, N);
201 }
202
203 /**
204 * Registers handlers in the service. Usually prefer using the other RegisterHandlers
205 * overload in order to avoid needing to specify the array size.
206 */
207 void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) {
208 RegisterHandlersBaseTipc(functions, n);
209 }
210
186private: 211private:
187 /** 212 /**
188 * This function is used to allow invocation of pointers to handlers stored in the base class 213 * This function is used to allow invocation of pointers to handlers stored in the base class
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index ee026e22f..147f12147 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -4,8 +4,13 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
7#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/k_client_port.h"
8#include "core/hle/kernel/k_client_session.h" 10#include "core/hle/kernel/k_client_session.h"
11#include "core/hle/kernel/k_port.h"
12#include "core/hle/kernel/k_scoped_resource_reservation.h"
13#include "core/hle/kernel/k_server_port.h"
9#include "core/hle/kernel/k_server_session.h" 14#include "core/hle/kernel/k_server_session.h"
10#include "core/hle/kernel/k_session.h" 15#include "core/hle/kernel/k_session.h"
11#include "core/hle/service/sm/controller.h" 16#include "core/hle/service/sm/controller.h"
@@ -13,7 +18,7 @@
13namespace Service::SM { 18namespace Service::SM {
14 19
15void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { 20void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); 21 ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain");
17 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); 22 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId());
18 ctx.Session()->ConvertToDomain(); 23 ctx.Session()->ConvertToDomain();
19 24
@@ -26,15 +31,43 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
26 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong 31 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
27 // and that we probably want to actually make an entirely new Session, but we still need to 32 // and that we probably want to actually make an entirely new Session, but we still need to
28 // verify this on hardware. 33 // verify this on hardware.
34
29 LOG_DEBUG(Service, "called"); 35 LOG_DEBUG(Service, "called");
30 36
37 auto& kernel = system.Kernel();
38 auto* session = ctx.Session()->GetParent();
39 auto* port = session->GetParent()->GetParent();
40
41 // Reserve a new session from the process resource limit.
42 Kernel::KScopedResourceReservation session_reservation(
43 kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
44 if (!session_reservation.Succeeded()) {
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(Kernel::ResultLimitReached);
47 }
48
49 // Create a new session.
50 auto* clone = Kernel::KSession::Create(kernel);
51 clone->Initialize(&port->GetClientPort(), session->GetName());
52
53 // Commit the session reservation.
54 session_reservation.Commit();
55
56 // Enqueue the session with the named port.
57 port->EnqueueSession(&clone->GetServerSession());
58
59 // Set the session request manager.
60 clone->GetServerSession().SetSessionRequestManager(
61 session->GetServerSession().GetSessionRequestManager());
62
63 // We succeeded.
31 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 64 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
32 rb.Push(RESULT_SUCCESS); 65 rb.Push(RESULT_SUCCESS);
33 rb.PushMoveObjects(ctx.Session()->GetParent()->GetClientSession()); 66 rb.PushMoveObjects(clone->GetClientSession());
34} 67}
35 68
36void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { 69void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
37 LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject"); 70 LOG_DEBUG(Service, "called");
38 71
39 CloneCurrentObject(ctx); 72 CloneCurrentObject(ctx);
40} 73}
@@ -44,7 +77,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
44 77
45 IPC::ResponseBuilder rb{ctx, 3}; 78 IPC::ResponseBuilder rb{ctx, 3};
46 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
47 rb.Push<u16>(0x1000); 80 rb.Push<u16>(0x8000);
48} 81}
49 82
50// https://switchbrew.org/wiki/IPC_Marshalling 83// https://switchbrew.org/wiki/IPC_Marshalling
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 568effbc9..a9bc7da74 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -9,6 +9,7 @@
9#include "core/hle/kernel/k_client_port.h" 9#include "core/hle/kernel/k_client_port.h"
10#include "core/hle/kernel/k_client_session.h" 10#include "core/hle/kernel/k_client_session.h"
11#include "core/hle/kernel/k_port.h" 11#include "core/hle/kernel/k_port.h"
12#include "core/hle/kernel/k_scoped_resource_reservation.h"
12#include "core/hle/kernel/k_server_port.h" 13#include "core/hle/kernel/k_server_port.h"
13#include "core/hle/kernel/k_server_session.h" 14#include "core/hle/kernel/k_server_session.h"
14#include "core/hle/kernel/k_session.h" 15#include "core/hle/kernel/k_session.h"
@@ -18,6 +19,7 @@
18 19
19namespace Service::SM { 20namespace Service::SM {
20 21
22constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2);
21constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); 23constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
22constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); 24constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
23constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); 25constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
@@ -34,20 +36,17 @@ static ResultCode ValidateServiceName(const std::string& name) {
34 LOG_ERROR(Service_SM, "Invalid service name! service={}", name); 36 LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
35 return ERR_INVALID_NAME; 37 return ERR_INVALID_NAME;
36 } 38 }
37 if (name.rfind('\0') != std::string::npos) {
38 LOG_ERROR(Service_SM, "A non null terminated service was passed");
39 return ERR_INVALID_NAME;
40 }
41 return RESULT_SUCCESS; 39 return RESULT_SUCCESS;
42} 40}
43 41
44void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) { 42Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
45 ASSERT(self->sm_interface.expired()); 43 ASSERT(self.sm_interface.expired());
46 44
47 auto sm = std::make_shared<SM>(self, system); 45 auto sm = std::make_shared<SM>(self, system);
48 sm->InstallAsNamedPort(system.Kernel()); 46 self.sm_interface = sm;
49 self->sm_interface = sm; 47 self.controller_interface = std::make_unique<Controller>(system);
50 self->controller_interface = std::make_unique<Controller>(system); 48
49 return sm->CreatePort(system.Kernel());
51} 50}
52 51
53ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name, 52ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
@@ -107,52 +106,81 @@ SM::~SM() = default;
107void SM::Initialize(Kernel::HLERequestContext& ctx) { 106void SM::Initialize(Kernel::HLERequestContext& ctx) {
108 LOG_DEBUG(Service_SM, "called"); 107 LOG_DEBUG(Service_SM, "called");
109 108
109 is_initialized = true;
110
110 IPC::ResponseBuilder rb{ctx, 2}; 111 IPC::ResponseBuilder rb{ctx, 2};
111 rb.Push(RESULT_SUCCESS); 112 rb.Push(RESULT_SUCCESS);
112} 113}
113 114
114void SM::GetService(Kernel::HLERequestContext& ctx) { 115void SM::GetService(Kernel::HLERequestContext& ctx) {
115 IPC::RequestParser rp{ctx}; 116 auto result = GetServiceImpl(ctx);
117 if (result.Succeeded()) {
118 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
119 rb.Push(result.Code());
120 rb.PushMoveObjects(result.Unwrap());
121 } else {
122 IPC::ResponseBuilder rb{ctx, 2};
123 rb.Push(result.Code());
124 }
125}
126
127void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) {
128 auto result = GetServiceImpl(ctx);
129 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
130 rb.Push(result.Code());
131 rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
132}
133
134static std::string PopServiceName(IPC::RequestParser& rp) {
116 auto name_buf = rp.PopRaw<std::array<char, 8>>(); 135 auto name_buf = rp.PopRaw<std::array<char, 8>>();
117 auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); 136 std::string result;
137 for (const auto& c : name_buf) {
138 if (c >= ' ' && c <= '~') {
139 result.push_back(c);
140 }
141 }
142 return result;
143}
144
145ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) {
146 if (!is_initialized) {
147 return ERR_NOT_INITIALIZED;
148 }
118 149
119 std::string name(name_buf.begin(), end); 150 IPC::RequestParser rp{ctx};
151 std::string name(PopServiceName(rp));
120 152
121 auto result = service_manager->GetServicePort(name); 153 // Find the named port.
154 auto result = service_manager.GetServicePort(name);
122 if (result.Failed()) { 155 if (result.Failed()) {
123 IPC::ResponseBuilder rb{ctx, 2};
124 rb.Push(result.Code());
125 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); 156 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw);
126 if (name.length() == 0) 157 return result.Code();
127 return; // LibNX Fix
128 UNIMPLEMENTED();
129 return;
130 } 158 }
131
132 auto* port = result.Unwrap(); 159 auto* port = result.Unwrap();
133 160
161 // Reserve a new session from the process resource limit.
162 Kernel::KScopedResourceReservation session_reservation(
163 kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
164 R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached);
165
166 // Create a new session.
134 auto* session = Kernel::KSession::Create(kernel); 167 auto* session = Kernel::KSession::Create(kernel);
135 session->Initialize(&port->GetClientPort(), std::move(name)); 168 session->Initialize(&port->GetClientPort(), std::move(name));
136 169
137 if (port->GetServerPort().GetHLEHandler()) { 170 // Commit the session reservation.
138 port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); 171 session_reservation.Commit();
139 } else { 172
140 port->EnqueueSession(&session->GetServerSession()); 173 // Enqueue the session with the named port.
141 } 174 port->EnqueueSession(&session->GetServerSession());
142 175
143 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); 176 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
144 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 177
145 rb.Push(RESULT_SUCCESS); 178 return MakeResult(&session->GetClientSession());
146 rb.PushMoveObjects(session->GetClientSession());
147} 179}
148 180
149void SM::RegisterService(Kernel::HLERequestContext& ctx) { 181void SM::RegisterService(Kernel::HLERequestContext& ctx) {
150 IPC::RequestParser rp{ctx}; 182 IPC::RequestParser rp{ctx};
151 183 std::string name(PopServiceName(rp));
152 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
153 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
154
155 const std::string name(name_buf.begin(), end);
156 184
157 const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); 185 const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
158 const auto max_session_count = rp.PopRaw<u32>(); 186 const auto max_session_count = rp.PopRaw<u32>();
@@ -160,7 +188,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
160 LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, 188 LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
161 max_session_count, is_light); 189 max_session_count, is_light);
162 190
163 auto handle = service_manager->RegisterService(name, max_session_count); 191 auto handle = service_manager.RegisterService(name, max_session_count);
164 if (handle.Failed()) { 192 if (handle.Failed()) {
165 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", 193 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
166 handle.Code().raw); 194 handle.Code().raw);
@@ -178,28 +206,31 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
178 206
179void SM::UnregisterService(Kernel::HLERequestContext& ctx) { 207void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
180 IPC::RequestParser rp{ctx}; 208 IPC::RequestParser rp{ctx};
209 std::string name(PopServiceName(rp));
181 210
182 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
183 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
184
185 const std::string name(name_buf.begin(), end);
186 LOG_DEBUG(Service_SM, "called with name={}", name); 211 LOG_DEBUG(Service_SM, "called with name={}", name);
187 212
188 IPC::ResponseBuilder rb{ctx, 2}; 213 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(service_manager->UnregisterService(name)); 214 rb.Push(service_manager.UnregisterService(name));
190} 215}
191 216
192SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_) 217SM::SM(ServiceManager& service_manager_, Core::System& system_)
193 : ServiceFramework{system_, "sm:", 4}, 218 : ServiceFramework{system_, "sm:", 4},
194 service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { 219 service_manager{service_manager_}, kernel{system_.Kernel()} {
195 static const FunctionInfo functions[] = { 220 RegisterHandlers({
196 {0, &SM::Initialize, "Initialize"}, 221 {0, &SM::Initialize, "Initialize"},
197 {1, &SM::GetService, "GetService"}, 222 {1, &SM::GetService, "GetService"},
198 {2, &SM::RegisterService, "RegisterService"}, 223 {2, &SM::RegisterService, "RegisterService"},
199 {3, &SM::UnregisterService, "UnregisterService"}, 224 {3, &SM::UnregisterService, "UnregisterService"},
200 {4, nullptr, "DetachClient"}, 225 {4, nullptr, "DetachClient"},
201 }; 226 });
202 RegisterHandlers(functions); 227 RegisterHandlersTipc({
228 {0, &SM::Initialize, "Initialize"},
229 {1, &SM::GetServiceTipc, "GetService"},
230 {2, &SM::RegisterService, "RegisterService"},
231 {3, &SM::UnregisterService, "UnregisterService"},
232 {4, nullptr, "DetachClient"},
233 });
203} 234}
204 235
205} // namespace Service::SM 236} // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index af5010c3b..ea37f11d4 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -34,22 +34,26 @@ class Controller;
34/// Interface to "sm:" service 34/// Interface to "sm:" service
35class SM final : public ServiceFramework<SM> { 35class SM final : public ServiceFramework<SM> {
36public: 36public:
37 explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_); 37 explicit SM(ServiceManager& service_manager_, Core::System& system_);
38 ~SM() override; 38 ~SM() override;
39 39
40private: 40private:
41 void Initialize(Kernel::HLERequestContext& ctx); 41 void Initialize(Kernel::HLERequestContext& ctx);
42 void GetService(Kernel::HLERequestContext& ctx); 42 void GetService(Kernel::HLERequestContext& ctx);
43 void GetServiceTipc(Kernel::HLERequestContext& ctx);
43 void RegisterService(Kernel::HLERequestContext& ctx); 44 void RegisterService(Kernel::HLERequestContext& ctx);
44 void UnregisterService(Kernel::HLERequestContext& ctx); 45 void UnregisterService(Kernel::HLERequestContext& ctx);
45 46
46 std::shared_ptr<ServiceManager> service_manager; 47 ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx);
48
49 ServiceManager& service_manager;
50 bool is_initialized{};
47 Kernel::KernelCore& kernel; 51 Kernel::KernelCore& kernel;
48}; 52};
49 53
50class ServiceManager { 54class ServiceManager {
51public: 55public:
52 static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system); 56 static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system);
53 57
54 explicit ServiceManager(Kernel::KernelCore& kernel_); 58 explicit ServiceManager(Kernel::KernelCore& kernel_);
55 ~ServiceManager(); 59 ~ServiceManager();
@@ -69,7 +73,7 @@ public:
69 if (port == nullptr) { 73 if (port == nullptr) {
70 return nullptr; 74 return nullptr;
71 } 75 }
72 return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler()); 76 return std::static_pointer_cast<T>(port->GetServerPort().GetSessionRequestHandler());
73 } 77 }
74 78
75 void InvokeControlRequest(Kernel::HLERequestContext& context); 79 void InvokeControlRequest(Kernel::HLERequestContext& context);
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 2c8899ae0..3b072f6bc 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -128,7 +128,7 @@ private:
128 128
129 LOG_WARNING(Service_SSL, "(STUBBED) called"); 129 LOG_WARNING(Service_SSL, "(STUBBED) called");
130 130
131 IPC::ResponseBuilder rb{ctx, 2}; 131 IPC::ResponseBuilder rb{ctx, 4};
132 rb.Push(RESULT_SUCCESS); 132 rb.Push(RESULT_SUCCESS);
133 rb.Push(client_id); 133 rb.Push(client_id);
134 } 134 }
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_core.h b/src/core/hle/service/time/ephemeral_network_system_clock_core.h
index 4c6cdef86..d12cb5335 100644
--- a/src/core/hle/service/time/ephemeral_network_system_clock_core.h
+++ b/src/core/hle/service/time/ephemeral_network_system_clock_core.h
@@ -10,8 +10,8 @@ namespace Service::Time::Clock {
10 10
11class EphemeralNetworkSystemClockCore final : public SystemClockCore { 11class EphemeralNetworkSystemClockCore final : public SystemClockCore {
12public: 12public:
13 explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core) 13 explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
14 : SystemClockCore{steady_clock_core} {} 14 : SystemClockCore{steady_clock_core_} {}
15}; 15};
16 16
17} // namespace Service::Time::Clock 17} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/local_system_clock_context_writer.h b/src/core/hle/service/time/local_system_clock_context_writer.h
index 7050844c6..490d0ef3e 100644
--- a/src/core/hle/service/time/local_system_clock_context_writer.h
+++ b/src/core/hle/service/time/local_system_clock_context_writer.h
@@ -12,8 +12,8 @@ namespace Service::Time::Clock {
12 12
13class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback { 13class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback {
14public: 14public:
15 explicit LocalSystemClockContextWriter(SharedMemory& shared_memory) 15 explicit LocalSystemClockContextWriter(SharedMemory& shared_memory_)
16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {} 16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
17 17
18protected: 18protected:
19 ResultCode Update() override { 19 ResultCode Update() override {
diff --git a/src/core/hle/service/time/network_system_clock_context_writer.h b/src/core/hle/service/time/network_system_clock_context_writer.h
index 94d8788ff..e2920b8eb 100644
--- a/src/core/hle/service/time/network_system_clock_context_writer.h
+++ b/src/core/hle/service/time/network_system_clock_context_writer.h
@@ -12,8 +12,8 @@ namespace Service::Time::Clock {
12 12
13class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback { 13class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
14public: 14public:
15 explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory) 15 explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory_)
16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {} 16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
17 17
18protected: 18protected:
19 ResultCode Update() override { 19 ResultCode Update() override {
diff --git a/src/core/hle/service/time/standard_local_system_clock_core.h b/src/core/hle/service/time/standard_local_system_clock_core.h
index 8c1882eb1..6320c7af1 100644
--- a/src/core/hle/service/time/standard_local_system_clock_core.h
+++ b/src/core/hle/service/time/standard_local_system_clock_core.h
@@ -10,8 +10,8 @@ namespace Service::Time::Clock {
10 10
11class StandardLocalSystemClockCore final : public SystemClockCore { 11class StandardLocalSystemClockCore final : public SystemClockCore {
12public: 12public:
13 explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core) 13 explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core_)
14 : SystemClockCore{steady_clock_core} {} 14 : SystemClockCore{steady_clock_core_} {}
15}; 15};
16 16
17} // namespace Service::Time::Clock 17} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_network_system_clock_core.h b/src/core/hle/service/time/standard_network_system_clock_core.h
index c993bdf79..9d0aeaedb 100644
--- a/src/core/hle/service/time/standard_network_system_clock_core.h
+++ b/src/core/hle/service/time/standard_network_system_clock_core.h
@@ -16,21 +16,21 @@ namespace Service::Time::Clock {
16 16
17class StandardNetworkSystemClockCore final : public SystemClockCore { 17class StandardNetworkSystemClockCore final : public SystemClockCore {
18public: 18public:
19 explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core) 19 explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
20 : SystemClockCore{steady_clock_core} {} 20 : SystemClockCore{steady_clock_core_} {}
21 21
22 void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) { 22 void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) {
23 standard_network_clock_sufficient_accuracy = value; 23 standard_network_clock_sufficient_accuracy = value;
24 } 24 }
25 25
26 bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const { 26 bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const {
27 SystemClockContext context{}; 27 SystemClockContext clock_ctx{};
28 if (GetClockContext(system, context) != RESULT_SUCCESS) { 28 if (GetClockContext(system, clock_ctx) != RESULT_SUCCESS) {
29 return {}; 29 return {};
30 } 30 }
31 31
32 s64 span{}; 32 s64 span{};
33 if (context.steady_time_point.GetSpanBetween( 33 if (clock_ctx.steady_time_point.GetSpanBetween(
34 GetSteadyClockCore().GetCurrentTimePoint(system), span) != RESULT_SUCCESS) { 34 GetSteadyClockCore().GetCurrentTimePoint(system), span) != RESULT_SUCCESS) {
35 return {}; 35 return {};
36 } 36 }
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp
index 7f47b12b8..41bc01abd 100644
--- a/src/core/hle/service/time/standard_user_system_clock_core.cpp
+++ b/src/core/hle/service/time/standard_user_system_clock_core.cpp
@@ -11,13 +11,13 @@
11namespace Service::Time::Clock { 11namespace Service::Time::Clock {
12 12
13StandardUserSystemClockCore::StandardUserSystemClockCore( 13StandardUserSystemClockCore::StandardUserSystemClockCore(
14 StandardLocalSystemClockCore& local_system_clock_core, 14 StandardLocalSystemClockCore& local_system_clock_core_,
15 StandardNetworkSystemClockCore& network_system_clock_core, Core::System& system) 15 StandardNetworkSystemClockCore& network_system_clock_core_, Core::System& system_)
16 : SystemClockCore(local_system_clock_core.GetSteadyClockCore()), 16 : SystemClockCore(local_system_clock_core_.GetSteadyClockCore()),
17 local_system_clock_core{local_system_clock_core}, 17 local_system_clock_core{local_system_clock_core_},
18 network_system_clock_core{network_system_clock_core}, auto_correction_enabled{}, 18 network_system_clock_core{network_system_clock_core_},
19 auto_correction_time{SteadyClockTimePoint::GetRandom()}, auto_correction_event{ 19 auto_correction_time{SteadyClockTimePoint::GetRandom()}, auto_correction_event{
20 system.Kernel()} { 20 system_.Kernel()} {
21 Kernel::KAutoObject::Create(std::addressof(auto_correction_event)); 21 Kernel::KAutoObject::Create(std::addressof(auto_correction_event));
22 auto_correction_event.Initialize("StandardUserSystemClockCore:AutoCorrectionEvent"); 22 auto_correction_event.Initialize("StandardUserSystemClockCore:AutoCorrectionEvent");
23} 23}
@@ -35,13 +35,13 @@ ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::Syst
35} 35}
36 36
37ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system, 37ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system,
38 SystemClockContext& context) const { 38 SystemClockContext& ctx) const {
39 if (const ResultCode result{ApplyAutomaticCorrection(system, false)}; 39 if (const ResultCode result{ApplyAutomaticCorrection(system, false)};
40 result != RESULT_SUCCESS) { 40 result != RESULT_SUCCESS) {
41 return result; 41 return result;
42 } 42 }
43 43
44 return local_system_clock_core.GetClockContext(system, context); 44 return local_system_clock_core.GetClockContext(system, ctx);
45} 45}
46 46
47ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) { 47ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) {
@@ -64,13 +64,13 @@ ResultCode StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& s
64 return ERROR_UNINITIALIZED_CLOCK; 64 return ERROR_UNINITIALIZED_CLOCK;
65 } 65 }
66 66
67 SystemClockContext context{}; 67 SystemClockContext ctx{};
68 if (const ResultCode result{network_system_clock_core.GetClockContext(system, context)}; 68 if (const ResultCode result{network_system_clock_core.GetClockContext(system, ctx)};
69 result != RESULT_SUCCESS) { 69 result != RESULT_SUCCESS) {
70 return result; 70 return result;
71 } 71 }
72 72
73 local_system_clock_core.SetClockContext(context); 73 local_system_clock_core.SetClockContext(ctx);
74 74
75 return RESULT_SUCCESS; 75 return RESULT_SUCCESS;
76} 76}
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h
index 1bff8a5af..bf9ec5e42 100644
--- a/src/core/hle/service/time/standard_user_system_clock_core.h
+++ b/src/core/hle/service/time/standard_user_system_clock_core.h
@@ -23,13 +23,13 @@ class StandardNetworkSystemClockCore;
23 23
24class StandardUserSystemClockCore final : public SystemClockCore { 24class StandardUserSystemClockCore final : public SystemClockCore {
25public: 25public:
26 StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core, 26 StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core_,
27 StandardNetworkSystemClockCore& network_system_clock_core, 27 StandardNetworkSystemClockCore& network_system_clock_core_,
28 Core::System& system); 28 Core::System& system_);
29 29
30 ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value); 30 ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value);
31 31
32 ResultCode GetClockContext(Core::System& system, SystemClockContext& context) const override; 32 ResultCode GetClockContext(Core::System& system, SystemClockContext& ctx) const override;
33 33
34 bool IsAutomaticCorrectionEnabled() const { 34 bool IsAutomaticCorrectionEnabled() const {
35 return auto_correction_enabled; 35 return auto_correction_enabled;
diff --git a/src/core/hle/service/time/system_clock_core.cpp b/src/core/hle/service/time/system_clock_core.cpp
index 46fc8c6c3..2ef442b56 100644
--- a/src/core/hle/service/time/system_clock_core.cpp
+++ b/src/core/hle/service/time/system_clock_core.cpp
@@ -8,8 +8,8 @@
8 8
9namespace Service::Time::Clock { 9namespace Service::Time::Clock {
10 10
11SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core) 11SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core_)
12 : steady_clock_core{steady_clock_core} { 12 : steady_clock_core{steady_clock_core_} {
13 context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId(); 13 context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId();
14} 14}
15 15
diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h
index 82a8b79ff..b8e6122bf 100644
--- a/src/core/hle/service/time/system_clock_core.h
+++ b/src/core/hle/service/time/system_clock_core.h
@@ -21,7 +21,7 @@ class SystemClockContextUpdateCallback;
21 21
22class SystemClockCore { 22class SystemClockCore {
23public: 23public:
24 explicit SystemClockCore(SteadyClockCore& steady_clock_core); 24 explicit SystemClockCore(SteadyClockCore& steady_clock_core_);
25 virtual ~SystemClockCore(); 25 virtual ~SystemClockCore();
26 26
27 SteadyClockCore& GetSteadyClockCore() const { 27 SteadyClockCore& GetSteadyClockCore() const {
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index fe01a3739..4f9684de8 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -223,7 +223,7 @@ struct TimeManager::Impl final {
223 TimeZone::TimeZoneContentManager time_zone_content_manager; 223 TimeZone::TimeZoneContentManager time_zone_content_manager;
224}; 224};
225 225
226TimeManager::TimeManager(Core::System& system) : system{system} {} 226TimeManager::TimeManager(Core::System& system_) : system{system_} {}
227 227
228TimeManager::~TimeManager() = default; 228TimeManager::~TimeManager() = default;
229 229
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h
index 4db8cc0e1..3af868d87 100644
--- a/src/core/hle/service/time/time_manager.h
+++ b/src/core/hle/service/time/time_manager.h
@@ -30,7 +30,7 @@ class NetworkSystemClockContextWriter;
30 30
31class TimeManager final { 31class TimeManager final {
32public: 32public:
33 explicit TimeManager(Core::System& system); 33 explicit TimeManager(Core::System& system_);
34 ~TimeManager(); 34 ~TimeManager();
35 35
36 void Initialize(); 36 void Initialize();
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index eb57899f6..176ad0eee 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -15,7 +15,7 @@ namespace Service::Time {
15 15
16static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000}; 16static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000};
17 17
18SharedMemory::SharedMemory(Core::System& system) : system(system) { 18SharedMemory::SharedMemory(Core::System& system_) : system(system_) {
19 std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE); 19 std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE);
20} 20}
21 21
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
index 1ad9a286d..d471b5d18 100644
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -14,7 +14,7 @@ namespace Service::Time {
14 14
15class SharedMemory final { 15class SharedMemory final {
16public: 16public:
17 explicit SharedMemory(Core::System& system); 17 explicit SharedMemory(Core::System& system_);
18 ~SharedMemory(); 18 ~SharedMemory();
19 19
20 // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? 20 // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
index 3c8e71a3c..57f71e6f0 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -68,8 +68,8 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
68 return location_name_cache; 68 return location_name_cache;
69} 69}
70 70
71TimeZoneContentManager::TimeZoneContentManager(Core::System& system) 71TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
72 : system{system}, location_name_cache{BuildLocationNameCache(system)} {} 72 : system{system_}, location_name_cache{BuildLocationNameCache(system)} {}
73 73
74void TimeZoneContentManager::Initialize(TimeManager& time_manager) { 74void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
75 std::string location_name; 75 std::string location_name;
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h
index 52dd1a020..cfa601084 100644
--- a/src/core/hle/service/time/time_zone_content_manager.h
+++ b/src/core/hle/service/time/time_zone_content_manager.h
@@ -21,7 +21,7 @@ namespace Service::Time::TimeZone {
21 21
22class TimeZoneContentManager final { 22class TimeZoneContentManager final {
23public: 23public:
24 explicit TimeZoneContentManager(Core::System& system); 24 explicit TimeZoneContentManager(Core::System& system_);
25 25
26 void Initialize(TimeManager& time_manager); 26 void Initialize(TimeManager& time_manager);
27 27
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index becbd36c1..0dd342dbf 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -17,8 +17,8 @@
17 17
18namespace Service::VI { 18namespace Service::VI {
19 19
20Display::Display(u64 id, std::string name, Core::System& system) 20Display::Display(u64 id, std::string name_, Core::System& system)
21 : id{id}, name{std::move(name)}, vsync_event{system.Kernel()} { 21 : display_id{id}, name{std::move(name_)}, vsync_event{system.Kernel()} {
22 Kernel::KAutoObject::Create(std::addressof(vsync_event)); 22 Kernel::KAutoObject::Create(std::addressof(vsync_event));
23 vsync_event.Initialize(fmt::format("Display VSync Event {}", id)); 23 vsync_event.Initialize(fmt::format("Display VSync Event {}", id));
24} 24}
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 388ce6083..166f2a4cc 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -32,14 +32,14 @@ public:
32 /// Constructs a display with a given unique ID and name. 32 /// Constructs a display with a given unique ID and name.
33 /// 33 ///
34 /// @param id The unique ID for this display. 34 /// @param id The unique ID for this display.
35 /// @param name The name for this display. 35 /// @param name_ The name for this display.
36 /// 36 ///
37 Display(u64 id, std::string name, Core::System& system); 37 Display(u64 id, std::string name_, Core::System& system);
38 ~Display(); 38 ~Display();
39 39
40 /// Gets the unique ID assigned to this display. 40 /// Gets the unique ID assigned to this display.
41 u64 GetID() const { 41 u64 GetID() const {
42 return id; 42 return display_id;
43 } 43 }
44 44
45 /// Gets the name of this display 45 /// Gets the name of this display
@@ -96,7 +96,7 @@ public:
96 const Layer* FindLayer(u64 layer_id) const; 96 const Layer* FindLayer(u64 layer_id) const;
97 97
98private: 98private:
99 u64 id; 99 u64 display_id;
100 std::string name; 100 std::string name;
101 101
102 std::vector<std::shared_ptr<Layer>> layers; 102 std::vector<std::shared_ptr<Layer>> layers;
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
index 954225c26..9bc382587 100644
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::VI { 7namespace Service::VI {
8 8
9Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : id{id}, buffer_queue{queue} {} 9Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : layer_id{id}, buffer_queue{queue} {}
10 10
11Layer::~Layer() = default; 11Layer::~Layer() = default;
12 12
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
index c6bfd01f6..ebdd85505 100644
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -31,7 +31,7 @@ public:
31 31
32 /// Gets the ID for this layer. 32 /// Gets the ID for this layer.
33 u64 GetID() const { 33 u64 GetID() const {
34 return id; 34 return layer_id;
35 } 35 }
36 36
37 /// Gets a reference to the buffer queue this layer is using. 37 /// Gets a reference to the buffer queue this layer is using.
@@ -45,7 +45,7 @@ public:
45 } 45 }
46 46
47private: 47private:
48 u64 id; 48 u64 layer_id;
49 NVFlinger::BufferQueue& buffer_queue; 49 NVFlinger::BufferQueue& buffer_queue;
50}; 50};
51 51
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 32e47a43e..fdd2b4b4f 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -212,7 +212,7 @@ private:
212 212
213class IGBPConnectRequestParcel : public Parcel { 213class IGBPConnectRequestParcel : public Parcel {
214public: 214public:
215 explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 215 explicit IGBPConnectRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
216 Deserialize(); 216 Deserialize();
217 } 217 }
218 218
@@ -274,8 +274,8 @@ private:
274 274
275class IGBPSetPreallocatedBufferRequestParcel : public Parcel { 275class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
276public: 276public:
277 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer) 277 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer_)
278 : Parcel(std::move(buffer)) { 278 : Parcel(std::move(buffer_)) {
279 Deserialize(); 279 Deserialize();
280 } 280 }
281 281
@@ -312,7 +312,7 @@ protected:
312 312
313class IGBPCancelBufferRequestParcel : public Parcel { 313class IGBPCancelBufferRequestParcel : public Parcel {
314public: 314public:
315 explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 315 explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
316 Deserialize(); 316 Deserialize();
317 } 317 }
318 318
@@ -338,7 +338,7 @@ protected:
338 338
339class IGBPDequeueBufferRequestParcel : public Parcel { 339class IGBPDequeueBufferRequestParcel : public Parcel {
340public: 340public:
341 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 341 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
342 Deserialize(); 342 Deserialize();
343 } 343 }
344 344
@@ -360,8 +360,8 @@ public:
360 360
361class IGBPDequeueBufferResponseParcel : public Parcel { 361class IGBPDequeueBufferResponseParcel : public Parcel {
362public: 362public:
363 explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence) 363 explicit IGBPDequeueBufferResponseParcel(u32 slot_, Nvidia::MultiFence& multi_fence_)
364 : slot(slot), multi_fence(multi_fence) {} 364 : slot(slot_), multi_fence(multi_fence_) {}
365 365
366protected: 366protected:
367 void SerializeData() override { 367 void SerializeData() override {
@@ -377,7 +377,7 @@ protected:
377 377
378class IGBPRequestBufferRequestParcel : public Parcel { 378class IGBPRequestBufferRequestParcel : public Parcel {
379public: 379public:
380 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 380 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
381 Deserialize(); 381 Deserialize();
382 } 382 }
383 383
@@ -391,7 +391,7 @@ public:
391 391
392class IGBPRequestBufferResponseParcel : public Parcel { 392class IGBPRequestBufferResponseParcel : public Parcel {
393public: 393public:
394 explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer) : buffer(buffer) {} 394 explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer_) : buffer(buffer_) {}
395 ~IGBPRequestBufferResponseParcel() override = default; 395 ~IGBPRequestBufferResponseParcel() override = default;
396 396
397protected: 397protected:
@@ -408,7 +408,7 @@ protected:
408 408
409class IGBPQueueBufferRequestParcel : public Parcel { 409class IGBPQueueBufferRequestParcel : public Parcel {
410public: 410public:
411 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 411 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
412 Deserialize(); 412 Deserialize();
413 } 413 }
414 414
@@ -470,7 +470,7 @@ private:
470 470
471class IGBPQueryRequestParcel : public Parcel { 471class IGBPQueryRequestParcel : public Parcel {
472public: 472public:
473 explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 473 explicit IGBPQueryRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
474 Deserialize(); 474 Deserialize();
475 } 475 }
476 476
@@ -484,7 +484,7 @@ public:
484 484
485class IGBPQueryResponseParcel : public Parcel { 485class IGBPQueryResponseParcel : public Parcel {
486public: 486public:
487 explicit IGBPQueryResponseParcel(u32 value) : value(value) {} 487 explicit IGBPQueryResponseParcel(u32 value_) : value{value_} {}
488 ~IGBPQueryResponseParcel() override = default; 488 ~IGBPQueryResponseParcel() override = default;
489 489
490protected: 490protected:
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 42f023258..022885c1b 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -22,8 +22,8 @@
22namespace Loader { 22namespace Loader {
23 23
24AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, 24AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
25 bool override_update) 25 bool override_update_)
26 : AppLoader(std::move(file_)), override_update(override_update) { 26 : AppLoader(std::move(file_)), override_update(override_update_) {
27 const auto file_dir = file->GetContainingDirectory(); 27 const auto file_dir = file->GetContainingDirectory();
28 28
29 // Title ID 29 // Title ID
@@ -48,9 +48,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
48 // Any png, jpeg, or bmp file 48 // Any png, jpeg, or bmp file
49 const auto& files = file_dir->GetFiles(); 49 const auto& files = file_dir->GetFiles();
50 const auto icon_iter = 50 const auto icon_iter =
51 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { 51 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) {
52 return file->GetExtension() == "png" || file->GetExtension() == "jpg" || 52 return f->GetExtension() == "png" || f->GetExtension() == "jpg" ||
53 file->GetExtension() == "bmp" || file->GetExtension() == "jpeg"; 53 f->GetExtension() == "bmp" || f->GetExtension() == "jpeg";
54 }); 54 });
55 if (icon_iter != files.end()) 55 if (icon_iter != files.end())
56 icon_data = (*icon_iter)->ReadAllBytes(); 56 icon_data = (*icon_iter)->ReadAllBytes();
@@ -61,9 +61,8 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
61 if (nacp_file == nullptr) { 61 if (nacp_file == nullptr) {
62 const auto& files = file_dir->GetFiles(); 62 const auto& files = file_dir->GetFiles();
63 const auto nacp_iter = 63 const auto nacp_iter =
64 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { 64 std::find_if(files.begin(), files.end(),
65 return file->GetExtension() == "nacp"; 65 [](const FileSys::VirtualFile& f) { return f->GetExtension() == "nacp"; });
66 });
67 if (nacp_iter != files.end()) 66 if (nacp_iter != files.end())
68 nacp_file = *nacp_iter; 67 nacp_file = *nacp_iter;
69 } 68 }
@@ -75,9 +74,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
75} 74}
76 75
77AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( 76AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
78 FileSys::VirtualDir directory, bool override_update) 77 FileSys::VirtualDir directory, bool override_update_)
79 : AppLoader(directory->GetFile("main")), dir(std::move(directory)), 78 : AppLoader(directory->GetFile("main")), dir(std::move(directory)),
80 override_update(override_update) {} 79 override_update(override_update_) {}
81 80
82FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) { 81FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
83 if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) { 82 if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
@@ -184,8 +183,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
184 // Find the RomFS by searching for a ".romfs" file in this directory 183 // Find the RomFS by searching for a ".romfs" file in this directory
185 const auto& files = dir->GetFiles(); 184 const auto& files = dir->GetFiles();
186 const auto romfs_iter = 185 const auto romfs_iter =
187 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { 186 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) {
188 return file->GetName().find(".romfs") != std::string::npos; 187 return f->GetName().find(".romfs") != std::string::npos;
189 }); 188 });
190 189
191 // Register the RomFS if a ".romfs" file was found 190 // Register the RomFS if a ".romfs" file was found
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index a49a8b001..79a4d4db5 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -24,11 +24,11 @@ namespace Loader {
24class AppLoader_DeconstructedRomDirectory final : public AppLoader { 24class AppLoader_DeconstructedRomDirectory final : public AppLoader {
25public: 25public:
26 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file, 26 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file,
27 bool override_update = false); 27 bool override_update_ = false);
28 28
29 // Overload to accept exefs directory. Must contain 'main' and 'main.npdm' 29 // Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
30 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory, 30 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
31 bool override_update = false); 31 bool override_update_ = false);
32 32
33 /** 33 /**
34 * Identifies whether or not the given file is a deconstructed ROM directory. 34 * Identifies whether or not the given file is a deconstructed ROM directory.
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 11b2d0837..d4808fb5b 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -194,7 +194,7 @@ std::ostream& operator<<(std::ostream& os, ResultStatus status) {
194 return os; 194 return os;
195} 195}
196 196
197AppLoader::AppLoader(FileSys::VirtualFile file) : file(std::move(file)) {} 197AppLoader::AppLoader(FileSys::VirtualFile file_) : file(std::move(file_)) {}
198AppLoader::~AppLoader() = default; 198AppLoader::~AppLoader() = default;
199 199
200/** 200/**
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 9eac11dec..edc8bb257 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -147,7 +147,7 @@ public:
147 }; 147 };
148 using LoadResult = std::pair<ResultStatus, std::optional<LoadParameters>>; 148 using LoadResult = std::pair<ResultStatus, std::optional<LoadParameters>>;
149 149
150 explicit AppLoader(FileSys::VirtualFile file); 150 explicit AppLoader(FileSys::VirtualFile file_);
151 virtual ~AppLoader(); 151 virtual ~AppLoader();
152 152
153 /** 153 /**
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index b4c56e1c1..bf2ef7816 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -82,22 +82,6 @@ struct Memory::Impl {
82 return nullptr; 82 return nullptr;
83 } 83 }
84 84
85 u8* GetKernelBuffer(VAddr start_vaddr, size_t size) {
86 // TODO(bunnei): This is just a workaround until we have kernel memory layout mapped &
87 // managed. Until then, we use this to allocate and access kernel memory regions.
88
89 auto search = kernel_memory_regions.find(start_vaddr);
90 if (search != kernel_memory_regions.end()) {
91 return search->second.get();
92 }
93
94 std::unique_ptr<u8[]> new_memory_region{new u8[size]};
95 u8* raw_ptr = new_memory_region.get();
96 kernel_memory_regions[start_vaddr] = std::move(new_memory_region);
97
98 return raw_ptr;
99 }
100
101 u8 Read8(const VAddr addr) { 85 u8 Read8(const VAddr addr) {
102 return Read<u8>(addr); 86 return Read<u8>(addr);
103 } 87 }
@@ -727,7 +711,6 @@ struct Memory::Impl {
727 } 711 }
728 712
729 Common::PageTable* current_page_table = nullptr; 713 Common::PageTable* current_page_table = nullptr;
730 std::unordered_map<VAddr, std::unique_ptr<u8[]>> kernel_memory_regions;
731 Core::System& system; 714 Core::System& system;
732}; 715};
733 716
@@ -765,10 +748,6 @@ u8* Memory::GetPointer(VAddr vaddr) {
765 return impl->GetPointer(vaddr); 748 return impl->GetPointer(vaddr);
766} 749}
767 750
768u8* Memory::GetKernelBuffer(VAddr start_vaddr, size_t size) {
769 return impl->GetKernelBuffer(start_vaddr, size);
770}
771
772const u8* Memory::GetPointer(VAddr vaddr) const { 751const u8* Memory::GetPointer(VAddr vaddr) const {
773 return impl->GetPointer(vaddr); 752 return impl->GetPointer(vaddr);
774} 753}
diff --git a/src/core/memory.h b/src/core/memory.h
index 345fd870d..c91eeced9 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -121,15 +121,6 @@ public:
121 */ 121 */
122 u8* GetPointer(VAddr vaddr); 122 u8* GetPointer(VAddr vaddr);
123 123
124 /**
125 * Gets a pointer to the start of a kernel heap allocated memory region. Will allocate one if it
126 * does not already exist.
127 *
128 * @param start_vaddr Start virtual address for the memory region.
129 * @param size Size of the memory region.
130 */
131 u8* GetKernelBuffer(VAddr start_vaddr, size_t size);
132
133 template <typename T> 124 template <typename T>
134 T* GetPointer(VAddr vaddr) { 125 T* GetPointer(VAddr vaddr) {
135 return reinterpret_cast<T*>(GetPointer(vaddr)); 126 return reinterpret_cast<T*>(GetPointer(vaddr));
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 0f5ef7954..46a7e09b4 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -37,8 +37,8 @@ std::string_view ExtractName(std::string_view data, std::size_t start_index, cha
37} 37}
38} // Anonymous namespace 38} // Anonymous namespace
39 39
40StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) 40StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_)
41 : metadata(metadata), system(system) {} 41 : metadata{metadata_}, system{system_} {}
42 42
43StandardVmCallbacks::~StandardVmCallbacks() = default; 43StandardVmCallbacks::~StandardVmCallbacks() = default;
44 44
@@ -174,11 +174,11 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
174 return out; 174 return out;
175} 175}
176 176
177CheatEngine::CheatEngine(Core::System& system, std::vector<CheatEntry> cheats, 177CheatEngine::CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
178 const std::array<u8, 0x20>& build_id) 178 const std::array<u8, 0x20>& build_id_)
179 : vm{std::make_unique<StandardVmCallbacks>(system, metadata)}, 179 : vm{std::make_unique<StandardVmCallbacks>(system_, metadata)},
180 cheats(std::move(cheats)), core_timing{system.CoreTiming()}, system{system} { 180 cheats(std::move(cheats_)), core_timing{system_.CoreTiming()}, system{system_} {
181 metadata.main_nso_build_id = build_id; 181 metadata.main_nso_build_id = build_id_;
182} 182}
183 183
184CheatEngine::~CheatEngine() { 184CheatEngine::~CheatEngine() {
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index 5e6f901ec..a8e041d9d 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -25,7 +25,7 @@ namespace Core::Memory {
25 25
26class StandardVmCallbacks : public DmntCheatVm::Callbacks { 26class StandardVmCallbacks : public DmntCheatVm::Callbacks {
27public: 27public:
28 StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata); 28 StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
29 ~StandardVmCallbacks() override; 29 ~StandardVmCallbacks() override;
30 30
31 void MemoryRead(VAddr address, void* data, u64 size) override; 31 void MemoryRead(VAddr address, void* data, u64 size) override;
@@ -38,7 +38,7 @@ private:
38 VAddr SanitizeAddress(VAddr address) const; 38 VAddr SanitizeAddress(VAddr address) const;
39 39
40 const CheatProcessMetadata& metadata; 40 const CheatProcessMetadata& metadata;
41 Core::System& system; 41 System& system;
42}; 42};
43 43
44// Intermediary class that parses a text file or other disk format for storing cheats into a 44// Intermediary class that parses a text file or other disk format for storing cheats into a
@@ -61,8 +61,8 @@ public:
61// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming 61// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming
62class CheatEngine final { 62class CheatEngine final {
63public: 63public:
64 CheatEngine(Core::System& system_, std::vector<CheatEntry> cheats_, 64 CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
65 const std::array<u8, 0x20>& build_id); 65 const std::array<u8, 0x20>& build_id_);
66 ~CheatEngine(); 66 ~CheatEngine();
67 67
68 void Initialize(); 68 void Initialize();
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index 48be80c12..dc04e37d2 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -29,7 +29,8 @@
29 29
30namespace Core::Memory { 30namespace Core::Memory {
31 31
32DmntCheatVm::DmntCheatVm(std::unique_ptr<Callbacks> callbacks) : callbacks(std::move(callbacks)) {} 32DmntCheatVm::DmntCheatVm(std::unique_ptr<Callbacks> callbacks_)
33 : callbacks(std::move(callbacks_)) {}
33 34
34DmntCheatVm::~DmntCheatVm() = default; 35DmntCheatVm::~DmntCheatVm() = default;
35 36
diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h
index 21b86b72c..707bee82b 100644
--- a/src/core/memory/dmnt_cheat_vm.h
+++ b/src/core/memory/dmnt_cheat_vm.h
@@ -293,7 +293,7 @@ public:
293 static constexpr std::size_t NumStaticRegisters = 293 static constexpr std::size_t NumStaticRegisters =
294 NumReadableStaticRegisters + NumWritableStaticRegisters; 294 NumReadableStaticRegisters + NumWritableStaticRegisters;
295 295
296 explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks); 296 explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks_);
297 ~DmntCheatVm(); 297 ~DmntCheatVm();
298 298
299 std::size_t GetProgramSize() const { 299 std::size_t GetProgramSize() const {
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index c92337079..c42c437b7 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -27,7 +27,7 @@ constexpr std::size_t IgnoreFrames = 5;
27 27
28namespace Core { 28namespace Core {
29 29
30PerfStats::PerfStats(u64 title_id) : title_id(title_id) {} 30PerfStats::PerfStats(u64 title_id_) : title_id(title_id_) {}
31 31
32PerfStats::~PerfStats() { 32PerfStats::~PerfStats() {
33 if (!Settings::values.record_frame_times || title_id == 0) { 33 if (!Settings::values.record_frame_times || title_id == 0) {
@@ -69,9 +69,7 @@ void PerfStats::EndSystemFrame() {
69} 69}
70 70
71void PerfStats::EndGameFrame() { 71void PerfStats::EndGameFrame() {
72 std::lock_guard lock{object_mutex}; 72 game_frames.fetch_add(1, std::memory_order_relaxed);
73
74 game_frames += 1;
75} 73}
76 74
77double PerfStats::GetMeanFrametime() const { 75double PerfStats::GetMeanFrametime() const {
@@ -94,10 +92,11 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
94 const auto interval = duration_cast<DoubleSecs>(now - reset_point).count(); 92 const auto interval = duration_cast<DoubleSecs>(now - reset_point).count();
95 93
96 const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval; 94 const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval;
97 95 const auto current_frames = static_cast<double>(game_frames.load(std::memory_order_relaxed));
96 const auto current_fps = current_frames / interval;
98 const PerfStatsResults results{ 97 const PerfStatsResults results{
99 .system_fps = static_cast<double>(system_frames) / interval, 98 .system_fps = static_cast<double>(system_frames) / interval,
100 .game_fps = static_cast<double>(game_frames) / interval, 99 .average_game_fps = (current_fps + previous_fps) / 2.0,
101 .frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() / 100 .frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() /
102 static_cast<double>(system_frames), 101 static_cast<double>(system_frames),
103 .emulation_speed = system_us_per_second.count() / 1'000'000.0, 102 .emulation_speed = system_us_per_second.count() / 1'000'000.0,
@@ -108,7 +107,8 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
108 reset_point_system_us = current_system_time_us; 107 reset_point_system_us = current_system_time_us;
109 accumulated_frametime = Clock::duration::zero(); 108 accumulated_frametime = Clock::duration::zero();
110 system_frames = 0; 109 system_frames = 0;
111 game_frames = 0; 110 game_frames.store(0, std::memory_order_relaxed);
111 previous_fps = current_fps;
112 112
113 return results; 113 return results;
114} 114}
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
index 69256b960..e5d603717 100644
--- a/src/core/perf_stats.h
+++ b/src/core/perf_stats.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <atomic>
8#include <chrono> 9#include <chrono>
9#include <cstddef> 10#include <cstddef>
10#include <mutex> 11#include <mutex>
@@ -15,8 +16,8 @@ namespace Core {
15struct PerfStatsResults { 16struct PerfStatsResults {
16 /// System FPS (LCD VBlanks) in Hz 17 /// System FPS (LCD VBlanks) in Hz
17 double system_fps; 18 double system_fps;
18 /// Game FPS (GSP frame submissions) in Hz 19 /// Average game FPS (GPU frame renders) in Hz
19 double game_fps; 20 double average_game_fps;
20 /// Walltime per system frame, in seconds, excluding any waits 21 /// Walltime per system frame, in seconds, excluding any waits
21 double frametime; 22 double frametime;
22 /// Ratio of walltime / emulated time elapsed 23 /// Ratio of walltime / emulated time elapsed
@@ -29,7 +30,7 @@ struct PerfStatsResults {
29 */ 30 */
30class PerfStats { 31class PerfStats {
31public: 32public:
32 explicit PerfStats(u64 title_id); 33 explicit PerfStats(u64 title_id_);
33 ~PerfStats(); 34 ~PerfStats();
34 35
35 using Clock = std::chrono::high_resolution_clock; 36 using Clock = std::chrono::high_resolution_clock;
@@ -72,7 +73,7 @@ private:
72 /// Cumulative number of system frames (LCD VBlanks) presented since last reset 73 /// Cumulative number of system frames (LCD VBlanks) presented since last reset
73 u32 system_frames = 0; 74 u32 system_frames = 0;
74 /// Cumulative number of game frames (GSP frame submissions) since last reset 75 /// Cumulative number of game frames (GSP frame submissions) since last reset
75 u32 game_frames = 0; 76 std::atomic<u32> game_frames = 0;
76 77
77 /// Point when the previous system frame ended 78 /// Point when the previous system frame ended
78 Clock::time_point previous_frame_end = reset_point; 79 Clock::time_point previous_frame_end = reset_point;
@@ -80,6 +81,8 @@ private:
80 Clock::time_point frame_begin = reset_point; 81 Clock::time_point frame_begin = reset_point;
81 /// Total visible duration (including frame-limiting, etc.) of the previous system frame 82 /// Total visible duration (including frame-limiting, etc.) of the previous system frame
82 Clock::duration previous_frame_length = Clock::duration::zero(); 83 Clock::duration previous_frame_length = Clock::duration::zero();
84 /// Previously computed fps
85 double previous_fps = 0;
83}; 86};
84 87
85class FrameLimiter { 88class FrameLimiter {
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 896add892..d1e807dd4 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -192,7 +192,7 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx, Core::Memory::Memo
192 192
193namespace Core { 193namespace Core {
194 194
195Reporter::Reporter(System& system) : system(system) {} 195Reporter::Reporter(System& system_) : system(system_) {}
196 196
197Reporter::~Reporter() = default; 197Reporter::~Reporter() = default;
198 198
diff --git a/src/core/reporter.h b/src/core/reporter.h
index b2c2d9a2e..6fb6ebffa 100644
--- a/src/core/reporter.h
+++ b/src/core/reporter.h
@@ -30,7 +30,7 @@ class System;
30 30
31class Reporter { 31class Reporter {
32public: 32public:
33 explicit Reporter(System& system); 33 explicit Reporter(System& system_);
34 ~Reporter(); 34 ~Reporter();
35 35
36 // Used by fatal services 36 // Used by fatal services
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 7c4e7dd3b..7399c3648 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -153,6 +153,11 @@ struct InputSubsystem::Impl {
153 // TODO return the correct motion device 153 // TODO return the correct motion device
154 return {}; 154 return {};
155 } 155 }
156#ifdef HAVE_SDL2
157 if (params.Get("class", "") == "sdl") {
158 return sdl->GetMotionMappingForDevice(params);
159 }
160#endif
156 return {}; 161 return {};
157 } 162 }
158 163
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h
index 42bbf14d4..b5d41bba4 100644
--- a/src/input_common/sdl/sdl.h
+++ b/src/input_common/sdl/sdl.h
@@ -37,6 +37,9 @@ public:
37 virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { 37 virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) {
38 return {}; 38 return {};
39 } 39 }
40 virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) {
41 return {};
42 }
40}; 43};
41 44
42class NullState : public State { 45class NullState : public State {
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 288557968..b9b584b2a 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -29,6 +29,7 @@
29#endif 29#endif
30 30
31#include "common/logging/log.h" 31#include "common/logging/log.h"
32#include "common/math_util.h"
32#include "common/param_package.h" 33#include "common/param_package.h"
33#include "common/settings_input.h" 34#include "common/settings_input.h"
34#include "common/threadsafe_queue.h" 35#include "common/threadsafe_queue.h"
@@ -68,13 +69,57 @@ public:
68 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, 69 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
69 SDL_GameController* game_controller) 70 SDL_GameController* game_controller)
70 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, 71 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
71 sdl_controller{game_controller, &SDL_GameControllerClose} {} 72 sdl_controller{game_controller, &SDL_GameControllerClose} {
73 EnableMotion();
74 }
75
76 void EnableMotion() {
77 if (sdl_controller) {
78 SDL_GameController* controller = sdl_controller.get();
79 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) {
80 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
81 has_accel = true;
82 }
83 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) {
84 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
85 has_gyro = true;
86 }
87 }
88 }
72 89
73 void SetButton(int button, bool value) { 90 void SetButton(int button, bool value) {
74 std::lock_guard lock{mutex}; 91 std::lock_guard lock{mutex};
75 state.buttons.insert_or_assign(button, value); 92 state.buttons.insert_or_assign(button, value);
76 } 93 }
77 94
95 void SetMotion(SDL_ControllerSensorEvent event) {
96 constexpr float gravity_constant = 9.80665f;
97 std::lock_guard lock{mutex};
98 u64 time_difference = event.timestamp - last_motion_update;
99 last_motion_update = event.timestamp;
100 switch (event.sensor) {
101 case SDL_SENSOR_ACCEL: {
102 const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]};
103 motion.SetAcceleration(acceleration / gravity_constant);
104 break;
105 }
106 case SDL_SENSOR_GYRO: {
107 const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]};
108 motion.SetGyroscope(gyroscope / (Common::PI * 2));
109 break;
110 }
111 }
112
113 // Ignore duplicated timestamps
114 if (time_difference == 0) {
115 return;
116 }
117
118 motion.SetGyroThreshold(0.0001f);
119 motion.UpdateRotation(time_difference * 1000);
120 motion.UpdateOrientation(time_difference * 1000);
121 }
122
78 bool GetButton(int button) const { 123 bool GetButton(int button) const {
79 std::lock_guard lock{mutex}; 124 std::lock_guard lock{mutex};
80 return state.buttons.at(button); 125 return state.buttons.at(button);
@@ -121,6 +166,14 @@ public:
121 return std::make_tuple(x, y); 166 return std::make_tuple(x, y);
122 } 167 }
123 168
169 bool HasGyro() const {
170 return has_gyro;
171 }
172
173 bool HasAccel() const {
174 return has_accel;
175 }
176
124 const MotionInput& GetMotion() const { 177 const MotionInput& GetMotion() const {
125 return motion; 178 return motion;
126 } 179 }
@@ -173,8 +226,11 @@ private:
173 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 226 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
174 mutable std::mutex mutex; 227 mutable std::mutex mutex;
175 228
176 // Motion is initialized without PID values as motion input is not aviable for SDL2 229 // Motion is initialized with the PID values
177 MotionInput motion{0.0f, 0.0f, 0.0f}; 230 MotionInput motion{0.3f, 0.005f, 0.0f};
231 u64 last_motion_update{};
232 bool has_gyro{false};
233 bool has_accel{false};
178}; 234};
179 235
180std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 236std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -298,6 +354,12 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
298 } 354 }
299 break; 355 break;
300 } 356 }
357 case SDL_CONTROLLERSENSORUPDATE: {
358 if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
359 joystick->SetMotion(event.csensor);
360 }
361 break;
362 }
301 case SDL_JOYDEVICEREMOVED: 363 case SDL_JOYDEVICEREMOVED:
302 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); 364 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
303 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); 365 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
@@ -451,6 +513,18 @@ private:
451 std::shared_ptr<SDLJoystick> joystick; 513 std::shared_ptr<SDLJoystick> joystick;
452}; 514};
453 515
516class SDLMotion final : public Input::MotionDevice {
517public:
518 explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {}
519
520 Input::MotionStatus GetStatus() const override {
521 return joystick->GetMotion().GetMotion();
522 }
523
524private:
525 std::shared_ptr<SDLJoystick> joystick;
526};
527
454class SDLDirectionMotion final : public Input::MotionDevice { 528class SDLDirectionMotion final : public Input::MotionDevice {
455public: 529public:
456 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) 530 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
@@ -660,6 +734,10 @@ public:
660 734
661 auto joystick = state.GetSDLJoystickByGUID(guid, port); 735 auto joystick = state.GetSDLJoystickByGUID(guid, port);
662 736
737 if (params.Has("motion")) {
738 return std::make_unique<SDLMotion>(joystick);
739 }
740
663 if (params.Has("hat")) { 741 if (params.Has("hat")) {
664 const int hat = params.Get("hat", 0); 742 const int hat = params.Get("hat", 0);
665 const std::string direction_name = params.Get("direction", ""); 743 const std::string direction_name = params.Get("direction", "");
@@ -719,6 +797,17 @@ SDLState::SDLState() {
719 RegisterFactory<VibrationDevice>("sdl", vibration_factory); 797 RegisterFactory<VibrationDevice>("sdl", vibration_factory);
720 RegisterFactory<MotionDevice>("sdl", motion_factory); 798 RegisterFactory<MotionDevice>("sdl", motion_factory);
721 799
800 // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
801 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
802 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
803
804 // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a
805 // GameController and not a generic one
806 SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1");
807
808 // Turn off Pro controller home led
809 SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0");
810
722 // If the frontend is going to manage the event loop, then we don't start one here 811 // If the frontend is going to manage the event loop, then we don't start one here
723 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; 812 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
724 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { 813 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
@@ -855,6 +944,13 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s
855 return params; 944 return params;
856} 945}
857 946
947Common::ParamPackage BuildMotionParam(int port, std::string guid) {
948 Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}});
949 params.Set("port", port);
950 params.Set("guid", std::move(guid));
951 return params;
952}
953
858Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { 954Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
859 switch (event.type) { 955 switch (event.type) {
860 case SDL_JOYAXISMOTION: { 956 case SDL_JOYAXISMOTION: {
@@ -909,6 +1005,35 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve
909 } 1005 }
910 break; 1006 break;
911 } 1007 }
1008 case SDL_CONTROLLERSENSORUPDATE: {
1009 bool is_motion_shaking = false;
1010 constexpr float gyro_threshold = 5.0f;
1011 constexpr float accel_threshold = 11.0f;
1012 if (event.csensor.sensor == SDL_SENSOR_ACCEL) {
1013 const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2],
1014 -event.csensor.data[1]};
1015 if (acceleration.Length() > accel_threshold) {
1016 is_motion_shaking = true;
1017 }
1018 }
1019
1020 if (event.csensor.sensor == SDL_SENSOR_GYRO) {
1021 const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2],
1022 event.csensor.data[1]};
1023 if (gyroscope.Length() > gyro_threshold) {
1024 is_motion_shaking = true;
1025 }
1026 }
1027
1028 if (!is_motion_shaking) {
1029 break;
1030 }
1031
1032 if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) {
1033 return BuildMotionParam(joystick->GetPort(), joystick->GetGUID());
1034 }
1035 break;
1036 }
912 } 1037 }
913 return {}; 1038 return {};
914} 1039}
@@ -1038,6 +1163,27 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
1038 return mapping; 1163 return mapping;
1039} 1164}
1040 1165
1166MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) {
1167 if (!params.Has("guid") || !params.Has("port")) {
1168 return {};
1169 }
1170 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
1171 auto* controller = joystick->GetSDLGameController();
1172 if (controller == nullptr) {
1173 return {};
1174 }
1175
1176 joystick->EnableMotion();
1177
1178 if (!joystick->HasGyro() && !joystick->HasAccel()) {
1179 return {};
1180 }
1181
1182 MotionMapping mapping = {};
1183 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
1184 BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
1185 return mapping;
1186}
1041namespace Polling { 1187namespace Polling {
1042class SDLPoller : public InputCommon::Polling::DevicePoller { 1188class SDLPoller : public InputCommon::Polling::DevicePoller {
1043public: 1189public:
@@ -1151,6 +1297,7 @@ public:
1151 [[fallthrough]]; 1297 [[fallthrough]];
1152 case SDL_JOYBUTTONUP: 1298 case SDL_JOYBUTTONUP:
1153 case SDL_JOYHATMOTION: 1299 case SDL_JOYHATMOTION:
1300 case SDL_CONTROLLERSENSORUPDATE:
1154 return {SDLEventToMotionParamPackage(state, event)}; 1301 return {SDLEventToMotionParamPackage(state, event)};
1155 } 1302 }
1156 return std::nullopt; 1303 return std::nullopt;
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index 8b7363f56..121e01913 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -57,6 +57,7 @@ public:
57 57
58 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; 58 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
59 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; 59 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
60 MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
60 61
61private: 62private:
62 void InitJoystick(int joystick_index); 63 void InitJoystick(int joystick_index);
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 8a38a380d..bc1dfab3d 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -86,6 +86,7 @@ private:
86 case Type::PadData: { 86 case Type::PadData: {
87 Response::PadData pad_data; 87 Response::PadData pad_data;
88 std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData)); 88 std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData));
89 SanitizeMotion(pad_data);
89 callback.pad_data(std::move(pad_data)); 90 callback.pad_data(std::move(pad_data));
90 break; 91 break;
91 } 92 }
@@ -114,6 +115,28 @@ private:
114 StartSend(timer.expiry()); 115 StartSend(timer.expiry());
115 } 116 }
116 117
118 void SanitizeMotion(Response::PadData& data) {
119 // Zero out any non number value
120 if (!std::isnormal(data.gyro.pitch)) {
121 data.gyro.pitch = 0;
122 }
123 if (!std::isnormal(data.gyro.roll)) {
124 data.gyro.roll = 0;
125 }
126 if (!std::isnormal(data.gyro.yaw)) {
127 data.gyro.yaw = 0;
128 }
129 if (!std::isnormal(data.accel.x)) {
130 data.accel.x = 0;
131 }
132 if (!std::isnormal(data.accel.y)) {
133 data.accel.y = 0;
134 }
135 if (!std::isnormal(data.accel.z)) {
136 data.accel.z = 0;
137 }
138 }
139
117 SocketCallback callback; 140 SocketCallback callback;
118 boost::asio::io_service io_service; 141 boost::asio::io_service io_service;
119 boost::asio::basic_waitable_timer<clock> timer; 142 boost::asio::basic_waitable_timer<clock> timer;
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 32dcbd693..de971041f 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -690,7 +690,10 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
690 const VAddr cpu_addr = binding.cpu_addr; 690 const VAddr cpu_addr = binding.cpu_addr;
691 const u32 size = binding.size; 691 const u32 size = binding.size;
692 Buffer& buffer = slot_buffers[binding.buffer_id]; 692 Buffer& buffer = slot_buffers[binding.buffer_id];
693 if (size <= uniform_buffer_skip_cache_size && !buffer.IsRegionGpuModified(cpu_addr, size)) { 693 const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID &&
694 size <= uniform_buffer_skip_cache_size &&
695 !buffer.IsRegionGpuModified(cpu_addr, size);
696 if (use_fast_buffer) {
694 if constexpr (IS_OPENGL) { 697 if constexpr (IS_OPENGL) {
695 if (runtime.HasFastBufferSubData()) { 698 if (runtime.HasFastBufferSubData()) {
696 // Fast path for Nvidia 699 // Fast path for Nvidia
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index a38024242..37f7b24e1 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -13,6 +13,7 @@
13#include "core/frontend/emu_window.h" 13#include "core/frontend/emu_window.h"
14#include "core/hardware_interrupt_manager.h" 14#include "core/hardware_interrupt_manager.h"
15#include "core/memory.h" 15#include "core/memory.h"
16#include "core/perf_stats.h"
16#include "video_core/engines/fermi_2d.h" 17#include "video_core/engines/fermi_2d.h"
17#include "video_core/engines/kepler_compute.h" 18#include "video_core/engines/kepler_compute.h"
18#include "video_core/engines/kepler_memory.h" 19#include "video_core/engines/kepler_memory.h"
@@ -191,6 +192,10 @@ u64 GPU::GetTicks() const {
191 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den; 192 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
192} 193}
193 194
195void GPU::RendererFrameEndNotify() {
196 system.GetPerfStats().EndGameFrame();
197}
198
194void GPU::FlushCommands() { 199void GPU::FlushCommands() {
195 rasterizer->FlushCommands(); 200 rasterizer->FlushCommands();
196} 201}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 8669e9940..29a867863 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -247,6 +247,8 @@ public:
247 return use_nvdec; 247 return use_nvdec;
248 } 248 }
249 249
250 void RendererFrameEndNotify();
251
250 enum class FenceOperation : u32 { 252 enum class FenceOperation : u32 {
251 Acquire = 0, 253 Acquire = 0,
252 Increment = 1, 254 Increment = 1,
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index b113f54db..3f4532ca7 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -241,7 +241,7 @@ Device::Device() {
241 has_variable_aoffi = TestVariableAoffi(); 241 has_variable_aoffi = TestVariableAoffi();
242 has_component_indexing_bug = is_amd; 242 has_component_indexing_bug = is_amd;
243 has_precise_bug = TestPreciseBug(); 243 has_precise_bug = TestPreciseBug();
244 has_broken_texture_view_formats = is_amd || is_intel; 244 has_broken_texture_view_formats = is_amd || (!is_linux && is_intel);
245 has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2; 245 has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2;
246 has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory; 246 has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory;
247 has_debugging_tool_attached = IsDebugToolAttached(extensions); 247 has_debugging_tool_attached = IsDebugToolAttached(extensions);
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 623b43d8a..ffe9edc1b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -543,8 +543,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src,
543} 543}
544 544
545void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src, 545void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src,
546 const std::array<Offset2D, 2>& dst_region, 546 const Region2D& dst_region, const Region2D& src_region,
547 const std::array<Offset2D, 2>& src_region,
548 Tegra::Engines::Fermi2D::Filter filter, 547 Tegra::Engines::Fermi2D::Filter filter,
549 Tegra::Engines::Fermi2D::Operation operation) { 548 Tegra::Engines::Fermi2D::Operation operation) {
550 state_tracker.NotifyScissor0(); 549 state_tracker.NotifyScissor0();
@@ -560,9 +559,9 @@ void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src,
560 const GLbitfield buffer_bits = dst->BufferBits(); 559 const GLbitfield buffer_bits = dst->BufferBits();
561 const bool has_depth = (buffer_bits & ~GL_COLOR_BUFFER_BIT) != 0; 560 const bool has_depth = (buffer_bits & ~GL_COLOR_BUFFER_BIT) != 0;
562 const bool is_linear = !has_depth && filter == Tegra::Engines::Fermi2D::Filter::Bilinear; 561 const bool is_linear = !has_depth && filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
563 glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region[0].x, src_region[0].y, 562 glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region.start.x, src_region.start.y,
564 src_region[1].x, src_region[1].y, dst_region[0].x, dst_region[0].y, 563 src_region.end.x, src_region.end.y, dst_region.start.x,
565 dst_region[1].x, dst_region[1].y, buffer_bits, 564 dst_region.start.y, dst_region.end.x, dst_region.end.y, buffer_bits,
566 is_linear ? GL_LINEAR : GL_NEAREST); 565 is_linear ? GL_LINEAR : GL_NEAREST);
567} 566}
568 567
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 3c871541b..df8be12ff 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -28,7 +28,7 @@ using VideoCommon::ImageId;
28using VideoCommon::ImageViewId; 28using VideoCommon::ImageViewId;
29using VideoCommon::ImageViewType; 29using VideoCommon::ImageViewType;
30using VideoCommon::NUM_RT; 30using VideoCommon::NUM_RT;
31using VideoCommon::Offset2D; 31using VideoCommon::Region2D;
32using VideoCommon::RenderTargets; 32using VideoCommon::RenderTargets;
33 33
34struct ImageBufferMap { 34struct ImageBufferMap {
@@ -73,10 +73,8 @@ public:
73 73
74 void EmulateCopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); 74 void EmulateCopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
75 75
76 void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, 76 void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, const Region2D& dst_region,
77 const std::array<Offset2D, 2>& dst_region, 77 const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
78 const std::array<Offset2D, 2>& src_region,
79 Tegra::Engines::Fermi2D::Filter filter,
80 Tegra::Engines::Fermi2D::Operation operation); 78 Tegra::Engines::Fermi2D::Operation operation);
81 79
82 void AccelerateImageUpload(Image& image, const ImageBufferMap& map, 80 void AccelerateImageUpload(Image& image, const ImageBufferMap& map,
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index cc2e499f9..a718bff7a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -155,6 +155,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
155 155
156 ++m_current_frame; 156 ++m_current_frame;
157 157
158 gpu.RendererFrameEndNotify();
158 rasterizer.TickFrame(); 159 rasterizer.TickFrame();
159 160
160 context->SwapBuffers(); 161 context->SwapBuffers();
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 1f6a169ae..b7f5b8bc2 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -289,16 +289,15 @@ void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descri
289 device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); 289 device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
290} 290}
291 291
292void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, 292void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
293 const std::array<Offset2D, 2>& dst_region, 293 const Region2D& src_region) {
294 const std::array<Offset2D, 2>& src_region) {
295 const VkOffset2D offset{ 294 const VkOffset2D offset{
296 .x = std::min(dst_region[0].x, dst_region[1].x), 295 .x = std::min(dst_region.start.x, dst_region.end.x),
297 .y = std::min(dst_region[0].y, dst_region[1].y), 296 .y = std::min(dst_region.start.y, dst_region.end.y),
298 }; 297 };
299 const VkExtent2D extent{ 298 const VkExtent2D extent{
300 .width = static_cast<u32>(std::abs(dst_region[1].x - dst_region[0].x)), 299 .width = static_cast<u32>(std::abs(dst_region.end.x - dst_region.start.x)),
301 .height = static_cast<u32>(std::abs(dst_region[1].y - dst_region[0].y)), 300 .height = static_cast<u32>(std::abs(dst_region.end.y - dst_region.start.y)),
302 }; 301 };
303 const VkViewport viewport{ 302 const VkViewport viewport{
304 .x = static_cast<float>(offset.x), 303 .x = static_cast<float>(offset.x),
@@ -313,11 +312,12 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
313 .offset = offset, 312 .offset = offset,
314 .extent = extent, 313 .extent = extent,
315 }; 314 };
316 const float scale_x = static_cast<float>(src_region[1].x - src_region[0].x); 315 const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x);
317 const float scale_y = static_cast<float>(src_region[1].y - src_region[0].y); 316 const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y);
318 const PushConstants push_constants{ 317 const PushConstants push_constants{
319 .tex_scale = {scale_x, scale_y}, 318 .tex_scale = {scale_x, scale_y},
320 .tex_offset = {static_cast<float>(src_region[0].x), static_cast<float>(src_region[0].y)}, 319 .tex_offset = {static_cast<float>(src_region.start.x),
320 static_cast<float>(src_region.start.y)},
321 }; 321 };
322 cmdbuf.SetViewport(0, viewport); 322 cmdbuf.SetViewport(0, viewport);
323 cmdbuf.SetScissor(0, scissor); 323 cmdbuf.SetScissor(0, scissor);
@@ -353,8 +353,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
353BlitImageHelper::~BlitImageHelper() = default; 353BlitImageHelper::~BlitImageHelper() = default;
354 354
355void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, 355void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
356 const std::array<Offset2D, 2>& dst_region, 356 const Region2D& dst_region, const Region2D& src_region,
357 const std::array<Offset2D, 2>& src_region,
358 Tegra::Engines::Fermi2D::Filter filter, 357 Tegra::Engines::Fermi2D::Filter filter,
359 Tegra::Engines::Fermi2D::Operation operation) { 358 Tegra::Engines::Fermi2D::Operation operation) {
360 const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear; 359 const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
@@ -383,8 +382,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
383 382
384void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, 383void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
385 VkImageView src_depth_view, VkImageView src_stencil_view, 384 VkImageView src_depth_view, VkImageView src_stencil_view,
386 const std::array<Offset2D, 2>& dst_region, 385 const Region2D& dst_region, const Region2D& src_region,
387 const std::array<Offset2D, 2>& src_region,
388 Tegra::Engines::Fermi2D::Filter filter, 386 Tegra::Engines::Fermi2D::Filter filter,
389 Tegra::Engines::Fermi2D::Operation operation) { 387 Tegra::Engines::Fermi2D::Operation operation) {
390 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); 388 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index 43fd3d737..0d81a06ed 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -13,7 +13,7 @@
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
16using VideoCommon::Offset2D; 16using VideoCommon::Region2D;
17 17
18class Device; 18class Device;
19class Framebuffer; 19class Framebuffer;
@@ -35,15 +35,13 @@ public:
35 ~BlitImageHelper(); 35 ~BlitImageHelper();
36 36
37 void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, 37 void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
38 const std::array<Offset2D, 2>& dst_region, 38 const Region2D& dst_region, const Region2D& src_region,
39 const std::array<Offset2D, 2>& src_region,
40 Tegra::Engines::Fermi2D::Filter filter, 39 Tegra::Engines::Fermi2D::Filter filter,
41 Tegra::Engines::Fermi2D::Operation operation); 40 Tegra::Engines::Fermi2D::Operation operation);
42 41
43 void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, 42 void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view,
44 VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region, 43 VkImageView src_stencil_view, const Region2D& dst_region,
45 const std::array<Offset2D, 2>& src_region, 44 const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
46 Tegra::Engines::Fermi2D::Filter filter,
47 Tegra::Engines::Fermi2D::Operation operation); 45 Tegra::Engines::Fermi2D::Operation operation);
48 46
49 void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); 47 void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 2e0cf4232..3986eb172 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -154,6 +154,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
154 if (swapchain.Present(render_semaphore)) { 154 if (swapchain.Present(render_semaphore)) {
155 blit_screen.Recreate(); 155 blit_screen.Recreate();
156 } 156 }
157 gpu.RendererFrameEndNotify();
157 rasterizer.TickFrame(); 158 rasterizer.TickFrame();
158 } 159 }
159 160
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 017348e05..bdd0ce8bc 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -490,8 +490,7 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
490 write_barrier); 490 write_barrier);
491} 491}
492 492
493[[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region, 493[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region,
494 const std::array<Offset2D, 2>& src_region,
495 const VkImageSubresourceLayers& dst_layers, 494 const VkImageSubresourceLayers& dst_layers,
496 const VkImageSubresourceLayers& src_layers) { 495 const VkImageSubresourceLayers& src_layers) {
497 return VkImageBlit{ 496 return VkImageBlit{
@@ -499,13 +498,13 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
499 .srcOffsets = 498 .srcOffsets =
500 { 499 {
501 { 500 {
502 .x = src_region[0].x, 501 .x = src_region.start.x,
503 .y = src_region[0].y, 502 .y = src_region.start.y,
504 .z = 0, 503 .z = 0,
505 }, 504 },
506 { 505 {
507 .x = src_region[1].x, 506 .x = src_region.end.x,
508 .y = src_region[1].y, 507 .y = src_region.end.y,
509 .z = 1, 508 .z = 1,
510 }, 509 },
511 }, 510 },
@@ -513,42 +512,42 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
513 .dstOffsets = 512 .dstOffsets =
514 { 513 {
515 { 514 {
516 .x = dst_region[0].x, 515 .x = dst_region.start.x,
517 .y = dst_region[0].y, 516 .y = dst_region.start.y,
518 .z = 0, 517 .z = 0,
519 }, 518 },
520 { 519 {
521 .x = dst_region[1].x, 520 .x = dst_region.end.x,
522 .y = dst_region[1].y, 521 .y = dst_region.end.y,
523 .z = 1, 522 .z = 1,
524 }, 523 },
525 }, 524 },
526 }; 525 };
527} 526}
528 527
529[[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region, 528[[nodiscard]] VkImageResolve MakeImageResolve(const Region2D& dst_region,
530 const std::array<Offset2D, 2>& src_region, 529 const Region2D& src_region,
531 const VkImageSubresourceLayers& dst_layers, 530 const VkImageSubresourceLayers& dst_layers,
532 const VkImageSubresourceLayers& src_layers) { 531 const VkImageSubresourceLayers& src_layers) {
533 return VkImageResolve{ 532 return VkImageResolve{
534 .srcSubresource = src_layers, 533 .srcSubresource = src_layers,
535 .srcOffset = 534 .srcOffset =
536 { 535 {
537 .x = src_region[0].x, 536 .x = src_region.start.x,
538 .y = src_region[0].y, 537 .y = src_region.start.y,
539 .z = 0, 538 .z = 0,
540 }, 539 },
541 .dstSubresource = dst_layers, 540 .dstSubresource = dst_layers,
542 .dstOffset = 541 .dstOffset =
543 { 542 {
544 .x = dst_region[0].x, 543 .x = dst_region.start.x,
545 .y = dst_region[0].y, 544 .y = dst_region.start.y,
546 .z = 0, 545 .z = 0,
547 }, 546 },
548 .extent = 547 .extent =
549 { 548 {
550 .width = static_cast<u32>(dst_region[1].x - dst_region[0].x), 549 .width = static_cast<u32>(dst_region.end.x - dst_region.start.x),
551 .height = static_cast<u32>(dst_region[1].y - dst_region[0].y), 550 .height = static_cast<u32>(dst_region.end.y - dst_region.start.y),
552 .depth = 1, 551 .depth = 1,
553 }, 552 },
554 }; 553 };
@@ -602,8 +601,7 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
602} 601}
603 602
604void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, 603void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
605 const std::array<Offset2D, 2>& dst_region, 604 const Region2D& dst_region, const Region2D& src_region,
606 const std::array<Offset2D, 2>& src_region,
607 Tegra::Engines::Fermi2D::Filter filter, 605 Tegra::Engines::Fermi2D::Filter filter,
608 Tegra::Engines::Fermi2D::Operation operation) { 606 Tegra::Engines::Fermi2D::Operation operation) {
609 const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format); 607 const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format);
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 628785d5e..4a57d378b 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -16,7 +16,7 @@ namespace Vulkan {
16 16
17using VideoCommon::ImageId; 17using VideoCommon::ImageId;
18using VideoCommon::NUM_RT; 18using VideoCommon::NUM_RT;
19using VideoCommon::Offset2D; 19using VideoCommon::Region2D;
20using VideoCommon::RenderTargets; 20using VideoCommon::RenderTargets;
21using VideoCore::Surface::PixelFormat; 21using VideoCore::Surface::PixelFormat;
22 22
@@ -71,8 +71,7 @@ struct TextureCacheRuntime {
71 [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size); 71 [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size);
72 72
73 void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, 73 void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
74 const std::array<Offset2D, 2>& dst_region, 74 const Region2D& dst_region, const Region2D& src_region,
75 const std::array<Offset2D, 2>& src_region,
76 Tegra::Engines::Fermi2D::Filter filter, 75 Tegra::Engines::Fermi2D::Filter filter,
77 Tegra::Engines::Fermi2D::Operation operation); 76 Tegra::Engines::Fermi2D::Operation operation);
78 77
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 98e33c3a0..59b7c678b 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -148,7 +148,9 @@ public:
148 /// Blit an image with the given parameters 148 /// Blit an image with the given parameters
149 void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, 149 void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
150 const Tegra::Engines::Fermi2D::Surface& src, 150 const Tegra::Engines::Fermi2D::Surface& src,
151 const Tegra::Engines::Fermi2D::Config& copy); 151 const Tegra::Engines::Fermi2D::Config& copy,
152 std::optional<Region2D> src_region_override = {},
153 std::optional<Region2D> dst_region_override = {});
152 154
153 /// Invalidate the contents of the color buffer index 155 /// Invalidate the contents of the color buffer index
154 /// These contents become unspecified, the cache can assume aggressive optimizations. 156 /// These contents become unspecified, the cache can assume aggressive optimizations.
@@ -615,7 +617,9 @@ void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) {
615template <class P> 617template <class P>
616void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, 618void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
617 const Tegra::Engines::Fermi2D::Surface& src, 619 const Tegra::Engines::Fermi2D::Surface& src,
618 const Tegra::Engines::Fermi2D::Config& copy) { 620 const Tegra::Engines::Fermi2D::Config& copy,
621 std::optional<Region2D> src_override,
622 std::optional<Region2D> dst_override) {
619 const BlitImages images = GetBlitImages(dst, src); 623 const BlitImages images = GetBlitImages(dst, src);
620 const ImageId dst_id = images.dst_id; 624 const ImageId dst_id = images.dst_id;
621 const ImageId src_id = images.src_id; 625 const ImageId src_id = images.src_id;
@@ -631,20 +635,42 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
631 const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range); 635 const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
632 const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info); 636 const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
633 const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples); 637 const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
634 const std::array src_region{ 638
635 Offset2D{.x = copy.src_x0 >> src_samples_x, .y = copy.src_y0 >> src_samples_y}, 639 // out of bounds texture blit checking
636 Offset2D{.x = copy.src_x1 >> src_samples_x, .y = copy.src_y1 >> src_samples_y}, 640 const bool use_override = src_override.has_value();
641 const s32 src_x0 = copy.src_x0 >> src_samples_x;
642 s32 src_x1 = use_override ? src_override->end.x : copy.src_x1 >> src_samples_x;
643 const s32 src_y0 = copy.src_y0 >> src_samples_y;
644 const s32 src_y1 = copy.src_y1 >> src_samples_y;
645
646 const auto src_width = static_cast<s32>(src_image.info.size.width);
647 const bool width_oob = src_x1 > src_width;
648 const auto width_diff = width_oob ? src_x1 - src_width : 0;
649 if (width_oob) {
650 src_x1 = src_width;
651 }
652
653 const Region2D src_dimensions{
654 Offset2D{.x = src_x0, .y = src_y0},
655 Offset2D{.x = src_x1, .y = src_y1},
637 }; 656 };
657 const auto src_region = use_override ? *src_override : src_dimensions;
638 658
639 const std::optional src_base = src_image.TryFindBase(src.Address()); 659 const std::optional src_base = src_image.TryFindBase(src.Address());
640 const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}}; 660 const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}};
641 const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range); 661 const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range);
642 const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info); 662 const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info);
643 const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples); 663 const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples);
644 const std::array dst_region{ 664
645 Offset2D{.x = copy.dst_x0 >> dst_samples_x, .y = copy.dst_y0 >> dst_samples_y}, 665 const s32 dst_x0 = copy.dst_x0 >> dst_samples_x;
646 Offset2D{.x = copy.dst_x1 >> dst_samples_x, .y = copy.dst_y1 >> dst_samples_y}, 666 const s32 dst_x1 = copy.dst_x1 >> dst_samples_x;
667 const s32 dst_y0 = copy.dst_y0 >> dst_samples_y;
668 const s32 dst_y1 = copy.dst_y1 >> dst_samples_y;
669 const Region2D dst_dimensions{
670 Offset2D{.x = dst_x0, .y = dst_y0},
671 Offset2D{.x = dst_x1 - width_diff, .y = dst_y1},
647 }; 672 };
673 const auto dst_region = use_override ? *dst_override : dst_dimensions;
648 674
649 // Always call this after src_framebuffer_id was queried, as the address might be invalidated. 675 // Always call this after src_framebuffer_id was queried, as the address might be invalidated.
650 Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id]; 676 Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id];
@@ -661,6 +687,21 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
661 runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter, 687 runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter,
662 copy.operation); 688 copy.operation);
663 } 689 }
690
691 if (width_oob) {
692 // Continue copy of the oob region of the texture on the next row
693 auto oob_src = src;
694 oob_src.height++;
695 const Region2D src_region_override{
696 Offset2D{.x = 0, .y = src_y0 + 1},
697 Offset2D{.x = width_diff, .y = src_y1 + 1},
698 };
699 const Region2D dst_region_override{
700 Offset2D{.x = dst_x1 - width_diff, .y = dst_y0},
701 Offset2D{.x = dst_x1, .y = dst_y1},
702 };
703 BlitImage(dst, oob_src, copy, src_region_override, dst_region_override);
704 }
664} 705}
665 706
666template <class P> 707template <class P>
diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h
index 2ad2d72a6..c9571f7e4 100644
--- a/src/video_core/texture_cache/types.h
+++ b/src/video_core/texture_cache/types.h
@@ -64,6 +64,13 @@ struct Offset3D {
64 s32 z; 64 s32 z;
65}; 65};
66 66
67struct Region2D {
68 constexpr auto operator<=>(const Region2D&) const noexcept = default;
69
70 Offset2D start;
71 Offset2D end;
72};
73
67struct Extent2D { 74struct Extent2D {
68 constexpr auto operator<=>(const Extent2D&) const noexcept = default; 75 constexpr auto operator<=>(const Extent2D&) const noexcept = default;
69 76
diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp
index 695b2ef5f..a2e0e6962 100644
--- a/src/yuzu/about_dialog.cpp
+++ b/src/yuzu/about_dialog.cpp
@@ -9,17 +9,19 @@
9#include "yuzu/about_dialog.h" 9#include "yuzu/about_dialog.h"
10 10
11AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { 11AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) {
12 const auto branch_name = std::string(Common::g_scm_branch);
13 const auto description = std::string(Common::g_scm_desc);
12 const auto build_id = std::string(Common::g_build_id); 14 const auto build_id = std::string(Common::g_build_id);
13 const auto fmt = std::string(Common::g_title_bar_format_idle); 15
14 const auto yuzu_build_version = 16 const auto yuzu_build = fmt::format("yuzu Development Build | {}-{}", branch_name, description);
15 fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{}, 17 const auto override_build = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
16 std::string{}, std::string{}, std::string{}, build_id); 18 const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build;
17 19
18 ui->setupUi(this); 20 ui->setupUi(this);
19 ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200)); 21 ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200));
20 ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg( 22 ui->labelBuildInfo->setText(
21 QString::fromStdString(yuzu_build_version), QString::fromUtf8(Common::g_scm_branch), 23 ui->labelBuildInfo->text().arg(QString::fromStdString(yuzu_build_version),
22 QString::fromUtf8(Common::g_scm_desc), QString::fromUtf8(Common::g_build_date).left(10))); 24 QString::fromUtf8(Common::g_build_date).left(10)));
23} 25}
24 26
25AboutDialog::~AboutDialog() = default; 27AboutDialog::~AboutDialog() = default;
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui
index 1b320630c..27d81cd13 100644
--- a/src/yuzu/aboutdialog.ui
+++ b/src/yuzu/aboutdialog.ui
@@ -70,7 +70,7 @@
70 </sizepolicy> 70 </sizepolicy>
71 </property> 71 </property>
72 <property name="text"> 72 <property name="text">
73 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 73 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 (%2)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
74 </property> 74 </property>
75 </widget> 75 </widget>
76 </item> 76 </item>
diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp
index 653486493..b0f764994 100644
--- a/src/yuzu/applets/software_keyboard.cpp
+++ b/src/yuzu/applets/software_keyboard.cpp
@@ -404,12 +404,16 @@ void QtSoftwareKeyboardDialog::ShowTextCheckDialog(
404 404
405 OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message), 405 OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message),
406 tr("Cancel"), tr("OK"), Qt::AlignCenter); 406 tr("Cancel"), tr("OK"), Qt::AlignCenter);
407 if (dialog.exec() == QDialog::Accepted) { 407 if (dialog.exec() != QDialog::Accepted) {
408 emit SubmitNormalText(SwkbdResult::Ok, current_text); 408 StartInputThread();
409 break; 409 break;
410 } 410 }
411 411
412 StartInputThread(); 412 auto text = ui->topOSK->currentIndex() == 1
413 ? ui->text_edit_osk->toPlainText().toStdU16String()
414 : ui->line_edit_osk->text().toStdU16String();
415
416 emit SubmitNormalText(SwkbdResult::Ok, std::move(text));
413 break; 417 break;
414 } 418 }
415 } 419 }
@@ -480,11 +484,7 @@ void QtSoftwareKeyboardDialog::open() {
480void QtSoftwareKeyboardDialog::reject() { 484void QtSoftwareKeyboardDialog::reject() {
481 // Pressing the ESC key in a dialog calls QDialog::reject(). 485 // Pressing the ESC key in a dialog calls QDialog::reject().
482 // We will override this behavior to the "Cancel" action on the software keyboard. 486 // We will override this behavior to the "Cancel" action on the software keyboard.
483 if (is_inline) { 487 TranslateButtonPress(HIDButton::X);
484 emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
485 } else {
486 emit SubmitNormalText(SwkbdResult::Cancel, current_text);
487 }
488} 488}
489 489
490void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) { 490void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index e80a3df77..125feb86b 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -736,10 +736,16 @@ void Config::ReadPathValues() {
736void Config::ReadCpuValues() { 736void Config::ReadCpuValues() {
737 qt_config->beginGroup(QStringLiteral("Cpu")); 737 qt_config->beginGroup(QStringLiteral("Cpu"));
738 738
739 if (global) { 739 ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"), 0);
740 Settings::values.cpu_accuracy = static_cast<Settings::CPUAccuracy>( 740
741 ReadSetting(QStringLiteral("cpu_accuracy"), 0).toInt()); 741 ReadSettingGlobal(Settings::values.cpuopt_unsafe_unfuse_fma,
742 QStringLiteral("cpuopt_unsafe_unfuse_fma"), true);
743 ReadSettingGlobal(Settings::values.cpuopt_unsafe_reduce_fp_error,
744 QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true);
745 ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan,
746 QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true);
742 747
748 if (global) {
743 Settings::values.cpuopt_page_tables = 749 Settings::values.cpuopt_page_tables =
744 ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool(); 750 ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool();
745 Settings::values.cpuopt_block_linking = 751 Settings::values.cpuopt_block_linking =
@@ -756,13 +762,6 @@ void Config::ReadCpuValues() {
756 ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool(); 762 ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
757 Settings::values.cpuopt_reduce_misalign_checks = 763 Settings::values.cpuopt_reduce_misalign_checks =
758 ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool(); 764 ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
759
760 Settings::values.cpuopt_unsafe_unfuse_fma =
761 ReadSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), true).toBool();
762 Settings::values.cpuopt_unsafe_reduce_fp_error =
763 ReadSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true).toBool();
764 Settings::values.cpuopt_unsafe_inaccurate_nan =
765 ReadSetting(QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true).toBool();
766 } 765 }
767 766
768 qt_config->endGroup(); 767 qt_config->endGroup();
@@ -869,17 +868,14 @@ void Config::ReadSystemValues() {
869 } 868 }
870 } 869 }
871 870
872 bool custom_rtc_enabled; 871 if (global) {
873 ReadSettingGlobal(custom_rtc_enabled, QStringLiteral("custom_rtc_enabled"), false); 872 const auto custom_rtc_enabled =
874 bool custom_rtc_global = 873 ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool();
875 global || qt_config->value(QStringLiteral("custom_rtc/use_global"), true).toBool();
876 Settings::values.custom_rtc.SetGlobal(custom_rtc_global);
877 if (global || !custom_rtc_global) {
878 if (custom_rtc_enabled) { 874 if (custom_rtc_enabled) {
879 Settings::values.custom_rtc.SetValue( 875 Settings::values.custom_rtc =
880 std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong())); 876 std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong());
881 } else { 877 } else {
882 Settings::values.custom_rtc.SetValue(std::nullopt); 878 Settings::values.custom_rtc = std::nullopt;
883 } 879 }
884 } 880 }
885 881
@@ -1313,10 +1309,19 @@ void Config::SavePathValues() {
1313void Config::SaveCpuValues() { 1309void Config::SaveCpuValues() {
1314 qt_config->beginGroup(QStringLiteral("Cpu")); 1310 qt_config->beginGroup(QStringLiteral("Cpu"));
1315 1311
1316 if (global) { 1312 WriteSettingGlobal(QStringLiteral("cpu_accuracy"),
1317 WriteSetting(QStringLiteral("cpu_accuracy"), 1313 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
1318 static_cast<int>(Settings::values.cpu_accuracy), 0); 1314 Settings::values.cpu_accuracy.UsingGlobal(),
1315 static_cast<u32>(Settings::CPUAccuracy::Accurate));
1319 1316
1317 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
1318 Settings::values.cpuopt_unsafe_unfuse_fma, true);
1319 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
1320 Settings::values.cpuopt_unsafe_reduce_fp_error, true);
1321 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
1322 Settings::values.cpuopt_unsafe_inaccurate_nan, true);
1323
1324 if (global) {
1320 WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables, 1325 WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
1321 true); 1326 true);
1322 WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking, 1327 WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking,
@@ -1331,13 +1336,6 @@ void Config::SaveCpuValues() {
1331 WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true); 1336 WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
1332 WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), 1337 WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
1333 Settings::values.cpuopt_reduce_misalign_checks, true); 1338 Settings::values.cpuopt_reduce_misalign_checks, true);
1334
1335 WriteSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
1336 Settings::values.cpuopt_unsafe_unfuse_fma, true);
1337 WriteSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
1338 Settings::values.cpuopt_unsafe_reduce_fp_error, true);
1339 WriteSetting(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
1340 Settings::values.cpuopt_unsafe_inaccurate_nan, true);
1341 } 1339 }
1342 1340
1343 qt_config->endGroup(); 1341 qt_config->endGroup();
@@ -1432,14 +1430,14 @@ void Config::SaveSystemValues() {
1432 Settings::values.rng_seed.GetValue(global).value_or(0), 1430 Settings::values.rng_seed.GetValue(global).value_or(0),
1433 Settings::values.rng_seed.UsingGlobal(), 0); 1431 Settings::values.rng_seed.UsingGlobal(), 0);
1434 1432
1435 WriteSettingGlobal(QStringLiteral("custom_rtc_enabled"), 1433 if (global) {
1436 Settings::values.custom_rtc.GetValue(global).has_value(), 1434 WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
1437 Settings::values.custom_rtc.UsingGlobal(), false); 1435 false);
1438 WriteSettingGlobal( 1436 WriteSetting(QStringLiteral("custom_rtc"),
1439 QStringLiteral("custom_rtc"), 1437 QVariant::fromValue<long long>(
1440 QVariant::fromValue<long long>( 1438 Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()),
1441 Settings::values.custom_rtc.GetValue(global).value_or(std::chrono::seconds{}).count()), 1439 0);
1442 Settings::values.custom_rtc.UsingGlobal(), 0); 1440 }
1443 1441
1444 WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1); 1442 WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
1445 1443
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 5a2c026b3..ce3355588 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -132,5 +132,6 @@ private:
132}; 132};
133 133
134// These metatype declarations cannot be in common/settings.h because core is devoid of QT 134// These metatype declarations cannot be in common/settings.h because core is devoid of QT
135Q_DECLARE_METATYPE(Settings::CPUAccuracy);
135Q_DECLARE_METATYPE(Settings::RendererBackend); 136Q_DECLARE_METATYPE(Settings::RendererBackend);
136Q_DECLARE_METATYPE(Settings::GPUAccuracy); 137Q_DECLARE_METATYPE(Settings::GPUAccuracy);
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp
index 89be4a62d..096e42e94 100644
--- a/src/yuzu/configuration/configuration_shared.cpp
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -13,32 +13,29 @@
13void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting, 13void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
14 const QCheckBox* checkbox, 14 const QCheckBox* checkbox,
15 const CheckState& tracker) { 15 const CheckState& tracker) {
16 if (tracker == CheckState::Global) { 16 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
17 setting->SetGlobal(true);
18 } else {
19 setting->SetGlobal(false);
20 setting->SetValue(checkbox->checkState()); 17 setting->SetValue(checkbox->checkState());
18 } else if (!Settings::IsConfiguringGlobal()) {
19 if (tracker == CheckState::Global) {
20 setting->SetGlobal(true);
21 } else {
22 setting->SetGlobal(false);
23 setting->SetValue(checkbox->checkState());
24 }
21 } 25 }
22} 26}
23 27
24void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting, 28void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting,
25 const QComboBox* combobox) { 29 const QComboBox* combobox) {
26 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 30 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
27 setting->SetGlobal(true); 31 setting->SetValue(combobox->currentIndex());
28 } else { 32 } else if (!Settings::IsConfiguringGlobal()) {
29 setting->SetGlobal(false); 33 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
30 setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET); 34 setting->SetGlobal(true);
31 } 35 } else {
32} 36 setting->SetGlobal(false);
33 37 setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET);
34void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting, 38 }
35 const QComboBox* combobox) {
36 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
37 setting->SetGlobal(true);
38 } else {
39 setting->SetGlobal(false);
40 setting->SetValue(static_cast<Settings::RendererBackend>(
41 combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
42 } 39 }
43} 40}
44 41
@@ -51,27 +48,6 @@ void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
51 } 48 }
52} 49}
53 50
54void ConfigurationShared::SetPerGameSetting(QComboBox* combobox,
55 const Settings::Setting<int>* setting) {
56 combobox->setCurrentIndex(setting->UsingGlobal()
57 ? ConfigurationShared::USE_GLOBAL_INDEX
58 : setting->GetValue() + ConfigurationShared::USE_GLOBAL_OFFSET);
59}
60
61void ConfigurationShared::SetPerGameSetting(
62 QComboBox* combobox, const Settings::Setting<Settings::RendererBackend>* setting) {
63 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
64 : static_cast<int>(setting->GetValue()) +
65 ConfigurationShared::USE_GLOBAL_OFFSET);
66}
67
68void ConfigurationShared::SetPerGameSetting(
69 QComboBox* combobox, const Settings::Setting<Settings::GPUAccuracy>* setting) {
70 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
71 : static_cast<int>(setting->GetValue()) +
72 ConfigurationShared::USE_GLOBAL_OFFSET);
73}
74
75void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) { 51void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) {
76 if (highlighted) { 52 if (highlighted) {
77 widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }") 53 widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }")
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
index 5b344cdbd..1e0ef01ca 100644
--- a/src/yuzu/configuration/configuration_shared.h
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -15,37 +15,45 @@ constexpr int USE_GLOBAL_INDEX = 0;
15constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1; 15constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
16constexpr int USE_GLOBAL_OFFSET = 2; 16constexpr int USE_GLOBAL_OFFSET = 2;
17 17
18// CheckBoxes require a tracker for their state since we emulate a tristate CheckBox
18enum class CheckState { 19enum class CheckState {
19 Off, 20 Off, // Checkbox overrides to off/false
20 On, 21 On, // Checkbox overrides to on/true
21 Global, 22 Global, // Checkbox defers to the global state
22 Count, 23 Count, // Simply the number of states, not a valid checkbox state
23}; 24};
24 25
25// Global-aware apply and set functions 26// Global-aware apply and set functions
26 27
28// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting
27void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox, 29void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox,
28 const CheckState& tracker); 30 const CheckState& tracker);
29void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox); 31void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox);
30void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
31 const QComboBox* combobox);
32void ApplyPerGameSetting(Settings::Setting<Settings::GPUAccuracy>* setting,
33 const QComboBox* combobox);
34 32
33// Sets a Qt UI element given a Settings::Setting
35void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting); 34void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting);
36void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<int>* setting);
37void SetPerGameSetting(QComboBox* combobox,
38 const Settings::Setting<Settings::RendererBackend>* setting);
39void SetPerGameSetting(QComboBox* combobox,
40 const Settings::Setting<Settings::GPUAccuracy>* setting);
41 35
36template <typename Type>
37void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<Type>* setting) {
38 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
39 : static_cast<int>(setting->GetValue()) +
40 ConfigurationShared::USE_GLOBAL_OFFSET);
41}
42
43// (Un)highlights a Qt UI element
42void SetHighlight(QWidget* widget, bool highlighted); 44void SetHighlight(QWidget* widget, bool highlighted);
45
46// Sets up a QCheckBox like a tristate one, given a Setting
43void SetColoredTristate(QCheckBox* checkbox, const Settings::Setting<bool>& setting, 47void SetColoredTristate(QCheckBox* checkbox, const Settings::Setting<bool>& setting,
44 CheckState& tracker); 48 CheckState& tracker);
45void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state, 49void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state,
46 CheckState& tracker); 50 CheckState& tracker);
51
52// Sets up coloring of a QWidget `target` based on the state of a QComboBox, and calls
53// InsertGlobalItem
47void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global); 54void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global);
48 55
56// Adds the "Use Global Configuration" selection and separator to the beginning of a QComboBox
49void InsertGlobalItem(QComboBox* combobox, int global_index); 57void InsertGlobalItem(QComboBox* combobox, int global_index);
50 58
51} // namespace ConfigurationShared 59} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index f9507e228..fc0191432 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -99,6 +99,9 @@ void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
99} 99}
100 100
101void ConfigureAudio::ApplyConfiguration() { 101void ConfigureAudio::ApplyConfiguration() {
102 ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
103 ui->toggle_audio_stretching, enable_audio_stretching);
104
102 if (Settings::IsConfiguringGlobal()) { 105 if (Settings::IsConfiguringGlobal()) {
103 Settings::values.sink_id = 106 Settings::values.sink_id =
104 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) 107 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
@@ -108,19 +111,12 @@ void ConfigureAudio::ApplyConfiguration() {
108 .toStdString(); 111 .toStdString();
109 112
110 // Guard if during game and set to game-specific value 113 // Guard if during game and set to game-specific value
111 if (Settings::values.enable_audio_stretching.UsingGlobal()) {
112 Settings::values.enable_audio_stretching.SetValue(
113 ui->toggle_audio_stretching->isChecked());
114 }
115 if (Settings::values.volume.UsingGlobal()) { 114 if (Settings::values.volume.UsingGlobal()) {
116 Settings::values.volume.SetValue( 115 Settings::values.volume.SetValue(
117 static_cast<float>(ui->volume_slider->sliderPosition()) / 116 static_cast<float>(ui->volume_slider->sliderPosition()) /
118 ui->volume_slider->maximum()); 117 ui->volume_slider->maximum());
119 } 118 }
120 } else { 119 } else {
121 ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
122 ui->toggle_audio_stretching,
123 enable_audio_stretching);
124 if (ui->volume_combo_box->currentIndex() == 0) { 120 if (ui->volume_combo_box->currentIndex() == 0) {
125 Settings::values.volume.SetGlobal(true); 121 Settings::values.volume.SetGlobal(true);
126 } else { 122 } else {
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 4f99bc80f..525c42ff0 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -10,11 +10,14 @@
10#include "common/settings.h" 10#include "common/settings.h"
11#include "core/core.h" 11#include "core/core.h"
12#include "ui_configure_cpu.h" 12#include "ui_configure_cpu.h"
13#include "yuzu/configuration/configuration_shared.h"
13#include "yuzu/configuration/configure_cpu.h" 14#include "yuzu/configuration/configure_cpu.h"
14 15
15ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) { 16ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) {
16 ui->setupUi(this); 17 ui->setupUi(this);
17 18
19 SetupPerGameUI();
20
18 SetConfiguration(); 21 SetConfiguration();
19 22
20 connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this, 23 connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
@@ -29,19 +32,29 @@ void ConfigureCpu::SetConfiguration() {
29 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 32 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
30 33
31 ui->accuracy->setEnabled(runtime_lock); 34 ui->accuracy->setEnabled(runtime_lock);
32 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy));
33 UpdateGroup(static_cast<int>(Settings::values.cpu_accuracy));
34
35 ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock); 35 ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
36 ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma);
37 ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock); 36 ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock);
38 ui->cpuopt_unsafe_reduce_fp_error->setChecked(Settings::values.cpuopt_unsafe_reduce_fp_error);
39 ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock); 37 ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock);
40 ui->cpuopt_unsafe_inaccurate_nan->setChecked(Settings::values.cpuopt_unsafe_inaccurate_nan); 38
39 ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue());
40 ui->cpuopt_unsafe_reduce_fp_error->setChecked(
41 Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue());
42 ui->cpuopt_unsafe_inaccurate_nan->setChecked(
43 Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue());
44
45 if (Settings::IsConfiguringGlobal()) {
46 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy.GetValue()));
47 } else {
48 ConfigurationShared::SetPerGameSetting(ui->accuracy, &Settings::values.cpu_accuracy);
49 ConfigurationShared::SetHighlight(ui->widget_accuracy,
50 !Settings::values.cpu_accuracy.UsingGlobal());
51 }
52 UpdateGroup(ui->accuracy->currentIndex());
41} 53}
42 54
43void ConfigureCpu::AccuracyUpdated(int index) { 55void ConfigureCpu::AccuracyUpdated(int index) {
44 if (static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) { 56 if (Settings::IsConfiguringGlobal() &&
57 static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
45 const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"), 58 const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"),
46 tr("CPU Debug Mode is only intended for developer " 59 tr("CPU Debug Mode is only intended for developer "
47 "use. Are you sure you want to enable this?"), 60 "use. Are you sure you want to enable this?"),
@@ -54,16 +67,39 @@ void ConfigureCpu::AccuracyUpdated(int index) {
54} 67}
55 68
56void ConfigureCpu::UpdateGroup(int index) { 69void ConfigureCpu::UpdateGroup(int index) {
57 ui->unsafe_group->setVisible(static_cast<Settings::CPUAccuracy>(index) == 70 if (!Settings::IsConfiguringGlobal()) {
58 Settings::CPUAccuracy::Unsafe); 71 index -= ConfigurationShared::USE_GLOBAL_OFFSET;
72 }
73 const auto accuracy = static_cast<Settings::CPUAccuracy>(index);
74 ui->unsafe_group->setVisible(accuracy == Settings::CPUAccuracy::Unsafe);
59} 75}
60 76
61void ConfigureCpu::ApplyConfiguration() { 77void ConfigureCpu::ApplyConfiguration() {
62 Settings::values.cpu_accuracy = 78 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma,
63 static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()); 79 ui->cpuopt_unsafe_unfuse_fma,
64 Settings::values.cpuopt_unsafe_unfuse_fma = ui->cpuopt_unsafe_unfuse_fma->isChecked(); 80 cpuopt_unsafe_unfuse_fma);
65 Settings::values.cpuopt_unsafe_reduce_fp_error = ui->cpuopt_unsafe_reduce_fp_error->isChecked(); 81 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_reduce_fp_error,
66 Settings::values.cpuopt_unsafe_inaccurate_nan = ui->cpuopt_unsafe_inaccurate_nan->isChecked(); 82 ui->cpuopt_unsafe_reduce_fp_error,
83 cpuopt_unsafe_reduce_fp_error);
84 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_inaccurate_nan,
85 ui->cpuopt_unsafe_inaccurate_nan,
86 cpuopt_unsafe_inaccurate_nan);
87
88 if (Settings::IsConfiguringGlobal()) {
89 // Guard if during game and set to game-specific value
90 if (Settings::values.cpu_accuracy.UsingGlobal()) {
91 Settings::values.cpu_accuracy.SetValue(
92 static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()));
93 }
94 } else {
95 if (ui->accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
96 Settings::values.cpu_accuracy.SetGlobal(true);
97 } else {
98 Settings::values.cpu_accuracy.SetGlobal(false);
99 Settings::values.cpu_accuracy.SetValue(static_cast<Settings::CPUAccuracy>(
100 ui->accuracy->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
101 }
102 }
67} 103}
68 104
69void ConfigureCpu::changeEvent(QEvent* event) { 105void ConfigureCpu::changeEvent(QEvent* event) {
@@ -77,3 +113,25 @@ void ConfigureCpu::changeEvent(QEvent* event) {
77void ConfigureCpu::RetranslateUI() { 113void ConfigureCpu::RetranslateUI() {
78 ui->retranslateUi(this); 114 ui->retranslateUi(this);
79} 115}
116
117void ConfigureCpu::SetupPerGameUI() {
118 if (Settings::IsConfiguringGlobal()) {
119 return;
120 }
121
122 ConfigurationShared::SetColoredComboBox(
123 ui->accuracy, ui->widget_accuracy,
124 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true)));
125 ui->accuracy->removeItem(static_cast<u32>(Settings::CPUAccuracy::DebugMode) +
126 ConfigurationShared::USE_GLOBAL_OFFSET);
127
128 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma,
129 Settings::values.cpuopt_unsafe_unfuse_fma,
130 cpuopt_unsafe_unfuse_fma);
131 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_reduce_fp_error,
132 Settings::values.cpuopt_unsafe_reduce_fp_error,
133 cpuopt_unsafe_reduce_fp_error);
134 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_inaccurate_nan,
135 Settings::values.cpuopt_unsafe_inaccurate_nan,
136 cpuopt_unsafe_inaccurate_nan);
137}
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index ef77b2e7e..8e2eeb7a6 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -8,6 +8,10 @@
8#include <QWidget> 8#include <QWidget>
9#include "common/settings.h" 9#include "common/settings.h"
10 10
11namespace ConfigurationShared {
12enum class CheckState;
13}
14
11namespace Ui { 15namespace Ui {
12class ConfigureCpu; 16class ConfigureCpu;
13} 17}
@@ -30,5 +34,11 @@ private:
30 34
31 void SetConfiguration(); 35 void SetConfiguration();
32 36
37 void SetupPerGameUI();
38
33 std::unique_ptr<Ui::ConfigureCpu> ui; 39 std::unique_ptr<Ui::ConfigureCpu> ui;
40
41 ConfigurationShared::CheckState cpuopt_unsafe_unfuse_fma;
42 ConfigurationShared::CheckState cpuopt_unsafe_reduce_fp_error;
43 ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan;
34}; 44};
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index bcd0962e9..d0e7e7bfe 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -23,42 +23,44 @@
23 </property> 23 </property>
24 <layout class="QVBoxLayout"> 24 <layout class="QVBoxLayout">
25 <item> 25 <item>
26 <layout class="QHBoxLayout"> 26 <widget class="QWidget" name="widget_accuracy" native="true">
27 <item> 27 <layout class="QHBoxLayout" name="layout_accuracy">
28 <widget class="QLabel"> 28 <item>
29 <property name="text"> 29 <widget class="QLabel" name="label">
30 <string>Accuracy:</string>
31 </property>
32 </widget>
33 </item>
34 <item>
35 <widget class="QComboBox" name="accuracy">
36 <item>
37 <property name="text"> 30 <property name="text">
38 <string>Accurate</string> 31 <string>Accuracy:</string>
39 </property> 32 </property>
40 </item> 33 </widget>
41 <item> 34 </item>
42 <property name="text"> 35 <item>
43 <string>Unsafe</string> 36 <widget class="QComboBox" name="accuracy">
44 </property> 37 <item>
45 </item> 38 <property name="text">
46 <item> 39 <string>Accurate</string>
47 <property name="text"> 40 </property>
48 <string>Enable Debug Mode</string> 41 </item>
49 </property> 42 <item>
50 </item> 43 <property name="text">
51 </widget> 44 <string>Unsafe</string>
52 </item> 45 </property>
53 </layout> 46 </item>
47 <item>
48 <property name="text">
49 <string>Enable Debug Mode</string>
50 </property>
51 </item>
52 </widget>
53 </item>
54 </layout>
55 </widget>
54 </item> 56 </item>
55 <item> 57 <item>
56 <widget class="QLabel"> 58 <widget class="QLabel" name="label">
57 <property name="wordWrap">
58 <bool>1</bool>
59 </property>
60 <property name="text"> 59 <property name="text">
61 <string>We recommend setting accuracy to "Accurate".</string> 60 <string>We recommend setting accuracy to &quot;Accurate&quot;.</string>
61 </property>
62 <property name="wordWrap">
63 <bool>false</bool>
62 </property> 64 </property>
63 </widget> 65 </widget>
64 </item> 66 </item>
@@ -76,49 +78,49 @@
76 </property> 78 </property>
77 <layout class="QVBoxLayout"> 79 <layout class="QVBoxLayout">
78 <item> 80 <item>
79 <widget class="QLabel"> 81 <widget class="QLabel" name="label">
80 <property name="wordWrap">
81 <bool>1</bool>
82 </property>
83 <property name="text"> 82 <property name="text">
84 <string>These settings reduce accuracy for speed.</string> 83 <string>These settings reduce accuracy for speed.</string>
85 </property> 84 </property>
85 <property name="wordWrap">
86 <bool>false</bool>
87 </property>
86 </widget> 88 </widget>
87 </item> 89 </item>
88 <item> 90 <item>
89 <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma"> 91 <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma">
90 <property name="text">
91 <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
92 </property>
93 <property name="toolTip"> 92 <property name="toolTip">
94 <string> 93 <string>
95 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt; 94 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
96 </string> 95 </string>
97 </property> 96 </property>
97 <property name="text">
98 <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
99 </property>
98 </widget> 100 </widget>
99 </item> 101 </item>
100 <item> 102 <item>
101 <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error"> 103 <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error">
102 <property name="text">
103 <string>Faster FRSQRTE and FRECPE</string>
104 </property>
105 <property name="toolTip"> 104 <property name="toolTip">
106 <string> 105 <string>
107 &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt; 106 &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
108 </string> 107 </string>
109 </property> 108 </property>
109 <property name="text">
110 <string>Faster FRSQRTE and FRECPE</string>
111 </property>
110 </widget> 112 </widget>
111 </item> 113 </item>
112 <item> 114 <item>
113 <widget class="QCheckBox" name="cpuopt_unsafe_inaccurate_nan"> 115 <widget class="QCheckBox" name="cpuopt_unsafe_inaccurate_nan">
114 <property name="text">
115 <string>Inaccurate NaN handling</string>
116 </property>
117 <property name="toolTip"> 116 <property name="toolTip">
118 <string> 117 <string>
119 &lt;div&gt;This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.&lt;/div&gt; 118 &lt;div&gt;This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.&lt;/div&gt;
120 </string> 119 </string>
121 </property> 120 </property>
121 <property name="text">
122 <string>Inaccurate NaN handling</string>
123 </property>
122 </widget> 124 </widget>
123 </item> 125 </item>
124 </layout> 126 </layout>
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index d812858b6..c9e60ee08 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -23,7 +23,7 @@
23 <item> 23 <item>
24 <layout class="QHBoxLayout" name="horizontalLayout_2"> 24 <layout class="QHBoxLayout" name="horizontalLayout_2">
25 <item> 25 <item>
26 <widget class="QLabel" name="label_2"> 26 <widget class="QLabel" name="label_1">
27 <property name="text"> 27 <property name="text">
28 <string>Global Log Filter</string> 28 <string>Global Log Filter</string>
29 </property> 29 </property>
@@ -66,7 +66,7 @@
66 </widget> 66 </widget>
67 </item> 67 </item>
68 <item> 68 <item>
69 <widget class="QLabel" name="label_3"> 69 <widget class="QLabel" name="label_2">
70 <property name="font"> 70 <property name="font">
71 <font> 71 <font>
72 <italic>true</italic> 72 <italic>true</italic>
@@ -92,7 +92,7 @@
92 <item> 92 <item>
93 <layout class="QHBoxLayout" name="horizontalLayout_4"> 93 <layout class="QHBoxLayout" name="horizontalLayout_4">
94 <item> 94 <item>
95 <widget class="QLabel" name="label_4"> 95 <widget class="QLabel" name="label_3">
96 <property name="text"> 96 <property name="text">
97 <string>Arguments String</string> 97 <string>Arguments String</string>
98 </property> 98 </property>
@@ -155,7 +155,7 @@
155 </widget> 155 </widget>
156 </item> 156 </item>
157 <item> 157 <item>
158 <widget class="QLabel" name="label_5"> 158 <widget class="QLabel" name="label_4">
159 <property name="font"> 159 <property name="font">
160 <font> 160 <font>
161 <italic>true</italic> 161 <italic>true</italic>
@@ -200,7 +200,7 @@
200 </widget> 200 </widget>
201 </item> 201 </item>
202 <item> 202 <item>
203 <widget class="QLabel" name="label_3"> 203 <widget class="QLabel" name="label_5">
204 <property name="font"> 204 <property name="font">
205 <font> 205 <font>
206 <italic>true</italic> 206 <italic>true</italic>
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 2fa88dcec..55a6a37bd 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -50,6 +50,9 @@ void ConfigureGeneral::SetConfiguration() {
50} 50}
51 51
52void ConfigureGeneral::ApplyConfiguration() { 52void ConfigureGeneral::ApplyConfiguration() {
53 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
54 use_multi_core);
55
53 if (Settings::IsConfiguringGlobal()) { 56 if (Settings::IsConfiguringGlobal()) {
54 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 57 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
55 UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); 58 UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
@@ -62,13 +65,7 @@ void ConfigureGeneral::ApplyConfiguration() {
62 Qt::Checked); 65 Qt::Checked);
63 Settings::values.frame_limit.SetValue(ui->frame_limit->value()); 66 Settings::values.frame_limit.SetValue(ui->frame_limit->value());
64 } 67 }
65 if (Settings::values.use_multi_core.UsingGlobal()) {
66 Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked());
67 }
68 } else { 68 } else {
69 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core,
70 ui->use_multi_core, use_multi_core);
71
72 bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global; 69 bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global;
73 Settings::values.use_frame_limit.SetGlobal(global_frame_limit); 70 Settings::values.use_frame_limit.SetGlobal(global_frame_limit);
74 Settings::values.frame_limit.SetGlobal(global_frame_limit); 71 Settings::values.frame_limit.SetGlobal(global_frame_limit);
@@ -94,6 +91,9 @@ void ConfigureGeneral::RetranslateUI() {
94 91
95void ConfigureGeneral::SetupPerGameUI() { 92void ConfigureGeneral::SetupPerGameUI() {
96 if (Settings::IsConfiguringGlobal()) { 93 if (Settings::IsConfiguringGlobal()) {
94 // Disables each setting if:
95 // - A game is running (thus settings in use), and
96 // - A non-global setting is applied.
97 ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal()); 97 ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal());
98 ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal()); 98 ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
99 99
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 0a7536617..fb9ec093c 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -106,6 +106,19 @@ void ConfigureGraphics::SetConfiguration() {
106} 106}
107 107
108void ConfigureGraphics::ApplyConfiguration() { 108void ConfigureGraphics::ApplyConfiguration() {
109 ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
110 ui->fullscreen_mode_combobox);
111 ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
112 ui->aspect_ratio_combobox);
113
114 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
115 ui->use_disk_shader_cache, use_disk_shader_cache);
116 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
117 ui->use_asynchronous_gpu_emulation,
118 use_asynchronous_gpu_emulation);
119 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_nvdec_emulation,
120 ui->use_nvdec_emulation, use_nvdec_emulation);
121
109 if (Settings::IsConfiguringGlobal()) { 122 if (Settings::IsConfiguringGlobal()) {
110 // Guard if during game and set to game-specific value 123 // Guard if during game and set to game-specific value
111 if (Settings::values.renderer_backend.UsingGlobal()) { 124 if (Settings::values.renderer_backend.UsingGlobal()) {
@@ -114,22 +127,6 @@ void ConfigureGraphics::ApplyConfiguration() {
114 if (Settings::values.vulkan_device.UsingGlobal()) { 127 if (Settings::values.vulkan_device.UsingGlobal()) {
115 Settings::values.vulkan_device.SetValue(vulkan_device); 128 Settings::values.vulkan_device.SetValue(vulkan_device);
116 } 129 }
117 if (Settings::values.fullscreen_mode.UsingGlobal()) {
118 Settings::values.fullscreen_mode.SetValue(ui->fullscreen_mode_combobox->currentIndex());
119 }
120 if (Settings::values.aspect_ratio.UsingGlobal()) {
121 Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
122 }
123 if (Settings::values.use_disk_shader_cache.UsingGlobal()) {
124 Settings::values.use_disk_shader_cache.SetValue(ui->use_disk_shader_cache->isChecked());
125 }
126 if (Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()) {
127 Settings::values.use_asynchronous_gpu_emulation.SetValue(
128 ui->use_asynchronous_gpu_emulation->isChecked());
129 }
130 if (Settings::values.use_nvdec_emulation.UsingGlobal()) {
131 Settings::values.use_nvdec_emulation.SetValue(ui->use_nvdec_emulation->isChecked());
132 }
133 if (Settings::values.bg_red.UsingGlobal()) { 130 if (Settings::values.bg_red.UsingGlobal()) {
134 Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF())); 131 Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
135 Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF())); 132 Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
@@ -150,19 +147,6 @@ void ConfigureGraphics::ApplyConfiguration() {
150 } 147 }
151 } 148 }
152 149
153 ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
154 ui->fullscreen_mode_combobox);
155 ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
156 ui->aspect_ratio_combobox);
157
158 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
159 ui->use_disk_shader_cache, use_disk_shader_cache);
160 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
161 ui->use_asynchronous_gpu_emulation,
162 use_asynchronous_gpu_emulation);
163 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_nvdec_emulation,
164 ui->use_nvdec_emulation, use_nvdec_emulation);
165
166 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 150 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
167 Settings::values.bg_red.SetGlobal(true); 151 Settings::values.bg_red.SetGlobal(true);
168 Settings::values.bg_green.SetGlobal(true); 152 Settings::values.bg_green.SetGlobal(true);
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index c67609b0e..35bf9c6be 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -54,47 +54,23 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
54 ui->gpu_accuracy->currentIndex() - 54 ui->gpu_accuracy->currentIndex() -
55 ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET)); 55 ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
56 56
57 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
58 ui->anisotropic_filtering_combobox);
59 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync);
60 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
61 ui->use_assembly_shaders, use_assembly_shaders);
62 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
63 ui->use_asynchronous_shaders,
64 use_asynchronous_shaders);
65 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
66 ui->use_fast_gpu_time, use_fast_gpu_time);
67
57 if (Settings::IsConfiguringGlobal()) { 68 if (Settings::IsConfiguringGlobal()) {
58 // Must guard in case of a during-game configuration when set to be game-specific. 69 // Must guard in case of a during-game configuration when set to be game-specific.
59 if (Settings::values.gpu_accuracy.UsingGlobal()) { 70 if (Settings::values.gpu_accuracy.UsingGlobal()) {
60 Settings::values.gpu_accuracy.SetValue(gpu_accuracy); 71 Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
61 } 72 }
62 if (Settings::values.use_vsync.UsingGlobal()) {
63 Settings::values.use_vsync.SetValue(ui->use_vsync->isChecked());
64 }
65 if (Settings::values.use_assembly_shaders.UsingGlobal()) {
66 Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked());
67 }
68 if (Settings::values.use_asynchronous_shaders.UsingGlobal()) {
69 Settings::values.use_asynchronous_shaders.SetValue(
70 ui->use_asynchronous_shaders->isChecked());
71 }
72 if (Settings::values.use_asynchronous_shaders.UsingGlobal()) {
73 Settings::values.use_asynchronous_shaders.SetValue(
74 ui->use_asynchronous_shaders->isChecked());
75 }
76 if (Settings::values.use_fast_gpu_time.UsingGlobal()) {
77 Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked());
78 }
79 if (Settings::values.max_anisotropy.UsingGlobal()) {
80 Settings::values.max_anisotropy.SetValue(
81 ui->anisotropic_filtering_combobox->currentIndex());
82 }
83 } else { 73 } else {
84 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
85 ui->anisotropic_filtering_combobox);
86 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync,
87 use_vsync);
88 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
89 ui->use_assembly_shaders, use_assembly_shaders);
90 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
91 ui->use_asynchronous_shaders,
92 use_asynchronous_shaders);
93 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
94 ui->use_fast_gpu_time, use_fast_gpu_time);
95 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
96 ui->anisotropic_filtering_combobox);
97
98 if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 74 if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
99 Settings::values.gpu_accuracy.SetGlobal(true); 75 Settings::values.gpu_accuracy.SetGlobal(true);
100 } else { 76 } else {
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index c9318c562..ab3512810 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -153,6 +153,10 @@ QString ButtonToText(const Common::ParamPackage& param) {
153 return QObject::tr("Button %1").arg(button_str); 153 return QObject::tr("Button %1").arg(button_str);
154 } 154 }
155 155
156 if (param.Has("motion")) {
157 return QObject::tr("SDL Motion");
158 }
159
156 return {}; 160 return {};
157 } 161 }
158 162
@@ -1245,12 +1249,16 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
1245 const auto& device = input_devices[ui->comboDevices->currentIndex()]; 1249 const auto& device = input_devices[ui->comboDevices->currentIndex()];
1246 auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); 1250 auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
1247 auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); 1251 auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
1252 auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device);
1248 for (std::size_t i = 0; i < buttons_param.size(); ++i) { 1253 for (std::size_t i = 0; i < buttons_param.size(); ++i) {
1249 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)]; 1254 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
1250 } 1255 }
1251 for (std::size_t i = 0; i < analogs_param.size(); ++i) { 1256 for (std::size_t i = 0; i < analogs_param.size(); ++i) {
1252 analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)]; 1257 analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
1253 } 1258 }
1259 for (std::size_t i = 0; i < motions_param.size(); ++i) {
1260 motions_param[i] = motion_mapping[static_cast<Settings::NativeMotion::Values>(i)];
1261 }
1254 1262
1255 UpdateUI(); 1263 UpdateUI();
1256} 1264}
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index bd91ebc42..f550567e2 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -52,6 +52,7 @@ ConfigurePerGame::~ConfigurePerGame() = default;
52void ConfigurePerGame::ApplyConfiguration() { 52void ConfigurePerGame::ApplyConfiguration() {
53 ui->addonsTab->ApplyConfiguration(); 53 ui->addonsTab->ApplyConfiguration();
54 ui->generalTab->ApplyConfiguration(); 54 ui->generalTab->ApplyConfiguration();
55 ui->cpuTab->ApplyConfiguration();
55 ui->systemTab->ApplyConfiguration(); 56 ui->systemTab->ApplyConfiguration();
56 ui->graphicsTab->ApplyConfiguration(); 57 ui->graphicsTab->ApplyConfiguration();
57 ui->graphicsAdvancedTab->ApplyConfiguration(); 58 ui->graphicsAdvancedTab->ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui
index 25975b3b9..adf6d0b39 100644
--- a/src/yuzu/configuration/configure_per_game.ui
+++ b/src/yuzu/configuration/configure_per_game.ui
@@ -235,6 +235,11 @@
235 <string>System</string> 235 <string>System</string>
236 </attribute> 236 </attribute>
237 </widget> 237 </widget>
238 <widget class="ConfigureCpu" name="cpuTab">
239 <attribute name="title">
240 <string>CPU</string>
241 </attribute>
242 </widget>
238 <widget class="ConfigureGraphics" name="graphicsTab"> 243 <widget class="ConfigureGraphics" name="graphicsTab">
239 <attribute name="title"> 244 <attribute name="title">
240 <string>Graphics</string> 245 <string>Graphics</string>
@@ -311,6 +316,12 @@
311 <header>configuration/configure_per_game_addons.h</header> 316 <header>configuration/configure_per_game_addons.h</header>
312 <container>1</container> 317 <container>1</container>
313 </customwidget> 318 </customwidget>
319 <customwidget>
320 <class>ConfigureCpu</class>
321 <extends>QWidget</extends>
322 <header>configuration/configure_cpu.h</header>
323 <container>1</container>
324 </customwidget>
314 </customwidgets> 325 </customwidgets>
315 <resources/> 326 <resources/>
316 <connections> 327 <connections>
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 268ed44c3..85418f969 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -65,7 +65,7 @@ void ConfigureSystem::SetConfiguration() {
65 QStringLiteral("%1") 65 QStringLiteral("%1")
66 .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'}) 66 .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
67 .toUpper(); 67 .toUpper();
68 const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or( 68 const auto rtc_time = Settings::values.custom_rtc.value_or(
69 std::chrono::seconds(QDateTime::currentSecsSinceEpoch())); 69 std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
70 70
71 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value()); 71 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
@@ -73,9 +73,8 @@ void ConfigureSystem::SetConfiguration() {
73 Settings::values.rng_seed.UsingGlobal()); 73 Settings::values.rng_seed.UsingGlobal());
74 ui->rng_seed_edit->setText(rng_seed); 74 ui->rng_seed_edit->setText(rng_seed);
75 75
76 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value()); 76 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
77 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() && 77 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
78 Settings::values.rng_seed.UsingGlobal());
79 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); 78 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
80 79
81 if (Settings::IsConfiguringGlobal()) { 80 if (Settings::IsConfiguringGlobal()) {
@@ -109,17 +108,17 @@ void ConfigureSystem::ApplyConfiguration() {
109 108
110 // Allow setting custom RTC even if system is powered on, 109 // Allow setting custom RTC even if system is powered on,
111 // to allow in-game time to be fast forwarded 110 // to allow in-game time to be fast forwarded
112 if (Settings::values.custom_rtc.UsingGlobal()) { 111 if (Settings::IsConfiguringGlobal()) {
113 if (ui->custom_rtc_checkbox->isChecked()) { 112 if (ui->custom_rtc_checkbox->isChecked()) {
114 Settings::values.custom_rtc.SetValue( 113 Settings::values.custom_rtc =
115 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch())); 114 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch());
116 if (system.IsPoweredOn()) { 115 if (system.IsPoweredOn()) {
117 const s64 posix_time{Settings::values.custom_rtc.GetValue()->count() + 116 const s64 posix_time{Settings::values.custom_rtc->count() +
118 Service::Time::TimeManager::GetExternalTimeZoneOffset()}; 117 Service::Time::TimeManager::GetExternalTimeZoneOffset()};
119 system.GetTimeManager().UpdateLocalSystemClockTime(posix_time); 118 system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);
120 } 119 }
121 } else { 120 } else {
122 Settings::values.custom_rtc.SetValue(std::nullopt); 121 Settings::values.custom_rtc = std::nullopt;
123 } 122 }
124 } 123 }
125 124
@@ -127,21 +126,14 @@ void ConfigureSystem::ApplyConfiguration() {
127 return; 126 return;
128 } 127 }
129 128
129 ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index, ui->combo_language);
130 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
131 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
132 ui->combo_time_zone);
133 ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
134
130 if (Settings::IsConfiguringGlobal()) { 135 if (Settings::IsConfiguringGlobal()) {
131 // Guard if during game and set to game-specific value 136 // Guard if during game and set to game-specific value
132 if (Settings::values.language_index.UsingGlobal()) {
133 Settings::values.language_index.SetValue(ui->combo_language->currentIndex());
134 }
135 if (Settings::values.region_index.UsingGlobal()) {
136 Settings::values.region_index.SetValue(ui->combo_region->currentIndex());
137 }
138 if (Settings::values.time_zone_index.UsingGlobal()) {
139 Settings::values.time_zone_index.SetValue(ui->combo_time_zone->currentIndex());
140 }
141 if (Settings::values.sound_index.UsingGlobal()) {
142 Settings::values.sound_index.SetValue(ui->combo_sound->currentIndex());
143 }
144
145 if (Settings::values.rng_seed.UsingGlobal()) { 137 if (Settings::values.rng_seed.UsingGlobal()) {
146 if (ui->rng_seed_checkbox->isChecked()) { 138 if (ui->rng_seed_checkbox->isChecked()) {
147 Settings::values.rng_seed.SetValue( 139 Settings::values.rng_seed.SetValue(
@@ -151,13 +143,6 @@ void ConfigureSystem::ApplyConfiguration() {
151 } 143 }
152 } 144 }
153 } else { 145 } else {
154 ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
155 ui->combo_language);
156 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
157 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
158 ui->combo_time_zone);
159 ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
160
161 switch (use_rng_seed) { 146 switch (use_rng_seed) {
162 case ConfigurationShared::CheckState::On: 147 case ConfigurationShared::CheckState::On:
163 case ConfigurationShared::CheckState::Off: 148 case ConfigurationShared::CheckState::Off:
@@ -177,26 +162,6 @@ void ConfigureSystem::ApplyConfiguration() {
177 case ConfigurationShared::CheckState::Count: 162 case ConfigurationShared::CheckState::Count:
178 break; 163 break;
179 } 164 }
180
181 switch (use_custom_rtc) {
182 case ConfigurationShared::CheckState::On:
183 case ConfigurationShared::CheckState::Off:
184 Settings::values.custom_rtc.SetGlobal(false);
185 if (ui->custom_rtc_checkbox->isChecked()) {
186 Settings::values.custom_rtc.SetValue(
187 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
188 } else {
189 Settings::values.custom_rtc.SetValue(std::nullopt);
190 }
191 break;
192 case ConfigurationShared::CheckState::Global:
193 Settings::values.custom_rtc.SetGlobal(false);
194 Settings::values.custom_rtc.SetValue(std::nullopt);
195 Settings::values.custom_rtc.SetGlobal(true);
196 break;
197 case ConfigurationShared::CheckState::Count:
198 break;
199 }
200 } 165 }
201 166
202 system.ApplySettings(); 167 system.ApplySettings();
@@ -227,8 +192,6 @@ void ConfigureSystem::SetupPerGameUI() {
227 ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal()); 192 ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
228 ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal()); 193 ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
229 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal()); 194 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
230 ui->custom_rtc_checkbox->setEnabled(Settings::values.custom_rtc.UsingGlobal());
231 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.UsingGlobal());
232 195
233 return; 196 return;
234 } 197 }
@@ -246,8 +209,7 @@ void ConfigureSystem::SetupPerGameUI() {
246 ui->rng_seed_checkbox, Settings::values.rng_seed.UsingGlobal(), 209 ui->rng_seed_checkbox, Settings::values.rng_seed.UsingGlobal(),
247 Settings::values.rng_seed.GetValue().has_value(), 210 Settings::values.rng_seed.GetValue().has_value(),
248 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed); 211 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
249 ConfigurationShared::SetColoredTristate( 212
250 ui->custom_rtc_checkbox, Settings::values.custom_rtc.UsingGlobal(), 213 ui->custom_rtc_checkbox->setVisible(false);
251 Settings::values.custom_rtc.GetValue().has_value(), 214 ui->custom_rtc_edit->setVisible(false);
252 Settings::values.custom_rtc.GetValue(true).has_value(), use_custom_rtc);
253} 215}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9e72acbf7..9275cba53 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -241,14 +241,15 @@ GMainWindow::GMainWindow()
241 ConnectMenuEvents(); 241 ConnectMenuEvents();
242 ConnectWidgetEvents(); 242 ConnectWidgetEvents();
243 243
244 const auto branch_name = std::string(Common::g_scm_branch);
245 const auto description = std::string(Common::g_scm_desc);
244 const auto build_id = std::string(Common::g_build_id); 246 const auto build_id = std::string(Common::g_build_id);
245 const auto fmt = std::string(Common::g_title_bar_format_idle);
246 const auto yuzu_build_version =
247 fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{},
248 std::string{}, std::string{}, std::string{}, build_id);
249 247
250 LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", yuzu_build_version, Common::g_scm_branch, 248 const auto yuzu_build = fmt::format("yuzu Development Build | {}-{}", branch_name, description);
251 Common::g_scm_desc); 249 const auto override_build = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
250 const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build;
251
252 LOG_INFO(Frontend, "yuzu Version: {}", yuzu_build_version);
252#ifdef ARCHITECTURE_x86_64 253#ifdef ARCHITECTURE_x86_64
253 const auto& caps = Common::GetCPUCaps(); 254 const auto& caps = Common::GetCPUCaps();
254 std::string cpu_string = caps.cpu_string; 255 std::string cpu_string = caps.cpu_string;
@@ -1377,7 +1378,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
1377 game_list->hide(); 1378 game_list->hide();
1378 game_list_placeholder->hide(); 1379 game_list_placeholder->hide();
1379 } 1380 }
1380 status_bar_update_timer.start(2000); 1381 status_bar_update_timer.start(500);
1381 async_status_button->setDisabled(true); 1382 async_status_button->setDisabled(true);
1382 multicore_status_button->setDisabled(true); 1383 multicore_status_button->setDisabled(true);
1383 renderer_status_button->setDisabled(true); 1384 renderer_status_button->setDisabled(true);
@@ -2101,6 +2102,7 @@ void GMainWindow::OnMenuInstallToNAND() {
2101 QStringList new_files{}; // Newly installed files that do not yet exist in the NAND 2102 QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
2102 QStringList overwritten_files{}; // Files that overwrote those existing in the NAND 2103 QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
2103 QStringList failed_files{}; // Files that failed to install due to errors 2104 QStringList failed_files{}; // Files that failed to install due to errors
2105 bool detected_base_install{}; // Whether a base game was attempted to be installed
2104 2106
2105 ui.action_Install_File_NAND->setEnabled(false); 2107 ui.action_Install_File_NAND->setEnabled(false);
2106 2108
@@ -2126,6 +2128,7 @@ void GMainWindow::OnMenuInstallToNAND() {
2126 2128
2127 while (!future.isFinished()) { 2129 while (!future.isFinished()) {
2128 QCoreApplication::processEvents(); 2130 QCoreApplication::processEvents();
2131 std::this_thread::sleep_for(std::chrono::milliseconds(1));
2129 } 2132 }
2130 2133
2131 result = future.result(); 2134 result = future.result();
@@ -2146,6 +2149,10 @@ void GMainWindow::OnMenuInstallToNAND() {
2146 case InstallResult::Failure: 2149 case InstallResult::Failure:
2147 failed_files.append(QFileInfo(file).fileName()); 2150 failed_files.append(QFileInfo(file).fileName());
2148 break; 2151 break;
2152 case InstallResult::BaseInstallAttempted:
2153 failed_files.append(QFileInfo(file).fileName());
2154 detected_base_install = true;
2155 break;
2149 } 2156 }
2150 2157
2151 --remaining; 2158 --remaining;
@@ -2153,6 +2160,13 @@ void GMainWindow::OnMenuInstallToNAND() {
2153 2160
2154 install_progress->close(); 2161 install_progress->close();
2155 2162
2163 if (detected_base_install) {
2164 QMessageBox::warning(
2165 this, tr("Install Results"),
2166 tr("To avoid possible conflicts, we discourage users from installing base games to the "
2167 "NAND.\nPlease, only use this feature to install updates and DLC."));
2168 }
2169
2156 const QString install_results = 2170 const QString install_results =
2157 (new_files.isEmpty() ? QString{} 2171 (new_files.isEmpty() ? QString{}
2158 : tr("%n file(s) were newly installed\n", "", new_files.size())) + 2172 : tr("%n file(s) were newly installed\n", "", new_files.size())) +
@@ -2214,11 +2228,14 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
2214 const auto res = 2228 const auto res =
2215 Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry( 2229 Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
2216 *nsp, true, qt_raw_copy); 2230 *nsp, true, qt_raw_copy);
2217 if (res == FileSys::InstallResult::Success) { 2231 switch (res) {
2232 case FileSys::InstallResult::Success:
2218 return InstallResult::Success; 2233 return InstallResult::Success;
2219 } else if (res == FileSys::InstallResult::OverwriteExisting) { 2234 case FileSys::InstallResult::OverwriteExisting:
2220 return InstallResult::Overwrite; 2235 return InstallResult::Overwrite;
2221 } else { 2236 case FileSys::InstallResult::ErrorBaseInstall:
2237 return InstallResult::BaseInstallAttempted;
2238 default:
2222 return InstallResult::Failure; 2239 return InstallResult::Failure;
2223 } 2240 }
2224} 2241}
@@ -2751,24 +2768,19 @@ void GMainWindow::MigrateConfigFiles() {
2751 2768
2752void GMainWindow::UpdateWindowTitle(const std::string& title_name, 2769void GMainWindow::UpdateWindowTitle(const std::string& title_name,
2753 const std::string& title_version) { 2770 const std::string& title_version) {
2754 const auto full_name = std::string(Common::g_build_fullname);
2755 const auto branch_name = std::string(Common::g_scm_branch); 2771 const auto branch_name = std::string(Common::g_scm_branch);
2756 const auto description = std::string(Common::g_scm_desc); 2772 const auto description = std::string(Common::g_scm_desc);
2757 const auto build_id = std::string(Common::g_build_id); 2773 const auto build_id = std::string(Common::g_build_id);
2758 2774
2759 const auto date = 2775 const auto yuzu_title = fmt::format("yuzu | {}-{}", branch_name, description);
2760 QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd")).toStdString(); 2776 const auto override_title = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
2777 const auto window_title = override_title.empty() ? yuzu_title : override_title;
2761 2778
2762 if (title_name.empty()) { 2779 if (title_name.empty()) {
2763 const auto fmt = std::string(Common::g_title_bar_format_idle); 2780 setWindowTitle(QString::fromStdString(window_title));
2764 setWindowTitle(QString::fromStdString(fmt::format(fmt.empty() ? "yuzu {0}| {1}-{2}" : fmt,
2765 full_name, branch_name, description,
2766 std::string{}, date, build_id)));
2767 } else { 2781 } else {
2768 const auto fmt = std::string(Common::g_title_bar_format_running); 2782 const auto run_title = fmt::format("{} | {} | {}", window_title, title_name, title_version);
2769 setWindowTitle(QString::fromStdString( 2783 setWindowTitle(QString::fromStdString(run_title));
2770 fmt::format(fmt.empty() ? "yuzu {0}| {3} | {6} | {1}-{2}" : fmt, full_name, branch_name,
2771 description, title_name, date, build_id, title_version)));
2772 } 2784 }
2773} 2785}
2774 2786
@@ -2797,7 +2809,7 @@ void GMainWindow::UpdateStatusBar() {
2797 } else { 2809 } else {
2798 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); 2810 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
2799 } 2811 }
2800 game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0)); 2812 game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0));
2801 emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); 2813 emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
2802 2814
2803 emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); 2815 emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 98a608fce..b3a5033ce 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -76,6 +76,7 @@ enum class InstallResult {
76 Success, 76 Success,
77 Overwrite, 77 Overwrite,
78 Failure, 78 Failure,
79 BaseInstallAttempted,
79}; 80};
80 81
81enum class ReinitializeKeyBehavior { 82enum class ReinitializeKeyBehavior {
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 7e1d5f379..38d896d65 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -361,10 +361,10 @@ void Config::ReadValues() {
361 361
362 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); 362 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
363 if (custom_rtc_enabled) { 363 if (custom_rtc_enabled) {
364 Settings::values.custom_rtc.SetValue( 364 Settings::values.custom_rtc =
365 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0))); 365 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0));
366 } else { 366 } else {
367 Settings::values.custom_rtc.SetValue(std::nullopt); 367 Settings::values.custom_rtc = std::nullopt;
368 } 368 }
369 369
370 Settings::values.language_index.SetValue( 370 Settings::values.language_index.SetValue(
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index d64f81106..06b20c975 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -215,7 +215,7 @@ void EmuWindow_SDL2::WaitEvent() {
215 const auto results = Core::System::GetInstance().GetAndResetPerfStats(); 215 const auto results = Core::System::GetInstance().GetAndResetPerfStats();
216 const auto title = 216 const auto title =
217 fmt::format("yuzu {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, 217 fmt::format("yuzu {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname,
218 Common::g_scm_branch, Common::g_scm_desc, results.game_fps, 218 Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps,
219 results.emulation_speed * 100.0); 219 results.emulation_speed * 100.0);
220 SDL_SetWindowTitle(render_window, title.c_str()); 220 SDL_SetWindowTitle(render_window, title.c_str());
221 last_time = current_time; 221 last_time = current_time;