summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt13
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt37
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt42
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt20
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt24
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt21
-rw-r--r--src/android/app/src/main/jni/native.cpp6
-rw-r--r--src/android/app/src/main/res/drawable/ic_shortcut.xml9
-rw-r--r--src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml35
-rw-r--r--src/android/app/src/main/res/layout/fragment_game_properties.xml40
-rw-r--r--src/audio_core/device/device_session.cpp1
-rw-r--r--src/audio_core/renderer/command/data_source/decode.cpp1
-rw-r--r--src/common/arm64/native_clock.cpp24
-rw-r--r--src/common/arm64/native_clock.h10
-rw-r--r--src/common/common_types.h1
-rw-r--r--src/common/memory_detect.h2
-rw-r--r--src/common/settings.h13
-rw-r--r--src/common/time_zone.cpp12
-rw-r--r--src/common/uuid.h12
-rw-r--r--src/common/wall_clock.cpp32
-rw-r--r--src/common/wall_clock.h9
-rw-r--r--src/common/x64/native_clock.cpp26
-rw-r--r--src/common/x64/native_clock.h9
-rw-r--r--src/core/CMakeLists.txt100
-rw-r--r--src/core/core.cpp103
-rw-r--r--src/core/core.h13
-rw-r--r--src/core/core_timing.cpp2
-rw-r--r--src/core/device_memory.h16
-rw-r--r--src/core/device_memory_manager.h211
-rw-r--r--src/core/device_memory_manager.inc581
-rw-r--r--src/core/file_sys/system_archive/system_archive.cpp12
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.cpp1
-rw-r--r--src/core/gpu_dirty_memory_manager.h14
-rw-r--r--src/core/guest_memory.h214
-rw-r--r--src/core/hle/kernel/k_process.cpp14
-rw-r--r--src/core/hle/kernel/k_process.h4
-rw-r--r--src/core/hle/service/caps/caps_manager.cpp47
-rw-r--r--src/core/hle/service/cmif_serialization.h337
-rw-r--r--src/core/hle/service/cmif_types.h234
-rw-r--r--src/core/hle/service/glue/glue.cpp19
-rw-r--r--src/core/hle/service/glue/time/alarm_worker.cpp82
-rw-r--r--src/core/hle/service/glue/time/alarm_worker.h53
-rw-r--r--src/core/hle/service/glue/time/file_timestamp_worker.cpp23
-rw-r--r--src/core/hle/service/glue/time/file_timestamp_worker.h28
-rw-r--r--src/core/hle/service/glue/time/manager.cpp277
-rw-r--r--src/core/hle/service/glue/time/manager.h42
-rw-r--r--src/core/hle/service/glue/time/pm_state_change_handler.cpp13
-rw-r--r--src/core/hle/service/glue/time/pm_state_change_handler.h18
-rw-r--r--src/core/hle/service/glue/time/standard_steady_clock_resource.cpp123
-rw-r--r--src/core/hle/service/glue/time/standard_steady_clock_resource.h41
-rw-r--r--src/core/hle/service/glue/time/static.cpp448
-rw-r--r--src/core/hle/service/glue/time/static.h110
-rw-r--r--src/core/hle/service/glue/time/time_zone.cpp377
-rw-r--r--src/core/hle/service/glue/time/time_zone.h95
-rw-r--r--src/core/hle/service/glue/time/time_zone_binary.cpp221
-rw-r--r--src/core/hle/service/glue/time/time_zone_binary.h32
-rw-r--r--src/core/hle/service/glue/time/worker.cpp338
-rw-r--r--src/core/hle/service/glue/time/worker.h64
-rw-r--r--src/core/hle/service/hle_ipc.cpp77
-rw-r--r--src/core/hle/service/hle_ipc.h7
-rw-r--r--src/core/hle/service/jit/jit.cpp283
-rw-r--r--src/core/hle/service/kernel_helpers.cpp3
-rw-r--r--src/core/hle/service/nfc/common/device.cpp42
-rw-r--r--src/core/hle/service/nfc/common/device.h7
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp37
-rw-r--r--src/core/hle/service/nfc/common/device_manager.h5
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp5
-rw-r--r--src/core/hle/service/ns/language.cpp2
-rw-r--r--src/core/hle/service/ns/language.h5
-rw-r--r--src/core/hle/service/nvdrv/core/container.cpp114
-rw-r--r--src/core/hle/service/nvdrv/core/container.h32
-rw-r--r--src/core/hle/service/nvdrv/core/heap_mapper.cpp175
-rw-r--r--src/core/hle/service/nvdrv/core/heap_mapper.h49
-rw-r--r--src/core/hle/service/nvdrv/core/nvmap.cpp120
-rw-r--r--src/core/hle/service/nvdrv/core/nvmap.h25
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp36
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h15
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp13
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp31
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h7
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp27
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h6
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp37
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.h1
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp25
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.h5
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp2
-rw-r--r--src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp2
-rw-r--r--src/core/hle/service/psc/psc.cpp17
-rw-r--r--src/core/hle/service/psc/time/alarms.cpp209
-rw-r--r--src/core/hle/service/psc/time/alarms.h139
-rw-r--r--src/core/hle/service/psc/time/clocks/context_writers.cpp83
-rw-r--r--src/core/hle/service/psc/time/clocks/context_writers.h79
-rw-r--r--src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h21
-rw-r--r--src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp20
-rw-r--r--src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h23
-rw-r--r--src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp42
-rw-r--r--src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h30
-rw-r--r--src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp101
-rw-r--r--src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h54
-rw-r--r--src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp63
-rw-r--r--src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h55
-rw-r--r--src/core/hle/service/psc/time/clocks/steady_clock_core.h81
-rw-r--r--src/core/hle/service/psc/time/clocks/system_clock_core.cpp75
-rw-r--r--src/core/hle/service/psc/time/clocks/system_clock_core.h55
-rw-r--r--src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp43
-rw-r--r--src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h41
-rw-r--r--src/core/hle/service/psc/time/common.cpp16
-rw-r--r--src/core/hle/service/psc/time/common.h168
-rw-r--r--src/core/hle/service/psc/time/errors.h24
-rw-r--r--src/core/hle/service/psc/time/manager.h56
-rw-r--r--src/core/hle/service/psc/time/power_state_request_manager.cpp50
-rw-r--r--src/core/hle/service/psc/time/power_state_request_manager.h42
-rw-r--r--src/core/hle/service/psc/time/power_state_service.cpp49
-rw-r--r--src/core/hle/service/psc/time/power_state_service.h32
-rw-r--r--src/core/hle/service/psc/time/service_manager.cpp494
-rw-r--r--src/core/hle/service/psc/time/service_manager.h101
-rw-r--r--src/core/hle/service/psc/time/shared_memory.cpp84
-rw-r--r--src/core/hle/service/psc/time/shared_memory.h70
-rw-r--r--src/core/hle/service/psc/time/static.cpp500
-rw-r--r--src/core/hle/service/psc/time/static.h95
-rw-r--r--src/core/hle/service/psc/time/steady_clock.cpp164
-rw-r--r--src/core/hle/service/psc/time/steady_clock.h49
-rw-r--r--src/core/hle/service/psc/time/system_clock.cpp127
-rw-r--r--src/core/hle/service/psc/time/system_clock.h46
-rw-r--r--src/core/hle/service/psc/time/time_zone.cpp280
-rw-r--r--src/core/hle/service/psc/time/time_zone.h62
-rw-r--r--src/core/hle/service/psc/time/time_zone_service.cpp289
-rw-r--r--src/core/hle/service/psc/time/time_zone_service.h69
-rw-r--r--src/core/hle/service/ro/ro.cpp192
-rw-r--r--src/core/hle/service/service.cpp7
-rw-r--r--src/core/hle/service/service.h16
-rw-r--r--src/core/hle/service/set/private_settings.h72
-rw-r--r--src/core/hle/service/set/setting_formats/private_settings.h1
-rw-r--r--src/core/hle/service/set/setting_formats/system_settings.cpp2
-rw-r--r--src/core/hle/service/set/setting_formats/system_settings.h16
-rw-r--r--src/core/hle/service/set/settings_types.h8
-rw-r--r--src/core/hle/service/set/system_settings_server.cpp70
-rw-r--r--src/core/hle/service/set/system_settings_server.h25
-rw-r--r--src/core/hle/service/sm/sm.h15
-rw-r--r--src/core/hle/service/time/clock_types.h129
-rw-r--r--src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h15
-rw-r--r--src/core/hle/service/time/ephemeral_network_system_clock_core.h16
-rw-r--r--src/core/hle/service/time/errors.h21
-rw-r--r--src/core/hle/service/time/local_system_clock_context_writer.h26
-rw-r--r--src/core/hle/service/time/network_system_clock_context_writer.h27
-rw-r--r--src/core/hle/service/time/standard_local_system_clock_core.h16
-rw-r--r--src/core/hle/service/time/standard_network_system_clock_core.h45
-rw-r--r--src/core/hle/service/time/standard_steady_clock_core.cpp24
-rw-r--r--src/core/hle/service/time/standard_steady_clock_core.h41
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.cpp81
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.h63
-rw-r--r--src/core/hle/service/time/steady_clock_core.h55
-rw-r--r--src/core/hle/service/time/system_clock_context_update_callback.cpp54
-rw-r--r--src/core/hle/service/time/system_clock_context_update_callback.h43
-rw-r--r--src/core/hle/service/time/system_clock_core.cpp71
-rw-r--r--src/core/hle/service/time/system_clock_core.h72
-rw-r--r--src/core/hle/service/time/tick_based_steady_clock_core.cpp22
-rw-r--r--src/core/hle/service/time/tick_based_steady_clock_core.h28
-rw-r--r--src/core/hle/service/time/time.cpp412
-rw-r--r--src/core/hle/service/time/time.h51
-rw-r--r--src/core/hle/service/time/time_interface.cpp41
-rw-r--r--src/core/hle/service/time/time_interface.h20
-rw-r--r--src/core/hle/service/time/time_manager.cpp293
-rw-r--r--src/core/hle/service/time/time_manager.h74
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp69
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h89
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp151
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.h49
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp1182
-rw-r--r--src/core/hle/service/time/time_zone_manager.h61
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp217
-rw-r--r--src/core/hle/service/time/time_zone_service.h38
-rw-r--r--src/core/hle/service/time/time_zone_types.h86
-rw-r--r--src/core/hle/service/vi/vi.cpp5
-rw-r--r--src/core/loader/nsp.cpp8
-rw-r--r--src/core/memory.cpp108
-rw-r--r--src/core/memory.h211
-rw-r--r--src/tests/video_core/memory_tracker.cpp9
-rw-r--r--src/video_core/CMakeLists.txt5
-rw-r--r--src/video_core/buffer_cache/buffer_base.h3
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h451
-rw-r--r--src/video_core/buffer_cache/buffer_cache_base.h98
-rw-r--r--src/video_core/buffer_cache/memory_tracker_base.h18
-rw-r--r--src/video_core/buffer_cache/word_manager.h28
-rw-r--r--src/video_core/dma_pusher.cpp10
-rw-r--r--src/video_core/engines/engine_upload.cpp5
-rw-r--r--src/video_core/engines/maxwell_3d.cpp1
-rw-r--r--src/video_core/engines/maxwell_dma.cpp26
-rw-r--r--src/video_core/engines/sw_blitter/blitter.cpp5
-rw-r--r--src/video_core/framebuffer_config.h2
-rw-r--r--src/video_core/gpu.cpp29
-rw-r--r--src/video_core/gpu.h12
-rw-r--r--src/video_core/gpu_thread.cpp6
-rw-r--r--src/video_core/gpu_thread.h18
-rw-r--r--src/video_core/guest_memory.h30
-rw-r--r--src/video_core/host1x/codecs/h264.cpp9
-rw-r--r--src/video_core/host1x/codecs/vp8.cpp4
-rw-r--r--src/video_core/host1x/codecs/vp9.cpp9
-rw-r--r--src/video_core/host1x/gpu_device_memory_manager.cpp32
-rw-r--r--src/video_core/host1x/gpu_device_memory_manager.h24
-rw-r--r--src/video_core/host1x/host1x.cpp5
-rw-r--r--src/video_core/host1x/host1x.h17
-rw-r--r--src/video_core/host1x/vic.cpp15
-rw-r--r--src/video_core/memory_manager.cpp229
-rw-r--r--src/video_core/memory_manager.h36
-rw-r--r--src/video_core/query_cache.h30
-rw-r--r--src/video_core/query_cache/query_base.h6
-rw-r--r--src/video_core/query_cache/query_cache.h37
-rw-r--r--src/video_core/query_cache/query_cache_base.h17
-rw-r--r--src/video_core/query_cache/query_stream.h2
-rw-r--r--src/video_core/query_cache/types.h2
-rw-r--r--src/video_core/rasterizer_accelerated.cpp72
-rw-r--r--src/video_core/rasterizer_accelerated.h49
-rw-r--r--src/video_core/rasterizer_download_area.h2
-rw-r--r--src/video_core/rasterizer_interface.h23
-rw-r--r--src/video_core/renderer_null/null_rasterizer.cpp26
-rw-r--r--src/video_core/renderer_null/null_rasterizer.h23
-rw-r--r--src/video_core/renderer_null/renderer_null.cpp5
-rw-r--r--src/video_core/renderer_null/renderer_null.h3
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h8
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp41
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h28
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h11
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp10
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h4
-rw-r--r--src/video_core/renderer_vulkan/pipeline_helper.h1
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp12
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp17
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h12
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h7
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp62
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp44
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h41
-rw-r--r--src/video_core/shader_cache.cpp8
-rw-r--r--src/video_core/shader_cache.h5
-rw-r--r--src/video_core/texture_cache/accelerated_swizzle.cpp2
-rw-r--r--src/video_core/texture_cache/texture_cache.h75
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h28
-rw-r--r--src/video_core/texture_cache/util.cpp5
-rw-r--r--src/video_core/video_core.cpp15
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp10
-rw-r--r--src/yuzu/configuration/configure_ringcon.cpp2
-rw-r--r--src/yuzu/configuration/configure_system.cpp57
-rw-r--r--src/yuzu/configuration/configure_system.h6
-rw-r--r--src/yuzu/configuration/shared_translation.cpp4
-rw-r--r--src/yuzu/debugger/console.h2
276 files changed, 10686 insertions, 5823 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 0fb35bf98..55abba093 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -303,6 +303,11 @@ object NativeLibrary {
303 */ 303 */
304 external fun getCpuBackend(): String 304 external fun getCpuBackend(): String
305 305
306 /**
307 * Returns the current GPU Driver.
308 */
309 external fun getGpuDriver(): String
310
306 external fun applySettings() 311 external fun applySettings()
307 312
308 external fun logSettings() 313 external fun logSettings()
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt
index f006f9e3d..0ab1b46c3 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt
@@ -14,15 +14,20 @@ import androidx.recyclerview.widget.RecyclerView
14 * Generic adapter that implements an [AsyncDifferConfig] and covers some of the basic boilerplate 14 * Generic adapter that implements an [AsyncDifferConfig] and covers some of the basic boilerplate
15 * code used in every [RecyclerView]. 15 * code used in every [RecyclerView].
16 * Type assigned to [Model] must inherit from [Object] in order to be compared properly. 16 * Type assigned to [Model] must inherit from [Object] in order to be compared properly.
17 * @param exact Decides whether each item will be compared by reference or by their contents
17 */ 18 */
18abstract class AbstractDiffAdapter<Model : Any, Holder : AbstractViewHolder<Model>> : 19abstract class AbstractDiffAdapter<Model : Any, Holder : AbstractViewHolder<Model>>(
19 ListAdapter<Model, Holder>(AsyncDifferConfig.Builder(DiffCallback<Model>()).build()) { 20 exact: Boolean = true
21) : ListAdapter<Model, Holder>(AsyncDifferConfig.Builder(DiffCallback<Model>(exact)).build()) {
20 override fun onBindViewHolder(holder: Holder, position: Int) = 22 override fun onBindViewHolder(holder: Holder, position: Int) =
21 holder.bind(currentList[position]) 23 holder.bind(currentList[position])
22 24
23 private class DiffCallback<Model> : DiffUtil.ItemCallback<Model>() { 25 private class DiffCallback<Model>(val exact: Boolean) : DiffUtil.ItemCallback<Model>() {
24 override fun areItemsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean { 26 override fun areItemsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean {
25 return oldItem === newItem 27 if (exact) {
28 return oldItem === newItem
29 }
30 return oldItem == newItem
26 } 31 }
27 32
28 @SuppressLint("DiffUtilEquals") 33 @SuppressLint("DiffUtilEquals")
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
index e26c2e0ab..85c8249e6 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
@@ -3,9 +3,6 @@
3 3
4package org.yuzu.yuzu_emu.adapters 4package org.yuzu.yuzu_emu.adapters
5 5
6import android.content.Intent
7import android.graphics.Bitmap
8import android.graphics.drawable.LayerDrawable
9import android.net.Uri 6import android.net.Uri
10import android.text.TextUtils 7import android.text.TextUtils
11import android.view.LayoutInflater 8import android.view.LayoutInflater
@@ -15,10 +12,6 @@ import android.widget.Toast
15import androidx.appcompat.app.AppCompatActivity 12import androidx.appcompat.app.AppCompatActivity
16import androidx.core.content.pm.ShortcutInfoCompat 13import androidx.core.content.pm.ShortcutInfoCompat
17import androidx.core.content.pm.ShortcutManagerCompat 14import androidx.core.content.pm.ShortcutManagerCompat
18import androidx.core.content.res.ResourcesCompat
19import androidx.core.graphics.drawable.IconCompat
20import androidx.core.graphics.drawable.toBitmap
21import androidx.core.graphics.drawable.toDrawable
22import androidx.documentfile.provider.DocumentFile 15import androidx.documentfile.provider.DocumentFile
23import androidx.lifecycle.ViewModelProvider 16import androidx.lifecycle.ViewModelProvider
24import androidx.lifecycle.lifecycleScope 17import androidx.lifecycle.lifecycleScope
@@ -30,7 +23,6 @@ import kotlinx.coroutines.withContext
30import org.yuzu.yuzu_emu.HomeNavigationDirections 23import org.yuzu.yuzu_emu.HomeNavigationDirections
31import org.yuzu.yuzu_emu.R 24import org.yuzu.yuzu_emu.R
32import org.yuzu.yuzu_emu.YuzuApplication 25import org.yuzu.yuzu_emu.YuzuApplication
33import org.yuzu.yuzu_emu.activities.EmulationActivity
34import org.yuzu.yuzu_emu.databinding.CardGameBinding 26import org.yuzu.yuzu_emu.databinding.CardGameBinding
35import org.yuzu.yuzu_emu.model.Game 27import org.yuzu.yuzu_emu.model.Game
36import org.yuzu.yuzu_emu.model.GamesViewModel 28import org.yuzu.yuzu_emu.model.GamesViewModel
@@ -38,7 +30,7 @@ import org.yuzu.yuzu_emu.utils.GameIconUtils
38import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder 30import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
39 31
40class GameAdapter(private val activity: AppCompatActivity) : 32class GameAdapter(private val activity: AppCompatActivity) :
41 AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>() { 33 AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>(exact = false) {
42 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder { 34 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
43 CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) 35 CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
44 .also { return GameViewHolder(it) } 36 .also { return GameViewHolder(it) }
@@ -89,36 +81,13 @@ class GameAdapter(private val activity: AppCompatActivity) :
89 ) 81 )
90 .apply() 82 .apply()
91 83
92 val openIntent =
93 Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
94 action = Intent.ACTION_VIEW
95 data = Uri.parse(game.path)
96 }
97
98 activity.lifecycleScope.launch { 84 activity.lifecycleScope.launch {
99 withContext(Dispatchers.IO) { 85 withContext(Dispatchers.IO) {
100 val layerDrawable = ResourcesCompat.getDrawable(
101 YuzuApplication.appContext.resources,
102 R.drawable.shortcut,
103 null
104 ) as LayerDrawable
105 layerDrawable.setDrawableByLayerId(
106 R.id.shortcut_foreground,
107 GameIconUtils.getGameIcon(activity, game)
108 .toDrawable(YuzuApplication.appContext.resources)
109 )
110 val inset = YuzuApplication.appContext.resources
111 .getDimensionPixelSize(R.dimen.icon_inset)
112 layerDrawable.setLayerInset(1, inset, inset, inset, inset)
113 val shortcut = 86 val shortcut =
114 ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path) 87 ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path)
115 .setShortLabel(game.title) 88 .setShortLabel(game.title)
116 .setIcon( 89 .setIcon(GameIconUtils.getShortcutIcon(activity, game))
117 IconCompat.createWithAdaptiveBitmap( 90 .setIntent(game.launchIntent)
118 layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
119 )
120 )
121 .setIntent(openIntent)
122 .build() 91 .build()
123 ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) 92 ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
124 } 93 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 2a97ae14d..d17e087fe 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -38,7 +38,6 @@ import androidx.window.layout.WindowLayoutInfo
38import com.google.android.material.dialog.MaterialAlertDialogBuilder 38import com.google.android.material.dialog.MaterialAlertDialogBuilder
39import com.google.android.material.slider.Slider 39import com.google.android.material.slider.Slider
40import kotlinx.coroutines.Dispatchers 40import kotlinx.coroutines.Dispatchers
41import kotlinx.coroutines.flow.collect
42import kotlinx.coroutines.flow.collectLatest 41import kotlinx.coroutines.flow.collectLatest
43import kotlinx.coroutines.launch 42import kotlinx.coroutines.launch
44import org.yuzu.yuzu_emu.HomeNavigationDirections 43import org.yuzu.yuzu_emu.HomeNavigationDirections
@@ -141,7 +140,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
141 140
142 // So this fragment doesn't restart on configuration changes; i.e. rotation. 141 // So this fragment doesn't restart on configuration changes; i.e. rotation.
143 retainInstance = true 142 retainInstance = true
144 emulationState = EmulationState(game.path) 143 emulationState = EmulationState(game.path) {
144 return@EmulationState driverViewModel.isInteractionAllowed.value
145 }
145 } 146 }
146 147
147 /** 148 /**
@@ -371,6 +372,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
371 } 372 }
372 } 373 }
373 launch { 374 launch {
375 repeatOnLifecycle(Lifecycle.State.RESUMED) {
376 driverViewModel.isInteractionAllowed.collect {
377 if (it) {
378 startEmulation()
379 }
380 }
381 }
382 }
383 launch {
374 repeatOnLifecycle(Lifecycle.State.CREATED) { 384 repeatOnLifecycle(Lifecycle.State.CREATED) {
375 emulationViewModel.emulationStarted.collectLatest { 385 emulationViewModel.emulationStarted.collectLatest {
376 if (it) { 386 if (it) {
@@ -398,19 +408,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
398 } 408 }
399 } 409 }
400 } 410 }
401 launch {
402 repeatOnLifecycle(Lifecycle.State.RESUMED) {
403 driverViewModel.isInteractionAllowed.collect {
404 if (it) {
405 onEmulationStart()
406 }
407 }
408 }
409 }
410 } 411 }
411 } 412 }
412 413
413 private fun onEmulationStart() { 414 private fun startEmulation() {
414 if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) { 415 if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
415 if (!DirectoryInitialization.areDirectoriesReady) { 416 if (!DirectoryInitialization.areDirectoriesReady) {
416 DirectoryInitialization.start() 417 DirectoryInitialization.start()
@@ -485,12 +486,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
485 val FRAMETIME = 2 486 val FRAMETIME = 2
486 val SPEED = 3 487 val SPEED = 3
487 perfStatsUpdater = { 488 perfStatsUpdater = {
488 if (emulationViewModel.emulationStarted.value) { 489 if (emulationViewModel.emulationStarted.value &&
490 !emulationViewModel.isEmulationStopping.value
491 ) {
489 val perfStats = NativeLibrary.getPerfStats() 492 val perfStats = NativeLibrary.getPerfStats()
490 val cpuBackend = NativeLibrary.getCpuBackend() 493 val cpuBackend = NativeLibrary.getCpuBackend()
494 val gpuDriver = NativeLibrary.getGpuDriver()
491 if (_binding != null) { 495 if (_binding != null) {
492 binding.showFpsText.text = 496 binding.showFpsText.text =
493 String.format("FPS: %.1f\n%s", perfStats[FPS], cpuBackend) 497 String.format("FPS: %.1f\n%s/%s", perfStats[FPS], cpuBackend, gpuDriver)
494 } 498 }
495 perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800) 499 perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
496 } 500 }
@@ -807,7 +811,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
807 } 811 }
808 } 812 }
809 813
810 private class EmulationState(private val gamePath: String) { 814 private class EmulationState(
815 private val gamePath: String,
816 private val emulationCanStart: () -> Boolean
817 ) {
811 private var state: State 818 private var state: State
812 private var surface: Surface? = null 819 private var surface: Surface? = null
813 820
@@ -901,6 +908,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
901 State.PAUSED -> Log.warning( 908 State.PAUSED -> Log.warning(
902 "[EmulationFragment] Surface cleared while emulation paused." 909 "[EmulationFragment] Surface cleared while emulation paused."
903 ) 910 )
911
904 else -> Log.warning( 912 else -> Log.warning(
905 "[EmulationFragment] Surface cleared while emulation stopped." 913 "[EmulationFragment] Surface cleared while emulation stopped."
906 ) 914 )
@@ -910,6 +918,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
910 918
911 private fun runWithValidSurface() { 919 private fun runWithValidSurface() {
912 NativeLibrary.surfaceChanged(surface) 920 NativeLibrary.surfaceChanged(surface)
921 if (!emulationCanStart.invoke()) {
922 return
923 }
924
913 when (state) { 925 when (state) {
914 State.STOPPED -> { 926 State.STOPPED -> {
915 val emulationThread = Thread({ 927 val emulationThread = Thread({
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
index 83a845434..582df0133 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
@@ -4,6 +4,8 @@
4package org.yuzu.yuzu_emu.fragments 4package org.yuzu.yuzu_emu.fragments
5 5
6import android.annotation.SuppressLint 6import android.annotation.SuppressLint
7import android.content.pm.ShortcutInfo
8import android.content.pm.ShortcutManager
7import android.os.Bundle 9import android.os.Bundle
8import android.text.TextUtils 10import android.text.TextUtils
9import android.view.LayoutInflater 11import android.view.LayoutInflater
@@ -84,6 +86,24 @@ class GamePropertiesFragment : Fragment() {
84 view.findNavController().popBackStack() 86 view.findNavController().popBackStack()
85 } 87 }
86 88
89 val shortcutManager = requireActivity().getSystemService(ShortcutManager::class.java)
90 binding.buttonShortcut.isEnabled = shortcutManager.isRequestPinShortcutSupported
91 binding.buttonShortcut.setOnClickListener {
92 viewLifecycleOwner.lifecycleScope.launch {
93 withContext(Dispatchers.IO) {
94 val shortcut = ShortcutInfo.Builder(requireContext(), args.game.title)
95 .setShortLabel(args.game.title)
96 .setIcon(
97 GameIconUtils.getShortcutIcon(requireActivity(), args.game)
98 .toIcon(requireContext())
99 )
100 .setIntent(args.game.launchIntent)
101 .build()
102 shortcutManager.requestPinShortcut(shortcut, null)
103 }
104 }
105 }
106
87 GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen) 107 GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen)
88 binding.title.text = args.game.title 108 binding.title.text = args.game.title
89 binding.title.postDelayed( 109 binding.title.postDelayed(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
index 15ae3a42b..5ed754c96 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
@@ -144,6 +144,7 @@ class DriverViewModel : ViewModel() {
144 val selectedDriverFile = File(StringSetting.DRIVER_PATH.getString()) 144 val selectedDriverFile = File(StringSetting.DRIVER_PATH.getString())
145 val selectedDriverMetadata = GpuDriverHelper.customDriverSettingData 145 val selectedDriverMetadata = GpuDriverHelper.customDriverSettingData
146 if (GpuDriverHelper.installedCustomDriverData == selectedDriverMetadata) { 146 if (GpuDriverHelper.installedCustomDriverData == selectedDriverMetadata) {
147 setDriverReady()
147 return 148 return
148 } 149 }
149 150
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
index f1ea1e20f..6859b7780 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
@@ -3,6 +3,7 @@
3 3
4package org.yuzu.yuzu_emu.model 4package org.yuzu.yuzu_emu.model
5 5
6import android.content.Intent
6import android.net.Uri 7import android.net.Uri
7import android.os.Parcelable 8import android.os.Parcelable
8import java.util.HashSet 9import java.util.HashSet
@@ -11,6 +12,7 @@ import kotlinx.serialization.Serializable
11import org.yuzu.yuzu_emu.NativeLibrary 12import org.yuzu.yuzu_emu.NativeLibrary
12import org.yuzu.yuzu_emu.R 13import org.yuzu.yuzu_emu.R
13import org.yuzu.yuzu_emu.YuzuApplication 14import org.yuzu.yuzu_emu.YuzuApplication
15import org.yuzu.yuzu_emu.activities.EmulationActivity
14import org.yuzu.yuzu_emu.utils.DirectoryInitialization 16import org.yuzu.yuzu_emu.utils.DirectoryInitialization
15import org.yuzu.yuzu_emu.utils.FileUtil 17import org.yuzu.yuzu_emu.utils.FileUtil
16import java.time.LocalDateTime 18import java.time.LocalDateTime
@@ -61,12 +63,26 @@ class Game(
61 val addonDir: String 63 val addonDir: String
62 get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/" 64 get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
63 65
64 override fun equals(other: Any?): Boolean { 66 val launchIntent: Intent
65 if (other !is Game) { 67 get() = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
66 return false 68 action = Intent.ACTION_VIEW
69 data = Uri.parse(path)
67 } 70 }
68 71
69 return hashCode() == other.hashCode() 72 override fun equals(other: Any?): Boolean {
73 if (this === other) return true
74 if (javaClass != other?.javaClass) return false
75
76 other as Game
77
78 if (title != other.title) return false
79 if (path != other.path) return false
80 if (programId != other.programId) return false
81 if (developer != other.developer) return false
82 if (version != other.version) return false
83 if (isHomebrew != other.isHomebrew) return false
84
85 return true
70 } 86 }
71 87
72 override fun hashCode(): Int { 88 override fun hashCode(): Int {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt
index 2e9b0beb8..d05020560 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt
@@ -5,7 +5,10 @@ package org.yuzu.yuzu_emu.utils
5 5
6import android.graphics.Bitmap 6import android.graphics.Bitmap
7import android.graphics.BitmapFactory 7import android.graphics.BitmapFactory
8import android.graphics.drawable.LayerDrawable
8import android.widget.ImageView 9import android.widget.ImageView
10import androidx.core.content.res.ResourcesCompat
11import androidx.core.graphics.drawable.IconCompat
9import androidx.core.graphics.drawable.toBitmap 12import androidx.core.graphics.drawable.toBitmap
10import androidx.core.graphics.drawable.toDrawable 13import androidx.core.graphics.drawable.toDrawable
11import androidx.lifecycle.LifecycleOwner 14import androidx.lifecycle.LifecycleOwner
@@ -85,4 +88,22 @@ object GameIconUtils {
85 return imageLoader.execute(request) 88 return imageLoader.execute(request)
86 .drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888) 89 .drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888)
87 } 90 }
91
92 suspend fun getShortcutIcon(lifecycleOwner: LifecycleOwner, game: Game): IconCompat {
93 val layerDrawable = ResourcesCompat.getDrawable(
94 YuzuApplication.appContext.resources,
95 R.drawable.shortcut,
96 null
97 ) as LayerDrawable
98 layerDrawable.setDrawableByLayerId(
99 R.id.shortcut_foreground,
100 getGameIcon(lifecycleOwner, game).toDrawable(YuzuApplication.appContext.resources)
101 )
102 val inset = YuzuApplication.appContext.resources
103 .getDimensionPixelSize(R.dimen.icon_inset)
104 layerDrawable.setLayerInset(1, inset, inset, inset, inset)
105 return IconCompat.createWithAdaptiveBitmap(
106 layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
107 )
108 }
88} 109}
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index e51453eca..247f2c2b3 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -247,6 +247,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
247 m_system.GetCpuManager().OnGpuReady(); 247 m_system.GetCpuManager().OnGpuReady();
248 m_system.RegisterExitCallback([&] { HaltEmulation(); }); 248 m_system.RegisterExitCallback([&] { HaltEmulation(); });
249 249
250 OnEmulationStarted();
250 return Core::SystemResultStatus::Success; 251 return Core::SystemResultStatus::Success;
251} 252}
252 253
@@ -674,6 +675,11 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCpuBackend(JNIEnv* env, jclass
674 return ToJString(env, "JIT"); 675 return ToJString(env, "JIT");
675} 676}
676 677
678jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuDriver(JNIEnv* env, jobject jobj) {
679 return ToJString(env,
680 EmulationSession::GetInstance().System().GPU().Renderer().GetDeviceVendor());
681}
682
677void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) { 683void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) {
678 EmulationSession::GetInstance().System().ApplySettings(); 684 EmulationSession::GetInstance().System().ApplySettings();
679} 685}
diff --git a/src/android/app/src/main/res/drawable/ic_shortcut.xml b/src/android/app/src/main/res/drawable/ic_shortcut.xml
new file mode 100644
index 000000000..06e1983b2
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_shortcut.xml
@@ -0,0 +1,9 @@
1<vector xmlns:android="http://schemas.android.com/apk/res/android"
2 android:width="24dp"
3 android:height="24dp"
4 android:viewportWidth="960"
5 android:viewportHeight="960">
6 <path
7 android:fillColor="?attr/colorControlNormal"
8 android:pathData="M280,920q-33,0 -56.5,-23.5T200,840v-720q0,-33 23.5,-56.5T280,40h400q33,0 56.5,23.5T760,120v160h-80v-40L280,240v480h400v-40h80v160q0,33 -23.5,56.5T680,920L280,920ZM686,520L480,520v120h-80v-120q0,-33 23.5,-56.5T480,440h206l-62,-64 56,-56 160,160 -160,160 -56,-56 62,-64Z" />
9</vector>
diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml b/src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml
index 0b9633855..551f255c0 100644
--- a/src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml
+++ b/src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml
@@ -43,16 +43,35 @@
43 app:layout_constraintStart_toStartOf="parent" 43 app:layout_constraintStart_toStartOf="parent"
44 app:layout_constraintTop_toTopOf="parent"> 44 app:layout_constraintTop_toTopOf="parent">
45 45
46 <Button 46 <androidx.constraintlayout.widget.ConstraintLayout
47 android:id="@+id/button_back" 47 android:layout_width="match_parent"
48 style="?attr/materialIconButtonStyle"
49 android:layout_width="wrap_content"
50 android:layout_height="wrap_content" 48 android:layout_height="wrap_content"
51 android:layout_gravity="start"
52 android:layout_margin="8dp" 49 android:layout_margin="8dp"
53 app:icon="@drawable/ic_back" 50 android:orientation="horizontal">
54 app:iconSize="24dp" 51
55 app:iconTint="?attr/colorOnSurface" /> 52 <Button
53 android:id="@+id/button_back"
54 style="?attr/materialIconButtonStyle"
55 android:layout_width="wrap_content"
56 android:layout_height="wrap_content"
57 app:icon="@drawable/ic_back"
58 app:iconSize="24dp"
59 app:iconTint="?attr/colorOnSurface"
60 app:layout_constraintStart_toStartOf="parent"
61 app:layout_constraintTop_toTopOf="parent" />
62
63 <Button
64 android:id="@+id/button_shortcut"
65 style="?attr/materialIconButtonStyle"
66 android:layout_width="wrap_content"
67 android:layout_height="wrap_content"
68 app:icon="@drawable/ic_shortcut"
69 app:iconSize="24dp"
70 app:iconTint="?attr/colorOnSurface"
71 app:layout_constraintTop_toTopOf="parent"
72 app:layout_constraintEnd_toEndOf="parent" />
73
74 </androidx.constraintlayout.widget.ConstraintLayout>
56 75
57 <com.google.android.material.card.MaterialCardView 76 <com.google.android.material.card.MaterialCardView
58 style="?attr/materialCardViewElevatedStyle" 77 style="?attr/materialCardViewElevatedStyle"
diff --git a/src/android/app/src/main/res/layout/fragment_game_properties.xml b/src/android/app/src/main/res/layout/fragment_game_properties.xml
index 72ecbde30..cadd0bc4a 100644
--- a/src/android/app/src/main/res/layout/fragment_game_properties.xml
+++ b/src/android/app/src/main/res/layout/fragment_game_properties.xml
@@ -1,6 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<androidx.constraintlayout.widget.ConstraintLayout 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:android="http://schemas.android.com/apk/res/android"
4 xmlns:app="http://schemas.android.com/apk/res-auto" 3 xmlns:app="http://schemas.android.com/apk/res-auto"
5 xmlns:tools="http://schemas.android.com/tools" 4 xmlns:tools="http://schemas.android.com/tools"
6 android:layout_width="match_parent" 5 android:layout_width="match_parent"
@@ -22,16 +21,35 @@
22 android:orientation="vertical" 21 android:orientation="vertical"
23 android:gravity="center_horizontal"> 22 android:gravity="center_horizontal">
24 23
25 <Button 24 <androidx.constraintlayout.widget.ConstraintLayout
26 android:id="@+id/button_back" 25 android:layout_width="match_parent"
27 style="?attr/materialIconButtonStyle"
28 android:layout_width="wrap_content"
29 android:layout_height="wrap_content" 26 android:layout_height="wrap_content"
30 android:layout_margin="8dp" 27 android:layout_margin="8dp"
31 android:layout_gravity="start" 28 android:orientation="horizontal">
32 app:icon="@drawable/ic_back" 29
33 app:iconSize="24dp" 30 <Button
34 app:iconTint="?attr/colorOnSurface" /> 31 android:id="@+id/button_back"
32 style="?attr/materialIconButtonStyle"
33 android:layout_width="wrap_content"
34 android:layout_height="wrap_content"
35 app:icon="@drawable/ic_back"
36 app:iconSize="24dp"
37 app:iconTint="?attr/colorOnSurface"
38 app:layout_constraintStart_toStartOf="parent"
39 app:layout_constraintTop_toTopOf="parent" />
40
41 <Button
42 android:id="@+id/button_shortcut"
43 style="?attr/materialIconButtonStyle"
44 android:layout_width="wrap_content"
45 android:layout_height="wrap_content"
46 app:icon="@drawable/ic_shortcut"
47 app:iconSize="24dp"
48 app:iconTint="?attr/colorOnSurface"
49 app:layout_constraintEnd_toEndOf="parent"
50 app:layout_constraintTop_toTopOf="parent" />
51
52 </androidx.constraintlayout.widget.ConstraintLayout>
35 53
36 <com.google.android.material.card.MaterialCardView 54 <com.google.android.material.card.MaterialCardView
37 style="?attr/materialCardViewElevatedStyle" 55 style="?attr/materialCardViewElevatedStyle"
@@ -45,7 +63,7 @@
45 android:id="@+id/image_game_screen" 63 android:id="@+id/image_game_screen"
46 android:layout_width="175dp" 64 android:layout_width="175dp"
47 android:layout_height="175dp" 65 android:layout_height="175dp"
48 tools:src="@drawable/default_icon"/> 66 tools:src="@drawable/default_icon" />
49 67
50 </com.google.android.material.card.MaterialCardView> 68 </com.google.android.material.card.MaterialCardView>
51 69
diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp
index 3c214ec00..2a1ae1bb3 100644
--- a/src/audio_core/device/device_session.cpp
+++ b/src/audio_core/device/device_session.cpp
@@ -8,6 +8,7 @@
8#include "audio_core/sink/sink_stream.h" 8#include "audio_core/sink/sink_stream.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/core_timing.h" 10#include "core/core_timing.h"
11#include "core/guest_memory.h"
11#include "core/memory.h" 12#include "core/memory.h"
12 13
13#include "core/hle/kernel/k_process.h" 14#include "core/hle/kernel/k_process.h"
diff --git a/src/audio_core/renderer/command/data_source/decode.cpp b/src/audio_core/renderer/command/data_source/decode.cpp
index 911dae3c1..905613a5a 100644
--- a/src/audio_core/renderer/command/data_source/decode.cpp
+++ b/src/audio_core/renderer/command/data_source/decode.cpp
@@ -9,6 +9,7 @@
9#include "common/fixed_point.h" 9#include "common/fixed_point.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/scratch_buffer.h" 11#include "common/scratch_buffer.h"
12#include "core/guest_memory.h"
12#include "core/memory.h" 13#include "core/memory.h"
13 14
14namespace AudioCore::Renderer { 15namespace AudioCore::Renderer {
diff --git a/src/common/arm64/native_clock.cpp b/src/common/arm64/native_clock.cpp
index f437d7187..76ffb74ba 100644
--- a/src/common/arm64/native_clock.cpp
+++ b/src/common/arm64/native_clock.cpp
@@ -30,27 +30,27 @@ NativeClock::NativeClock() {
30} 30}
31 31
32std::chrono::nanoseconds NativeClock::GetTimeNS() const { 32std::chrono::nanoseconds NativeClock::GetTimeNS() const {
33 return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_cntfrq_factor)}; 33 return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)};
34} 34}
35 35
36std::chrono::microseconds NativeClock::GetTimeUS() const { 36std::chrono::microseconds NativeClock::GetTimeUS() const {
37 return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_cntfrq_factor)}; 37 return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)};
38} 38}
39 39
40std::chrono::milliseconds NativeClock::GetTimeMS() const { 40std::chrono::milliseconds NativeClock::GetTimeMS() const {
41 return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_cntfrq_factor)}; 41 return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)};
42} 42}
43 43
44u64 NativeClock::GetCNTPCT() const { 44s64 NativeClock::GetCNTPCT() const {
45 return MultiplyHigh(GetHostTicksElapsed(), guest_cntfrq_factor); 45 return MultiplyHigh(GetUptime(), guest_cntfrq_factor);
46} 46}
47 47
48u64 NativeClock::GetGPUTick() const { 48s64 NativeClock::GetGPUTick() const {
49 return MultiplyHigh(GetHostTicksElapsed(), gputick_cntfrq_factor); 49 return MultiplyHigh(GetUptime(), gputick_cntfrq_factor);
50} 50}
51 51
52u64 NativeClock::GetHostTicksNow() const { 52s64 NativeClock::GetUptime() const {
53 u64 cntvct_el0 = 0; 53 s64 cntvct_el0 = 0;
54 asm volatile("dsb ish\n\t" 54 asm volatile("dsb ish\n\t"
55 "mrs %[cntvct_el0], cntvct_el0\n\t" 55 "mrs %[cntvct_el0], cntvct_el0\n\t"
56 "dsb ish\n\t" 56 "dsb ish\n\t"
@@ -58,15 +58,11 @@ u64 NativeClock::GetHostTicksNow() const {
58 return cntvct_el0; 58 return cntvct_el0;
59} 59}
60 60
61u64 NativeClock::GetHostTicksElapsed() const {
62 return GetHostTicksNow();
63}
64
65bool NativeClock::IsNative() const { 61bool NativeClock::IsNative() const {
66 return true; 62 return true;
67} 63}
68 64
69u64 NativeClock::GetHostCNTFRQ() { 65s64 NativeClock::GetHostCNTFRQ() {
70 u64 cntfrq_el0 = 0; 66 u64 cntfrq_el0 = 0;
71 std::string_view board{""}; 67 std::string_view board{""};
72#ifdef ANDROID 68#ifdef ANDROID
diff --git a/src/common/arm64/native_clock.h b/src/common/arm64/native_clock.h
index a28b419f2..94bc1882e 100644
--- a/src/common/arm64/native_clock.h
+++ b/src/common/arm64/native_clock.h
@@ -17,17 +17,15 @@ public:
17 17
18 std::chrono::milliseconds GetTimeMS() const override; 18 std::chrono::milliseconds GetTimeMS() const override;
19 19
20 u64 GetCNTPCT() const override; 20 s64 GetCNTPCT() const override;
21 21
22 u64 GetGPUTick() const override; 22 s64 GetGPUTick() const override;
23 23
24 u64 GetHostTicksNow() const override; 24 s64 GetUptime() const override;
25
26 u64 GetHostTicksElapsed() const override;
27 25
28 bool IsNative() const override; 26 bool IsNative() const override;
29 27
30 static u64 GetHostCNTFRQ(); 28 static s64 GetHostCNTFRQ();
31 29
32public: 30public:
33 using FactorType = unsigned __int128; 31 using FactorType = unsigned __int128;
diff --git a/src/common/common_types.h b/src/common/common_types.h
index 0fc225aff..ae04c4d60 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -45,6 +45,7 @@ using f32 = float; ///< 32-bit floating point
45using f64 = double; ///< 64-bit floating point 45using f64 = double; ///< 64-bit floating point
46 46
47using VAddr = u64; ///< Represents a pointer in the userspace virtual address space. 47using VAddr = u64; ///< Represents a pointer in the userspace virtual address space.
48using DAddr = u64; ///< Represents a pointer in the device specific virtual address space.
48using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space. 49using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space.
49using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space. 50using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space.
50 51
diff --git a/src/common/memory_detect.h b/src/common/memory_detect.h
index a345e6d28..c8f239aed 100644
--- a/src/common/memory_detect.h
+++ b/src/common/memory_detect.h
@@ -18,4 +18,4 @@ struct MemoryInfo {
18 */ 18 */
19[[nodiscard]] const MemoryInfo& GetMemInfo(); 19[[nodiscard]] const MemoryInfo& GetMemInfo();
20 20
21} // namespace Common \ No newline at end of file 21} // namespace Common
diff --git a/src/common/settings.h b/src/common/settings.h
index 07dba53ab..16749ab68 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -419,9 +419,16 @@ struct Values {
419 linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true}; 419 linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
420 SwitchableSetting<s64> custom_rtc{ 420 SwitchableSetting<s64> custom_rtc{
421 linkage, 0, "custom_rtc", Category::System, Specialization::Time, 421 linkage, 0, "custom_rtc", Category::System, Specialization::Time,
422 true, true, &custom_rtc_enabled}; 422 false, true, &custom_rtc_enabled};
423 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` 423 SwitchableSetting<s64, true> custom_rtc_offset{linkage,
424 s64 custom_rtc_differential; 424 0,
425 std::numeric_limits<int>::min(),
426 std::numeric_limits<int>::max(),
427 "custom_rtc_offset",
428 Category::System,
429 Specialization::Countable,
430 true,
431 true};
425 SwitchableSetting<bool> rng_seed_enabled{ 432 SwitchableSetting<bool> rng_seed_enabled{
426 linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true}; 433 linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true};
427 SwitchableSetting<u32> rng_seed{ 434 SwitchableSetting<u32> rng_seed{
diff --git a/src/common/time_zone.cpp b/src/common/time_zone.cpp
index 69e728a9d..f77df604f 100644
--- a/src/common/time_zone.cpp
+++ b/src/common/time_zone.cpp
@@ -88,7 +88,17 @@ std::string FindSystemTimeZone() {
88 LOG_ERROR(Common, "Time zone {} not handled, defaulting to hour offset.", tz_index); 88 LOG_ERROR(Common, "Time zone {} not handled, defaulting to hour offset.", tz_index);
89 } 89 }
90 } 90 }
91 return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours)); 91
92 // For some reason the Etc/GMT times are reversed. GMT+6 contains -21600 as its offset,
93 // -6 hours instead of +6 hours, so these signs are purposefully reversed to fix it.
94 std::string postfix{""};
95 if (hours > 0) {
96 postfix = fmt::format("-{:d}", std::abs(hours));
97 } else if (hours < 0) {
98 postfix = fmt::format("+{:d}", std::abs(hours));
99 }
100
101 return fmt::format("Etc/GMT{:s}", postfix);
92} 102}
93 103
94} // namespace Common::TimeZone 104} // namespace Common::TimeZone
diff --git a/src/common/uuid.h b/src/common/uuid.h
index 7172ca165..81bfefbbb 100644
--- a/src/common/uuid.h
+++ b/src/common/uuid.h
@@ -12,9 +12,8 @@
12namespace Common { 12namespace Common {
13 13
14struct UUID { 14struct UUID {
15 std::array<u8, 0x10> uuid{}; 15 std::array<u8, 0x10> uuid;
16 16
17 /// Constructs an invalid UUID.
18 constexpr UUID() = default; 17 constexpr UUID() = default;
19 18
20 /// Constructs a UUID from a reference to a 128 bit array. 19 /// Constructs a UUID from a reference to a 128 bit array.
@@ -34,14 +33,6 @@ struct UUID {
34 */ 33 */
35 explicit UUID(std::string_view uuid_string); 34 explicit UUID(std::string_view uuid_string);
36 35
37 ~UUID() = default;
38
39 constexpr UUID(const UUID&) noexcept = default;
40 constexpr UUID(UUID&&) noexcept = default;
41
42 constexpr UUID& operator=(const UUID&) noexcept = default;
43 constexpr UUID& operator=(UUID&&) noexcept = default;
44
45 /** 36 /**
46 * Returns whether the stored UUID is valid or not. 37 * Returns whether the stored UUID is valid or not.
47 * 38 *
@@ -121,6 +112,7 @@ struct UUID {
121 friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default; 112 friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
122}; 113};
123static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size."); 114static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size.");
115static_assert(std::is_trivial_v<UUID>);
124 116
125/// An invalid UUID. This UUID has all its bytes set to 0. 117/// An invalid UUID. This UUID has all its bytes set to 0.
126constexpr UUID InvalidUUID = {}; 118constexpr UUID InvalidUUID = {};
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index 012fdc1e0..e14bf3e65 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -18,42 +18,40 @@ namespace Common {
18 18
19class StandardWallClock final : public WallClock { 19class StandardWallClock final : public WallClock {
20public: 20public:
21 explicit StandardWallClock() : start_time{SteadyClock::Now()} {} 21 explicit StandardWallClock() {}
22 22
23 std::chrono::nanoseconds GetTimeNS() const override { 23 std::chrono::nanoseconds GetTimeNS() const override {
24 return SteadyClock::Now() - start_time; 24 return std::chrono::duration_cast<std::chrono::nanoseconds>(
25 std::chrono::system_clock::now().time_since_epoch());
25 } 26 }
26 27
27 std::chrono::microseconds GetTimeUS() const override { 28 std::chrono::microseconds GetTimeUS() const override {
28 return static_cast<std::chrono::microseconds>(GetHostTicksElapsed() / NsToUsRatio::den); 29 return std::chrono::duration_cast<std::chrono::microseconds>(
30 std::chrono::system_clock::now().time_since_epoch());
29 } 31 }
30 32
31 std::chrono::milliseconds GetTimeMS() const override { 33 std::chrono::milliseconds GetTimeMS() const override {
32 return static_cast<std::chrono::milliseconds>(GetHostTicksElapsed() / NsToMsRatio::den); 34 return std::chrono::duration_cast<std::chrono::milliseconds>(
35 std::chrono::system_clock::now().time_since_epoch());
33 } 36 }
34 37
35 u64 GetCNTPCT() const override { 38 s64 GetCNTPCT() const override {
36 return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; 39 return GetUptime() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
37 } 40 }
38 41
39 u64 GetGPUTick() const override { 42 s64 GetGPUTick() const override {
40 return GetHostTicksElapsed() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; 43 return GetUptime() * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
41 } 44 }
42 45
43 u64 GetHostTicksNow() const override { 46 s64 GetUptime() const override {
44 return static_cast<u64>(SteadyClock::Now().time_since_epoch().count()); 47 return std::chrono::duration_cast<std::chrono::nanoseconds>(
45 } 48 std::chrono::steady_clock::now().time_since_epoch())
46 49 .count();
47 u64 GetHostTicksElapsed() const override {
48 return static_cast<u64>(GetTimeNS().count());
49 } 50 }
50 51
51 bool IsNative() const override { 52 bool IsNative() const override {
52 return false; 53 return false;
53 } 54 }
54
55private:
56 SteadyClock::time_point start_time;
57}; 55};
58 56
59std::unique_ptr<WallClock> CreateOptimalClock() { 57std::unique_ptr<WallClock> CreateOptimalClock() {
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index f45d3d8c5..3a0c43909 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -29,16 +29,13 @@ public:
29 virtual std::chrono::milliseconds GetTimeMS() const = 0; 29 virtual std::chrono::milliseconds GetTimeMS() const = 0;
30 30
31 /// @returns The guest CNTPCT ticks since the construction of this clock. 31 /// @returns The guest CNTPCT ticks since the construction of this clock.
32 virtual u64 GetCNTPCT() const = 0; 32 virtual s64 GetCNTPCT() const = 0;
33 33
34 /// @returns The guest GPU ticks since the construction of this clock. 34 /// @returns The guest GPU ticks since the construction of this clock.
35 virtual u64 GetGPUTick() const = 0; 35 virtual s64 GetGPUTick() const = 0;
36 36
37 /// @returns The raw host timer ticks since an indeterminate epoch. 37 /// @returns The raw host timer ticks since an indeterminate epoch.
38 virtual u64 GetHostTicksNow() const = 0; 38 virtual s64 GetUptime() const = 0;
39
40 /// @returns The raw host timer ticks since the construction of this clock.
41 virtual u64 GetHostTicksElapsed() const = 0;
42 39
43 /// @returns Whether the clock directly uses the host's hardware clock. 40 /// @returns Whether the clock directly uses the host's hardware clock.
44 virtual bool IsNative() const = 0; 41 virtual bool IsNative() const = 0;
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index 7d2a26bd9..d2d27fafe 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -8,39 +8,35 @@
8namespace Common::X64 { 8namespace Common::X64 {
9 9
10NativeClock::NativeClock(u64 rdtsc_frequency_) 10NativeClock::NativeClock(u64 rdtsc_frequency_)
11 : start_ticks{FencedRDTSC()}, rdtsc_frequency{rdtsc_frequency_}, 11 : rdtsc_frequency{rdtsc_frequency_}, ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den,
12 ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)}, 12 rdtsc_frequency)},
13 us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, 13 us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)},
14 ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, 14 ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)},
15 cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)}, 15 cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)},
16 gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {} 16 gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {}
17 17
18std::chrono::nanoseconds NativeClock::GetTimeNS() const { 18std::chrono::nanoseconds NativeClock::GetTimeNS() const {
19 return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)}; 19 return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_rdtsc_factor)};
20} 20}
21 21
22std::chrono::microseconds NativeClock::GetTimeUS() const { 22std::chrono::microseconds NativeClock::GetTimeUS() const {
23 return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_rdtsc_factor)}; 23 return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_rdtsc_factor)};
24} 24}
25 25
26std::chrono::milliseconds NativeClock::GetTimeMS() const { 26std::chrono::milliseconds NativeClock::GetTimeMS() const {
27 return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_rdtsc_factor)}; 27 return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_rdtsc_factor)};
28} 28}
29 29
30u64 NativeClock::GetCNTPCT() const { 30s64 NativeClock::GetCNTPCT() const {
31 return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor); 31 return MultiplyHigh(GetUptime(), cntpct_rdtsc_factor);
32} 32}
33 33
34u64 NativeClock::GetGPUTick() const { 34s64 NativeClock::GetGPUTick() const {
35 return MultiplyHigh(GetHostTicksElapsed(), gputick_rdtsc_factor); 35 return MultiplyHigh(GetUptime(), gputick_rdtsc_factor);
36} 36}
37 37
38u64 NativeClock::GetHostTicksNow() const { 38s64 NativeClock::GetUptime() const {
39 return FencedRDTSC(); 39 return static_cast<s64>(FencedRDTSC());
40}
41
42u64 NativeClock::GetHostTicksElapsed() const {
43 return FencedRDTSC() - start_ticks;
44} 40}
45 41
46bool NativeClock::IsNative() const { 42bool NativeClock::IsNative() const {
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h
index 334415eff..b2629b031 100644
--- a/src/common/x64/native_clock.h
+++ b/src/common/x64/native_clock.h
@@ -17,18 +17,15 @@ public:
17 17
18 std::chrono::milliseconds GetTimeMS() const override; 18 std::chrono::milliseconds GetTimeMS() const override;
19 19
20 u64 GetCNTPCT() const override; 20 s64 GetCNTPCT() const override;
21 21
22 u64 GetGPUTick() const override; 22 s64 GetGPUTick() const override;
23 23
24 u64 GetHostTicksNow() const override; 24 s64 GetUptime() const override;
25
26 u64 GetHostTicksElapsed() const override;
27 25
28 bool IsNative() const override; 26 bool IsNative() const override;
29 27
30private: 28private:
31 u64 start_ticks;
32 u64 rdtsc_frequency; 29 u64 rdtsc_frequency;
33 30
34 u64 ns_rdtsc_factor; 31 u64 ns_rdtsc_factor;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 16ddb5e90..45a0d8746 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -37,6 +37,8 @@ add_library(core STATIC
37 debugger/gdbstub_arch.h 37 debugger/gdbstub_arch.h
38 debugger/gdbstub.cpp 38 debugger/gdbstub.cpp
39 debugger/gdbstub.h 39 debugger/gdbstub.h
40 device_memory_manager.h
41 device_memory_manager.inc
40 device_memory.cpp 42 device_memory.cpp
41 device_memory.h 43 device_memory.h
42 file_sys/fssystem/fs_i_storage.h 44 file_sys/fssystem/fs_i_storage.h
@@ -470,6 +472,8 @@ add_library(core STATIC
470 hle/service/caps/caps_types.h 472 hle/service/caps/caps_types.h
471 hle/service/caps/caps_u.cpp 473 hle/service/caps/caps_u.cpp
472 hle/service/caps/caps_u.h 474 hle/service/caps/caps_u.h
475 hle/service/cmif_serialization.h
476 hle/service/cmif_types.h
473 hle/service/erpt/erpt.cpp 477 hle/service/erpt/erpt.cpp
474 hle/service/erpt/erpt.h 478 hle/service/erpt/erpt.h
475 hle/service/es/es.cpp 479 hle/service/es/es.cpp
@@ -513,6 +517,24 @@ add_library(core STATIC
513 hle/service/glue/glue_manager.h 517 hle/service/glue/glue_manager.h
514 hle/service/glue/notif.cpp 518 hle/service/glue/notif.cpp
515 hle/service/glue/notif.h 519 hle/service/glue/notif.h
520 hle/service/glue/time/alarm_worker.cpp
521 hle/service/glue/time/alarm_worker.h
522 hle/service/glue/time/file_timestamp_worker.cpp
523 hle/service/glue/time/file_timestamp_worker.h
524 hle/service/glue/time/manager.cpp
525 hle/service/glue/time/manager.h
526 hle/service/glue/time/pm_state_change_handler.cpp
527 hle/service/glue/time/pm_state_change_handler.h
528 hle/service/glue/time/standard_steady_clock_resource.cpp
529 hle/service/glue/time/standard_steady_clock_resource.h
530 hle/service/glue/time/static.cpp
531 hle/service/glue/time/static.h
532 hle/service/glue/time/time_zone.cpp
533 hle/service/glue/time/time_zone.h
534 hle/service/glue/time/time_zone_binary.cpp
535 hle/service/glue/time/time_zone_binary.h
536 hle/service/glue/time/worker.cpp
537 hle/service/glue/time/worker.h
516 hle/service/grc/grc.cpp 538 hle/service/grc/grc.cpp
517 hle/service/grc/grc.h 539 hle/service/grc/grc.h
518 hle/service/hid/hid.cpp 540 hle/service/hid/hid.cpp
@@ -609,6 +631,8 @@ add_library(core STATIC
609 hle/service/ns/pdm_qry.h 631 hle/service/ns/pdm_qry.h
610 hle/service/nvdrv/core/container.cpp 632 hle/service/nvdrv/core/container.cpp
611 hle/service/nvdrv/core/container.h 633 hle/service/nvdrv/core/container.h
634 hle/service/nvdrv/core/heap_mapper.cpp
635 hle/service/nvdrv/core/heap_mapper.h
612 hle/service/nvdrv/core/nvmap.cpp 636 hle/service/nvdrv/core/nvmap.cpp
613 hle/service/nvdrv/core/nvmap.h 637 hle/service/nvdrv/core/nvmap.h
614 hle/service/nvdrv/core/syncpoint_manager.cpp 638 hle/service/nvdrv/core/syncpoint_manager.cpp
@@ -689,6 +713,46 @@ add_library(core STATIC
689 hle/service/prepo/prepo.h 713 hle/service/prepo/prepo.h
690 hle/service/psc/psc.cpp 714 hle/service/psc/psc.cpp
691 hle/service/psc/psc.h 715 hle/service/psc/psc.h
716 hle/service/psc/time/alarms.cpp
717 hle/service/psc/time/alarms.h
718 hle/service/psc/time/clocks/context_writers.cpp
719 hle/service/psc/time/clocks/context_writers.h
720 hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h
721 hle/service/psc/time/clocks/standard_local_system_clock_core.cpp
722 hle/service/psc/time/clocks/standard_local_system_clock_core.h
723 hle/service/psc/time/clocks/standard_network_system_clock_core.cpp
724 hle/service/psc/time/clocks/standard_network_system_clock_core.h
725 hle/service/psc/time/clocks/standard_steady_clock_core.cpp
726 hle/service/psc/time/clocks/standard_steady_clock_core.h
727 hle/service/psc/time/clocks/standard_user_system_clock_core.cpp
728 hle/service/psc/time/clocks/standard_user_system_clock_core.h
729 hle/service/psc/time/clocks/steady_clock_core.h
730 hle/service/psc/time/clocks/system_clock_core.cpp
731 hle/service/psc/time/clocks/system_clock_core.h
732 hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp
733 hle/service/psc/time/clocks/tick_based_steady_clock_core.h
734 hle/service/psc/time/common.cpp
735 hle/service/psc/time/common.h
736 hle/service/psc/time/errors.h
737 hle/service/psc/time/shared_memory.cpp
738 hle/service/psc/time/shared_memory.h
739 hle/service/psc/time/static.cpp
740 hle/service/psc/time/static.h
741 hle/service/psc/time/manager.h
742 hle/service/psc/time/power_state_service.cpp
743 hle/service/psc/time/power_state_service.h
744 hle/service/psc/time/service_manager.cpp
745 hle/service/psc/time/service_manager.h
746 hle/service/psc/time/steady_clock.cpp
747 hle/service/psc/time/steady_clock.h
748 hle/service/psc/time/system_clock.cpp
749 hle/service/psc/time/system_clock.h
750 hle/service/psc/time/time_zone.cpp
751 hle/service/psc/time/time_zone.h
752 hle/service/psc/time/time_zone_service.cpp
753 hle/service/psc/time/time_zone_service.h
754 hle/service/psc/time/power_state_request_manager.cpp
755 hle/service/psc/time/power_state_request_manager.h
692 hle/service/ptm/psm.cpp 756 hle/service/ptm/psm.cpp
693 hle/service/ptm/psm.h 757 hle/service/ptm/psm.h
694 hle/service/ptm/ptm.cpp 758 hle/service/ptm/ptm.cpp
@@ -756,40 +820,6 @@ add_library(core STATIC
756 hle/service/ssl/ssl.cpp 820 hle/service/ssl/ssl.cpp
757 hle/service/ssl/ssl.h 821 hle/service/ssl/ssl.h
758 hle/service/ssl/ssl_backend.h 822 hle/service/ssl/ssl_backend.h
759 hle/service/time/clock_types.h
760 hle/service/time/ephemeral_network_system_clock_context_writer.h
761 hle/service/time/ephemeral_network_system_clock_core.h
762 hle/service/time/errors.h
763 hle/service/time/local_system_clock_context_writer.h
764 hle/service/time/network_system_clock_context_writer.h
765 hle/service/time/standard_local_system_clock_core.h
766 hle/service/time/standard_network_system_clock_core.h
767 hle/service/time/standard_steady_clock_core.cpp
768 hle/service/time/standard_steady_clock_core.h
769 hle/service/time/standard_user_system_clock_core.cpp
770 hle/service/time/standard_user_system_clock_core.h
771 hle/service/time/steady_clock_core.h
772 hle/service/time/system_clock_context_update_callback.cpp
773 hle/service/time/system_clock_context_update_callback.h
774 hle/service/time/system_clock_core.cpp
775 hle/service/time/system_clock_core.h
776 hle/service/time/tick_based_steady_clock_core.cpp
777 hle/service/time/tick_based_steady_clock_core.h
778 hle/service/time/time.cpp
779 hle/service/time/time.h
780 hle/service/time/time_interface.cpp
781 hle/service/time/time_interface.h
782 hle/service/time/time_manager.cpp
783 hle/service/time/time_manager.h
784 hle/service/time/time_sharedmemory.cpp
785 hle/service/time/time_sharedmemory.h
786 hle/service/time/time_zone_content_manager.cpp
787 hle/service/time/time_zone_content_manager.h
788 hle/service/time/time_zone_manager.cpp
789 hle/service/time/time_zone_manager.h
790 hle/service/time/time_zone_service.cpp
791 hle/service/time/time_zone_service.h
792 hle/service/time/time_zone_types.h
793 hle/service/usb/usb.cpp 823 hle/service/usb/usb.cpp
794 hle/service/usb/usb.h 824 hle/service/usb/usb.h
795 hle/service/vi/display/vi_display.cpp 825 hle/service/vi/display/vi_display.cpp
@@ -870,7 +900,7 @@ endif()
870 900
871create_target_directory_groups(core) 901create_target_directory_groups(core)
872 902
873target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb) 903target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
874target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API) 904target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API)
875if (MINGW) 905if (MINGW)
876 target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) 906 target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 461eea9c8..dd9de948c 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -28,6 +28,7 @@
28#include "core/file_sys/savedata_factory.h" 28#include "core/file_sys/savedata_factory.h"
29#include "core/file_sys/vfs_concat.h" 29#include "core/file_sys/vfs_concat.h"
30#include "core/file_sys/vfs_real.h" 30#include "core/file_sys/vfs_real.h"
31#include "core/gpu_dirty_memory_manager.h"
31#include "core/hle/kernel/k_memory_manager.h" 32#include "core/hle/kernel/k_memory_manager.h"
32#include "core/hle/kernel/k_process.h" 33#include "core/hle/kernel/k_process.h"
33#include "core/hle/kernel/k_resource_limit.h" 34#include "core/hle/kernel/k_resource_limit.h"
@@ -39,9 +40,14 @@
39#include "core/hle/service/apm/apm_controller.h" 40#include "core/hle/service/apm/apm_controller.h"
40#include "core/hle/service/filesystem/filesystem.h" 41#include "core/hle/service/filesystem/filesystem.h"
41#include "core/hle/service/glue/glue_manager.h" 42#include "core/hle/service/glue/glue_manager.h"
43#include "core/hle/service/glue/time/static.h"
44#include "core/hle/service/psc/time/static.h"
45#include "core/hle/service/psc/time/steady_clock.h"
46#include "core/hle/service/psc/time/system_clock.h"
47#include "core/hle/service/psc/time/time_zone_service.h"
42#include "core/hle/service/service.h" 48#include "core/hle/service/service.h"
49#include "core/hle/service/set/system_settings_server.h"
43#include "core/hle/service/sm/sm.h" 50#include "core/hle/service/sm/sm.h"
44#include "core/hle/service/time/time_manager.h"
45#include "core/internal_network/network.h" 51#include "core/internal_network/network.h"
46#include "core/loader/loader.h" 52#include "core/loader/loader.h"
47#include "core/memory.h" 53#include "core/memory.h"
@@ -129,8 +135,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
129 135
130struct System::Impl { 136struct System::Impl {
131 explicit Impl(System& system) 137 explicit Impl(System& system)
132 : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system}, 138 : kernel{system}, fs_controller{system}, hid_core{}, room_network{},
133 reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {} 139 cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {}
134 140
135 void Initialize(System& system) { 141 void Initialize(System& system) {
136 device_memory = std::make_unique<Core::DeviceMemory>(); 142 device_memory = std::make_unique<Core::DeviceMemory>();
@@ -142,8 +148,6 @@ struct System::Impl {
142 core_timing.SetMulticore(is_multicore); 148 core_timing.SetMulticore(is_multicore);
143 core_timing.Initialize([&system]() { system.RegisterHostThread(); }); 149 core_timing.Initialize([&system]() { system.RegisterHostThread(); });
144 150
145 RefreshTime();
146
147 // Create a default fs if one doesn't already exist. 151 // Create a default fs if one doesn't already exist.
148 if (virtual_filesystem == nullptr) { 152 if (virtual_filesystem == nullptr) {
149 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); 153 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
@@ -181,14 +185,57 @@ struct System::Impl {
181 Initialize(system); 185 Initialize(system);
182 } 186 }
183 187
184 void RefreshTime() { 188 void RefreshTime(System& system) {
189 if (!system.IsPoweredOn()) {
190 return;
191 }
192
193 auto settings_service =
194 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys",
195 true);
196 auto static_service_a =
197 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:a", true);
198
199 auto static_service_s =
200 system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:s", true);
201
202 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock;
203 static_service_a->GetStandardUserSystemClock(user_clock);
204
205 std::shared_ptr<Service::PSC::Time::SystemClock> local_clock;
206 static_service_a->GetStandardLocalSystemClock(local_clock);
207
208 std::shared_ptr<Service::PSC::Time::SystemClock> network_clock;
209 static_service_s->GetStandardNetworkSystemClock(network_clock);
210
211 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service;
212 static_service_a->GetTimeZoneService(timezone_service);
213
214 Service::PSC::Time::LocationName name{};
215 auto new_name = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
216 std::memcpy(name.name.data(), new_name.data(), std::min(name.name.size(), new_name.size()));
217
218 timezone_service->SetDeviceLocation(name);
219
220 u64 time_offset = 0;
221 if (Settings::values.custom_rtc_enabled) {
222 time_offset = Settings::values.custom_rtc_offset.GetValue();
223 }
224
185 const auto posix_time = std::chrono::system_clock::now().time_since_epoch(); 225 const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
186 const auto current_time = 226 const u64 current_time =
187 std::chrono::duration_cast<std::chrono::seconds>(posix_time).count(); 227 +std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
188 Settings::values.custom_rtc_differential = 228 const u64 new_time = current_time + time_offset;
189 (Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue() 229
190 : current_time) - 230 Service::PSC::Time::SystemClockContext context{};
191 current_time; 231 settings_service->SetUserSystemClockContext(context);
232 user_clock->SetCurrentTime(new_time);
233
234 local_clock->SetCurrentTime(new_time);
235
236 network_clock->GetSystemClockContext(context);
237 settings_service->SetNetworkSystemClockContext(context);
238 network_clock->SetCurrentTime(new_time);
192 } 239 }
193 240
194 void Run() { 241 void Run() {
@@ -264,9 +311,6 @@ struct System::Impl {
264 service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); 311 service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
265 services = std::make_unique<Service::Services>(service_manager, system); 312 services = std::make_unique<Service::Services>(service_manager, system);
266 313
267 // Initialize time manager, which must happen after kernel is created
268 time_manager.Initialize();
269
270 is_powered_on = true; 314 is_powered_on = true;
271 exit_locked = false; 315 exit_locked = false;
272 exit_requested = false; 316 exit_requested = false;
@@ -416,7 +460,6 @@ struct System::Impl {
416 fs_controller.Reset(); 460 fs_controller.Reset();
417 cheat_engine.reset(); 461 cheat_engine.reset();
418 telemetry_session.reset(); 462 telemetry_session.reset();
419 time_manager.Shutdown();
420 core_timing.ClearPendingEvents(); 463 core_timing.ClearPendingEvents();
421 app_loader.reset(); 464 app_loader.reset();
422 audio_core.reset(); 465 audio_core.reset();
@@ -532,7 +575,6 @@ struct System::Impl {
532 /// Service State 575 /// Service State
533 Service::Glue::ARPManager arp_manager; 576 Service::Glue::ARPManager arp_manager;
534 Service::Account::ProfileManager profile_manager; 577 Service::Account::ProfileManager profile_manager;
535 Service::Time::TimeManager time_manager;
536 578
537 /// Service manager 579 /// Service manager
538 std::shared_ptr<Service::SM::ServiceManager> service_manager; 580 std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -565,6 +607,9 @@ struct System::Impl {
565 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; 607 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
566 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; 608 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
567 609
610 std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
611 gpu_dirty_memory_managers;
612
568 std::deque<std::vector<u8>> user_channel; 613 std::deque<std::vector<u8>> user_channel;
569}; 614};
570 615
@@ -651,8 +696,14 @@ size_t System::GetCurrentHostThreadID() const {
651 return impl->kernel.GetCurrentHostThreadID(); 696 return impl->kernel.GetCurrentHostThreadID();
652} 697}
653 698
654void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { 699std::span<GPUDirtyMemoryManager> System::GetGPUDirtyMemoryManager() {
655 return this->ApplicationProcess()->GatherGPUDirtyMemory(callback); 700 return impl->gpu_dirty_memory_managers;
701}
702
703void System::GatherGPUDirtyMemory(std::function<void(PAddr, size_t)>& callback) {
704 for (auto& manager : impl->gpu_dirty_memory_managers) {
705 manager.Gather(callback);
706 }
656} 707}
657 708
658PerfStatsResults System::GetAndResetPerfStats() { 709PerfStatsResults System::GetAndResetPerfStats() {
@@ -901,14 +952,6 @@ const Service::Account::ProfileManager& System::GetProfileManager() const {
901 return impl->profile_manager; 952 return impl->profile_manager;
902} 953}
903 954
904Service::Time::TimeManager& System::GetTimeManager() {
905 return impl->time_manager;
906}
907
908const Service::Time::TimeManager& System::GetTimeManager() const {
909 return impl->time_manager;
910}
911
912void System::SetExitLocked(bool locked) { 955void System::SetExitLocked(bool locked) {
913 impl->exit_locked = locked; 956 impl->exit_locked = locked;
914} 957}
@@ -1020,13 +1063,9 @@ void System::Exit() {
1020} 1063}
1021 1064
1022void System::ApplySettings() { 1065void System::ApplySettings() {
1023 impl->RefreshTime(); 1066 impl->RefreshTime(*this);
1024 1067
1025 if (IsPoweredOn()) { 1068 if (IsPoweredOn()) {
1026 if (Settings::values.custom_rtc_enabled) {
1027 const s64 posix_time{Settings::values.custom_rtc.GetValue()};
1028 GetTimeManager().UpdateLocalSystemClockTime(posix_time);
1029 }
1030 Renderer().RefreshBaseSettings(); 1069 Renderer().RefreshBaseSettings();
1031 } 1070 }
1032} 1071}
diff --git a/src/core/core.h b/src/core/core.h
index ba5add0dc..183410602 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -8,6 +8,7 @@
8#include <functional> 8#include <functional>
9#include <memory> 9#include <memory>
10#include <mutex> 10#include <mutex>
11#include <span>
11#include <string> 12#include <string>
12#include <vector> 13#include <vector>
13 14
@@ -72,10 +73,6 @@ namespace SM {
72class ServiceManager; 73class ServiceManager;
73} // namespace SM 74} // namespace SM
74 75
75namespace Time {
76class TimeManager;
77} // namespace Time
78
79} // namespace Service 76} // namespace Service
80 77
81namespace Tegra { 78namespace Tegra {
@@ -116,6 +113,7 @@ class CpuManager;
116class Debugger; 113class Debugger;
117class DeviceMemory; 114class DeviceMemory;
118class ExclusiveMonitor; 115class ExclusiveMonitor;
116class GPUDirtyMemoryManager;
119class PerfStats; 117class PerfStats;
120class Reporter; 118class Reporter;
121class SpeedLimiter; 119class SpeedLimiter;
@@ -224,7 +222,9 @@ public:
224 /// Prepare the core emulation for a reschedule 222 /// Prepare the core emulation for a reschedule
225 void PrepareReschedule(u32 core_index); 223 void PrepareReschedule(u32 core_index);
226 224
227 void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); 225 std::span<GPUDirtyMemoryManager> GetGPUDirtyMemoryManager();
226
227 void GatherGPUDirtyMemory(std::function<void(PAddr, size_t)>& callback);
228 228
229 [[nodiscard]] size_t GetCurrentHostThreadID() const; 229 [[nodiscard]] size_t GetCurrentHostThreadID() const;
230 230
@@ -377,9 +377,6 @@ public:
377 [[nodiscard]] Service::Account::ProfileManager& GetProfileManager(); 377 [[nodiscard]] Service::Account::ProfileManager& GetProfileManager();
378 [[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const; 378 [[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const;
379 379
380 [[nodiscard]] Service::Time::TimeManager& GetTimeManager();
381 [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
382
383 [[nodiscard]] Core::Debugger& GetDebugger(); 380 [[nodiscard]] Core::Debugger& GetDebugger();
384 [[nodiscard]] const Core::Debugger& GetDebugger() const; 381 [[nodiscard]] const Core::Debugger& GetDebugger() const;
385 382
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index fc536413b..1abfa920c 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -157,7 +157,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
157 } 157 }
158 } 158 }
159 159
160 for (auto h : to_remove) { 160 for (auto& h : to_remove) {
161 event_queue.erase(h); 161 event_queue.erase(h);
162 } 162 }
163 163
diff --git a/src/core/device_memory.h b/src/core/device_memory.h
index 13388b73e..11bf0e326 100644
--- a/src/core/device_memory.h
+++ b/src/core/device_memory.h
@@ -32,6 +32,12 @@ public:
32 } 32 }
33 33
34 template <typename T> 34 template <typename T>
35 PAddr GetRawPhysicalAddr(const T* ptr) const {
36 return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) -
37 reinterpret_cast<uintptr_t>(buffer.BackingBasePointer()));
38 }
39
40 template <typename T>
35 T* GetPointer(Common::PhysicalAddress addr) { 41 T* GetPointer(Common::PhysicalAddress addr) {
36 return reinterpret_cast<T*>(buffer.BackingBasePointer() + 42 return reinterpret_cast<T*>(buffer.BackingBasePointer() +
37 (GetInteger(addr) - DramMemoryMap::Base)); 43 (GetInteger(addr) - DramMemoryMap::Base));
@@ -43,6 +49,16 @@ public:
43 (GetInteger(addr) - DramMemoryMap::Base)); 49 (GetInteger(addr) - DramMemoryMap::Base));
44 } 50 }
45 51
52 template <typename T>
53 T* GetPointerFromRaw(PAddr addr) {
54 return reinterpret_cast<T*>(buffer.BackingBasePointer() + addr);
55 }
56
57 template <typename T>
58 const T* GetPointerFromRaw(PAddr addr) const {
59 return reinterpret_cast<T*>(buffer.BackingBasePointer() + addr);
60 }
61
46 Common::HostMemory buffer; 62 Common::HostMemory buffer;
47}; 63};
48 64
diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h
new file mode 100644
index 000000000..ffeed46cc
--- /dev/null
+++ b/src/core/device_memory_manager.h
@@ -0,0 +1,211 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <atomic>
8#include <deque>
9#include <memory>
10#include <mutex>
11
12#include "common/common_types.h"
13#include "common/scratch_buffer.h"
14#include "common/virtual_buffer.h"
15
16namespace Core {
17
18constexpr size_t DEVICE_PAGEBITS = 12ULL;
19constexpr size_t DEVICE_PAGESIZE = 1ULL << DEVICE_PAGEBITS;
20constexpr size_t DEVICE_PAGEMASK = DEVICE_PAGESIZE - 1ULL;
21
22class DeviceMemory;
23
24namespace Memory {
25class Memory;
26}
27
28template <typename DTraits>
29struct DeviceMemoryManagerAllocator;
30
31struct Asid {
32 size_t id;
33};
34
35template <typename Traits>
36class DeviceMemoryManager {
37 using DeviceInterface = typename Traits::DeviceInterface;
38 using DeviceMethods = typename Traits::DeviceMethods;
39
40public:
41 DeviceMemoryManager(const DeviceMemory& device_memory);
42 ~DeviceMemoryManager();
43
44 void BindInterface(DeviceInterface* device_inter);
45
46 DAddr Allocate(size_t size);
47 void AllocateFixed(DAddr start, size_t size);
48 void Free(DAddr start, size_t size);
49
50 void Map(DAddr address, VAddr virtual_address, size_t size, Asid asid, bool track = false);
51
52 void Unmap(DAddr address, size_t size);
53
54 void TrackContinuityImpl(DAddr address, VAddr virtual_address, size_t size, Asid asid);
55 void TrackContinuity(DAddr address, VAddr virtual_address, size_t size, Asid asid) {
56 std::scoped_lock lk(mapping_guard);
57 TrackContinuityImpl(address, virtual_address, size, asid);
58 }
59
60 // Write / Read
61 template <typename T>
62 T* GetPointer(DAddr address);
63
64 template <typename T>
65 const T* GetPointer(DAddr address) const;
66
67 template <typename Func>
68 void ApplyOpOnPAddr(PAddr address, Common::ScratchBuffer<u32>& buffer, Func&& operation) {
69 DAddr subbits = static_cast<DAddr>(address & page_mask);
70 const u32 base = compressed_device_addr[(address >> page_bits)];
71 if ((base >> MULTI_FLAG_BITS) == 0) [[likely]] {
72 const DAddr d_address = (static_cast<DAddr>(base) << page_bits) + subbits;
73 operation(d_address);
74 return;
75 }
76 InnerGatherDeviceAddresses(buffer, address);
77 for (u32 value : buffer) {
78 operation((static_cast<DAddr>(value) << page_bits) + subbits);
79 }
80 }
81
82 template <typename Func>
83 void ApplyOpOnPointer(const u8* p, Common::ScratchBuffer<u32>& buffer, Func&& operation) {
84 PAddr address = GetRawPhysicalAddr<u8>(p);
85 ApplyOpOnPAddr(address, buffer, operation);
86 }
87
88 PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const {
89 PAddr subbits = static_cast<PAddr>(address & page_mask);
90 auto paddr = compressed_physical_ptr[(address >> page_bits)];
91 if (paddr == 0) {
92 return 0;
93 }
94 return (static_cast<PAddr>(paddr - 1) << page_bits) + subbits;
95 }
96
97 template <typename T>
98 void Write(DAddr address, T value);
99
100 template <typename T>
101 T Read(DAddr address) const;
102
103 u8* GetSpan(const DAddr src_addr, const std::size_t size);
104 const u8* GetSpan(const DAddr src_addr, const std::size_t size) const;
105
106 void ReadBlock(DAddr address, void* dest_pointer, size_t size);
107 void ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size);
108 void WriteBlock(DAddr address, const void* src_pointer, size_t size);
109 void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size);
110
111 Asid RegisterProcess(Memory::Memory* memory);
112 void UnregisterProcess(Asid id);
113
114 void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta);
115
116 static constexpr size_t AS_BITS = Traits::device_virtual_bits;
117
118private:
119 static constexpr size_t device_virtual_bits = Traits::device_virtual_bits;
120 static constexpr size_t device_as_size = 1ULL << device_virtual_bits;
121 static constexpr size_t physical_min_bits = 32;
122 static constexpr size_t physical_max_bits = 33;
123 static constexpr size_t page_bits = 12;
124 static constexpr size_t page_size = 1ULL << page_bits;
125 static constexpr size_t page_mask = page_size - 1ULL;
126 static constexpr u32 physical_address_base = 1U << page_bits;
127 static constexpr u32 MULTI_FLAG_BITS = 31;
128 static constexpr u32 MULTI_FLAG = 1U << MULTI_FLAG_BITS;
129 static constexpr u32 MULTI_MASK = ~MULTI_FLAG;
130
131 template <typename T>
132 T* GetPointerFromRaw(PAddr addr) {
133 return reinterpret_cast<T*>(physical_base + addr);
134 }
135
136 template <typename T>
137 const T* GetPointerFromRaw(PAddr addr) const {
138 return reinterpret_cast<T*>(physical_base + addr);
139 }
140
141 template <typename T>
142 PAddr GetRawPhysicalAddr(const T* ptr) const {
143 return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) - physical_base);
144 }
145
146 void WalkBlock(const DAddr addr, const std::size_t size, auto on_unmapped, auto on_memory,
147 auto increment);
148
149 void InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer, PAddr address);
150
151 std::unique_ptr<DeviceMemoryManagerAllocator<Traits>> impl;
152
153 const uintptr_t physical_base;
154 DeviceInterface* device_inter;
155 Common::VirtualBuffer<u32> compressed_physical_ptr;
156 Common::VirtualBuffer<u32> compressed_device_addr;
157 Common::VirtualBuffer<u32> continuity_tracker;
158
159 // Process memory interfaces
160
161 std::deque<size_t> id_pool;
162 std::deque<Memory::Memory*> registered_processes;
163
164 // Memory protection management
165
166 static constexpr size_t guest_max_as_bits = 39;
167 static constexpr size_t guest_as_size = 1ULL << guest_max_as_bits;
168 static constexpr size_t guest_mask = guest_as_size - 1ULL;
169 static constexpr size_t asid_start_bit = guest_max_as_bits;
170
171 std::pair<Asid, VAddr> ExtractCPUBacking(size_t page_index) {
172 auto content = cpu_backing_address[page_index];
173 const VAddr address = content & guest_mask;
174 const Asid asid{static_cast<size_t>(content >> asid_start_bit)};
175 return std::make_pair(asid, address);
176 }
177
178 void InsertCPUBacking(size_t page_index, VAddr address, Asid asid) {
179 cpu_backing_address[page_index] = address | (asid.id << asid_start_bit);
180 }
181
182 Common::VirtualBuffer<VAddr> cpu_backing_address;
183 static constexpr size_t subentries = 8 / sizeof(u8);
184 static constexpr size_t subentries_mask = subentries - 1;
185 class CounterEntry final {
186 public:
187 CounterEntry() = default;
188
189 std::atomic_uint8_t& Count(std::size_t page) {
190 return values[page & subentries_mask];
191 }
192
193 const std::atomic_uint8_t& Count(std::size_t page) const {
194 return values[page & subentries_mask];
195 }
196
197 private:
198 std::array<std::atomic_uint8_t, subentries> values{};
199 };
200 static_assert(sizeof(CounterEntry) == subentries * sizeof(u8),
201 "CounterEntry should be 8 bytes!");
202
203 static constexpr size_t num_counter_entries =
204 (1ULL << (device_virtual_bits - page_bits)) / subentries;
205 using CachedPages = std::array<CounterEntry, num_counter_entries>;
206 std::unique_ptr<CachedPages> cached_pages;
207 std::mutex counter_guard;
208 std::mutex mapping_guard;
209};
210
211} // namespace Core
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
new file mode 100644
index 000000000..eab8a2731
--- /dev/null
+++ b/src/core/device_memory_manager.inc
@@ -0,0 +1,581 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <atomic>
5#include <limits>
6#include <memory>
7#include <type_traits>
8
9#include "common/address_space.h"
10#include "common/address_space.inc"
11#include "common/alignment.h"
12#include "common/assert.h"
13#include "common/div_ceil.h"
14#include "common/scope_exit.h"
15#include "common/settings.h"
16#include "core/device_memory.h"
17#include "core/device_memory_manager.h"
18#include "core/memory.h"
19
20namespace Core {
21
22namespace {
23
24class MultiAddressContainer {
25public:
26 MultiAddressContainer() = default;
27 ~MultiAddressContainer() = default;
28
29 void GatherValues(u32 start_entry, Common::ScratchBuffer<u32>& buffer) {
30 buffer.resize(8);
31 buffer.resize(0);
32 size_t index = 0;
33 const auto add_value = [&](u32 value) {
34 buffer.resize(index + 1);
35 buffer[index++] = value;
36 };
37
38 u32 iter_entry = start_entry;
39 Entry* current = &storage[iter_entry - 1];
40 add_value(current->value);
41 while (current->next_entry != 0) {
42 iter_entry = current->next_entry;
43 current = &storage[iter_entry - 1];
44 add_value(current->value);
45 }
46 }
47
48 u32 Register(u32 value) {
49 return RegisterImplementation(value);
50 }
51
52 void Register(u32 value, u32 start_entry) {
53 auto entry_id = RegisterImplementation(value);
54 u32 iter_entry = start_entry;
55 Entry* current = &storage[iter_entry - 1];
56 while (current->next_entry != 0) {
57 iter_entry = current->next_entry;
58 current = &storage[iter_entry - 1];
59 }
60 current->next_entry = entry_id;
61 }
62
63 std::pair<bool, u32> Unregister(u32 value, u32 start_entry) {
64 u32 iter_entry = start_entry;
65 Entry* previous{};
66 Entry* current = &storage[iter_entry - 1];
67 Entry* next{};
68 bool more_than_one_remaining = false;
69 u32 result_start{start_entry};
70 size_t count = 0;
71 while (current->value != value) {
72 count++;
73 previous = current;
74 iter_entry = current->next_entry;
75 current = &storage[iter_entry - 1];
76 }
77 // Find next
78 u32 next_entry = current->next_entry;
79 if (next_entry != 0) {
80 next = &storage[next_entry - 1];
81 more_than_one_remaining = next->next_entry != 0 || previous != nullptr;
82 }
83 if (previous) {
84 previous->next_entry = next_entry;
85 } else {
86 result_start = next_entry;
87 }
88 free_entries.emplace_back(iter_entry);
89 return std::make_pair(more_than_one_remaining || count > 1, result_start);
90 }
91
92 u32 ReleaseEntry(u32 start_entry) {
93 Entry* current = &storage[start_entry - 1];
94 free_entries.emplace_back(start_entry);
95 return current->value;
96 }
97
98private:
99 u32 RegisterImplementation(u32 value) {
100 auto entry_id = GetNewEntry();
101 auto& entry = storage[entry_id - 1];
102 entry.next_entry = 0;
103 entry.value = value;
104 return entry_id;
105 }
106 u32 GetNewEntry() {
107 if (!free_entries.empty()) {
108 u32 result = free_entries.front();
109 free_entries.pop_front();
110 return result;
111 }
112 storage.emplace_back();
113 u32 new_entry = static_cast<u32>(storage.size());
114 return new_entry;
115 }
116
117 struct Entry {
118 u32 next_entry{};
119 u32 value{};
120 };
121
122 std::deque<Entry> storage;
123 std::deque<u32> free_entries;
124};
125
126struct EmptyAllocator {
127 EmptyAllocator([[maybe_unused]] DAddr address) {}
128};
129
130} // namespace
131
132template <typename DTraits>
133struct DeviceMemoryManagerAllocator {
134 static constexpr size_t device_virtual_bits = DTraits::device_virtual_bits;
135 static constexpr DAddr first_address = 1ULL << Memory::YUZU_PAGEBITS;
136 static constexpr DAddr max_device_area = 1ULL << device_virtual_bits;
137
138 DeviceMemoryManagerAllocator() : main_allocator(first_address) {}
139
140 Common::FlatAllocator<DAddr, 0, device_virtual_bits> main_allocator;
141 MultiAddressContainer multi_dev_address;
142
143 /// Returns true when vaddr -> vaddr+size is fully contained in the buffer
144 template <bool pin_area>
145 [[nodiscard]] bool IsInBounds(VAddr addr, u64 size) const noexcept {
146 return addr >= 0 && addr + size <= max_device_area;
147 }
148
149 DAddr Allocate(size_t size) {
150 return main_allocator.Allocate(size);
151 }
152
153 void AllocateFixed(DAddr b_address, size_t b_size) {
154 main_allocator.AllocateFixed(b_address, b_size);
155 }
156
157 void Free(DAddr b_address, size_t b_size) {
158 main_allocator.Free(b_address, b_size);
159 }
160};
161
162template <typename Traits>
163DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
164 : physical_base{reinterpret_cast<const uintptr_t>(device_memory_.buffer.BackingBasePointer())},
165 device_inter{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS),
166 compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() ==
167 Settings::MemoryLayout::Memory_4Gb
168 ? physical_min_bits
169 : physical_max_bits) -
170 Memory::YUZU_PAGEBITS)),
171 continuity_tracker(device_as_size >> Memory::YUZU_PAGEBITS),
172 cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) {
173 impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
174 cached_pages = std::make_unique<CachedPages>();
175
176 const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS;
177 for (size_t i = 0; i < total_virtual; i++) {
178 compressed_physical_ptr[i] = 0;
179 continuity_tracker[i] = 1;
180 cpu_backing_address[i] = 0;
181 }
182 const size_t total_phys = 1ULL << ((Settings::values.memory_layout_mode.GetValue() ==
183 Settings::MemoryLayout::Memory_4Gb
184 ? physical_min_bits
185 : physical_max_bits) -
186 Memory::YUZU_PAGEBITS);
187 for (size_t i = 0; i < total_phys; i++) {
188 compressed_device_addr[i] = 0;
189 }
190}
191
192template <typename Traits>
193DeviceMemoryManager<Traits>::~DeviceMemoryManager() = default;
194
195template <typename Traits>
196void DeviceMemoryManager<Traits>::BindInterface(DeviceInterface* device_inter_) {
197 device_inter = device_inter_;
198}
199
200template <typename Traits>
201DAddr DeviceMemoryManager<Traits>::Allocate(size_t size) {
202 return impl->Allocate(size);
203}
204
205template <typename Traits>
206void DeviceMemoryManager<Traits>::AllocateFixed(DAddr start, size_t size) {
207 return impl->AllocateFixed(start, size);
208}
209
210template <typename Traits>
211void DeviceMemoryManager<Traits>::Free(DAddr start, size_t size) {
212 impl->Free(start, size);
213}
214
215template <typename Traits>
216void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size,
217 Asid asid, bool track) {
218 Core::Memory::Memory* process_memory = registered_processes[asid.id];
219 size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
220 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
221 std::scoped_lock lk(mapping_guard);
222 for (size_t i = 0; i < num_pages; i++) {
223 const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE;
224 auto* ptr = process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress));
225 if (ptr == nullptr) [[unlikely]] {
226 compressed_physical_ptr[start_page_d + i] = 0;
227 continue;
228 }
229 auto phys_addr = static_cast<u32>(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U;
230 compressed_physical_ptr[start_page_d + i] = phys_addr;
231 InsertCPUBacking(start_page_d + i, new_vaddress, asid);
232 const u32 base_dev = compressed_device_addr[phys_addr - 1U];
233 const u32 new_dev = static_cast<u32>(start_page_d + i);
234 if (base_dev == 0) [[likely]] {
235 compressed_device_addr[phys_addr - 1U] = new_dev;
236 continue;
237 }
238 u32 start_id = base_dev & MULTI_MASK;
239 if ((base_dev >> MULTI_FLAG_BITS) == 0) {
240 start_id = impl->multi_dev_address.Register(base_dev);
241 compressed_device_addr[phys_addr - 1U] = MULTI_FLAG | start_id;
242 }
243 impl->multi_dev_address.Register(new_dev, start_id);
244 }
245 if (track) {
246 TrackContinuityImpl(address, virtual_address, size, asid);
247 }
248}
249
250template <typename Traits>
251void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
252 size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
253 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
254 device_inter->InvalidateRegion(address, size);
255 std::scoped_lock lk(mapping_guard);
256 for (size_t i = 0; i < num_pages; i++) {
257 auto phys_addr = compressed_physical_ptr[start_page_d + i];
258 compressed_physical_ptr[start_page_d + i] = 0;
259 cpu_backing_address[start_page_d + i] = 0;
260 if (phys_addr != 0) [[likely]] {
261 const u32 base_dev = compressed_device_addr[phys_addr - 1U];
262 if ((base_dev >> MULTI_FLAG_BITS) == 0) [[likely]] {
263 compressed_device_addr[phys_addr - 1] = 0;
264 continue;
265 }
266 const auto [more_entries, new_start] = impl->multi_dev_address.Unregister(
267 static_cast<u32>(start_page_d + i), base_dev & MULTI_MASK);
268 if (!more_entries) {
269 compressed_device_addr[phys_addr - 1] =
270 impl->multi_dev_address.ReleaseEntry(new_start);
271 continue;
272 }
273 compressed_device_addr[phys_addr - 1] = new_start | MULTI_FLAG;
274 }
275 }
276}
277template <typename Traits>
278void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
279 size_t size, Asid asid) {
280 Core::Memory::Memory* process_memory = registered_processes[asid.id];
281 size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
282 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
283 uintptr_t last_ptr = 0;
284 size_t page_count = 1;
285 for (size_t i = num_pages; i > 0; i--) {
286 size_t index = i - 1;
287 const VAddr new_vaddress = virtual_address + index * Memory::YUZU_PAGESIZE;
288 const uintptr_t new_ptr = reinterpret_cast<uintptr_t>(
289 process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress)));
290 if (new_ptr + page_size == last_ptr) {
291 page_count++;
292 } else {
293 page_count = 1;
294 }
295 last_ptr = new_ptr;
296 continuity_tracker[start_page_d + index] = static_cast<u32>(page_count);
297 }
298}
299template <typename Traits>
300u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::size_t size) {
301 size_t page_index = src_addr >> page_bits;
302 size_t subbits = src_addr & page_mask;
303 if ((static_cast<size_t>(continuity_tracker[page_index]) << page_bits) >= size + subbits) {
304 return GetPointer<u8>(src_addr);
305 }
306 return nullptr;
307}
308
309template <typename Traits>
310const u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::size_t size) const {
311 size_t page_index = src_addr >> page_bits;
312 size_t subbits = src_addr & page_mask;
313 if ((static_cast<size_t>(continuity_tracker[page_index]) << page_bits) >= size + subbits) {
314 return GetPointer<u8>(src_addr);
315 }
316 return nullptr;
317}
318
319template <typename Traits>
320void DeviceMemoryManager<Traits>::InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer,
321 PAddr address) {
322 size_t phys_addr = address >> page_bits;
323 std::scoped_lock lk(mapping_guard);
324 u32 backing = compressed_device_addr[phys_addr];
325 if ((backing >> MULTI_FLAG_BITS) != 0) {
326 impl->multi_dev_address.GatherValues(backing & MULTI_MASK, buffer);
327 return;
328 }
329 buffer.resize(1);
330 buffer[0] = backing;
331}
332
333template <typename Traits>
334template <typename T>
335T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) {
336 const size_t index = address >> Memory::YUZU_PAGEBITS;
337 const size_t offset = address & Memory::YUZU_PAGEMASK;
338 auto phys_addr = compressed_physical_ptr[index];
339 if (phys_addr == 0) [[unlikely]] {
340 return nullptr;
341 }
342 return GetPointerFromRaw<T>((static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) +
343 offset);
344}
345
346template <typename Traits>
347template <typename T>
348const T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) const {
349 const size_t index = address >> Memory::YUZU_PAGEBITS;
350 const size_t offset = address & Memory::YUZU_PAGEMASK;
351 auto phys_addr = compressed_physical_ptr[index];
352 if (phys_addr == 0) [[unlikely]] {
353 return nullptr;
354 }
355 return GetPointerFromRaw<T>((static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) +
356 offset);
357}
358
359template <typename Traits>
360template <typename T>
361void DeviceMemoryManager<Traits>::Write(DAddr address, T value) {
362 T* ptr = GetPointer<T>(address);
363 if (!ptr) [[unlikely]] {
364 return;
365 }
366 std::memcpy(ptr, &value, sizeof(T));
367}
368
369template <typename Traits>
370template <typename T>
371T DeviceMemoryManager<Traits>::Read(DAddr address) const {
372 const T* ptr = GetPointer<T>(address);
373 T result{};
374 if (!ptr) [[unlikely]] {
375 return result;
376 }
377 std::memcpy(&result, ptr, sizeof(T));
378 return result;
379}
380
381template <typename Traits>
382void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto on_unmapped,
383 auto on_memory, auto increment) {
384 std::size_t remaining_size = size;
385 std::size_t page_index = addr >> Memory::YUZU_PAGEBITS;
386 std::size_t page_offset = addr & Memory::YUZU_PAGEMASK;
387
388 while (remaining_size) {
389 const size_t next_pages = static_cast<std::size_t>(continuity_tracker[page_index]);
390 const std::size_t copy_amount =
391 std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
392 const auto current_vaddr =
393 static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
394 SCOPE_EXIT({
395 page_index += next_pages;
396 page_offset = 0;
397 increment(copy_amount);
398 remaining_size -= copy_amount;
399 });
400
401 auto phys_addr = compressed_physical_ptr[page_index];
402 if (phys_addr == 0) {
403 on_unmapped(copy_amount, current_vaddr);
404 continue;
405 }
406 auto* mem_ptr = GetPointerFromRaw<u8>(
407 (static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset);
408 on_memory(copy_amount, mem_ptr);
409 }
410}
411
412template <typename Traits>
413void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, size_t size) {
414 device_inter->FlushRegion(address, size);
415 WalkBlock(
416 address, size,
417 [&](size_t copy_amount, DAddr current_vaddr) {
418 LOG_ERROR(
419 HW_Memory,
420 "Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
421 current_vaddr, address, size);
422 std::memset(dest_pointer, 0, copy_amount);
423 },
424 [&](size_t copy_amount, const u8* const src_ptr) {
425 std::memcpy(dest_pointer, src_ptr, copy_amount);
426 },
427 [&](const std::size_t copy_amount) {
428 dest_pointer = static_cast<u8*>(dest_pointer) + copy_amount;
429 });
430}
431
432template <typename Traits>
433void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, const void* src_pointer, size_t size) {
434 WalkBlock(
435 address, size,
436 [&](size_t copy_amount, DAddr current_vaddr) {
437 LOG_ERROR(
438 HW_Memory,
439 "Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
440 current_vaddr, address, size);
441 },
442 [&](size_t copy_amount, u8* const dst_ptr) {
443 std::memcpy(dst_ptr, src_pointer, copy_amount);
444 },
445 [&](const std::size_t copy_amount) {
446 src_pointer = static_cast<const u8*>(src_pointer) + copy_amount;
447 });
448 device_inter->InvalidateRegion(address, size);
449}
450
451template <typename Traits>
452void DeviceMemoryManager<Traits>::ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size) {
453 WalkBlock(
454 address, size,
455 [&](size_t copy_amount, DAddr current_vaddr) {
456 LOG_ERROR(
457 HW_Memory,
458 "Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
459 current_vaddr, address, size);
460 std::memset(dest_pointer, 0, copy_amount);
461 },
462 [&](size_t copy_amount, const u8* const src_ptr) {
463 std::memcpy(dest_pointer, src_ptr, copy_amount);
464 },
465 [&](const std::size_t copy_amount) {
466 dest_pointer = static_cast<u8*>(dest_pointer) + copy_amount;
467 });
468}
469
470template <typename Traits>
471void DeviceMemoryManager<Traits>::WriteBlockUnsafe(DAddr address, const void* src_pointer,
472 size_t size) {
473 WalkBlock(
474 address, size,
475 [&](size_t copy_amount, DAddr current_vaddr) {
476 LOG_ERROR(
477 HW_Memory,
478 "Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
479 current_vaddr, address, size);
480 },
481 [&](size_t copy_amount, u8* const dst_ptr) {
482 std::memcpy(dst_ptr, src_pointer, copy_amount);
483 },
484 [&](const std::size_t copy_amount) {
485 src_pointer = static_cast<const u8*>(src_pointer) + copy_amount;
486 });
487}
488
489template <typename Traits>
490Asid DeviceMemoryManager<Traits>::RegisterProcess(Memory::Memory* memory_device_inter) {
491 size_t new_id{};
492 if (!id_pool.empty()) {
493 new_id = id_pool.front();
494 id_pool.pop_front();
495 registered_processes[new_id] = memory_device_inter;
496 } else {
497 registered_processes.emplace_back(memory_device_inter);
498 new_id = registered_processes.size() - 1U;
499 }
500 return Asid{new_id};
501}
502
503template <typename Traits>
504void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) {
505 registered_processes[asid.id] = nullptr;
506 id_pool.push_front(asid.id);
507}
508
509template <typename Traits>
510void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
511 std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock);
512 const auto Lock = [&] {
513 if (!lk) {
514 lk.lock();
515 }
516 };
517 u64 uncache_begin = 0;
518 u64 cache_begin = 0;
519 u64 uncache_bytes = 0;
520 u64 cache_bytes = 0;
521 const auto MarkRegionCaching = &DeviceMemoryManager<Traits>::DeviceMethods::MarkRegionCaching;
522
523 std::atomic_thread_fence(std::memory_order_acquire);
524 const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
525 size_t page = addr >> Memory::YUZU_PAGEBITS;
526 auto [asid, base_vaddress] = ExtractCPUBacking(page);
527 size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS;
528 auto* memory_device_inter = registered_processes[asid.id];
529 for (; page != page_end; ++page) {
530 std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page);
531
532 if (delta > 0) {
533 ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits<u8>::max(),
534 "Count may overflow!");
535 } else if (delta < 0) {
536 ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
537 } else {
538 ASSERT_MSG(false, "Delta must be non-zero!");
539 }
540
541 // Adds or subtracts 1, as count is a unsigned 8-bit value
542 count.fetch_add(static_cast<u8>(delta), std::memory_order_release);
543
544 // Assume delta is either -1 or 1
545 if (count.load(std::memory_order::relaxed) == 0) {
546 if (uncache_bytes == 0) {
547 uncache_begin = vpage;
548 }
549 uncache_bytes += Memory::YUZU_PAGESIZE;
550 } else if (uncache_bytes > 0) {
551 Lock();
552 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
553 uncache_bytes, false);
554 uncache_bytes = 0;
555 }
556 if (count.load(std::memory_order::relaxed) == 1 && delta > 0) {
557 if (cache_bytes == 0) {
558 cache_begin = vpage;
559 }
560 cache_bytes += Memory::YUZU_PAGESIZE;
561 } else if (cache_bytes > 0) {
562 Lock();
563 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
564 true);
565 cache_bytes = 0;
566 }
567 vpage++;
568 }
569 if (uncache_bytes > 0) {
570 Lock();
571 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
572 false);
573 }
574 if (cache_bytes > 0) {
575 Lock();
576 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
577 true);
578 }
579}
580
581} // namespace Core
diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp
index 6abac793b..b53eef877 100644
--- a/src/core/file_sys/system_archive/system_archive.cpp
+++ b/src/core/file_sys/system_archive/system_archive.cpp
@@ -67,25 +67,29 @@ constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHI
67}}; 67}};
68 68
69VirtualFile SynthesizeSystemArchive(const u64 title_id) { 69VirtualFile SynthesizeSystemArchive(const u64 title_id) {
70 if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) 70 if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) {
71 return nullptr; 71 return nullptr;
72 }
72 73
73 const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID]; 74 const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID];
74 75
75 LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id); 76 LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id);
76 77
77 if (desc.supplier == nullptr) 78 if (desc.supplier == nullptr) {
78 return nullptr; 79 return nullptr;
80 }
79 81
80 const auto dir = desc.supplier(); 82 const auto dir = desc.supplier();
81 83
82 if (dir == nullptr) 84 if (dir == nullptr) {
83 return nullptr; 85 return nullptr;
86 }
84 87
85 const auto romfs = CreateRomFS(dir); 88 const auto romfs = CreateRomFS(dir);
86 89
87 if (romfs == nullptr) 90 if (romfs == nullptr) {
88 return nullptr; 91 return nullptr;
92 }
89 93
90 LOG_INFO(Service_FS, " - System archive generation successful!"); 94 LOG_INFO(Service_FS, " - System archive generation successful!");
91 return romfs; 95 return romfs;
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp
index 7c17bbefa..d4d2eae76 100644
--- a/src/core/file_sys/system_archive/time_zone_binary.cpp
+++ b/src/core/file_sys/system_archive/time_zone_binary.cpp
@@ -6,7 +6,6 @@
6#include "common/swap.h" 6#include "common/swap.h"
7#include "core/file_sys/system_archive/time_zone_binary.h" 7#include "core/file_sys/system_archive/time_zone_binary.h"
8#include "core/file_sys/vfs_vector.h" 8#include "core/file_sys/vfs_vector.h"
9#include "core/hle/service/time/time_zone_types.h"
10 9
11#include "nx_tzdb.h" 10#include "nx_tzdb.h"
12 11
diff --git a/src/core/gpu_dirty_memory_manager.h b/src/core/gpu_dirty_memory_manager.h
index 9687531e8..cc8fc176f 100644
--- a/src/core/gpu_dirty_memory_manager.h
+++ b/src/core/gpu_dirty_memory_manager.h
@@ -10,7 +10,7 @@
10#include <utility> 10#include <utility>
11#include <vector> 11#include <vector>
12 12
13#include "core/memory.h" 13#include "core/device_memory_manager.h"
14 14
15namespace Core { 15namespace Core {
16 16
@@ -23,7 +23,7 @@ public:
23 23
24 ~GPUDirtyMemoryManager() = default; 24 ~GPUDirtyMemoryManager() = default;
25 25
26 void Collect(VAddr address, size_t size) { 26 void Collect(PAddr address, size_t size) {
27 TransformAddress t = BuildTransform(address, size); 27 TransformAddress t = BuildTransform(address, size);
28 TransformAddress tmp, original; 28 TransformAddress tmp, original;
29 do { 29 do {
@@ -47,7 +47,7 @@ public:
47 std::memory_order_relaxed)); 47 std::memory_order_relaxed));
48 } 48 }
49 49
50 void Gather(std::function<void(VAddr, size_t)>& callback) { 50 void Gather(std::function<void(PAddr, size_t)>& callback) {
51 { 51 {
52 std::scoped_lock lk(guard); 52 std::scoped_lock lk(guard);
53 TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed); 53 TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed);
@@ -65,7 +65,7 @@ public:
65 mask = mask >> empty_bits; 65 mask = mask >> empty_bits;
66 66
67 const size_t continuous_bits = std::countr_one(mask); 67 const size_t continuous_bits = std::countr_one(mask);
68 callback((static_cast<VAddr>(transform.address) << page_bits) + offset, 68 callback((static_cast<PAddr>(transform.address) << page_bits) + offset,
69 continuous_bits << align_bits); 69 continuous_bits << align_bits);
70 mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0; 70 mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0;
71 offset += continuous_bits << align_bits; 71 offset += continuous_bits << align_bits;
@@ -80,7 +80,7 @@ private:
80 u32 mask; 80 u32 mask;
81 }; 81 };
82 82
83 constexpr static size_t page_bits = Memory::YUZU_PAGEBITS - 1; 83 constexpr static size_t page_bits = DEVICE_PAGEBITS - 1;
84 constexpr static size_t page_size = 1ULL << page_bits; 84 constexpr static size_t page_size = 1ULL << page_bits;
85 constexpr static size_t page_mask = page_size - 1; 85 constexpr static size_t page_mask = page_size - 1;
86 86
@@ -89,7 +89,7 @@ private:
89 constexpr static size_t align_mask = align_size - 1; 89 constexpr static size_t align_mask = align_size - 1;
90 constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U}; 90 constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U};
91 91
92 bool IsValid(VAddr address) { 92 bool IsValid(PAddr address) {
93 return address < (1ULL << 39); 93 return address < (1ULL << 39);
94 } 94 }
95 95
@@ -103,7 +103,7 @@ private:
103 return mask; 103 return mask;
104 } 104 }
105 105
106 TransformAddress BuildTransform(VAddr address, size_t size) { 106 TransformAddress BuildTransform(PAddr address, size_t size) {
107 const size_t minor_address = address & page_mask; 107 const size_t minor_address = address & page_mask;
108 const size_t minor_bit = minor_address >> align_bits; 108 const size_t minor_bit = minor_address >> align_bits;
109 const size_t top_bit = (minor_address + size + align_mask) >> align_bits; 109 const size_t top_bit = (minor_address + size + align_mask) >> align_bits;
diff --git a/src/core/guest_memory.h b/src/core/guest_memory.h
new file mode 100644
index 000000000..7ee18c126
--- /dev/null
+++ b/src/core/guest_memory.h
@@ -0,0 +1,214 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <iterator>
7#include <memory>
8#include <optional>
9#include <span>
10#include <vector>
11
12#include "common/assert.h"
13#include "common/scratch_buffer.h"
14
15namespace Core::Memory {
16
17enum GuestMemoryFlags : u32 {
18 Read = 1 << 0,
19 Write = 1 << 1,
20 Safe = 1 << 2,
21 Cached = 1 << 3,
22
23 SafeRead = Read | Safe,
24 SafeWrite = Write | Safe,
25 SafeReadWrite = SafeRead | SafeWrite,
26 SafeReadCachedWrite = SafeReadWrite | Cached,
27
28 UnsafeRead = Read,
29 UnsafeWrite = Write,
30 UnsafeReadWrite = UnsafeRead | UnsafeWrite,
31 UnsafeReadCachedWrite = UnsafeReadWrite | Cached,
32};
33
34namespace {
35template <typename M, typename T, GuestMemoryFlags FLAGS>
36class GuestMemory {
37 using iterator = T*;
38 using const_iterator = const T*;
39 using value_type = T;
40 using element_type = T;
41 using iterator_category = std::contiguous_iterator_tag;
42
43public:
44 GuestMemory() = delete;
45 explicit GuestMemory(M& memory, u64 addr, std::size_t size,
46 Common::ScratchBuffer<T>* backup = nullptr)
47 : m_memory{memory}, m_addr{addr}, m_size{size} {
48 static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
49 if constexpr (FLAGS & GuestMemoryFlags::Read) {
50 Read(addr, size, backup);
51 }
52 }
53
54 ~GuestMemory() = default;
55
56 T* data() noexcept {
57 return m_data_span.data();
58 }
59
60 const T* data() const noexcept {
61 return m_data_span.data();
62 }
63
64 size_t size() const noexcept {
65 return m_size;
66 }
67
68 size_t size_bytes() const noexcept {
69 return this->size() * sizeof(T);
70 }
71
72 [[nodiscard]] T* begin() noexcept {
73 return this->data();
74 }
75
76 [[nodiscard]] const T* begin() const noexcept {
77 return this->data();
78 }
79
80 [[nodiscard]] T* end() noexcept {
81 return this->data() + this->size();
82 }
83
84 [[nodiscard]] const T* end() const noexcept {
85 return this->data() + this->size();
86 }
87
88 T& operator[](size_t index) noexcept {
89 return m_data_span[index];
90 }
91
92 const T& operator[](size_t index) const noexcept {
93 return m_data_span[index];
94 }
95
96 void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
97 m_addr = addr;
98 m_size = size;
99 m_addr_changed = true;
100 }
101
102 std::span<T> Read(u64 addr, std::size_t size,
103 Common::ScratchBuffer<T>* backup = nullptr) noexcept {
104 m_addr = addr;
105 m_size = size;
106 if (m_size == 0) {
107 m_is_data_copy = true;
108 return {};
109 }
110
111 if (this->TrySetSpan()) {
112 if constexpr (FLAGS & GuestMemoryFlags::Safe) {
113 m_memory.FlushRegion(m_addr, this->size_bytes());
114 }
115 } else {
116 if (backup) {
117 backup->resize_destructive(this->size());
118 m_data_span = *backup;
119 } else {
120 m_data_copy.resize(this->size());
121 m_data_span = std::span(m_data_copy);
122 }
123 m_is_data_copy = true;
124 m_span_valid = true;
125 if constexpr (FLAGS & GuestMemoryFlags::Safe) {
126 m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
127 } else {
128 m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
129 }
130 }
131 return m_data_span;
132 }
133
134 void Write(std::span<T> write_data) noexcept {
135 if constexpr (FLAGS & GuestMemoryFlags::Cached) {
136 m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
137 } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
138 m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
139 } else {
140 m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
141 }
142 }
143
144 bool TrySetSpan() noexcept {
145 if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
146 m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
147 m_span_valid = true;
148 return true;
149 }
150 return false;
151 }
152
153protected:
154 bool IsDataCopy() const noexcept {
155 return m_is_data_copy;
156 }
157
158 bool AddressChanged() const noexcept {
159 return m_addr_changed;
160 }
161
162 M& m_memory;
163 u64 m_addr{};
164 size_t m_size{};
165 std::span<T> m_data_span{};
166 std::vector<T> m_data_copy{};
167 bool m_span_valid{false};
168 bool m_is_data_copy{false};
169 bool m_addr_changed{false};
170};
171
172template <typename M, typename T, GuestMemoryFlags FLAGS>
173class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
174public:
175 GuestMemoryScoped() = delete;
176 explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
177 Common::ScratchBuffer<T>* backup = nullptr)
178 : GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
179 if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
180 if (!this->TrySetSpan()) {
181 if (backup) {
182 this->m_data_span = *backup;
183 this->m_span_valid = true;
184 this->m_is_data_copy = true;
185 }
186 }
187 }
188 }
189
190 ~GuestMemoryScoped() {
191 if constexpr (FLAGS & GuestMemoryFlags::Write) {
192 if (this->size() == 0) [[unlikely]] {
193 return;
194 }
195
196 if (this->AddressChanged() || this->IsDataCopy()) {
197 ASSERT(this->m_span_valid);
198 if constexpr (FLAGS & GuestMemoryFlags::Cached) {
199 this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
200 } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
201 this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
202 } else {
203 this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
204 }
205 } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
206 (FLAGS & GuestMemoryFlags::Cached)) {
207 this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
208 }
209 }
210 }
211};
212} // namespace
213
214} // namespace Core::Memory
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 53735a225..0b08e877e 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -5,6 +5,7 @@
5#include "common/scope_exit.h" 5#include "common/scope_exit.h"
6#include "common/settings.h" 6#include "common/settings.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/gpu_dirty_memory_manager.h"
8#include "core/hle/kernel/k_process.h" 9#include "core/hle/kernel/k_process.h"
9#include "core/hle/kernel/k_scoped_resource_reservation.h" 10#include "core/hle/kernel/k_scoped_resource_reservation.h"
10#include "core/hle/kernel/k_shared_memory.h" 11#include "core/hle/kernel/k_shared_memory.h"
@@ -320,7 +321,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
320 321
321 // Ensure our memory is initialized. 322 // Ensure our memory is initialized.
322 m_memory.SetCurrentPageTable(*this); 323 m_memory.SetCurrentPageTable(*this);
323 m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); 324 m_memory.SetGPUDirtyManagers(m_kernel.System().GetGPUDirtyMemoryManager());
324 325
325 // Ensure we can insert the code region. 326 // Ensure we can insert the code region.
326 R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, 327 R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize,
@@ -417,7 +418,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
417 418
418 // Ensure our memory is initialized. 419 // Ensure our memory is initialized.
419 m_memory.SetCurrentPageTable(*this); 420 m_memory.SetCurrentPageTable(*this);
420 m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); 421 m_memory.SetGPUDirtyManagers(m_kernel.System().GetGPUDirtyMemoryManager());
421 422
422 // Ensure we can insert the code region. 423 // Ensure we can insert the code region.
423 R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), 424 R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code),
@@ -1141,8 +1142,7 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {}
1141KProcess::KProcess(KernelCore& kernel) 1142KProcess::KProcess(KernelCore& kernel)
1142 : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, 1143 : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel},
1143 m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, 1144 m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()},
1144 m_handle_table{kernel}, m_dirty_memory_managers{}, 1145 m_handle_table{kernel}, m_exclusive_monitor{}, m_memory{kernel.System()} {}
1145 m_exclusive_monitor{}, m_memory{kernel.System()} {}
1146KProcess::~KProcess() = default; 1146KProcess::~KProcess() = default;
1147 1147
1148Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, 1148Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
@@ -1324,10 +1324,4 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT
1324 return true; 1324 return true;
1325} 1325}
1326 1326
1327void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
1328 for (auto& manager : m_dirty_memory_managers) {
1329 manager.Gather(callback);
1330 }
1331}
1332
1333} // namespace Kernel 1327} // namespace Kernel
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 53c0e3316..ab1358a12 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -7,7 +7,6 @@
7 7
8#include "core/arm/arm_interface.h" 8#include "core/arm/arm_interface.h"
9#include "core/file_sys/program_metadata.h" 9#include "core/file_sys/program_metadata.h"
10#include "core/gpu_dirty_memory_manager.h"
11#include "core/hle/kernel/code_set.h" 10#include "core/hle/kernel/code_set.h"
12#include "core/hle/kernel/k_address_arbiter.h" 11#include "core/hle/kernel/k_address_arbiter.h"
13#include "core/hle/kernel/k_capabilities.h" 12#include "core/hle/kernel/k_capabilities.h"
@@ -128,7 +127,6 @@ private:
128#ifdef HAS_NCE 127#ifdef HAS_NCE
129 std::unordered_map<u64, u64> m_post_handlers{}; 128 std::unordered_map<u64, u64> m_post_handlers{};
130#endif 129#endif
131 std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers;
132 std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor; 130 std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor;
133 Core::Memory::Memory m_memory; 131 Core::Memory::Memory m_memory;
134 132
@@ -511,8 +509,6 @@ public:
511 return m_memory; 509 return m_memory;
512 } 510 }
513 511
514 void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
515
516 Core::ExclusiveMonitor& GetExclusiveMonitor() const { 512 Core::ExclusiveMonitor& GetExclusiveMonitor() const {
517 return *m_exclusive_monitor; 513 return *m_exclusive_monitor;
518 } 514 }
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp
index 261fc204c..e3b8ecf3e 100644
--- a/src/core/hle/service/caps/caps_manager.cpp
+++ b/src/core/hle/service/caps/caps_manager.cpp
@@ -10,8 +10,10 @@
10#include "core/core.h" 10#include "core/core.h"
11#include "core/hle/service/caps/caps_manager.h" 11#include "core/hle/service/caps/caps_manager.h"
12#include "core/hle/service/caps/caps_result.h" 12#include "core/hle/service/caps/caps_result.h"
13#include "core/hle/service/time/time_manager.h" 13#include "core/hle/service/glue/time/static.h"
14#include "core/hle/service/time/time_zone_content_manager.h" 14#include "core/hle/service/psc/time/system_clock.h"
15#include "core/hle/service/service.h"
16#include "core/hle/service/sm/sm.h"
15 17
16namespace Service::Capture { 18namespace Service::Capture {
17 19
@@ -239,10 +241,15 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
239 const ApplicationData& app_data, std::span<const u8> image_data, 241 const ApplicationData& app_data, std::span<const u8> image_data,
240 u64 aruid) { 242 u64 aruid) {
241 const u64 title_id = system.GetApplicationProcessProgramID(); 243 const u64 title_id = system.GetApplicationProcessProgramID();
242 const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); 244
245 auto static_service =
246 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
247
248 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{};
249 static_service->GetStandardUserSystemClock(user_clock);
243 250
244 s64 posix_time{}; 251 s64 posix_time{};
245 Result result = user_clock.GetCurrentTime(system, posix_time); 252 auto result = user_clock->GetCurrentTime(posix_time);
246 253
247 if (result.IsError()) { 254 if (result.IsError()) {
248 return result; 255 return result;
@@ -257,10 +264,14 @@ Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
257 const ScreenShotAttribute& attribute, 264 const ScreenShotAttribute& attribute,
258 const AlbumFileId& file_id, 265 const AlbumFileId& file_id,
259 std::span<const u8> image_data) { 266 std::span<const u8> image_data) {
260 const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); 267 auto static_service =
268 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
269
270 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{};
271 static_service->GetStandardUserSystemClock(user_clock);
261 272
262 s64 posix_time{}; 273 s64 posix_time{};
263 Result result = user_clock.GetCurrentTime(system, posix_time); 274 auto result = user_clock->GetCurrentTime(posix_time);
264 275
265 if (result.IsError()) { 276 if (result.IsError()) {
266 return result; 277 return result;
@@ -455,19 +466,23 @@ Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const
455} 466}
456 467
457AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { 468AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
458 Time::TimeZone::CalendarInfo calendar_date{}; 469 auto static_service =
459 const auto& time_zone_manager = 470 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
460 system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); 471
472 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{};
473 static_service->GetTimeZoneService(timezone_service);
461 474
462 time_zone_manager.ToCalendarTimeWithMyRules(posix_time, calendar_date); 475 Service::PSC::Time::CalendarTime calendar_time{};
476 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
477 timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time);
463 478
464 return { 479 return {
465 .year = calendar_date.time.year, 480 .year = calendar_time.year,
466 .month = calendar_date.time.month, 481 .month = calendar_time.month,
467 .day = calendar_date.time.day, 482 .day = calendar_time.day,
468 .hour = calendar_date.time.hour, 483 .hour = calendar_time.hour,
469 .minute = calendar_date.time.minute, 484 .minute = calendar_time.minute,
470 .second = calendar_date.time.second, 485 .second = calendar_time.second,
471 .unique_id = 0, 486 .unique_id = 0,
472 }; 487 };
473} 488}
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
new file mode 100644
index 000000000..8e8cf2507
--- /dev/null
+++ b/src/core/hle/service/cmif_serialization.h
@@ -0,0 +1,337 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/div_ceil.h"
7
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/service.h"
11
12namespace Service {
13
14// clang-format off
15struct RequestLayout {
16 u32 copy_handle_count;
17 u32 move_handle_count;
18 u32 cmif_raw_data_size;
19 u32 domain_interface_count;
20};
21
22template <ArgumentType Type1, ArgumentType Type2, typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0>
23constexpr u32 GetArgumentRawDataSize() {
24 if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) {
25 return static_cast<u32>(DataOffset);
26 } else {
27 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
28
29 if constexpr (ArgumentTraits<ArgType>::Type == Type1 || ArgumentTraits<ArgType>::Type == Type2) {
30 constexpr size_t ArgAlign = alignof(ArgType);
31 constexpr size_t ArgSize = sizeof(ArgType);
32
33 static_assert(PrevAlign <= ArgAlign, "Input argument is not ordered by alignment");
34
35 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
36 constexpr size_t ArgEnd = ArgOffset + ArgSize;
37
38 return GetArgumentRawDataSize<Type1, Type2, MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>();
39 } else {
40 return GetArgumentRawDataSize<Type1, Type2, MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>();
41 }
42 }
43}
44
45template <ArgumentType DataType, typename MethodArguments, size_t ArgCount = 0, size_t ArgIndex = 0>
46constexpr u32 GetArgumentTypeCount() {
47 if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) {
48 return static_cast<u32>(ArgCount);
49 } else {
50 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
51
52 if constexpr (ArgumentTraits<ArgType>::Type == DataType) {
53 return GetArgumentTypeCount<DataType, MethodArguments, ArgCount + 1, ArgIndex + 1>();
54 } else {
55 return GetArgumentTypeCount<DataType, MethodArguments, ArgCount, ArgIndex + 1>();
56 }
57 }
58}
59
60template <typename MethodArguments>
61constexpr RequestLayout GetNonDomainReplyInLayout() {
62 return RequestLayout{
63 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(),
64 .move_handle_count = 0,
65 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(),
66 .domain_interface_count = 0,
67 };
68}
69
70template <typename MethodArguments>
71constexpr RequestLayout GetDomainReplyInLayout() {
72 return RequestLayout{
73 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(),
74 .move_handle_count = 0,
75 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(),
76 .domain_interface_count = GetArgumentTypeCount<ArgumentType::InInterface, MethodArguments>(),
77 };
78}
79
80template <typename MethodArguments>
81constexpr RequestLayout GetNonDomainReplyOutLayout() {
82 return RequestLayout{
83 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(),
84 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>() + GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(),
85 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(),
86 .domain_interface_count = 0,
87 };
88}
89
90template <typename MethodArguments>
91constexpr RequestLayout GetDomainReplyOutLayout() {
92 return RequestLayout{
93 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(),
94 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>(),
95 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(),
96 .domain_interface_count = GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(),
97 };
98}
99
100template <bool Domain, typename MethodArguments>
101constexpr RequestLayout GetReplyInLayout() {
102 return Domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>();
103}
104
105template <bool Domain, typename MethodArguments>
106constexpr RequestLayout GetReplyOutLayout() {
107 return Domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>();
108}
109
110using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>;
111
112template <bool Domain, typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t HandleIndex = 0, size_t InBufferIndex = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0>
113void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) {
114 if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) {
115 return;
116 } else {
117 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
118
119 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InData || ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) {
120 constexpr size_t ArgAlign = alignof(ArgType);
121 constexpr size_t ArgSize = sizeof(ArgType);
122
123 static_assert(PrevAlign <= ArgAlign, "Input argument is not ordered by alignment");
124 static_assert(!RawDataFinished, "All input interface arguments must appear after raw data");
125
126 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
127 constexpr size_t ArgEnd = ArgOffset + ArgSize;
128
129 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) {
130 // TODO: abort parsing if PID is not provided?
131 // TODO: validate against raw data value?
132 std::get<ArgIndex>(args).pid = ctx.GetPID();
133 } else {
134 std::memcpy(&std::get<ArgIndex>(args), raw_data + ArgOffset, ArgSize);
135 }
136
137 return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp);
138 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InInterface) {
139 constexpr size_t ArgAlign = alignof(u32);
140 constexpr size_t ArgSize = sizeof(u32);
141 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
142 constexpr size_t ArgEnd = ArgOffset + ArgSize;
143
144 static_assert(Domain);
145 ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0);
146
147 u32 value{};
148 std::memcpy(&value, raw_data + ArgOffset, ArgSize);
149 std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1);
150
151 return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp);
152 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) {
153 std::get<ArgIndex>(args) = std::move(ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex)));
154
155 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
156 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) {
157 constexpr size_t BufferSize = sizeof(ArgType);
158
159 // Clear the existing data.
160 std::memset(&std::get<ArgIndex>(args), 0, BufferSize);
161
162 std::span<const u8> buffer{};
163
164 ASSERT(ctx.CanReadBuffer(InBufferIndex));
165 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
166 buffer = ctx.ReadBuffer(InBufferIndex);
167 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) {
168 buffer = ctx.ReadBufferA(InBufferIndex);
169 } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ {
170 buffer = ctx.ReadBufferX(InBufferIndex);
171 }
172
173 std::memcpy(&std::get<ArgIndex>(args), buffer.data(), std::min(BufferSize, buffer.size()));
174
175 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
176 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InBuffer) {
177 using ElementType = typename ArgType::Type;
178
179 std::span<const u8> buffer{};
180
181 if (ctx.CanReadBuffer(InBufferIndex)) {
182 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
183 buffer = ctx.ReadBuffer(InBufferIndex);
184 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) {
185 buffer = ctx.ReadBufferA(InBufferIndex);
186 } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ {
187 buffer = ctx.ReadBufferX(InBufferIndex);
188 }
189 }
190
191 ElementType* ptr = (ElementType*) buffer.data();
192 size_t size = buffer.size() / sizeof(ElementType);
193
194 std::get<ArgIndex>(args) = std::span(ptr, size);
195
196 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
197 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) {
198 constexpr size_t BufferSize = sizeof(ArgType);
199
200 // Clear the existing data.
201 std::memset(&std::get<ArgIndex>(args), 0, BufferSize);
202
203 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
204 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) {
205 using ElementType = typename ArgType::Type;
206
207 // Set up scratch buffer.
208 auto& buffer = temp[OutBufferIndex];
209 if (ctx.CanWriteBuffer(OutBufferIndex)) {
210 buffer.resize_destructive(ctx.GetWriteBufferSize(OutBufferIndex));
211 } else {
212 buffer.resize_destructive(0);
213 }
214
215 ElementType* ptr = (ElementType*) buffer.data();
216 size_t size = buffer.size() / sizeof(ElementType);
217
218 std::get<ArgIndex>(args) = std::span(ptr, size);
219
220 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
221 } else {
222 return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
223 }
224 }
225}
226
227template <bool Domain, typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0>
228void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) {
229 if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) {
230 return;
231 } else {
232 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
233
234 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) {
235 constexpr size_t ArgAlign = alignof(ArgType);
236 constexpr size_t ArgSize = sizeof(ArgType);
237
238 static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment");
239 static_assert(!RawDataFinished, "All output interface arguments must appear after raw data");
240
241 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
242 constexpr size_t ArgEnd = ArgOffset + ArgSize;
243
244 std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize);
245
246 return WriteOutArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp);
247 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) {
248 if constexpr (Domain) {
249 ctx.AddDomainObject(std::get<ArgIndex>(args));
250 } else {
251 ctx.AddMoveInterface(std::get<ArgIndex>(args));
252 }
253
254 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp);
255 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) {
256 ctx.AddCopyObject(std::get<ArgIndex>(args).GetPointerUnsafe());
257
258 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
259 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) {
260 ctx.AddMoveObject(std::get<ArgIndex>(args).GetPointerUnsafe());
261
262 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
263 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) {
264 constexpr size_t BufferSize = sizeof(ArgType);
265
266 ASSERT(ctx.CanWriteBuffer(OutBufferIndex));
267 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
268 ctx.WriteBuffer(std::get<ArgIndex>(args), OutBufferIndex);
269 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) {
270 ctx.WriteBufferB(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex);
271 } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ {
272 ctx.WriteBufferC(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex);
273 }
274
275 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
276 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) {
277 auto& buffer = temp[OutBufferIndex];
278 const size_t size = buffer.size();
279
280 if (ctx.CanWriteBuffer(OutBufferIndex)) {
281 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
282 ctx.WriteBuffer(buffer.data(), size, OutBufferIndex);
283 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) {
284 ctx.WriteBufferB(buffer.data(), size, OutBufferIndex);
285 } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ {
286 ctx.WriteBufferC(buffer.data(), size, OutBufferIndex);
287 }
288 }
289
290 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>( args, raw_data, ctx, temp);
291 } else {
292 return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp);
293 }
294 }
295}
296
297template <bool Domain, typename T, typename... A>
298void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
299 // Verify domain state.
300 if constexpr (Domain) {
301 ASSERT_MSG(ctx.GetManager()->IsDomain(), "Domain reply used on non-domain session");
302 } else {
303 ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Non-domain reply used on domain session");
304 }
305
306 using MethodArguments = std::tuple<std::remove_reference_t<A>...>;
307
308 OutTemporaryBuffers buffers{};
309 auto call_arguments = std::tuple<typename RemoveOut<A>::Type...>();
310
311 // Read inputs.
312 const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2;
313 ReadInArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers);
314
315 // Call.
316 const auto Callable = [&]<typename... CallArgs>(CallArgs&... args) {
317 return (t.*f)(args...);
318 };
319 const Result res = std::apply(Callable, call_arguments);
320
321 // Write result.
322 constexpr RequestLayout layout = GetReplyOutLayout<Domain, MethodArguments>();
323 IPC::ResponseBuilder rb{ctx, 2 + Common::DivCeil(layout.cmif_raw_data_size, sizeof(u32)), layout.copy_handle_count, layout.move_handle_count + layout.domain_interface_count};
324 rb.Push(res);
325
326 // Write out arguments.
327 WriteOutArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers);
328}
329// clang-format on
330
331template <typename Self>
332template <bool Domain, auto F>
333inline void ServiceFramework<Self>::CmifReplyWrap(HLERequestContext& ctx) {
334 return CmifReplyWrapImpl<Domain>(ctx, *static_cast<Self*>(this), F);
335}
336
337} // namespace Service
diff --git a/src/core/hle/service/cmif_types.h b/src/core/hle/service/cmif_types.h
new file mode 100644
index 000000000..b80028c19
--- /dev/null
+++ b/src/core/hle/service/cmif_types.h
@@ -0,0 +1,234 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10#include "core/hle/service/hle_ipc.h"
11
12namespace Service {
13
14// clang-format off
15template <typename T>
16class Out {
17public:
18 /* implicit */ Out(T& t) : raw(&t) {}
19 ~Out() = default;
20
21 T* Get() const {
22 return raw;
23 }
24
25 T& operator*() {
26 return *raw;
27 }
28
29private:
30 T* raw;
31};
32
33template <typename T>
34using SharedPointer = std::shared_ptr<T>;
35
36struct ClientProcessId {
37 explicit operator bool() const {
38 return pid != 0;
39 }
40
41 const u64& operator*() const {
42 return pid;
43 }
44
45 u64 pid;
46};
47
48using ClientAppletResourceUserId = ClientProcessId;
49
50template <typename T>
51class InCopyHandle : public Kernel::KScopedAutoObject<T> {
52public:
53 using Type = T;
54
55 template <typename... Args>
56 /* implicit */ InCopyHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {}
57 ~InCopyHandle() = default;
58
59 InCopyHandle& operator=(InCopyHandle&& rhs) {
60 Kernel::KScopedAutoObject<T>::operator=(std::move(rhs));
61 return *this;
62 }
63};
64
65template <typename T>
66class OutCopyHandle : public Kernel::KScopedAutoObject<T> {
67public:
68 using Type = T;
69
70 template <typename... Args>
71 /* implicit */ OutCopyHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {}
72 ~OutCopyHandle() = default;
73
74 OutCopyHandle& operator=(OutCopyHandle&& rhs) {
75 Kernel::KScopedAutoObject<T>::operator=(std::move(rhs));
76 return *this;
77 }
78};
79
80template <typename T>
81class OutMoveHandle : public Kernel::KScopedAutoObject<T> {
82public:
83 using Type = T;
84
85 template <typename... Args>
86 /* implicit */ OutMoveHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {}
87 ~OutMoveHandle() = default;
88
89 OutMoveHandle& operator=(OutMoveHandle&& rhs) {
90 Kernel::KScopedAutoObject<T>::operator=(std::move(rhs));
91 return *this;
92 }
93};
94
95enum BufferAttr : int {
96 BufferAttr_In = (1U << 0),
97 BufferAttr_Out = (1U << 1),
98 BufferAttr_HipcMapAlias = (1U << 2),
99 BufferAttr_HipcPointer = (1U << 3),
100 BufferAttr_FixedSize = (1U << 4),
101 BufferAttr_HipcAutoSelect = (1U << 5),
102 BufferAttr_HipcMapTransferAllowsNonSecure = (1U << 6),
103 BufferAttr_HipcMapTransferAllowsNonDevice = (1U << 7),
104};
105
106template <typename T, int A>
107struct Buffer : public std::span<T> {
108 static_assert(std::is_trivial_v<T>, "Buffer type must be trivial");
109 static_assert((A & BufferAttr_FixedSize) == 0, "Buffer attr must not contain FixedSize");
110 static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "Buffer attr must be In or Out");
111 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A);
112 using Type = T;
113
114 Buffer& operator=(const std::span<T>& rhs) {
115 std::span<T>::operator=(rhs);
116 return *this;
117 }
118
119 T& operator*() const {
120 return *this->data();
121 }
122
123 explicit operator bool() const {
124 return this->size() > 0;
125 }
126};
127
128template <BufferAttr A>
129using InBuffer = Buffer<const u8, BufferAttr_In | A>;
130
131template <typename T, BufferAttr A>
132using InArray = Buffer<T, BufferAttr_In | A>;
133
134template <BufferAttr A>
135using OutBuffer = Buffer<u8, BufferAttr_Out | A>;
136
137template <typename T, BufferAttr A>
138using OutArray = Buffer<T, BufferAttr_Out | A>;
139
140template <typename T, int A>
141struct LargeData : public T {
142 static_assert(std::is_trivial_v<T>, "LargeData type must be trivial");
143 static_assert((A & BufferAttr_FixedSize) != 0, "LargeData attr must contain FixedSize");
144 static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "LargeData attr must be In or Out");
145 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A);
146 using Type = T;
147};
148
149template <typename T, BufferAttr A>
150using InLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_In | A>;
151
152template <typename T, BufferAttr A>
153using OutLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_Out | A>;
154
155template <typename T>
156struct RemoveOut {
157 using Type = std::remove_reference_t<T>;
158};
159
160template <typename T>
161struct RemoveOut<Out<T>> {
162 using Type = T;
163};
164
165enum class ArgumentType {
166 InProcessId,
167 InData,
168 InInterface,
169 InCopyHandle,
170 OutData,
171 OutInterface,
172 OutCopyHandle,
173 OutMoveHandle,
174 InBuffer,
175 InLargeData,
176 OutBuffer,
177 OutLargeData,
178};
179
180template <typename T>
181struct ArgumentTraits;
182
183template <>
184struct ArgumentTraits<ClientProcessId> {
185 static constexpr ArgumentType Type = ArgumentType::InProcessId;
186};
187
188template <typename T>
189struct ArgumentTraits<SharedPointer<T>> {
190 static constexpr ArgumentType Type = ArgumentType::InInterface;
191};
192
193template <typename T>
194struct ArgumentTraits<InCopyHandle<T>> {
195 static constexpr ArgumentType Type = ArgumentType::InCopyHandle;
196};
197
198template <typename T>
199struct ArgumentTraits<Out<SharedPointer<T>>> {
200 static constexpr ArgumentType Type = ArgumentType::OutInterface;
201};
202
203template <typename T>
204struct ArgumentTraits<Out<T>> {
205 static constexpr ArgumentType Type = ArgumentType::OutData;
206};
207
208template <typename T>
209struct ArgumentTraits<OutCopyHandle<T>> {
210 static constexpr ArgumentType Type = ArgumentType::OutCopyHandle;
211};
212
213template <typename T>
214struct ArgumentTraits<OutMoveHandle<T>> {
215 static constexpr ArgumentType Type = ArgumentType::OutMoveHandle;
216};
217
218template <typename T, int A>
219struct ArgumentTraits<Buffer<T, A>> {
220 static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutBuffer : ArgumentType::InBuffer;
221};
222
223template <typename T, int A>
224struct ArgumentTraits<LargeData<T, A>> {
225 static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutLargeData : ArgumentType::InLargeData;
226};
227
228template <typename T>
229struct ArgumentTraits {
230 static constexpr ArgumentType Type = ArgumentType::InData;
231};
232// clang-format on
233
234} // namespace Service
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp
index 993c3d21d..10376bfac 100644
--- a/src/core/hle/service/glue/glue.cpp
+++ b/src/core/hle/service/glue/glue.cpp
@@ -8,6 +8,9 @@
8#include "core/hle/service/glue/ectx.h" 8#include "core/hle/service/glue/ectx.h"
9#include "core/hle/service/glue/glue.h" 9#include "core/hle/service/glue/glue.h"
10#include "core/hle/service/glue/notif.h" 10#include "core/hle/service/glue/notif.h"
11#include "core/hle/service/glue/time/manager.h"
12#include "core/hle/service/glue/time/static.h"
13#include "core/hle/service/psc/time/common.h"
11#include "core/hle/service/server_manager.h" 14#include "core/hle/service/server_manager.h"
12 15
13namespace Service::Glue { 16namespace Service::Glue {
@@ -31,6 +34,22 @@ void LoopProcess(Core::System& system) {
31 // Notification Services for application 34 // Notification Services for application
32 server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system)); 35 server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system));
33 36
37 // Time
38 auto time = std::make_shared<Time::TimeManager>(system);
39
40 server_manager->RegisterNamedService(
41 "time:u",
42 std::make_shared<Time::StaticService>(
43 system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, time, "time:u"));
44 server_manager->RegisterNamedService(
45 "time:a",
46 std::make_shared<Time::StaticService>(
47 system, Service::PSC::Time::StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, time, "time:a"));
48 server_manager->RegisterNamedService(
49 "time:r",
50 std::make_shared<Time::StaticService>(
51 system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, time, "time:r"));
52
34 ServerManager::RunServer(std::move(server_manager)); 53 ServerManager::RunServer(std::move(server_manager));
35} 54}
36 55
diff --git a/src/core/hle/service/glue/time/alarm_worker.cpp b/src/core/hle/service/glue/time/alarm_worker.cpp
new file mode 100644
index 000000000..f549ed00a
--- /dev/null
+++ b/src/core/hle/service/glue/time/alarm_worker.cpp
@@ -0,0 +1,82 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/core_timing.h"
6#include "core/hle/kernel/svc.h"
7#include "core/hle/service/glue/time/alarm_worker.h"
8#include "core/hle/service/psc/time/service_manager.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::Glue::Time {
12
13AlarmWorker::AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource)
14 : m_system{system}, m_ctx{system, "Glue:AlarmWorker"}, m_steady_clock_resource{
15 steady_clock_resource} {}
16
17AlarmWorker::~AlarmWorker() {
18 m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
19
20 m_ctx.CloseEvent(m_timer_event);
21}
22
23void AlarmWorker::Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m) {
24 m_time_m = std::move(time_m);
25
26 m_timer_event = m_ctx.CreateEvent("Glue:AlarmWorker:TimerEvent");
27 m_timer_timing_event = Core::Timing::CreateEvent(
28 "Glue:AlarmWorker::AlarmTimer",
29 [this](s64 time,
30 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
31 m_timer_event->Signal();
32 return std::nullopt;
33 });
34
35 AttachToClosestAlarmEvent();
36}
37
38bool AlarmWorker::GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info,
39 s64& out_time) {
40 bool is_valid{};
41 Service::PSC::Time::AlarmInfo alarm_info{};
42 s64 closest_time{};
43
44 auto res = m_time_m->GetClosestAlarmInfo(is_valid, alarm_info, closest_time);
45 ASSERT(res == ResultSuccess);
46
47 if (is_valid) {
48 out_alarm_info = alarm_info;
49 out_time = closest_time;
50 }
51
52 return is_valid;
53}
54
55void AlarmWorker::OnPowerStateChanged() {
56 Service::PSC::Time::AlarmInfo closest_alarm_info{};
57 s64 closest_time{};
58 if (!GetClosestAlarmInfo(closest_alarm_info, closest_time)) {
59 m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
60 m_timer_event->Clear();
61 return;
62 }
63
64 if (closest_alarm_info.alert_time <= closest_time) {
65 m_time_m->CheckAndSignalAlarms();
66 } else {
67 auto next_time{closest_alarm_info.alert_time - closest_time};
68
69 m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
70 m_timer_event->Clear();
71
72 m_system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds(next_time),
73 m_timer_timing_event);
74 }
75}
76
77Result AlarmWorker::AttachToClosestAlarmEvent() {
78 m_time_m->GetClosestAlarmUpdatedEvent(&m_event);
79 R_SUCCEED();
80}
81
82} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/alarm_worker.h b/src/core/hle/service/glue/time/alarm_worker.h
new file mode 100644
index 000000000..f269cffdb
--- /dev/null
+++ b/src/core/hle/service/glue/time/alarm_worker.h
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/psc/time/common.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::PSC::Time {
16class ServiceManager;
17}
18
19namespace Service::Glue::Time {
20class StandardSteadyClockResource;
21
22class AlarmWorker {
23public:
24 explicit AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource);
25 ~AlarmWorker();
26
27 void Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m);
28
29 Kernel::KEvent& GetEvent() {
30 return *m_event;
31 }
32
33 Kernel::KEvent& GetTimerEvent() {
34 return *m_timer_event;
35 }
36
37 void OnPowerStateChanged();
38
39private:
40 bool GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, s64& out_time);
41 Result AttachToClosestAlarmEvent();
42
43 Core::System& m_system;
44 KernelHelpers::ServiceContext m_ctx;
45 std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
46
47 Kernel::KEvent* m_event{};
48 Kernel::KEvent* m_timer_event{};
49 std::shared_ptr<Core::Timing::EventType> m_timer_timing_event;
50 StandardSteadyClockResource& m_steady_clock_resource;
51};
52
53} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.cpp b/src/core/hle/service/glue/time/file_timestamp_worker.cpp
new file mode 100644
index 000000000..5a6309549
--- /dev/null
+++ b/src/core/hle/service/glue/time/file_timestamp_worker.cpp
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/glue/time/file_timestamp_worker.h"
5#include "core/hle/service/psc/time/common.h"
6#include "core/hle/service/psc/time/system_clock.h"
7#include "core/hle/service/psc/time/time_zone_service.h"
8
9namespace Service::Glue::Time {
10
11void FileTimestampWorker::SetFilesystemPosixTime() {
12 s64 time{};
13 Service::PSC::Time::CalendarTime calendar_time{};
14 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
15
16 if (m_initialized && m_system_clock->GetCurrentTime(time) == ResultSuccess &&
17 m_time_zone->ToCalendarTimeWithMyRule(calendar_time, additional_info, time) ==
18 ResultSuccess) {
19 // TODO IFileSystemProxy::SetCurrentPosixTime
20 }
21}
22
23} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.h b/src/core/hle/service/glue/time/file_timestamp_worker.h
new file mode 100644
index 000000000..5f8b9b049
--- /dev/null
+++ b/src/core/hle/service/glue/time/file_timestamp_worker.h
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7
8#include "common/common_types.h"
9
10namespace Service::PSC::Time {
11class SystemClock;
12class TimeZoneService;
13} // namespace Service::PSC::Time
14
15namespace Service::Glue::Time {
16
17class FileTimestampWorker {
18public:
19 FileTimestampWorker() = default;
20
21 void SetFilesystemPosixTime();
22
23 std::shared_ptr<Service::PSC::Time::SystemClock> m_system_clock{};
24 std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone{};
25 bool m_initialized{};
26};
27
28} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/manager.cpp b/src/core/hle/service/glue/time/manager.cpp
new file mode 100644
index 000000000..6423e5089
--- /dev/null
+++ b/src/core/hle/service/glue/time/manager.cpp
@@ -0,0 +1,277 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5
6#include "core/core.h"
7#include "core/core_timing.h"
8
9#include "common/settings.h"
10#include "common/time_zone.h"
11#include "core/file_sys/vfs.h"
12#include "core/hle/kernel/svc.h"
13#include "core/hle/service/glue/time/manager.h"
14#include "core/hle/service/glue/time/time_zone_binary.h"
15#include "core/hle/service/psc/time/service_manager.h"
16#include "core/hle/service/psc/time/static.h"
17#include "core/hle/service/psc/time/system_clock.h"
18#include "core/hle/service/psc/time/time_zone_service.h"
19#include "core/hle/service/set/system_settings_server.h"
20#include "core/hle/service/sm/sm.h"
21
22namespace Service::Glue::Time {
23namespace {
24
25template <typename T>
26T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
27 const char* category, const char* name) {
28 std::vector<u8> interval_buf;
29 auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
30 ASSERT(res == ResultSuccess);
31
32 T v{};
33 std::memcpy(&v, interval_buf.data(), sizeof(T));
34 return v;
35}
36
37s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) {
38 constexpr auto is_leap = [](s32 year) -> bool {
39 return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
40 };
41 constexpr std::array<s32, 12> MonthStartDayOfYear{
42 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
43 };
44
45 s16 month_s16{calendar.month};
46 s8 month{static_cast<s8>(((month_s16 * 43) & ~std::numeric_limits<s16>::max()) +
47 ((month_s16 * 43) >> 9))};
48 s8 month_index{static_cast<s8>(calendar.month - 12 * month)};
49 if (month_index == 0) {
50 month_index = 12;
51 }
52 s32 year{(month + calendar.year) - !month_index};
53 s32 v8{year >= 0 ? year : year + 3};
54
55 s64 days_since_epoch = calendar.day + MonthStartDayOfYear[month_index - 1];
56 days_since_epoch += (year * 365) + (v8 / 4) - (year / 100) + (year / 400) - 365;
57
58 if (month_index <= 2 && is_leap(year)) {
59 days_since_epoch--;
60 }
61 auto epoch_s{((24ll * days_since_epoch + calendar.hour) * 60ll + calendar.minute) * 60ll +
62 calendar.second};
63 return epoch_s - 62135683200ll;
64}
65
66s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) {
67 Service::PSC::Time::CalendarTime calendar{
68 .year = GetSettingsItemValue<s16>(set_sys, "time", "standard_user_clock_initial_year"),
69 .month = 1,
70 .day = 1,
71 .hour = 0,
72 .minute = 0,
73 .second = 0,
74 };
75 return CalendarTimeToEpoch(calendar);
76}
77
78Service::PSC::Time::LocationName GetTimeZoneString(Service::PSC::Time::LocationName& in_name) {
79 auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
80
81 Service::PSC::Time::LocationName configured_name{};
82 std::memcpy(configured_name.name.data(), configured_zone.data(),
83 std::min(configured_name.name.size(), configured_zone.size()));
84
85 if (!IsTimeZoneBinaryValid(configured_name)) {
86 configured_zone = Common::TimeZone::FindSystemTimeZone();
87 configured_name = {};
88 std::memcpy(configured_name.name.data(), configured_zone.data(),
89 std::min(configured_name.name.size(), configured_zone.size()));
90 }
91
92 ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!",
93 configured_name.name.data());
94
95 return configured_name;
96}
97
98} // namespace
99
100TimeManager::TimeManager(Core::System& system)
101 : m_steady_clock_resource{system}, m_worker{system, m_steady_clock_resource,
102 m_file_timestamp_worker} {
103 m_time_m =
104 system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
105
106 auto res = m_time_m->GetStaticServiceAsServiceManager(m_time_sm);
107 ASSERT(res == ResultSuccess);
108
109 m_set_sys =
110 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
111
112 res = MountTimeZoneBinary(system);
113 ASSERT(res == ResultSuccess);
114
115 m_worker.Initialize(m_time_sm, m_set_sys);
116
117 res = m_time_sm->GetStandardUserSystemClock(m_file_timestamp_worker.m_system_clock);
118 ASSERT(res == ResultSuccess);
119
120 res = m_time_sm->GetTimeZoneService(m_file_timestamp_worker.m_time_zone);
121 ASSERT(res == ResultSuccess);
122
123 res = SetupStandardSteadyClockCore();
124 ASSERT(res == ResultSuccess);
125
126 Service::PSC::Time::SystemClockContext user_clock_context{};
127 res = m_set_sys->GetUserSystemClockContext(user_clock_context);
128 ASSERT(res == ResultSuccess);
129
130 // TODO the local clock should initialise with this epoch time, and be updated somewhere else on
131 // first boot to update it, but I haven't been able to find that point (likely via ntc's auto
132 // correct as it's defaulted to be enabled). So to get a time that isn't stuck in the past for
133 // first boot, grab the current real seconds.
134 auto epoch_time{GetEpochTimeFromInitialYear(m_set_sys)};
135 if (user_clock_context == Service::PSC::Time::SystemClockContext{}) {
136 m_steady_clock_resource.GetRtcTimeInSeconds(epoch_time);
137 }
138
139 res = m_time_m->SetupStandardLocalSystemClockCore(user_clock_context, epoch_time);
140 ASSERT(res == ResultSuccess);
141
142 Service::PSC::Time::SystemClockContext network_clock_context{};
143 res = m_set_sys->GetNetworkSystemClockContext(network_clock_context);
144 ASSERT(res == ResultSuccess);
145
146 auto network_accuracy_m{GetSettingsItemValue<s32>(
147 m_set_sys, "time", "standard_network_clock_sufficient_accuracy_minutes")};
148 auto one_minute_ns{
149 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
150 s64 network_accuracy_ns{network_accuracy_m * one_minute_ns};
151
152 res = m_time_m->SetupStandardNetworkSystemClockCore(network_clock_context, network_accuracy_ns);
153 ASSERT(res == ResultSuccess);
154
155 bool is_automatic_correction_enabled{};
156 res = m_set_sys->IsUserSystemClockAutomaticCorrectionEnabled(is_automatic_correction_enabled);
157 ASSERT(res == ResultSuccess);
158
159 Service::PSC::Time::SteadyClockTimePoint automatic_correction_time_point{};
160 res = m_set_sys->GetUserSystemClockAutomaticCorrectionUpdatedTime(
161 automatic_correction_time_point);
162 ASSERT(res == ResultSuccess);
163
164 res = m_time_m->SetupStandardUserSystemClockCore(automatic_correction_time_point,
165 is_automatic_correction_enabled);
166 ASSERT(res == ResultSuccess);
167
168 res = m_time_m->SetupEphemeralNetworkSystemClockCore();
169 ASSERT(res == ResultSuccess);
170
171 res = SetupTimeZoneServiceCore();
172 ASSERT(res == ResultSuccess);
173
174 s64 rtc_time_s{};
175 res = m_steady_clock_resource.GetRtcTimeInSeconds(rtc_time_s);
176 ASSERT(res == ResultSuccess);
177
178 // TODO system report "launch"
179 // "rtc_reset" = m_steady_clock_resource.m_rtc_reset
180 // "rtc_value" = rtc_time_s
181
182 m_worker.StartThread();
183
184 m_file_timestamp_worker.m_initialized = true;
185
186 s64 system_clock_time{};
187 if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(system_clock_time) ==
188 ResultSuccess) {
189 Service::PSC::Time::CalendarTime calendar_time{};
190 Service::PSC::Time::CalendarAdditionalInfo calendar_additional{};
191 if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule(
192 calendar_time, calendar_additional, system_clock_time) == ResultSuccess) {
193 // TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time,
194 // calendar_additional.ut_offset)
195 }
196 }
197}
198
199Result TimeManager::SetupStandardSteadyClockCore() {
200 Common::UUID external_clock_source_id{};
201 auto res = m_set_sys->GetExternalSteadyClockSourceId(external_clock_source_id);
202 ASSERT(res == ResultSuccess);
203
204 s64 external_steady_clock_internal_offset_s{};
205 res = m_set_sys->GetExternalSteadyClockInternalOffset(external_steady_clock_internal_offset_s);
206 ASSERT(res == ResultSuccess);
207
208 auto one_second_ns{
209 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
210 s64 external_steady_clock_internal_offset_ns{external_steady_clock_internal_offset_s *
211 one_second_ns};
212
213 s32 standard_steady_clock_test_offset_m{
214 GetSettingsItemValue<s32>(m_set_sys, "time", "standard_steady_clock_test_offset_minutes")};
215 auto one_minute_ns{
216 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
217 s64 standard_steady_clock_test_offset_ns{standard_steady_clock_test_offset_m * one_minute_ns};
218
219 auto reset_detected = m_steady_clock_resource.GetResetDetected();
220 if (reset_detected) {
221 external_clock_source_id = {};
222 }
223
224 Common::UUID clock_source_id{};
225 m_steady_clock_resource.Initialize(&clock_source_id, &external_clock_source_id);
226
227 if (clock_source_id != external_clock_source_id) {
228 m_set_sys->SetExternalSteadyClockSourceId(clock_source_id);
229 }
230
231 res = m_time_m->SetupStandardSteadyClockCore(clock_source_id, m_steady_clock_resource.GetTime(),
232 external_steady_clock_internal_offset_ns,
233 standard_steady_clock_test_offset_ns,
234 reset_detected);
235 ASSERT(res == ResultSuccess);
236 R_SUCCEED();
237}
238
239Result TimeManager::SetupTimeZoneServiceCore() {
240 Service::PSC::Time::LocationName name{};
241 auto res = m_set_sys->GetDeviceTimeZoneLocationName(name);
242 ASSERT(res == ResultSuccess);
243
244 auto configured_zone = GetTimeZoneString(name);
245
246 if (configured_zone.name != name.name) {
247 m_set_sys->SetDeviceTimeZoneLocationName(configured_zone);
248 name = configured_zone;
249
250 std::shared_ptr<Service::PSC::Time::SystemClock> local_clock;
251 m_time_sm->GetStandardLocalSystemClock(local_clock);
252 Service::PSC::Time::SystemClockContext context{};
253 local_clock->GetSystemClockContext(context);
254 m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(context.steady_time_point);
255 }
256
257 Service::PSC::Time::SteadyClockTimePoint time_point{};
258 res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(time_point);
259 ASSERT(res == ResultSuccess);
260
261 auto location_count = GetTimeZoneCount();
262 Service::PSC::Time::RuleVersion rule_version{};
263 GetTimeZoneVersion(rule_version);
264
265 std::span<const u8> rule_buffer{};
266 size_t rule_size{};
267 res = GetTimeZoneRule(rule_buffer, rule_size, name);
268 ASSERT(res == ResultSuccess);
269
270 res = m_time_m->SetupTimeZoneServiceCore(name, time_point, rule_version, location_count,
271 rule_buffer);
272 ASSERT(res == ResultSuccess);
273
274 R_SUCCEED();
275}
276
277} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/manager.h b/src/core/hle/service/glue/time/manager.h
new file mode 100644
index 000000000..a46ec6364
--- /dev/null
+++ b/src/core/hle/service/glue/time/manager.h
@@ -0,0 +1,42 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <functional>
7#include <string>
8
9#include "common/common_types.h"
10#include "core/file_sys/vfs_types.h"
11#include "core/hle/service/glue/time/file_timestamp_worker.h"
12#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
13#include "core/hle/service/glue/time/worker.h"
14#include "core/hle/service/service.h"
15
16namespace Core {
17class System;
18}
19
20namespace Service::PSC::Time {
21class ServiceManager;
22class StaticService;
23} // namespace Service::PSC::Time
24
25namespace Service::Glue::Time {
26class TimeManager {
27public:
28 explicit TimeManager(Core::System& system);
29
30 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
31
32 std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m{};
33 std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm{};
34 StandardSteadyClockResource m_steady_clock_resource;
35 FileTimestampWorker m_file_timestamp_worker;
36 TimeWorker m_worker;
37
38private:
39 Result SetupStandardSteadyClockCore();
40 Result SetupTimeZoneServiceCore();
41};
42} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/pm_state_change_handler.cpp b/src/core/hle/service/glue/time/pm_state_change_handler.cpp
new file mode 100644
index 000000000..7470fb225
--- /dev/null
+++ b/src/core/hle/service/glue/time/pm_state_change_handler.cpp
@@ -0,0 +1,13 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/glue/time/pm_state_change_handler.h"
5
6namespace Service::Glue::Time {
7
8PmStateChangeHandler::PmStateChangeHandler(AlarmWorker& alarm_worker)
9 : m_alarm_worker{alarm_worker} {
10 // TODO Initialize IPmModule, dependent on Rtc and Fs
11}
12
13} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/pm_state_change_handler.h b/src/core/hle/service/glue/time/pm_state_change_handler.h
new file mode 100644
index 000000000..27d9f7872
--- /dev/null
+++ b/src/core/hle/service/glue/time/pm_state_change_handler.h
@@ -0,0 +1,18 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::Glue::Time {
9class AlarmWorker;
10
11class PmStateChangeHandler {
12public:
13 explicit PmStateChangeHandler(AlarmWorker& alarm_worker);
14
15 AlarmWorker& m_alarm_worker;
16 s32 m_priority{};
17};
18} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp b/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp
new file mode 100644
index 000000000..5ebaa33e0
--- /dev/null
+++ b/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp
@@ -0,0 +1,123 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5
6#include "common/settings.h"
7#include "core/core.h"
8#include "core/core_timing.h"
9#include "core/hle/kernel/svc.h"
10#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
11#include "core/hle/service/psc/time/errors.h"
12
13namespace Service::Glue::Time {
14namespace {
15[[maybe_unused]] constexpr u32 Max77620PmicSession = 0x3A000001;
16[[maybe_unused]] constexpr u32 Max77620RtcSession = 0x3B000001;
17
18Result GetTimeInSeconds(Core::System& system, s64& out_time_s) {
19 out_time_s = std::chrono::duration_cast<std::chrono::seconds>(
20 std::chrono::system_clock::now().time_since_epoch())
21 .count();
22
23 if (Settings::values.custom_rtc_enabled) {
24 out_time_s += Settings::values.custom_rtc_offset.GetValue();
25 }
26 R_SUCCEED();
27}
28} // namespace
29
30StandardSteadyClockResource::StandardSteadyClockResource(Core::System& system) : m_system{system} {}
31
32void StandardSteadyClockResource::Initialize(Common::UUID* out_source_id,
33 Common::UUID* external_source_id) {
34 constexpr size_t NUM_TRIES{20};
35
36 size_t i{0};
37 Result res{ResultSuccess};
38 for (; i < NUM_TRIES; i++) {
39 res = SetCurrentTime();
40 if (res == ResultSuccess) {
41 break;
42 }
43 Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>(
44 std::chrono::milliseconds(1))
45 .count());
46 }
47
48 if (i < NUM_TRIES) {
49 m_set_time_result = ResultSuccess;
50 if (*external_source_id != Service::PSC::Time::ClockSourceId{}) {
51 m_clock_source_id = *external_source_id;
52 } else {
53 m_clock_source_id = Common::UUID::MakeRandom();
54 }
55 } else {
56 m_set_time_result = res;
57 auto ticks{m_system.CoreTiming().GetClockTicks()};
58 m_time = -Service::PSC::Time::ConvertToTimeSpan(ticks).count();
59 m_clock_source_id = Common::UUID::MakeRandom();
60 }
61
62 if (out_source_id) {
63 *out_source_id = m_clock_source_id;
64 }
65}
66
67bool StandardSteadyClockResource::GetResetDetected() {
68 // TODO:
69 // call Rtc::GetRtcResetDetected(Max77620RtcSession)
70 // if detected:
71 // SetSys::SetExternalSteadyClockSourceId(invalid_id)
72 // Rtc::ClearRtcResetDetected(Max77620RtcSession)
73 // set m_rtc_reset to result
74 // Instead, only set reset to true if we're booting for the first time.
75 m_rtc_reset = false;
76 return m_rtc_reset;
77}
78
79Result StandardSteadyClockResource::SetCurrentTime() {
80 auto start_tick{m_system.CoreTiming().GetClockTicks()};
81
82 s64 rtc_time_s{};
83 // TODO R_TRY(Rtc::GetTimeInSeconds(rtc_time_s, Max77620RtcSession))
84 R_TRY(GetTimeInSeconds(m_system, rtc_time_s));
85
86 auto end_tick{m_system.CoreTiming().GetClockTicks()};
87 auto diff{Service::PSC::Time::ConvertToTimeSpan(end_tick - start_tick)};
88 // Why is this here?
89 R_UNLESS(diff < std::chrono::milliseconds(101), Service::PSC::Time::ResultRtcTimeout);
90
91 auto one_second_ns{
92 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
93 s64 boot_time{rtc_time_s * one_second_ns -
94 Service::PSC::Time::ConvertToTimeSpan(end_tick).count()};
95
96 std::scoped_lock l{m_mutex};
97 m_time = boot_time;
98 R_SUCCEED();
99}
100
101Result StandardSteadyClockResource::GetRtcTimeInSeconds(s64& out_time) {
102 // TODO
103 // R_TRY(Rtc::GetTimeInSeconds(time_s, Max77620RtcSession)
104 R_RETURN(GetTimeInSeconds(m_system, out_time));
105}
106
107void StandardSteadyClockResource::UpdateTime() {
108 constexpr size_t NUM_TRIES{3};
109
110 size_t i{0};
111 Result res{ResultSuccess};
112 for (; i < NUM_TRIES; i++) {
113 res = SetCurrentTime();
114 if (res == ResultSuccess) {
115 break;
116 }
117 Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>(
118 std::chrono::milliseconds(1))
119 .count());
120 }
121}
122
123} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/standard_steady_clock_resource.h b/src/core/hle/service/glue/time/standard_steady_clock_resource.h
new file mode 100644
index 000000000..978d6b63b
--- /dev/null
+++ b/src/core/hle/service/glue/time/standard_steady_clock_resource.h
@@ -0,0 +1,41 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7
8#include "common/common_types.h"
9#include "core/hle/result.h"
10#include "core/hle/service/psc/time/common.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::Glue::Time {
17class StandardSteadyClockResource {
18public:
19 StandardSteadyClockResource(Core::System& system);
20
21 void Initialize(Common::UUID* out_source_id, Common::UUID* external_source_id);
22
23 s64 GetTime() const {
24 return m_time;
25 }
26
27 bool GetResetDetected();
28 Result SetCurrentTime();
29 Result GetRtcTimeInSeconds(s64& out_time);
30 void UpdateTime();
31
32private:
33 Core::System& m_system;
34
35 std::mutex m_mutex;
36 Service::PSC::Time::ClockSourceId m_clock_source_id{};
37 s64 m_time{};
38 Result m_set_time_result;
39 bool m_rtc_reset;
40};
41} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp
new file mode 100644
index 000000000..63b7d91da
--- /dev/null
+++ b/src/core/hle/service/glue/time/static.cpp
@@ -0,0 +1,448 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5
6#include "core/core.h"
7#include "core/hle/kernel/k_shared_memory.h"
8#include "core/hle/kernel/svc.h"
9#include "core/hle/service/glue/time/file_timestamp_worker.h"
10#include "core/hle/service/glue/time/static.h"
11#include "core/hle/service/psc/time/errors.h"
12#include "core/hle/service/psc/time/service_manager.h"
13#include "core/hle/service/psc/time/static.h"
14#include "core/hle/service/psc/time/steady_clock.h"
15#include "core/hle/service/psc/time/system_clock.h"
16#include "core/hle/service/psc/time/time_zone_service.h"
17#include "core/hle/service/set/system_settings_server.h"
18#include "core/hle/service/sm/sm.h"
19
20namespace Service::Glue::Time {
21namespace {
22template <typename T>
23T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
24 const char* category, const char* name) {
25 std::vector<u8> interval_buf;
26 auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
27 ASSERT(res == ResultSuccess);
28
29 T v{};
30 std::memcpy(&v, interval_buf.data(), sizeof(T));
31 return v;
32}
33} // namespace
34
35StaticService::StaticService(Core::System& system_,
36 Service::PSC::Time::StaticServiceSetupInfo setup_info,
37 std::shared_ptr<TimeManager> time, const char* name)
38 : ServiceFramework{system_, name}, m_system{system_}, m_time_m{time->m_time_m},
39 m_setup_info{setup_info}, m_time_sm{time->m_time_sm},
40 m_file_timestamp_worker{time->m_file_timestamp_worker}, m_standard_steady_clock_resource{
41 time->m_steady_clock_resource} {
42 // clang-format off
43 static const FunctionInfo functions[] = {
44 {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"},
45 {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
46 {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"},
47 {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"},
48 {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
49 {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"},
50 {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
51 {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"},
52 {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"},
53 {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
54 {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
55 {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"},
56 {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
57 {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
58 {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
59 {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"},
60 {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
61 {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
62 {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"},
63 };
64 // clang-format on
65
66 RegisterHandlers(functions);
67
68 m_set_sys =
69 m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
70
71 if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock &&
72 !m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location &&
73 !m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) {
74 m_time_m->GetStaticServiceAsAdmin(m_wrapped_service);
75 } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock &&
76 !m_setup_info.can_write_network_clock &&
77 !m_setup_info.can_write_timezone_device_location &&
78 !m_setup_info.can_write_steady_clock &&
79 !m_setup_info.can_write_uninitialized_clock) {
80 m_time_m->GetStaticServiceAsUser(m_wrapped_service);
81 } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock &&
82 !m_setup_info.can_write_network_clock &&
83 !m_setup_info.can_write_timezone_device_location &&
84 m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) {
85 m_time_m->GetStaticServiceAsRepair(m_wrapped_service);
86 } else {
87 UNREACHABLE();
88 }
89
90 auto res = m_wrapped_service->GetTimeZoneService(m_time_zone);
91 ASSERT(res == ResultSuccess);
92}
93
94void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) {
95 LOG_DEBUG(Service_Time, "called.");
96
97 std::shared_ptr<Service::PSC::Time::SystemClock> service{};
98 auto res = GetStandardUserSystemClock(service);
99
100 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
101 rb.Push(res);
102 rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
103}
104
105void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_Time, "called.");
107
108 std::shared_ptr<Service::PSC::Time::SystemClock> service{};
109 auto res = GetStandardNetworkSystemClock(service);
110
111 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
112 rb.Push(res);
113 rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
114}
115
116void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) {
117 LOG_DEBUG(Service_Time, "called.");
118
119 std::shared_ptr<Service::PSC::Time::SteadyClock> service{};
120 auto res = GetStandardSteadyClock(service);
121
122 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
123 rb.Push(res);
124 rb.PushIpcInterface(std::move(service));
125}
126
127void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) {
128 LOG_DEBUG(Service_Time, "called.");
129
130 std::shared_ptr<TimeZoneService> service{};
131 auto res = GetTimeZoneService(service);
132
133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
134 rb.Push(res);
135 rb.PushIpcInterface(std::move(service));
136}
137
138void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) {
139 LOG_DEBUG(Service_Time, "called.");
140
141 std::shared_ptr<Service::PSC::Time::SystemClock> service{};
142 auto res = GetStandardLocalSystemClock(service);
143
144 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
145 rb.Push(res);
146 rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
147}
148
149void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) {
150 LOG_DEBUG(Service_Time, "called.");
151
152 std::shared_ptr<Service::PSC::Time::SystemClock> service{};
153 auto res = GetEphemeralNetworkSystemClock(service);
154
155 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
156 rb.Push(res);
157 rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
158}
159
160void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
161 LOG_DEBUG(Service_Time, "called.");
162
163 Kernel::KSharedMemory* shared_memory{};
164 auto res = GetSharedMemoryNativeHandle(&shared_memory);
165
166 IPC::ResponseBuilder rb{ctx, 2, 1};
167 rb.Push(res);
168 rb.PushCopyObjects(shared_memory);
169}
170
171void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Time, "called.");
173
174 IPC::RequestParser rp{ctx};
175 auto offset_ns{rp.Pop<s64>()};
176
177 auto res = SetStandardSteadyClockInternalOffset(offset_ns);
178
179 IPC::ResponseBuilder rb{ctx, 2};
180 rb.Push(res);
181}
182
183void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) {
184 LOG_DEBUG(Service_Time, "called.");
185
186 s64 rtc_value{};
187 auto res = GetStandardSteadyClockRtcValue(rtc_value);
188
189 IPC::ResponseBuilder rb{ctx, 4};
190 rb.Push(res);
191 rb.Push(rtc_value);
192}
193
194void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(
195 HLERequestContext& ctx) {
196 LOG_DEBUG(Service_Time, "called.");
197
198 bool is_enabled{};
199 auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled);
200
201 IPC::ResponseBuilder rb{ctx, 3};
202 rb.Push(res);
203 rb.Push<bool>(is_enabled);
204}
205
206void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(
207 HLERequestContext& ctx) {
208 LOG_DEBUG(Service_Time, "called.");
209
210 IPC::RequestParser rp{ctx};
211 auto automatic_correction{rp.Pop<bool>()};
212
213 auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
214
215 IPC::ResponseBuilder rb{ctx, 2};
216 rb.Push(res);
217}
218
219void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) {
220 LOG_DEBUG(Service_Time, "called.");
221
222 s32 initial_year{};
223 auto res = GetStandardUserSystemClockInitialYear(initial_year);
224
225 IPC::ResponseBuilder rb{ctx, 3};
226 rb.Push(res);
227 rb.Push(initial_year);
228}
229
230void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
231 LOG_DEBUG(Service_Time, "called.");
232
233 bool is_sufficient{};
234 auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient);
235
236 IPC::ResponseBuilder rb{ctx, 3};
237 rb.Push(res);
238 rb.Push<bool>(is_sufficient);
239}
240
241void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
242 HLERequestContext& ctx) {
243 LOG_DEBUG(Service_Time, "called.");
244
245 Service::PSC::Time::SteadyClockTimePoint time_point{};
246 auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
247
248 IPC::ResponseBuilder rb{ctx,
249 2 + sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32)};
250 rb.Push(res);
251 rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
252}
253
254void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
255 LOG_DEBUG(Service_Time, "called.");
256
257 IPC::RequestParser rp{ctx};
258 auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
259
260 s64 time{};
261 auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context);
262
263 IPC::ResponseBuilder rb{ctx, 4};
264 rb.Push(res);
265 rb.Push<s64>(time);
266}
267
268void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) {
269 LOG_DEBUG(Service_Time, "called.");
270
271 IPC::RequestParser rp{ctx};
272 auto type{rp.PopEnum<Service::PSC::Time::TimeType>()};
273
274 Service::PSC::Time::ClockSnapshot snapshot{};
275 auto res = GetClockSnapshot(snapshot, type);
276
277 ctx.WriteBuffer(snapshot);
278
279 IPC::ResponseBuilder rb{ctx, 2};
280 rb.Push(res);
281}
282
283void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
284 LOG_DEBUG(Service_Time, "called.");
285
286 IPC::RequestParser rp{ctx};
287 auto clock_type{rp.PopEnum<Service::PSC::Time::TimeType>()};
288 [[maybe_unused]] auto alignment{rp.Pop<u32>()};
289 auto user_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
290 auto network_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
291
292 Service::PSC::Time::ClockSnapshot snapshot{};
293 auto res =
294 GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type);
295
296 ctx.WriteBuffer(snapshot);
297
298 IPC::ResponseBuilder rb{ctx, 2};
299 rb.Push(res);
300}
301
302void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser(
303 HLERequestContext& ctx) {
304 LOG_DEBUG(Service_Time, "called.");
305
306 Service::PSC::Time::ClockSnapshot a{};
307 Service::PSC::Time::ClockSnapshot b{};
308
309 auto a_buffer{ctx.ReadBuffer(0)};
310 auto b_buffer{ctx.ReadBuffer(1)};
311
312 std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
313 std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
314
315 s64 difference{};
316 auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b);
317
318 IPC::ResponseBuilder rb{ctx, 4};
319 rb.Push(res);
320 rb.Push(difference);
321}
322
323void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) {
324 LOG_DEBUG(Service_Time, "called.");
325
326 Service::PSC::Time::ClockSnapshot a{};
327 Service::PSC::Time::ClockSnapshot b{};
328
329 auto a_buffer{ctx.ReadBuffer(0)};
330 auto b_buffer{ctx.ReadBuffer(1)};
331
332 std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
333 std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
334
335 s64 time{};
336 auto res = CalculateSpanBetween(time, a, b);
337
338 IPC::ResponseBuilder rb{ctx, 4};
339 rb.Push(res);
340 rb.Push(time);
341}
342
343// =============================== Implementations ===========================
344
345Result StaticService::GetStandardUserSystemClock(
346 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
347 R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service));
348}
349
350Result StaticService::GetStandardNetworkSystemClock(
351 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
352 R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service));
353}
354
355Result StaticService::GetStandardSteadyClock(
356 std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service) {
357 R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service));
358}
359
360Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) {
361 out_service = std::make_shared<TimeZoneService>(m_system, m_file_timestamp_worker,
362 m_setup_info.can_write_timezone_device_location,
363 m_time_zone);
364 R_SUCCEED();
365}
366
367Result StaticService::GetStandardLocalSystemClock(
368 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
369 R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service));
370}
371
372Result StaticService::GetEphemeralNetworkSystemClock(
373 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
374 R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service));
375}
376
377Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) {
378 R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory));
379}
380
381Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
382 R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied);
383
384 R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset(
385 offset_ns /
386 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()));
387}
388
389Result StaticService::GetStandardSteadyClockRtcValue(s64& out_rtc_value) {
390 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(out_rtc_value));
391}
392
393Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
394 bool& out_automatic_correction) {
395 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled(
396 out_automatic_correction));
397}
398
399Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
400 bool automatic_correction) {
401 R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled(
402 automatic_correction));
403}
404
405Result StaticService::GetStandardUserSystemClockInitialYear(s32& out_year) {
406 out_year = GetSettingsItemValue<s32>(m_set_sys, "time", "standard_user_clock_initial_year");
407 R_SUCCEED();
408}
409
410Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) {
411 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient));
412}
413
414Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
415 Service::PSC::Time::SteadyClockTimePoint& out_time_point) {
416 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
417 out_time_point));
418}
419
420Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
421 s64& out_time, Service::PSC::Time::SystemClockContext& context) {
422 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
423}
424
425Result StaticService::GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot,
426 Service::PSC::Time::TimeType type) {
427 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type));
428}
429
430Result StaticService::GetClockSnapshotFromSystemClockContext(
431 Service::PSC::Time::ClockSnapshot& out_snapshot,
432 Service::PSC::Time::SystemClockContext& user_context,
433 Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type) {
434 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(out_snapshot, user_context,
435 network_context, type));
436}
437
438Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(
439 s64& out_time, Service::PSC::Time::ClockSnapshot& a, Service::PSC::Time::ClockSnapshot& b) {
440 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b));
441}
442
443Result StaticService::CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a,
444 Service::PSC::Time::ClockSnapshot& b) {
445 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
446}
447
448} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/static.h b/src/core/hle/service/glue/time/static.h
new file mode 100644
index 000000000..75fe4e2cd
--- /dev/null
+++ b/src/core/hle/service/glue/time/static.h
@@ -0,0 +1,110 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/service/glue/time/manager.h"
8#include "core/hle/service/glue/time/time_zone.h"
9#include "core/hle/service/psc/time/common.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::Set {
16class ISystemSettingsServer;
17}
18
19namespace Service::PSC::Time {
20class StaticService;
21class SystemClock;
22class SteadyClock;
23class TimeZoneService;
24class ServiceManager;
25} // namespace Service::PSC::Time
26
27namespace Service::Glue::Time {
28class FileTimestampWorker;
29class StandardSteadyClockResource;
30
31class StaticService final : public ServiceFramework<StaticService> {
32public:
33 explicit StaticService(Core::System& system,
34 Service::PSC::Time::StaticServiceSetupInfo setup_info,
35 std::shared_ptr<TimeManager> time, const char* name);
36
37 ~StaticService() override = default;
38
39 Result GetStandardUserSystemClock(
40 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
41 Result GetStandardNetworkSystemClock(
42 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
43 Result GetStandardSteadyClock(std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service);
44 Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service);
45 Result GetStandardLocalSystemClock(
46 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
47 Result GetEphemeralNetworkSystemClock(
48 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
49 Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory);
50 Result SetStandardSteadyClockInternalOffset(s64 offset);
51 Result GetStandardSteadyClockRtcValue(s64& out_rtc_value);
52 Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_automatic_correction);
53 Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction);
54 Result GetStandardUserSystemClockInitialYear(s32& out_year);
55 Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient);
56 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
57 Service::PSC::Time::SteadyClockTimePoint& out_time_point);
58 Result CalculateMonotonicSystemClockBaseTimePoint(
59 s64& out_time, Service::PSC::Time::SystemClockContext& context);
60 Result GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot,
61 Service::PSC::Time::TimeType type);
62 Result GetClockSnapshotFromSystemClockContext(
63 Service::PSC::Time::ClockSnapshot& out_snapshot,
64 Service::PSC::Time::SystemClockContext& user_context,
65 Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type);
66 Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time,
67 Service::PSC::Time::ClockSnapshot& a,
68 Service::PSC::Time::ClockSnapshot& b);
69 Result CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a,
70 Service::PSC::Time::ClockSnapshot& b);
71
72private:
73 Result GetClockSnapshotImpl(Service::PSC::Time::ClockSnapshot& out_snapshot,
74 Service::PSC::Time::SystemClockContext& user_context,
75 Service::PSC::Time::SystemClockContext& network_context,
76 Service::PSC::Time::TimeType type);
77
78 void Handle_GetStandardUserSystemClock(HLERequestContext& ctx);
79 void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx);
80 void Handle_GetStandardSteadyClock(HLERequestContext& ctx);
81 void Handle_GetTimeZoneService(HLERequestContext& ctx);
82 void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx);
83 void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx);
84 void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx);
85 void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx);
86 void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx);
87 void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
88 void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
89 void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx);
90 void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
91 void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
92 void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
93 void Handle_GetClockSnapshot(HLERequestContext& ctx);
94 void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
95 void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
96 void Handle_CalculateSpanBetween(HLERequestContext& ctx);
97
98 Core::System& m_system;
99
100 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
101 std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
102 std::shared_ptr<Service::PSC::Time::StaticService> m_wrapped_service;
103
104 Service::PSC::Time::StaticServiceSetupInfo m_setup_info;
105 std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm;
106 std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone;
107 FileTimestampWorker& m_file_timestamp_worker;
108 StandardSteadyClockResource& m_standard_steady_clock_resource;
109};
110} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp
new file mode 100644
index 000000000..503c327dd
--- /dev/null
+++ b/src/core/hle/service/glue/time/time_zone.cpp
@@ -0,0 +1,377 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5
6#include "core/core.h"
7#include "core/hle/kernel/svc.h"
8#include "core/hle/service/glue/time/file_timestamp_worker.h"
9#include "core/hle/service/glue/time/time_zone.h"
10#include "core/hle/service/glue/time/time_zone_binary.h"
11#include "core/hle/service/psc/time/time_zone_service.h"
12#include "core/hle/service/set/system_settings_server.h"
13#include "core/hle/service/sm/sm.h"
14
15namespace Service::Glue::Time {
16namespace {
17static std::mutex g_list_mutex;
18static Common::IntrusiveListBaseTraits<Service::PSC::Time::OperationEvent>::ListType g_list_nodes{};
19} // namespace
20
21TimeZoneService::TimeZoneService(
22 Core::System& system_, FileTimestampWorker& file_timestamp_worker,
23 bool can_write_timezone_device_location,
24 std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service)
25 : ServiceFramework{system_, "ITimeZoneService"}, m_system{system},
26 m_can_write_timezone_device_location{can_write_timezone_device_location},
27 m_file_timestamp_worker{file_timestamp_worker},
28 m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} {
29 // clang-format off
30 static const FunctionInfo functions[] = {
31 {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"},
32 {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"},
33 {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"},
34 {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"},
35 {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"},
36 {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
37 {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"},
38 {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"},
39 {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"},
40 {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"},
41 {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"},
42 {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
43 {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"},
44 {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
45 };
46 // clang-format on
47 RegisterHandlers(functions);
48
49 g_list_nodes.clear();
50 m_set_sys =
51 m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
52}
53
54TimeZoneService::~TimeZoneService() = default;
55
56void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) {
57 LOG_DEBUG(Service_Time, "called.");
58
59 Service::PSC::Time::LocationName name{};
60 auto res = GetDeviceLocationName(name);
61
62 IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)};
63 rb.Push(res);
64 rb.PushRaw<Service::PSC::Time::LocationName>(name);
65}
66
67void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) {
68 LOG_DEBUG(Service_Time, "called.");
69
70 IPC::RequestParser rp{ctx};
71 auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
72
73 auto res = SetDeviceLocation(name);
74
75 IPC::ResponseBuilder rb{ctx, 2};
76 rb.Push(res);
77}
78
79void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) {
80 LOG_DEBUG(Service_Time, "called.");
81
82 u32 count{};
83 auto res = GetTotalLocationNameCount(count);
84
85 IPC::ResponseBuilder rb{ctx, 3};
86 rb.Push(res);
87 rb.Push(count);
88}
89
90void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) {
91 LOG_DEBUG(Service_Time, "called.");
92
93 IPC::RequestParser rp{ctx};
94 auto index{rp.Pop<u32>()};
95
96 auto max_names{ctx.GetWriteBufferSize() / sizeof(Service::PSC::Time::LocationName)};
97
98 std::vector<Service::PSC::Time::LocationName> names{};
99 u32 count{};
100 auto res = LoadLocationNameList(count, names, max_names, index);
101
102 ctx.WriteBuffer(names);
103
104 IPC::ResponseBuilder rb{ctx, 3};
105 rb.Push(res);
106 rb.Push(count);
107}
108
109void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) {
110 LOG_DEBUG(Service_Time, "called.");
111
112 IPC::RequestParser rp{ctx};
113 auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
114
115 Tz::Rule rule{};
116 auto res = LoadTimeZoneRule(rule, name);
117
118 ctx.WriteBuffer(rule);
119
120 IPC::ResponseBuilder rb{ctx, 2};
121 rb.Push(res);
122}
123
124void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) {
125 LOG_DEBUG(Service_Time, "called.");
126
127 Service::PSC::Time::RuleVersion rule_version{};
128 auto res = GetTimeZoneRuleVersion(rule_version);
129
130 IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::RuleVersion) / sizeof(u32)};
131 rb.Push(res);
132 rb.PushRaw<Service::PSC::Time::RuleVersion>(rule_version);
133}
134
135void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) {
136 LOG_DEBUG(Service_Time, "called.");
137
138 Service::PSC::Time::LocationName name{};
139 Service::PSC::Time::SteadyClockTimePoint time_point{};
140 auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name);
141
142 IPC::ResponseBuilder rb{ctx,
143 2 + (sizeof(Service::PSC::Time::LocationName) / sizeof(u32)) +
144 (sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32))};
145 rb.Push(res);
146 rb.PushRaw<Service::PSC::Time::LocationName>(name);
147 rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
148}
149
150void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) {
151 LOG_DEBUG(Service_Time, "called.");
152
153 auto res = SetDeviceLocationNameWithTimeZoneRule();
154
155 IPC::ResponseBuilder rb{ctx, 2};
156 rb.Push(res);
157}
158
159void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) {
160 LOG_DEBUG(Service_Time, "called.");
161
162 IPC::ResponseBuilder rb{ctx, 2};
163 rb.Push(Service::PSC::Time::ResultNotImplemented);
164}
165
166void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle(
167 HLERequestContext& ctx) {
168 LOG_DEBUG(Service_Time, "called.");
169
170 Kernel::KEvent* event{};
171 auto res = GetDeviceLocationNameOperationEventReadableHandle(&event);
172
173 IPC::ResponseBuilder rb{ctx, 2, 1};
174 rb.Push(res);
175 rb.PushCopyObjects(event->GetReadableEvent());
176}
177
178void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) {
179 LOG_DEBUG(Service_Time, "called.");
180
181 IPC::RequestParser rp{ctx};
182 auto time{rp.Pop<s64>()};
183
184 auto rule_buffer{ctx.ReadBuffer()};
185 Tz::Rule rule{};
186 std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule));
187
188 Service::PSC::Time::CalendarTime calendar_time{};
189 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
190 auto res = ToCalendarTime(calendar_time, additional_info, time, rule);
191
192 IPC::ResponseBuilder rb{ctx,
193 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) +
194 (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))};
195 rb.Push(res);
196 rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time);
197 rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info);
198}
199
200void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
201 IPC::RequestParser rp{ctx};
202 auto time{rp.Pop<s64>()};
203
204 LOG_DEBUG(Service_Time, "called. time={}", time);
205
206 Service::PSC::Time::CalendarTime calendar_time{};
207 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
208 auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time);
209
210 IPC::ResponseBuilder rb{ctx,
211 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) +
212 (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))};
213 rb.Push(res);
214 rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time);
215 rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info);
216}
217
218void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) {
219 IPC::RequestParser rp{ctx};
220 auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()};
221
222 LOG_DEBUG(Service_Time, "called. calendar year {} month {} day {} hour {} minute {} second {}",
223 calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute,
224 calendar.second);
225
226 auto binary{ctx.ReadBuffer()};
227
228 Tz::Rule rule{};
229 std::memcpy(&rule, binary.data(), sizeof(Tz::Rule));
230
231 u32 count{};
232 std::array<s64, 2> times{};
233 u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
234
235 auto res = ToPosixTime(count, times, times_count, calendar, rule);
236
237 ctx.WriteBuffer(times);
238
239 IPC::ResponseBuilder rb{ctx, 3};
240 rb.Push(res);
241 rb.Push(count);
242}
243
244void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) {
245 LOG_DEBUG(Service_Time, "called.");
246
247 IPC::RequestParser rp{ctx};
248 auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()};
249
250 u32 count{};
251 std::array<s64, 2> times{};
252 u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
253
254 auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar);
255
256 ctx.WriteBuffer(times);
257
258 IPC::ResponseBuilder rb{ctx, 3};
259 rb.Push(res);
260 rb.Push(count);
261}
262
263// =============================== Implementations ===========================
264
265Result TimeZoneService::GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name) {
266 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
267}
268
269Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& location_name) {
270 R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
271 R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound);
272
273 std::scoped_lock l{m_mutex};
274
275 std::span<const u8> binary{};
276 size_t binary_size{};
277 R_TRY(GetTimeZoneRule(binary, binary_size, location_name))
278
279 R_TRY(m_wrapped_service->SetDeviceLocationNameWithTimeZoneRule(location_name, binary));
280
281 m_file_timestamp_worker.SetFilesystemPosixTime();
282
283 Service::PSC::Time::SteadyClockTimePoint time_point{};
284 Service::PSC::Time::LocationName name{};
285 R_TRY(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(time_point, name));
286
287 m_set_sys->SetDeviceTimeZoneLocationName(name);
288 m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point);
289
290 std::scoped_lock m{g_list_mutex};
291 for (auto& operation_event : g_list_nodes) {
292 operation_event.m_event->Signal();
293 }
294 R_SUCCEED();
295}
296
297Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) {
298 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count));
299}
300
301Result TimeZoneService::LoadLocationNameList(
302 u32& out_count, std::vector<Service::PSC::Time::LocationName>& out_names, size_t max_names,
303 u32 index) {
304 std::scoped_lock l{m_mutex};
305 R_RETURN(GetTimeZoneLocationList(out_count, out_names, max_names, index));
306}
307
308Result TimeZoneService::LoadTimeZoneRule(Tz::Rule& out_rule,
309 Service::PSC::Time::LocationName& name) {
310 std::scoped_lock l{m_mutex};
311 std::span<const u8> binary{};
312 size_t binary_size{};
313 R_TRY(GetTimeZoneRule(binary, binary_size, name))
314 R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary));
315}
316
317Result TimeZoneService::GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
318 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version));
319}
320
321Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
322 Service::PSC::Time::SteadyClockTimePoint& out_time_point,
323 Service::PSC::Time::LocationName& location_name) {
324 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(out_time_point, location_name));
325}
326
327Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule() {
328 R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
329 R_RETURN(Service::PSC::Time::ResultNotImplemented);
330}
331
332Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
333 Kernel::KEvent** out_event) {
334 if (!operation_event_initialized) {
335 operation_event_initialized = false;
336
337 m_operation_event.m_ctx.CloseEvent(m_operation_event.m_event);
338 m_operation_event.m_event =
339 m_operation_event.m_ctx.CreateEvent("Psc:TimeZoneService:OperationEvent");
340 operation_event_initialized = true;
341 std::scoped_lock l{m_mutex};
342 g_list_nodes.push_back(m_operation_event);
343 }
344
345 *out_event = m_operation_event.m_event;
346 R_SUCCEED();
347}
348
349Result TimeZoneService::ToCalendarTime(
350 Service::PSC::Time::CalendarTime& out_calendar_time,
351 Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule) {
352 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
353}
354
355Result TimeZoneService::ToCalendarTimeWithMyRule(
356 Service::PSC::Time::CalendarTime& out_calendar_time,
357 Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time) {
358 R_RETURN(
359 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
360}
361
362Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times,
363 u32 out_times_count,
364 Service::PSC::Time::CalendarTime& calendar_time,
365 Tz::Rule& rule) {
366 R_RETURN(
367 m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule));
368}
369
370Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times,
371 u32 out_times_count,
372 Service::PSC::Time::CalendarTime& calendar_time) {
373 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count,
374 calendar_time));
375}
376
377} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/time_zone.h b/src/core/hle/service/glue/time/time_zone.h
new file mode 100644
index 000000000..3c8ae4bf8
--- /dev/null
+++ b/src/core/hle/service/glue/time/time_zone.h
@@ -0,0 +1,95 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <mutex>
8#include <span>
9#include <vector>
10
11#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/psc/time/common.h"
13#include "core/hle/service/server_manager.h"
14#include "core/hle/service/service.h"
15
16namespace Core {
17class System;
18}
19
20namespace Tz {
21struct Rule;
22}
23
24namespace Service::Set {
25class ISystemSettingsServer;
26}
27
28namespace Service::PSC::Time {
29class TimeZoneService;
30}
31
32namespace Service::Glue::Time {
33class FileTimestampWorker;
34
35class TimeZoneService final : public ServiceFramework<TimeZoneService> {
36public:
37 explicit TimeZoneService(
38 Core::System& system, FileTimestampWorker& file_timestamp_worker,
39 bool can_write_timezone_device_location,
40 std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service);
41
42 ~TimeZoneService() override;
43
44 Result GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name);
45 Result SetDeviceLocation(Service::PSC::Time::LocationName& location_name);
46 Result GetTotalLocationNameCount(u32& out_count);
47 Result LoadLocationNameList(u32& out_count,
48 std::vector<Service::PSC::Time::LocationName>& out_names,
49 size_t max_names, u32 index);
50 Result LoadTimeZoneRule(Tz::Rule& out_rule, Service::PSC::Time::LocationName& name);
51 Result GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version);
52 Result GetDeviceLocationNameAndUpdatedTime(
53 Service::PSC::Time::SteadyClockTimePoint& out_time_point,
54 Service::PSC::Time::LocationName& location_name);
55 Result SetDeviceLocationNameWithTimeZoneRule();
56 Result GetDeviceLocationNameOperationEventReadableHandle(Kernel::KEvent** out_event);
57 Result ToCalendarTime(Service::PSC::Time::CalendarTime& out_calendar_time,
58 Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time,
59 Tz::Rule& rule);
60 Result ToCalendarTimeWithMyRule(Service::PSC::Time::CalendarTime& out_calendar_time,
61 Service::PSC::Time::CalendarAdditionalInfo& out_additional_info,
62 s64 time);
63 Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
64 Service::PSC::Time::CalendarTime& calendar_time, Tz::Rule& rule);
65 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
66 Service::PSC::Time::CalendarTime& calendar_time);
67
68private:
69 void Handle_GetDeviceLocationName(HLERequestContext& ctx);
70 void Handle_SetDeviceLocationName(HLERequestContext& ctx);
71 void Handle_GetTotalLocationNameCount(HLERequestContext& ctx);
72 void Handle_LoadLocationNameList(HLERequestContext& ctx);
73 void Handle_LoadTimeZoneRule(HLERequestContext& ctx);
74 void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx);
75 void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx);
76 void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx);
77 void Handle_ParseTimeZoneBinary(HLERequestContext& ctx);
78 void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx);
79 void Handle_ToCalendarTime(HLERequestContext& ctx);
80 void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx);
81 void Handle_ToPosixTime(HLERequestContext& ctx);
82 void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx);
83
84 Core::System& m_system;
85 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
86
87 bool m_can_write_timezone_device_location;
88 FileTimestampWorker& m_file_timestamp_worker;
89 std::shared_ptr<Service::PSC::Time::TimeZoneService> m_wrapped_service;
90 std::mutex m_mutex;
91 bool operation_event_initialized{};
92 Service::PSC::Time::OperationEvent m_operation_event;
93};
94
95} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/time_zone_binary.cpp b/src/core/hle/service/glue/time/time_zone_binary.cpp
new file mode 100644
index 000000000..67969aa3f
--- /dev/null
+++ b/src/core/hle/service/glue/time/time_zone_binary.cpp
@@ -0,0 +1,221 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/file_sys/content_archive.h"
6#include "core/file_sys/nca_metadata.h"
7#include "core/file_sys/registered_cache.h"
8#include "core/file_sys/romfs.h"
9#include "core/file_sys/system_archive/system_archive.h"
10#include "core/file_sys/vfs.h"
11#include "core/hle/service/filesystem/filesystem.h"
12#include "core/hle/service/glue/time/time_zone_binary.h"
13
14namespace Service::Glue::Time {
15namespace {
16constexpr u64 TimeZoneBinaryId = 0x10000000000080E;
17
18static FileSys::VirtualDir g_time_zone_binary_romfs{};
19static Result g_time_zone_binary_mount_result{ResultUnknown};
20static std::vector<u8> g_time_zone_scratch_space(0x2800, 0);
21
22Result TimeZoneReadBinary(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size,
23 std::string_view path) {
24 R_UNLESS(g_time_zone_binary_mount_result == ResultSuccess, g_time_zone_binary_mount_result);
25
26 auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)};
27 R_UNLESS(vfs_file, ResultUnknown);
28
29 auto file_size{vfs_file->GetSize()};
30 R_UNLESS(file_size > 0, ResultUnknown);
31
32 R_UNLESS(file_size <= out_buffer_size, Service::PSC::Time::ResultFailed);
33
34 out_read_size = vfs_file->Read(out_buffer.data(), file_size);
35 R_UNLESS(out_read_size > 0, ResultUnknown);
36
37 R_SUCCEED();
38}
39} // namespace
40
41void ResetTimeZoneBinary() {
42 g_time_zone_binary_romfs = {};
43 g_time_zone_binary_mount_result = ResultUnknown;
44 g_time_zone_scratch_space.clear();
45 g_time_zone_scratch_space.resize(0x2800, 0);
46}
47
48Result MountTimeZoneBinary(Core::System& system) {
49 ResetTimeZoneBinary();
50
51 auto& fsc{system.GetFileSystemController()};
52 std::unique_ptr<FileSys::NCA> nca{};
53
54 auto* bis_system = fsc.GetSystemNANDContents();
55
56 R_UNLESS(bis_system, ResultUnknown);
57
58 nca = bis_system->GetEntry(TimeZoneBinaryId, FileSys::ContentRecordType::Data);
59
60 if (nca) {
61 g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS());
62 }
63
64 if (g_time_zone_binary_romfs) {
65 // Validate that the romfs is readable, using invalid firmware keys can cause this to get
66 // set but the files to be garbage. In that case, we want to hit the next path and
67 // synthesise them instead.
68 Service::PSC::Time::LocationName name{"Etc/GMT"};
69 if (!IsTimeZoneBinaryValid(name)) {
70 ResetTimeZoneBinary();
71 }
72 }
73
74 if (!g_time_zone_binary_romfs) {
75 g_time_zone_binary_romfs = FileSys::ExtractRomFS(
76 FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId));
77 }
78
79 R_UNLESS(g_time_zone_binary_romfs, ResultUnknown);
80
81 g_time_zone_binary_mount_result = ResultSuccess;
82 R_SUCCEED();
83}
84
85void GetTimeZoneBinaryListPath(std::string& out_path) {
86 if (g_time_zone_binary_mount_result != ResultSuccess) {
87 return;
88 }
89 // out_path = fmt::format("{}:/binaryList.txt", "TimeZoneBinary");
90 out_path = "/binaryList.txt";
91}
92
93void GetTimeZoneBinaryVersionPath(std::string& out_path) {
94 if (g_time_zone_binary_mount_result != ResultSuccess) {
95 return;
96 }
97 // out_path = fmt::format("{}:/version.txt", "TimeZoneBinary");
98 out_path = "/version.txt";
99}
100
101void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name) {
102 if (g_time_zone_binary_mount_result != ResultSuccess) {
103 return;
104 }
105 // out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name);
106 out_path = fmt::format("/zoneinfo/{}", name.name.data());
107}
108
109bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) {
110 std::string path{};
111 GetTimeZoneZonePath(path, name);
112
113 auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)};
114 if (!vfs_file) {
115 LOG_INFO(Service_Time, "Could not find timezone file {}", path);
116 return false;
117 }
118 return vfs_file->GetSize() != 0;
119}
120
121u32 GetTimeZoneCount() {
122 std::string path{};
123 GetTimeZoneBinaryListPath(path);
124
125 size_t bytes_read{};
126 if (TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, 0x2800, path) != ResultSuccess) {
127 return 0;
128 }
129 if (bytes_read == 0) {
130 return 0;
131 }
132
133 auto chars = std::span(reinterpret_cast<char*>(g_time_zone_scratch_space.data()), bytes_read);
134 u32 count{};
135 for (auto chr : chars) {
136 if (chr == '\n') {
137 count++;
138 }
139 }
140 return count;
141}
142
143Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
144 std::string path{};
145 GetTimeZoneBinaryVersionPath(path);
146
147 auto rule_version_buffer{std::span(reinterpret_cast<u8*>(&out_rule_version),
148 sizeof(Service::PSC::Time::RuleVersion))};
149 size_t bytes_read{};
150 R_TRY(TimeZoneReadBinary(bytes_read, rule_version_buffer, rule_version_buffer.size_bytes(),
151 path));
152
153 rule_version_buffer[bytes_read] = 0;
154 R_SUCCEED();
155}
156
157Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
158 Service::PSC::Time::LocationName& name) {
159 std::string path{};
160 GetTimeZoneZonePath(path, name);
161
162 size_t bytes_read{};
163 R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space,
164 g_time_zone_scratch_space.size(), path));
165
166 out_rule = std::span(g_time_zone_scratch_space.data(), bytes_read);
167 out_rule_size = bytes_read;
168 R_SUCCEED();
169}
170
171Result GetTimeZoneLocationList(u32& out_count,
172 std::vector<Service::PSC::Time::LocationName>& out_names,
173 size_t max_names, u32 index) {
174 std::string path{};
175 GetTimeZoneBinaryListPath(path);
176
177 size_t bytes_read{};
178 R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space,
179 g_time_zone_scratch_space.size(), path));
180
181 out_count = 0;
182 R_SUCCEED_IF(bytes_read == 0);
183
184 Service::PSC::Time::LocationName current_name{};
185 size_t current_name_len{};
186 std::span<const u8> chars{g_time_zone_scratch_space};
187 u32 name_count{};
188
189 for (auto chr : chars) {
190 if (chr == '\r') {
191 continue;
192 }
193
194 if (chr == '\n') {
195 if (name_count >= index) {
196 out_names.push_back(current_name);
197 out_count++;
198 if (out_count >= max_names) {
199 break;
200 }
201 }
202 name_count++;
203 current_name_len = 0;
204 current_name = {};
205 continue;
206 }
207
208 if (chr == '\0') {
209 break;
210 }
211
212 R_UNLESS(current_name_len <= current_name.name.size() - 2,
213 Service::PSC::Time::ResultFailed);
214
215 current_name.name[current_name_len++] = chr;
216 }
217
218 R_SUCCEED();
219}
220
221} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/time_zone_binary.h b/src/core/hle/service/glue/time/time_zone_binary.h
new file mode 100644
index 000000000..2cad6b458
--- /dev/null
+++ b/src/core/hle/service/glue/time/time_zone_binary.h
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <span>
7#include <string>
8#include <string_view>
9
10#include "core/hle/service/psc/time/common.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::Glue::Time {
17
18void ResetTimeZoneBinary();
19Result MountTimeZoneBinary(Core::System& system);
20void GetTimeZoneBinaryListPath(std::string& out_path);
21void GetTimeZoneBinaryVersionPath(std::string& out_path);
22void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name);
23bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name);
24u32 GetTimeZoneCount();
25Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version);
26Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
27 Service::PSC::Time::LocationName& name);
28Result GetTimeZoneLocationList(u32& out_count,
29 std::vector<Service::PSC::Time::LocationName>& out_names,
30 size_t max_names, u32 index);
31
32} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/worker.cpp b/src/core/hle/service/glue/time/worker.cpp
new file mode 100644
index 000000000..ea0e49b90
--- /dev/null
+++ b/src/core/hle/service/glue/time/worker.cpp
@@ -0,0 +1,338 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/hle/service/glue/time/file_timestamp_worker.h"
8#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
9#include "core/hle/service/glue/time/worker.h"
10#include "core/hle/service/psc/time/common.h"
11#include "core/hle/service/psc/time/service_manager.h"
12#include "core/hle/service/psc/time/static.h"
13#include "core/hle/service/psc/time/system_clock.h"
14#include "core/hle/service/set/system_settings_server.h"
15#include "core/hle/service/sm/sm.h"
16
17namespace Service::Glue::Time {
18namespace {
19
20bool g_ig_report_network_clock_context_set{};
21Service::PSC::Time::SystemClockContext g_report_network_clock_context{};
22bool g_ig_report_ephemeral_clock_context_set{};
23Service::PSC::Time::SystemClockContext g_report_ephemeral_clock_context{};
24
25template <typename T>
26T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
27 const char* category, const char* name) {
28 std::vector<u8> interval_buf;
29 auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
30 ASSERT(res == ResultSuccess);
31
32 T v{};
33 std::memcpy(&v, interval_buf.data(), sizeof(T));
34 return v;
35}
36
37} // namespace
38
39TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
40 FileTimestampWorker& file_timestamp_worker)
41 : m_system{system}, m_ctx{m_system, "Glue:58"}, m_event{m_ctx.CreateEvent("Glue:58:Event")},
42 m_steady_clock_resource{steady_clock_resource},
43 m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent(
44 "Glue:58:SteadyClockTimerEvent")},
45 m_timer_file_system{m_ctx.CreateEvent("Glue:58:FileTimeTimerEvent")},
46 m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} {
47 g_ig_report_network_clock_context_set = false;
48 g_report_network_clock_context = {};
49 g_ig_report_ephemeral_clock_context_set = false;
50 g_report_ephemeral_clock_context = {};
51
52 m_timer_steady_clock_timing_event = Core::Timing::CreateEvent(
53 "Time::SteadyClockEvent",
54 [this](s64 time,
55 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
56 m_timer_steady_clock->Signal();
57 return std::nullopt;
58 });
59
60 m_timer_file_system_timing_event = Core::Timing::CreateEvent(
61 "Time::SteadyClockEvent",
62 [this](s64 time,
63 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
64 m_timer_file_system->Signal();
65 return std::nullopt;
66 });
67}
68
69TimeWorker::~TimeWorker() {
70 m_local_clock_event->Signal();
71 m_network_clock_event->Signal();
72 m_ephemeral_clock_event->Signal();
73 std::this_thread::sleep_for(std::chrono::milliseconds(16));
74
75 m_thread.request_stop();
76 m_event->Signal();
77 m_thread.join();
78
79 m_ctx.CloseEvent(m_event);
80 m_system.CoreTiming().UnscheduleEvent(m_timer_steady_clock_timing_event);
81 m_ctx.CloseEvent(m_timer_steady_clock);
82 m_system.CoreTiming().UnscheduleEvent(m_timer_file_system_timing_event);
83 m_ctx.CloseEvent(m_timer_file_system);
84}
85
86void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm,
87 std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys) {
88 m_set_sys = std::move(set_sys);
89 m_time_m =
90 m_system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
91 m_time_sm = std::move(time_sm);
92
93 m_alarm_worker.Initialize(m_time_m);
94
95 auto steady_clock_interval_m = GetSettingsItemValue<s32>(
96 m_set_sys, "time", "standard_steady_clock_rtc_update_interval_minutes");
97
98 auto one_minute_ns{
99 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
100 s64 steady_clock_interval_ns{steady_clock_interval_m * one_minute_ns};
101
102 m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0),
103 std::chrono::nanoseconds(steady_clock_interval_ns),
104 m_timer_steady_clock_timing_event);
105
106 auto fs_notify_time_s =
107 GetSettingsItemValue<s32>(m_set_sys, "time", "notify_time_to_fs_interval_seconds");
108 auto one_second_ns{
109 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
110 s64 fs_notify_time_ns{fs_notify_time_s * one_second_ns};
111
112 m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0),
113 std::chrono::nanoseconds(fs_notify_time_ns),
114 m_timer_file_system_timing_event);
115
116 auto res = m_time_sm->GetStandardLocalSystemClock(m_local_clock);
117 ASSERT(res == ResultSuccess);
118 res = m_time_m->GetStandardLocalClockOperationEvent(&m_local_clock_event);
119 ASSERT(res == ResultSuccess);
120
121 res = m_time_sm->GetStandardNetworkSystemClock(m_network_clock);
122 ASSERT(res == ResultSuccess);
123 res = m_time_m->GetStandardNetworkClockOperationEventForServiceManager(&m_network_clock_event);
124 ASSERT(res == ResultSuccess);
125
126 res = m_time_sm->GetEphemeralNetworkSystemClock(m_ephemeral_clock);
127 ASSERT(res == ResultSuccess);
128 res =
129 m_time_m->GetEphemeralNetworkClockOperationEventForServiceManager(&m_ephemeral_clock_event);
130 ASSERT(res == ResultSuccess);
131
132 res = m_time_m->GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
133 &m_standard_user_auto_correct_clock_event);
134 ASSERT(res == ResultSuccess);
135}
136
137void TimeWorker::StartThread() {
138 m_thread = std::jthread(std::bind_front(&TimeWorker::ThreadFunc, this));
139}
140
141void TimeWorker::ThreadFunc(std::stop_token stop_token) {
142 Common::SetCurrentThreadName("TimeWorker");
143 Common::SetCurrentThreadPriority(Common::ThreadPriority::Low);
144
145 enum class EventType {
146 Exit = 0,
147 IpmModuleService_GetEvent = 1,
148 PowerStateChange = 2,
149 SignalAlarms = 3,
150 UpdateLocalSystemClock = 4,
151 UpdateNetworkSystemClock = 5,
152 UpdateEphemeralSystemClock = 6,
153 UpdateSteadyClock = 7,
154 UpdateFileTimestamp = 8,
155 AutoCorrect = 9,
156 Max = 10,
157 };
158
159 s32 num_objs{};
160 std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{};
161 std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{};
162
163 const auto AddWaiter{
164 [&](Kernel::KSynchronizationObject* synchronization_object, EventType type) {
165 // Open a new reference to the object.
166 synchronization_object->Open();
167
168 // Insert into the list.
169 wait_indices[num_objs] = type;
170 wait_objs[num_objs++] = synchronization_object;
171 }};
172
173 while (!stop_token.stop_requested()) {
174 SCOPE_EXIT({
175 for (s32 i = 0; i < num_objs; i++) {
176 wait_objs[i]->Close();
177 }
178 });
179
180 num_objs = {};
181 wait_objs = {};
182 if (m_pm_state_change_handler.m_priority != 0) {
183 AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
184 // TODO
185 // AddWaiter(gIPmModuleService::GetEvent(), 1);
186 AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange);
187 } else {
188 AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
189 // TODO
190 // AddWaiter(gIPmModuleService::GetEvent(), 1);
191 AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange);
192 AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms);
193 AddWaiter(&m_local_clock_event->GetReadableEvent(), EventType::UpdateLocalSystemClock);
194 AddWaiter(&m_network_clock_event->GetReadableEvent(),
195 EventType::UpdateNetworkSystemClock);
196 AddWaiter(&m_ephemeral_clock_event->GetReadableEvent(),
197 EventType::UpdateEphemeralSystemClock);
198 AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock);
199 AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp);
200 AddWaiter(&m_standard_user_auto_correct_clock_event->GetReadableEvent(),
201 EventType::AutoCorrect);
202 }
203
204 s32 out_index{-1};
205 Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(),
206 num_objs, -1);
207 ASSERT(out_index >= 0 && out_index < num_objs);
208
209 if (stop_token.stop_requested()) {
210 return;
211 }
212
213 switch (wait_indices[out_index]) {
214 case EventType::Exit:
215 return;
216
217 case EventType::IpmModuleService_GetEvent:
218 // TODO
219 // IPmModuleService::GetEvent()
220 // clear the event
221 // Handle power state change event
222 break;
223
224 case EventType::PowerStateChange:
225 m_alarm_worker.GetEvent().Clear();
226 if (m_pm_state_change_handler.m_priority <= 1) {
227 m_alarm_worker.OnPowerStateChanged();
228 }
229 break;
230
231 case EventType::SignalAlarms:
232 m_alarm_worker.GetTimerEvent().Clear();
233 m_time_m->CheckAndSignalAlarms();
234 break;
235
236 case EventType::UpdateLocalSystemClock: {
237 m_local_clock_event->Clear();
238
239 Service::PSC::Time::SystemClockContext context{};
240 auto res = m_local_clock->GetSystemClockContext(context);
241 ASSERT(res == ResultSuccess);
242
243 m_set_sys->SetUserSystemClockContext(context);
244
245 m_file_timestamp_worker.SetFilesystemPosixTime();
246 } break;
247
248 case EventType::UpdateNetworkSystemClock: {
249 m_network_clock_event->Clear();
250 Service::PSC::Time::SystemClockContext context{};
251 auto res = m_network_clock->GetSystemClockContext(context);
252 ASSERT(res == ResultSuccess);
253 m_set_sys->SetNetworkSystemClockContext(context);
254
255 s64 time{};
256 if (m_network_clock->GetCurrentTime(time) != ResultSuccess) {
257 break;
258 }
259
260 [[maybe_unused]] auto offset_before{
261 g_ig_report_network_clock_context_set ? g_report_network_clock_context.offset : 0};
262 // TODO system report "standard_netclock_operation"
263 // "clock_time" = time
264 // "context_offset_before" = offset_before
265 // "context_offset_after" = context.offset
266 g_report_network_clock_context = context;
267 if (!g_ig_report_network_clock_context_set) {
268 g_ig_report_network_clock_context_set = true;
269 }
270
271 m_file_timestamp_worker.SetFilesystemPosixTime();
272 } break;
273
274 case EventType::UpdateEphemeralSystemClock: {
275 m_ephemeral_clock_event->Clear();
276
277 Service::PSC::Time::SystemClockContext context{};
278 auto res = m_ephemeral_clock->GetSystemClockContext(context);
279 if (res != ResultSuccess) {
280 break;
281 }
282
283 s64 time{};
284 res = m_ephemeral_clock->GetCurrentTime(time);
285 if (res != ResultSuccess) {
286 break;
287 }
288
289 [[maybe_unused]] auto offset_before{g_ig_report_ephemeral_clock_context_set
290 ? g_report_ephemeral_clock_context.offset
291 : 0};
292 // TODO system report "ephemeral_netclock_operation"
293 // "clock_time" = time
294 // "context_offset_before" = offset_before
295 // "context_offset_after" = context.offset
296 g_report_ephemeral_clock_context = context;
297 if (!g_ig_report_ephemeral_clock_context_set) {
298 g_ig_report_ephemeral_clock_context_set = true;
299 }
300 } break;
301
302 case EventType::UpdateSteadyClock:
303 m_timer_steady_clock->Clear();
304
305 m_steady_clock_resource.UpdateTime();
306 m_time_m->SetStandardSteadyClockBaseTime(m_steady_clock_resource.GetTime());
307 break;
308
309 case EventType::UpdateFileTimestamp:
310 m_timer_file_system->Clear();
311
312 m_file_timestamp_worker.SetFilesystemPosixTime();
313 break;
314
315 case EventType::AutoCorrect: {
316 m_standard_user_auto_correct_clock_event->Clear();
317
318 bool automatic_correction{};
319 auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(
320 automatic_correction);
321 ASSERT(res == ResultSuccess);
322
323 Service::PSC::Time::SteadyClockTimePoint time_point{};
324 res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
325 ASSERT(res == ResultSuccess);
326
327 m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
328 m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
329 } break;
330
331 default:
332 UNREACHABLE();
333 break;
334 }
335 }
336}
337
338} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/worker.h b/src/core/hle/service/glue/time/worker.h
new file mode 100644
index 000000000..adbbe6b6d
--- /dev/null
+++ b/src/core/hle/service/glue/time/worker.h
@@ -0,0 +1,64 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/glue/time/alarm_worker.h"
9#include "core/hle/service/glue/time/pm_state_change_handler.h"
10#include "core/hle/service/kernel_helpers.h"
11
12namespace Service::Set {
13class ISystemSettingsServer;
14}
15
16namespace Service::PSC::Time {
17class StaticService;
18class SystemClock;
19} // namespace Service::PSC::Time
20
21namespace Service::Glue::Time {
22class FileTimestampWorker;
23class StandardSteadyClockResource;
24
25class TimeWorker {
26public:
27 explicit TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
28 FileTimestampWorker& file_timestamp_worker);
29 ~TimeWorker();
30
31 void Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm,
32 std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys);
33
34 void StartThread();
35
36private:
37 void ThreadFunc(std::stop_token stop_token);
38
39 Core::System& m_system;
40 KernelHelpers::ServiceContext m_ctx;
41 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
42
43 std::jthread m_thread;
44 Kernel::KEvent* m_event{};
45 std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
46 std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm;
47 std::shared_ptr<Service::PSC::Time::SystemClock> m_network_clock;
48 std::shared_ptr<Service::PSC::Time::SystemClock> m_local_clock;
49 std::shared_ptr<Service::PSC::Time::SystemClock> m_ephemeral_clock;
50 StandardSteadyClockResource& m_steady_clock_resource;
51 FileTimestampWorker& m_file_timestamp_worker;
52 Kernel::KEvent* m_local_clock_event{};
53 Kernel::KEvent* m_network_clock_event{};
54 Kernel::KEvent* m_ephemeral_clock_event{};
55 Kernel::KEvent* m_standard_user_auto_correct_clock_event{};
56 Kernel::KEvent* m_timer_steady_clock{};
57 std::shared_ptr<Core::Timing::EventType> m_timer_steady_clock_timing_event;
58 Kernel::KEvent* m_timer_file_system{};
59 std::shared_ptr<Core::Timing::EventType> m_timer_file_system_timing_event;
60 AlarmWorker m_alarm_worker;
61 PmStateChangeHandler m_pm_state_change_handler;
62};
63
64} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp
index 3f38ceb03..50e1ed756 100644
--- a/src/core/hle/service/hle_ipc.cpp
+++ b/src/core/hle/service/hle_ipc.cpp
@@ -12,6 +12,7 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/scratch_buffer.h" 14#include "common/scratch_buffer.h"
15#include "core/guest_memory.h"
15#include "core/hle/kernel/k_auto_object.h" 16#include "core/hle/kernel/k_auto_object.h"
16#include "core/hle/kernel/k_handle_table.h" 17#include "core/hle/kernel/k_handle_table.h"
17#include "core/hle/kernel/k_process.h" 18#include "core/hle/kernel/k_process.h"
@@ -23,19 +24,6 @@
23#include "core/hle/service/ipc_helpers.h" 24#include "core/hle/service/ipc_helpers.h"
24#include "core/memory.h" 25#include "core/memory.h"
25 26
26namespace {
27static thread_local std::array read_buffer_data_a{
28 Common::ScratchBuffer<u8>(),
29 Common::ScratchBuffer<u8>(),
30 Common::ScratchBuffer<u8>(),
31};
32static thread_local std::array read_buffer_data_x{
33 Common::ScratchBuffer<u8>(),
34 Common::ScratchBuffer<u8>(),
35 Common::ScratchBuffer<u8>(),
36};
37} // Anonymous namespace
38
39namespace Service { 27namespace Service {
40 28
41SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_) 29SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_)
@@ -343,48 +331,27 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons
343} 331}
344 332
345std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const { 333std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const {
346 static thread_local std::array read_buffer_a{ 334 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0);
347 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
348 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
349 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
350 };
351 335
352 ASSERT_OR_EXECUTE_MSG( 336 ASSERT_OR_EXECUTE_MSG(
353 BufferDescriptorA().size() > buffer_index, { return {}; }, 337 BufferDescriptorA().size() > buffer_index, { return {}; },
354 "BufferDescriptorA invalid buffer_index {}", buffer_index); 338 "BufferDescriptorA invalid buffer_index {}", buffer_index);
355 auto& read_buffer = read_buffer_a[buffer_index]; 339 return gm.Read(BufferDescriptorA()[buffer_index].Address(),
356 return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), 340 BufferDescriptorA()[buffer_index].Size(), &read_buffer_data_a[buffer_index]);
357 BufferDescriptorA()[buffer_index].Size(),
358 &read_buffer_data_a[buffer_index]);
359} 341}
360 342
361std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const { 343std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const {
362 static thread_local std::array read_buffer_x{ 344 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0);
363 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
364 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
365 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
366 };
367 345
368 ASSERT_OR_EXECUTE_MSG( 346 ASSERT_OR_EXECUTE_MSG(
369 BufferDescriptorX().size() > buffer_index, { return {}; }, 347 BufferDescriptorX().size() > buffer_index, { return {}; },
370 "BufferDescriptorX invalid buffer_index {}", buffer_index); 348 "BufferDescriptorX invalid buffer_index {}", buffer_index);
371 auto& read_buffer = read_buffer_x[buffer_index]; 349 return gm.Read(BufferDescriptorX()[buffer_index].Address(),
372 return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), 350 BufferDescriptorX()[buffer_index].Size(), &read_buffer_data_x[buffer_index]);
373 BufferDescriptorX()[buffer_index].Size(),
374 &read_buffer_data_x[buffer_index]);
375} 351}
376 352
377std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { 353std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
378 static thread_local std::array read_buffer_a{ 354 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0);
379 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
380 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
381 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
382 };
383 static thread_local std::array read_buffer_x{
384 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
385 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
386 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
387 };
388 355
389 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && 356 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
390 BufferDescriptorA()[buffer_index].Size()}; 357 BufferDescriptorA()[buffer_index].Size()};
@@ -401,18 +368,14 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons
401 ASSERT_OR_EXECUTE_MSG( 368 ASSERT_OR_EXECUTE_MSG(
402 BufferDescriptorA().size() > buffer_index, { return {}; }, 369 BufferDescriptorA().size() > buffer_index, { return {}; },
403 "BufferDescriptorA invalid buffer_index {}", buffer_index); 370 "BufferDescriptorA invalid buffer_index {}", buffer_index);
404 auto& read_buffer = read_buffer_a[buffer_index]; 371 return gm.Read(BufferDescriptorA()[buffer_index].Address(),
405 return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), 372 BufferDescriptorA()[buffer_index].Size(), &read_buffer_data_a[buffer_index]);
406 BufferDescriptorA()[buffer_index].Size(),
407 &read_buffer_data_a[buffer_index]);
408 } else { 373 } else {
409 ASSERT_OR_EXECUTE_MSG( 374 ASSERT_OR_EXECUTE_MSG(
410 BufferDescriptorX().size() > buffer_index, { return {}; }, 375 BufferDescriptorX().size() > buffer_index, { return {}; },
411 "BufferDescriptorX invalid buffer_index {}", buffer_index); 376 "BufferDescriptorX invalid buffer_index {}", buffer_index);
412 auto& read_buffer = read_buffer_x[buffer_index]; 377 return gm.Read(BufferDescriptorX()[buffer_index].Address(),
413 return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), 378 BufferDescriptorX()[buffer_index].Size(), &read_buffer_data_x[buffer_index]);
414 BufferDescriptorX()[buffer_index].Size(),
415 &read_buffer_data_x[buffer_index]);
416 } 379 }
417} 380}
418 381
@@ -538,6 +501,22 @@ bool HLERequestContext::CanWriteBuffer(std::size_t buffer_index) const {
538 } 501 }
539} 502}
540 503
504void HLERequestContext::AddMoveInterface(SessionRequestHandlerPtr s) {
505 ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve(
506 Kernel::LimitableResource::SessionCountMax, 1));
507
508 auto* session = Kernel::KSession::Create(kernel);
509 session->Initialize(nullptr, 0);
510 Kernel::KSession::Register(kernel, session);
511
512 auto& server = manager.lock()->GetServerManager();
513 auto next_manager = std::make_shared<Service::SessionRequestManager>(kernel, server);
514 next_manager->SetSessionHandler(std::move(s));
515 server.RegisterSession(&session->GetServerSession(), next_manager);
516
517 AddMoveObject(&session->GetClientSession());
518}
519
541std::string HLERequestContext::Description() const { 520std::string HLERequestContext::Description() const {
542 if (!command_header) { 521 if (!command_header) {
543 return "No command header available"; 522 return "No command header available";
diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h
index 440737db5..c2e0e5e8c 100644
--- a/src/core/hle/service/hle_ipc.h
+++ b/src/core/hle/service/hle_ipc.h
@@ -41,6 +41,8 @@ class KernelCore;
41class KHandleTable; 41class KHandleTable;
42class KProcess; 42class KProcess;
43class KServerSession; 43class KServerSession;
44template <typename T>
45class KScopedAutoObject;
44class KThread; 46class KThread;
45} // namespace Kernel 47} // namespace Kernel
46 48
@@ -337,6 +339,8 @@ public:
337 outgoing_move_objects.emplace_back(object); 339 outgoing_move_objects.emplace_back(object);
338 } 340 }
339 341
342 void AddMoveInterface(SessionRequestHandlerPtr s);
343
340 void AddCopyObject(Kernel::KAutoObject* object) { 344 void AddCopyObject(Kernel::KAutoObject* object) {
341 outgoing_copy_objects.emplace_back(object); 345 outgoing_copy_objects.emplace_back(object);
342 } 346 }
@@ -424,6 +428,9 @@ private:
424 428
425 Kernel::KernelCore& kernel; 429 Kernel::KernelCore& kernel;
426 Core::Memory::Memory& memory; 430 Core::Memory::Memory& memory;
431
432 mutable std::array<Common::ScratchBuffer<u8>, 3> read_buffer_data_a{};
433 mutable std::array<Common::ScratchBuffer<u8>, 3> read_buffer_data_x{};
427}; 434};
428 435
429} // namespace Service 436} // namespace Service
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index 77aa6d7d1..d8fefff89 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -6,12 +6,12 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/kernel/k_transfer_memory.h" 7#include "core/hle/kernel/k_transfer_memory.h"
8#include "core/hle/result.h" 8#include "core/hle/result.h"
9#include "core/hle/service/cmif_serialization.h"
9#include "core/hle/service/ipc_helpers.h" 10#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/jit/jit.h" 11#include "core/hle/service/jit/jit.h"
11#include "core/hle/service/jit/jit_code_memory.h" 12#include "core/hle/service/jit/jit_code_memory.h"
12#include "core/hle/service/jit/jit_context.h" 13#include "core/hle/service/jit/jit_context.h"
13#include "core/hle/service/server_manager.h" 14#include "core/hle/service/server_manager.h"
14#include "core/hle/service/service.h"
15#include "core/memory.h" 15#include "core/memory.h"
16 16
17namespace Service::JIT { 17namespace Service::JIT {
@@ -21,6 +21,9 @@ struct CodeRange {
21 u64 size; 21 u64 size;
22}; 22};
23 23
24using Struct32 = std::array<u64, 4>;
25static_assert(sizeof(Struct32) == 32, "Struct32 has wrong size");
26
24class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { 27class IJitEnvironment final : public ServiceFramework<IJitEnvironment> {
25public: 28public:
26 explicit IJitEnvironment(Core::System& system_, 29 explicit IJitEnvironment(Core::System& system_,
@@ -29,12 +32,13 @@ public:
29 : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, 32 : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)},
30 user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, 33 user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)},
31 context{system_.ApplicationMemory()} { 34 context{system_.ApplicationMemory()} {
35
32 // clang-format off 36 // clang-format off
33 static const FunctionInfo functions[] = { 37 static const FunctionInfo functions[] = {
34 {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, 38 {0, C<&IJitEnvironment::GenerateCode>, "GenerateCode"},
35 {1, &IJitEnvironment::Control, "Control"}, 39 {1, C<&IJitEnvironment::Control>, "Control"},
36 {1000, &IJitEnvironment::LoadPlugin, "LoadPlugin"}, 40 {1000, C<&IJitEnvironment::LoadPlugin>, "LoadPlugin"},
37 {1001, &IJitEnvironment::GetCodeAddress, "GetCodeAddress"}, 41 {1001, C<&IJitEnvironment::GetCodeAddress>, "GetCodeAddress"},
38 }; 42 };
39 // clang-format on 43 // clang-format on
40 44
@@ -50,28 +54,10 @@ public:
50 configuration.sys_ro_memory = configuration.user_ro_memory; 54 configuration.sys_ro_memory = configuration.user_ro_memory;
51 } 55 }
52 56
53 void GenerateCode(HLERequestContext& ctx) { 57 Result GenerateCode(Out<s32> out_return_value, Out<CodeRange> out_range0,
54 LOG_DEBUG(Service_JIT, "called"); 58 Out<CodeRange> out_range1, OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
55 59 u32 data_size, u64 command, CodeRange range0, CodeRange range1,
56 struct InputParameters { 60 Struct32 data, InBuffer<BufferAttr_HipcMapAlias> buffer) {
57 u32 data_size;
58 u64 command;
59 std::array<CodeRange, 2> ranges;
60 Struct32 data;
61 };
62
63 struct OutputParameters {
64 s32 return_value;
65 std::array<CodeRange, 2> ranges;
66 };
67
68 IPC::RequestParser rp{ctx};
69 const auto parameters{rp.PopRaw<InputParameters>()};
70
71 // Optional input/output buffers
72 const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()};
73 std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0);
74
75 // Function call prototype: 61 // Function call prototype:
76 // void GenerateCode(s32* ret, CodeRange* c0_out, CodeRange* c1_out, JITConfiguration* cfg, 62 // void GenerateCode(s32* ret, CodeRange* c0_out, CodeRange* c1_out, JITConfiguration* cfg,
77 // u64 cmd, u8* input_buf, size_t input_size, CodeRange* c0_in, 63 // u64 cmd, u8* input_buf, size_t input_size, CodeRange* c0_in,
@@ -83,66 +69,36 @@ public:
83 // other arguments are used to transfer state between the game and the plugin. 69 // other arguments are used to transfer state between the game and the plugin.
84 70
85 const VAddr ret_ptr{context.AddHeap(0u)}; 71 const VAddr ret_ptr{context.AddHeap(0u)};
86 const VAddr c0_in_ptr{context.AddHeap(parameters.ranges[0])}; 72 const VAddr c0_in_ptr{context.AddHeap(range0)};
87 const VAddr c1_in_ptr{context.AddHeap(parameters.ranges[1])}; 73 const VAddr c1_in_ptr{context.AddHeap(range1)};
88 const VAddr c0_out_ptr{context.AddHeap(ClearSize(parameters.ranges[0]))}; 74 const VAddr c0_out_ptr{context.AddHeap(ClearSize(range0))};
89 const VAddr c1_out_ptr{context.AddHeap(ClearSize(parameters.ranges[1]))}; 75 const VAddr c1_out_ptr{context.AddHeap(ClearSize(range1))};
90 76
91 const VAddr input_ptr{context.AddHeap(input_buffer.data(), input_buffer.size())}; 77 const VAddr input_ptr{context.AddHeap(buffer.data(), buffer.size())};
92 const VAddr output_ptr{context.AddHeap(output_buffer.data(), output_buffer.size())}; 78 const VAddr output_ptr{context.AddHeap(out_buffer.data(), out_buffer.size())};
93 const VAddr data_ptr{context.AddHeap(parameters.data)}; 79 const VAddr data_ptr{context.AddHeap(data)};
94 const VAddr configuration_ptr{context.AddHeap(configuration)}; 80 const VAddr configuration_ptr{context.AddHeap(configuration)};
95 81
96 // The callback does not directly return a value, it only writes to the output pointer 82 // The callback does not directly return a value, it only writes to the output pointer
97 context.CallFunction(callbacks.GenerateCode, ret_ptr, c0_out_ptr, c1_out_ptr, 83 context.CallFunction(callbacks.GenerateCode, ret_ptr, c0_out_ptr, c1_out_ptr,
98 configuration_ptr, parameters.command, input_ptr, input_buffer.size(), 84 configuration_ptr, command, input_ptr, buffer.size(), c0_in_ptr,
99 c0_in_ptr, c1_in_ptr, data_ptr, parameters.data_size, output_ptr, 85 c1_in_ptr, data_ptr, data_size, output_ptr, out_buffer.size());
100 output_buffer.size());
101
102 const s32 return_value{context.GetHeap<s32>(ret_ptr)};
103
104 if (return_value == 0) {
105 // The callback has written to the output executable code range,
106 // requiring an instruction cache invalidation
107 Core::InvalidateInstructionCacheRange(process.GetPointerUnsafe(),
108 configuration.user_rx_memory.offset,
109 configuration.user_rx_memory.size);
110
111 // Write back to the IPC output buffer, if provided
112 if (ctx.CanWriteBuffer()) {
113 context.GetHeap(output_ptr, output_buffer.data(), output_buffer.size());
114 ctx.WriteBuffer(output_buffer.data(), output_buffer.size());
115 }
116
117 const OutputParameters out{
118 .return_value = return_value,
119 .ranges =
120 {
121 context.GetHeap<CodeRange>(c0_out_ptr),
122 context.GetHeap<CodeRange>(c1_out_ptr),
123 },
124 };
125
126 IPC::ResponseBuilder rb{ctx, 8};
127 rb.Push(ResultSuccess);
128 rb.PushRaw(out);
129 } else {
130 LOG_WARNING(Service_JIT, "plugin GenerateCode callback failed");
131 IPC::ResponseBuilder rb{ctx, 2};
132 rb.Push(ResultUnknown);
133 }
134 };
135 86
136 void Control(HLERequestContext& ctx) { 87 *out_return_value = context.GetHeap<s32>(ret_ptr);
137 LOG_DEBUG(Service_JIT, "called"); 88 *out_range0 = context.GetHeap<CodeRange>(c0_out_ptr);
89 *out_range1 = context.GetHeap<CodeRange>(c1_out_ptr);
90 context.GetHeap(output_ptr, out_buffer.data(), out_buffer.size());
138 91
139 IPC::RequestParser rp{ctx}; 92 if (*out_return_value != 0) {
140 const auto command{rp.PopRaw<u64>()}; 93 LOG_WARNING(Service_JIT, "plugin GenerateCode callback failed");
94 R_THROW(ResultUnknown);
95 }
141 96
142 // Optional input/output buffers 97 R_SUCCEED();
143 const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()}; 98 }
144 std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0);
145 99
100 Result Control(Out<s32> out_return_value, InBuffer<BufferAttr_HipcMapAlias> in_data,
101 OutBuffer<BufferAttr_HipcMapAlias> out_data, u64 command) {
146 // Function call prototype: 102 // Function call prototype:
147 // u64 Control(s32* ret, JITConfiguration* cfg, u64 cmd, u8* input_buf, size_t input_size, 103 // u64 Control(s32* ret, JITConfiguration* cfg, u64 cmd, u8* input_buf, size_t input_size,
148 // u8* output_buf, size_t output_size); 104 // u8* output_buf, size_t output_size);
@@ -152,53 +108,30 @@ public:
152 108
153 const VAddr ret_ptr{context.AddHeap(0u)}; 109 const VAddr ret_ptr{context.AddHeap(0u)};
154 const VAddr configuration_ptr{context.AddHeap(configuration)}; 110 const VAddr configuration_ptr{context.AddHeap(configuration)};
155 const VAddr input_ptr{context.AddHeap(input_buffer.data(), input_buffer.size())}; 111 const VAddr input_ptr{context.AddHeap(in_data.data(), in_data.size())};
156 const VAddr output_ptr{context.AddHeap(output_buffer.data(), output_buffer.size())}; 112 const VAddr output_ptr{context.AddHeap(out_data.data(), out_data.size())};
157 113
158 const u64 wrapper_value{context.CallFunction(callbacks.Control, ret_ptr, configuration_ptr, 114 const u64 wrapper_value{context.CallFunction(callbacks.Control, ret_ptr, configuration_ptr,
159 command, input_ptr, input_buffer.size(), 115 command, input_ptr, in_data.size(), output_ptr,
160 output_ptr, output_buffer.size())}; 116 out_data.size())};
161
162 const s32 return_value{context.GetHeap<s32>(ret_ptr)};
163
164 if (wrapper_value == 0 && return_value == 0) {
165 // Write back to the IPC output buffer, if provided
166 if (ctx.CanWriteBuffer()) {
167 context.GetHeap(output_ptr, output_buffer.data(), output_buffer.size());
168 ctx.WriteBuffer(output_buffer.data(), output_buffer.size());
169 }
170
171 IPC::ResponseBuilder rb{ctx, 3};
172 rb.Push(ResultSuccess);
173 rb.Push(return_value);
174 } else {
175 LOG_WARNING(Service_JIT, "plugin Control callback failed");
176 IPC::ResponseBuilder rb{ctx, 2};
177 rb.Push(ResultUnknown);
178 }
179 }
180
181 void LoadPlugin(HLERequestContext& ctx) {
182 LOG_DEBUG(Service_JIT, "called");
183 117
184 IPC::RequestParser rp{ctx}; 118 *out_return_value = context.GetHeap<s32>(ret_ptr);
185 const auto tmem_size{rp.PopRaw<u64>()}; 119 context.GetHeap(output_ptr, out_data.data(), out_data.size());
186 const auto tmem_handle{ctx.GetCopyHandle(0)};
187 const auto nro_plugin{ctx.ReadBuffer(1)};
188 120
189 if (tmem_size == 0) { 121 if (wrapper_value == 0 && *out_return_value == 0) {
190 LOG_ERROR(Service_JIT, "attempted to load plugin with empty transfer memory"); 122 R_SUCCEED();
191 IPC::ResponseBuilder rb{ctx, 2};
192 rb.Push(ResultUnknown);
193 return;
194 } 123 }
195 124
196 auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)}; 125 LOG_WARNING(Service_JIT, "plugin Control callback failed");
126 R_THROW(ResultUnknown);
127 }
128
129 Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory>& tmem,
130 InBuffer<BufferAttr_HipcMapAlias> nrr,
131 InBuffer<BufferAttr_HipcMapAlias> nro) {
197 if (tmem.IsNull()) { 132 if (tmem.IsNull()) {
198 LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); 133 LOG_ERROR(Service_JIT, "Invalid transfer memory handle!");
199 IPC::ResponseBuilder rb{ctx, 2}; 134 R_THROW(ResultUnknown);
200 rb.Push(ResultUnknown);
201 return;
202 } 135 }
203 136
204 // Set up the configuration with the required TransferMemory address 137 // Set up the configuration with the required TransferMemory address
@@ -206,7 +139,7 @@ public:
206 configuration.transfer_memory.size = tmem_size; 139 configuration.transfer_memory.size = tmem_size;
207 140
208 // Gather up all the callbacks from the loaded plugin 141 // Gather up all the callbacks from the loaded plugin
209 auto symbols{Core::Symbols::GetSymbols(nro_plugin, true)}; 142 auto symbols{Core::Symbols::GetSymbols(nro, true)};
210 const auto GetSymbol{[&](const std::string& name) { return symbols[name].first; }}; 143 const auto GetSymbol{[&](const std::string& name) { return symbols[name].first; }};
211 144
212 callbacks.rtld_fini = GetSymbol("_fini"); 145 callbacks.rtld_fini = GetSymbol("_fini");
@@ -223,16 +156,12 @@ public:
223 if (callbacks.GetVersion == 0 || callbacks.Configure == 0 || callbacks.GenerateCode == 0 || 156 if (callbacks.GetVersion == 0 || callbacks.Configure == 0 || callbacks.GenerateCode == 0 ||
224 callbacks.OnPrepared == 0) { 157 callbacks.OnPrepared == 0) {
225 LOG_ERROR(Service_JIT, "plugin does not implement all necessary functionality"); 158 LOG_ERROR(Service_JIT, "plugin does not implement all necessary functionality");
226 IPC::ResponseBuilder rb{ctx, 2}; 159 R_THROW(ResultUnknown);
227 rb.Push(ResultUnknown);
228 return;
229 } 160 }
230 161
231 if (!context.LoadNRO(nro_plugin)) { 162 if (!context.LoadNRO(nro)) {
232 LOG_ERROR(Service_JIT, "failed to load plugin"); 163 LOG_ERROR(Service_JIT, "failed to load plugin");
233 IPC::ResponseBuilder rb{ctx, 2}; 164 R_THROW(ResultUnknown);
234 rb.Push(ResultUnknown);
235 return;
236 } 165 }
237 166
238 context.MapProcessMemory(configuration.sys_ro_memory.offset, 167 context.MapProcessMemory(configuration.sys_ro_memory.offset,
@@ -252,9 +181,7 @@ public:
252 const auto version{context.CallFunction(callbacks.GetVersion)}; 181 const auto version{context.CallFunction(callbacks.GetVersion)};
253 if (version != 1) { 182 if (version != 1) {
254 LOG_ERROR(Service_JIT, "unknown plugin version {}", version); 183 LOG_ERROR(Service_JIT, "unknown plugin version {}", version);
255 IPC::ResponseBuilder rb{ctx, 2}; 184 R_THROW(ResultUnknown);
256 rb.Push(ResultUnknown);
257 return;
258 } 185 }
259 186
260 // Function prototype: 187 // Function prototype:
@@ -280,22 +207,19 @@ public:
280 const auto configuration_ptr{context.AddHeap(configuration)}; 207 const auto configuration_ptr{context.AddHeap(configuration)};
281 context.CallFunction(callbacks.OnPrepared, configuration_ptr); 208 context.CallFunction(callbacks.OnPrepared, configuration_ptr);
282 209
283 IPC::ResponseBuilder rb{ctx, 2}; 210 R_SUCCEED();
284 rb.Push(ResultSuccess);
285 } 211 }
286 212
287 void GetCodeAddress(HLERequestContext& ctx) { 213 Result GetCodeAddress(Out<u64> rx_offset, Out<u64> ro_offset) {
288 LOG_DEBUG(Service_JIT, "called"); 214 LOG_DEBUG(Service_JIT, "called");
289 215
290 IPC::ResponseBuilder rb{ctx, 6}; 216 *rx_offset = configuration.user_rx_memory.offset;
291 rb.Push(ResultSuccess); 217 *ro_offset = configuration.user_ro_memory.offset;
292 rb.Push(configuration.user_rx_memory.offset); 218
293 rb.Push(configuration.user_ro_memory.offset); 219 R_SUCCEED();
294 } 220 }
295 221
296private: 222private:
297 using Struct32 = std::array<u8, 32>;
298
299 struct GuestCallbacks { 223 struct GuestCallbacks {
300 VAddr rtld_fini; 224 VAddr rtld_fini;
301 VAddr rtld_init; 225 VAddr rtld_init;
@@ -335,7 +259,7 @@ public:
335 explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} { 259 explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} {
336 // clang-format off 260 // clang-format off
337 static const FunctionInfo functions[] = { 261 static const FunctionInfo functions[] = {
338 {0, &JITU::CreateJitEnvironment, "CreateJitEnvironment"}, 262 {0, C<&JITU::CreateJitEnvironment>, "CreateJitEnvironment"},
339 }; 263 };
340 // clang-format on 264 // clang-format on
341 265
@@ -343,76 +267,33 @@ public:
343 } 267 }
344 268
345private: 269private:
346 void CreateJitEnvironment(HLERequestContext& ctx) { 270 Result CreateJitEnvironment(Out<SharedPointer<IJitEnvironment>> out_jit_environment,
347 LOG_DEBUG(Service_JIT, "called"); 271 u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess>& process,
348 272 InCopyHandle<Kernel::KCodeMemory>& rx_mem,
349 struct Parameters { 273 InCopyHandle<Kernel::KCodeMemory>& ro_mem) {
350 u64 rx_size;
351 u64 ro_size;
352 };
353
354 IPC::RequestParser rp{ctx};
355 const auto parameters{rp.PopRaw<Parameters>()};
356 const auto process_handle{ctx.GetCopyHandle(0)};
357 const auto rx_mem_handle{ctx.GetCopyHandle(1)};
358 const auto ro_mem_handle{ctx.GetCopyHandle(2)};
359
360 if (parameters.rx_size == 0 || parameters.ro_size == 0) {
361 LOG_ERROR(Service_JIT, "attempted to init with empty code regions");
362 IPC::ResponseBuilder rb{ctx, 2};
363 rb.Push(ResultUnknown);
364 return;
365 }
366
367 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
368 if (process.IsNull()) { 274 if (process.IsNull()) {
369 LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); 275 LOG_ERROR(Service_JIT, "process is null");
370 IPC::ResponseBuilder rb{ctx, 2}; 276 R_THROW(ResultUnknown);
371 rb.Push(ResultUnknown);
372 return;
373 } 277 }
374
375 auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)};
376 if (rx_mem.IsNull()) { 278 if (rx_mem.IsNull()) {
377 LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); 279 LOG_ERROR(Service_JIT, "rx_mem is null");
378 IPC::ResponseBuilder rb{ctx, 2}; 280 R_THROW(ResultUnknown);
379 rb.Push(ResultUnknown);
380 return;
381 } 281 }
382 282 if (rx_mem.IsNull()) {
383 auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)}; 283 LOG_ERROR(Service_JIT, "ro_mem is null");
384 if (ro_mem.IsNull()) { 284 R_THROW(ResultUnknown);
385 LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle);
386 IPC::ResponseBuilder rb{ctx, 2};
387 rb.Push(ResultUnknown);
388 return;
389 } 285 }
390 286
391 CodeMemory rx, ro; 287 CodeMemory rx, ro;
392 Result res;
393
394 res = rx.Initialize(*process, *rx_mem, parameters.rx_size,
395 Kernel::Svc::MemoryPermission::ReadExecute, generate_random);
396 if (R_FAILED(res)) {
397 LOG_ERROR(Service_JIT, "rx_mem could not be mapped for handle=0x{:08X}", rx_mem_handle);
398 IPC::ResponseBuilder rb{ctx, 2};
399 rb.Push(res);
400 return;
401 }
402 288
403 res = ro.Initialize(*process, *ro_mem, parameters.ro_size, 289 R_TRY(rx.Initialize(*process, *rx_mem, rx_size, Kernel::Svc::MemoryPermission::ReadExecute,
404 Kernel::Svc::MemoryPermission::Read, generate_random); 290 generate_random));
405 if (R_FAILED(res)) { 291 R_TRY(ro.Initialize(*process, *ro_mem, ro_size, Kernel::Svc::MemoryPermission::Read,
406 LOG_ERROR(Service_JIT, "ro_mem could not be mapped for handle=0x{:08X}", ro_mem_handle); 292 generate_random));
407 IPC::ResponseBuilder rb{ctx, 2};
408 rb.Push(res);
409 return;
410 }
411 293
412 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 294 *out_jit_environment = std::make_shared<IJitEnvironment>(system, std::move(process),
413 rb.Push(ResultSuccess); 295 std::move(rx), std::move(ro));
414 rb.PushIpcInterface<IJitEnvironment>(system, std::move(process), std::move(rx), 296 R_SUCCEED();
415 std::move(ro));
416 } 297 }
417 298
418private: 299private:
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
index f51e63564..f080f7ffa 100644
--- a/src/core/hle/service/kernel_helpers.cpp
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -65,6 +65,9 @@ Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
65} 65}
66 66
67void ServiceContext::CloseEvent(Kernel::KEvent* event) { 67void ServiceContext::CloseEvent(Kernel::KEvent* event) {
68 if (!event) {
69 return;
70 }
68 event->GetReadableEvent().Close(); 71 event->GetReadableEvent().Close();
69 event->Close(); 72 event->Close();
70} 73}
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index cc7776efc..1e2d2d212 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -1,6 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/glue/time/static.h"
5#include "core/hle/service/psc/time/steady_clock.h"
4#ifdef _MSC_VER 6#ifdef _MSC_VER
5#pragma warning(push) 7#pragma warning(push)
6#pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used 8#pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used
@@ -29,7 +31,8 @@
29#include "core/hle/service/nfc/common/device.h" 31#include "core/hle/service/nfc/common/device.h"
30#include "core/hle/service/nfc/mifare_result.h" 32#include "core/hle/service/nfc/mifare_result.h"
31#include "core/hle/service/nfc/nfc_result.h" 33#include "core/hle/service/nfc/nfc_result.h"
32#include "core/hle/service/time/time_manager.h" 34#include "core/hle/service/service.h"
35#include "core/hle/service/sm/sm.h"
33#include "hid_core/frontend/emulated_controller.h" 36#include "hid_core/frontend/emulated_controller.h"
34#include "hid_core/hid_core.h" 37#include "hid_core/hid_core.h"
35#include "hid_core/hid_types.h" 38#include "hid_core/hid_types.h"
@@ -393,8 +396,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
393 return result; 396 return result;
394} 397}
395 398
396Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, 399Result NfcDevice::SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data,
397 std::span<const u8> command_data,
398 std::span<u8> out_data) { 400 std::span<u8> out_data) {
399 // Not implemented 401 // Not implemented
400 return ResultSuccess; 402 return ResultSuccess;
@@ -1399,27 +1401,41 @@ void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
1399} 1401}
1400 1402
1401NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const { 1403NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
1402 const auto& time_zone_manager = 1404 auto static_service =
1403 system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); 1405 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
1404 Time::TimeZone::CalendarInfo calendar_info{}; 1406
1407 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{};
1408 static_service->GetTimeZoneService(timezone_service);
1409
1410 Service::PSC::Time::CalendarTime calendar_time{};
1411 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
1412
1405 NFP::AmiiboDate amiibo_date{}; 1413 NFP::AmiiboDate amiibo_date{};
1406 1414
1407 amiibo_date.SetYear(2000); 1415 amiibo_date.SetYear(2000);
1408 amiibo_date.SetMonth(1); 1416 amiibo_date.SetMonth(1);
1409 amiibo_date.SetDay(1); 1417 amiibo_date.SetDay(1);
1410 1418
1411 if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) { 1419 if (timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time) ==
1412 amiibo_date.SetYear(calendar_info.time.year); 1420 ResultSuccess) {
1413 amiibo_date.SetMonth(calendar_info.time.month); 1421 amiibo_date.SetYear(calendar_time.year);
1414 amiibo_date.SetDay(calendar_info.time.day); 1422 amiibo_date.SetMonth(calendar_time.month);
1423 amiibo_date.SetDay(calendar_time.day);
1415 } 1424 }
1416 1425
1417 return amiibo_date; 1426 return amiibo_date;
1418} 1427}
1419 1428
1420u64 NfcDevice::GetCurrentPosixTime() const { 1429s64 NfcDevice::GetCurrentPosixTime() const {
1421 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; 1430 auto static_service =
1422 return standard_steady_clock.GetCurrentTimePoint(system).time_point; 1431 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
1432
1433 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
1434 static_service->GetStandardSteadyClock(steady_clock);
1435
1436 Service::PSC::Time::SteadyClockTimePoint time_point{};
1437 R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
1438 return time_point.time_point;
1423} 1439}
1424 1440
1425u64 NfcDevice::RemoveVersionByte(u64 application_id) const { 1441u64 NfcDevice::RemoveVersionByte(u64 application_id) const {
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 15f9b25da..d59202d18 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -11,7 +11,6 @@
11#include "core/hle/service/nfc/nfc_types.h" 11#include "core/hle/service/nfc/nfc_types.h"
12#include "core/hle/service/nfp/nfp_types.h" 12#include "core/hle/service/nfp/nfp_types.h"
13#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
14#include "core/hle/service/time/clock_types.h"
15 14
16namespace Kernel { 15namespace Kernel {
17class KEvent; 16class KEvent;
@@ -49,8 +48,8 @@ public:
49 48
50 Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); 49 Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
51 50
52 Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, 51 Result SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data,
53 std::span<const u8> command_data, std::span<u8> out_data); 52 std::span<u8> out_data);
54 53
55 Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target); 54 Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
56 Result Unmount(); 55 Result Unmount();
@@ -108,7 +107,7 @@ private:
108 NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; 107 NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
109 void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const; 108 void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const;
110 NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const; 109 NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
111 u64 GetCurrentPosixTime() const; 110 s64 GetCurrentPosixTime() const;
112 u64 RemoveVersionByte(u64 application_id) const; 111 u64 RemoveVersionByte(u64 application_id) const;
113 void UpdateSettingsCrc(); 112 void UpdateSettingsCrc();
114 void UpdateRegisterInfoCrc(); 113 void UpdateRegisterInfoCrc();
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index 44f651b87..b60699c45 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -6,12 +6,14 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/glue/time/static.h"
9#include "core/hle/service/ipc_helpers.h" 10#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/nfc/common/device.h" 11#include "core/hle/service/nfc/common/device.h"
11#include "core/hle/service/nfc/common/device_manager.h" 12#include "core/hle/service/nfc/common/device_manager.h"
12#include "core/hle/service/nfc/nfc_result.h" 13#include "core/hle/service/nfc/nfc_result.h"
13#include "core/hle/service/time/clock_types.h" 14#include "core/hle/service/psc/time/steady_clock.h"
14#include "core/hle/service/time/time_manager.h" 15#include "core/hle/service/service.h"
16#include "core/hle/service/sm/sm.h"
15#include "hid_core/hid_types.h" 17#include "hid_core/hid_types.h"
16#include "hid_core/hid_util.h" 18#include "hid_core/hid_util.h"
17 19
@@ -82,11 +84,19 @@ Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max
82 continue; 84 continue;
83 } 85 }
84 if (skip_fatal_errors) { 86 if (skip_fatal_errors) {
85 constexpr u64 MinimumRecoveryTime = 60; 87 constexpr s64 MinimumRecoveryTime = 60;
86 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
87 const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point -
88 time_since_last_error;
89 88
89 auto static_service =
90 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u",
91 true);
92
93 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
94 static_service->GetStandardSteadyClock(steady_clock);
95
96 Service::PSC::Time::SteadyClockTimePoint time_point{};
97 R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
98
99 const s64 elapsed_time = time_point.time_point - time_since_last_error;
90 if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) { 100 if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) {
91 continue; 101 continue;
92 } 102 }
@@ -250,8 +260,7 @@ Result DeviceManager::WriteMifare(u64 device_handle,
250 return result; 260 return result;
251} 261}
252 262
253Result DeviceManager::SendCommandByPassThrough(u64 device_handle, 263Result DeviceManager::SendCommandByPassThrough(u64 device_handle, const s64& timeout,
254 const Time::Clock::TimeSpanType& timeout,
255 std::span<const u8> command_data, 264 std::span<const u8> command_data,
256 std::span<u8> out_data) { 265 std::span<u8> out_data) {
257 std::scoped_lock lock{mutex}; 266 std::scoped_lock lock{mutex};
@@ -741,8 +750,16 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
741 750
742 if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 || 751 if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 ||
743 operation_result == ResultUnknown115) { 752 operation_result == ResultUnknown115) {
744 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; 753 auto static_service =
745 time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point; 754 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
755
756 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
757 static_service->GetStandardSteadyClock(steady_clock);
758
759 Service::PSC::Time::SteadyClockTimePoint time_point{};
760 R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
761
762 time_since_last_error = time_point.time_point;
746 } 763 }
747 764
748 return operation_result; 765 return operation_result;
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
index f02bdccf5..c56a2fbda 100644
--- a/src/core/hle/service/nfc/common/device_manager.h
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -13,7 +13,6 @@
13#include "core/hle/service/nfc/nfc_types.h" 13#include "core/hle/service/nfc/nfc_types.h"
14#include "core/hle/service/nfp/nfp_types.h" 14#include "core/hle/service/nfp/nfp_types.h"
15#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
16#include "core/hle/service/time/clock_types.h"
17#include "hid_core/hid_types.h" 16#include "hid_core/hid_types.h"
18 17
19namespace Service::NFC { 18namespace Service::NFC {
@@ -42,7 +41,7 @@ public:
42 std::span<MifareReadBlockData> read_data); 41 std::span<MifareReadBlockData> read_data);
43 Result WriteMifare(u64 device_handle, 42 Result WriteMifare(u64 device_handle,
44 std::span<const MifareWriteBlockParameter> write_parameters); 43 std::span<const MifareWriteBlockParameter> write_parameters);
45 Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout, 44 Result SendCommandByPassThrough(u64 device_handle, const s64& timeout,
46 std::span<const u8> command_data, std::span<u8> out_data); 45 std::span<const u8> command_data, std::span<u8> out_data);
47 46
48 // Nfp device manager 47 // Nfp device manager
@@ -92,7 +91,7 @@ private:
92 const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const; 91 const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
93 92
94 bool is_initialized = false; 93 bool is_initialized = false;
95 u64 time_since_last_error = 0; 94 s64 time_since_last_error = 0;
96 mutable std::mutex mutex; 95 mutable std::mutex mutex;
97 std::array<std::shared_ptr<NfcDevice>, 10> devices{}; 96 std::array<std::shared_ptr<NfcDevice>, 10> devices{};
98 97
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index a71cf74b8..207ac4efe 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -13,7 +13,6 @@
13#include "core/hle/service/nfc/nfc_result.h" 13#include "core/hle/service/nfc/nfc_result.h"
14#include "core/hle/service/nfc/nfc_types.h" 14#include "core/hle/service/nfc/nfc_types.h"
15#include "core/hle/service/nfp/nfp_result.h" 15#include "core/hle/service/nfp/nfp_result.h"
16#include "core/hle/service/time/clock_types.h"
17#include "hid_core/hid_types.h" 16#include "hid_core/hid_types.h"
18 17
19namespace Service::NFC { 18namespace Service::NFC {
@@ -261,10 +260,10 @@ void NfcInterface::WriteMifare(HLERequestContext& ctx) {
261void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) { 260void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) {
262 IPC::RequestParser rp{ctx}; 261 IPC::RequestParser rp{ctx};
263 const auto device_handle{rp.Pop<u64>()}; 262 const auto device_handle{rp.Pop<u64>()};
264 const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()}; 263 const auto timeout{rp.PopRaw<s64>()};
265 const auto command_data{ctx.ReadBuffer()}; 264 const auto command_data{ctx.ReadBuffer()};
266 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}", 265 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
267 device_handle, timeout.ToSeconds(), command_data.size()); 266 device_handle, timeout, command_data.size());
268 267
269 std::vector<u8> out_data(1); 268 std::vector<u8> out_data(1);
270 auto result = 269 auto result =
diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp
index b1a7686ff..d187be935 100644
--- a/src/core/hle/service/ns/language.cpp
+++ b/src/core/hle/service/ns/language.cpp
@@ -415,4 +415,4 @@ std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage
415 return std::nullopt; 415 return std::nullopt;
416 } 416 }
417} 417}
418} // namespace Service::NS \ No newline at end of file 418} // namespace Service::NS
diff --git a/src/core/hle/service/ns/language.h b/src/core/hle/service/ns/language.h
index ab6b71029..dad9934f2 100644
--- a/src/core/hle/service/ns/language.h
+++ b/src/core/hle/service/ns/language.h
@@ -5,10 +5,7 @@
5 5
6#include <optional> 6#include <optional>
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8#include "core/hle/service/set/system_settings_server.h"
9namespace Service::Set {
10enum class LanguageCode : u64;
11}
12 9
13namespace Service::NS { 10namespace Service::NS {
14/// This is nn::ns::detail::ApplicationLanguage 11/// This is nn::ns::detail::ApplicationLanguage
diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp
index 37ca24f5d..21ef57d27 100644
--- a/src/core/hle/service/nvdrv/core/container.cpp
+++ b/src/core/hle/service/nvdrv/core/container.cpp
@@ -2,27 +2,135 @@
2// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors 2// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors
3// SPDX-License-Identifier: GPL-3.0-or-later 3// SPDX-License-Identifier: GPL-3.0-or-later
4 4
5#include <atomic>
6#include <deque>
7#include <mutex>
8
9#include "core/hle/kernel/k_process.h"
5#include "core/hle/service/nvdrv/core/container.h" 10#include "core/hle/service/nvdrv/core/container.h"
11#include "core/hle/service/nvdrv/core/heap_mapper.h"
6#include "core/hle/service/nvdrv/core/nvmap.h" 12#include "core/hle/service/nvdrv/core/nvmap.h"
7#include "core/hle/service/nvdrv/core/syncpoint_manager.h" 13#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
14#include "core/memory.h"
8#include "video_core/host1x/host1x.h" 15#include "video_core/host1x/host1x.h"
9 16
10namespace Service::Nvidia::NvCore { 17namespace Service::Nvidia::NvCore {
11 18
19Session::Session(SessionId id_, Kernel::KProcess* process_, Core::Asid asid_)
20 : id{id_}, process{process_}, asid{asid_}, has_preallocated_area{}, mapper{}, is_active{} {}
21
22Session::~Session() = default;
23
12struct ContainerImpl { 24struct ContainerImpl {
13 explicit ContainerImpl(Tegra::Host1x::Host1x& host1x_) 25 explicit ContainerImpl(Container& core, Tegra::Host1x::Host1x& host1x_)
14 : file{host1x_}, manager{host1x_}, device_file_data{} {} 26 : host1x{host1x_}, file{core, host1x_}, manager{host1x_}, device_file_data{} {}
27 Tegra::Host1x::Host1x& host1x;
15 NvMap file; 28 NvMap file;
16 SyncpointManager manager; 29 SyncpointManager manager;
17 Container::Host1xDeviceFileData device_file_data; 30 Container::Host1xDeviceFileData device_file_data;
31 std::deque<Session> sessions;
32 size_t new_ids{};
33 std::deque<size_t> id_pool;
34 std::mutex session_guard;
18}; 35};
19 36
20Container::Container(Tegra::Host1x::Host1x& host1x_) { 37Container::Container(Tegra::Host1x::Host1x& host1x_) {
21 impl = std::make_unique<ContainerImpl>(host1x_); 38 impl = std::make_unique<ContainerImpl>(*this, host1x_);
22} 39}
23 40
24Container::~Container() = default; 41Container::~Container() = default;
25 42
43SessionId Container::OpenSession(Kernel::KProcess* process) {
44 using namespace Common::Literals;
45
46 std::scoped_lock lk(impl->session_guard);
47 for (auto& session : impl->sessions) {
48 if (!session.is_active) {
49 continue;
50 }
51 if (session.process == process) {
52 return session.id;
53 }
54 }
55 size_t new_id{};
56 auto* memory_interface = &process->GetMemory();
57 auto& smmu = impl->host1x.MemoryManager();
58 auto asid = smmu.RegisterProcess(memory_interface);
59 if (!impl->id_pool.empty()) {
60 new_id = impl->id_pool.front();
61 impl->id_pool.pop_front();
62 impl->sessions[new_id] = Session{SessionId{new_id}, process, asid};
63 } else {
64 new_id = impl->new_ids++;
65 impl->sessions.emplace_back(SessionId{new_id}, process, asid);
66 }
67 auto& session = impl->sessions[new_id];
68 session.is_active = true;
69 // Optimization
70 if (process->IsApplication()) {
71 auto& page_table = process->GetPageTable().GetBasePageTable();
72 auto heap_start = page_table.GetHeapRegionStart();
73
74 Kernel::KProcessAddress cur_addr = heap_start;
75 size_t region_size = 0;
76 VAddr region_start = 0;
77 while (true) {
78 Kernel::KMemoryInfo mem_info{};
79 Kernel::Svc::PageInfo page_info{};
80 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info),
81 cur_addr));
82 auto svc_mem_info = mem_info.GetSvcMemoryInfo();
83
84 // Check if this memory block is heap.
85 if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) {
86 if (svc_mem_info.size > region_size) {
87 region_size = svc_mem_info.size;
88 region_start = svc_mem_info.base_address;
89 }
90 }
91
92 // Check if we're done.
93 const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size;
94 if (next_address <= GetInteger(cur_addr)) {
95 break;
96 }
97
98 cur_addr = next_address;
99 }
100 session.has_preallocated_area = false;
101 auto start_region = region_size >= 32_MiB ? smmu.Allocate(region_size) : 0;
102 if (start_region != 0) {
103 session.mapper = std::make_unique<HeapMapper>(region_start, start_region, region_size,
104 asid, impl->host1x);
105 smmu.TrackContinuity(start_region, region_start, region_size, asid);
106 session.has_preallocated_area = true;
107 LOG_DEBUG(Debug, "Preallocation created!");
108 }
109 }
110 return SessionId{new_id};
111}
112
113void Container::CloseSession(SessionId session_id) {
114 std::scoped_lock lk(impl->session_guard);
115 auto& session = impl->sessions[session_id.id];
116 auto& smmu = impl->host1x.MemoryManager();
117 if (session.has_preallocated_area) {
118 const DAddr region_start = session.mapper->GetRegionStart();
119 const size_t region_size = session.mapper->GetRegionSize();
120 session.mapper.reset();
121 smmu.Free(region_start, region_size);
122 session.has_preallocated_area = false;
123 }
124 session.is_active = false;
125 smmu.UnregisterProcess(impl->sessions[session_id.id].asid);
126 impl->id_pool.emplace_front(session_id.id);
127}
128
129Session* Container::GetSession(SessionId session_id) {
130 std::atomic_thread_fence(std::memory_order_acquire);
131 return &impl->sessions[session_id.id];
132}
133
26NvMap& Container::GetNvMapFile() { 134NvMap& Container::GetNvMapFile() {
27 return impl->file; 135 return impl->file;
28} 136}
diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h
index b4b63ac90..b4d3938a8 100644
--- a/src/core/hle/service/nvdrv/core/container.h
+++ b/src/core/hle/service/nvdrv/core/container.h
@@ -8,24 +8,56 @@
8#include <memory> 8#include <memory>
9#include <unordered_map> 9#include <unordered_map>
10 10
11#include "core/device_memory_manager.h"
11#include "core/hle/service/nvdrv/nvdata.h" 12#include "core/hle/service/nvdrv/nvdata.h"
12 13
14namespace Kernel {
15class KProcess;
16}
17
13namespace Tegra::Host1x { 18namespace Tegra::Host1x {
14class Host1x; 19class Host1x;
15} // namespace Tegra::Host1x 20} // namespace Tegra::Host1x
16 21
17namespace Service::Nvidia::NvCore { 22namespace Service::Nvidia::NvCore {
18 23
24class HeapMapper;
19class NvMap; 25class NvMap;
20class SyncpointManager; 26class SyncpointManager;
21 27
22struct ContainerImpl; 28struct ContainerImpl;
23 29
30struct SessionId {
31 size_t id;
32};
33
34struct Session {
35 Session(SessionId id_, Kernel::KProcess* process_, Core::Asid asid_);
36 ~Session();
37
38 Session(const Session&) = delete;
39 Session& operator=(const Session&) = delete;
40 Session(Session&&) = default;
41 Session& operator=(Session&&) = default;
42
43 SessionId id;
44 Kernel::KProcess* process;
45 Core::Asid asid;
46 bool has_preallocated_area{};
47 std::unique_ptr<HeapMapper> mapper{};
48 bool is_active{};
49};
50
24class Container { 51class Container {
25public: 52public:
26 explicit Container(Tegra::Host1x::Host1x& host1x); 53 explicit Container(Tegra::Host1x::Host1x& host1x);
27 ~Container(); 54 ~Container();
28 55
56 SessionId OpenSession(Kernel::KProcess* process);
57 void CloseSession(SessionId id);
58
59 Session* GetSession(SessionId id);
60
29 NvMap& GetNvMapFile(); 61 NvMap& GetNvMapFile();
30 62
31 const NvMap& GetNvMapFile() const; 63 const NvMap& GetNvMapFile() const;
diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.cpp b/src/core/hle/service/nvdrv/core/heap_mapper.cpp
new file mode 100644
index 000000000..096dc5deb
--- /dev/null
+++ b/src/core/hle/service/nvdrv/core/heap_mapper.cpp
@@ -0,0 +1,175 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <mutex>
5
6#include <boost/container/small_vector.hpp>
7#define BOOST_NO_MT
8#include <boost/pool/detail/mutex.hpp>
9#undef BOOST_NO_MT
10#include <boost/icl/interval.hpp>
11#include <boost/icl/interval_base_set.hpp>
12#include <boost/icl/interval_set.hpp>
13#include <boost/icl/split_interval_map.hpp>
14#include <boost/pool/pool.hpp>
15#include <boost/pool/pool_alloc.hpp>
16#include <boost/pool/poolfwd.hpp>
17
18#include "core/hle/service/nvdrv/core/heap_mapper.h"
19#include "video_core/host1x/host1x.h"
20
21namespace boost {
22template <typename T>
23class fast_pool_allocator<T, default_user_allocator_new_delete, details::pool::null_mutex, 4096, 0>;
24}
25
26namespace Service::Nvidia::NvCore {
27
28using IntervalCompare = std::less<DAddr>;
29using IntervalInstance = boost::icl::interval_type_default<DAddr, std::less>;
30using IntervalAllocator = boost::fast_pool_allocator<DAddr>;
31using IntervalSet = boost::icl::interval_set<DAddr>;
32using IntervalType = typename IntervalSet::interval_type;
33
34template <typename Type>
35struct counter_add_functor : public boost::icl::identity_based_inplace_combine<Type> {
36 // types
37 typedef counter_add_functor<Type> type;
38 typedef boost::icl::identity_based_inplace_combine<Type> base_type;
39
40 // public member functions
41 void operator()(Type& current, const Type& added) const {
42 current += added;
43 if (current < base_type::identity_element()) {
44 current = base_type::identity_element();
45 }
46 }
47
48 // public static functions
49 static void version(Type&){};
50};
51
52using OverlapCombine = counter_add_functor<int>;
53using OverlapSection = boost::icl::inter_section<int>;
54using OverlapCounter = boost::icl::split_interval_map<DAddr, int>;
55
56struct HeapMapper::HeapMapperInternal {
57 HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : device_memory{host1x.MemoryManager()} {}
58 ~HeapMapperInternal() = default;
59
60 template <typename Func>
61 void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size,
62 Func&& func) {
63 const DAddr start_address = cpu_addr;
64 const DAddr end_address = start_address + size;
65 const IntervalType search_interval{start_address, end_address};
66 auto it = current_range.lower_bound(search_interval);
67 if (it == current_range.end()) {
68 return;
69 }
70 auto end_it = current_range.upper_bound(search_interval);
71 for (; it != end_it; it++) {
72 auto& inter = it->first;
73 DAddr inter_addr_end = inter.upper();
74 DAddr inter_addr = inter.lower();
75 if (inter_addr_end > end_address) {
76 inter_addr_end = end_address;
77 }
78 if (inter_addr < start_address) {
79 inter_addr = start_address;
80 }
81 func(inter_addr, inter_addr_end, it->second);
82 }
83 }
84
85 void RemoveEachInOverlapCounter(OverlapCounter& current_range,
86 const IntervalType search_interval, int subtract_value) {
87 bool any_removals = false;
88 current_range.add(std::make_pair(search_interval, subtract_value));
89 do {
90 any_removals = false;
91 auto it = current_range.lower_bound(search_interval);
92 if (it == current_range.end()) {
93 return;
94 }
95 auto end_it = current_range.upper_bound(search_interval);
96 for (; it != end_it; it++) {
97 if (it->second <= 0) {
98 any_removals = true;
99 current_range.erase(it);
100 break;
101 }
102 }
103 } while (any_removals);
104 }
105
106 IntervalSet base_set;
107 OverlapCounter mapping_overlaps;
108 Tegra::MaxwellDeviceMemoryManager& device_memory;
109 std::mutex guard;
110};
111
112HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid,
113 Tegra::Host1x::Host1x& host1x)
114 : m_vaddress{start_vaddress}, m_daddress{start_daddress}, m_size{size}, m_asid{asid} {
115 m_internal = std::make_unique<HeapMapperInternal>(host1x);
116}
117
118HeapMapper::~HeapMapper() {
119 m_internal->device_memory.Unmap(m_daddress, m_size);
120}
121
122DAddr HeapMapper::Map(VAddr start, size_t size) {
123 std::scoped_lock lk(m_internal->guard);
124 m_internal->base_set.clear();
125 const IntervalType interval{start, start + size};
126 m_internal->base_set.insert(interval);
127 m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
128 [this](VAddr start_addr, VAddr end_addr, int) {
129 const IntervalType other{start_addr, end_addr};
130 m_internal->base_set.subtract(other);
131 });
132 if (!m_internal->base_set.empty()) {
133 auto it = m_internal->base_set.begin();
134 auto end_it = m_internal->base_set.end();
135 for (; it != end_it; it++) {
136 const VAddr inter_addr_end = it->upper();
137 const VAddr inter_addr = it->lower();
138 const size_t offset = inter_addr - m_vaddress;
139 const size_t sub_size = inter_addr_end - inter_addr;
140 m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size,
141 m_asid);
142 }
143 }
144 m_internal->mapping_overlaps += std::make_pair(interval, 1);
145 m_internal->base_set.clear();
146 return m_daddress + (start - m_vaddress);
147}
148
149void HeapMapper::Unmap(VAddr start, size_t size) {
150 std::scoped_lock lk(m_internal->guard);
151 m_internal->base_set.clear();
152 m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
153 [this](VAddr start_addr, VAddr end_addr, int value) {
154 if (value <= 1) {
155 const IntervalType other{start_addr, end_addr};
156 m_internal->base_set.insert(other);
157 }
158 });
159 if (!m_internal->base_set.empty()) {
160 auto it = m_internal->base_set.begin();
161 auto end_it = m_internal->base_set.end();
162 for (; it != end_it; it++) {
163 const VAddr inter_addr_end = it->upper();
164 const VAddr inter_addr = it->lower();
165 const size_t offset = inter_addr - m_vaddress;
166 const size_t sub_size = inter_addr_end - inter_addr;
167 m_internal->device_memory.Unmap(m_daddress + offset, sub_size);
168 }
169 }
170 const IntervalType to_remove{start, start + size};
171 m_internal->RemoveEachInOverlapCounter(m_internal->mapping_overlaps, to_remove, -1);
172 m_internal->base_set.clear();
173}
174
175} // namespace Service::Nvidia::NvCore
diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.h b/src/core/hle/service/nvdrv/core/heap_mapper.h
new file mode 100644
index 000000000..491a12e4f
--- /dev/null
+++ b/src/core/hle/service/nvdrv/core/heap_mapper.h
@@ -0,0 +1,49 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <memory>
7
8#include "common/common_types.h"
9#include "core/device_memory_manager.h"
10
11namespace Tegra::Host1x {
12class Host1x;
13} // namespace Tegra::Host1x
14
15namespace Service::Nvidia::NvCore {
16
17class HeapMapper {
18public:
19 HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid,
20 Tegra::Host1x::Host1x& host1x);
21 ~HeapMapper();
22
23 bool IsInBounds(VAddr start, size_t size) const {
24 VAddr end = start + size;
25 return start >= m_vaddress && end <= (m_vaddress + m_size);
26 }
27
28 DAddr Map(VAddr start, size_t size);
29
30 void Unmap(VAddr start, size_t size);
31
32 DAddr GetRegionStart() const {
33 return m_daddress;
34 }
35
36 size_t GetRegionSize() const {
37 return m_size;
38 }
39
40private:
41 struct HeapMapperInternal;
42 VAddr m_vaddress;
43 DAddr m_daddress;
44 size_t m_size;
45 Core::Asid m_asid;
46 std::unique_ptr<HeapMapperInternal> m_internal;
47};
48
49} // namespace Service::Nvidia::NvCore
diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp
index 0ca05257e..1b59c6b15 100644
--- a/src/core/hle/service/nvdrv/core/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/core/nvmap.cpp
@@ -2,14 +2,19 @@
2// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors 2// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors
3// SPDX-License-Identifier: GPL-3.0-or-later 3// SPDX-License-Identifier: GPL-3.0-or-later
4 4
5#include <functional>
6
5#include "common/alignment.h" 7#include "common/alignment.h"
6#include "common/assert.h" 8#include "common/assert.h"
7#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/hle/service/nvdrv/core/container.h"
11#include "core/hle/service/nvdrv/core/heap_mapper.h"
8#include "core/hle/service/nvdrv/core/nvmap.h" 12#include "core/hle/service/nvdrv/core/nvmap.h"
9#include "core/memory.h" 13#include "core/memory.h"
10#include "video_core/host1x/host1x.h" 14#include "video_core/host1x/host1x.h"
11 15
12using Core::Memory::YUZU_PAGESIZE; 16using Core::Memory::YUZU_PAGESIZE;
17constexpr size_t BIG_PAGE_SIZE = YUZU_PAGESIZE * 16;
13 18
14namespace Service::Nvidia::NvCore { 19namespace Service::Nvidia::NvCore {
15NvMap::Handle::Handle(u64 size_, Id id_) 20NvMap::Handle::Handle(u64 size_, Id id_)
@@ -17,9 +22,9 @@ NvMap::Handle::Handle(u64 size_, Id id_)
17 flags.raw = 0; 22 flags.raw = 0;
18} 23}
19 24
20NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { 25NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress,
26 NvCore::SessionId pSessionId) {
21 std::scoped_lock lock(mutex); 27 std::scoped_lock lock(mutex);
22
23 // Handles cannot be allocated twice 28 // Handles cannot be allocated twice
24 if (allocated) { 29 if (allocated) {
25 return NvResult::AccessDenied; 30 return NvResult::AccessDenied;
@@ -28,6 +33,7 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress)
28 flags = pFlags; 33 flags = pFlags;
29 kind = pKind; 34 kind = pKind;
30 align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign; 35 align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign;
36 session_id = pSessionId;
31 37
32 // This flag is only applicable for handles with an address passed 38 // This flag is only applicable for handles with an address passed
33 if (pAddress) { 39 if (pAddress) {
@@ -63,7 +69,7 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) {
63 return NvResult::Success; 69 return NvResult::Success;
64} 70}
65 71
66NvMap::NvMap(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {} 72NvMap::NvMap(Container& core_, Tegra::Host1x::Host1x& host1x_) : host1x{host1x_}, core{core_} {}
67 73
68void NvMap::AddHandle(std::shared_ptr<Handle> handle_description) { 74void NvMap::AddHandle(std::shared_ptr<Handle> handle_description) {
69 std::scoped_lock lock(handles_lock); 75 std::scoped_lock lock(handles_lock);
@@ -78,12 +84,30 @@ void NvMap::UnmapHandle(Handle& handle_description) {
78 handle_description.unmap_queue_entry.reset(); 84 handle_description.unmap_queue_entry.reset();
79 } 85 }
80 86
87 // Free and unmap the handle from Host1x GMMU
88 if (handle_description.pin_virt_address) {
89 host1x.GMMU().Unmap(static_cast<GPUVAddr>(handle_description.pin_virt_address),
90 handle_description.aligned_size);
91 host1x.Allocator().Free(handle_description.pin_virt_address,
92 static_cast<u32>(handle_description.aligned_size));
93 handle_description.pin_virt_address = 0;
94 }
95
81 // Free and unmap the handle from the SMMU 96 // Free and unmap the handle from the SMMU
82 host1x.MemoryManager().Unmap(static_cast<GPUVAddr>(handle_description.pin_virt_address), 97 const size_t map_size = handle_description.aligned_size;
83 handle_description.aligned_size); 98 if (!handle_description.in_heap) {
84 host1x.Allocator().Free(handle_description.pin_virt_address, 99 auto& smmu = host1x.MemoryManager();
85 static_cast<u32>(handle_description.aligned_size)); 100 size_t aligned_up = Common::AlignUp(map_size, BIG_PAGE_SIZE);
86 handle_description.pin_virt_address = 0; 101 smmu.Unmap(handle_description.d_address, map_size);
102 smmu.Free(handle_description.d_address, static_cast<size_t>(aligned_up));
103 handle_description.d_address = 0;
104 return;
105 }
106 const VAddr vaddress = handle_description.address;
107 auto* session = core.GetSession(handle_description.session_id);
108 session->mapper->Unmap(vaddress, map_size);
109 handle_description.d_address = 0;
110 handle_description.in_heap = false;
87} 111}
88 112
89bool NvMap::TryRemoveHandle(const Handle& handle_description) { 113bool NvMap::TryRemoveHandle(const Handle& handle_description) {
@@ -124,22 +148,33 @@ std::shared_ptr<NvMap::Handle> NvMap::GetHandle(Handle::Id handle) {
124 } 148 }
125} 149}
126 150
127VAddr NvMap::GetHandleAddress(Handle::Id handle) { 151DAddr NvMap::GetHandleAddress(Handle::Id handle) {
128 std::scoped_lock lock(handles_lock); 152 std::scoped_lock lock(handles_lock);
129 try { 153 try {
130 return handles.at(handle)->address; 154 return handles.at(handle)->d_address;
131 } catch (std::out_of_range&) { 155 } catch (std::out_of_range&) {
132 return 0; 156 return 0;
133 } 157 }
134} 158}
135 159
136u32 NvMap::PinHandle(NvMap::Handle::Id handle) { 160DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) {
137 auto handle_description{GetHandle(handle)}; 161 auto handle_description{GetHandle(handle)};
138 if (!handle_description) [[unlikely]] { 162 if (!handle_description) [[unlikely]] {
139 return 0; 163 return 0;
140 } 164 }
141 165
142 std::scoped_lock lock(handle_description->mutex); 166 std::scoped_lock lock(handle_description->mutex);
167 const auto map_low_area = [&] {
168 if (handle_description->pin_virt_address == 0) {
169 auto& gmmu_allocator = host1x.Allocator();
170 auto& gmmu = host1x.GMMU();
171 u32 address =
172 gmmu_allocator.Allocate(static_cast<u32>(handle_description->aligned_size));
173 gmmu.Map(static_cast<GPUVAddr>(address), handle_description->d_address,
174 handle_description->aligned_size);
175 handle_description->pin_virt_address = address;
176 }
177 };
143 if (!handle_description->pins) { 178 if (!handle_description->pins) {
144 // If we're in the unmap queue we can just remove ourselves and return since we're already 179 // If we're in the unmap queue we can just remove ourselves and return since we're already
145 // mapped 180 // mapped
@@ -151,37 +186,58 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) {
151 unmap_queue.erase(*handle_description->unmap_queue_entry); 186 unmap_queue.erase(*handle_description->unmap_queue_entry);
152 handle_description->unmap_queue_entry.reset(); 187 handle_description->unmap_queue_entry.reset();
153 188
189 if (low_area_pin) {
190 map_low_area();
191 handle_description->pins++;
192 return static_cast<DAddr>(handle_description->pin_virt_address);
193 }
194
154 handle_description->pins++; 195 handle_description->pins++;
155 return handle_description->pin_virt_address; 196 return handle_description->d_address;
156 } 197 }
157 } 198 }
158 199
200 using namespace std::placeholders;
159 // If not then allocate some space and map it 201 // If not then allocate some space and map it
160 u32 address{}; 202 DAddr address{};
161 auto& smmu_allocator = host1x.Allocator(); 203 auto& smmu = host1x.MemoryManager();
162 auto& smmu_memory_manager = host1x.MemoryManager(); 204 auto* session = core.GetSession(handle_description->session_id);
163 while ((address = smmu_allocator.Allocate( 205 const VAddr vaddress = handle_description->address;
164 static_cast<u32>(handle_description->aligned_size))) == 0) { 206 const size_t map_size = handle_description->aligned_size;
165 // Free handles until the allocation succeeds 207 if (session->has_preallocated_area && session->mapper->IsInBounds(vaddress, map_size)) {
166 std::scoped_lock queueLock(unmap_queue_lock); 208 handle_description->d_address = session->mapper->Map(vaddress, map_size);
167 if (auto freeHandleDesc{unmap_queue.front()}) { 209 handle_description->in_heap = true;
168 // Handles in the unmap queue are guaranteed not to be pinned so don't bother 210 } else {
169 // checking if they are before unmapping 211 size_t aligned_up = Common::AlignUp(map_size, BIG_PAGE_SIZE);
170 std::scoped_lock freeLock(freeHandleDesc->mutex); 212 while ((address = smmu.Allocate(aligned_up)) == 0) {
171 if (handle_description->pin_virt_address) 213 // Free handles until the allocation succeeds
172 UnmapHandle(*freeHandleDesc); 214 std::scoped_lock queueLock(unmap_queue_lock);
173 } else { 215 if (auto freeHandleDesc{unmap_queue.front()}) {
174 LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); 216 // Handles in the unmap queue are guaranteed not to be pinned so don't bother
217 // checking if they are before unmapping
218 std::scoped_lock freeLock(freeHandleDesc->mutex);
219 if (handle_description->d_address)
220 UnmapHandle(*freeHandleDesc);
221 } else {
222 LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!");
223 }
175 } 224 }
225
226 handle_description->d_address = address;
227 smmu.Map(address, vaddress, map_size, session->asid, true);
228 handle_description->in_heap = false;
176 } 229 }
230 }
177 231
178 smmu_memory_manager.Map(static_cast<GPUVAddr>(address), handle_description->address, 232 if (low_area_pin) {
179 handle_description->aligned_size); 233 map_low_area();
180 handle_description->pin_virt_address = address;
181 } 234 }
182 235
183 handle_description->pins++; 236 handle_description->pins++;
184 return handle_description->pin_virt_address; 237 if (low_area_pin) {
238 return static_cast<DAddr>(handle_description->pin_virt_address);
239 }
240 return handle_description->d_address;
185} 241}
186 242
187void NvMap::UnpinHandle(Handle::Id handle) { 243void NvMap::UnpinHandle(Handle::Id handle) {
@@ -232,7 +288,7 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna
232 LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); 288 LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!");
233 } else if (handle_description->dupes == 0) { 289 } else if (handle_description->dupes == 0) {
234 // Force unmap the handle 290 // Force unmap the handle
235 if (handle_description->pin_virt_address) { 291 if (handle_description->d_address) {
236 std::scoped_lock queueLock(unmap_queue_lock); 292 std::scoped_lock queueLock(unmap_queue_lock);
237 UnmapHandle(*handle_description); 293 UnmapHandle(*handle_description);
238 } 294 }
diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h
index a8e573890..d7f695845 100644
--- a/src/core/hle/service/nvdrv/core/nvmap.h
+++ b/src/core/hle/service/nvdrv/core/nvmap.h
@@ -14,6 +14,7 @@
14 14
15#include "common/bit_field.h" 15#include "common/bit_field.h"
16#include "common/common_types.h" 16#include "common/common_types.h"
17#include "core/hle/service/nvdrv/core/container.h"
17#include "core/hle/service/nvdrv/nvdata.h" 18#include "core/hle/service/nvdrv/nvdata.h"
18 19
19namespace Tegra { 20namespace Tegra {
@@ -25,6 +26,8 @@ class Host1x;
25} // namespace Tegra 26} // namespace Tegra
26 27
27namespace Service::Nvidia::NvCore { 28namespace Service::Nvidia::NvCore {
29
30class Container;
28/** 31/**
29 * @brief The nvmap core class holds the global state for nvmap and provides methods to manage 32 * @brief The nvmap core class holds the global state for nvmap and provides methods to manage
30 * handles 33 * handles
@@ -48,7 +51,7 @@ public:
48 using Id = u32; 51 using Id = u32;
49 Id id; //!< A globally unique identifier for this handle 52 Id id; //!< A globally unique identifier for this handle
50 53
51 s32 pins{}; 54 s64 pins{};
52 u32 pin_virt_address{}; 55 u32 pin_virt_address{};
53 std::optional<typename std::list<std::shared_ptr<Handle>>::iterator> unmap_queue_entry{}; 56 std::optional<typename std::list<std::shared_ptr<Handle>>::iterator> unmap_queue_entry{};
54 57
@@ -61,15 +64,18 @@ public:
61 } flags{}; 64 } flags{};
62 static_assert(sizeof(Flags) == sizeof(u32)); 65 static_assert(sizeof(Flags) == sizeof(u32));
63 66
64 u64 address{}; //!< The memory location in the guest's AS that this handle corresponds to, 67 VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to,
65 //!< this can also be in the nvdrv tmem 68 //!< this can also be in the nvdrv tmem
66 bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC 69 bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC
67 //!< call 70 //!< call
68 71
69 u8 kind{}; //!< Used for memory compression 72 u8 kind{}; //!< Used for memory compression
70 bool allocated{}; //!< If the handle has been allocated with `Alloc` 73 bool allocated{}; //!< If the handle has been allocated with `Alloc`
74 bool in_heap{};
75 NvCore::SessionId session_id{};
71 76
72 u64 dma_map_addr{}; //! remove me after implementing pinning. 77 DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds
78 //!< to, this can also be in the nvdrv tmem
73 79
74 Handle(u64 size, Id id); 80 Handle(u64 size, Id id);
75 81
@@ -77,7 +83,8 @@ public:
77 * @brief Sets up the handle with the given memory config, can allocate memory from the tmem 83 * @brief Sets up the handle with the given memory config, can allocate memory from the tmem
78 * if a 0 address is passed 84 * if a 0 address is passed
79 */ 85 */
80 [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress); 86 [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress,
87 NvCore::SessionId pSessionId);
81 88
82 /** 89 /**
83 * @brief Increases the dupe counter of the handle for the given session 90 * @brief Increases the dupe counter of the handle for the given session
@@ -108,7 +115,7 @@ public:
108 bool can_unlock; //!< If the address region is ready to be unlocked 115 bool can_unlock; //!< If the address region is ready to be unlocked
109 }; 116 };
110 117
111 explicit NvMap(Tegra::Host1x::Host1x& host1x); 118 explicit NvMap(Container& core, Tegra::Host1x::Host1x& host1x);
112 119
113 /** 120 /**
114 * @brief Creates an unallocated handle of the given size 121 * @brief Creates an unallocated handle of the given size
@@ -117,7 +124,7 @@ public:
117 124
118 std::shared_ptr<Handle> GetHandle(Handle::Id handle); 125 std::shared_ptr<Handle> GetHandle(Handle::Id handle);
119 126
120 VAddr GetHandleAddress(Handle::Id handle); 127 DAddr GetHandleAddress(Handle::Id handle);
121 128
122 /** 129 /**
123 * @brief Maps a handle into the SMMU address space 130 * @brief Maps a handle into the SMMU address space
@@ -125,7 +132,7 @@ public:
125 * number of calls to `UnpinHandle` 132 * number of calls to `UnpinHandle`
126 * @return The SMMU virtual address that the handle has been mapped to 133 * @return The SMMU virtual address that the handle has been mapped to
127 */ 134 */
128 u32 PinHandle(Handle::Id handle); 135 DAddr PinHandle(Handle::Id handle, bool low_area_pin);
129 136
130 /** 137 /**
131 * @brief When this has been called an equal number of times to `PinHandle` for the supplied 138 * @brief When this has been called an equal number of times to `PinHandle` for the supplied
@@ -172,5 +179,7 @@ private:
172 * @return If the handle was removed from the map 179 * @return If the handle was removed from the map
173 */ 180 */
174 bool TryRemoveHandle(const Handle& handle_description); 181 bool TryRemoveHandle(const Handle& handle_description);
182
183 Container& core;
175}; 184};
176} // namespace Service::Nvidia::NvCore 185} // namespace Service::Nvidia::NvCore
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index a04538d5d..8adaddc60 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -7,6 +7,7 @@
7#include <vector> 7#include <vector>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/service/nvdrv/core/container.h"
10#include "core/hle/service/nvdrv/nvdata.h" 11#include "core/hle/service/nvdrv/nvdata.h"
11 12
12namespace Core { 13namespace Core {
@@ -62,7 +63,7 @@ public:
62 * Called once a device is opened 63 * Called once a device is opened
63 * @param fd The device fd 64 * @param fd The device fd
64 */ 65 */
65 virtual void OnOpen(DeviceFD fd) = 0; 66 virtual void OnOpen(NvCore::SessionId session_id, DeviceFD fd) = 0;
66 67
67 /** 68 /**
68 * Called once a device is closed 69 * Called once a device is closed
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 05a43d8dc..c1ebbd62d 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -35,14 +35,14 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
35 return NvResult::NotImplemented; 35 return NvResult::NotImplemented;
36} 36}
37 37
38void nvdisp_disp0::OnOpen(DeviceFD fd) {} 38void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
39void nvdisp_disp0::OnClose(DeviceFD fd) {} 39void nvdisp_disp0::OnClose(DeviceFD fd) {}
40 40
41void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, 41void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
42 u32 height, u32 stride, android::BufferTransformFlags transform, 42 u32 height, u32 stride, android::BufferTransformFlags transform,
43 const Common::Rectangle<int>& crop_rect, 43 const Common::Rectangle<int>& crop_rect,
44 std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) { 44 std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) {
45 const VAddr addr = nvmap.GetHandleAddress(buffer_handle); 45 const DAddr addr = nvmap.GetHandleAddress(buffer_handle);
46 LOG_TRACE(Service, 46 LOG_TRACE(Service,
47 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", 47 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
48 addr, offset, width, height, stride, format); 48 addr, offset, width, height, stride, format);
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index daee05fe8..5f13a50a2 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -32,7 +32,7 @@ public:
32 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 32 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
33 std::span<u8> inline_output) override; 33 std::span<u8> inline_output) override;
34 34
35 void OnOpen(DeviceFD fd) override; 35 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
36 void OnClose(DeviceFD fd) override; 36 void OnClose(DeviceFD fd) override;
37 37
38 /// Performs a screen flip, drawing the buffer pointed to by the handle. 38 /// Performs a screen flip, drawing the buffer pointed to by the handle.
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 6b3639008..e6646ba04 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -86,7 +86,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
86 return NvResult::NotImplemented; 86 return NvResult::NotImplemented;
87} 87}
88 88
89void nvhost_as_gpu::OnOpen(DeviceFD fd) {} 89void nvhost_as_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
90void nvhost_as_gpu::OnClose(DeviceFD fd) {} 90void nvhost_as_gpu::OnClose(DeviceFD fd) {}
91 91
92NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { 92NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
@@ -206,6 +206,8 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
206 static_cast<u32>(aligned_size >> page_size_bits)); 206 static_cast<u32>(aligned_size >> page_size_bits));
207 } 207 }
208 208
209 nvmap.UnpinHandle(mapping->handle);
210
209 // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state 211 // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state
210 // Only FreeSpace can unmap them fully 212 // Only FreeSpace can unmap them fully
211 if (mapping->sparse_alloc) { 213 if (mapping->sparse_alloc) {
@@ -293,12 +295,12 @@ NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
293 return NvResult::BadValue; 295 return NvResult::BadValue;
294 } 296 }
295 297
296 VAddr cpu_address{static_cast<VAddr>( 298 DAddr base = nvmap.PinHandle(entry.handle, false);
297 handle->address + 299 DAddr device_address{static_cast<DAddr>(
298 (static_cast<u64>(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; 300 base + (static_cast<u64>(entry.handle_offset_big_pages) << vm.big_page_size_bits))};
299 301
300 gmmu->Map(virtual_address, cpu_address, size, static_cast<Tegra::PTEKind>(entry.kind), 302 gmmu->Map(virtual_address, device_address, size,
301 use_big_pages); 303 static_cast<Tegra::PTEKind>(entry.kind), use_big_pages);
302 } 304 }
303 } 305 }
304 306
@@ -331,9 +333,9 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
331 } 333 }
332 334
333 u64 gpu_address{static_cast<u64>(params.offset + params.buffer_offset)}; 335 u64 gpu_address{static_cast<u64>(params.offset + params.buffer_offset)};
334 VAddr cpu_address{mapping->ptr + params.buffer_offset}; 336 VAddr device_address{mapping->ptr + params.buffer_offset};
335 337
336 gmmu->Map(gpu_address, cpu_address, params.mapping_size, 338 gmmu->Map(gpu_address, device_address, params.mapping_size,
337 static_cast<Tegra::PTEKind>(params.kind), mapping->big_page); 339 static_cast<Tegra::PTEKind>(params.kind), mapping->big_page);
338 340
339 return NvResult::Success; 341 return NvResult::Success;
@@ -349,7 +351,8 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
349 return NvResult::BadValue; 351 return NvResult::BadValue;
350 } 352 }
351 353
352 VAddr cpu_address{static_cast<VAddr>(handle->address + params.buffer_offset)}; 354 DAddr device_address{
355 static_cast<DAddr>(nvmap.PinHandle(params.handle, false) + params.buffer_offset)};
353 u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; 356 u64 size{params.mapping_size ? params.mapping_size : handle->orig_size};
354 357
355 bool big_page{[&]() { 358 bool big_page{[&]() {
@@ -373,15 +376,14 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
373 } 376 }
374 377
375 const bool use_big_pages = alloc->second.big_pages && big_page; 378 const bool use_big_pages = alloc->second.big_pages && big_page;
376 gmmu->Map(params.offset, cpu_address, size, static_cast<Tegra::PTEKind>(params.kind), 379 gmmu->Map(params.offset, device_address, size, static_cast<Tegra::PTEKind>(params.kind),
377 use_big_pages); 380 use_big_pages);
378 381
379 auto mapping{std::make_shared<Mapping>(cpu_address, params.offset, size, true, 382 auto mapping{std::make_shared<Mapping>(params.handle, device_address, params.offset, size,
380 use_big_pages, alloc->second.sparse)}; 383 true, use_big_pages, alloc->second.sparse)};
381 alloc->second.mappings.push_back(mapping); 384 alloc->second.mappings.push_back(mapping);
382 mapping_map[params.offset] = mapping; 385 mapping_map[params.offset] = mapping;
383 } else { 386 } else {
384
385 auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; 387 auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator};
386 u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; 388 u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE};
387 u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; 389 u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS};
@@ -394,11 +396,11 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
394 return NvResult::InsufficientMemory; 396 return NvResult::InsufficientMemory;
395 } 397 }
396 398
397 gmmu->Map(params.offset, cpu_address, Common::AlignUp(size, page_size), 399 gmmu->Map(params.offset, device_address, Common::AlignUp(size, page_size),
398 static_cast<Tegra::PTEKind>(params.kind), big_page); 400 static_cast<Tegra::PTEKind>(params.kind), big_page);
399 401
400 auto mapping{ 402 auto mapping{std::make_shared<Mapping>(params.handle, device_address, params.offset, size,
401 std::make_shared<Mapping>(cpu_address, params.offset, size, false, big_page, false)}; 403 false, big_page, false)};
402 mapping_map[params.offset] = mapping; 404 mapping_map[params.offset] = mapping;
403 } 405 }
404 406
@@ -433,6 +435,8 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
433 gmmu->Unmap(params.offset, mapping->size); 435 gmmu->Unmap(params.offset, mapping->size);
434 } 436 }
435 437
438 nvmap.UnpinHandle(mapping->handle);
439
436 mapping_map.erase(params.offset); 440 mapping_map.erase(params.offset);
437 } catch (const std::out_of_range&) { 441 } catch (const std::out_of_range&) {
438 LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset); 442 LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset);
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 79a21683d..7d0a99988 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -55,7 +55,7 @@ public:
55 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 55 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
56 std::span<u8> inline_output) override; 56 std::span<u8> inline_output) override;
57 57
58 void OnOpen(DeviceFD fd) override; 58 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
59 void OnClose(DeviceFD fd) override; 59 void OnClose(DeviceFD fd) override;
60 60
61 Kernel::KEvent* QueryEvent(u32 event_id) override; 61 Kernel::KEvent* QueryEvent(u32 event_id) override;
@@ -159,16 +159,18 @@ private:
159 NvCore::NvMap& nvmap; 159 NvCore::NvMap& nvmap;
160 160
161 struct Mapping { 161 struct Mapping {
162 VAddr ptr; 162 NvCore::NvMap::Handle::Id handle;
163 DAddr ptr;
163 u64 offset; 164 u64 offset;
164 u64 size; 165 u64 size;
165 bool fixed; 166 bool fixed;
166 bool big_page; // Only valid if fixed == false 167 bool big_page; // Only valid if fixed == false
167 bool sparse_alloc; 168 bool sparse_alloc;
168 169
169 Mapping(VAddr ptr_, u64 offset_, u64 size_, bool fixed_, bool big_page_, bool sparse_alloc_) 170 Mapping(NvCore::NvMap::Handle::Id handle_, DAddr ptr_, u64 offset_, u64 size_, bool fixed_,
170 : ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), big_page(big_page_), 171 bool big_page_, bool sparse_alloc_)
171 sparse_alloc(sparse_alloc_) {} 172 : handle(handle_), ptr(ptr_), offset(offset_), size(size_), fixed(fixed_),
173 big_page(big_page_), sparse_alloc(sparse_alloc_) {}
172 }; 174 };
173 175
174 struct Allocation { 176 struct Allocation {
@@ -212,9 +214,6 @@ private:
212 bool initialised{}; 214 bool initialised{};
213 } vm; 215 } vm;
214 std::shared_ptr<Tegra::MemoryManager> gmmu; 216 std::shared_ptr<Tegra::MemoryManager> gmmu;
215
216 // s32 channel{};
217 // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE};
218}; 217};
219 218
220} // namespace Service::Nvidia::Devices 219} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index b8dd34e24..250d01de3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -76,7 +76,7 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inp
76 return NvResult::NotImplemented; 76 return NvResult::NotImplemented;
77} 77}
78 78
79void nvhost_ctrl::OnOpen(DeviceFD fd) {} 79void nvhost_ctrl::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
80 80
81void nvhost_ctrl::OnClose(DeviceFD fd) {} 81void nvhost_ctrl::OnClose(DeviceFD fd) {}
82 82
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 992124b60..403f1a746 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -32,7 +32,7 @@ public:
32 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 32 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
33 std::span<u8> inline_output) override; 33 std::span<u8> inline_output) override;
34 34
35 void OnOpen(DeviceFD fd) override; 35 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
36 void OnClose(DeviceFD fd) override; 36 void OnClose(DeviceFD fd) override;
37 37
38 Kernel::KEvent* QueryEvent(u32 event_id) override; 38 Kernel::KEvent* QueryEvent(u32 event_id) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 3e0c96456..ddd85678b 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
82 return NvResult::NotImplemented; 82 return NvResult::NotImplemented;
83} 83}
84 84
85void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} 85void nvhost_ctrl_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
86void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} 86void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
87 87
88NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) { 88NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index d170299bd..d2ab05b21 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -28,7 +28,7 @@ public:
28 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 28 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
29 std::span<u8> inline_output) override; 29 std::span<u8> inline_output) override;
30 30
31 void OnOpen(DeviceFD fd) override; 31 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
32 void OnClose(DeviceFD fd) override; 32 void OnClose(DeviceFD fd) override;
33 33
34 Kernel::KEvent* QueryEvent(u32 event_id) override; 34 Kernel::KEvent* QueryEvent(u32 event_id) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index b0395c2f0..bf12d69a5 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -120,7 +120,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
120 return NvResult::NotImplemented; 120 return NvResult::NotImplemented;
121} 121}
122 122
123void nvhost_gpu::OnOpen(DeviceFD fd) {} 123void nvhost_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
124void nvhost_gpu::OnClose(DeviceFD fd) {} 124void nvhost_gpu::OnClose(DeviceFD fd) {}
125 125
126NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) { 126NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 88fd228ff..e34a978db 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -47,7 +47,7 @@ public:
47 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 47 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
48 std::span<u8> inline_output) override; 48 std::span<u8> inline_output) override;
49 49
50 void OnOpen(DeviceFD fd) override; 50 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
51 void OnClose(DeviceFD fd) override; 51 void OnClose(DeviceFD fd) override;
52 52
53 Kernel::KEvent* QueryEvent(u32 event_id) override; 53 Kernel::KEvent* QueryEvent(u32 event_id) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index f43914e1b..2c0ac2a46 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -35,7 +35,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
35 case 0x7: 35 case 0x7:
36 return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output); 36 return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output);
37 case 0x9: 37 case 0x9:
38 return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output); 38 return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output, fd);
39 case 0xa: 39 case 0xa:
40 return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output); 40 return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output);
41 default: 41 default:
@@ -68,9 +68,10 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
68 return NvResult::NotImplemented; 68 return NvResult::NotImplemented;
69} 69}
70 70
71void nvhost_nvdec::OnOpen(DeviceFD fd) { 71void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
72 LOG_INFO(Service_NVDRV, "NVDEC video stream started"); 72 LOG_INFO(Service_NVDRV, "NVDEC video stream started");
73 system.SetNVDECActive(true); 73 system.SetNVDECActive(true);
74 sessions[fd] = session_id;
74} 75}
75 76
76void nvhost_nvdec::OnClose(DeviceFD fd) { 77void nvhost_nvdec::OnClose(DeviceFD fd) {
@@ -81,6 +82,10 @@ void nvhost_nvdec::OnClose(DeviceFD fd) {
81 system.GPU().ClearCdmaInstance(iter->second); 82 system.GPU().ClearCdmaInstance(iter->second);
82 } 83 }
83 system.SetNVDECActive(false); 84 system.SetNVDECActive(false);
85 auto it = sessions.find(fd);
86 if (it != sessions.end()) {
87 sessions.erase(it);
88 }
84} 89}
85 90
86} // namespace Service::Nvidia::Devices 91} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index ad2233c49..627686757 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -20,7 +20,7 @@ public:
20 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 20 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
21 std::span<u8> inline_output) override; 21 std::span<u8> inline_output) override;
22 22
23 void OnOpen(DeviceFD fd) override; 23 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
24 void OnClose(DeviceFD fd) override; 24 void OnClose(DeviceFD fd) override;
25}; 25};
26 26
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 74c701b95..a0a7bfa40 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -8,6 +8,7 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/hle/kernel/k_process.h"
11#include "core/hle/service/nvdrv/core/container.h" 12#include "core/hle/service/nvdrv/core/container.h"
12#include "core/hle/service/nvdrv/core/nvmap.h" 13#include "core/hle/service/nvdrv/core/nvmap.h"
13#include "core/hle/service/nvdrv/core/syncpoint_manager.h" 14#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
@@ -95,6 +96,8 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
95 offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); 96 offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
96 97
97 auto& gpu = system.GPU(); 98 auto& gpu = system.GPU();
99 auto* session = core.GetSession(sessions[fd]);
100
98 if (gpu.UseNvdec()) { 101 if (gpu.UseNvdec()) {
99 for (std::size_t i = 0; i < syncpt_increments.size(); i++) { 102 for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
100 const SyncptIncr& syncpt_incr = syncpt_increments[i]; 103 const SyncptIncr& syncpt_incr = syncpt_increments[i];
@@ -106,8 +109,8 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
106 const auto object = nvmap.GetHandle(cmd_buffer.memory_id); 109 const auto object = nvmap.GetHandle(cmd_buffer.memory_id);
107 ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); 110 ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
108 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); 111 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
109 system.ApplicationMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), 112 session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(),
110 cmdlist.size() * sizeof(u32)); 113 cmdlist.size() * sizeof(u32));
111 gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); 114 gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
112 } 115 }
113 // Some games expect command_buffers to be written back 116 // Some games expect command_buffers to be written back
@@ -133,10 +136,12 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) {
133 return NvResult::Success; 136 return NvResult::Success;
134} 137}
135 138
136NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) { 139NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries,
140 DeviceFD fd) {
137 const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size())); 141 const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
138 for (size_t i = 0; i < num_entries; i++) { 142 for (size_t i = 0; i < num_entries; i++) {
139 entries[i].map_address = nvmap.PinHandle(entries[i].map_handle); 143 DAddr pin_address = nvmap.PinHandle(entries[i].map_handle, true);
144 entries[i].map_address = static_cast<u32>(pin_address);
140 } 145 }
141 146
142 return NvResult::Success; 147 return NvResult::Success;
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 7ce748e18..900db81d2 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -4,7 +4,9 @@
4#pragma once 4#pragma once
5 5
6#include <deque> 6#include <deque>
7#include <unordered_map>
7#include <vector> 8#include <vector>
9
8#include "common/common_types.h" 10#include "common/common_types.h"
9#include "common/swap.h" 11#include "common/swap.h"
10#include "core/hle/service/nvdrv/core/syncpoint_manager.h" 12#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
@@ -111,7 +113,7 @@ protected:
111 NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd); 113 NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd);
112 NvResult GetSyncpoint(IoctlGetSyncpoint& params); 114 NvResult GetSyncpoint(IoctlGetSyncpoint& params);
113 NvResult GetWaitbase(IoctlGetWaitbase& params); 115 NvResult GetWaitbase(IoctlGetWaitbase& params);
114 NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); 116 NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd);
115 NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); 117 NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
116 NvResult SetSubmitTimeout(u32 timeout); 118 NvResult SetSubmitTimeout(u32 timeout);
117 119
@@ -125,6 +127,7 @@ protected:
125 NvCore::NvMap& nvmap; 127 NvCore::NvMap& nvmap;
126 NvCore::ChannelType channel_type; 128 NvCore::ChannelType channel_type;
127 std::array<u32, MaxSyncPoints> device_syncpoints{}; 129 std::array<u32, MaxSyncPoints> device_syncpoints{};
130 std::unordered_map<DeviceFD, NvCore::SessionId> sessions;
128}; 131};
129}; // namespace Devices 132}; // namespace Devices
130} // namespace Service::Nvidia 133} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index 9e6b86458..f87d53f12 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -44,7 +44,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
44 return NvResult::NotImplemented; 44 return NvResult::NotImplemented;
45} 45}
46 46
47void nvhost_nvjpg::OnOpen(DeviceFD fd) {} 47void nvhost_nvjpg::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
48void nvhost_nvjpg::OnClose(DeviceFD fd) {} 48void nvhost_nvjpg::OnClose(DeviceFD fd) {}
49 49
50NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) { 50NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 790c97f6a..def9c254d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -22,7 +22,7 @@ public:
22 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 22 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
23 std::span<u8> inline_output) override; 23 std::span<u8> inline_output) override;
24 24
25 void OnOpen(DeviceFD fd) override; 25 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
26 void OnClose(DeviceFD fd) override; 26 void OnClose(DeviceFD fd) override;
27 27
28private: 28private:
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 87f8d7c22..bf090f5eb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -33,7 +33,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
33 case 0x3: 33 case 0x3:
34 return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output); 34 return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output);
35 case 0x9: 35 case 0x9:
36 return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output); 36 return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output, fd);
37 case 0xa: 37 case 0xa:
38 return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output); 38 return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output);
39 default: 39 default:
@@ -68,7 +68,9 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
68 return NvResult::NotImplemented; 68 return NvResult::NotImplemented;
69} 69}
70 70
71void nvhost_vic::OnOpen(DeviceFD fd) {} 71void nvhost_vic::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
72 sessions[fd] = session_id;
73}
72 74
73void nvhost_vic::OnClose(DeviceFD fd) { 75void nvhost_vic::OnClose(DeviceFD fd) {
74 auto& host1x_file = core.Host1xDeviceFile(); 76 auto& host1x_file = core.Host1xDeviceFile();
@@ -76,6 +78,7 @@ void nvhost_vic::OnClose(DeviceFD fd) {
76 if (iter != host1x_file.fd_to_id.end()) { 78 if (iter != host1x_file.fd_to_id.end()) {
77 system.GPU().ClearCdmaInstance(iter->second); 79 system.GPU().ClearCdmaInstance(iter->second);
78 } 80 }
81 sessions.erase(fd);
79} 82}
80 83
81} // namespace Service::Nvidia::Devices 84} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index cadbcb0a5..0cc04354a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -19,7 +19,7 @@ public:
19 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 19 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
20 std::span<u8> inline_output) override; 20 std::span<u8> inline_output) override;
21 21
22 void OnOpen(DeviceFD fd) override; 22 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
23 void OnClose(DeviceFD fd) override; 23 void OnClose(DeviceFD fd) override;
24}; 24};
25} // namespace Service::Nvidia::Devices 25} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 71b2e62ec..da61a3bfe 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -36,9 +36,9 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
36 case 0x3: 36 case 0x3:
37 return WrapFixed(this, &nvmap::IocFromId, input, output); 37 return WrapFixed(this, &nvmap::IocFromId, input, output);
38 case 0x4: 38 case 0x4:
39 return WrapFixed(this, &nvmap::IocAlloc, input, output); 39 return WrapFixed(this, &nvmap::IocAlloc, input, output, fd);
40 case 0x5: 40 case 0x5:
41 return WrapFixed(this, &nvmap::IocFree, input, output); 41 return WrapFixed(this, &nvmap::IocFree, input, output, fd);
42 case 0x9: 42 case 0x9:
43 return WrapFixed(this, &nvmap::IocParam, input, output); 43 return WrapFixed(this, &nvmap::IocParam, input, output);
44 case 0xe: 44 case 0xe:
@@ -67,8 +67,15 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st
67 return NvResult::NotImplemented; 67 return NvResult::NotImplemented;
68} 68}
69 69
70void nvmap::OnOpen(DeviceFD fd) {} 70void nvmap::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
71void nvmap::OnClose(DeviceFD fd) {} 71 sessions[fd] = session_id;
72}
73void nvmap::OnClose(DeviceFD fd) {
74 auto it = sessions.find(fd);
75 if (it != sessions.end()) {
76 sessions.erase(it);
77 }
78}
72 79
73NvResult nvmap::IocCreate(IocCreateParams& params) { 80NvResult nvmap::IocCreate(IocCreateParams& params) {
74 LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); 81 LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
@@ -87,7 +94,7 @@ NvResult nvmap::IocCreate(IocCreateParams& params) {
87 return NvResult::Success; 94 return NvResult::Success;
88} 95}
89 96
90NvResult nvmap::IocAlloc(IocAllocParams& params) { 97NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) {
91 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); 98 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
92 99
93 if (!params.handle) { 100 if (!params.handle) {
@@ -116,15 +123,15 @@ NvResult nvmap::IocAlloc(IocAllocParams& params) {
116 return NvResult::InsufficientMemory; 123 return NvResult::InsufficientMemory;
117 } 124 }
118 125
119 const auto result = 126 const auto result = handle_description->Alloc(params.flags, params.align, params.kind,
120 handle_description->Alloc(params.flags, params.align, params.kind, params.address); 127 params.address, sessions[fd]);
121 if (result != NvResult::Success) { 128 if (result != NvResult::Success) {
122 LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); 129 LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle);
123 return result; 130 return result;
124 } 131 }
125 bool is_out_io{}; 132 bool is_out_io{};
126 ASSERT(system.ApplicationProcess() 133 auto process = container.GetSession(sessions[fd])->process;
127 ->GetPageTable() 134 ASSERT(process->GetPageTable()
128 .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, 135 .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address,
129 handle_description->size, 136 handle_description->size,
130 Kernel::KMemoryPermission::None, true, false) 137 Kernel::KMemoryPermission::None, true, false)
@@ -224,7 +231,7 @@ NvResult nvmap::IocParam(IocParamParams& params) {
224 return NvResult::Success; 231 return NvResult::Success;
225} 232}
226 233
227NvResult nvmap::IocFree(IocFreeParams& params) { 234NvResult nvmap::IocFree(IocFreeParams& params, DeviceFD fd) {
228 LOG_DEBUG(Service_NVDRV, "called"); 235 LOG_DEBUG(Service_NVDRV, "called");
229 236
230 if (!params.handle) { 237 if (!params.handle) {
@@ -233,9 +240,9 @@ NvResult nvmap::IocFree(IocFreeParams& params) {
233 } 240 }
234 241
235 if (auto freeInfo{file.FreeHandle(params.handle, false)}) { 242 if (auto freeInfo{file.FreeHandle(params.handle, false)}) {
243 auto process = container.GetSession(sessions[fd])->process;
236 if (freeInfo->can_unlock) { 244 if (freeInfo->can_unlock) {
237 ASSERT(system.ApplicationProcess() 245 ASSERT(process->GetPageTable()
238 ->GetPageTable()
239 .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) 246 .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size)
240 .IsSuccess()); 247 .IsSuccess());
241 } 248 }
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 049c11028..d07d85f88 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -33,7 +33,7 @@ public:
33 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, 33 NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
34 std::span<u8> inline_output) override; 34 std::span<u8> inline_output) override;
35 35
36 void OnOpen(DeviceFD fd) override; 36 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
37 void OnClose(DeviceFD fd) override; 37 void OnClose(DeviceFD fd) override;
38 38
39 enum class HandleParameterType : u32_le { 39 enum class HandleParameterType : u32_le {
@@ -100,11 +100,11 @@ public:
100 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); 100 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
101 101
102 NvResult IocCreate(IocCreateParams& params); 102 NvResult IocCreate(IocCreateParams& params);
103 NvResult IocAlloc(IocAllocParams& params); 103 NvResult IocAlloc(IocAllocParams& params, DeviceFD fd);
104 NvResult IocGetId(IocGetIdParams& params); 104 NvResult IocGetId(IocGetIdParams& params);
105 NvResult IocFromId(IocFromIdParams& params); 105 NvResult IocFromId(IocFromIdParams& params);
106 NvResult IocParam(IocParamParams& params); 106 NvResult IocParam(IocParamParams& params);
107 NvResult IocFree(IocFreeParams& params); 107 NvResult IocFree(IocFreeParams& params, DeviceFD fd);
108 108
109private: 109private:
110 /// Id to use for the next handle that is created. 110 /// Id to use for the next handle that is created.
@@ -115,6 +115,7 @@ private:
115 115
116 NvCore::Container& container; 116 NvCore::Container& container;
117 NvCore::NvMap& file; 117 NvCore::NvMap& file;
118 std::unordered_map<DeviceFD, NvCore::SessionId> sessions;
118}; 119};
119 120
120} // namespace Service::Nvidia::Devices 121} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 9e46ee8dd..cb256e5b4 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -45,13 +45,22 @@ void EventInterface::FreeEvent(Kernel::KEvent* event) {
45void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { 45void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
46 auto server_manager = std::make_unique<ServerManager>(system); 46 auto server_manager = std::make_unique<ServerManager>(system);
47 auto module = std::make_shared<Module>(system); 47 auto module = std::make_shared<Module>(system);
48 server_manager->RegisterNamedService("nvdrv", std::make_shared<NVDRV>(system, module, "nvdrv")); 48 const auto NvdrvInterfaceFactoryForApplication = [&, module] {
49 server_manager->RegisterNamedService("nvdrv:a", 49 return std::make_shared<NVDRV>(system, module, "nvdrv");
50 std::make_shared<NVDRV>(system, module, "nvdrv:a")); 50 };
51 server_manager->RegisterNamedService("nvdrv:s", 51 const auto NvdrvInterfaceFactoryForApplets = [&, module] {
52 std::make_shared<NVDRV>(system, module, "nvdrv:s")); 52 return std::make_shared<NVDRV>(system, module, "nvdrv:a");
53 server_manager->RegisterNamedService("nvdrv:t", 53 };
54 std::make_shared<NVDRV>(system, module, "nvdrv:t")); 54 const auto NvdrvInterfaceFactoryForSysmodules = [&, module] {
55 return std::make_shared<NVDRV>(system, module, "nvdrv:s");
56 };
57 const auto NvdrvInterfaceFactoryForTesting = [&, module] {
58 return std::make_shared<NVDRV>(system, module, "nvdrv:t");
59 };
60 server_manager->RegisterNamedService("nvdrv", NvdrvInterfaceFactoryForApplication);
61 server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets);
62 server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules);
63 server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting);
55 server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system)); 64 server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system));
56 nvnflinger.SetNVDrvInstance(module); 65 nvnflinger.SetNVDrvInstance(module);
57 ServerManager::RunServer(std::move(server_manager)); 66 ServerManager::RunServer(std::move(server_manager));
@@ -113,7 +122,7 @@ NvResult Module::VerifyFD(DeviceFD fd) const {
113 return NvResult::Success; 122 return NvResult::Success;
114} 123}
115 124
116DeviceFD Module::Open(const std::string& device_name) { 125DeviceFD Module::Open(const std::string& device_name, NvCore::SessionId session_id) {
117 auto it = builders.find(device_name); 126 auto it = builders.find(device_name);
118 if (it == builders.end()) { 127 if (it == builders.end()) {
119 LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); 128 LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
@@ -124,7 +133,7 @@ DeviceFD Module::Open(const std::string& device_name) {
124 auto& builder = it->second; 133 auto& builder = it->second;
125 auto device = builder(fd)->second; 134 auto device = builder(fd)->second;
126 135
127 device->OnOpen(fd); 136 device->OnOpen(session_id, fd);
128 137
129 return fd; 138 return fd;
130} 139}
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index d8622b3ca..c594f0e5e 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -77,7 +77,7 @@ public:
77 NvResult VerifyFD(DeviceFD fd) const; 77 NvResult VerifyFD(DeviceFD fd) const;
78 78
79 /// Opens a device node and returns a file descriptor to it. 79 /// Opens a device node and returns a file descriptor to it.
80 DeviceFD Open(const std::string& device_name); 80 DeviceFD Open(const std::string& device_name, NvCore::SessionId session_id);
81 81
82 /// Sends an ioctl command to the specified file descriptor. 82 /// Sends an ioctl command to the specified file descriptor.
83 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output); 83 NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output);
@@ -93,6 +93,10 @@ public:
93 93
94 NvResult QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event); 94 NvResult QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event);
95 95
96 NvCore::Container& GetContainer() {
97 return container;
98 }
99
96private: 100private:
97 friend class EventInterface; 101 friend class EventInterface;
98 friend class Service::Nvnflinger::Nvnflinger; 102 friend class Service::Nvnflinger::Nvnflinger;
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index c8a880e84..ffe72f281 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -3,8 +3,11 @@
3// SPDX-License-Identifier: GPL-3.0-or-later 3// SPDX-License-Identifier: GPL-3.0-or-later
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "common/scope_exit.h"
7#include "common/string_util.h"
6#include "core/core.h" 8#include "core/core.h"
7#include "core/hle/kernel/k_event.h" 9#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_process.h"
8#include "core/hle/kernel/k_readable_event.h" 11#include "core/hle/kernel/k_readable_event.h"
9#include "core/hle/service/ipc_helpers.h" 12#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/nvdrv/nvdata.h" 13#include "core/hle/service/nvdrv/nvdata.h"
@@ -27,7 +30,7 @@ void NVDRV::Open(HLERequestContext& ctx) {
27 } 30 }
28 31
29 const auto& buffer = ctx.ReadBuffer(); 32 const auto& buffer = ctx.ReadBuffer();
30 const std::string device_name(buffer.begin(), buffer.end()); 33 const std::string device_name(Common::StringFromBuffer(buffer));
31 34
32 if (device_name == "/dev/nvhost-prof-gpu") { 35 if (device_name == "/dev/nvhost-prof-gpu") {
33 rb.Push<DeviceFD>(0); 36 rb.Push<DeviceFD>(0);
@@ -37,7 +40,7 @@ void NVDRV::Open(HLERequestContext& ctx) {
37 return; 40 return;
38 } 41 }
39 42
40 DeviceFD fd = nvdrv->Open(device_name); 43 DeviceFD fd = nvdrv->Open(device_name, session_id);
41 44
42 rb.Push<DeviceFD>(fd); 45 rb.Push<DeviceFD>(fd);
43 rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); 46 rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
@@ -150,12 +153,29 @@ void NVDRV::Close(HLERequestContext& ctx) {
150 153
151void NVDRV::Initialize(HLERequestContext& ctx) { 154void NVDRV::Initialize(HLERequestContext& ctx) {
152 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 155 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
156 IPC::ResponseBuilder rb{ctx, 3};
157 SCOPE_EXIT({
158 rb.Push(ResultSuccess);
159 rb.PushEnum(NvResult::Success);
160 });
153 161
154 is_initialized = true; 162 if (is_initialized) {
163 // No need to initialize again
164 return;
165 }
155 166
156 IPC::ResponseBuilder rb{ctx, 3}; 167 IPC::RequestParser rp{ctx};
157 rb.Push(ResultSuccess); 168 const auto process_handle{ctx.GetCopyHandle(0)};
158 rb.PushEnum(NvResult::Success); 169 // The transfer memory is lent to nvdrv as a work buffer since nvdrv is
170 // unable to allocate as much memory on its own. For HLE it's unnecessary to handle it
171 [[maybe_unused]] const auto transfer_memory_handle{ctx.GetCopyHandle(1)};
172 [[maybe_unused]] const auto transfer_memory_size = rp.Pop<u32>();
173
174 auto& container = nvdrv->GetContainer();
175 auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle);
176 session_id = container.OpenSession(process.GetPointerUnsafe());
177
178 is_initialized = true;
159} 179}
160 180
161void NVDRV::QueryEvent(HLERequestContext& ctx) { 181void NVDRV::QueryEvent(HLERequestContext& ctx) {
@@ -242,6 +262,9 @@ NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char*
242 RegisterHandlers(functions); 262 RegisterHandlers(functions);
243} 263}
244 264
245NVDRV::~NVDRV() = default; 265NVDRV::~NVDRV() {
266 auto& container = nvdrv->GetContainer();
267 container.CloseSession(session_id);
268}
246 269
247} // namespace Service::Nvidia 270} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h
index 6e98115dc..f2195ae1e 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.h
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.h
@@ -35,6 +35,7 @@ private:
35 35
36 u64 pid{}; 36 u64 pid{};
37 bool is_initialized{}; 37 bool is_initialized{};
38 NvCore::SessionId session_id{};
38 Common::ScratchBuffer<u8> output_buffer; 39 Common::ScratchBuffer<u8> output_buffer;
39 Common::ScratchBuffer<u8> inline_output_buffer; 40 Common::ScratchBuffer<u8> inline_output_buffer;
40}; 41};
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
index 2fef6cc1a..86e272b41 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -87,19 +87,20 @@ Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap,
87 R_SUCCEED(); 87 R_SUCCEED();
88} 88}
89 89
90Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) { 90Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::DeviceFD nvmap_fd) {
91 // Free the handle. 91 // Free the handle.
92 Nvidia::Devices::nvmap::IocFreeParams free_params{ 92 Nvidia::Devices::nvmap::IocFreeParams free_params{
93 .handle = handle, 93 .handle = handle,
94 }; 94 };
95 R_UNLESS(nvmap.IocFree(free_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); 95 R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success,
96 VI::ResultOperationFailed);
96 97
97 // We succeeded. 98 // We succeeded.
98 R_SUCCEED(); 99 R_SUCCEED();
99} 100}
100 101
101Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, 102Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
102 u32 size) { 103 u32 size, Nvidia::DeviceFD nvmap_fd) {
103 // Assign the allocated memory to the handle. 104 // Assign the allocated memory to the handle.
104 Nvidia::Devices::nvmap::IocAllocParams alloc_params{ 105 Nvidia::Devices::nvmap::IocAllocParams alloc_params{
105 .handle = handle, 106 .handle = handle,
@@ -109,16 +110,16 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce
109 .kind = 0, 110 .kind = 0,
110 .address = GetInteger(buffer), 111 .address = GetInteger(buffer),
111 }; 112 };
112 R_UNLESS(nvmap.IocAlloc(alloc_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); 113 R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success,
114 VI::ResultOperationFailed);
113 115
114 // We succeeded. 116 // We succeeded.
115 R_SUCCEED(); 117 R_SUCCEED();
116} 118}
117 119
118Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, 120Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd,
119 Common::ProcessAddress buffer, u32 size) { 121 Common::ProcessAddress buffer, u32 size) {
120 // Get the nvmap device. 122 // Get the nvmap device.
121 auto nvmap_fd = nvdrv.Open("/dev/nvmap");
122 auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd); 123 auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
123 ASSERT(nvmap != nullptr); 124 ASSERT(nvmap != nullptr);
124 125
@@ -127,11 +128,11 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv,
127 128
128 // Ensure we maintain a clean state on failure. 129 // Ensure we maintain a clean state on failure.
129 ON_RESULT_FAILURE { 130 ON_RESULT_FAILURE {
130 ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle))); 131 ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd)));
131 }; 132 };
132 133
133 // Assign the allocated memory to the handle. 134 // Assign the allocated memory to the handle.
134 R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size)); 135 R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd));
135} 136}
136 137
137constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; 138constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
@@ -197,9 +198,13 @@ Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u
197 std::addressof(m_buffer_page_group), m_system, 198 std::addressof(m_buffer_page_group), m_system,
198 SharedBufferSize)); 199 SharedBufferSize));
199 200
201 auto& container = m_nvdrv->GetContainer();
202 m_session_id = container.OpenSession(m_system.ApplicationProcess());
203 m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id);
204
200 // Create an nvmap handle for the buffer and assign the memory to it. 205 // Create an nvmap handle for the buffer and assign the memory to it.
201 R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, map_address, 206 R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd,
202 SharedBufferSize)); 207 map_address, SharedBufferSize));
203 208
204 // Record the display id. 209 // Record the display id.
205 m_display_id = display_id; 210 m_display_id = display_id;
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
index c809c01b4..033bf4bbe 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
@@ -4,6 +4,8 @@
4#pragma once 4#pragma once
5 5
6#include "common/math_util.h" 6#include "common/math_util.h"
7#include "core/hle/service/nvdrv/core/container.h"
8#include "core/hle/service/nvdrv/nvdata.h"
7#include "core/hle/service/nvnflinger/nvnflinger.h" 9#include "core/hle/service/nvnflinger/nvnflinger.h"
8#include "core/hle/service/nvnflinger/ui/fence.h" 10#include "core/hle/service/nvnflinger/ui/fence.h"
9 11
@@ -53,7 +55,8 @@ private:
53 u64 m_layer_id = 0; 55 u64 m_layer_id = 0;
54 u32 m_buffer_nvmap_handle = 0; 56 u32 m_buffer_nvmap_handle = 0;
55 SharedMemoryPoolLayout m_pool_layout = {}; 57 SharedMemoryPoolLayout m_pool_layout = {};
56 58 Nvidia::DeviceFD m_nvmap_fd = {};
59 Nvidia::NvCore::SessionId m_session_id = {};
57 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; 60 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
58 61
59 std::mutex m_guard; 62 std::mutex m_guard;
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index af6591370..71d6fdb0c 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -124,7 +124,7 @@ void Nvnflinger::ShutdownLayers() {
124 124
125void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { 125void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
126 nvdrv = std::move(instance); 126 nvdrv = std::move(instance);
127 disp_fd = nvdrv->Open("/dev/nvdisp_disp0"); 127 disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {});
128} 128}
129 129
130std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) { 130std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) {
diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
index ce70946ec..ede2a1193 100644
--- a/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
+++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
@@ -22,11 +22,13 @@ GraphicBuffer::GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
22 : NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) { 22 : NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) {
23 if (this->BufferId() > 0) { 23 if (this->BufferId() > 0) {
24 m_nvmap->DuplicateHandle(this->BufferId(), true); 24 m_nvmap->DuplicateHandle(this->BufferId(), true);
25 m_nvmap->PinHandle(this->BufferId(), false);
25 } 26 }
26} 27}
27 28
28GraphicBuffer::~GraphicBuffer() { 29GraphicBuffer::~GraphicBuffer() {
29 if (m_nvmap != nullptr && this->BufferId() > 0) { 30 if (m_nvmap != nullptr && this->BufferId() > 0) {
31 m_nvmap->UnpinHandle(this->BufferId());
30 m_nvmap->FreeHandle(this->BufferId(), true); 32 m_nvmap->FreeHandle(this->BufferId(), true);
31 } 33 }
32} 34}
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index cd0cc9287..44310756b 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -4,9 +4,13 @@
4#include <memory> 4#include <memory>
5 5
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
7#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
8#include "core/hle/service/psc/psc.h" 9#include "core/hle/service/psc/psc.h"
9#include "core/hle/service/server_manager.h" 10#include "core/hle/service/psc/time/manager.h"
11#include "core/hle/service/psc/time/power_state_service.h"
12#include "core/hle/service/psc/time/service_manager.h"
13#include "core/hle/service/psc/time/static.h"
10#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
11 15
12namespace Service::PSC { 16namespace Service::PSC {
@@ -76,6 +80,17 @@ void LoopProcess(Core::System& system) {
76 80
77 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); 81 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
78 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); 82 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
83
84 auto time = std::make_shared<Time::TimeManager>(system);
85
86 server_manager->RegisterNamedService(
87 "time:m", std::make_shared<Time::ServiceManager>(system, time, server_manager.get()));
88 server_manager->RegisterNamedService(
89 "time:su", std::make_shared<Time::StaticService>(
90 system, Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 1}, time, "time:su"));
91 server_manager->RegisterNamedService("time:al",
92 std::make_shared<Time::IAlarmService>(system, time));
93
79 ServerManager::RunServer(std::move(server_manager)); 94 ServerManager::RunServer(std::move(server_manager));
80} 95}
81 96
diff --git a/src/core/hle/service/psc/time/alarms.cpp b/src/core/hle/service/psc/time/alarms.cpp
new file mode 100644
index 000000000..5e52c19f8
--- /dev/null
+++ b/src/core/hle/service/psc/time/alarms.cpp
@@ -0,0 +1,209 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/psc/time/alarms.h"
6#include "core/hle/service/psc/time/manager.h"
7
8namespace Service::PSC::Time {
9Alarm::Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type)
10 : m_ctx{ctx}, m_event{ctx.CreateEvent("Psc:Alarm:Event")} {
11 m_event->Clear();
12
13 switch (type) {
14 case WakeupAlarm:
15 m_priority = 1;
16 break;
17 case BackgroundTaskAlarm:
18 m_priority = 0;
19 break;
20 default:
21 UNREACHABLE();
22 return;
23 }
24}
25
26Alarm::~Alarm() {
27 m_ctx.CloseEvent(m_event);
28}
29
30Alarms::Alarms(Core::System& system, StandardSteadyClockCore& steady_clock,
31 PowerStateRequestManager& power_state_request_manager)
32 : m_system{system}, m_ctx{system, "Psc:Alarms"}, m_steady_clock{steady_clock},
33 m_power_state_request_manager{power_state_request_manager}, m_event{m_ctx.CreateEvent(
34 "Psc:Alarms:Event")} {}
35
36Alarms::~Alarms() {
37 m_ctx.CloseEvent(m_event);
38}
39
40Result Alarms::Enable(Alarm& alarm, s64 time) {
41 R_UNLESS(m_steady_clock.IsInitialized(), ResultClockUninitialized);
42
43 std::scoped_lock l{m_mutex};
44 R_UNLESS(alarm.IsLinked(), ResultAlarmNotRegistered);
45
46 auto time_ns{time + m_steady_clock.GetRawTime()};
47 auto one_second_ns{
48 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
49 time_ns = Common::AlignUp(time_ns, one_second_ns);
50 alarm.SetAlertTime(time_ns);
51
52 Insert(alarm);
53 R_RETURN(UpdateClosestAndSignal());
54}
55
56void Alarms::Disable(Alarm& alarm) {
57 std::scoped_lock l{m_mutex};
58 if (!alarm.IsLinked()) {
59 return;
60 }
61
62 Erase(alarm);
63 UpdateClosestAndSignal();
64}
65
66void Alarms::CheckAndSignal() {
67 std::scoped_lock l{m_mutex};
68 if (m_alarms.empty()) {
69 return;
70 }
71
72 bool alarm_signalled{false};
73 for (auto& alarm : m_alarms) {
74 if (m_steady_clock.GetRawTime() >= alarm.GetAlertTime()) {
75 alarm.Signal();
76 alarm.Lock();
77 Erase(alarm);
78
79 m_power_state_request_manager.UpdatePendingPowerStateRequestPriority(
80 alarm.GetPriority());
81 alarm_signalled = true;
82 }
83 }
84
85 if (!alarm_signalled) {
86 return;
87 }
88
89 m_power_state_request_manager.SignalPowerStateRequestAvailability();
90 UpdateClosestAndSignal();
91}
92
93bool Alarms::GetClosestAlarm(Alarm** out_alarm) {
94 std::scoped_lock l{m_mutex};
95 auto alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front());
96 *out_alarm = alarm;
97 return alarm != nullptr;
98}
99
100void Alarms::Insert(Alarm& alarm) {
101 // Alarms are sorted by alert time, then priority
102 auto it{m_alarms.begin()};
103 while (it != m_alarms.end()) {
104 if (alarm.GetAlertTime() < it->GetAlertTime() ||
105 (alarm.GetAlertTime() == it->GetAlertTime() &&
106 alarm.GetPriority() < it->GetPriority())) {
107 m_alarms.insert(it, alarm);
108 return;
109 }
110 it++;
111 }
112
113 m_alarms.push_back(alarm);
114}
115
116void Alarms::Erase(Alarm& alarm) {
117 m_alarms.erase(m_alarms.iterator_to(alarm));
118}
119
120Result Alarms::UpdateClosestAndSignal() {
121 m_closest_alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front());
122 R_SUCCEED_IF(m_closest_alarm == nullptr);
123
124 m_event->Signal();
125
126 R_SUCCEED();
127}
128
129IAlarmService::IAlarmService(Core::System& system_, std::shared_ptr<TimeManager> manager)
130 : ServiceFramework{system_, "time:al"}, m_system{system}, m_alarms{manager->m_alarms} {
131 // clang-format off
132 static const FunctionInfo functions[] = {
133 {0, &IAlarmService::CreateWakeupAlarm, "CreateWakeupAlarm"},
134 {1, &IAlarmService::CreateBackgroundTaskAlarm, "CreateBackgroundTaskAlarm"},
135 };
136 // clang-format on
137 RegisterHandlers(functions);
138}
139
140void IAlarmService::CreateWakeupAlarm(HLERequestContext& ctx) {
141 LOG_DEBUG(Service_Time, "called.");
142
143 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
144 rb.Push(ResultSuccess);
145 rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::WakeupAlarm);
146}
147
148void IAlarmService::CreateBackgroundTaskAlarm(HLERequestContext& ctx) {
149 LOG_DEBUG(Service_Time, "called.");
150
151 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
152 rb.Push(ResultSuccess);
153 rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::BackgroundTaskAlarm);
154}
155
156ISteadyClockAlarm::ISteadyClockAlarm(Core::System& system_, Alarms& alarms, AlarmType type)
157 : ServiceFramework{system_, "ISteadyClockAlarm"}, m_ctx{system, "Psc:ISteadyClockAlarm"},
158 m_alarms{alarms}, m_alarm{system, m_ctx, type} {
159 // clang-format off
160 static const FunctionInfo functions[] = {
161 {0, &ISteadyClockAlarm::GetAlarmEvent, "GetAlarmEvent"},
162 {1, &ISteadyClockAlarm::Enable, "Enable"},
163 {2, &ISteadyClockAlarm::Disable, "Disable"},
164 {3, &ISteadyClockAlarm::IsEnabled, "IsEnabled"},
165 {10, nullptr, "CreateWakeLock"},
166 {11, nullptr, "DestroyWakeLock"},
167 };
168 // clang-format on
169 RegisterHandlers(functions);
170}
171
172void ISteadyClockAlarm::GetAlarmEvent(HLERequestContext& ctx) {
173 LOG_DEBUG(Service_Time, "called.");
174
175 IPC::ResponseBuilder rb{ctx, 2, 1};
176 rb.Push(ResultSuccess);
177 rb.PushCopyObjects(m_alarm.GetEventHandle());
178}
179
180void ISteadyClockAlarm::Enable(HLERequestContext& ctx) {
181 LOG_DEBUG(Service_Time, "called.");
182
183 IPC::RequestParser rp{ctx};
184 auto time{rp.Pop<s64>()};
185
186 auto res = m_alarms.Enable(m_alarm, time);
187
188 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(res);
190}
191
192void ISteadyClockAlarm::Disable(HLERequestContext& ctx) {
193 LOG_DEBUG(Service_Time, "called.");
194
195 m_alarms.Disable(m_alarm);
196
197 IPC::ResponseBuilder rb{ctx, 2};
198 rb.Push(ResultSuccess);
199}
200
201void ISteadyClockAlarm::IsEnabled(HLERequestContext& ctx) {
202 LOG_DEBUG(Service_Time, "called.");
203
204 IPC::ResponseBuilder rb{ctx, 3};
205 rb.Push(ResultSuccess);
206 rb.Push<bool>(m_alarm.IsLinked());
207}
208
209} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/alarms.h b/src/core/hle/service/psc/time/alarms.h
new file mode 100644
index 000000000..597770028
--- /dev/null
+++ b/src/core/hle/service/psc/time/alarms.h
@@ -0,0 +1,139 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
12#include "core/hle/service/psc/time/common.h"
13#include "core/hle/service/psc/time/power_state_request_manager.h"
14#include "core/hle/service/server_manager.h"
15#include "core/hle/service/service.h"
16
17namespace Core {
18class System;
19}
20
21namespace Service::PSC::Time {
22class TimeManager;
23
24enum AlarmType : u32 {
25 WakeupAlarm = 0,
26 BackgroundTaskAlarm = 1,
27};
28
29struct Alarm : public Common::IntrusiveListBaseNode<Alarm> {
30 using AlarmList = Common::IntrusiveListBaseTraits<Alarm>::ListType;
31
32 Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type);
33 ~Alarm();
34
35 Kernel::KReadableEvent& GetEventHandle() {
36 return m_event->GetReadableEvent();
37 }
38
39 s64 GetAlertTime() const {
40 return m_alert_time;
41 }
42
43 void SetAlertTime(s64 time) {
44 m_alert_time = time;
45 }
46
47 u32 GetPriority() const {
48 return m_priority;
49 }
50
51 void Signal() {
52 m_event->Signal();
53 }
54
55 Result Lock() {
56 // TODO
57 // if (m_lock_service) {
58 // return m_lock_service->Lock();
59 // }
60 R_SUCCEED();
61 }
62
63 KernelHelpers::ServiceContext& m_ctx;
64
65 u32 m_priority;
66 Kernel::KEvent* m_event{};
67 s64 m_alert_time{};
68 // TODO
69 // nn::psc::sf::IPmStateLock* m_lock_service{};
70};
71
72class Alarms {
73public:
74 explicit Alarms(Core::System& system, StandardSteadyClockCore& steady_clock,
75 PowerStateRequestManager& power_state_request_manager);
76 ~Alarms();
77
78 Kernel::KEvent& GetEvent() {
79 return *m_event;
80 }
81
82 s64 GetRawTime() {
83 return m_steady_clock.GetRawTime();
84 }
85
86 Result Enable(Alarm& alarm, s64 time);
87 void Disable(Alarm& alarm);
88 void CheckAndSignal();
89 bool GetClosestAlarm(Alarm** out_alarm);
90
91private:
92 void Insert(Alarm& alarm);
93 void Erase(Alarm& alarm);
94 Result UpdateClosestAndSignal();
95
96 Core::System& m_system;
97 KernelHelpers::ServiceContext m_ctx;
98
99 StandardSteadyClockCore& m_steady_clock;
100 PowerStateRequestManager& m_power_state_request_manager;
101 Alarm::AlarmList m_alarms;
102 Kernel::KEvent* m_event{};
103 Alarm* m_closest_alarm{};
104 std::mutex m_mutex;
105};
106
107class IAlarmService final : public ServiceFramework<IAlarmService> {
108public:
109 explicit IAlarmService(Core::System& system, std::shared_ptr<TimeManager> manager);
110
111 ~IAlarmService() override = default;
112
113private:
114 void CreateWakeupAlarm(HLERequestContext& ctx);
115 void CreateBackgroundTaskAlarm(HLERequestContext& ctx);
116
117 Core::System& m_system;
118 Alarms& m_alarms;
119};
120
121class ISteadyClockAlarm final : public ServiceFramework<ISteadyClockAlarm> {
122public:
123 explicit ISteadyClockAlarm(Core::System& system, Alarms& alarms, AlarmType type);
124
125 ~ISteadyClockAlarm() override = default;
126
127private:
128 void GetAlarmEvent(HLERequestContext& ctx);
129 void Enable(HLERequestContext& ctx);
130 void Disable(HLERequestContext& ctx);
131 void IsEnabled(HLERequestContext& ctx);
132
133 KernelHelpers::ServiceContext m_ctx;
134
135 Alarms& m_alarms;
136 Alarm m_alarm;
137};
138
139} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/context_writers.cpp b/src/core/hle/service/psc/time/clocks/context_writers.cpp
new file mode 100644
index 000000000..ac8700f76
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/context_writers.cpp
@@ -0,0 +1,83 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/psc/time/clocks/context_writers.h"
6
7namespace Service::PSC::Time {
8
9void ContextWriter::SignalAllNodes() {
10 std::scoped_lock l{m_mutex};
11 for (auto& operation : m_operation_events) {
12 operation.m_event->Signal();
13 }
14}
15
16void ContextWriter::Link(OperationEvent& operation_event) {
17 std::scoped_lock l{m_mutex};
18 m_operation_events.push_back(operation_event);
19}
20
21LocalSystemClockContextWriter::LocalSystemClockContextWriter(Core::System& system,
22 SharedMemory& shared_memory)
23 : m_system{system}, m_shared_memory{shared_memory} {}
24
25Result LocalSystemClockContextWriter::Write(SystemClockContext& context) {
26 if (m_in_use) {
27 R_SUCCEED_IF(context == m_context);
28 m_context = context;
29 } else {
30 m_context = context;
31 m_in_use = true;
32 }
33
34 m_shared_memory.SetLocalSystemContext(context);
35
36 SignalAllNodes();
37
38 R_SUCCEED();
39}
40
41NetworkSystemClockContextWriter::NetworkSystemClockContextWriter(Core::System& system,
42 SharedMemory& shared_memory,
43 SystemClockCore& system_clock)
44 : m_system{system}, m_shared_memory{shared_memory}, m_system_clock{system_clock} {}
45
46Result NetworkSystemClockContextWriter::Write(SystemClockContext& context) {
47 s64 time{};
48 [[maybe_unused]] auto res = m_system_clock.GetCurrentTime(&time);
49
50 if (m_in_use) {
51 R_SUCCEED_IF(context == m_context);
52 m_context = context;
53 } else {
54 m_context = context;
55 m_in_use = true;
56 }
57
58 m_shared_memory.SetNetworkSystemContext(context);
59
60 SignalAllNodes();
61
62 R_SUCCEED();
63}
64
65EphemeralNetworkSystemClockContextWriter::EphemeralNetworkSystemClockContextWriter(
66 Core::System& system)
67 : m_system{system} {}
68
69Result EphemeralNetworkSystemClockContextWriter::Write(SystemClockContext& context) {
70 if (m_in_use) {
71 R_SUCCEED_IF(context == m_context);
72 m_context = context;
73 } else {
74 m_context = context;
75 m_in_use = true;
76 }
77
78 SignalAllNodes();
79
80 R_SUCCEED();
81}
82
83} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/context_writers.h b/src/core/hle/service/psc/time/clocks/context_writers.h
new file mode 100644
index 000000000..afd3725d4
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/context_writers.h
@@ -0,0 +1,79 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <list>
7
8#include "common/common_types.h"
9#include "core/hle/kernel/k_event.h"
10#include "core/hle/service/psc/time/clocks/system_clock_core.h"
11#include "core/hle/service/psc/time/common.h"
12#include "core/hle/service/psc/time/shared_memory.h"
13
14namespace Core {
15class System;
16}
17
18namespace Service::PSC::Time {
19
20class ContextWriter {
21private:
22 using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType;
23
24public:
25 virtual ~ContextWriter() = default;
26
27 virtual Result Write(SystemClockContext& context) = 0;
28 void SignalAllNodes();
29 void Link(OperationEvent& operation_event);
30
31private:
32 OperationEventList m_operation_events;
33 std::mutex m_mutex;
34};
35
36class LocalSystemClockContextWriter : public ContextWriter {
37public:
38 explicit LocalSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory);
39
40 Result Write(SystemClockContext& context) override;
41
42private:
43 Core::System& m_system;
44
45 SharedMemory& m_shared_memory;
46 bool m_in_use{};
47 SystemClockContext m_context{};
48};
49
50class NetworkSystemClockContextWriter : public ContextWriter {
51public:
52 explicit NetworkSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory,
53 SystemClockCore& system_clock);
54
55 Result Write(SystemClockContext& context) override;
56
57private:
58 Core::System& m_system;
59
60 SharedMemory& m_shared_memory;
61 bool m_in_use{};
62 SystemClockContext m_context{};
63 SystemClockCore& m_system_clock;
64};
65
66class EphemeralNetworkSystemClockContextWriter : public ContextWriter {
67public:
68 EphemeralNetworkSystemClockContextWriter(Core::System& system);
69
70 Result Write(SystemClockContext& context) override;
71
72private:
73 Core::System& m_system;
74
75 bool m_in_use{};
76 SystemClockContext m_context{};
77};
78
79} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h b/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h
new file mode 100644
index 000000000..0a68867d9
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7#include "core/hle/service/psc/time/clocks/context_writers.h"
8#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
9#include "core/hle/service/psc/time/clocks/system_clock_core.h"
10#include "core/hle/service/psc/time/common.h"
11
12namespace Service::PSC::Time {
13
14class EphemeralNetworkSystemClockCore : public SystemClockCore {
15public:
16 explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock)
17 : SystemClockCore{steady_clock} {}
18 ~EphemeralNetworkSystemClockCore() override = default;
19};
20
21} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp
new file mode 100644
index 000000000..36dca6689
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
5
6namespace Service::PSC::Time {
7
8void StandardLocalSystemClockCore::Initialize(SystemClockContext& context, s64 time) {
9 SteadyClockTimePoint time_point{};
10 if (GetCurrentTimePoint(time_point) == ResultSuccess &&
11 context.steady_time_point.IdMatches(time_point)) {
12 SetContextAndWrite(context);
13 } else if (SetCurrentTime(time) != ResultSuccess) {
14 LOG_ERROR(Service_Time, "Failed to SetCurrentTime");
15 }
16
17 SetInitialized();
18}
19
20} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h
new file mode 100644
index 000000000..176ba3e94
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7#include "core/hle/service/psc/time/clocks/context_writers.h"
8#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
9#include "core/hle/service/psc/time/clocks/system_clock_core.h"
10#include "core/hle/service/psc/time/common.h"
11
12namespace Service::PSC::Time {
13
14class StandardLocalSystemClockCore : public SystemClockCore {
15public:
16 explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock)
17 : SystemClockCore{steady_clock} {}
18 ~StandardLocalSystemClockCore() override = default;
19
20 void Initialize(SystemClockContext& context, s64 time);
21};
22
23} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp
new file mode 100644
index 000000000..8d6cb7db1
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp
@@ -0,0 +1,42 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
5
6namespace Service::PSC::Time {
7
8void StandardNetworkSystemClockCore::Initialize(SystemClockContext& context, s64 accuracy) {
9 if (SetContextAndWrite(context) != ResultSuccess) {
10 LOG_ERROR(Service_Time, "Failed to SetContext");
11 }
12 m_sufficient_accuracy = accuracy;
13 SetInitialized();
14}
15
16bool StandardNetworkSystemClockCore::IsAccuracySufficient() {
17 if (!IsInitialized()) {
18 return false;
19 }
20
21 SystemClockContext context{};
22 SteadyClockTimePoint current_time_point{};
23 if (GetCurrentTimePoint(current_time_point) != ResultSuccess ||
24 GetContext(context) != ResultSuccess) {
25 return false;
26 }
27
28 s64 seconds{};
29 if (GetSpanBetweenTimePoints(&seconds, context.steady_time_point, current_time_point) !=
30 ResultSuccess) {
31 return false;
32 }
33
34 if (std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(seconds))
35 .count() < m_sufficient_accuracy) {
36 return true;
37 }
38
39 return false;
40}
41
42} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h
new file mode 100644
index 000000000..933d2c8e3
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <chrono>
7
8#include "core/hle/result.h"
9#include "core/hle/service/psc/time/clocks/context_writers.h"
10#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
11#include "core/hle/service/psc/time/clocks/system_clock_core.h"
12#include "core/hle/service/psc/time/common.h"
13
14namespace Service::PSC::Time {
15
16class StandardNetworkSystemClockCore : public SystemClockCore {
17public:
18 explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock)
19 : SystemClockCore{steady_clock} {}
20 ~StandardNetworkSystemClockCore() override = default;
21
22 void Initialize(SystemClockContext& context, s64 accuracy);
23 bool IsAccuracySufficient();
24
25private:
26 s64 m_sufficient_accuracy{
27 std::chrono ::duration_cast<std::chrono::nanoseconds>(std::chrono::days(10)).count()};
28};
29
30} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp
new file mode 100644
index 000000000..7a72d7aa2
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp
@@ -0,0 +1,101 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5
6#include "core/core.h"
7#include "core/core_timing.h"
8#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
9
10namespace Service::PSC::Time {
11
12void StandardSteadyClockCore::Initialize(ClockSourceId clock_source_id, s64 rtc_offset,
13 s64 internal_offset, s64 test_offset,
14 bool is_rtc_reset_detected) {
15 m_clock_source_id = clock_source_id;
16 m_rtc_offset = rtc_offset;
17 m_internal_offset = internal_offset;
18 m_test_offset = test_offset;
19 if (is_rtc_reset_detected) {
20 SetResetDetected();
21 }
22 SetInitialized();
23}
24
25void StandardSteadyClockCore::SetRtcOffset(s64 offset) {
26 m_rtc_offset = offset;
27}
28
29void StandardSteadyClockCore::SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time) {
30 auto ticks{m_system.CoreTiming().GetClockTicks()};
31
32 m_continuous_adjustment_time_point.rtc_offset = ConvertToTimeSpan(ticks).count();
33 m_continuous_adjustment_time_point.diff_scale = 0;
34 m_continuous_adjustment_time_point.shift_amount = 0;
35 m_continuous_adjustment_time_point.lower = time;
36 m_continuous_adjustment_time_point.upper = time;
37 m_continuous_adjustment_time_point.clock_source_id = clock_source_id;
38}
39
40void StandardSteadyClockCore::GetContinuousAdjustment(
41 ContinuousAdjustmentTimePoint& out_time_point) const {
42 out_time_point = m_continuous_adjustment_time_point;
43}
44
45void StandardSteadyClockCore::UpdateContinuousAdjustmentTime(s64 in_time) {
46 auto ticks{m_system.CoreTiming().GetClockTicks()};
47 auto uptime_ns{ConvertToTimeSpan(ticks).count()};
48 auto adjusted_time{((uptime_ns - m_continuous_adjustment_time_point.rtc_offset) *
49 m_continuous_adjustment_time_point.diff_scale) >>
50 m_continuous_adjustment_time_point.shift_amount};
51 auto expected_time{adjusted_time + m_continuous_adjustment_time_point.lower};
52
53 auto last_time_point{m_continuous_adjustment_time_point.upper};
54 m_continuous_adjustment_time_point.upper = in_time;
55 auto t1{std::min<s64>(expected_time, last_time_point)};
56 expected_time = std::max<s64>(expected_time, last_time_point);
57 expected_time = m_continuous_adjustment_time_point.diff_scale >= 0 ? t1 : expected_time;
58
59 auto new_diff{in_time < expected_time ? -55 : 55};
60
61 m_continuous_adjustment_time_point.rtc_offset = uptime_ns;
62 m_continuous_adjustment_time_point.shift_amount = expected_time == in_time ? 0 : 14;
63 m_continuous_adjustment_time_point.diff_scale = expected_time == in_time ? 0 : new_diff;
64 m_continuous_adjustment_time_point.lower = expected_time;
65}
66
67Result StandardSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) {
68 auto current_time_ns = GetCurrentRawTimePointImpl();
69 auto current_time_s =
70 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::nanoseconds(current_time_ns));
71 out_time_point.time_point = current_time_s.count();
72 out_time_point.clock_source_id = m_clock_source_id;
73 R_SUCCEED();
74}
75
76s64 StandardSteadyClockCore::GetCurrentRawTimePointImpl() {
77 std::scoped_lock l{m_mutex};
78 auto ticks{static_cast<s64>(m_system.CoreTiming().GetClockTicks())};
79 auto current_time_ns = m_rtc_offset + ConvertToTimeSpan(ticks).count();
80 auto time_point = std::max<s64>(current_time_ns, m_cached_time_point);
81 m_cached_time_point = time_point;
82 return time_point;
83}
84
85s64 StandardSteadyClockCore::GetTestOffsetImpl() const {
86 return m_test_offset;
87}
88
89void StandardSteadyClockCore::SetTestOffsetImpl(s64 offset) {
90 m_test_offset = offset;
91}
92
93s64 StandardSteadyClockCore::GetInternalOffsetImpl() const {
94 return m_internal_offset;
95}
96
97void StandardSteadyClockCore::SetInternalOffsetImpl(s64 offset) {
98 m_internal_offset = offset;
99}
100
101} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h
new file mode 100644
index 000000000..bbf98fcd5
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h
@@ -0,0 +1,54 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7
8#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::PSC::Time {
15class StandardSteadyClockCore : public SteadyClockCore {
16public:
17 explicit StandardSteadyClockCore(Core::System& system) : m_system{system} {}
18 ~StandardSteadyClockCore() override = default;
19
20 void Initialize(ClockSourceId clock_source_id, s64 rtc_offset, s64 internal_offset,
21 s64 test_offset, bool is_rtc_reset_detected);
22
23 void SetRtcOffset(s64 offset);
24 void SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time);
25 void GetContinuousAdjustment(ContinuousAdjustmentTimePoint& out_time_point) const;
26 void UpdateContinuousAdjustmentTime(s64 time);
27
28 Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override;
29 s64 GetCurrentRawTimePointImpl() override;
30 s64 GetTestOffsetImpl() const override;
31 void SetTestOffsetImpl(s64 offset) override;
32 s64 GetInternalOffsetImpl() const override;
33 void SetInternalOffsetImpl(s64 offset) override;
34
35 Result GetRtcValueImpl(s64& out_value) override {
36 R_RETURN(ResultNotImplemented);
37 }
38
39 Result GetSetupResultValueImpl() override {
40 R_SUCCEED();
41 }
42
43private:
44 Core::System& m_system;
45
46 std::mutex m_mutex;
47 s64 m_test_offset{};
48 s64 m_internal_offset{};
49 ClockSourceId m_clock_source_id{};
50 s64 m_rtc_offset{};
51 s64 m_cached_time_point{};
52 ContinuousAdjustmentTimePoint m_continuous_adjustment_time_point{};
53};
54} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp
new file mode 100644
index 000000000..9e9be05d6
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
6
7namespace Service::PSC::Time {
8
9StandardUserSystemClockCore::StandardUserSystemClockCore(
10 Core::System& system, StandardLocalSystemClockCore& local_clock,
11 StandardNetworkSystemClockCore& network_clock)
12 : SystemClockCore{local_clock.GetSteadyClock()}, m_system{system},
13 m_ctx{m_system, "Psc:StandardUserSystemClockCore"}, m_local_system_clock{local_clock},
14 m_network_system_clock{network_clock}, m_event{m_ctx.CreateEvent(
15 "Psc:StandardUserSystemClockCore:Event")} {}
16
17StandardUserSystemClockCore::~StandardUserSystemClockCore() {
18 m_ctx.CloseEvent(m_event);
19}
20
21Result StandardUserSystemClockCore::SetAutomaticCorrection(bool automatic_correction) {
22 R_SUCCEED_IF(m_automatic_correction == automatic_correction);
23 R_SUCCEED_IF(!m_network_system_clock.CheckClockSourceMatches());
24
25 SystemClockContext context{};
26 R_TRY(m_network_system_clock.GetContext(context));
27 R_TRY(m_local_system_clock.SetContextAndWrite(context));
28
29 m_automatic_correction = automatic_correction;
30 R_SUCCEED();
31}
32
33Result StandardUserSystemClockCore::GetContext(SystemClockContext& out_context) const {
34 if (!m_automatic_correction) {
35 R_RETURN(m_local_system_clock.GetContext(out_context));
36 }
37
38 if (!m_network_system_clock.CheckClockSourceMatches()) {
39 R_RETURN(m_local_system_clock.GetContext(out_context));
40 }
41
42 SystemClockContext context{};
43 R_TRY(m_network_system_clock.GetContext(context));
44 R_TRY(m_local_system_clock.SetContextAndWrite(context));
45
46 R_RETURN(m_local_system_clock.GetContext(out_context));
47}
48
49Result StandardUserSystemClockCore::SetContext(SystemClockContext& context) {
50 R_RETURN(ResultNotImplemented);
51}
52
53Result StandardUserSystemClockCore::GetTimePoint(SteadyClockTimePoint& out_time_point) {
54 out_time_point = m_time_point;
55 R_SUCCEED();
56}
57
58void StandardUserSystemClockCore::SetTimePointAndSignal(SteadyClockTimePoint& time_point) {
59 m_time_point = time_point;
60 m_event->Signal();
61}
62
63} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h
new file mode 100644
index 000000000..a7fe7648d
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h
@@ -0,0 +1,55 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/kernel/k_event.h"
7#include "core/hle/result.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/psc/time/clocks/context_writers.h"
10#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
11#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
12#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
13#include "core/hle/service/psc/time/clocks/system_clock_core.h"
14#include "core/hle/service/psc/time/common.h"
15
16namespace Core {
17class System;
18}
19
20namespace Service::PSC::Time {
21
22class StandardUserSystemClockCore : public SystemClockCore {
23public:
24 explicit StandardUserSystemClockCore(Core::System& system,
25 StandardLocalSystemClockCore& local_clock,
26 StandardNetworkSystemClockCore& network_clock);
27 ~StandardUserSystemClockCore() override;
28
29 Kernel::KEvent& GetEvent() {
30 return *m_event;
31 }
32
33 bool GetAutomaticCorrection() const {
34 return m_automatic_correction;
35 }
36 Result SetAutomaticCorrection(bool automatic_correction);
37
38 Result GetContext(SystemClockContext& out_context) const override;
39 Result SetContext(SystemClockContext& context) override;
40
41 Result GetTimePoint(SteadyClockTimePoint& out_time_point);
42 void SetTimePointAndSignal(SteadyClockTimePoint& time_point);
43
44private:
45 Core::System& m_system;
46 KernelHelpers::ServiceContext m_ctx;
47
48 bool m_automatic_correction{};
49 StandardLocalSystemClockCore& m_local_system_clock;
50 StandardNetworkSystemClockCore& m_network_system_clock;
51 SteadyClockTimePoint m_time_point{};
52 Kernel::KEvent* m_event{};
53};
54
55} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/steady_clock_core.h b/src/core/hle/service/psc/time/clocks/steady_clock_core.h
new file mode 100644
index 000000000..f933cc15f
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/steady_clock_core.h
@@ -0,0 +1,81 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <chrono>
7
8#include "core/hle/result.h"
9#include "core/hle/service/psc/time/common.h"
10
11namespace Service::PSC::Time {
12
13class SteadyClockCore {
14public:
15 SteadyClockCore() = default;
16 virtual ~SteadyClockCore() = default;
17
18 void SetInitialized() {
19 m_initialized = true;
20 }
21
22 bool IsInitialized() const {
23 return m_initialized;
24 }
25
26 void SetResetDetected() {
27 m_reset_detected = true;
28 }
29
30 bool IsResetDetected() const {
31 return m_reset_detected;
32 }
33
34 Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
35 R_TRY(GetCurrentTimePointImpl(out_time_point));
36
37 auto one_second_ns{
38 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
39 out_time_point.time_point += GetTestOffsetImpl() / one_second_ns;
40 out_time_point.time_point += GetInternalOffsetImpl() / one_second_ns;
41 R_SUCCEED();
42 }
43
44 s64 GetTestOffset() const {
45 return GetTestOffsetImpl();
46 }
47
48 void SetTestOffset(s64 offset) {
49 SetTestOffsetImpl(offset);
50 }
51
52 s64 GetInternalOffset() const {
53 return GetInternalOffsetImpl();
54 }
55
56 s64 GetRawTime() {
57 return GetCurrentRawTimePointImpl() + GetTestOffsetImpl() + GetInternalOffsetImpl();
58 }
59
60 Result GetRtcValue(s64& out_value) {
61 R_RETURN(GetRtcValueImpl(out_value));
62 }
63
64 Result GetSetupResultValue() {
65 R_RETURN(GetSetupResultValueImpl());
66 }
67
68private:
69 virtual Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) = 0;
70 virtual s64 GetCurrentRawTimePointImpl() = 0;
71 virtual s64 GetTestOffsetImpl() const = 0;
72 virtual void SetTestOffsetImpl(s64 offset) = 0;
73 virtual s64 GetInternalOffsetImpl() const = 0;
74 virtual void SetInternalOffsetImpl(s64 offset) = 0;
75 virtual Result GetRtcValueImpl(s64& out_value) = 0;
76 virtual Result GetSetupResultValueImpl() = 0;
77
78 bool m_initialized{};
79 bool m_reset_detected{};
80};
81} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/system_clock_core.cpp
new file mode 100644
index 000000000..c507ef517
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/system_clock_core.cpp
@@ -0,0 +1,75 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/time/clocks/context_writers.h"
5#include "core/hle/service/psc/time/clocks/system_clock_core.h"
6
7namespace Service::PSC::Time {
8
9bool SystemClockCore::CheckClockSourceMatches() {
10 SystemClockContext context{};
11 if (GetContext(context) != ResultSuccess) {
12 return false;
13 }
14
15 SteadyClockTimePoint time_point{};
16 if (m_steady_clock.GetCurrentTimePoint(time_point) != ResultSuccess) {
17 return false;
18 }
19
20 return context.steady_time_point.IdMatches(time_point);
21}
22
23Result SystemClockCore::GetCurrentTime(s64* out_time) const {
24 R_UNLESS(out_time != nullptr, ResultInvalidArgument);
25
26 SystemClockContext context{};
27 SteadyClockTimePoint time_point{};
28
29 R_TRY(m_steady_clock.GetCurrentTimePoint(time_point));
30 R_TRY(GetContext(context));
31
32 R_UNLESS(context.steady_time_point.IdMatches(time_point), ResultClockMismatch);
33
34 *out_time = context.offset + time_point.time_point;
35 R_SUCCEED();
36}
37
38Result SystemClockCore::SetCurrentTime(s64 time) {
39 SteadyClockTimePoint time_point{};
40 R_TRY(m_steady_clock.GetCurrentTimePoint(time_point));
41
42 SystemClockContext context{
43 .offset = time - time_point.time_point,
44 .steady_time_point = time_point,
45 };
46 R_RETURN(SetContextAndWrite(context));
47}
48
49Result SystemClockCore::GetContext(SystemClockContext& out_context) const {
50 out_context = m_context;
51 R_SUCCEED();
52}
53
54Result SystemClockCore::SetContext(SystemClockContext& context) {
55 m_context = context;
56 R_SUCCEED();
57}
58
59Result SystemClockCore::SetContextAndWrite(SystemClockContext& context) {
60 R_TRY(SetContext(context));
61
62 if (m_context_writer) {
63 R_RETURN(m_context_writer->Write(context));
64 }
65
66 R_SUCCEED();
67}
68
69void SystemClockCore::LinkOperationEvent(OperationEvent& operation_event) {
70 if (m_context_writer) {
71 m_context_writer->Link(operation_event);
72 }
73}
74
75} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/system_clock_core.h b/src/core/hle/service/psc/time/clocks/system_clock_core.h
new file mode 100644
index 000000000..73811712e
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/system_clock_core.h
@@ -0,0 +1,55 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
8#include "core/hle/service/psc/time/common.h"
9
10namespace Service::PSC::Time {
11class ContextWriter;
12
13class SystemClockCore {
14public:
15 explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {}
16 virtual ~SystemClockCore() = default;
17
18 SteadyClockCore& GetSteadyClock() {
19 return m_steady_clock;
20 }
21
22 bool IsInitialized() const {
23 return m_initialized;
24 }
25
26 void SetInitialized() {
27 m_initialized = true;
28 }
29
30 void SetContextWriter(ContextWriter& context_writer) {
31 m_context_writer = &context_writer;
32 }
33
34 bool CheckClockSourceMatches();
35
36 Result GetCurrentTime(s64* out_time) const;
37 Result SetCurrentTime(s64 time);
38
39 Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
40 R_RETURN(m_steady_clock.GetCurrentTimePoint(out_time_point));
41 }
42
43 virtual Result GetContext(SystemClockContext& out_context) const;
44 virtual Result SetContext(SystemClockContext& context);
45 Result SetContextAndWrite(SystemClockContext& context);
46
47 void LinkOperationEvent(OperationEvent& operation_event);
48
49private:
50 bool m_initialized{};
51 ContextWriter* m_context_writer{};
52 SteadyClockCore& m_steady_clock;
53 SystemClockContext m_context{};
54};
55} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp
new file mode 100644
index 000000000..22da1fbcc
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp
@@ -0,0 +1,43 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5
6#include "core/core.h"
7#include "core/core_timing.h"
8#include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h"
9
10namespace Service::PSC::Time {
11
12Result TickBasedSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) {
13 auto ticks{m_system.CoreTiming().GetClockTicks()};
14 auto current_time_s =
15 std::chrono::duration_cast<std::chrono::seconds>(ConvertToTimeSpan(ticks)).count();
16 out_time_point.time_point = current_time_s;
17 out_time_point.clock_source_id = m_clock_source_id;
18 R_SUCCEED();
19}
20
21s64 TickBasedSteadyClockCore::GetCurrentRawTimePointImpl() {
22 SteadyClockTimePoint time_point{};
23 if (GetCurrentTimePointImpl(time_point) != ResultSuccess) {
24 LOG_ERROR(Service_Time, "Failed to GetCurrentTimePoint!");
25 }
26 return std::chrono::duration_cast<std::chrono::nanoseconds>(
27 std::chrono::seconds(time_point.time_point))
28 .count();
29}
30
31s64 TickBasedSteadyClockCore::GetTestOffsetImpl() const {
32 return 0;
33}
34
35void TickBasedSteadyClockCore::SetTestOffsetImpl(s64 offset) {}
36
37s64 TickBasedSteadyClockCore::GetInternalOffsetImpl() const {
38 return 0;
39}
40
41void TickBasedSteadyClockCore::SetInternalOffsetImpl(s64 offset) {}
42
43} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h
new file mode 100644
index 000000000..a7bea86a2
--- /dev/null
+++ b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h
@@ -0,0 +1,41 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7
8#include "common/uuid.h"
9#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::PSC::Time {
16class TickBasedSteadyClockCore : public SteadyClockCore {
17public:
18 explicit TickBasedSteadyClockCore(Core::System& system) : m_system{system} {}
19 ~TickBasedSteadyClockCore() override = default;
20
21 Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override;
22 s64 GetCurrentRawTimePointImpl() override;
23 s64 GetTestOffsetImpl() const override;
24 void SetTestOffsetImpl(s64 offset) override;
25 s64 GetInternalOffsetImpl() const override;
26 void SetInternalOffsetImpl(s64 offset) override;
27
28 Result GetRtcValueImpl(s64& out_value) override {
29 R_RETURN(ResultNotImplemented);
30 }
31
32 Result GetSetupResultValueImpl() override {
33 R_SUCCEED();
34 }
35
36private:
37 Core::System& m_system;
38
39 ClockSourceId m_clock_source_id{Common::UUID::MakeRandom()};
40};
41} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/common.cpp b/src/core/hle/service/psc/time/common.cpp
new file mode 100644
index 000000000..a6d9f02ca
--- /dev/null
+++ b/src/core/hle/service/psc/time/common.cpp
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/psc/time/common.h"
6
7namespace Service::PSC::Time {
8OperationEvent::OperationEvent(Core::System& system)
9 : m_ctx{system, "Time:OperationEvent"}, m_event{
10 m_ctx.CreateEvent("Time:OperationEvent:Event")} {}
11
12OperationEvent::~OperationEvent() {
13 m_ctx.CloseEvent(m_event);
14}
15
16} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/common.h b/src/core/hle/service/psc/time/common.h
new file mode 100644
index 000000000..d17b31143
--- /dev/null
+++ b/src/core/hle/service/psc/time/common.h
@@ -0,0 +1,168 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <chrono>
8
9#include "common/common_types.h"
10#include "common/intrusive_list.h"
11#include "common/uuid.h"
12#include "common/wall_clock.h"
13#include "core/hle/kernel/k_event.h"
14#include "core/hle/service/kernel_helpers.h"
15#include "core/hle/service/psc/time/errors.h"
16
17namespace Core {
18class System;
19}
20
21namespace Service::PSC::Time {
22using ClockSourceId = Common::UUID;
23
24struct SteadyClockTimePoint {
25 constexpr bool IdMatches(SteadyClockTimePoint& other) {
26 return clock_source_id == other.clock_source_id;
27 }
28 bool operator==(const SteadyClockTimePoint& other) const = default;
29
30 s64 time_point;
31 ClockSourceId clock_source_id;
32};
33static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint has the wrong size!");
34static_assert(std::is_trivial_v<ClockSourceId>);
35
36struct SystemClockContext {
37 bool operator==(const SystemClockContext& other) const = default;
38
39 s64 offset;
40 SteadyClockTimePoint steady_time_point;
41};
42static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext has the wrong size!");
43static_assert(std::is_trivial_v<SystemClockContext>);
44
45enum class TimeType : u8 {
46 UserSystemClock,
47 NetworkSystemClock,
48 LocalSystemClock,
49};
50
51struct CalendarTime {
52 s16 year;
53 s8 month;
54 s8 day;
55 s8 hour;
56 s8 minute;
57 s8 second;
58};
59static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime has the wrong size!");
60
61struct CalendarAdditionalInfo {
62 s32 day_of_week;
63 s32 day_of_year;
64 std::array<char, 8> name;
65 s32 is_dst;
66 s32 ut_offset;
67};
68static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo has the wrong size!");
69
70struct LocationName {
71 std::array<char, 36> name;
72};
73static_assert(sizeof(LocationName) == 0x24, "LocationName has the wrong size!");
74
75struct RuleVersion {
76 std::array<char, 16> version;
77};
78static_assert(sizeof(RuleVersion) == 0x10, "RuleVersion has the wrong size!");
79
80struct ClockSnapshot {
81 SystemClockContext user_context;
82 SystemClockContext network_context;
83 s64 user_time;
84 s64 network_time;
85 CalendarTime user_calendar_time;
86 CalendarTime network_calendar_time;
87 CalendarAdditionalInfo user_calendar_additional_time;
88 CalendarAdditionalInfo network_calendar_additional_time;
89 SteadyClockTimePoint steady_clock_time_point;
90 LocationName location_name;
91 bool is_automatic_correction_enabled;
92 TimeType type;
93 u16 unk_CE;
94};
95static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot has the wrong size!");
96static_assert(std::is_trivial_v<ClockSnapshot>);
97
98struct ContinuousAdjustmentTimePoint {
99 s64 rtc_offset;
100 s64 diff_scale;
101 s64 shift_amount;
102 s64 lower;
103 s64 upper;
104 ClockSourceId clock_source_id;
105};
106static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38,
107 "ContinuousAdjustmentTimePoint has the wrong size!");
108static_assert(std::is_trivial_v<ContinuousAdjustmentTimePoint>);
109
110struct AlarmInfo {
111 s64 alert_time;
112 u32 priority;
113};
114static_assert(sizeof(AlarmInfo) == 0x10, "AlarmInfo has the wrong size!");
115
116struct StaticServiceSetupInfo {
117 bool can_write_local_clock;
118 bool can_write_user_clock;
119 bool can_write_network_clock;
120 bool can_write_timezone_device_location;
121 bool can_write_steady_clock;
122 bool can_write_uninitialized_clock;
123};
124static_assert(sizeof(StaticServiceSetupInfo) == 0x6, "StaticServiceSetupInfo has the wrong size!");
125
126struct OperationEvent : public Common::IntrusiveListBaseNode<OperationEvent> {
127 using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType;
128
129 OperationEvent(Core::System& system);
130 ~OperationEvent();
131
132 KernelHelpers::ServiceContext m_ctx;
133 Kernel::KEvent* m_event{};
134};
135
136constexpr inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) {
137 constexpr auto one_second_ns{
138 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
139
140 constexpr s64 max{Common::WallClock::CNTFRQ *
141 (std::numeric_limits<s64>::max() / one_second_ns)};
142
143 if (ticks > max) {
144 return std::chrono::nanoseconds(std::numeric_limits<s64>::max());
145 } else if (ticks < -max) {
146 return std::chrono::nanoseconds(std::numeric_limits<s64>::min());
147 }
148
149 auto a{ticks / Common::WallClock::CNTFRQ * one_second_ns};
150 auto b{((ticks % Common::WallClock::CNTFRQ) * one_second_ns) / Common::WallClock::CNTFRQ};
151
152 return std::chrono::nanoseconds(a + b);
153}
154
155constexpr inline Result GetSpanBetweenTimePoints(s64* out_seconds, SteadyClockTimePoint& a,
156 SteadyClockTimePoint& b) {
157 R_UNLESS(out_seconds, ResultInvalidArgument);
158 R_UNLESS(a.IdMatches(b), ResultInvalidArgument);
159 R_UNLESS(a.time_point >= 0 || b.time_point <= a.time_point + std::numeric_limits<s64>::max(),
160 ResultOverflow);
161 R_UNLESS(a.time_point < 0 || b.time_point >= a.time_point + std::numeric_limits<s64>::min(),
162 ResultOverflow);
163
164 *out_seconds = b.time_point - a.time_point;
165 R_SUCCEED();
166}
167
168} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/errors.h b/src/core/hle/service/psc/time/errors.h
new file mode 100644
index 000000000..6d833a006
--- /dev/null
+++ b/src/core/hle/service/psc/time/errors.h
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::PSC::Time {
9
10constexpr Result ResultPermissionDenied{ErrorModule::Time, 1};
11constexpr Result ResultClockMismatch{ErrorModule::Time, 102};
12constexpr Result ResultClockUninitialized{ErrorModule::Time, 103};
13constexpr Result ResultTimeNotFound{ErrorModule::Time, 200};
14constexpr Result ResultOverflow{ErrorModule::Time, 201};
15constexpr Result ResultFailed{ErrorModule::Time, 801};
16constexpr Result ResultInvalidArgument{ErrorModule::Time, 901};
17constexpr Result ResultTimeZoneOutOfRange{ErrorModule::Time, 902};
18constexpr Result ResultTimeZoneParseFailed{ErrorModule::Time, 903};
19constexpr Result ResultRtcTimeout{ErrorModule::Time, 988};
20constexpr Result ResultTimeZoneNotFound{ErrorModule::Time, 989};
21constexpr Result ResultNotImplemented{ErrorModule::Time, 990};
22constexpr Result ResultAlarmNotRegistered{ErrorModule::Time, 1502};
23
24} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/manager.h b/src/core/hle/service/psc/time/manager.h
new file mode 100644
index 000000000..62ded1247
--- /dev/null
+++ b/src/core/hle/service/psc/time/manager.h
@@ -0,0 +1,56 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/psc/time/alarms.h"
7#include "core/hle/service/psc/time/clocks/context_writers.h"
8#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h"
9#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
10#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
11#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
12#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
13#include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h"
14#include "core/hle/service/psc/time/power_state_request_manager.h"
15#include "core/hle/service/psc/time/shared_memory.h"
16#include "core/hle/service/psc/time/time_zone.h"
17
18namespace Core {
19class System;
20}
21
22namespace Service::PSC::Time {
23class TimeManager {
24public:
25 explicit TimeManager(Core::System& system)
26 : m_system{system}, m_standard_steady_clock{system}, m_tick_based_steady_clock{m_system},
27 m_standard_local_system_clock{m_standard_steady_clock},
28 m_standard_network_system_clock{m_standard_steady_clock},
29 m_standard_user_system_clock{m_system, m_standard_local_system_clock,
30 m_standard_network_system_clock},
31 m_ephemeral_network_clock{m_tick_based_steady_clock}, m_shared_memory{m_system},
32 m_power_state_request_manager{m_system}, m_alarms{m_system, m_standard_steady_clock,
33 m_power_state_request_manager},
34 m_local_system_clock_context_writer{m_system, m_shared_memory},
35 m_network_system_clock_context_writer{m_system, m_shared_memory,
36 m_standard_user_system_clock},
37 m_ephemeral_network_clock_context_writer{m_system} {}
38
39 Core::System& m_system;
40
41 StandardSteadyClockCore m_standard_steady_clock;
42 TickBasedSteadyClockCore m_tick_based_steady_clock;
43 StandardLocalSystemClockCore m_standard_local_system_clock;
44 StandardNetworkSystemClockCore m_standard_network_system_clock;
45 StandardUserSystemClockCore m_standard_user_system_clock;
46 EphemeralNetworkSystemClockCore m_ephemeral_network_clock;
47 TimeZone m_time_zone;
48 SharedMemory m_shared_memory;
49 PowerStateRequestManager m_power_state_request_manager;
50 Alarms m_alarms;
51 LocalSystemClockContextWriter m_local_system_clock_context_writer;
52 NetworkSystemClockContextWriter m_network_system_clock_context_writer;
53 EphemeralNetworkSystemClockContextWriter m_ephemeral_network_clock_context_writer;
54};
55
56} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/power_state_request_manager.cpp b/src/core/hle/service/psc/time/power_state_request_manager.cpp
new file mode 100644
index 000000000..17de0bf4d
--- /dev/null
+++ b/src/core/hle/service/psc/time/power_state_request_manager.cpp
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/psc/time/power_state_request_manager.h"
6
7namespace Service::PSC::Time {
8
9PowerStateRequestManager::PowerStateRequestManager(Core::System& system)
10 : m_system{system}, m_ctx{system, "Psc:PowerStateRequestManager"},
11 m_event{m_ctx.CreateEvent("Psc:PowerStateRequestManager:Event")} {}
12
13PowerStateRequestManager::~PowerStateRequestManager() {
14 m_ctx.CloseEvent(m_event);
15}
16
17void PowerStateRequestManager::UpdatePendingPowerStateRequestPriority(u32 priority) {
18 std::scoped_lock l{m_mutex};
19 if (m_has_pending_request) {
20 m_pending_request_priority = std::max(m_pending_request_priority, priority);
21 } else {
22 m_pending_request_priority = priority;
23 m_has_pending_request = true;
24 }
25}
26
27void PowerStateRequestManager::SignalPowerStateRequestAvailability() {
28 std::scoped_lock l{m_mutex};
29 if (m_has_pending_request) {
30 if (!m_has_available_request) {
31 m_has_available_request = true;
32 }
33 m_has_pending_request = false;
34 m_available_request_priority = m_pending_request_priority;
35 m_event->Signal();
36 }
37}
38
39bool PowerStateRequestManager::GetAndClearPowerStateRequest(u32& out_priority) {
40 std::scoped_lock l{m_mutex};
41 auto had_request{m_has_available_request};
42 if (m_has_available_request) {
43 out_priority = m_available_request_priority;
44 m_has_available_request = false;
45 m_event->Clear();
46 }
47 return had_request;
48}
49
50} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/power_state_request_manager.h b/src/core/hle/service/psc/time/power_state_request_manager.h
new file mode 100644
index 000000000..30a0c947d
--- /dev/null
+++ b/src/core/hle/service/psc/time/power_state_request_manager.h
@@ -0,0 +1,42 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/kernel_helpers.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::PSC::Time {
16
17class PowerStateRequestManager {
18public:
19 explicit PowerStateRequestManager(Core::System& system);
20 ~PowerStateRequestManager();
21
22 Kernel::KReadableEvent& GetReadableEvent() {
23 return m_event->GetReadableEvent();
24 }
25
26 void UpdatePendingPowerStateRequestPriority(u32 priority);
27 void SignalPowerStateRequestAvailability();
28 bool GetAndClearPowerStateRequest(u32& out_priority);
29
30private:
31 Core::System& m_system;
32 KernelHelpers::ServiceContext m_ctx;
33
34 Kernel::KEvent* m_event{};
35 bool m_has_pending_request{};
36 u32 m_pending_request_priority{};
37 bool m_has_available_request{};
38 u32 m_available_request_priority{};
39 std::mutex m_mutex;
40};
41
42} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/power_state_service.cpp b/src/core/hle/service/psc/time/power_state_service.cpp
new file mode 100644
index 000000000..b0ae71bf9
--- /dev/null
+++ b/src/core/hle/service/psc/time/power_state_service.cpp
@@ -0,0 +1,49 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/time/power_state_service.h"
5
6namespace Service::PSC::Time {
7
8IPowerStateRequestHandler::IPowerStateRequestHandler(
9 Core::System& system_, PowerStateRequestManager& power_state_request_manager)
10 : ServiceFramework{system_, "time:p"}, m_system{system}, m_power_state_request_manager{
11 power_state_request_manager} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, &IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle, "GetPowerStateRequestEventReadableHandle"},
15 {1, &IPowerStateRequestHandler::GetAndClearPowerStateRequest, "GetAndClearPowerStateRequest"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22void IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx) {
23 LOG_DEBUG(Service_Time, "called.");
24
25 IPC::ResponseBuilder rb{ctx, 2, 1};
26 rb.Push(ResultSuccess);
27 rb.PushCopyObjects(m_power_state_request_manager.GetReadableEvent());
28}
29
30void IPowerStateRequestHandler::GetAndClearPowerStateRequest(HLERequestContext& ctx) {
31 LOG_DEBUG(Service_Time, "called.");
32
33 u32 priority{};
34 auto cleared = m_power_state_request_manager.GetAndClearPowerStateRequest(priority);
35
36 if (cleared) {
37 IPC::ResponseBuilder rb{ctx, 4};
38 rb.Push(ResultSuccess);
39 rb.Push(priority);
40 rb.Push(cleared);
41 return;
42 }
43
44 IPC::ResponseBuilder rb{ctx, 3};
45 rb.Push(ResultSuccess);
46 rb.Push(cleared);
47}
48
49} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/power_state_service.h b/src/core/hle/service/psc/time/power_state_service.h
new file mode 100644
index 000000000..3ebfddb79
--- /dev/null
+++ b/src/core/hle/service/psc/time/power_state_service.h
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/power_state_request_manager.h"
8#include "core/hle/service/server_manager.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::PSC::Time {
16
17class IPowerStateRequestHandler final : public ServiceFramework<IPowerStateRequestHandler> {
18public:
19 explicit IPowerStateRequestHandler(Core::System& system,
20 PowerStateRequestManager& power_state_request_manager);
21
22 ~IPowerStateRequestHandler() override = default;
23
24private:
25 void GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx);
26 void GetAndClearPowerStateRequest(HLERequestContext& ctx);
27
28 Core::System& m_system;
29 PowerStateRequestManager& m_power_state_request_manager;
30};
31
32} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/service_manager.cpp b/src/core/hle/service/psc/time/service_manager.cpp
new file mode 100644
index 000000000..60820aa9b
--- /dev/null
+++ b/src/core/hle/service/psc/time/service_manager.cpp
@@ -0,0 +1,494 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/core_timing.h"
6#include "core/hle/service/psc/time/power_state_service.h"
7#include "core/hle/service/psc/time/service_manager.h"
8#include "core/hle/service/psc/time/static.h"
9
10namespace Service::PSC::Time {
11
12ServiceManager::ServiceManager(Core::System& system_, std::shared_ptr<TimeManager> time,
13 ServerManager* server_manager)
14 : ServiceFramework{system_, "time:m"}, m_system{system}, m_time{std::move(time)},
15 m_server_manager{*server_manager},
16 m_local_system_clock{m_time->m_standard_local_system_clock},
17 m_user_system_clock{m_time->m_standard_user_system_clock},
18 m_network_system_clock{m_time->m_standard_network_system_clock},
19 m_steady_clock{m_time->m_standard_steady_clock}, m_time_zone{m_time->m_time_zone},
20 m_ephemeral_network_clock{m_time->m_ephemeral_network_clock},
21 m_shared_memory{m_time->m_shared_memory}, m_alarms{m_time->m_alarms},
22 m_local_system_context_writer{m_time->m_local_system_clock_context_writer},
23 m_network_system_context_writer{m_time->m_network_system_clock_context_writer},
24 m_ephemeral_system_context_writer{m_time->m_ephemeral_network_clock_context_writer},
25 m_local_operation{m_system}, m_network_operation{m_system}, m_ephemeral_operation{m_system} {
26 // clang-format off
27 static const FunctionInfo functions[] = {
28 {0, &ServiceManager::Handle_GetStaticServiceAsUser, "GetStaticServiceAsUser"},
29 {5, &ServiceManager::Handle_GetStaticServiceAsAdmin, "GetStaticServiceAsAdmin"},
30 {6, &ServiceManager::Handle_GetStaticServiceAsRepair, "GetStaticServiceAsRepair"},
31 {9, &ServiceManager::Handle_GetStaticServiceAsServiceManager, "GetStaticServiceAsServiceManager"},
32 {10, &ServiceManager::Handle_SetupStandardSteadyClockCore, "SetupStandardSteadyClockCore"},
33 {11, &ServiceManager::Handle_SetupStandardLocalSystemClockCore, "SetupStandardLocalSystemClockCore"},
34 {12, &ServiceManager::Handle_SetupStandardNetworkSystemClockCore, "SetupStandardNetworkSystemClockCore"},
35 {13, &ServiceManager::Handle_SetupStandardUserSystemClockCore, "SetupStandardUserSystemClockCore"},
36 {14, &ServiceManager::Handle_SetupTimeZoneServiceCore, "SetupTimeZoneServiceCore"},
37 {15, &ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore, "SetupEphemeralNetworkSystemClockCore"},
38 {50, &ServiceManager::Handle_GetStandardLocalClockOperationEvent, "GetStandardLocalClockOperationEvent"},
39 {51, &ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager, "GetStandardNetworkClockOperationEventForServiceManager"},
40 {52, &ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager, "GetEphemeralNetworkClockOperationEventForServiceManager"},
41 {60, &ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent, "GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent"},
42 {100, &ServiceManager::Handle_SetStandardSteadyClockBaseTime, "SetStandardSteadyClockBaseTime"},
43 {200, &ServiceManager::Handle_GetClosestAlarmUpdatedEvent, "GetClosestAlarmUpdatedEvent"},
44 {201, &ServiceManager::Handle_CheckAndSignalAlarms, "CheckAndSignalAlarms"},
45 {202, &ServiceManager::Handle_GetClosestAlarmInfo, "GetClosestAlarmInfo "},
46 };
47 // clang-format on
48 RegisterHandlers(functions);
49
50 m_local_system_context_writer.Link(m_local_operation);
51 m_network_system_context_writer.Link(m_network_operation);
52 m_ephemeral_system_context_writer.Link(m_ephemeral_operation);
53}
54
55void ServiceManager::SetupSAndP() {
56 if (!m_is_s_and_p_setup) {
57 m_is_s_and_p_setup = true;
58 m_server_manager.RegisterNamedService(
59 "time:s", std::make_shared<StaticService>(
60 m_system, StaticServiceSetupInfo{0, 0, 1, 0, 0, 0}, m_time, "time:s"));
61 m_server_manager.RegisterNamedService("time:p",
62 std::make_shared<IPowerStateRequestHandler>(
63 m_system, m_time->m_power_state_request_manager));
64 }
65}
66
67void ServiceManager::CheckAndSetupServicesSAndP() {
68 if (m_local_system_clock.IsInitialized() && m_user_system_clock.IsInitialized() &&
69 m_network_system_clock.IsInitialized() && m_steady_clock.IsInitialized() &&
70 m_time_zone.IsInitialized() && m_ephemeral_network_clock.IsInitialized()) {
71 SetupSAndP();
72 }
73}
74
75void ServiceManager::Handle_GetStaticServiceAsUser(HLERequestContext& ctx) {
76 LOG_DEBUG(Service_Time, "called.");
77
78 std::shared_ptr<StaticService> service{};
79 auto res = GetStaticServiceAsUser(service);
80
81 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
82 rb.Push(res);
83 rb.PushIpcInterface<StaticService>(std::move(service));
84}
85
86void ServiceManager::Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx) {
87 LOG_DEBUG(Service_Time, "called.");
88
89 std::shared_ptr<StaticService> service{};
90 auto res = GetStaticServiceAsAdmin(service);
91
92 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
93 rb.Push(res);
94 rb.PushIpcInterface<StaticService>(std::move(service));
95}
96
97void ServiceManager::Handle_GetStaticServiceAsRepair(HLERequestContext& ctx) {
98 LOG_DEBUG(Service_Time, "called.");
99
100 std::shared_ptr<StaticService> service{};
101 auto res = GetStaticServiceAsRepair(service);
102
103 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
104 rb.Push(res);
105 rb.PushIpcInterface<StaticService>(std::move(service));
106}
107
108void ServiceManager::Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx) {
109 LOG_DEBUG(Service_Time, "called.");
110
111 std::shared_ptr<StaticService> service{};
112 auto res = GetStaticServiceAsServiceManager(service);
113
114 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
115 rb.Push(res);
116 rb.PushIpcInterface<StaticService>(std::move(service));
117}
118
119void ServiceManager::Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx) {
120 LOG_DEBUG(Service_Time, "called.");
121
122 struct Parameters {
123 bool reset_detected;
124 Common::UUID clock_source_id;
125 s64 rtc_offset;
126 s64 internal_offset;
127 s64 test_offset;
128 };
129 static_assert(sizeof(Parameters) == 0x30);
130
131 IPC::RequestParser rp{ctx};
132 auto params{rp.PopRaw<Parameters>()};
133
134 auto res = SetupStandardSteadyClockCore(params.clock_source_id, params.rtc_offset,
135 params.internal_offset, params.test_offset,
136 params.reset_detected);
137
138 IPC::ResponseBuilder rb{ctx, 2};
139 rb.Push(res);
140}
141
142void ServiceManager::Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx) {
143 LOG_DEBUG(Service_Time, "called.");
144
145 IPC::RequestParser rp{ctx};
146 auto context{rp.PopRaw<SystemClockContext>()};
147 auto time{rp.Pop<s64>()};
148
149 auto res = SetupStandardLocalSystemClockCore(context, time);
150
151 IPC::ResponseBuilder rb{ctx, 2};
152 rb.Push(res);
153}
154
155void ServiceManager::Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx) {
156 LOG_DEBUG(Service_Time, "called.");
157
158 IPC::RequestParser rp{ctx};
159 auto context{rp.PopRaw<SystemClockContext>()};
160 auto accuracy{rp.Pop<s64>()};
161
162 auto res = SetupStandardNetworkSystemClockCore(context, accuracy);
163
164 IPC::ResponseBuilder rb{ctx, 2};
165 rb.Push(res);
166}
167
168void ServiceManager::Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx) {
169 LOG_DEBUG(Service_Time, "called.");
170
171 struct Parameters {
172 bool automatic_correction;
173 SteadyClockTimePoint time_point;
174 };
175 static_assert(sizeof(Parameters) == 0x20);
176
177 IPC::RequestParser rp{ctx};
178 auto params{rp.PopRaw<Parameters>()};
179
180 auto res = SetupStandardUserSystemClockCore(params.time_point, params.automatic_correction);
181
182 IPC::ResponseBuilder rb{ctx, 2};
183 rb.Push(res);
184}
185
186void ServiceManager::Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx) {
187 LOG_DEBUG(Service_Time, "called.");
188
189 struct Parameters {
190 u32 location_count;
191 LocationName name;
192 SteadyClockTimePoint time_point;
193 RuleVersion rule_version;
194 };
195 static_assert(sizeof(Parameters) == 0x50);
196
197 IPC::RequestParser rp{ctx};
198 auto params{rp.PopRaw<Parameters>()};
199
200 auto rule_buffer{ctx.ReadBuffer()};
201
202 auto res = SetupTimeZoneServiceCore(params.name, params.time_point, params.rule_version,
203 params.location_count, rule_buffer);
204
205 IPC::ResponseBuilder rb{ctx, 2};
206 rb.Push(res);
207}
208
209void ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx) {
210 LOG_DEBUG(Service_Time, "called.");
211
212 auto res = SetupEphemeralNetworkSystemClockCore();
213
214 IPC::ResponseBuilder rb{ctx, 2};
215 rb.Push(res);
216}
217
218void ServiceManager::Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx) {
219 LOG_DEBUG(Service_Time, "called.");
220
221 Kernel::KEvent* event{};
222 auto res = GetStandardLocalClockOperationEvent(&event);
223
224 IPC::ResponseBuilder rb{ctx, 2, 1};
225 rb.Push(res);
226 rb.PushCopyObjects(event->GetReadableEvent());
227}
228
229void ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager(
230 HLERequestContext& ctx) {
231 LOG_DEBUG(Service_Time, "called.");
232
233 Kernel::KEvent* event{};
234 auto res = GetStandardNetworkClockOperationEventForServiceManager(&event);
235
236 IPC::ResponseBuilder rb{ctx, 2, 1};
237 rb.Push(res);
238 rb.PushCopyObjects(event);
239}
240
241void ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager(
242 HLERequestContext& ctx) {
243 LOG_DEBUG(Service_Time, "called.");
244
245 Kernel::KEvent* event{};
246 auto res = GetEphemeralNetworkClockOperationEventForServiceManager(&event);
247
248 IPC::ResponseBuilder rb{ctx, 2, 1};
249 rb.Push(res);
250 rb.PushCopyObjects(event);
251}
252
253void ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
254 HLERequestContext& ctx) {
255 LOG_DEBUG(Service_Time, "called.");
256
257 Kernel::KEvent* event{};
258 auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(&event);
259
260 IPC::ResponseBuilder rb{ctx, 2, 1};
261 rb.Push(res);
262 rb.PushCopyObjects(event);
263}
264
265void ServiceManager::Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx) {
266 LOG_DEBUG(Service_Time, "called.");
267
268 IPC::RequestParser rp{ctx};
269 auto base_time{rp.Pop<s64>()};
270
271 auto res = SetStandardSteadyClockBaseTime(base_time);
272
273 IPC::ResponseBuilder rb{ctx, 2};
274 rb.Push(res);
275}
276
277void ServiceManager::Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx) {
278 LOG_DEBUG(Service_Time, "called.");
279
280 Kernel::KEvent* event{};
281 auto res = GetClosestAlarmUpdatedEvent(&event);
282
283 IPC::ResponseBuilder rb{ctx, 3};
284 rb.Push(res);
285 rb.PushCopyObjects(event->GetReadableEvent());
286}
287
288void ServiceManager::Handle_CheckAndSignalAlarms(HLERequestContext& ctx) {
289 LOG_DEBUG(Service_Time, "called.");
290
291 auto res = CheckAndSignalAlarms();
292
293 IPC::ResponseBuilder rb{ctx, 2};
294 rb.Push(res);
295}
296
297void ServiceManager::Handle_GetClosestAlarmInfo(HLERequestContext& ctx) {
298 LOG_DEBUG(Service_Time, "called.");
299
300 AlarmInfo alarm_info{};
301 bool is_valid{};
302 s64 time{};
303 auto res = GetClosestAlarmInfo(is_valid, alarm_info, time);
304
305 struct OutParameters {
306 bool is_valid;
307 AlarmInfo alarm_info;
308 s64 time;
309 };
310 static_assert(sizeof(OutParameters) == 0x20);
311
312 OutParameters out_params{
313 .is_valid = is_valid,
314 .alarm_info = alarm_info,
315 .time = time,
316 };
317
318 IPC::ResponseBuilder rb{ctx, 2 + sizeof(OutParameters) / sizeof(u32)};
319 rb.Push(res);
320 rb.PushRaw<OutParameters>(out_params);
321}
322
323// =============================== Implementations ===========================
324
325Result ServiceManager::GetStaticService(std::shared_ptr<StaticService>& out_service,
326 StaticServiceSetupInfo setup_info, const char* name) {
327 out_service = std::make_shared<StaticService>(m_system, setup_info, m_time, name);
328 R_SUCCEED();
329}
330
331Result ServiceManager::GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service) {
332 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, "time:u"));
333}
334
335Result ServiceManager::GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service) {
336 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, "time:a"));
337}
338
339Result ServiceManager::GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service) {
340 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, "time:r"));
341}
342
343Result ServiceManager::GetStaticServiceAsServiceManager(
344 std::shared_ptr<StaticService>& out_service) {
345 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 1, 1, 1, 0}, "time:sm"));
346}
347
348Result ServiceManager::SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset,
349 s64 internal_offset, s64 test_offset,
350 bool is_rtc_reset_detected) {
351 m_steady_clock.Initialize(clock_source_id, rtc_offset, internal_offset, test_offset,
352 is_rtc_reset_detected);
353 auto time = m_steady_clock.GetRawTime();
354 auto ticks = m_system.CoreTiming().GetClockTicks();
355 auto boot_time = time - ConvertToTimeSpan(ticks).count();
356 m_shared_memory.SetSteadyClockTimePoint(clock_source_id, boot_time);
357 m_steady_clock.SetContinuousAdjustment(clock_source_id, boot_time);
358
359 ContinuousAdjustmentTimePoint time_point{};
360 m_steady_clock.GetContinuousAdjustment(time_point);
361 m_shared_memory.SetContinuousAdjustment(time_point);
362
363 CheckAndSetupServicesSAndP();
364 R_SUCCEED();
365}
366
367Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time) {
368 m_local_system_clock.SetContextWriter(m_local_system_context_writer);
369 m_local_system_clock.Initialize(context, time);
370
371 CheckAndSetupServicesSAndP();
372 R_SUCCEED();
373}
374
375Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& context,
376 s64 accuracy) {
377 // TODO this is a hack! The network clock should be updated independently, from the ntc service
378 // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot
379 // to avoid it being stuck at 0.
380 if (context == Service::PSC::Time::SystemClockContext{}) {
381 m_local_system_clock.GetContext(context);
382 }
383
384 m_network_system_clock.SetContextWriter(m_network_system_context_writer);
385 m_network_system_clock.Initialize(context, accuracy);
386
387 CheckAndSetupServicesSAndP();
388 R_SUCCEED();
389}
390
391Result ServiceManager::SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point,
392 bool automatic_correction) {
393 // TODO this is a hack! The user clock should be updated independently, from the ntc service
394 // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot
395 // to avoid it being stuck at 0.
396 if (time_point == Service::PSC::Time::SteadyClockTimePoint{}) {
397 m_local_system_clock.GetCurrentTimePoint(time_point);
398 }
399
400 m_user_system_clock.SetAutomaticCorrection(automatic_correction);
401 m_user_system_clock.SetTimePointAndSignal(time_point);
402 m_user_system_clock.SetInitialized();
403 m_shared_memory.SetAutomaticCorrection(automatic_correction);
404
405 CheckAndSetupServicesSAndP();
406 R_SUCCEED();
407}
408
409Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name,
410 SteadyClockTimePoint& time_point,
411 RuleVersion& rule_version, u32 location_count,
412 std::span<const u8> rule_buffer) {
413 if (m_time_zone.ParseBinary(name, rule_buffer) != ResultSuccess) {
414 LOG_ERROR(Service_Time, "Failed to parse time zone binary!");
415 }
416
417 m_time_zone.SetTimePoint(time_point);
418 m_time_zone.SetTotalLocationNameCount(location_count);
419 m_time_zone.SetRuleVersion(rule_version);
420 m_time_zone.SetInitialized();
421
422 CheckAndSetupServicesSAndP();
423 R_SUCCEED();
424}
425
426Result ServiceManager::SetupEphemeralNetworkSystemClockCore() {
427 m_ephemeral_network_clock.SetContextWriter(m_ephemeral_system_context_writer);
428 m_ephemeral_network_clock.SetInitialized();
429
430 CheckAndSetupServicesSAndP();
431 R_SUCCEED();
432}
433
434Result ServiceManager::GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event) {
435 *out_event = m_local_operation.m_event;
436 R_SUCCEED();
437}
438
439Result ServiceManager::GetStandardNetworkClockOperationEventForServiceManager(
440 Kernel::KEvent** out_event) {
441 *out_event = m_network_operation.m_event;
442 R_SUCCEED();
443}
444
445Result ServiceManager::GetEphemeralNetworkClockOperationEventForServiceManager(
446 Kernel::KEvent** out_event) {
447 *out_event = m_ephemeral_operation.m_event;
448 R_SUCCEED();
449}
450
451Result ServiceManager::GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
452 Kernel::KEvent** out_event) {
453 *out_event = &m_user_system_clock.GetEvent();
454 R_SUCCEED();
455}
456
457Result ServiceManager::SetStandardSteadyClockBaseTime(s64 base_time) {
458 m_steady_clock.SetRtcOffset(base_time);
459 auto time = m_steady_clock.GetRawTime();
460 auto ticks = m_system.CoreTiming().GetClockTicks();
461 auto diff = time - ConvertToTimeSpan(ticks).count();
462 m_shared_memory.UpdateBaseTime(diff);
463 m_steady_clock.UpdateContinuousAdjustmentTime(diff);
464
465 ContinuousAdjustmentTimePoint time_point{};
466 m_steady_clock.GetContinuousAdjustment(time_point);
467 m_shared_memory.SetContinuousAdjustment(time_point);
468 R_SUCCEED();
469}
470
471Result ServiceManager::GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event) {
472 *out_event = &m_alarms.GetEvent();
473 R_SUCCEED();
474}
475
476Result ServiceManager::CheckAndSignalAlarms() {
477 m_alarms.CheckAndSignal();
478 R_SUCCEED();
479}
480
481Result ServiceManager::GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time) {
482 Alarm* alarm{nullptr};
483 out_is_valid = m_alarms.GetClosestAlarm(&alarm);
484 if (out_is_valid) {
485 out_info = {
486 .alert_time = alarm->GetAlertTime(),
487 .priority = alarm->GetPriority(),
488 };
489 out_time = m_alarms.GetRawTime();
490 }
491 R_SUCCEED();
492}
493
494} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/service_manager.h b/src/core/hle/service/psc/time/service_manager.h
new file mode 100644
index 000000000..1d9952317
--- /dev/null
+++ b/src/core/hle/service/psc/time/service_manager.h
@@ -0,0 +1,101 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <list>
7#include <memory>
8
9#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/psc/time/common.h"
11#include "core/hle/service/psc/time/manager.h"
12#include "core/hle/service/server_manager.h"
13#include "core/hle/service/service.h"
14
15namespace Core {
16class System;
17}
18
19namespace Kernel {
20class KReadableEvent;
21}
22
23namespace Service::PSC::Time {
24class StaticService;
25
26class ServiceManager final : public ServiceFramework<ServiceManager> {
27public:
28 explicit ServiceManager(Core::System& system, std::shared_ptr<TimeManager> time,
29 ServerManager* server_manager);
30 ~ServiceManager() override = default;
31
32 Result GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service);
33 Result GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service);
34 Result GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service);
35 Result GetStaticServiceAsServiceManager(std::shared_ptr<StaticService>& out_service);
36 Result SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset,
37 s64 internal_offset, s64 test_offset,
38 bool is_rtc_reset_detected);
39 Result SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time);
40 Result SetupStandardNetworkSystemClockCore(SystemClockContext& context, s64 accuracy);
41 Result SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point,
42 bool automatic_correction);
43 Result SetupTimeZoneServiceCore(LocationName& name, SteadyClockTimePoint& time_point,
44 RuleVersion& rule_version, u32 location_count,
45 std::span<const u8> rule_buffer);
46 Result SetupEphemeralNetworkSystemClockCore();
47 Result GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event);
48 Result GetStandardNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event);
49 Result GetEphemeralNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event);
50 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(Kernel::KEvent** out_event);
51 Result SetStandardSteadyClockBaseTime(s64 base_time);
52 Result GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event);
53 Result CheckAndSignalAlarms();
54 Result GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time);
55
56private:
57 void CheckAndSetupServicesSAndP();
58 void SetupSAndP();
59 Result GetStaticService(std::shared_ptr<StaticService>& out_service,
60 StaticServiceSetupInfo setup_info, const char* name);
61
62 void Handle_GetStaticServiceAsUser(HLERequestContext& ctx);
63 void Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx);
64 void Handle_GetStaticServiceAsRepair(HLERequestContext& ctx);
65 void Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx);
66 void Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx);
67 void Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx);
68 void Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx);
69 void Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx);
70 void Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx);
71 void Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx);
72 void Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx);
73 void Handle_GetStandardNetworkClockOperationEventForServiceManager(HLERequestContext& ctx);
74 void Handle_GetEphemeralNetworkClockOperationEventForServiceManager(HLERequestContext& ctx);
75 void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(HLERequestContext& ctx);
76 void Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx);
77 void Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx);
78 void Handle_CheckAndSignalAlarms(HLERequestContext& ctx);
79 void Handle_GetClosestAlarmInfo(HLERequestContext& ctx);
80
81 Core::System& m_system;
82 std::shared_ptr<TimeManager> m_time;
83 ServerManager& m_server_manager;
84 bool m_is_s_and_p_setup{};
85 StandardLocalSystemClockCore& m_local_system_clock;
86 StandardUserSystemClockCore& m_user_system_clock;
87 StandardNetworkSystemClockCore& m_network_system_clock;
88 StandardSteadyClockCore& m_steady_clock;
89 TimeZone& m_time_zone;
90 EphemeralNetworkSystemClockCore& m_ephemeral_network_clock;
91 SharedMemory& m_shared_memory;
92 Alarms& m_alarms;
93 LocalSystemClockContextWriter& m_local_system_context_writer;
94 NetworkSystemClockContextWriter& m_network_system_context_writer;
95 EphemeralNetworkSystemClockContextWriter& m_ephemeral_system_context_writer;
96 OperationEvent m_local_operation;
97 OperationEvent m_network_operation;
98 OperationEvent m_ephemeral_operation;
99};
100
101} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/shared_memory.cpp b/src/core/hle/service/psc/time/shared_memory.cpp
new file mode 100644
index 000000000..defaceebe
--- /dev/null
+++ b/src/core/hle/service/psc/time/shared_memory.cpp
@@ -0,0 +1,84 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/kernel/k_shared_memory.h"
6#include "core/hle/service/psc/time/shared_memory.h"
7
8namespace Service::PSC::Time {
9namespace {
10template <typename T>
11constexpr inline T ReadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) {
12 while (true) {
13 // Get the counter.
14 auto counter = p->m_counter;
15
16 // Get the value.
17 auto value = p->m_value[counter % 2];
18
19 // Fence memory.
20 std::atomic_thread_fence(std::memory_order_acquire);
21
22 // Check that the counter matches.
23 if (counter == p->m_counter) {
24 return value;
25 }
26 }
27}
28
29template <typename T>
30constexpr inline void WriteToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) {
31 // Get the current counter.
32 auto counter = p->m_counter;
33
34 // Increment the counter.
35 ++counter;
36
37 // Store the updated value.
38 p->m_value[counter % 2] = value;
39
40 // Fence memory.
41 std::atomic_thread_fence(std::memory_order_release);
42
43 // Set the updated counter.
44 p->m_counter = counter;
45}
46} // namespace
47
48SharedMemory::SharedMemory(Core::System& system)
49 : m_system{system}, m_k_shared_memory{m_system.Kernel().GetTimeSharedMem()},
50 m_shared_memory_ptr{reinterpret_cast<SharedMemoryStruct*>(m_k_shared_memory.GetPointer())} {
51 std::memset(m_shared_memory_ptr, 0, sizeof(*m_shared_memory_ptr));
52}
53
54void SharedMemory::SetLocalSystemContext(SystemClockContext& context) {
55 WriteToLockFreeAtomicType(&m_shared_memory_ptr->local_system_clock_contexts, context);
56}
57
58void SharedMemory::SetNetworkSystemContext(SystemClockContext& context) {
59 WriteToLockFreeAtomicType(&m_shared_memory_ptr->network_system_clock_contexts, context);
60}
61
62void SharedMemory::SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_point) {
63 WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points,
64 {time_point, clock_source_id});
65}
66
67void SharedMemory::SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point) {
68 WriteToLockFreeAtomicType(&m_shared_memory_ptr->continuous_adjustment_time_points, time_point);
69}
70
71void SharedMemory::SetAutomaticCorrection(bool automatic_correction) {
72 WriteToLockFreeAtomicType(&m_shared_memory_ptr->automatic_corrections, automatic_correction);
73}
74
75void SharedMemory::UpdateBaseTime(s64 time) {
76 SteadyClockTimePoint time_point{
77 ReadFromLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points)};
78
79 time_point.time_point = time;
80
81 WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points, time_point);
82}
83
84} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/shared_memory.h b/src/core/hle/service/psc/time/shared_memory.h
new file mode 100644
index 000000000..f9bf97d5c
--- /dev/null
+++ b/src/core/hle/service/psc/time/shared_memory.h
@@ -0,0 +1,70 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_types.h"
9#include "core/hle/service/psc/time/common.h"
10
11namespace Core {
12class System;
13}
14
15namespace Kernel {
16class KSharedMemory;
17}
18
19namespace Service::PSC::Time {
20
21template <typename T>
22struct LockFreeAtomicType {
23 u32 m_counter;
24 std::array<T, 2> m_value;
25};
26
27struct SharedMemoryStruct {
28 LockFreeAtomicType<SteadyClockTimePoint> steady_time_points;
29 LockFreeAtomicType<SystemClockContext> local_system_clock_contexts;
30 LockFreeAtomicType<SystemClockContext> network_system_clock_contexts;
31 LockFreeAtomicType<bool> automatic_corrections;
32 LockFreeAtomicType<ContinuousAdjustmentTimePoint> continuous_adjustment_time_points;
33 std::array<char, 0xEB8> pad0148;
34};
35static_assert(offsetof(SharedMemoryStruct, steady_time_points) == 0x0,
36 "steady_time_points are in the wrong place!");
37static_assert(offsetof(SharedMemoryStruct, local_system_clock_contexts) == 0x38,
38 "local_system_clock_contexts are in the wrong place!");
39static_assert(offsetof(SharedMemoryStruct, network_system_clock_contexts) == 0x80,
40 "network_system_clock_contexts are in the wrong place!");
41static_assert(offsetof(SharedMemoryStruct, automatic_corrections) == 0xC8,
42 "automatic_corrections are in the wrong place!");
43static_assert(offsetof(SharedMemoryStruct, continuous_adjustment_time_points) == 0xD0,
44 "continuous_adjustment_time_points are in the wrong place!");
45static_assert(sizeof(SharedMemoryStruct) == 0x1000,
46 "Time's SharedMemoryStruct has the wrong size!");
47static_assert(std::is_trivial_v<SharedMemoryStruct>);
48
49class SharedMemory {
50public:
51 explicit SharedMemory(Core::System& system);
52
53 Kernel::KSharedMemory& GetKSharedMemory() {
54 return m_k_shared_memory;
55 }
56
57 void SetLocalSystemContext(SystemClockContext& context);
58 void SetNetworkSystemContext(SystemClockContext& context);
59 void SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_diff);
60 void SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point);
61 void SetAutomaticCorrection(bool automatic_correction);
62 void UpdateBaseTime(s64 time);
63
64private:
65 Core::System& m_system;
66 Kernel::KSharedMemory& m_k_shared_memory;
67 SharedMemoryStruct* m_shared_memory_ptr;
68};
69
70} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/static.cpp b/src/core/hle/service/psc/time/static.cpp
new file mode 100644
index 000000000..6f8cf3f88
--- /dev/null
+++ b/src/core/hle/service/psc/time/static.cpp
@@ -0,0 +1,500 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/core_timing.h"
6#include "core/hle/kernel/k_shared_memory.h"
7#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h"
8#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
9#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
10#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
11#include "core/hle/service/psc/time/manager.h"
12#include "core/hle/service/psc/time/shared_memory.h"
13#include "core/hle/service/psc/time/static.h"
14#include "core/hle/service/psc/time/steady_clock.h"
15#include "core/hle/service/psc/time/system_clock.h"
16#include "core/hle/service/psc/time/time_zone.h"
17#include "core/hle/service/psc/time/time_zone_service.h"
18
19namespace Service::PSC::Time {
20namespace {
21constexpr Result GetTimeFromTimePointAndContext(s64* out_time, SteadyClockTimePoint& time_point,
22 SystemClockContext& context) {
23 R_UNLESS(out_time != nullptr, ResultInvalidArgument);
24 R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch);
25
26 *out_time = context.offset + time_point.time_point;
27 R_SUCCEED();
28}
29} // namespace
30
31StaticService::StaticService(Core::System& system_, StaticServiceSetupInfo setup_info,
32 std::shared_ptr<TimeManager> time, const char* name)
33 : ServiceFramework{system_, name}, m_system{system}, m_setup_info{setup_info}, m_time{time},
34 m_local_system_clock{m_time->m_standard_local_system_clock},
35 m_user_system_clock{m_time->m_standard_user_system_clock},
36 m_network_system_clock{m_time->m_standard_network_system_clock},
37 m_time_zone{m_time->m_time_zone},
38 m_ephemeral_network_clock{m_time->m_ephemeral_network_clock}, m_shared_memory{
39 m_time->m_shared_memory} {
40 // clang-format off
41 static const FunctionInfo functions[] = {
42 {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"},
43 {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
44 {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"},
45 {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"},
46 {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
47 {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"},
48 {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
49 {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"},
50 {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"},
51 {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
52 {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
53 {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"},
54 {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
55 {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
56 {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
57 {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"},
58 {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
59 {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
60 {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"},
61 };
62 // clang-format on
63
64 RegisterHandlers(functions);
65}
66
67Result StaticService::GetClockSnapshotImpl(ClockSnapshot& out_snapshot,
68 SystemClockContext& user_context,
69 SystemClockContext& network_context, TimeType type) {
70 out_snapshot.user_context = user_context;
71 out_snapshot.network_context = network_context;
72
73 R_TRY(
74 m_time->m_standard_steady_clock.GetCurrentTimePoint(out_snapshot.steady_clock_time_point));
75
76 out_snapshot.is_automatic_correction_enabled = m_user_system_clock.GetAutomaticCorrection();
77
78 R_TRY(m_time_zone.GetLocationName(out_snapshot.location_name));
79
80 R_TRY(GetTimeFromTimePointAndContext(
81 &out_snapshot.user_time, out_snapshot.steady_clock_time_point, out_snapshot.user_context));
82
83 R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.user_calendar_time,
84 out_snapshot.user_calendar_additional_time,
85 out_snapshot.user_time));
86
87 if (GetTimeFromTimePointAndContext(&out_snapshot.network_time,
88 out_snapshot.steady_clock_time_point,
89 out_snapshot.network_context) != ResultSuccess) {
90 out_snapshot.network_time = 0;
91 }
92
93 R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.network_calendar_time,
94 out_snapshot.network_calendar_additional_time,
95 out_snapshot.network_time));
96 out_snapshot.type = type;
97 out_snapshot.unk_CE = 0;
98 R_SUCCEED();
99}
100
101void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) {
102 LOG_DEBUG(Service_Time, "called.");
103
104 std::shared_ptr<SystemClock> service{};
105 auto res = GetStandardUserSystemClock(service);
106
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(res);
109 rb.PushIpcInterface<SystemClock>(std::move(service));
110}
111
112void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) {
113 LOG_DEBUG(Service_Time, "called.");
114
115 std::shared_ptr<SystemClock> service{};
116 auto res = GetStandardNetworkSystemClock(service);
117
118 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
119 rb.Push(res);
120 rb.PushIpcInterface<SystemClock>(std::move(service));
121}
122
123void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) {
124 LOG_DEBUG(Service_Time, "called.");
125
126 std::shared_ptr<SteadyClock> service{};
127 auto res = GetStandardSteadyClock(service);
128
129 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
130 rb.Push(res);
131 rb.PushIpcInterface(std::move(service));
132}
133
134void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) {
135 LOG_DEBUG(Service_Time, "called.");
136
137 std::shared_ptr<TimeZoneService> service{};
138 auto res = GetTimeZoneService(service);
139
140 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
141 rb.Push(res);
142 rb.PushIpcInterface(std::move(service));
143}
144
145void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) {
146 LOG_DEBUG(Service_Time, "called.");
147
148 std::shared_ptr<SystemClock> service{};
149 auto res = GetStandardLocalSystemClock(service);
150
151 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
152 rb.Push(res);
153 rb.PushIpcInterface<SystemClock>(std::move(service));
154}
155
156void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) {
157 LOG_DEBUG(Service_Time, "called.");
158
159 std::shared_ptr<SystemClock> service{};
160 auto res = GetEphemeralNetworkSystemClock(service);
161
162 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
163 rb.Push(res);
164 rb.PushIpcInterface<SystemClock>(std::move(service));
165}
166
167void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
168 LOG_DEBUG(Service_Time, "called.");
169
170 Kernel::KSharedMemory* shared_memory{};
171 auto res = GetSharedMemoryNativeHandle(&shared_memory);
172
173 IPC::ResponseBuilder rb{ctx, 2, 1};
174 rb.Push(res);
175 rb.PushCopyObjects(shared_memory);
176}
177
178void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) {
179 LOG_DEBUG(Service_Time, "called.");
180
181 IPC::ResponseBuilder rb{ctx, 2};
182 rb.Push(m_setup_info.can_write_steady_clock ? ResultNotImplemented : ResultPermissionDenied);
183}
184
185void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) {
186 LOG_DEBUG(Service_Time, "called.");
187
188 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(ResultNotImplemented);
190}
191
192void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(
193 HLERequestContext& ctx) {
194 LOG_DEBUG(Service_Time, "called.");
195
196 bool is_enabled{};
197 auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled);
198
199 IPC::ResponseBuilder rb{ctx, 3};
200 rb.Push(res);
201 rb.Push<bool>(is_enabled);
202}
203
204void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(
205 HLERequestContext& ctx) {
206 LOG_DEBUG(Service_Time, "called.");
207
208 IPC::RequestParser rp{ctx};
209 auto automatic_correction{rp.Pop<bool>()};
210
211 auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
212
213 IPC::ResponseBuilder rb{ctx, 2};
214 rb.Push(res);
215}
216
217void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) {
218 LOG_DEBUG(Service_Time, "called.");
219
220 IPC::ResponseBuilder rb{ctx, 2};
221 rb.Push(ResultNotImplemented);
222}
223
224void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
225 LOG_DEBUG(Service_Time, "called.");
226
227 bool is_sufficient{};
228 auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient);
229
230 IPC::ResponseBuilder rb{ctx, 3};
231 rb.Push(res);
232 rb.Push<bool>(is_sufficient);
233}
234
235void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
236 HLERequestContext& ctx) {
237 LOG_DEBUG(Service_Time, "called.");
238
239 SteadyClockTimePoint time_point{};
240 auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
241
242 IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)};
243 rb.Push(res);
244 rb.PushRaw<SteadyClockTimePoint>(time_point);
245}
246
247void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
248 LOG_DEBUG(Service_Time, "called.");
249
250 IPC::RequestParser rp{ctx};
251 auto context{rp.PopRaw<SystemClockContext>()};
252
253 s64 time{};
254 auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context);
255
256 IPC::ResponseBuilder rb{ctx, 4};
257 rb.Push(res);
258 rb.Push<s64>(time);
259}
260
261void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) {
262 LOG_DEBUG(Service_Time, "called.");
263
264 IPC::RequestParser rp{ctx};
265 auto type{rp.PopEnum<TimeType>()};
266
267 ClockSnapshot snapshot{};
268 auto res = GetClockSnapshot(snapshot, type);
269
270 ctx.WriteBuffer(snapshot);
271
272 IPC::ResponseBuilder rb{ctx, 2};
273 rb.Push(res);
274}
275
276void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
277 LOG_DEBUG(Service_Time, "called.");
278
279 IPC::RequestParser rp{ctx};
280 auto clock_type{rp.PopEnum<TimeType>()};
281 [[maybe_unused]] auto alignment{rp.Pop<u32>()};
282 auto user_context{rp.PopRaw<SystemClockContext>()};
283 auto network_context{rp.PopRaw<SystemClockContext>()};
284
285 ClockSnapshot snapshot{};
286 auto res =
287 GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type);
288
289 ctx.WriteBuffer(snapshot);
290
291 IPC::ResponseBuilder rb{ctx, 2};
292 rb.Push(res);
293}
294
295void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser(
296 HLERequestContext& ctx) {
297 LOG_DEBUG(Service_Time, "called.");
298
299 ClockSnapshot a{};
300 ClockSnapshot b{};
301
302 auto a_buffer{ctx.ReadBuffer(0)};
303 auto b_buffer{ctx.ReadBuffer(1)};
304
305 std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot));
306 std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot));
307
308 s64 difference{};
309 auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b);
310
311 IPC::ResponseBuilder rb{ctx, 4};
312 rb.Push(res);
313 rb.Push(difference);
314}
315
316void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) {
317 LOG_DEBUG(Service_Time, "called.");
318
319 ClockSnapshot a{};
320 ClockSnapshot b{};
321
322 auto a_buffer{ctx.ReadBuffer(0)};
323 auto b_buffer{ctx.ReadBuffer(1)};
324
325 std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot));
326 std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot));
327
328 s64 time{};
329 auto res = CalculateSpanBetween(time, a, b);
330
331 IPC::ResponseBuilder rb{ctx, 4};
332 rb.Push(res);
333 rb.Push(time);
334}
335
336// =============================== Implementations ===========================
337
338Result StaticService::GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service) {
339 out_service = std::make_shared<SystemClock>(m_system, m_user_system_clock,
340 m_setup_info.can_write_user_clock,
341 m_setup_info.can_write_uninitialized_clock);
342 R_SUCCEED();
343}
344
345Result StaticService::GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) {
346 out_service = std::make_shared<SystemClock>(m_system, m_network_system_clock,
347 m_setup_info.can_write_network_clock,
348 m_setup_info.can_write_uninitialized_clock);
349 R_SUCCEED();
350}
351
352Result StaticService::GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service) {
353 out_service =
354 std::make_shared<SteadyClock>(m_system, m_time, m_setup_info.can_write_steady_clock,
355 m_setup_info.can_write_uninitialized_clock);
356 R_SUCCEED();
357}
358
359Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) {
360 out_service =
361 std::make_shared<TimeZoneService>(m_system, m_time->m_standard_steady_clock, m_time_zone,
362 m_setup_info.can_write_timezone_device_location);
363 R_SUCCEED();
364}
365
366Result StaticService::GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service) {
367 out_service = std::make_shared<SystemClock>(m_system, m_local_system_clock,
368 m_setup_info.can_write_local_clock,
369 m_setup_info.can_write_uninitialized_clock);
370 R_SUCCEED();
371}
372
373Result StaticService::GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) {
374 out_service = std::make_shared<SystemClock>(m_system, m_ephemeral_network_clock,
375 m_setup_info.can_write_network_clock,
376 m_setup_info.can_write_uninitialized_clock);
377 R_SUCCEED();
378}
379
380Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) {
381 *out_shared_memory = &m_shared_memory.GetKSharedMemory();
382 R_SUCCEED();
383}
384
385Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled) {
386 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
387
388 out_is_enabled = m_user_system_clock.GetAutomaticCorrection();
389 R_SUCCEED();
390}
391
392Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
393 bool automatic_correction) {
394 R_UNLESS(m_user_system_clock.IsInitialized() && m_time->m_standard_steady_clock.IsInitialized(),
395 ResultClockUninitialized);
396 R_UNLESS(m_setup_info.can_write_user_clock, ResultPermissionDenied);
397
398 R_TRY(m_user_system_clock.SetAutomaticCorrection(automatic_correction));
399
400 m_shared_memory.SetAutomaticCorrection(automatic_correction);
401
402 SteadyClockTimePoint time_point{};
403 R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point));
404
405 m_user_system_clock.SetTimePointAndSignal(time_point);
406 m_user_system_clock.GetEvent().Signal();
407 R_SUCCEED();
408}
409
410Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) {
411 out_is_sufficient = m_network_system_clock.IsAccuracySufficient();
412 R_SUCCEED();
413}
414
415Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
416 SteadyClockTimePoint& out_time_point) {
417 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
418
419 m_user_system_clock.GetTimePoint(out_time_point);
420
421 R_SUCCEED();
422}
423
424Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(s64& out_time,
425 SystemClockContext& context) {
426 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
427
428 SteadyClockTimePoint time_point{};
429 R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point));
430
431 R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch);
432
433 auto one_second_ns{
434 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
435 auto ticks{m_system.CoreTiming().GetClockTicks()};
436 auto current_time{ConvertToTimeSpan(ticks).count()};
437 out_time = ((context.offset + time_point.time_point) - (current_time / one_second_ns));
438 R_SUCCEED();
439}
440
441Result StaticService::GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type) {
442 SystemClockContext user_context{};
443 R_TRY(m_user_system_clock.GetContext(user_context));
444
445 SystemClockContext network_context{};
446 R_TRY(m_network_system_clock.GetContext(network_context));
447
448 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
449}
450
451Result StaticService::GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot,
452 SystemClockContext& user_context,
453 SystemClockContext& network_context,
454 TimeType type) {
455 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
456}
457
458Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(s64& out_time,
459 ClockSnapshot& a,
460 ClockSnapshot& b) {
461 auto diff_s =
462 std::chrono::seconds(b.user_context.offset) - std::chrono::seconds(a.user_context.offset);
463
464 if (a.user_context == b.user_context ||
465 !a.user_context.steady_time_point.IdMatches(b.user_context.steady_time_point)) {
466 out_time = 0;
467 R_SUCCEED();
468 }
469
470 if (!a.is_automatic_correction_enabled || !b.is_automatic_correction_enabled) {
471 out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count();
472 R_SUCCEED();
473 }
474
475 if (a.network_context.steady_time_point.IdMatches(a.steady_clock_time_point) ||
476 b.network_context.steady_time_point.IdMatches(b.steady_clock_time_point)) {
477 out_time = 0;
478 R_SUCCEED();
479 }
480
481 out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count();
482 R_SUCCEED();
483}
484
485Result StaticService::CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b) {
486 s64 time_s{};
487 auto res =
488 GetSpanBetweenTimePoints(&time_s, a.steady_clock_time_point, b.steady_clock_time_point);
489
490 if (res != ResultSuccess) {
491 R_UNLESS(a.network_time != 0 && b.network_time != 0, ResultTimeNotFound);
492 time_s = b.network_time - a.network_time;
493 }
494
495 out_time =
496 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(time_s)).count();
497 R_SUCCEED();
498}
499
500} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/static.h b/src/core/hle/service/psc/time/static.h
new file mode 100644
index 000000000..498cd5ab5
--- /dev/null
+++ b/src/core/hle/service/psc/time/static.h
@@ -0,0 +1,95 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/common.h"
8#include "core/hle/service/server_manager.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Kernel {
16class KSharedMemory;
17}
18
19namespace Service::PSC::Time {
20class TimeManager;
21class StandardLocalSystemClockCore;
22class StandardUserSystemClockCore;
23class StandardNetworkSystemClockCore;
24class TimeZone;
25class SystemClock;
26class SteadyClock;
27class TimeZoneService;
28class EphemeralNetworkSystemClockCore;
29class SharedMemory;
30
31class StaticService final : public ServiceFramework<StaticService> {
32public:
33 explicit StaticService(Core::System& system, StaticServiceSetupInfo setup_info,
34 std::shared_ptr<TimeManager> time, const char* name);
35
36 ~StaticService() override = default;
37
38 Result GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service);
39 Result GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service);
40 Result GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service);
41 Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service);
42 Result GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service);
43 Result GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service);
44 Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory);
45 Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled);
46 Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction);
47 Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient);
48 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
49 SteadyClockTimePoint& out_time_point);
50 Result CalculateMonotonicSystemClockBaseTimePoint(s64& out_time, SystemClockContext& context);
51 Result GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type);
52 Result GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot,
53 SystemClockContext& user_context,
54 SystemClockContext& network_context,
55 TimeType type);
56 Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, ClockSnapshot& a,
57 ClockSnapshot& b);
58 Result CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b);
59
60private:
61 Result GetClockSnapshotImpl(ClockSnapshot& out_snapshot, SystemClockContext& user_context,
62 SystemClockContext& network_context, TimeType type);
63
64 void Handle_GetStandardUserSystemClock(HLERequestContext& ctx);
65 void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx);
66 void Handle_GetStandardSteadyClock(HLERequestContext& ctx);
67 void Handle_GetTimeZoneService(HLERequestContext& ctx);
68 void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx);
69 void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx);
70 void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx);
71 void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx);
72 void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx);
73 void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
74 void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
75 void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx);
76 void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
77 void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
78 void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
79 void Handle_GetClockSnapshot(HLERequestContext& ctx);
80 void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
81 void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
82 void Handle_CalculateSpanBetween(HLERequestContext& ctx);
83
84 Core::System& m_system;
85 StaticServiceSetupInfo m_setup_info;
86 std::shared_ptr<TimeManager> m_time;
87 StandardLocalSystemClockCore& m_local_system_clock;
88 StandardUserSystemClockCore& m_user_system_clock;
89 StandardNetworkSystemClockCore& m_network_system_clock;
90 TimeZone& m_time_zone;
91 EphemeralNetworkSystemClockCore& m_ephemeral_network_clock;
92 SharedMemory& m_shared_memory;
93};
94
95} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp
new file mode 100644
index 000000000..1ed5c7679
--- /dev/null
+++ b/src/core/hle/service/psc/time/steady_clock.cpp
@@ -0,0 +1,164 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/psc/time/steady_clock.h"
6
7namespace Service::PSC::Time {
8
9SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> manager,
10 bool can_write_steady_clock, bool can_write_uninitialized_clock)
11 : ServiceFramework{system_, "ISteadyClock"}, m_system{system},
12 m_clock_core{manager->m_standard_steady_clock},
13 m_can_write_steady_clock{can_write_steady_clock}, m_can_write_uninitialized_clock{
14 can_write_uninitialized_clock} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, &SteadyClock::Handle_GetCurrentTimePoint, "GetCurrentTimePoint"},
18 {2, &SteadyClock::Handle_GetTestOffset, "GetTestOffset"},
19 {3, &SteadyClock::Handle_SetTestOffset, "SetTestOffset"},
20 {100, &SteadyClock::Handle_GetRtcValue, "GetRtcValue"},
21 {101, &SteadyClock::Handle_IsRtcResetDetected, "IsRtcResetDetected"},
22 {102, &SteadyClock::Handle_GetSetupResultValue, "GetSetupResultValue"},
23 {200, &SteadyClock::Handle_GetInternalOffset, "GetInternalOffset"},
24 };
25 // clang-format on
26 RegisterHandlers(functions);
27}
28
29void SteadyClock::Handle_GetCurrentTimePoint(HLERequestContext& ctx) {
30 LOG_DEBUG(Service_Time, "called.");
31
32 SteadyClockTimePoint time_point{};
33 auto res = GetCurrentTimePoint(time_point);
34
35 IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)};
36 rb.Push(res);
37 rb.PushRaw<SteadyClockTimePoint>(time_point);
38}
39
40void SteadyClock::Handle_GetTestOffset(HLERequestContext& ctx) {
41 LOG_DEBUG(Service_Time, "called.");
42
43 s64 test_offset{};
44 auto res = GetTestOffset(test_offset);
45
46 IPC::ResponseBuilder rb{ctx, 4};
47 rb.Push(res);
48 rb.Push(test_offset);
49}
50
51void SteadyClock::Handle_SetTestOffset(HLERequestContext& ctx) {
52 LOG_DEBUG(Service_Time, "called.");
53
54 IPC::RequestParser rp{ctx};
55 auto test_offset{rp.Pop<s64>()};
56
57 auto res = SetTestOffset(test_offset);
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(res);
61}
62
63void SteadyClock::Handle_GetRtcValue(HLERequestContext& ctx) {
64 LOG_DEBUG(Service_Time, "called.");
65
66 s64 rtc_value{};
67 auto res = GetRtcValue(rtc_value);
68
69 IPC::ResponseBuilder rb{ctx, 4};
70 rb.Push(res);
71 rb.Push(rtc_value);
72}
73
74void SteadyClock::Handle_IsRtcResetDetected(HLERequestContext& ctx) {
75 LOG_DEBUG(Service_Time, "called.");
76
77 bool reset_detected{false};
78 auto res = IsRtcResetDetected(reset_detected);
79
80 IPC::ResponseBuilder rb{ctx, 3};
81 rb.Push(res);
82 rb.Push(reset_detected);
83}
84
85void SteadyClock::Handle_GetSetupResultValue(HLERequestContext& ctx) {
86 LOG_DEBUG(Service_Time, "called.");
87
88 Result result_value{ResultSuccess};
89 auto res = GetSetupResultValue(result_value);
90
91 IPC::ResponseBuilder rb{ctx, 3};
92 rb.Push(res);
93 rb.Push(result_value);
94}
95
96void SteadyClock::Handle_GetInternalOffset(HLERequestContext& ctx) {
97 LOG_DEBUG(Service_Time, "called.");
98
99 s64 internal_offset{};
100 auto res = GetInternalOffset(internal_offset);
101
102 IPC::ResponseBuilder rb{ctx, 4};
103 rb.Push(res);
104 rb.Push(internal_offset);
105}
106
107// =============================== Implementations ===========================
108
109Result SteadyClock::GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
110 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
111 ResultClockUninitialized);
112
113 R_RETURN(m_clock_core.GetCurrentTimePoint(out_time_point));
114}
115
116Result SteadyClock::GetTestOffset(s64& out_test_offset) {
117 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
118 ResultClockUninitialized);
119
120 out_test_offset = m_clock_core.GetTestOffset();
121 R_SUCCEED();
122}
123
124Result SteadyClock::SetTestOffset(s64 test_offset) {
125 R_UNLESS(m_can_write_steady_clock, ResultPermissionDenied);
126 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
127 ResultClockUninitialized);
128
129 m_clock_core.SetTestOffset(test_offset);
130 R_SUCCEED();
131}
132
133Result SteadyClock::GetRtcValue(s64& out_rtc_value) {
134 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
135 ResultClockUninitialized);
136
137 R_RETURN(m_clock_core.GetRtcValue(out_rtc_value));
138}
139
140Result SteadyClock::IsRtcResetDetected(bool& out_is_detected) {
141 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
142 ResultClockUninitialized);
143
144 out_is_detected = m_clock_core.IsResetDetected();
145 R_SUCCEED();
146}
147
148Result SteadyClock::GetSetupResultValue(Result& out_result) {
149 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
150 ResultClockUninitialized);
151
152 out_result = m_clock_core.GetSetupResultValue();
153 R_SUCCEED();
154}
155
156Result SteadyClock::GetInternalOffset(s64& out_internal_offset) {
157 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
158 ResultClockUninitialized);
159
160 out_internal_offset = m_clock_core.GetInternalOffset();
161 R_SUCCEED();
162}
163
164} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/steady_clock.h b/src/core/hle/service/psc/time/steady_clock.h
new file mode 100644
index 000000000..115e9b138
--- /dev/null
+++ b/src/core/hle/service/psc/time/steady_clock.h
@@ -0,0 +1,49 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/common.h"
8#include "core/hle/service/psc/time/manager.h"
9#include "core/hle/service/server_manager.h"
10#include "core/hle/service/service.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::PSC::Time {
17
18class SteadyClock final : public ServiceFramework<SteadyClock> {
19public:
20 explicit SteadyClock(Core::System& system, std::shared_ptr<TimeManager> manager,
21 bool can_write_steady_clock, bool can_write_uninitialized_clock);
22
23 ~SteadyClock() override = default;
24
25 Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point);
26 Result GetTestOffset(s64& out_test_offset);
27 Result SetTestOffset(s64 test_offset);
28 Result GetRtcValue(s64& out_rtc_value);
29 Result IsRtcResetDetected(bool& out_is_detected);
30 Result GetSetupResultValue(Result& out_result);
31 Result GetInternalOffset(s64& out_internal_offset);
32
33private:
34 void Handle_GetCurrentTimePoint(HLERequestContext& ctx);
35 void Handle_GetTestOffset(HLERequestContext& ctx);
36 void Handle_SetTestOffset(HLERequestContext& ctx);
37 void Handle_GetRtcValue(HLERequestContext& ctx);
38 void Handle_IsRtcResetDetected(HLERequestContext& ctx);
39 void Handle_GetSetupResultValue(HLERequestContext& ctx);
40 void Handle_GetInternalOffset(HLERequestContext& ctx);
41
42 Core::System& m_system;
43
44 StandardSteadyClockCore& m_clock_core;
45 bool m_can_write_steady_clock;
46 bool m_can_write_uninitialized_clock;
47};
48
49} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/system_clock.cpp b/src/core/hle/service/psc/time/system_clock.cpp
new file mode 100644
index 000000000..13d2f1d11
--- /dev/null
+++ b/src/core/hle/service/psc/time/system_clock.cpp
@@ -0,0 +1,127 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/psc/time/system_clock.h"
6
7namespace Service::PSC::Time {
8
9SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, bool can_write_clock,
10 bool can_write_uninitialized_clock)
11 : ServiceFramework{system_, "ISystemClock"}, m_system{system}, m_clock_core{clock_core},
12 m_can_write_clock{can_write_clock}, m_can_write_uninitialized_clock{
13 can_write_uninitialized_clock} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, &SystemClock::Handle_GetCurrentTime, "GetCurrentTime"},
17 {1, &SystemClock::Handle_SetCurrentTime, "SetCurrentTime"},
18 {2, &SystemClock::Handle_GetSystemClockContext, "GetSystemClockContext"},
19 {3, &SystemClock::Handle_SetSystemClockContext, "SetSystemClockContext"},
20 {4, &SystemClock::Handle_GetOperationEventReadableHandle, "GetOperationEventReadableHandle"},
21 };
22 // clang-format on
23 RegisterHandlers(functions);
24}
25
26void SystemClock::Handle_GetCurrentTime(HLERequestContext& ctx) {
27 LOG_DEBUG(Service_Time, "called.");
28
29 s64 time{};
30 auto res = GetCurrentTime(time);
31
32 IPC::ResponseBuilder rb{ctx, 4};
33 rb.Push(res);
34 rb.Push<s64>(time);
35}
36
37void SystemClock::Handle_SetCurrentTime(HLERequestContext& ctx) {
38 LOG_DEBUG(Service_Time, "called.");
39
40 IPC::RequestParser rp{ctx};
41 auto time{rp.Pop<s64>()};
42
43 auto res = SetCurrentTime(time);
44
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(res);
47}
48
49void SystemClock::Handle_GetSystemClockContext(HLERequestContext& ctx) {
50 LOG_DEBUG(Service_Time, "called.");
51
52 SystemClockContext context{};
53 auto res = GetSystemClockContext(context);
54
55 IPC::ResponseBuilder rb{ctx, 2 + sizeof(SystemClockContext) / sizeof(u32)};
56 rb.Push(res);
57 rb.PushRaw<SystemClockContext>(context);
58}
59
60void SystemClock::Handle_SetSystemClockContext(HLERequestContext& ctx) {
61 LOG_DEBUG(Service_Time, "called.");
62
63 IPC::RequestParser rp{ctx};
64 auto context{rp.PopRaw<SystemClockContext>()};
65
66 auto res = SetSystemClockContext(context);
67
68 IPC::ResponseBuilder rb{ctx, 2};
69 rb.Push(res);
70}
71
72void SystemClock::Handle_GetOperationEventReadableHandle(HLERequestContext& ctx) {
73 LOG_DEBUG(Service_Time, "called.");
74
75 Kernel::KEvent* event{};
76 auto res = GetOperationEventReadableHandle(&event);
77
78 IPC::ResponseBuilder rb{ctx, 2, 1};
79 rb.Push(res);
80 rb.PushCopyObjects(event->GetReadableEvent());
81}
82
83// =============================== Implementations ===========================
84
85Result SystemClock::GetCurrentTime(s64& out_time) {
86 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
87 ResultClockUninitialized);
88
89 R_RETURN(m_clock_core.GetCurrentTime(&out_time));
90}
91
92Result SystemClock::SetCurrentTime(s64 time) {
93 R_UNLESS(m_can_write_clock, ResultPermissionDenied);
94 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
95 ResultClockUninitialized);
96
97 R_RETURN(m_clock_core.SetCurrentTime(time));
98}
99
100Result SystemClock::GetSystemClockContext(SystemClockContext& out_context) {
101 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
102 ResultClockUninitialized);
103
104 R_RETURN(m_clock_core.GetContext(out_context));
105}
106
107Result SystemClock::SetSystemClockContext(SystemClockContext& context) {
108 R_UNLESS(m_can_write_clock, ResultPermissionDenied);
109 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
110 ResultClockUninitialized);
111
112 R_RETURN(m_clock_core.SetContextAndWrite(context));
113}
114
115Result SystemClock::GetOperationEventReadableHandle(Kernel::KEvent** out_event) {
116 if (!m_operation_event) {
117 m_operation_event = std::make_unique<OperationEvent>(m_system);
118 R_UNLESS(m_operation_event != nullptr, ResultFailed);
119
120 m_clock_core.LinkOperationEvent(*m_operation_event);
121 }
122
123 *out_event = m_operation_event->m_event;
124 R_SUCCEED();
125}
126
127} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/system_clock.h b/src/core/hle/service/psc/time/system_clock.h
new file mode 100644
index 000000000..f30027e7b
--- /dev/null
+++ b/src/core/hle/service/psc/time/system_clock.h
@@ -0,0 +1,46 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/common.h"
8#include "core/hle/service/psc/time/manager.h"
9#include "core/hle/service/server_manager.h"
10#include "core/hle/service/service.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::PSC::Time {
17
18class SystemClock final : public ServiceFramework<SystemClock> {
19public:
20 explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core,
21 bool can_write_clock, bool can_write_uninitialized_clock);
22
23 ~SystemClock() override = default;
24
25 Result GetCurrentTime(s64& out_time);
26 Result SetCurrentTime(s64 time);
27 Result GetSystemClockContext(SystemClockContext& out_context);
28 Result SetSystemClockContext(SystemClockContext& context);
29 Result GetOperationEventReadableHandle(Kernel::KEvent** out_event);
30
31private:
32 void Handle_GetCurrentTime(HLERequestContext& ctx);
33 void Handle_SetCurrentTime(HLERequestContext& ctx);
34 void Handle_GetSystemClockContext(HLERequestContext& ctx);
35 void Handle_SetSystemClockContext(HLERequestContext& ctx);
36 void Handle_GetOperationEventReadableHandle(HLERequestContext& ctx);
37
38 Core::System& m_system;
39
40 SystemClockCore& m_clock_core;
41 bool m_can_write_clock;
42 bool m_can_write_uninitialized_clock;
43 std::unique_ptr<OperationEvent> m_operation_event{};
44};
45
46} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/time_zone.cpp b/src/core/hle/service/psc/time/time_zone.cpp
new file mode 100644
index 000000000..cfee8f866
--- /dev/null
+++ b/src/core/hle/service/psc/time/time_zone.cpp
@@ -0,0 +1,280 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/time/time_zone.h"
5
6namespace Service::PSC::Time {
7namespace {
8constexpr Result ValidateRule(Tz::Rule& rule) {
9 if (rule.typecnt > static_cast<s32>(Tz::TZ_MAX_TYPES) ||
10 rule.timecnt > static_cast<s32>(Tz::TZ_MAX_TIMES) ||
11 rule.charcnt > static_cast<s32>(Tz::TZ_MAX_CHARS)) {
12 R_RETURN(ResultTimeZoneOutOfRange);
13 }
14
15 for (s32 i = 0; i < rule.timecnt; i++) {
16 if (rule.types[i] >= rule.typecnt) {
17 R_RETURN(ResultTimeZoneOutOfRange);
18 }
19 }
20
21 for (s32 i = 0; i < rule.typecnt; i++) {
22 if (rule.ttis[i].tt_desigidx >= static_cast<s32>(rule.chars.size())) {
23 R_RETURN(ResultTimeZoneOutOfRange);
24 }
25 }
26 R_SUCCEED();
27}
28
29constexpr bool GetTimeZoneTime(s64& out_time, Tz::Rule& rule, s64 time, s32 index,
30 s32 index_offset) {
31 s32 found_idx{};
32 s32 expected_index{index + index_offset};
33 s64 time_to_find{time + rule.ttis[rule.types[index]].tt_utoff -
34 rule.ttis[rule.types[expected_index]].tt_utoff};
35
36 if (rule.timecnt > 1 && rule.ats[0] <= time_to_find) {
37 s32 low{1};
38 s32 high{rule.timecnt};
39
40 while (low < high) {
41 auto mid{(low + high) / 2};
42 if (rule.ats[mid] <= time_to_find) {
43 low = mid + 1;
44 } else if (rule.ats[mid] > time_to_find) {
45 high = mid;
46 }
47 }
48 found_idx = low - 1;
49 }
50
51 if (found_idx == expected_index) {
52 out_time = time_to_find;
53 }
54 return found_idx == expected_index;
55}
56} // namespace
57
58void TimeZone::SetTimePoint(SteadyClockTimePoint& time_point) {
59 std::scoped_lock l{m_mutex};
60 m_steady_clock_time_point = time_point;
61}
62
63void TimeZone::SetTotalLocationNameCount(u32 count) {
64 std::scoped_lock l{m_mutex};
65 m_total_location_name_count = count;
66}
67
68void TimeZone::SetRuleVersion(RuleVersion& rule_version) {
69 std::scoped_lock l{m_mutex};
70 m_rule_version = rule_version;
71}
72
73Result TimeZone::GetLocationName(LocationName& out_name) {
74 std::scoped_lock l{m_mutex};
75 R_UNLESS(m_initialized, ResultClockUninitialized);
76 out_name = m_location;
77 R_SUCCEED();
78}
79
80Result TimeZone::GetTotalLocationCount(u32& out_count) {
81 std::scoped_lock l{m_mutex};
82 if (!m_initialized) {
83 return ResultClockUninitialized;
84 }
85
86 out_count = m_total_location_name_count;
87 R_SUCCEED();
88}
89
90Result TimeZone::GetRuleVersion(RuleVersion& out_rule_version) {
91 std::scoped_lock l{m_mutex};
92 if (!m_initialized) {
93 return ResultClockUninitialized;
94 }
95 out_rule_version = m_rule_version;
96 R_SUCCEED();
97}
98
99Result TimeZone::GetTimePoint(SteadyClockTimePoint& out_time_point) {
100 std::scoped_lock l{m_mutex};
101 if (!m_initialized) {
102 return ResultClockUninitialized;
103 }
104 out_time_point = m_steady_clock_time_point;
105 R_SUCCEED();
106}
107
108Result TimeZone::ToCalendarTime(CalendarTime& out_calendar_time,
109 CalendarAdditionalInfo& out_additional_info, s64 time,
110 Tz::Rule& rule) {
111 std::scoped_lock l{m_mutex};
112 R_RETURN(ToCalendarTimeImpl(out_calendar_time, out_additional_info, time, rule));
113}
114
115Result TimeZone::ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
116 CalendarAdditionalInfo& calendar_additional, s64 time) {
117 // This is checked outside the mutex. Bug?
118 if (!m_initialized) {
119 return ResultClockUninitialized;
120 }
121
122 std::scoped_lock l{m_mutex};
123 R_RETURN(ToCalendarTimeImpl(calendar_time, calendar_additional, time, m_my_rule));
124}
125
126Result TimeZone::ParseBinary(LocationName& name, std::span<const u8> binary) {
127 std::scoped_lock l{m_mutex};
128
129 Tz::Rule tmp_rule{};
130 R_TRY(ParseBinaryImpl(tmp_rule, binary));
131
132 m_my_rule = tmp_rule;
133 m_location = name;
134
135 R_SUCCEED();
136}
137
138Result TimeZone::ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary) {
139 std::scoped_lock l{m_mutex};
140 R_RETURN(ParseBinaryImpl(out_rule, binary));
141}
142
143Result TimeZone::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
144 CalendarTime& calendar, Tz::Rule& rule) {
145 std::scoped_lock l{m_mutex};
146
147 auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, rule, -1);
148
149 if (res != ResultSuccess) {
150 if (res == ResultTimeZoneNotFound) {
151 res = ResultSuccess;
152 out_count = 0;
153 }
154 } else if (out_count == 2 && out_times[0] > out_times[1]) {
155 std::swap(out_times[0], out_times[1]);
156 }
157 R_RETURN(res);
158}
159
160Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times,
161 u32 out_times_count, CalendarTime& calendar) {
162 std::scoped_lock l{m_mutex};
163
164 auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, m_my_rule, -1);
165
166 if (res != ResultSuccess) {
167 if (res == ResultTimeZoneNotFound) {
168 res = ResultSuccess;
169 out_count = 0;
170 }
171 } else if (out_count == 2 && out_times[0] > out_times[1]) {
172 std::swap(out_times[0], out_times[1]);
173 }
174 R_RETURN(res);
175}
176
177Result TimeZone::ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary) {
178 if (Tz::ParseTimeZoneBinary(out_rule, binary)) {
179 R_RETURN(ResultTimeZoneParseFailed);
180 }
181 R_SUCCEED();
182}
183
184Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time,
185 CalendarAdditionalInfo& out_additional_info, s64 time,
186 Tz::Rule& rule) {
187 R_TRY(ValidateRule(rule));
188
189 Tz::CalendarTimeInternal calendar_internal{};
190 time_t time_tmp{static_cast<time_t>(time)};
191 if (Tz::localtime_rz(&calendar_internal, &rule, &time_tmp)) {
192 R_RETURN(ResultOverflow);
193 }
194
195 out_calendar_time.year = static_cast<s16>(calendar_internal.tm_year + 1900);
196 out_calendar_time.month = static_cast<s8>(calendar_internal.tm_mon + 1);
197 out_calendar_time.day = static_cast<s8>(calendar_internal.tm_mday);
198 out_calendar_time.hour = static_cast<s8>(calendar_internal.tm_hour);
199 out_calendar_time.minute = static_cast<s8>(calendar_internal.tm_min);
200 out_calendar_time.second = static_cast<s8>(calendar_internal.tm_sec);
201
202 out_additional_info.day_of_week = calendar_internal.tm_wday;
203 out_additional_info.day_of_year = calendar_internal.tm_yday;
204
205 std::memcpy(out_additional_info.name.data(), calendar_internal.tm_zone.data(),
206 out_additional_info.name.size());
207 out_additional_info.name[out_additional_info.name.size() - 1] = '\0';
208
209 out_additional_info.is_dst = calendar_internal.tm_isdst;
210 out_additional_info.ut_offset = calendar_internal.tm_utoff;
211
212 R_SUCCEED();
213}
214
215Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
216 CalendarTime& calendar, Tz::Rule& rule, s32 is_dst) {
217 R_TRY(ValidateRule(rule));
218
219 calendar.month -= 1;
220 calendar.year -= 1900;
221
222 Tz::CalendarTimeInternal internal{
223 .tm_sec = calendar.second,
224 .tm_min = calendar.minute,
225 .tm_hour = calendar.hour,
226 .tm_mday = calendar.day,
227 .tm_mon = calendar.month,
228 .tm_year = calendar.year,
229 .tm_wday = 0,
230 .tm_yday = 0,
231 .tm_isdst = is_dst,
232 .tm_zone = {},
233 .tm_utoff = 0,
234 .time_index = 0,
235 };
236 time_t time_tmp{};
237 auto res = Tz::mktime_tzname(&time_tmp, &rule, &internal);
238 s64 time = static_cast<s64>(time_tmp);
239
240 if (res == 1) {
241 R_RETURN(ResultOverflow);
242 } else if (res == 2) {
243 R_RETURN(ResultTimeZoneNotFound);
244 }
245
246 if (internal.tm_sec != calendar.second || internal.tm_min != calendar.minute ||
247 internal.tm_hour != calendar.hour || internal.tm_mday != calendar.day ||
248 internal.tm_mon != calendar.month || internal.tm_year != calendar.year) {
249 R_RETURN(ResultTimeZoneNotFound);
250 }
251
252 if (res != 0) {
253 ASSERT(false);
254 }
255
256 out_times[0] = time;
257 if (out_times_count < 2) {
258 out_count = 1;
259 R_SUCCEED();
260 }
261
262 s64 time2{};
263 if (internal.time_index > 0 && GetTimeZoneTime(time2, rule, time, internal.time_index, -1)) {
264 out_times[1] = time2;
265 out_count = 2;
266 R_SUCCEED();
267 }
268
269 if (((internal.time_index + 1) < rule.timecnt) &&
270 GetTimeZoneTime(time2, rule, time, internal.time_index, 1)) {
271 out_times[1] = time2;
272 out_count = 2;
273 R_SUCCEED();
274 }
275
276 out_count = 1;
277 R_SUCCEED();
278}
279
280} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/time_zone.h b/src/core/hle/service/psc/time/time_zone.h
new file mode 100644
index 000000000..ce2acca17
--- /dev/null
+++ b/src/core/hle/service/psc/time/time_zone.h
@@ -0,0 +1,62 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7#include <span>
8
9#include <tz/tz.h>
10#include "core/hle/service/psc/time/common.h"
11
12namespace Service::PSC::Time {
13
14class TimeZone {
15public:
16 TimeZone() = default;
17
18 bool IsInitialized() const {
19 return m_initialized;
20 }
21
22 void SetInitialized() {
23 m_initialized = true;
24 }
25
26 void SetTimePoint(SteadyClockTimePoint& time_point);
27 void SetTotalLocationNameCount(u32 count);
28 void SetRuleVersion(RuleVersion& rule_version);
29 Result GetLocationName(LocationName& out_name);
30 Result GetTotalLocationCount(u32& out_count);
31 Result GetRuleVersion(RuleVersion& out_rule_version);
32 Result GetTimePoint(SteadyClockTimePoint& out_time_point);
33
34 Result ToCalendarTime(CalendarTime& out_calendar_time,
35 CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule);
36 Result ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
37 CalendarAdditionalInfo& calendar_additional, s64 time);
38 Result ParseBinary(LocationName& name, std::span<const u8> binary);
39 Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary);
40 Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
41 CalendarTime& calendar, Tz::Rule& rule);
42 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
43 CalendarTime& calendar);
44
45private:
46 Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary);
47 Result ToCalendarTimeImpl(CalendarTime& out_calendar_time,
48 CalendarAdditionalInfo& out_additional_info, s64 time,
49 Tz::Rule& rule);
50 Result ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
51 CalendarTime& calendar, Tz::Rule& rule, s32 is_dst);
52
53 bool m_initialized{};
54 std::recursive_mutex m_mutex;
55 LocationName m_location{};
56 Tz::Rule m_my_rule{};
57 SteadyClockTimePoint m_steady_clock_time_point{};
58 u32 m_total_location_name_count{};
59 RuleVersion m_rule_version{};
60};
61
62} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp
new file mode 100644
index 000000000..e304c8387
--- /dev/null
+++ b/src/core/hle/service/psc/time/time_zone_service.cpp
@@ -0,0 +1,289 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <tz/tz.h>
5#include "core/core.h"
6#include "core/hle/service/psc/time/time_zone_service.h"
7
8namespace Service::PSC::Time {
9
10TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore& clock_core,
11 TimeZone& time_zone, bool can_write_timezone_device_location)
12 : ServiceFramework{system_, "ITimeZoneService"}, m_system{system}, m_clock_core{clock_core},
13 m_time_zone{time_zone}, m_can_write_timezone_device_location{
14 can_write_timezone_device_location} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"},
18 {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"},
19 {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"},
20 {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"},
21 {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"},
22 {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
23 {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"},
24 {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"},
25 {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"},
26 {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"},
27 {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"},
28 {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
29 {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"},
30 {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
31 };
32 // clang-format on
33 RegisterHandlers(functions);
34}
35
36void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) {
37 LOG_DEBUG(Service_Time, "called.");
38
39 LocationName name{};
40 auto res = GetDeviceLocationName(name);
41
42 IPC::ResponseBuilder rb{ctx, 2 + sizeof(LocationName) / sizeof(u32)};
43 rb.Push(res);
44 rb.PushRaw<LocationName>(name);
45}
46
47void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) {
48 LOG_DEBUG(Service_Time, "called.");
49
50 IPC::RequestParser rp{ctx};
51 [[maybe_unused]] auto name{rp.PopRaw<LocationName>()};
52
53 if (!m_can_write_timezone_device_location) {
54 IPC::ResponseBuilder rb{ctx, 2};
55 rb.Push(ResultPermissionDenied);
56 return;
57 }
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(ResultNotImplemented);
61}
62
63void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) {
64 LOG_DEBUG(Service_Time, "called.");
65
66 u32 count{};
67 auto res = GetTotalLocationNameCount(count);
68
69 IPC::ResponseBuilder rb{ctx, 3};
70 rb.Push(res);
71 rb.Push(count);
72}
73
74void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) {
75 LOG_DEBUG(Service_Time, "called.");
76
77 IPC::ResponseBuilder rb{ctx, 2};
78 rb.Push(ResultNotImplemented);
79}
80
81void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) {
82 LOG_DEBUG(Service_Time, "called.");
83
84 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(ResultNotImplemented);
86}
87
88void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_Time, "called.");
90
91 RuleVersion rule_version{};
92 auto res = GetTimeZoneRuleVersion(rule_version);
93
94 IPC::ResponseBuilder rb{ctx, 2 + sizeof(RuleVersion) / sizeof(u32)};
95 rb.Push(res);
96 rb.PushRaw<RuleVersion>(rule_version);
97}
98
99void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) {
100 LOG_DEBUG(Service_Time, "called.");
101
102 LocationName name{};
103 SteadyClockTimePoint time_point{};
104 auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name);
105
106 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(LocationName) / sizeof(u32)) +
107 (sizeof(SteadyClockTimePoint) / sizeof(u32))};
108 rb.Push(res);
109 rb.PushRaw<LocationName>(name);
110 rb.PushRaw<SteadyClockTimePoint>(time_point);
111}
112
113void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) {
114 LOG_DEBUG(Service_Time, "called.");
115
116 IPC::RequestParser rp{ctx};
117 auto name{rp.PopRaw<LocationName>()};
118
119 auto binary{ctx.ReadBuffer()};
120 auto res = SetDeviceLocationNameWithTimeZoneRule(name, binary);
121
122 IPC::ResponseBuilder rb{ctx, 2};
123 rb.Push(res);
124}
125
126void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) {
127 LOG_DEBUG(Service_Time, "called.");
128
129 auto binary{ctx.ReadBuffer()};
130
131 Tz::Rule rule{};
132 auto res = ParseTimeZoneBinary(rule, binary);
133
134 ctx.WriteBuffer(rule);
135
136 IPC::ResponseBuilder rb{ctx, 2};
137 rb.Push(res);
138}
139
140void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle(
141 HLERequestContext& ctx) {
142 LOG_DEBUG(Service_Time, "called.");
143
144 IPC::ResponseBuilder rb{ctx, 2};
145 rb.Push(ResultNotImplemented);
146}
147
148void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) {
149 LOG_DEBUG(Service_Time, "called.");
150
151 IPC::RequestParser rp{ctx};
152 auto time{rp.Pop<s64>()};
153
154 auto rule_buffer{ctx.ReadBuffer()};
155 Tz::Rule rule{};
156 std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule));
157
158 CalendarTime calendar_time{};
159 CalendarAdditionalInfo additional_info{};
160 auto res = ToCalendarTime(calendar_time, additional_info, time, rule);
161
162 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) +
163 (sizeof(CalendarAdditionalInfo) / sizeof(u32))};
164 rb.Push(res);
165 rb.PushRaw<CalendarTime>(calendar_time);
166 rb.PushRaw<CalendarAdditionalInfo>(additional_info);
167}
168
169void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
170 LOG_DEBUG(Service_Time, "called.");
171
172 IPC::RequestParser rp{ctx};
173 auto time{rp.Pop<s64>()};
174
175 CalendarTime calendar_time{};
176 CalendarAdditionalInfo additional_info{};
177 auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time);
178
179 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) +
180 (sizeof(CalendarAdditionalInfo) / sizeof(u32))};
181 rb.Push(res);
182 rb.PushRaw<CalendarTime>(calendar_time);
183 rb.PushRaw<CalendarAdditionalInfo>(additional_info);
184}
185
186void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) {
187 LOG_DEBUG(Service_Time, "called.");
188
189 IPC::RequestParser rp{ctx};
190 auto calendar{rp.PopRaw<CalendarTime>()};
191
192 auto binary{ctx.ReadBuffer()};
193
194 Tz::Rule rule{};
195 std::memcpy(&rule, binary.data(), sizeof(Tz::Rule));
196
197 u32 count{};
198 std::array<s64, 2> times{};
199 u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
200
201 auto res = ToPosixTime(count, times, times_count, calendar, rule);
202
203 ctx.WriteBuffer(times);
204
205 IPC::ResponseBuilder rb{ctx, 3};
206 rb.Push(res);
207 rb.Push(count);
208}
209
210void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) {
211 LOG_DEBUG(Service_Time, "called.");
212
213 IPC::RequestParser rp{ctx};
214 auto calendar{rp.PopRaw<CalendarTime>()};
215
216 u32 count{};
217 std::array<s64, 2> times{};
218 u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
219
220 auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar);
221
222 ctx.WriteBuffer(times);
223
224 IPC::ResponseBuilder rb{ctx, 3};
225 rb.Push(res);
226 rb.Push(count);
227}
228
229// =============================== Implementations ===========================
230
231Result TimeZoneService::GetDeviceLocationName(LocationName& out_location_name) {
232 R_RETURN(m_time_zone.GetLocationName(out_location_name));
233}
234
235Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) {
236 R_RETURN(m_time_zone.GetTotalLocationCount(out_count));
237}
238
239Result TimeZoneService::GetTimeZoneRuleVersion(RuleVersion& out_rule_version) {
240 R_RETURN(m_time_zone.GetRuleVersion(out_rule_version));
241}
242
243Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point,
244 LocationName& location_name) {
245 R_TRY(m_time_zone.GetLocationName(location_name));
246 R_RETURN(m_time_zone.GetTimePoint(out_time_point));
247}
248
249Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name,
250 std::span<const u8> binary) {
251 R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied);
252 R_TRY(m_time_zone.ParseBinary(location_name, binary));
253
254 SteadyClockTimePoint time_point{};
255 R_TRY(m_clock_core.GetCurrentTimePoint(time_point));
256
257 m_time_zone.SetTimePoint(time_point);
258 R_SUCCEED();
259}
260
261Result TimeZoneService::ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary) {
262 R_RETURN(m_time_zone.ParseBinaryInto(out_rule, binary));
263}
264
265Result TimeZoneService::ToCalendarTime(CalendarTime& out_calendar_time,
266 CalendarAdditionalInfo& out_additional_info, s64 time,
267 Tz::Rule& rule) {
268 R_RETURN(m_time_zone.ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
269}
270
271Result TimeZoneService::ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time,
272 CalendarAdditionalInfo& out_additional_info,
273 s64 time) {
274 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
275}
276
277Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times,
278 u32 out_times_count, CalendarTime& calendar_time,
279 Tz::Rule& rule) {
280 R_RETURN(m_time_zone.ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule));
281}
282
283Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times,
284 u32 out_times_count, CalendarTime& calendar_time) {
285 R_RETURN(
286 m_time_zone.ToPosixTimeWithMyRule(out_count, out_times, out_times_count, calendar_time));
287}
288
289} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/time_zone_service.h b/src/core/hle/service/psc/time/time_zone_service.h
new file mode 100644
index 000000000..074c1d4ae
--- /dev/null
+++ b/src/core/hle/service/psc/time/time_zone_service.h
@@ -0,0 +1,69 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/common.h"
8#include "core/hle/service/psc/time/manager.h"
9#include "core/hle/service/server_manager.h"
10#include "core/hle/service/service.h"
11
12namespace Core {
13class System;
14}
15
16namespace Tz {
17struct Rule;
18}
19
20namespace Service::PSC::Time {
21
22class TimeZoneService final : public ServiceFramework<TimeZoneService> {
23public:
24 explicit TimeZoneService(Core::System& system, StandardSteadyClockCore& clock_core,
25 TimeZone& time_zone, bool can_write_timezone_device_location);
26
27 ~TimeZoneService() override = default;
28
29 Result GetDeviceLocationName(LocationName& out_location_name);
30 Result GetTotalLocationNameCount(u32& out_count);
31 Result GetTimeZoneRuleVersion(RuleVersion& out_rule_version);
32 Result GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point,
33 LocationName& location_name);
34 Result SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name,
35 std::span<const u8> binary);
36 Result ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary);
37 Result ToCalendarTime(CalendarTime& out_calendar_time,
38 CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule);
39 Result ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time,
40 CalendarAdditionalInfo& out_additional_info, s64 time);
41 Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
42 CalendarTime& calendar_time, Tz::Rule& rule);
43 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
44 CalendarTime& calendar_time);
45
46private:
47 void Handle_GetDeviceLocationName(HLERequestContext& ctx);
48 void Handle_SetDeviceLocationName(HLERequestContext& ctx);
49 void Handle_GetTotalLocationNameCount(HLERequestContext& ctx);
50 void Handle_LoadLocationNameList(HLERequestContext& ctx);
51 void Handle_LoadTimeZoneRule(HLERequestContext& ctx);
52 void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx);
53 void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx);
54 void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx);
55 void Handle_ParseTimeZoneBinary(HLERequestContext& ctx);
56 void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx);
57 void Handle_ToCalendarTime(HLERequestContext& ctx);
58 void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx);
59 void Handle_ToPosixTime(HLERequestContext& ctx);
60 void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx);
61
62 Core::System& m_system;
63
64 StandardSteadyClockCore& m_clock_core;
65 TimeZone& m_time_zone;
66 bool m_can_write_timezone_device_location;
67};
68
69} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp
index f0658bb5d..ae62c430e 100644
--- a/src/core/hle/service/ro/ro.cpp
+++ b/src/core/hle/service/ro/ro.cpp
@@ -6,13 +6,13 @@
6#include "common/scope_exit.h" 6#include "common/scope_exit.h"
7#include "core/hle/kernel/k_process.h" 7#include "core/hle/kernel/k_process.h"
8 8
9#include "core/hle/service/cmif_serialization.h"
9#include "core/hle/service/ipc_helpers.h" 10#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/ro/ro.h" 11#include "core/hle/service/ro/ro.h"
11#include "core/hle/service/ro/ro_nro_utils.h" 12#include "core/hle/service/ro/ro_nro_utils.h"
12#include "core/hle/service/ro/ro_results.h" 13#include "core/hle/service/ro/ro_results.h"
13#include "core/hle/service/ro/ro_types.h" 14#include "core/hle/service/ro/ro_types.h"
14#include "core/hle/service/server_manager.h" 15#include "core/hle/service/server_manager.h"
15#include "core/hle/service/service.h"
16 16
17namespace Service::RO { 17namespace Service::RO {
18 18
@@ -500,46 +500,65 @@ private:
500 } 500 }
501}; 501};
502 502
503class RoInterface { 503class RoInterface : public ServiceFramework<RoInterface> {
504public: 504public:
505 explicit RoInterface(std::shared_ptr<RoContext> ro, NrrKind nrr_kind) 505 explicit RoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro,
506 : m_ro(ro), m_context_id(InvalidContextId), m_nrr_kind(nrr_kind) {} 506 NrrKind nrr_kind)
507 : ServiceFramework{system_, name_}, m_ro(ro), m_context_id(InvalidContextId),
508 m_nrr_kind(nrr_kind) {
509
510 // clang-format off
511 static const FunctionInfo functions[] = {
512 {0, C<&RoInterface::MapManualLoadModuleMemory>, "MapManualLoadModuleMemory"},
513 {1, C<&RoInterface::UnmapManualLoadModuleMemory>, "UnmapManualLoadModuleMemory"},
514 {2, C<&RoInterface::RegisterModuleInfo>, "RegisterModuleInfo"},
515 {3, C<&RoInterface::UnregisterModuleInfo>, "UnregisterModuleInfo"},
516 {4, C<&RoInterface::RegisterProcessHandle>, "RegisterProcessHandle"},
517 {10, C<&RoInterface::RegisterProcessModuleInfo>, "RegisterProcessModuleInfo"},
518 };
519 // clang-format on
520
521 RegisterHandlers(functions);
522 }
523
507 ~RoInterface() { 524 ~RoInterface() {
508 m_ro->UnregisterProcess(m_context_id); 525 m_ro->UnregisterProcess(m_context_id);
509 } 526 }
510 527
511 Result MapManualLoadModuleMemory(u64* out_load_address, u64 client_pid, u64 nro_address, 528 Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid,
512 u64 nro_size, u64 bss_address, u64 bss_size) { 529 u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
513 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); 530 R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
514 R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address, m_context_id, nro_address, 531 R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address.Get(), m_context_id, nro_address,
515 nro_size, bss_address, bss_size)); 532 nro_size, bss_address, bss_size));
516 } 533 }
517 534
518 Result UnmapManualLoadModuleMemory(u64 client_pid, u64 nro_address) { 535 Result UnmapManualLoadModuleMemory(ClientProcessId client_pid, u64 nro_address) {
519 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); 536 R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
520 R_RETURN(m_ro->UnmapManualLoadModuleMemory(m_context_id, nro_address)); 537 R_RETURN(m_ro->UnmapManualLoadModuleMemory(m_context_id, nro_address));
521 } 538 }
522 539
523 Result RegisterModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size) { 540 Result RegisterModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size) {
524 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); 541 R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
525 R_RETURN( 542 R_RETURN(
526 m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, NrrKind::User, true)); 543 m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, NrrKind::User, true));
527 } 544 }
528 545
529 Result UnregisterModuleInfo(u64 client_pid, u64 nrr_address) { 546 Result UnregisterModuleInfo(ClientProcessId client_pid, u64 nrr_address) {
530 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); 547 R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
531 R_RETURN(m_ro->UnregisterModuleInfo(m_context_id, nrr_address)); 548 R_RETURN(m_ro->UnregisterModuleInfo(m_context_id, nrr_address));
532 } 549 }
533 550
534 Result RegisterProcessHandle(u64 client_pid, Kernel::KProcess* process) { 551 Result RegisterProcessHandle(ClientProcessId client_pid,
552 InCopyHandle<Kernel::KProcess>& process) {
535 // Register the process. 553 // Register the process.
536 R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process, client_pid)); 554 R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.GetPointerUnsafe(),
555 *client_pid));
537 } 556 }
538 557
539 Result RegisterProcessModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size, 558 Result RegisterProcessModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size,
540 Kernel::KProcess* process) { 559 InCopyHandle<Kernel::KProcess>& process) {
541 // Validate the process. 560 // Validate the process.
542 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); 561 R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
543 562
544 // Register the module. 563 // Register the module.
545 R_RETURN(m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, m_nrr_kind, 564 R_RETURN(m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, m_nrr_kind,
@@ -552,137 +571,6 @@ private:
552 NrrKind m_nrr_kind{}; 571 NrrKind m_nrr_kind{};
553}; 572};
554 573
555class IRoInterface : public ServiceFramework<IRoInterface> {
556public:
557 explicit IRoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro,
558 NrrKind nrr_kind)
559 : ServiceFramework{system_, name_}, interface {
560 ro, nrr_kind
561 } {
562 // clang-format off
563 static const FunctionInfo functions[] = {
564 {0, &IRoInterface::MapManualLoadModuleMemory, "MapManualLoadModuleMemory"},
565 {1, &IRoInterface::UnmapManualLoadModuleMemory, "UnmapManualLoadModuleMemory"},
566 {2, &IRoInterface::RegisterModuleInfo, "RegisterModuleInfo"},
567 {3, &IRoInterface::UnregisterModuleInfo, "UnregisterModuleInfo"},
568 {4, &IRoInterface::RegisterProcessHandle, "RegisterProcessHandle"},
569 {10, &IRoInterface::RegisterProcessModuleInfo, "RegisterProcessModuleInfo"},
570 };
571 // clang-format on
572
573 RegisterHandlers(functions);
574 }
575
576private:
577 void MapManualLoadModuleMemory(HLERequestContext& ctx) {
578 LOG_DEBUG(Service_LDR, "(called)");
579
580 struct InputParameters {
581 u64 client_pid;
582 u64 nro_address;
583 u64 nro_size;
584 u64 bss_address;
585 u64 bss_size;
586 };
587
588 IPC::RequestParser rp{ctx};
589 auto params = rp.PopRaw<InputParameters>();
590
591 u64 load_address = 0;
592 auto result = interface.MapManualLoadModuleMemory(&load_address, ctx.GetPID(),
593 params.nro_address, params.nro_size,
594 params.bss_address, params.bss_size);
595
596 IPC::ResponseBuilder rb{ctx, 4};
597 rb.Push(result);
598 rb.Push(load_address);
599 }
600
601 void UnmapManualLoadModuleMemory(HLERequestContext& ctx) {
602 LOG_DEBUG(Service_LDR, "(called)");
603
604 struct InputParameters {
605 u64 client_pid;
606 u64 nro_address;
607 };
608
609 IPC::RequestParser rp{ctx};
610 auto params = rp.PopRaw<InputParameters>();
611 auto result = interface.UnmapManualLoadModuleMemory(ctx.GetPID(), params.nro_address);
612
613 IPC::ResponseBuilder rb{ctx, 2};
614 rb.Push(result);
615 }
616
617 void RegisterModuleInfo(HLERequestContext& ctx) {
618 LOG_DEBUG(Service_LDR, "(called)");
619
620 struct InputParameters {
621 u64 client_pid;
622 u64 nrr_address;
623 u64 nrr_size;
624 };
625
626 IPC::RequestParser rp{ctx};
627 auto params = rp.PopRaw<InputParameters>();
628 auto result =
629 interface.RegisterModuleInfo(ctx.GetPID(), params.nrr_address, params.nrr_size);
630
631 IPC::ResponseBuilder rb{ctx, 2};
632 rb.Push(result);
633 }
634
635 void UnregisterModuleInfo(HLERequestContext& ctx) {
636 LOG_DEBUG(Service_LDR, "(called)");
637
638 struct InputParameters {
639 u64 client_pid;
640 u64 nrr_address;
641 };
642
643 IPC::RequestParser rp{ctx};
644 auto params = rp.PopRaw<InputParameters>();
645 auto result = interface.UnregisterModuleInfo(ctx.GetPID(), params.nrr_address);
646
647 IPC::ResponseBuilder rb{ctx, 2};
648 rb.Push(result);
649 }
650
651 void RegisterProcessHandle(HLERequestContext& ctx) {
652 LOG_DEBUG(Service_LDR, "(called)");
653
654 auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
655 auto client_pid = ctx.GetPID();
656 auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe());
657
658 IPC::ResponseBuilder rb{ctx, 2};
659 rb.Push(result);
660 }
661
662 void RegisterProcessModuleInfo(HLERequestContext& ctx) {
663 LOG_DEBUG(Service_LDR, "(called)");
664
665 struct InputParameters {
666 u64 client_pid;
667 u64 nrr_address;
668 u64 nrr_size;
669 };
670
671 IPC::RequestParser rp{ctx};
672 auto params = rp.PopRaw<InputParameters>();
673 auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
674
675 auto client_pid = ctx.GetPID();
676 auto result = interface.RegisterProcessModuleInfo(
677 client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe());
678
679 IPC::ResponseBuilder rb{ctx, 2};
680 rb.Push(result);
681 }
682
683 RoInterface interface;
684};
685
686} // namespace 574} // namespace
687 575
688void LoopProcess(Core::System& system) { 576void LoopProcess(Core::System& system) {
@@ -691,11 +579,11 @@ void LoopProcess(Core::System& system) {
691 auto ro = std::make_shared<RoContext>(); 579 auto ro = std::make_shared<RoContext>();
692 580
693 const auto RoInterfaceFactoryForUser = [&, ro] { 581 const auto RoInterfaceFactoryForUser = [&, ro] {
694 return std::make_shared<IRoInterface>(system, "ldr:ro", ro, NrrKind::User); 582 return std::make_shared<RoInterface>(system, "ldr:ro", ro, NrrKind::User);
695 }; 583 };
696 584
697 const auto RoInterfaceFactoryForJitPlugin = [&, ro] { 585 const auto RoInterfaceFactoryForJitPlugin = [&, ro] {
698 return std::make_shared<IRoInterface>(system, "ro:1", ro, NrrKind::JitPlugin); 586 return std::make_shared<RoInterface>(system, "ro:1", ro, NrrKind::JitPlugin);
699 }; 587 };
700 588
701 server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser)); 589 server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser));
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 39124c5fd..06cbad268 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -66,7 +66,6 @@
66#include "core/hle/service/sockets/sockets.h" 66#include "core/hle/service/sockets/sockets.h"
67#include "core/hle/service/spl/spl_module.h" 67#include "core/hle/service/spl/spl_module.h"
68#include "core/hle/service/ssl/ssl.h" 68#include "core/hle/service/ssl/ssl.h"
69#include "core/hle/service/time/time.h"
70#include "core/hle/service/usb/usb.h" 69#include "core/hle/service/usb/usb.h"
71#include "core/hle/service/vi/vi.h" 70#include "core/hle/service/vi/vi.h"
72#include "core/reporter.h" 71#include "core/reporter.h"
@@ -246,6 +245,9 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
246 kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); }); 245 kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); });
247 kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); }); 246 kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); });
248 kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); }); 247 kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); });
248 // glue depends on settings and psc, so they must come first
249 kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
250 kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
249 kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); }); 251 kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); });
250 kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); }); 252 kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); });
251 kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); }); 253 kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); });
@@ -269,13 +271,10 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
269 kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); }); 271 kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); });
270 kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); }); 272 kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); });
271 kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); }); 273 kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
272 kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
273 kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); }); 274 kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); });
274 kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); }); 275 kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); });
275 kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
276 kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); }); 276 kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); });
277 kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); }); 277 kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); });
278 kernel.RunOnGuestCoreProcess("time", [&] { Time::LoopProcess(system); });
279 kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); }); 278 kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); });
280 // clang-format on 279 // clang-format on
281} 280}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index d539ed0f4..22d1343d5 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -206,6 +206,22 @@ protected:
206 RegisterHandlersBaseTipc(functions, n); 206 RegisterHandlersBaseTipc(functions, n);
207 } 207 }
208 208
209protected:
210 template <bool Domain, auto F>
211 void CmifReplyWrap(HLERequestContext& ctx);
212
213 /**
214 * Wraps the template pointer-to-member function for use in a domain session.
215 */
216 template <auto F>
217 static constexpr HandlerFnP<Self> D = &Self::template CmifReplyWrap<true, F>;
218
219 /**
220 * Wraps the template pointer-to-member function for use in a non-domain session.
221 */
222 template <auto F>
223 static constexpr HandlerFnP<Self> C = &Self::template CmifReplyWrap<false, F>;
224
209private: 225private:
210 /** 226 /**
211 * This function is used to allow invocation of pointers to handlers stored in the base class 227 * This function is used to allow invocation of pointers to handlers stored in the base class
diff --git a/src/core/hle/service/set/private_settings.h b/src/core/hle/service/set/private_settings.h
new file mode 100644
index 000000000..b02291ce7
--- /dev/null
+++ b/src/core/hle/service/set/private_settings.h
@@ -0,0 +1,72 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/bit_field.h"
9#include "common/common_funcs.h"
10#include "common/common_types.h"
11#include "common/uuid.h"
12#include "core/hle/service/psc/time/common.h"
13
14namespace Service::Set {
15
16/// This is nn::settings::system::InitialLaunchFlag
17struct InitialLaunchFlag {
18 union {
19 u32 raw{};
20
21 BitField<0, 1, u32> InitialLaunchCompletionFlag;
22 BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
23 BitField<16, 1, u32> InitialLaunchTimestampFlag;
24 };
25};
26static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
27
28/// This is nn::settings::system::InitialLaunchSettings
29struct InitialLaunchSettings {
30 InitialLaunchFlag flags;
31 INSERT_PADDING_BYTES(0x4);
32 Service::PSC::Time::SteadyClockTimePoint timestamp;
33};
34static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
35
36#pragma pack(push, 4)
37struct InitialLaunchSettingsPacked {
38 InitialLaunchFlag flags;
39 Service::PSC::Time::SteadyClockTimePoint timestamp;
40};
41#pragma pack(pop)
42static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C,
43 "InitialLaunchSettingsPacked is incorrect size");
44
45struct PrivateSettings {
46 std::array<u8, 0x10> reserved_00;
47
48 // nn::settings::system::InitialLaunchSettings
49 InitialLaunchSettings initial_launch_settings;
50
51 std::array<u8, 0x20> reserved_30;
52
53 Common::UUID external_clock_source_id;
54 s64 shutdown_rtc_value;
55 s64 external_steady_clock_internal_offset;
56
57 std::array<u8, 0x60> reserved_70;
58
59 // nn::settings::system::PlatformRegion
60 std::array<u8, 0x4> platform_region;
61
62 std::array<u8, 0x4> reserved_D4;
63};
64static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10);
65static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50);
66static_assert(offsetof(PrivateSettings, reserved_70) == 0x70);
67static_assert(offsetof(PrivateSettings, platform_region) == 0xD0);
68static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!");
69
70PrivateSettings DefaultPrivateSettings();
71
72} // namespace Service::Set
diff --git a/src/core/hle/service/set/setting_formats/private_settings.h b/src/core/hle/service/set/setting_formats/private_settings.h
index 6c40f62e1..6579e95e0 100644
--- a/src/core/hle/service/set/setting_formats/private_settings.h
+++ b/src/core/hle/service/set/setting_formats/private_settings.h
@@ -8,7 +8,6 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/uuid.h" 9#include "common/uuid.h"
10#include "core/hle/service/set/settings_types.h" 10#include "core/hle/service/set/settings_types.h"
11#include "core/hle/service/time/clock_types.h"
12 11
13namespace Service::Set { 12namespace Service::Set {
14 13
diff --git a/src/core/hle/service/set/setting_formats/system_settings.cpp b/src/core/hle/service/set/setting_formats/system_settings.cpp
index 66e57651e..ec00b90a6 100644
--- a/src/core/hle/service/set/setting_formats/system_settings.cpp
+++ b/src/core/hle/service/set/setting_formats/system_settings.cpp
@@ -45,7 +45,7 @@ SystemSettings DefaultSystemSettings() {
45 }; 45 };
46 46
47 settings.device_time_zone_location_name = {"UTC"}; 47 settings.device_time_zone_location_name = {"UTC"};
48 settings.user_system_clock_automatic_correction_enabled = false; 48 settings.user_system_clock_automatic_correction_enabled = true;
49 49
50 settings.primary_album_storage = PrimaryAlbumStorage::SdCard; 50 settings.primary_album_storage = PrimaryAlbumStorage::SdCard;
51 settings.battery_percentage_flag = true; 51 settings.battery_percentage_flag = true;
diff --git a/src/core/hle/service/set/setting_formats/system_settings.h b/src/core/hle/service/set/setting_formats/system_settings.h
index 14654f8b1..af5929fa9 100644
--- a/src/core/hle/service/set/setting_formats/system_settings.h
+++ b/src/core/hle/service/set/setting_formats/system_settings.h
@@ -12,7 +12,6 @@
12#include "common/vector_math.h" 12#include "common/vector_math.h"
13#include "core/hle/service/set/setting_formats/private_settings.h" 13#include "core/hle/service/set/setting_formats/private_settings.h"
14#include "core/hle/service/set/settings_types.h" 14#include "core/hle/service/set/settings_types.h"
15#include "core/hle/service/time/clock_types.h"
16 15
17namespace Service::Set { 16namespace Service::Set {
18 17
@@ -197,12 +196,14 @@ struct SystemSettings {
197 std::array<u8, 0x2C> backlight_settings_mixed_up; 196 std::array<u8, 0x2C> backlight_settings_mixed_up;
198 INSERT_PADDING_BYTES(0x64); // Reserved 197 INSERT_PADDING_BYTES(0x64); // Reserved
199 198
200 Service::Time::Clock::SystemClockContext user_system_clock_context; 199 // nn::time::SystemClockContext
201 Service::Time::Clock::SystemClockContext network_system_clock_context; 200 Service::PSC::Time::SystemClockContext user_system_clock_context;
201 Service::PSC::Time::SystemClockContext network_system_clock_context;
202 bool user_system_clock_automatic_correction_enabled; 202 bool user_system_clock_automatic_correction_enabled;
203 INSERT_PADDING_BYTES(0x3); 203 INSERT_PADDING_BYTES(0x3);
204 INSERT_PADDING_BYTES(0x4); // Reserved 204 INSERT_PADDING_BYTES(0x4); // Reserved
205 Service::Time::Clock::SteadyClockTimePoint 205 // nn::time::SteadyClockTimePoint
206 Service::PSC::Time::SteadyClockTimePoint
206 user_system_clock_automatic_correction_updated_time_point; 207 user_system_clock_automatic_correction_updated_time_point;
207 INSERT_PADDING_BYTES(0x10); // Reserved 208 INSERT_PADDING_BYTES(0x10); // Reserved
208 209
@@ -280,9 +281,12 @@ struct SystemSettings {
280 bool requires_run_repair_time_reviser; 281 bool requires_run_repair_time_reviser;
281 INSERT_PADDING_BYTES(0x6B); // Reserved 282 INSERT_PADDING_BYTES(0x6B); // Reserved
282 283
283 Service::Time::TimeZone::LocationName device_time_zone_location_name; 284 // nn::time::LocationName
285 Service::PSC::Time::LocationName device_time_zone_location_name;
284 INSERT_PADDING_BYTES(0x4); // Reserved 286 INSERT_PADDING_BYTES(0x4); // Reserved
285 Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time; 287 // nn::time::SteadyClockTimePoint
288 Service::PSC::Time::SteadyClockTimePoint device_time_zone_location_updated_time;
289
286 INSERT_PADDING_BYTES(0xC0); // Reserved 290 INSERT_PADDING_BYTES(0xC0); // Reserved
287 291
288 // nn::settings::system::PrimaryAlbumStorage 292 // nn::settings::system::PrimaryAlbumStorage
diff --git a/src/core/hle/service/set/settings_types.h b/src/core/hle/service/set/settings_types.h
index 4dee202d7..f6f227fde 100644
--- a/src/core/hle/service/set/settings_types.h
+++ b/src/core/hle/service/set/settings_types.h
@@ -9,7 +9,7 @@
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/uuid.h" 11#include "common/uuid.h"
12#include "core/hle/service/time/clock_types.h" 12#include "core/hle/service/psc/time/common.h"
13 13
14namespace Service::Set { 14namespace Service::Set {
15 15
@@ -365,7 +365,7 @@ struct EulaVersion {
365 EulaVersionClockType clock_type; 365 EulaVersionClockType clock_type;
366 INSERT_PADDING_BYTES(0x4); 366 INSERT_PADDING_BYTES(0x4);
367 s64 posix_time; 367 s64 posix_time;
368 Time::Clock::SteadyClockTimePoint timestamp; 368 Service::PSC::Time::SteadyClockTimePoint timestamp;
369}; 369};
370static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); 370static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
371 371
@@ -398,14 +398,14 @@ static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size"
398struct InitialLaunchSettings { 398struct InitialLaunchSettings {
399 InitialLaunchFlag flags; 399 InitialLaunchFlag flags;
400 INSERT_PADDING_BYTES(0x4); 400 INSERT_PADDING_BYTES(0x4);
401 Service::Time::Clock::SteadyClockTimePoint timestamp; 401 Service::PSC::Time::SteadyClockTimePoint timestamp;
402}; 402};
403static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); 403static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
404 404
405#pragma pack(push, 4) 405#pragma pack(push, 4)
406struct InitialLaunchSettingsPacked { 406struct InitialLaunchSettingsPacked {
407 InitialLaunchFlag flags; 407 InitialLaunchFlag flags;
408 Service::Time::Clock::SteadyClockTimePoint timestamp; 408 Service::PSC::Time::SteadyClockTimePoint timestamp;
409}; 409};
410#pragma pack(pop) 410#pragma pack(pop)
411static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, 411static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C,
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index 2e5785fed..f40a1c8f3 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -489,11 +489,10 @@ void ISystemSettingsServer::SetExternalSteadyClockSourceId(HLERequestContext& ct
489void ISystemSettingsServer::GetUserSystemClockContext(HLERequestContext& ctx) { 489void ISystemSettingsServer::GetUserSystemClockContext(HLERequestContext& ctx) {
490 LOG_INFO(Service_SET, "called"); 490 LOG_INFO(Service_SET, "called");
491 491
492 Service::Time::Clock::SystemClockContext context{}; 492 Service::PSC::Time::SystemClockContext context{};
493 auto res = GetUserSystemClockContext(context); 493 auto res = GetUserSystemClockContext(context);
494 494
495 IPC::ResponseBuilder rb{ctx, 495 IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::SystemClockContext) / sizeof(u32)};
496 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)};
497 rb.Push(res); 496 rb.Push(res);
498 rb.PushRaw(context); 497 rb.PushRaw(context);
499} 498}
@@ -502,7 +501,7 @@ void ISystemSettingsServer::SetUserSystemClockContext(HLERequestContext& ctx) {
502 LOG_INFO(Service_SET, "called"); 501 LOG_INFO(Service_SET, "called");
503 502
504 IPC::RequestParser rp{ctx}; 503 IPC::RequestParser rp{ctx};
505 auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()}; 504 auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
506 505
507 auto res = SetUserSystemClockContext(context); 506 auto res = SetUserSystemClockContext(context);
508 507
@@ -710,12 +709,12 @@ void ISystemSettingsServer::GetSettingsItemValueSize(HLERequestContext& ctx) {
710 // The category of the setting. This corresponds to the top-level keys of 709 // The category of the setting. This corresponds to the top-level keys of
711 // system_settings.ini. 710 // system_settings.ini.
712 const auto setting_category_buf{ctx.ReadBuffer(0)}; 711 const auto setting_category_buf{ctx.ReadBuffer(0)};
713 const std::string setting_category{setting_category_buf.begin(), setting_category_buf.end()}; 712 const std::string setting_category{Common::StringFromBuffer(setting_category_buf)};
714 713
715 // The name of the setting. This corresponds to the second-level keys of 714 // The name of the setting. This corresponds to the second-level keys of
716 // system_settings.ini. 715 // system_settings.ini.
717 const auto setting_name_buf{ctx.ReadBuffer(1)}; 716 const auto setting_name_buf{ctx.ReadBuffer(1)};
718 const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()}; 717 const std::string setting_name{Common::StringFromBuffer(setting_name_buf)};
719 718
720 auto settings{GetSettings()}; 719 auto settings{GetSettings()};
721 u64 response_size{0}; 720 u64 response_size{0};
@@ -733,12 +732,12 @@ void ISystemSettingsServer::GetSettingsItemValue(HLERequestContext& ctx) {
733 // The category of the setting. This corresponds to the top-level keys of 732 // The category of the setting. This corresponds to the top-level keys of
734 // system_settings.ini. 733 // system_settings.ini.
735 const auto setting_category_buf{ctx.ReadBuffer(0)}; 734 const auto setting_category_buf{ctx.ReadBuffer(0)};
736 const std::string setting_category{setting_category_buf.begin(), setting_category_buf.end()}; 735 const std::string setting_category{Common::StringFromBuffer(setting_category_buf)};
737 736
738 // The name of the setting. This corresponds to the second-level keys of 737 // The name of the setting. This corresponds to the second-level keys of
739 // system_settings.ini. 738 // system_settings.ini.
740 const auto setting_name_buf{ctx.ReadBuffer(1)}; 739 const auto setting_name_buf{ctx.ReadBuffer(1)};
741 const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()}; 740 const std::string setting_name{Common::StringFromBuffer(setting_name_buf)};
742 741
743 std::vector<u8> value; 742 std::vector<u8> value;
744 auto response = GetSettingsItemValue(value, setting_category, setting_name); 743 auto response = GetSettingsItemValue(value, setting_category, setting_name);
@@ -809,19 +808,19 @@ void ISystemSettingsServer::GetQuestFlag(HLERequestContext& ctx) {
809void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) { 808void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) {
810 LOG_INFO(Service_SET, "called"); 809 LOG_INFO(Service_SET, "called");
811 810
812 Service::Time::TimeZone::LocationName name{}; 811 Service::PSC::Time::LocationName name{};
813 auto res = GetDeviceTimeZoneLocationName(name); 812 auto res = GetDeviceTimeZoneLocationName(name);
814 813
815 IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::Time::TimeZone::LocationName) / sizeof(u32)}; 814 IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)};
816 rb.Push(res); 815 rb.Push(res);
817 rb.PushRaw<Service::Time::TimeZone::LocationName>(name); 816 rb.PushRaw<Service::PSC::Time::LocationName>(name);
818} 817}
819 818
820void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) { 819void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) {
821 LOG_INFO(Service_SET, "called"); 820 LOG_INFO(Service_SET, "called");
822 821
823 IPC::RequestParser rp{ctx}; 822 IPC::RequestParser rp{ctx};
824 auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()}; 823 auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
825 824
826 auto res = SetDeviceTimeZoneLocationName(name); 825 auto res = SetDeviceTimeZoneLocationName(name);
827 826
@@ -843,11 +842,10 @@ void ISystemSettingsServer::SetRegionCode(HLERequestContext& ctx) {
843void ISystemSettingsServer::GetNetworkSystemClockContext(HLERequestContext& ctx) { 842void ISystemSettingsServer::GetNetworkSystemClockContext(HLERequestContext& ctx) {
844 LOG_INFO(Service_SET, "called"); 843 LOG_INFO(Service_SET, "called");
845 844
846 Service::Time::Clock::SystemClockContext context{}; 845 Service::PSC::Time::SystemClockContext context{};
847 auto res = GetNetworkSystemClockContext(context); 846 auto res = GetNetworkSystemClockContext(context);
848 847
849 IPC::ResponseBuilder rb{ctx, 848 IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::SystemClockContext) / sizeof(u32)};
850 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)};
851 rb.Push(res); 849 rb.Push(res);
852 rb.PushRaw(context); 850 rb.PushRaw(context);
853} 851}
@@ -856,7 +854,7 @@ void ISystemSettingsServer::SetNetworkSystemClockContext(HLERequestContext& ctx)
856 LOG_INFO(Service_SET, "called"); 854 LOG_INFO(Service_SET, "called");
857 855
858 IPC::RequestParser rp{ctx}; 856 IPC::RequestParser rp{ctx};
859 auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()}; 857 auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
860 858
861 auto res = SetNetworkSystemClockContext(context); 859 auto res = SetNetworkSystemClockContext(context);
862 860
@@ -1141,19 +1139,19 @@ void ISystemSettingsServer::GetKeyboardLayout(HLERequestContext& ctx) {
1141void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { 1139void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) {
1142 LOG_INFO(Service_SET, "called"); 1140 LOG_INFO(Service_SET, "called");
1143 1141
1144 Service::Time::Clock::SteadyClockTimePoint time_point{}; 1142 Service::PSC::Time::SteadyClockTimePoint time_point{};
1145 auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point); 1143 auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point);
1146 1144
1147 IPC::ResponseBuilder rb{ctx, 4}; 1145 IPC::ResponseBuilder rb{ctx, 4};
1148 rb.Push(res); 1146 rb.Push(res);
1149 rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point); 1147 rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
1150} 1148}
1151 1149
1152void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { 1150void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) {
1153 LOG_INFO(Service_SET, "called"); 1151 LOG_INFO(Service_SET, "called");
1154 1152
1155 IPC::RequestParser rp{ctx}; 1153 IPC::RequestParser rp{ctx};
1156 auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; 1154 auto time_point{rp.PopRaw<Service::PSC::Time::SteadyClockTimePoint>()};
1157 1155
1158 auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point); 1156 auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point);
1159 1157
@@ -1165,12 +1163,12 @@ void ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime(
1165 HLERequestContext& ctx) { 1163 HLERequestContext& ctx) {
1166 LOG_INFO(Service_SET, "called"); 1164 LOG_INFO(Service_SET, "called");
1167 1165
1168 Service::Time::Clock::SteadyClockTimePoint time_point{}; 1166 Service::PSC::Time::SteadyClockTimePoint time_point{};
1169 auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); 1167 auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
1170 1168
1171 IPC::ResponseBuilder rb{ctx, 4}; 1169 IPC::ResponseBuilder rb{ctx, 4};
1172 rb.Push(res); 1170 rb.Push(res);
1173 rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point); 1171 rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
1174} 1172}
1175 1173
1176void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( 1174void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime(
@@ -1178,7 +1176,7 @@ void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime(
1178 LOG_INFO(Service_SET, "called"); 1176 LOG_INFO(Service_SET, "called");
1179 1177
1180 IPC::RequestParser rp{ctx}; 1178 IPC::RequestParser rp{ctx};
1181 auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; 1179 auto time_point{rp.PopRaw<Service::PSC::Time::SteadyClockTimePoint>()};
1182 1180
1183 auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); 1181 auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
1184 1182
@@ -1257,25 +1255,25 @@ void ISystemSettingsServer::StoreSettings() {
1257 auto system_dir = 1255 auto system_dir =
1258 Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; 1256 Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050";
1259 if (!StoreSettingsFile(system_dir, m_system_settings)) { 1257 if (!StoreSettingsFile(system_dir, m_system_settings)) {
1260 LOG_ERROR(HW_GPU, "Failed to store System settings"); 1258 LOG_ERROR(Service_SET, "Failed to store System settings");
1261 } 1259 }
1262 1260
1263 auto private_dir = 1261 auto private_dir =
1264 Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; 1262 Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052";
1265 if (!StoreSettingsFile(private_dir, m_private_settings)) { 1263 if (!StoreSettingsFile(private_dir, m_private_settings)) {
1266 LOG_ERROR(HW_GPU, "Failed to store Private settings"); 1264 LOG_ERROR(Service_SET, "Failed to store Private settings");
1267 } 1265 }
1268 1266
1269 auto device_dir = 1267 auto device_dir =
1270 Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; 1268 Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053";
1271 if (!StoreSettingsFile(device_dir, m_device_settings)) { 1269 if (!StoreSettingsFile(device_dir, m_device_settings)) {
1272 LOG_ERROR(HW_GPU, "Failed to store Device settings"); 1270 LOG_ERROR(Service_SET, "Failed to store Device settings");
1273 } 1271 }
1274 1272
1275 auto appln_dir = 1273 auto appln_dir =
1276 Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; 1274 Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054";
1277 if (!StoreSettingsFile(appln_dir, m_appln_settings)) { 1275 if (!StoreSettingsFile(appln_dir, m_appln_settings)) {
1278 LOG_ERROR(HW_GPU, "Failed to store ApplLn settings"); 1276 LOG_ERROR(Service_SET, "Failed to store ApplLn settings");
1279 } 1277 }
1280} 1278}
1281 1279
@@ -1318,39 +1316,39 @@ Result ISystemSettingsServer::SetExternalSteadyClockSourceId(Common::UUID id) {
1318} 1316}
1319 1317
1320Result ISystemSettingsServer::GetUserSystemClockContext( 1318Result ISystemSettingsServer::GetUserSystemClockContext(
1321 Service::Time::Clock::SystemClockContext& out_context) { 1319 Service::PSC::Time::SystemClockContext& out_context) {
1322 out_context = m_system_settings.user_system_clock_context; 1320 out_context = m_system_settings.user_system_clock_context;
1323 R_SUCCEED(); 1321 R_SUCCEED();
1324} 1322}
1325 1323
1326Result ISystemSettingsServer::SetUserSystemClockContext( 1324Result ISystemSettingsServer::SetUserSystemClockContext(
1327 Service::Time::Clock::SystemClockContext& context) { 1325 Service::PSC::Time::SystemClockContext& context) {
1328 m_system_settings.user_system_clock_context = context; 1326 m_system_settings.user_system_clock_context = context;
1329 SetSaveNeeded(); 1327 SetSaveNeeded();
1330 R_SUCCEED(); 1328 R_SUCCEED();
1331} 1329}
1332 1330
1333Result ISystemSettingsServer::GetDeviceTimeZoneLocationName( 1331Result ISystemSettingsServer::GetDeviceTimeZoneLocationName(
1334 Service::Time::TimeZone::LocationName& out_name) { 1332 Service::PSC::Time::LocationName& out_name) {
1335 out_name = m_system_settings.device_time_zone_location_name; 1333 out_name = m_system_settings.device_time_zone_location_name;
1336 R_SUCCEED(); 1334 R_SUCCEED();
1337} 1335}
1338 1336
1339Result ISystemSettingsServer::SetDeviceTimeZoneLocationName( 1337Result ISystemSettingsServer::SetDeviceTimeZoneLocationName(
1340 Service::Time::TimeZone::LocationName& name) { 1338 Service::PSC::Time::LocationName& name) {
1341 m_system_settings.device_time_zone_location_name = name; 1339 m_system_settings.device_time_zone_location_name = name;
1342 SetSaveNeeded(); 1340 SetSaveNeeded();
1343 R_SUCCEED(); 1341 R_SUCCEED();
1344} 1342}
1345 1343
1346Result ISystemSettingsServer::GetNetworkSystemClockContext( 1344Result ISystemSettingsServer::GetNetworkSystemClockContext(
1347 Service::Time::Clock::SystemClockContext& out_context) { 1345 Service::PSC::Time::SystemClockContext& out_context) {
1348 out_context = m_system_settings.network_system_clock_context; 1346 out_context = m_system_settings.network_system_clock_context;
1349 R_SUCCEED(); 1347 R_SUCCEED();
1350} 1348}
1351 1349
1352Result ISystemSettingsServer::SetNetworkSystemClockContext( 1350Result ISystemSettingsServer::SetNetworkSystemClockContext(
1353 Service::Time::Clock::SystemClockContext& context) { 1351 Service::PSC::Time::SystemClockContext& context) {
1354 m_system_settings.network_system_clock_context = context; 1352 m_system_settings.network_system_clock_context = context;
1355 SetSaveNeeded(); 1353 SetSaveNeeded();
1356 R_SUCCEED(); 1354 R_SUCCEED();
@@ -1379,26 +1377,26 @@ Result ISystemSettingsServer::GetExternalSteadyClockInternalOffset(s64& out_offs
1379} 1377}
1380 1378
1381Result ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime( 1379Result ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(
1382 Service::Time::Clock::SteadyClockTimePoint& out_time_point) { 1380 Service::PSC::Time::SteadyClockTimePoint& out_time_point) {
1383 out_time_point = m_system_settings.device_time_zone_location_updated_time; 1381 out_time_point = m_system_settings.device_time_zone_location_updated_time;
1384 R_SUCCEED(); 1382 R_SUCCEED();
1385} 1383}
1386 1384
1387Result ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime( 1385Result ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(
1388 Service::Time::Clock::SteadyClockTimePoint& time_point) { 1386 Service::PSC::Time::SteadyClockTimePoint& time_point) {
1389 m_system_settings.device_time_zone_location_updated_time = time_point; 1387 m_system_settings.device_time_zone_location_updated_time = time_point;
1390 SetSaveNeeded(); 1388 SetSaveNeeded();
1391 R_SUCCEED(); 1389 R_SUCCEED();
1392} 1390}
1393 1391
1394Result ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( 1392Result ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime(
1395 Service::Time::Clock::SteadyClockTimePoint& out_time_point) { 1393 Service::PSC::Time::SteadyClockTimePoint& out_time_point) {
1396 out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point; 1394 out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point;
1397 R_SUCCEED(); 1395 R_SUCCEED();
1398} 1396}
1399 1397
1400Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( 1398Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime(
1401 Service::Time::Clock::SteadyClockTimePoint out_time_point) { 1399 Service::PSC::Time::SteadyClockTimePoint out_time_point) {
1402 m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point; 1400 m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point;
1403 SetSaveNeeded(); 1401 SetSaveNeeded();
1404 R_SUCCEED(); 1402 R_SUCCEED();
diff --git a/src/core/hle/service/set/system_settings_server.h b/src/core/hle/service/set/system_settings_server.h
index 32716f567..a2258d16d 100644
--- a/src/core/hle/service/set/system_settings_server.h
+++ b/src/core/hle/service/set/system_settings_server.h
@@ -11,14 +11,13 @@
11#include "common/polyfill_thread.h" 11#include "common/polyfill_thread.h"
12#include "common/uuid.h" 12#include "common/uuid.h"
13#include "core/hle/result.h" 13#include "core/hle/result.h"
14#include "core/hle/service/psc/time/common.h"
14#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
15#include "core/hle/service/set/setting_formats/appln_settings.h" 16#include "core/hle/service/set/setting_formats/appln_settings.h"
16#include "core/hle/service/set/setting_formats/device_settings.h" 17#include "core/hle/service/set/setting_formats/device_settings.h"
17#include "core/hle/service/set/setting_formats/private_settings.h" 18#include "core/hle/service/set/setting_formats/private_settings.h"
18#include "core/hle/service/set/setting_formats/system_settings.h" 19#include "core/hle/service/set/setting_formats/system_settings.h"
19#include "core/hle/service/set/settings_types.h" 20#include "core/hle/service/set/settings_types.h"
20#include "core/hle/service/time/clock_types.h"
21#include "core/hle/service/time/time_zone_types.h"
22 21
23namespace Core { 22namespace Core {
24class System; 23class System;
@@ -51,24 +50,24 @@ public:
51 50
52 Result GetExternalSteadyClockSourceId(Common::UUID& out_id); 51 Result GetExternalSteadyClockSourceId(Common::UUID& out_id);
53 Result SetExternalSteadyClockSourceId(Common::UUID id); 52 Result SetExternalSteadyClockSourceId(Common::UUID id);
54 Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); 53 Result GetUserSystemClockContext(Service::PSC::Time::SystemClockContext& out_context);
55 Result SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context); 54 Result SetUserSystemClockContext(Service::PSC::Time::SystemClockContext& context);
56 Result GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name); 55 Result GetDeviceTimeZoneLocationName(Service::PSC::Time::LocationName& out_name);
57 Result SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name); 56 Result SetDeviceTimeZoneLocationName(Service::PSC::Time::LocationName& name);
58 Result GetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); 57 Result GetNetworkSystemClockContext(Service::PSC::Time::SystemClockContext& out_context);
59 Result SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context); 58 Result SetNetworkSystemClockContext(Service::PSC::Time::SystemClockContext& context);
60 Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled); 59 Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled);
61 Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled); 60 Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled);
62 Result SetExternalSteadyClockInternalOffset(s64 offset); 61 Result SetExternalSteadyClockInternalOffset(s64 offset);
63 Result GetExternalSteadyClockInternalOffset(s64& out_offset); 62 Result GetExternalSteadyClockInternalOffset(s64& out_offset);
64 Result GetDeviceTimeZoneLocationUpdatedTime( 63 Result GetDeviceTimeZoneLocationUpdatedTime(
65 Service::Time::Clock::SteadyClockTimePoint& out_time_point); 64 Service::PSC::Time::SteadyClockTimePoint& out_time_point);
66 Result SetDeviceTimeZoneLocationUpdatedTime( 65 Result SetDeviceTimeZoneLocationUpdatedTime(
67 Service::Time::Clock::SteadyClockTimePoint& time_point); 66 Service::PSC::Time::SteadyClockTimePoint& time_point);
68 Result GetUserSystemClockAutomaticCorrectionUpdatedTime( 67 Result GetUserSystemClockAutomaticCorrectionUpdatedTime(
69 Service::Time::Clock::SteadyClockTimePoint& out_time_point); 68 Service::PSC::Time::SteadyClockTimePoint& out_time_point);
70 Result SetUserSystemClockAutomaticCorrectionUpdatedTime( 69 Result SetUserSystemClockAutomaticCorrectionUpdatedTime(
71 Service::Time::Clock::SteadyClockTimePoint time_point); 70 Service::PSC::Time::SteadyClockTimePoint time_point);
72 71
73private: 72private:
74 void SetLanguageCode(HLERequestContext& ctx); 73 void SetLanguageCode(HLERequestContext& ctx);
@@ -147,8 +146,8 @@ private:
147 PrivateSettings m_private_settings{}; 146 PrivateSettings m_private_settings{};
148 DeviceSettings m_device_settings{}; 147 DeviceSettings m_device_settings{};
149 ApplnSettings m_appln_settings{}; 148 ApplnSettings m_appln_settings{};
150 std::jthread m_save_thread;
151 std::mutex m_save_needed_mutex; 149 std::mutex m_save_needed_mutex;
150 std::jthread m_save_thread;
152 bool m_save_needed{false}; 151 bool m_save_needed{false};
153}; 152};
154 153
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 4ae32a9c1..32c218638 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <chrono>
6#include <memory> 7#include <memory>
7#include <mutex> 8#include <mutex>
8#include <string> 9#include <string>
@@ -10,6 +11,7 @@
10 11
11#include "common/concepts.h" 12#include "common/concepts.h"
12#include "core/hle/kernel/k_port.h" 13#include "core/hle/kernel/k_port.h"
14#include "core/hle/kernel/svc.h"
13#include "core/hle/result.h" 15#include "core/hle/result.h"
14#include "core/hle/service/service.h" 16#include "core/hle/service/service.h"
15 17
@@ -62,12 +64,21 @@ public:
62 Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name); 64 Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name);
63 65
64 template <Common::DerivedFrom<SessionRequestHandler> T> 66 template <Common::DerivedFrom<SessionRequestHandler> T>
65 std::shared_ptr<T> GetService(const std::string& service_name) const { 67 std::shared_ptr<T> GetService(const std::string& service_name, bool block = false) const {
66 auto service = registered_services.find(service_name); 68 auto service = registered_services.find(service_name);
67 if (service == registered_services.end()) { 69 if (service == registered_services.end() && !block) {
68 LOG_DEBUG(Service, "Can't find service: {}", service_name); 70 LOG_DEBUG(Service, "Can't find service: {}", service_name);
69 return nullptr; 71 return nullptr;
72 } else if (block) {
73 using namespace std::literals::chrono_literals;
74 while (service == registered_services.end()) {
75 Kernel::Svc::SleepThread(
76 kernel.System(),
77 std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count());
78 service = registered_services.find(service_name);
79 }
70 } 80 }
81
71 return std::static_pointer_cast<T>(service->second()); 82 return std::static_pointer_cast<T>(service->second());
72 } 83 }
73 84
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h
deleted file mode 100644
index 7149fffeb..000000000
--- a/src/core/hle/service/time/clock_types.h
+++ /dev/null
@@ -1,129 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <ratio>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10#include "common/uuid.h"
11#include "core/hle/service/time/errors.h"
12#include "core/hle/service/time/time_zone_types.h"
13
14// Defined by WinBase.h on Windows
15#ifdef GetCurrentTime
16#undef GetCurrentTime
17#endif
18
19namespace Service::Time::Clock {
20
21enum class TimeType : u8 {
22 UserSystemClock,
23 NetworkSystemClock,
24 LocalSystemClock,
25};
26
27/// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint
28struct SteadyClockTimePoint {
29 s64 time_point;
30 Common::UUID clock_source_id;
31
32 Result GetSpanBetween(SteadyClockTimePoint other, s64& span) const {
33 span = 0;
34
35 if (clock_source_id != other.clock_source_id) {
36 return ERROR_TIME_MISMATCH;
37 }
38
39 span = other.time_point - time_point;
40
41 return ResultSuccess;
42 }
43
44 static SteadyClockTimePoint GetRandom() {
45 return {0, Common::UUID::MakeRandom()};
46 }
47};
48static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
49static_assert(std::is_trivially_copyable_v<SteadyClockTimePoint>,
50 "SteadyClockTimePoint must be trivially copyable");
51
52struct SteadyClockContext {
53 u64 internal_offset;
54 Common::UUID steady_time_point;
55};
56static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size");
57static_assert(std::is_trivially_copyable_v<SteadyClockContext>,
58 "SteadyClockContext must be trivially copyable");
59using StandardSteadyClockTimePointType = SteadyClockContext;
60
61struct SystemClockContext {
62 s64 offset;
63 SteadyClockTimePoint steady_time_point;
64};
65static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorrect size");
66static_assert(std::is_trivially_copyable_v<SystemClockContext>,
67 "SystemClockContext must be trivially copyable");
68
69struct ContinuousAdjustmentTimePoint {
70 s64 measurement_offset;
71 s64 diff_scale;
72 u32 shift_amount;
73 s64 lower;
74 s64 upper;
75 Common::UUID clock_source_id;
76};
77static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38);
78static_assert(std::is_trivially_copyable_v<ContinuousAdjustmentTimePoint>,
79 "ContinuousAdjustmentTimePoint must be trivially copyable");
80
81/// https://switchbrew.org/wiki/Glue_services#TimeSpanType
82struct TimeSpanType {
83 s64 nanoseconds{};
84
85 s64 ToSeconds() const {
86 return nanoseconds / std::nano::den;
87 }
88
89 static TimeSpanType FromSeconds(s64 seconds) {
90 return {seconds * std::nano::den};
91 }
92
93 template <u64 Frequency>
94 static TimeSpanType FromTicks(u64 ticks) {
95 using TicksToNSRatio = std::ratio<std::nano::den, Frequency>;
96 return {static_cast<s64>(ticks * TicksToNSRatio::num / TicksToNSRatio::den)};
97 }
98};
99static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size");
100
101struct ClockSnapshot {
102 SystemClockContext user_context;
103 SystemClockContext network_context;
104 s64 user_time;
105 s64 network_time;
106 TimeZone::CalendarTime user_calendar_time;
107 TimeZone::CalendarTime network_calendar_time;
108 TimeZone::CalendarAdditionalInfo user_calendar_additional_time;
109 TimeZone::CalendarAdditionalInfo network_calendar_additional_time;
110 SteadyClockTimePoint steady_clock_time_point;
111 TimeZone::LocationName location_name;
112 u8 is_automatic_correction_enabled;
113 TimeType type;
114 INSERT_PADDING_BYTES_NOINIT(0x2);
115
116 static Result GetCurrentTime(s64& current_time,
117 const SteadyClockTimePoint& steady_clock_time_point,
118 const SystemClockContext& context) {
119 if (steady_clock_time_point.clock_source_id != context.steady_time_point.clock_source_id) {
120 current_time = 0;
121 return ERROR_TIME_MISMATCH;
122 }
123 current_time = steady_clock_time_point.time_point + context.offset;
124 return ResultSuccess;
125 }
126};
127static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot is incorrect size");
128
129} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h b/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h
deleted file mode 100644
index 0f928a5a5..000000000
--- a/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h
+++ /dev/null
@@ -1,15 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/system_clock_context_update_callback.h"
7
8namespace Service::Time::Clock {
9
10class EphemeralNetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
11public:
12 EphemeralNetworkSystemClockContextWriter() : SystemClockContextUpdateCallback{} {}
13};
14
15} // namespace Service::Time::Clock
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
deleted file mode 100644
index 0a5f5aafb..000000000
--- a/src/core/hle/service/time/ephemeral_network_system_clock_core.h
+++ /dev/null
@@ -1,16 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/system_clock_core.h"
7
8namespace Service::Time::Clock {
9
10class EphemeralNetworkSystemClockCore final : public SystemClockCore {
11public:
12 explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
13 : SystemClockCore{steady_clock_core_} {}
14};
15
16} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/errors.h b/src/core/hle/service/time/errors.h
deleted file mode 100644
index 6655d30e1..000000000
--- a/src/core/hle/service/time/errors.h
+++ /dev/null
@@ -1,21 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::Time {
9
10constexpr Result ERROR_PERMISSION_DENIED{ErrorModule::Time, 1};
11constexpr Result ERROR_TIME_MISMATCH{ErrorModule::Time, 102};
12constexpr Result ERROR_UNINITIALIZED_CLOCK{ErrorModule::Time, 103};
13constexpr Result ERROR_TIME_NOT_FOUND{ErrorModule::Time, 200};
14constexpr Result ERROR_OVERFLOW{ErrorModule::Time, 201};
15constexpr Result ERROR_LOCATION_NAME_TOO_LONG{ErrorModule::Time, 801};
16constexpr Result ERROR_OUT_OF_RANGE{ErrorModule::Time, 902};
17constexpr Result ERROR_TIME_ZONE_CONVERSION_FAILED{ErrorModule::Time, 903};
18constexpr Result ERROR_TIME_ZONE_NOT_FOUND{ErrorModule::Time, 989};
19constexpr Result ERROR_NOT_IMPLEMENTED{ErrorModule::Time, 990};
20
21} // namespace Service::Time
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
deleted file mode 100644
index 1639ef2b9..000000000
--- a/src/core/hle/service/time/local_system_clock_context_writer.h
+++ /dev/null
@@ -1,26 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/system_clock_context_update_callback.h"
7#include "core/hle/service/time/time_sharedmemory.h"
8
9namespace Service::Time::Clock {
10
11class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback {
12public:
13 explicit LocalSystemClockContextWriter(SharedMemory& shared_memory_)
14 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
15
16protected:
17 Result Update() override {
18 shared_memory.UpdateLocalSystemClockContext(context);
19 return ResultSuccess;
20 }
21
22private:
23 SharedMemory& shared_memory;
24};
25
26} // namespace Service::Time::Clock
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
deleted file mode 100644
index 655e4c06d..000000000
--- a/src/core/hle/service/time/network_system_clock_context_writer.h
+++ /dev/null
@@ -1,27 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/errors.h"
7#include "core/hle/service/time/system_clock_context_update_callback.h"
8#include "core/hle/service/time/time_sharedmemory.h"
9
10namespace Service::Time::Clock {
11
12class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
13public:
14 explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory_)
15 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
16
17protected:
18 Result Update() override {
19 shared_memory.UpdateNetworkSystemClockContext(context);
20 return ResultSuccess;
21 }
22
23private:
24 SharedMemory& shared_memory;
25};
26
27} // namespace Service::Time::Clock
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
deleted file mode 100644
index ae2ff1bfd..000000000
--- a/src/core/hle/service/time/standard_local_system_clock_core.h
+++ /dev/null
@@ -1,16 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/system_clock_core.h"
7
8namespace Service::Time::Clock {
9
10class StandardLocalSystemClockCore final : public SystemClockCore {
11public:
12 explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core_)
13 : SystemClockCore{steady_clock_core_} {}
14};
15
16} // 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
deleted file mode 100644
index c1ec5252b..000000000
--- a/src/core/hle/service/time/standard_network_system_clock_core.h
+++ /dev/null
@@ -1,45 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/clock_types.h"
7#include "core/hle/service/time/steady_clock_core.h"
8#include "core/hle/service/time/system_clock_core.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::Time::Clock {
15
16class StandardNetworkSystemClockCore final : public SystemClockCore {
17public:
18 explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
19 : SystemClockCore{steady_clock_core_} {}
20
21 void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) {
22 standard_network_clock_sufficient_accuracy = value;
23 }
24
25 bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const {
26 SystemClockContext clock_ctx{};
27 if (GetClockContext(system, clock_ctx) != ResultSuccess) {
28 return {};
29 }
30
31 s64 span{};
32 if (clock_ctx.steady_time_point.GetSpanBetween(
33 GetSteadyClockCore().GetCurrentTimePoint(system), span) != ResultSuccess) {
34 return {};
35 }
36
37 return TimeSpanType{span}.nanoseconds <
38 standard_network_clock_sufficient_accuracy.nanoseconds;
39 }
40
41private:
42 TimeSpanType standard_network_clock_sufficient_accuracy{};
43};
44
45} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp
deleted file mode 100644
index 5627b7003..000000000
--- a/src/core/hle/service/time/standard_steady_clock_core.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/core_timing.h"
6#include "core/hardware_properties.h"
7#include "core/hle/service/time/standard_steady_clock_core.h"
8
9namespace Service::Time::Clock {
10
11TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
12 const TimeSpanType ticks_time_span{
13 TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())};
14 TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
15
16 if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
17 raw_time_point.nanoseconds = cached_raw_time_point.nanoseconds;
18 }
19
20 cached_raw_time_point = raw_time_point;
21 return raw_time_point;
22}
23
24} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_steady_clock_core.h b/src/core/hle/service/time/standard_steady_clock_core.h
deleted file mode 100644
index 036463b87..000000000
--- a/src/core/hle/service/time/standard_steady_clock_core.h
+++ /dev/null
@@ -1,41 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/clock_types.h"
7#include "core/hle/service/time/steady_clock_core.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Time::Clock {
14
15class StandardSteadyClockCore final : public SteadyClockCore {
16public:
17 SteadyClockTimePoint GetTimePoint(Core::System& system) override {
18 return {GetCurrentRawTimePoint(system).ToSeconds(), GetClockSourceId()};
19 }
20
21 TimeSpanType GetInternalOffset() const override {
22 return internal_offset;
23 }
24
25 void SetInternalOffset(TimeSpanType value) override {
26 internal_offset = value;
27 }
28
29 TimeSpanType GetCurrentRawTimePoint(Core::System& system) override;
30
31 void SetSetupValue(TimeSpanType value) {
32 setup_value = value;
33 }
34
35private:
36 TimeSpanType setup_value{};
37 TimeSpanType internal_offset{};
38 TimeSpanType cached_raw_time_point{};
39};
40
41} // namespace Service::Time::Clock
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
deleted file mode 100644
index b033757ed..000000000
--- a/src/core/hle/service/time/standard_user_system_clock_core.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/assert.h"
5#include "core/core.h"
6#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/time/standard_local_system_clock_core.h"
8#include "core/hle/service/time/standard_network_system_clock_core.h"
9#include "core/hle/service/time/standard_user_system_clock_core.h"
10
11namespace Service::Time::Clock {
12
13StandardUserSystemClockCore::StandardUserSystemClockCore(
14 StandardLocalSystemClockCore& local_system_clock_core_,
15 StandardNetworkSystemClockCore& network_system_clock_core_, Core::System& system_)
16 : SystemClockCore(local_system_clock_core_.GetSteadyClockCore()),
17 local_system_clock_core{local_system_clock_core_},
18 network_system_clock_core{network_system_clock_core_},
19 auto_correction_time{SteadyClockTimePoint::GetRandom()}, service_context{
20 system_,
21 "StandardUserSystemClockCore"} {
22 auto_correction_event =
23 service_context.CreateEvent("StandardUserSystemClockCore:AutoCorrectionEvent");
24}
25
26StandardUserSystemClockCore::~StandardUserSystemClockCore() {
27 service_context.CloseEvent(auto_correction_event);
28}
29
30Result StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system,
31 bool value) {
32 if (const Result result{ApplyAutomaticCorrection(system, value)}; result != ResultSuccess) {
33 return result;
34 }
35
36 auto_correction_enabled = value;
37
38 return ResultSuccess;
39}
40
41Result StandardUserSystemClockCore::GetClockContext(Core::System& system,
42 SystemClockContext& ctx) const {
43 if (const Result result{ApplyAutomaticCorrection(system, false)}; result != ResultSuccess) {
44 return result;
45 }
46
47 return local_system_clock_core.GetClockContext(system, ctx);
48}
49
50Result StandardUserSystemClockCore::Flush(const SystemClockContext&) {
51 UNIMPLEMENTED();
52 return ERROR_NOT_IMPLEMENTED;
53}
54
55Result StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) {
56 UNIMPLEMENTED();
57 return ERROR_NOT_IMPLEMENTED;
58}
59
60Result StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& system,
61 bool value) const {
62 if (auto_correction_enabled == value) {
63 return ResultSuccess;
64 }
65
66 if (!network_system_clock_core.IsClockSetup(system)) {
67 return ERROR_UNINITIALIZED_CLOCK;
68 }
69
70 SystemClockContext ctx{};
71 if (const Result result{network_system_clock_core.GetClockContext(system, ctx)};
72 result != ResultSuccess) {
73 return result;
74 }
75
76 local_system_clock_core.SetClockContext(ctx);
77
78 return ResultSuccess;
79}
80
81} // namespace Service::Time::Clock
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
deleted file mode 100644
index ee6e29487..000000000
--- a/src/core/hle/service/time/standard_user_system_clock_core.h
+++ /dev/null
@@ -1,63 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/time/clock_types.h"
8#include "core/hle/service/time/system_clock_core.h"
9
10namespace Core {
11class System;
12}
13
14namespace Kernel {
15class KEvent;
16}
17
18namespace Service::Time::Clock {
19
20class StandardLocalSystemClockCore;
21class StandardNetworkSystemClockCore;
22
23class StandardUserSystemClockCore final : public SystemClockCore {
24public:
25 StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core_,
26 StandardNetworkSystemClockCore& network_system_clock_core_,
27 Core::System& system_);
28
29 ~StandardUserSystemClockCore() override;
30
31 Result SetAutomaticCorrectionEnabled(Core::System& system, bool value);
32
33 Result GetClockContext(Core::System& system, SystemClockContext& ctx) const override;
34
35 bool IsAutomaticCorrectionEnabled() const {
36 return auto_correction_enabled;
37 }
38
39 void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steady_clock_time_point) {
40 auto_correction_time = steady_clock_time_point;
41 }
42
43protected:
44 Result Flush(const SystemClockContext&) override;
45
46 Result SetClockContext(const SystemClockContext&) override;
47
48 Result ApplyAutomaticCorrection(Core::System& system, bool value) const;
49
50 const SteadyClockTimePoint& GetAutomaticCorrectionUpdatedTime() const {
51 return auto_correction_time;
52 }
53
54private:
55 StandardLocalSystemClockCore& local_system_clock_core;
56 StandardNetworkSystemClockCore& network_system_clock_core;
57 bool auto_correction_enabled{};
58 SteadyClockTimePoint auto_correction_time;
59 KernelHelpers::ServiceContext service_context;
60 Kernel::KEvent* auto_correction_event;
61};
62
63} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/steady_clock_core.h b/src/core/hle/service/time/steady_clock_core.h
deleted file mode 100644
index 2867c351c..000000000
--- a/src/core/hle/service/time/steady_clock_core.h
+++ /dev/null
@@ -1,55 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/uuid.h"
7#include "core/hle/service/time/clock_types.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Time::Clock {
14
15class SteadyClockCore {
16public:
17 SteadyClockCore() = default;
18 virtual ~SteadyClockCore() = default;
19
20 const Common::UUID& GetClockSourceId() const {
21 return clock_source_id;
22 }
23
24 void SetClockSourceId(const Common::UUID& value) {
25 clock_source_id = value;
26 }
27
28 virtual TimeSpanType GetInternalOffset() const = 0;
29
30 virtual void SetInternalOffset(TimeSpanType internal_offset) = 0;
31
32 virtual SteadyClockTimePoint GetTimePoint(Core::System& system) = 0;
33
34 virtual TimeSpanType GetCurrentRawTimePoint(Core::System& system) = 0;
35
36 SteadyClockTimePoint GetCurrentTimePoint(Core::System& system) {
37 SteadyClockTimePoint result{GetTimePoint(system)};
38 result.time_point += GetInternalOffset().ToSeconds();
39 return result;
40 }
41
42 bool IsInitialized() const {
43 return is_initialized;
44 }
45
46 void MarkAsInitialized() {
47 is_initialized = true;
48 }
49
50private:
51 Common::UUID clock_source_id{Common::UUID::MakeRandom()};
52 bool is_initialized{};
53};
54
55} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.cpp b/src/core/hle/service/time/system_clock_context_update_callback.cpp
deleted file mode 100644
index cafc04ee7..000000000
--- a/src/core/hle/service/time/system_clock_context_update_callback.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_event.h"
5#include "core/hle/service/time/errors.h"
6#include "core/hle/service/time/system_clock_context_update_callback.h"
7
8namespace Service::Time::Clock {
9
10SystemClockContextUpdateCallback::SystemClockContextUpdateCallback() = default;
11SystemClockContextUpdateCallback::~SystemClockContextUpdateCallback() = default;
12
13bool SystemClockContextUpdateCallback::NeedUpdate(const SystemClockContext& value) const {
14 if (has_context) {
15 return context.offset != value.offset ||
16 context.steady_time_point.clock_source_id != value.steady_time_point.clock_source_id;
17 }
18
19 return true;
20}
21
22void SystemClockContextUpdateCallback::RegisterOperationEvent(
23 std::shared_ptr<Kernel::KEvent>&& event) {
24 operation_event_list.emplace_back(std::move(event));
25}
26
27void SystemClockContextUpdateCallback::BroadcastOperationEvent() {
28 for (const auto& event : operation_event_list) {
29 event->Signal();
30 }
31}
32
33Result SystemClockContextUpdateCallback::Update(const SystemClockContext& value) {
34 Result result{ResultSuccess};
35
36 if (NeedUpdate(value)) {
37 context = value;
38 has_context = true;
39
40 result = Update();
41
42 if (result == ResultSuccess) {
43 BroadcastOperationEvent();
44 }
45 }
46
47 return result;
48}
49
50Result SystemClockContextUpdateCallback::Update() {
51 return ResultSuccess;
52}
53
54} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.h b/src/core/hle/service/time/system_clock_context_update_callback.h
deleted file mode 100644
index bf657acd9..000000000
--- a/src/core/hle/service/time/system_clock_context_update_callback.h
+++ /dev/null
@@ -1,43 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <vector>
8
9#include "core/hle/service/time/clock_types.h"
10
11namespace Kernel {
12class KEvent;
13}
14
15namespace Service::Time::Clock {
16
17// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
18// This code was released under public domain.
19
20class SystemClockContextUpdateCallback {
21public:
22 SystemClockContextUpdateCallback();
23 virtual ~SystemClockContextUpdateCallback();
24
25 bool NeedUpdate(const SystemClockContext& value) const;
26
27 void RegisterOperationEvent(std::shared_ptr<Kernel::KEvent>&& event);
28
29 void BroadcastOperationEvent();
30
31 Result Update(const SystemClockContext& value);
32
33protected:
34 virtual Result Update();
35
36 SystemClockContext context{};
37
38private:
39 bool has_context{};
40 std::vector<std::shared_ptr<Kernel::KEvent>> operation_event_list;
41};
42
43} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_core.cpp b/src/core/hle/service/time/system_clock_core.cpp
deleted file mode 100644
index da078241f..000000000
--- a/src/core/hle/service/time/system_clock_core.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/time/steady_clock_core.h"
5#include "core/hle/service/time/system_clock_context_update_callback.h"
6#include "core/hle/service/time/system_clock_core.h"
7
8namespace Service::Time::Clock {
9
10SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core_)
11 : steady_clock_core{steady_clock_core_} {
12 context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId();
13}
14
15SystemClockCore::~SystemClockCore() = default;
16
17Result SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const {
18 posix_time = 0;
19
20 const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
21
22 SystemClockContext clock_context{};
23 if (const Result result{GetClockContext(system, clock_context)}; result != ResultSuccess) {
24 return result;
25 }
26
27 if (current_time_point.clock_source_id != clock_context.steady_time_point.clock_source_id) {
28 return ERROR_TIME_MISMATCH;
29 }
30
31 posix_time = clock_context.offset + current_time_point.time_point;
32
33 return ResultSuccess;
34}
35
36Result SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time) {
37 const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
38 const SystemClockContext clock_context{posix_time - current_time_point.time_point,
39 current_time_point};
40
41 if (const Result result{SetClockContext(clock_context)}; result != ResultSuccess) {
42 return result;
43 }
44 return Flush(clock_context);
45}
46
47Result SystemClockCore::Flush(const SystemClockContext& clock_context) {
48 if (!system_clock_context_update_callback) {
49 return ResultSuccess;
50 }
51 return system_clock_context_update_callback->Update(clock_context);
52}
53
54Result SystemClockCore::SetSystemClockContext(const SystemClockContext& clock_context) {
55 if (const Result result{SetClockContext(clock_context)}; result != ResultSuccess) {
56 return result;
57 }
58 return Flush(clock_context);
59}
60
61bool SystemClockCore::IsClockSetup(Core::System& system) const {
62 SystemClockContext value{};
63 if (GetClockContext(system, value) == ResultSuccess) {
64 const SteadyClockTimePoint steady_clock_time_point{
65 steady_clock_core.GetCurrentTimePoint(system)};
66 return steady_clock_time_point.clock_source_id == value.steady_time_point.clock_source_id;
67 }
68 return {};
69}
70
71} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h
deleted file mode 100644
index 8cb34126f..000000000
--- a/src/core/hle/service/time/system_clock_core.h
+++ /dev/null
@@ -1,72 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7
8#include "common/common_types.h"
9#include "core/hle/service/time/clock_types.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::Time::Clock {
16
17class SteadyClockCore;
18class SystemClockContextUpdateCallback;
19
20// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
21// This code was released under public domain.
22
23class SystemClockCore {
24public:
25 explicit SystemClockCore(SteadyClockCore& steady_clock_core_);
26 virtual ~SystemClockCore();
27
28 SteadyClockCore& GetSteadyClockCore() const {
29 return steady_clock_core;
30 }
31
32 Result GetCurrentTime(Core::System& system, s64& posix_time) const;
33
34 Result SetCurrentTime(Core::System& system, s64 posix_time);
35
36 virtual Result GetClockContext([[maybe_unused]] Core::System& system,
37 SystemClockContext& value) const {
38 value = context;
39 return ResultSuccess;
40 }
41
42 virtual Result SetClockContext(const SystemClockContext& value) {
43 context = value;
44 return ResultSuccess;
45 }
46
47 virtual Result Flush(const SystemClockContext& clock_context);
48
49 void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) {
50 system_clock_context_update_callback = std::move(callback);
51 }
52
53 Result SetSystemClockContext(const SystemClockContext& context);
54
55 bool IsInitialized() const {
56 return is_initialized;
57 }
58
59 void MarkAsInitialized() {
60 is_initialized = true;
61 }
62
63 bool IsClockSetup(Core::System& system) const;
64
65private:
66 SteadyClockCore& steady_clock_core;
67 SystemClockContext context{};
68 bool is_initialized{};
69 std::shared_ptr<SystemClockContextUpdateCallback> system_clock_context_update_callback;
70};
71
72} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
deleted file mode 100644
index 0d9fb3143..000000000
--- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/core_timing.h"
6#include "core/hardware_properties.h"
7#include "core/hle/service/time/tick_based_steady_clock_core.h"
8
9namespace Service::Time::Clock {
10
11SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
12 const TimeSpanType ticks_time_span{
13 TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())};
14
15 return {ticks_time_span.ToSeconds(), GetClockSourceId()};
16}
17
18TimeSpanType TickBasedSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
19 return TimeSpanType::FromSeconds(GetTimePoint(system).time_point);
20}
21
22} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.h b/src/core/hle/service/time/tick_based_steady_clock_core.h
deleted file mode 100644
index 491185dc3..000000000
--- a/src/core/hle/service/time/tick_based_steady_clock_core.h
+++ /dev/null
@@ -1,28 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/clock_types.h"
7#include "core/hle/service/time/steady_clock_core.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Time::Clock {
14
15class TickBasedSteadyClockCore final : public SteadyClockCore {
16public:
17 TimeSpanType GetInternalOffset() const override {
18 return {};
19 }
20
21 void SetInternalOffset(TimeSpanType internal_offset) override {}
22
23 SteadyClockTimePoint GetTimePoint(Core::System& system) override;
24
25 TimeSpanType GetCurrentRawTimePoint(Core::System& system) override;
26};
27
28} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
deleted file mode 100644
index 7197ca30f..000000000
--- a/src/core/hle/service/time/time.cpp
+++ /dev/null
@@ -1,412 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/hardware_properties.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/server_manager.h"
11#include "core/hle/service/time/time.h"
12#include "core/hle/service/time/time_interface.h"
13#include "core/hle/service/time/time_manager.h"
14#include "core/hle/service/time/time_sharedmemory.h"
15#include "core/hle/service/time/time_zone_service.h"
16
17namespace Service::Time {
18
19class ISystemClock final : public ServiceFramework<ISystemClock> {
20public:
21 explicit ISystemClock(Clock::SystemClockCore& clock_core_, Core::System& system_)
22 : ServiceFramework{system_, "ISystemClock"}, clock_core{clock_core_} {
23 // clang-format off
24 static const FunctionInfo functions[] = {
25 {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
26 {1, nullptr, "SetCurrentTime"},
27 {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
28 {3, nullptr, "SetSystemClockContext"},
29 {4, nullptr, "GetOperationEventReadableHandle"},
30 };
31 // clang-format on
32
33 RegisterHandlers(functions);
34 }
35
36private:
37 void GetCurrentTime(HLERequestContext& ctx) {
38 LOG_DEBUG(Service_Time, "called");
39
40 if (!clock_core.IsInitialized()) {
41 IPC::ResponseBuilder rb{ctx, 2};
42 rb.Push(ERROR_UNINITIALIZED_CLOCK);
43 return;
44 }
45
46 s64 posix_time{};
47 if (const Result result{clock_core.GetCurrentTime(system, posix_time)}; result.IsError()) {
48 IPC::ResponseBuilder rb{ctx, 2};
49 rb.Push(result);
50 return;
51 }
52
53 IPC::ResponseBuilder rb{ctx, 4};
54 rb.Push(ResultSuccess);
55 rb.Push<s64>(posix_time);
56 }
57
58 void GetSystemClockContext(HLERequestContext& ctx) {
59 LOG_DEBUG(Service_Time, "called");
60
61 if (!clock_core.IsInitialized()) {
62 IPC::ResponseBuilder rb{ctx, 2};
63 rb.Push(ERROR_UNINITIALIZED_CLOCK);
64 return;
65 }
66
67 Clock::SystemClockContext system_clock_context{};
68 if (const Result result{clock_core.GetClockContext(system, system_clock_context)};
69 result.IsError()) {
70 IPC::ResponseBuilder rb{ctx, 2};
71 rb.Push(result);
72 return;
73 }
74
75 IPC::ResponseBuilder rb{ctx, sizeof(Clock::SystemClockContext) / 4 + 2};
76 rb.Push(ResultSuccess);
77 rb.PushRaw(system_clock_context);
78 }
79
80 Clock::SystemClockCore& clock_core;
81};
82
83class ISteadyClock final : public ServiceFramework<ISteadyClock> {
84public:
85 explicit ISteadyClock(Clock::SteadyClockCore& clock_core_, Core::System& system_)
86 : ServiceFramework{system_, "ISteadyClock"}, clock_core{clock_core_} {
87 static const FunctionInfo functions[] = {
88 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
89 {2, nullptr, "GetTestOffset"},
90 {3, nullptr, "SetTestOffset"},
91 {100, nullptr, "GetRtcValue"},
92 {101, nullptr, "IsRtcResetDetected"},
93 {102, nullptr, "GetSetupResultValue"},
94 {200, nullptr, "GetInternalOffset"},
95 {201, nullptr, "SetInternalOffset"},
96 };
97 RegisterHandlers(functions);
98 }
99
100private:
101 void GetCurrentTimePoint(HLERequestContext& ctx) {
102 LOG_DEBUG(Service_Time, "called");
103
104 if (!clock_core.IsInitialized()) {
105 IPC::ResponseBuilder rb{ctx, 2};
106 rb.Push(ERROR_UNINITIALIZED_CLOCK);
107 return;
108 }
109
110 const Clock::SteadyClockTimePoint time_point{clock_core.GetCurrentTimePoint(system)};
111 IPC::ResponseBuilder rb{ctx, (sizeof(Clock::SteadyClockTimePoint) / 4) + 2};
112 rb.Push(ResultSuccess);
113 rb.PushRaw(time_point);
114 }
115
116 Clock::SteadyClockCore& clock_core;
117};
118
119Result Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
120 Kernel::KThread* thread, Clock::SystemClockContext user_context,
121 Clock::SystemClockContext network_context, Clock::TimeType type,
122 Clock::ClockSnapshot& clock_snapshot) {
123
124 auto& time_manager{system.GetTimeManager()};
125
126 clock_snapshot.steady_clock_time_point =
127 time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system);
128 clock_snapshot.is_automatic_correction_enabled =
129 time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
130 clock_snapshot.type = type;
131
132 if (const Result result{
133 time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName(
134 clock_snapshot.location_name)};
135 result != ResultSuccess) {
136 return result;
137 }
138
139 clock_snapshot.user_context = user_context;
140
141 if (const Result result{Clock::ClockSnapshot::GetCurrentTime(
142 clock_snapshot.user_time, clock_snapshot.steady_clock_time_point,
143 clock_snapshot.user_context)};
144 result != ResultSuccess) {
145 return result;
146 }
147
148 TimeZone::CalendarInfo userCalendarInfo{};
149 if (const Result result{
150 time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
151 clock_snapshot.user_time, userCalendarInfo)};
152 result != ResultSuccess) {
153 return result;
154 }
155
156 clock_snapshot.user_calendar_time = userCalendarInfo.time;
157 clock_snapshot.user_calendar_additional_time = userCalendarInfo.additional_info;
158
159 clock_snapshot.network_context = network_context;
160
161 if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time,
162 clock_snapshot.steady_clock_time_point,
163 clock_snapshot.network_context) != ResultSuccess) {
164 clock_snapshot.network_time = 0;
165 }
166
167 TimeZone::CalendarInfo networkCalendarInfo{};
168 if (const Result result{
169 time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
170 clock_snapshot.network_time, networkCalendarInfo)};
171 result != ResultSuccess) {
172 return result;
173 }
174
175 clock_snapshot.network_calendar_time = networkCalendarInfo.time;
176 clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additional_info;
177
178 return ResultSuccess;
179}
180
181void Module::Interface::GetStandardUserSystemClock(HLERequestContext& ctx) {
182 LOG_DEBUG(Service_Time, "called");
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(ResultSuccess);
185 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(),
186 system);
187}
188
189void Module::Interface::GetStandardNetworkSystemClock(HLERequestContext& ctx) {
190 LOG_DEBUG(Service_Time, "called");
191 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
192 rb.Push(ResultSuccess);
193 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(),
194 system);
195}
196
197void Module::Interface::GetStandardSteadyClock(HLERequestContext& ctx) {
198 LOG_DEBUG(Service_Time, "called");
199 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
200 rb.Push(ResultSuccess);
201 rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system);
202}
203
204void Module::Interface::GetTimeZoneService(HLERequestContext& ctx) {
205 LOG_DEBUG(Service_Time, "called");
206 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
207 rb.Push(ResultSuccess);
208 rb.PushIpcInterface<ITimeZoneService>(system,
209 system.GetTimeManager().GetTimeZoneContentManager());
210}
211
212void Module::Interface::GetStandardLocalSystemClock(HLERequestContext& ctx) {
213 LOG_DEBUG(Service_Time, "called");
214 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
215 rb.Push(ResultSuccess);
216 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(),
217 system);
218}
219
220void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
221 LOG_DEBUG(Service_Time, "called");
222 auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()};
223 IPC::ResponseBuilder rb{ctx, 3};
224 rb.Push(ResultSuccess);
225 rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
226}
227
228void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
229 LOG_DEBUG(Service_Time, "called");
230
231 auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()};
232 if (!steady_clock_core.IsInitialized()) {
233 IPC::ResponseBuilder rb{ctx, 2};
234 rb.Push(ERROR_UNINITIALIZED_CLOCK);
235 return;
236 }
237
238 IPC::RequestParser rp{ctx};
239 const auto context{rp.PopRaw<Clock::SystemClockContext>()};
240 const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
241
242 if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
243 const auto ticks{Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(
244 system.CoreTiming().GetClockTicks())};
245 const s64 base_time_point{context.offset + current_time_point.time_point -
246 ticks.ToSeconds()};
247 IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
248 rb.Push(ResultSuccess);
249 rb.PushRaw(base_time_point);
250 return;
251 }
252
253 IPC::ResponseBuilder rb{ctx, 2};
254 rb.Push(ERROR_TIME_MISMATCH);
255}
256
257void Module::Interface::GetClockSnapshot(HLERequestContext& ctx) {
258 IPC::RequestParser rp{ctx};
259 const auto type{rp.PopEnum<Clock::TimeType>()};
260
261 LOG_DEBUG(Service_Time, "called, type={}", type);
262
263 Clock::SystemClockContext user_context{};
264 if (const Result result{
265 system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system,
266 user_context)};
267 result.IsError()) {
268 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(result);
270 return;
271 }
272
273 Clock::SystemClockContext network_context{};
274 if (const Result result{
275 system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
276 system, network_context)};
277 result.IsError()) {
278 IPC::ResponseBuilder rb{ctx, 2};
279 rb.Push(result);
280 return;
281 }
282
283 Clock::ClockSnapshot clock_snapshot{};
284 if (const Result result{GetClockSnapshotFromSystemClockContextInternal(
285 &ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
286 result.IsError()) {
287 IPC::ResponseBuilder rb{ctx, 2};
288 rb.Push(result);
289 return;
290 }
291
292 ctx.WriteBuffer(clock_snapshot);
293
294 IPC::ResponseBuilder rb{ctx, 2};
295 rb.Push(ResultSuccess);
296}
297
298void Module::Interface::GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
299 IPC::RequestParser rp{ctx};
300 const auto type{rp.PopEnum<Clock::TimeType>()};
301
302 rp.Skip(1, false);
303
304 const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()};
305 const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()};
306
307 LOG_DEBUG(Service_Time, "called, type={}", type);
308
309 Clock::ClockSnapshot clock_snapshot{};
310 if (const Result result{GetClockSnapshotFromSystemClockContextInternal(
311 &ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
312 result != ResultSuccess) {
313 IPC::ResponseBuilder rb{ctx, 2};
314 rb.Push(result);
315 return;
316 }
317
318 ctx.WriteBuffer(clock_snapshot);
319
320 IPC::ResponseBuilder rb{ctx, 2};
321 rb.Push(ResultSuccess);
322}
323
324void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx) {
325 LOG_DEBUG(Service_Time, "called");
326
327 Clock::ClockSnapshot snapshot_a;
328 Clock::ClockSnapshot snapshot_b;
329
330 const auto snapshot_a_data = ctx.ReadBuffer(0);
331 const auto snapshot_b_data = ctx.ReadBuffer(1);
332
333 std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot));
334 std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot));
335
336 auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset -
337 snapshot_a.user_context.offset)};
338
339 if ((snapshot_b.user_context.steady_time_point.clock_source_id !=
340 snapshot_a.user_context.steady_time_point.clock_source_id) ||
341 (snapshot_b.is_automatic_correction_enabled &&
342 snapshot_a.is_automatic_correction_enabled)) {
343 time_span_type.nanoseconds = 0;
344 }
345
346 IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
347 rb.Push(ResultSuccess);
348 rb.PushRaw(time_span_type.nanoseconds);
349}
350
351void Module::Interface::CalculateSpanBetween(HLERequestContext& ctx) {
352 LOG_DEBUG(Service_Time, "called");
353
354 Clock::ClockSnapshot snapshot_a;
355 Clock::ClockSnapshot snapshot_b;
356
357 const auto snapshot_a_data = ctx.ReadBuffer(0);
358 const auto snapshot_b_data = ctx.ReadBuffer(1);
359
360 std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot));
361 std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot));
362
363 Clock::TimeSpanType time_span_type{};
364 s64 span{};
365
366 if (const Result result{snapshot_a.steady_clock_time_point.GetSpanBetween(
367 snapshot_b.steady_clock_time_point, span)};
368 result != ResultSuccess) {
369 if (snapshot_a.network_time && snapshot_b.network_time) {
370 time_span_type =
371 Clock::TimeSpanType::FromSeconds(snapshot_b.network_time - snapshot_a.network_time);
372 } else {
373 IPC::ResponseBuilder rb{ctx, 2};
374 rb.Push(ERROR_TIME_NOT_FOUND);
375 return;
376 }
377 } else {
378 time_span_type = Clock::TimeSpanType::FromSeconds(span);
379 }
380
381 IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
382 rb.Push(ResultSuccess);
383 rb.PushRaw(time_span_type.nanoseconds);
384}
385
386void Module::Interface::GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
387 LOG_DEBUG(Service_Time, "called");
388 IPC::ResponseBuilder rb{ctx, 2, 1};
389 rb.Push(ResultSuccess);
390 rb.PushCopyObjects(&system.Kernel().GetTimeSharedMem());
391}
392
393Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
394 const char* name)
395 : ServiceFramework{system_, name}, module{std::move(module_)} {}
396
397Module::Interface::~Interface() = default;
398
399void LoopProcess(Core::System& system) {
400 auto server_manager = std::make_unique<ServerManager>(system);
401 auto module{std::make_shared<Module>()};
402
403 server_manager->RegisterNamedService("time:a",
404 std::make_shared<Time>(module, system, "time:a"));
405 server_manager->RegisterNamedService("time:s",
406 std::make_shared<Time>(module, system, "time:s"));
407 server_manager->RegisterNamedService("time:u",
408 std::make_shared<Time>(module, system, "time:u"));
409 ServerManager::RunServer(std::move(server_manager));
410}
411
412} // namespace Service::Time
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
deleted file mode 100644
index b2d754ef3..000000000
--- a/src/core/hle/service/time/time.h
+++ /dev/null
@@ -1,51 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7#include "core/hle/service/time/clock_types.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Time {
14
15class Module final {
16public:
17 Module() = default;
18
19 class Interface : public ServiceFramework<Interface> {
20 public:
21 explicit Interface(std::shared_ptr<Module> module_, Core::System& system_,
22 const char* name);
23 ~Interface() override;
24
25 void GetStandardUserSystemClock(HLERequestContext& ctx);
26 void GetStandardNetworkSystemClock(HLERequestContext& ctx);
27 void GetStandardSteadyClock(HLERequestContext& ctx);
28 void GetTimeZoneService(HLERequestContext& ctx);
29 void GetStandardLocalSystemClock(HLERequestContext& ctx);
30 void IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
31 void CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
32 void GetClockSnapshot(HLERequestContext& ctx);
33 void GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
34 void CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
35 void CalculateSpanBetween(HLERequestContext& ctx);
36 void GetSharedMemoryNativeHandle(HLERequestContext& ctx);
37
38 private:
39 Result GetClockSnapshotFromSystemClockContextInternal(
40 Kernel::KThread* thread, Clock::SystemClockContext user_context,
41 Clock::SystemClockContext network_context, Clock::TimeType type,
42 Clock::ClockSnapshot& cloc_snapshot);
43
44 protected:
45 std::shared_ptr<Module> module;
46 };
47};
48
49void LoopProcess(Core::System& system);
50
51} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_interface.cpp b/src/core/hle/service/time/time_interface.cpp
deleted file mode 100644
index 0c53e98ee..000000000
--- a/src/core/hle/service/time/time_interface.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/time/time_interface.h"
5
6namespace Service::Time {
7
8Time::Time(std::shared_ptr<Module> module_, Core::System& system_, const char* name_)
9 : Interface{std::move(module_), system_, name_} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
13 {1, &Time::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
14 {2, &Time::GetStandardSteadyClock, "GetStandardSteadyClock"},
15 {3, &Time::GetTimeZoneService, "GetTimeZoneService"},
16 {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
17 {5, nullptr, "GetEphemeralNetworkSystemClock"},
18 {20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
19 {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"},
20 {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
21 {50, nullptr, "SetStandardSteadyClockInternalOffset"},
22 {51, nullptr, "GetStandardSteadyClockRtcValue"},
23 {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
24 {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
25 {102, nullptr, "GetStandardUserSystemClockInitialYear"},
26 {200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
27 {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
28 {300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
29 {400, &Time::GetClockSnapshot, "GetClockSnapshot"},
30 {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
31 {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
32 {501, &Time::CalculateSpanBetween, "CalculateSpanBetween"},
33 };
34 // clang-format on
35
36 RegisterHandlers(functions);
37}
38
39Time::~Time() = default;
40
41} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_interface.h b/src/core/hle/service/time/time_interface.h
deleted file mode 100644
index ceeb0e5ef..000000000
--- a/src/core/hle/service/time/time_interface.h
+++ /dev/null
@@ -1,20 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/time/time.h"
7
8namespace Core {
9class System;
10}
11
12namespace Service::Time {
13
14class Time final : public Module::Interface {
15public:
16 explicit Time(std::shared_ptr<Module> time, Core::System& system_, const char* name_);
17 ~Time() override;
18};
19
20} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
deleted file mode 100644
index fa0fd0531..000000000
--- a/src/core/hle/service/time/time_manager.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5#include <ctime>
6
7#include "common/settings.h"
8#include "common/time_zone.h"
9#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h"
10#include "core/hle/service/time/ephemeral_network_system_clock_core.h"
11#include "core/hle/service/time/local_system_clock_context_writer.h"
12#include "core/hle/service/time/network_system_clock_context_writer.h"
13#include "core/hle/service/time/tick_based_steady_clock_core.h"
14#include "core/hle/service/time/time_manager.h"
15
16namespace Service::Time {
17namespace {
18constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL};
19
20s64 GetSecondsSinceEpoch() {
21 const auto time_since_epoch = std::chrono::system_clock::now().time_since_epoch();
22 return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() +
23 Settings::values.custom_rtc_differential;
24}
25} // Anonymous namespace
26
27struct TimeManager::Impl final {
28 explicit Impl(Core::System& system)
29 : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
30 standard_network_system_clock_core{standard_steady_clock_core},
31 standard_user_system_clock_core{standard_local_system_clock_core,
32 standard_network_system_clock_core, system},
33 ephemeral_network_system_clock_core{tick_based_steady_clock_core},
34 local_system_clock_context_writer{
35 std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
36 network_system_clock_context_writer{
37 std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
38 ephemeral_network_system_clock_context_writer{
39 std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
40 time_zone_content_manager{system} {
41
42 const auto system_time{Clock::TimeSpanType::FromSeconds(GetSecondsSinceEpoch())};
43 SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {});
44 SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
45
46 Clock::SystemClockContext clock_context{};
47 standard_local_system_clock_core.GetClockContext(system, clock_context);
48
49 SetupStandardNetworkSystemClock(clock_context, standard_network_clock_accuracy);
50 SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
51 SetupEphemeralNetworkSystemClock();
52 }
53
54 ~Impl() = default;
55
56 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
57 return standard_steady_clock_core;
58 }
59
60 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
61 return standard_steady_clock_core;
62 }
63
64 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
65 return standard_local_system_clock_core;
66 }
67
68 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
69 return standard_local_system_clock_core;
70 }
71
72 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
73 return standard_network_system_clock_core;
74 }
75
76 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
77 return standard_network_system_clock_core;
78 }
79
80 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
81 return standard_user_system_clock_core;
82 }
83
84 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
85 return standard_user_system_clock_core;
86 }
87
88 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
89 return time_zone_content_manager;
90 }
91
92 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
93 return time_zone_content_manager;
94 }
95
96 SharedMemory& GetSharedMemory() {
97 return shared_memory;
98 }
99
100 const SharedMemory& GetSharedMemory() const {
101 return shared_memory;
102 }
103
104 void SetupTimeZoneManager(std::string location_name,
105 Clock::SteadyClockTimePoint time_zone_updated_time_point,
106 std::vector<std::string> location_names, u128 time_zone_rule_version,
107 FileSys::VirtualFile& vfs_file) {
108 if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
109 location_name, vfs_file) != ResultSuccess) {
110 ASSERT(false);
111 return;
112 }
113
114 time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
115 time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
116 location_names.size());
117 time_zone_content_manager.GetTimeZoneManager().SetLocationNames(location_names);
118 time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(
119 time_zone_rule_version);
120 time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
121 }
122
123 void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id,
124 Clock::TimeSpanType setup_value,
125 Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
126 standard_steady_clock_core.SetClockSourceId(clock_source_id);
127 standard_steady_clock_core.SetSetupValue(setup_value);
128 standard_steady_clock_core.SetInternalOffset(internal_offset);
129 standard_steady_clock_core.MarkAsInitialized();
130
131 const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system_)};
132 shared_memory.SetupStandardSteadyClock(clock_source_id, current_time_point);
133 }
134
135 void SetupStandardLocalSystemClock(Core::System& system_,
136 Clock::SystemClockContext clock_context, s64 posix_time) {
137 standard_local_system_clock_core.SetUpdateCallbackInstance(
138 local_system_clock_context_writer);
139
140 const auto current_time_point{
141 standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system_)};
142 if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
143 standard_local_system_clock_core.SetSystemClockContext(clock_context);
144 } else {
145 if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) !=
146 ResultSuccess) {
147 ASSERT(false);
148 return;
149 }
150 }
151
152 standard_local_system_clock_core.MarkAsInitialized();
153 }
154
155 void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
156 Clock::TimeSpanType sufficient_accuracy) {
157 standard_network_system_clock_core.SetUpdateCallbackInstance(
158 network_system_clock_context_writer);
159
160 if (standard_network_system_clock_core.SetSystemClockContext(clock_context) !=
161 ResultSuccess) {
162 ASSERT(false);
163 return;
164 }
165
166 standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
167 sufficient_accuracy);
168 standard_network_system_clock_core.MarkAsInitialized();
169 }
170
171 void SetupStandardUserSystemClock(Core::System& system_, bool is_automatic_correction_enabled,
172 Clock::SteadyClockTimePoint steady_clock_time_point) {
173 if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
174 system_, is_automatic_correction_enabled) != ResultSuccess) {
175 ASSERT(false);
176 return;
177 }
178
179 standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
180 standard_user_system_clock_core.MarkAsInitialized();
181 shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
182 }
183
184 void SetupEphemeralNetworkSystemClock() {
185 ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
186 ephemeral_network_system_clock_context_writer);
187 ephemeral_network_system_clock_core.MarkAsInitialized();
188 }
189
190 void UpdateLocalSystemClockTime(Core::System& system_, s64 posix_time) {
191 const auto timespan{Clock::TimeSpanType::FromSeconds(posix_time)};
192 if (GetStandardLocalSystemClockCore()
193 .SetCurrentTime(system_, timespan.ToSeconds())
194 .IsError()) {
195 ASSERT(false);
196 return;
197 }
198 }
199
200 SharedMemory shared_memory;
201
202 Clock::StandardSteadyClockCore standard_steady_clock_core;
203 Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
204 Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
205 Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
206 Clock::StandardUserSystemClockCore standard_user_system_clock_core;
207 Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
208
209 std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
210 std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
211 std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
212 ephemeral_network_system_clock_context_writer;
213
214 TimeZone::TimeZoneContentManager time_zone_content_manager;
215};
216
217TimeManager::TimeManager(Core::System& system_) : system{system_} {}
218
219TimeManager::~TimeManager() = default;
220
221void TimeManager::Initialize() {
222 impl = std::make_unique<Impl>(system);
223
224 // Time zones can only be initialized after impl is valid
225 impl->time_zone_content_manager.Initialize(*this);
226}
227
228Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() {
229 return impl->standard_steady_clock_core;
230}
231
232const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const {
233 return impl->standard_steady_clock_core;
234}
235
236Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() {
237 return impl->standard_local_system_clock_core;
238}
239
240const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const {
241 return impl->standard_local_system_clock_core;
242}
243
244Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() {
245 return impl->standard_network_system_clock_core;
246}
247
248const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore()
249 const {
250 return impl->standard_network_system_clock_core;
251}
252
253Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() {
254 return impl->standard_user_system_clock_core;
255}
256
257const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const {
258 return impl->standard_user_system_clock_core;
259}
260
261TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() {
262 return impl->time_zone_content_manager;
263}
264
265const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const {
266 return impl->time_zone_content_manager;
267}
268
269SharedMemory& TimeManager::GetSharedMemory() {
270 return impl->shared_memory;
271}
272
273const SharedMemory& TimeManager::GetSharedMemory() const {
274 return impl->shared_memory;
275}
276
277void TimeManager::Shutdown() {
278 impl.reset();
279}
280
281void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) {
282 impl->UpdateLocalSystemClockTime(system, posix_time);
283}
284
285void TimeManager::SetupTimeZoneManager(std::string location_name,
286 Clock::SteadyClockTimePoint time_zone_updated_time_point,
287 std::vector<std::string> location_names,
288 u128 time_zone_rule_version,
289 FileSys::VirtualFile& vfs_file) {
290 impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, location_names,
291 time_zone_rule_version, vfs_file);
292}
293} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h
deleted file mode 100644
index 84572dbfa..000000000
--- a/src/core/hle/service/time/time_manager.h
+++ /dev/null
@@ -1,74 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/file_sys/vfs_types.h"
8#include "core/hle/service/time/clock_types.h"
9#include "core/hle/service/time/standard_local_system_clock_core.h"
10#include "core/hle/service/time/standard_network_system_clock_core.h"
11#include "core/hle/service/time/standard_steady_clock_core.h"
12#include "core/hle/service/time/standard_user_system_clock_core.h"
13#include "core/hle/service/time/time_sharedmemory.h"
14#include "core/hle/service/time/time_zone_content_manager.h"
15
16namespace Service::Time {
17
18namespace Clock {
19class EphemeralNetworkSystemClockContextWriter;
20class LocalSystemClockContextWriter;
21class NetworkSystemClockContextWriter;
22} // namespace Clock
23
24// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
25// This code was released under public domain.
26
27class TimeManager final {
28public:
29 explicit TimeManager(Core::System& system_);
30 ~TimeManager();
31
32 void Initialize();
33
34 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore();
35
36 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const;
37
38 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore();
39
40 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const;
41
42 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore();
43
44 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const;
45
46 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore();
47
48 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const;
49
50 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager();
51
52 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const;
53
54 void UpdateLocalSystemClockTime(s64 posix_time);
55
56 SharedMemory& GetSharedMemory();
57
58 const SharedMemory& GetSharedMemory() const;
59
60 void Shutdown();
61
62 void SetupTimeZoneManager(std::string location_name,
63 Clock::SteadyClockTimePoint time_zone_updated_time_point,
64 std::vector<std::string> location_names, u128 time_zone_rule_version,
65 FileSys::VirtualFile& vfs_file);
66
67private:
68 Core::System& system;
69
70 struct Impl;
71 std::unique_ptr<Impl> impl;
72};
73
74} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
deleted file mode 100644
index a00676669..000000000
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/core_timing.h"
6#include "core/hardware_properties.h"
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/service/time/clock_types.h"
9#include "core/hle/service/time/steady_clock_core.h"
10#include "core/hle/service/time/time_sharedmemory.h"
11
12namespace Service::Time {
13
14static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000};
15
16SharedMemory::SharedMemory(Core::System& system_) : system(system_) {
17 std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE);
18}
19
20SharedMemory::~SharedMemory() = default;
21
22void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
23 Clock::TimeSpanType current_time_point) {
24 const Clock::TimeSpanType ticks_time_span{
25 Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(
26 system.CoreTiming().GetClockTicks())};
27 const Clock::SteadyClockContext context{
28 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
29 clock_source_id};
30 StoreToLockFreeAtomicType(&GetFormat()->standard_steady_clock_timepoint, context);
31}
32
33void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
34 // lower and upper are related to the measurement point for the steady time point,
35 // and compare equal on boot
36 const s64 time_point_ns = context.steady_time_point.time_point * 1'000'000'000LL;
37
38 // This adjusts for some sort of time skew
39 // Both 0 on boot
40 const s64 diff_scale = 0;
41 const u32 shift_amount = 0;
42
43 const Clock::ContinuousAdjustmentTimePoint adjustment{
44 .measurement_offset = system.CoreTiming().GetGlobalTimeNs().count(),
45 .diff_scale = diff_scale,
46 .shift_amount = shift_amount,
47 .lower = time_point_ns,
48 .upper = time_point_ns,
49 .clock_source_id = context.steady_time_point.clock_source_id,
50 };
51
52 StoreToLockFreeAtomicType(&GetFormat()->continuous_adjustment_timepoint, adjustment);
53 StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context);
54}
55
56void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
57 StoreToLockFreeAtomicType(&GetFormat()->standard_network_system_clock_context, context);
58}
59
60void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
61 StoreToLockFreeAtomicType(
62 &GetFormat()->is_standard_user_system_clock_automatic_correction_enabled, is_enabled);
63}
64
65SharedMemory::Format* SharedMemory::GetFormat() {
66 return reinterpret_cast<SharedMemory::Format*>(system.Kernel().GetTimeSharedMem().GetPointer());
67}
68
69} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
deleted file mode 100644
index c89be9765..000000000
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ /dev/null
@@ -1,89 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "common/uuid.h"
8#include "core/hle/kernel/k_shared_memory.h"
9#include "core/hle/service/time/clock_types.h"
10
11namespace Service::Time {
12
13// Note: this type is not safe for concurrent writes.
14template <typename T>
15struct LockFreeAtomicType {
16 u32 counter_;
17 std::array<T, 2> value_;
18};
19
20template <typename T>
21static inline void StoreToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) {
22 // Get the current counter.
23 auto counter = p->counter_;
24
25 // Increment the counter.
26 ++counter;
27
28 // Store the updated value.
29 p->value_[counter % 2] = value;
30
31 // Fence memory.
32 std::atomic_thread_fence(std::memory_order_release);
33
34 // Set the updated counter.
35 p->counter_ = counter;
36}
37
38template <typename T>
39static inline T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) {
40 while (true) {
41 // Get the counter.
42 auto counter = p->counter_;
43
44 // Get the value.
45 auto value = p->value_[counter % 2];
46
47 // Fence memory.
48 std::atomic_thread_fence(std::memory_order_acquire);
49
50 // Check that the counter matches.
51 if (counter == p->counter_) {
52 return value;
53 }
54 }
55}
56
57class SharedMemory final {
58public:
59 explicit SharedMemory(Core::System& system_);
60 ~SharedMemory();
61
62 // Shared memory format
63 struct Format {
64 LockFreeAtomicType<Clock::StandardSteadyClockTimePointType> standard_steady_clock_timepoint;
65 LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context;
66 LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context;
67 LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled;
68 LockFreeAtomicType<Clock::ContinuousAdjustmentTimePoint> continuous_adjustment_timepoint;
69 };
70 static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0);
71 static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38);
72 static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80);
73 static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) ==
74 0xc8);
75 static_assert(offsetof(Format, continuous_adjustment_timepoint) == 0xd0);
76 static_assert(sizeof(Format) == 0x148, "Format is an invalid size");
77
78 void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
79 Clock::TimeSpanType current_time_point);
80 void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context);
81 void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context);
82 void SetAutomaticCorrectionEnabled(bool is_enabled);
83 Format* GetFormat();
84
85private:
86 Core::System& system;
87};
88
89} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
deleted file mode 100644
index 1b96de37a..000000000
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5#include <sstream>
6#include <utility>
7
8#include "common/logging/log.h"
9#include "common/settings.h"
10#include "common/time_zone.h"
11#include "core/core.h"
12#include "core/file_sys/content_archive.h"
13#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/registered_cache.h"
15#include "core/file_sys/romfs.h"
16#include "core/file_sys/system_archive/system_archive.h"
17#include "core/file_sys/vfs.h"
18#include "core/file_sys/vfs_types.h"
19#include "core/hle/result.h"
20#include "core/hle/service/filesystem/filesystem.h"
21#include "core/hle/service/time/errors.h"
22#include "core/hle/service/time/time_manager.h"
23#include "core/hle/service/time/time_zone_content_manager.h"
24
25namespace Service::Time::TimeZone {
26
27constexpr u64 time_zone_binary_titleid{0x010000000000080E};
28
29static FileSys::VirtualDir GetTimeZoneBinary(Core::System& system) {
30 const auto* nand{system.GetFileSystemController().GetSystemNANDContents()};
31 const auto nca{nand->GetEntry(time_zone_binary_titleid, FileSys::ContentRecordType::Data)};
32
33 FileSys::VirtualFile romfs;
34 if (nca) {
35 romfs = nca->GetRomFS();
36 }
37
38 if (!romfs) {
39 romfs = FileSys::SystemArchive::SynthesizeSystemArchive(time_zone_binary_titleid);
40 }
41
42 if (!romfs) {
43 LOG_ERROR(Service_Time, "Failed to find or synthesize {:016X!}", time_zone_binary_titleid);
44 return {};
45 }
46
47 return FileSys::ExtractRomFS(romfs);
48}
49
50static std::vector<std::string> BuildLocationNameCache(
51 const FileSys::VirtualDir& time_zone_binary) {
52 if (!time_zone_binary) {
53 LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
54 return {};
55 }
56
57 const FileSys::VirtualFile binary_list{time_zone_binary->GetFile("binaryList.txt")};
58 if (!binary_list) {
59 LOG_ERROR(Service_Time, "{:016X} has no file binaryList.txt!", time_zone_binary_titleid);
60 return {};
61 }
62
63 std::vector<char> raw_data(binary_list->GetSize() + 1);
64 binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize());
65
66 std::stringstream data_stream{raw_data.data()};
67 std::string name;
68 std::vector<std::string> location_name_cache;
69 while (std::getline(data_stream, name)) {
70 name.pop_back(); // Remove carriage return
71 location_name_cache.emplace_back(std::move(name));
72 }
73 return location_name_cache;
74}
75
76TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
77 : system{system_}, time_zone_binary{GetTimeZoneBinary(system)},
78 location_name_cache{BuildLocationNameCache(time_zone_binary)} {}
79
80void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
81 const auto timezone_setting =
82 Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
83
84 if (FileSys::VirtualFile vfs_file;
85 GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) {
86 const auto time_point{
87 time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
88 time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache, {},
89 vfs_file);
90 } else {
91 time_zone_manager.MarkAsInitialized();
92 }
93}
94
95Result TimeZoneContentManager::LoadTimeZoneRule(TimeZoneRule& rules,
96 const std::string& location_name) const {
97 FileSys::VirtualFile vfs_file;
98 if (const Result result{GetTimeZoneInfoFile(location_name, vfs_file)};
99 result != ResultSuccess) {
100 return result;
101 }
102
103 return time_zone_manager.ParseTimeZoneRuleBinary(rules, vfs_file);
104}
105
106bool TimeZoneContentManager::IsLocationNameValid(const std::string& location_name) const {
107 return std::find(location_name_cache.begin(), location_name_cache.end(), location_name) !=
108 location_name_cache.end();
109}
110
111Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_name,
112 FileSys::VirtualFile& vfs_file) const {
113 if (!IsLocationNameValid(location_name)) {
114 return ERROR_TIME_NOT_FOUND;
115 }
116
117 if (!time_zone_binary) {
118 LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
119 return ERROR_TIME_NOT_FOUND;
120 }
121
122 const FileSys::VirtualDir zoneinfo_dir{time_zone_binary->GetSubdirectory("zoneinfo")};
123 if (!zoneinfo_dir) {
124 LOG_ERROR(Service_Time, "{:016X} has no directory zoneinfo!", time_zone_binary_titleid);
125 return ERROR_TIME_NOT_FOUND;
126 }
127
128 vfs_file = zoneinfo_dir->GetFileRelative(location_name);
129 if (!vfs_file) {
130 LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.",
131 time_zone_binary_titleid, location_name);
132 const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()};
133 vfs_file = zoneinfo_dir->GetFile(system_time_zone);
134 }
135
136 if (!vfs_file) {
137 LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
138 time_zone_binary_titleid, location_name);
139 vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone());
140 }
141
142 if (!vfs_file) {
143 LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid,
144 location_name);
145 return ERROR_TIME_NOT_FOUND;
146 }
147
148 return ResultSuccess;
149}
150
151} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h
deleted file mode 100644
index a6f9698bc..000000000
--- a/src/core/hle/service/time/time_zone_content_manager.h
+++ /dev/null
@@ -1,49 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <string>
7#include <vector>
8
9#include "core/file_sys/vfs_types.h"
10#include "core/hle/service/time/time_zone_manager.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::Time {
17class TimeManager;
18}
19
20namespace Service::Time::TimeZone {
21
22class TimeZoneContentManager final {
23public:
24 explicit TimeZoneContentManager(Core::System& system_);
25
26 void Initialize(TimeManager& time_manager);
27
28 TimeZoneManager& GetTimeZoneManager() {
29 return time_zone_manager;
30 }
31
32 const TimeZoneManager& GetTimeZoneManager() const {
33 return time_zone_manager;
34 }
35
36 Result LoadTimeZoneRule(TimeZoneRule& rules, const std::string& location_name) const;
37
38private:
39 bool IsLocationNameValid(const std::string& location_name) const;
40 Result GetTimeZoneInfoFile(const std::string& location_name,
41 FileSys::VirtualFile& vfs_file) const;
42
43 Core::System& system;
44 TimeZoneManager time_zone_manager;
45 const FileSys::VirtualDir time_zone_binary;
46 const std::vector<std::string> location_name_cache;
47};
48
49} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
deleted file mode 100644
index 205371a26..000000000
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ /dev/null
@@ -1,1182 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <climits>
5#include <limits>
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/file_sys/content_archive.h"
10#include "core/file_sys/nca_metadata.h"
11#include "core/file_sys/registered_cache.h"
12#include "core/hle/service/time/time_zone_manager.h"
13#include "core/hle/service/time/time_zone_types.h"
14
15namespace Service::Time::TimeZone {
16
17static constexpr s32 epoch_year{1970};
18static constexpr s32 year_base{1900};
19static constexpr s32 epoch_week_day{4};
20static constexpr s32 seconds_per_minute{60};
21static constexpr s32 minutes_per_hour{60};
22static constexpr s32 hours_per_day{24};
23static constexpr s32 days_per_week{7};
24static constexpr s32 days_per_normal_year{365};
25static constexpr s32 days_per_leap_year{366};
26static constexpr s32 months_per_year{12};
27static constexpr s32 seconds_per_hour{seconds_per_minute * minutes_per_hour};
28static constexpr s32 seconds_per_day{seconds_per_hour * hours_per_day};
29static constexpr s32 years_per_repeat{400};
30static constexpr s64 average_seconds_per_year{31556952};
31static constexpr s64 seconds_per_repeat{years_per_repeat * average_seconds_per_year};
32
33struct Rule {
34 enum class Type : u32 { JulianDay, DayOfYear, MonthNthDayOfWeek };
35 Type rule_type{};
36 s32 day{};
37 s32 week{};
38 s32 month{};
39 s32 transition_time{};
40};
41
42struct CalendarTimeInternal {
43 s64 year{};
44 s8 month{};
45 s8 day{};
46 s8 hour{};
47 s8 minute{};
48 s8 second{};
49 int Compare(const CalendarTimeInternal& other) const {
50 if (year != other.year) {
51 if (year < other.year) {
52 return -1;
53 }
54 return 1;
55 }
56 if (month != other.month) {
57 return month - other.month;
58 }
59 if (day != other.day) {
60 return day - other.day;
61 }
62 if (hour != other.hour) {
63 return hour - other.hour;
64 }
65 if (minute != other.minute) {
66 return minute - other.minute;
67 }
68 if (second != other.second) {
69 return second - other.second;
70 }
71 return {};
72 }
73};
74
75template <typename TResult, typename TOperand>
76static bool SafeAdd(TResult& result, TOperand op) {
77 result = result + op;
78 return true;
79}
80
81template <typename TResult, typename TUnit, typename TBase>
82static bool SafeNormalize(TResult& result, TUnit& unit, TBase base) {
83 TUnit delta{};
84 if (unit >= 0) {
85 delta = unit / base;
86 } else {
87 delta = -1 - (-1 - unit) / base;
88 }
89 unit -= delta * base;
90 return SafeAdd(result, delta);
91}
92
93template <typename T>
94static constexpr bool IsLeapYear(T year) {
95 return ((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0);
96}
97
98template <typename T>
99static constexpr T GetYearLengthInDays(T year) {
100 return IsLeapYear(year) ? days_per_leap_year : days_per_normal_year;
101}
102
103static constexpr s64 GetLeapDaysFromYearPositive(s64 year) {
104 return year / 4 - year / 100 + year / years_per_repeat;
105}
106
107static constexpr s64 GetLeapDaysFromYear(s64 year) {
108 if (year < 0) {
109 return -1 - GetLeapDaysFromYearPositive(-1 - year);
110 } else {
111 return GetLeapDaysFromYearPositive(year);
112 }
113}
114
115static constexpr s8 GetMonthLength(bool is_leap_year, int month) {
116 constexpr std::array<s8, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
117 constexpr std::array<s8, 12> month_lengths_leap{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
118 return is_leap_year ? month_lengths_leap[month] : month_lengths[month];
119}
120
121static constexpr bool IsDigit(char value) {
122 return value >= '0' && value <= '9';
123}
124
125static constexpr int GetQZName(const char* name, int offset, char delimiter) {
126 while (name[offset] != '\0' && name[offset] != delimiter) {
127 offset++;
128 }
129 return offset;
130}
131
132static constexpr int GetTZName(const char* name, int offset) {
133 char c;
134
135 while ((c = name[offset]) != '\0' && !IsDigit(c) && c != ',' && c != '-' && c != '+') {
136 ++offset;
137 }
138 return offset;
139}
140
141static constexpr bool GetInteger(const char* name, int& offset, int& value, int min, int max) {
142 value = 0;
143 char temp{name[offset]};
144 if (!IsDigit(temp)) {
145 return {};
146 }
147 do {
148 value = value * 10 + (temp - '0');
149 if (value > max) {
150 return {};
151 }
152 offset++;
153 temp = name[offset];
154 } while (IsDigit(temp));
155
156 return value >= min;
157}
158
159static constexpr bool GetSeconds(const char* name, int& offset, int& seconds) {
160 seconds = 0;
161 int value{};
162 if (!GetInteger(name, offset, value, 0, hours_per_day * days_per_week - 1)) {
163 return {};
164 }
165 seconds = value * seconds_per_hour;
166
167 if (name[offset] == ':') {
168 offset++;
169 if (!GetInteger(name, offset, value, 0, minutes_per_hour - 1)) {
170 return {};
171 }
172 seconds += value * seconds_per_minute;
173 if (name[offset] == ':') {
174 offset++;
175 if (!GetInteger(name, offset, value, 0, seconds_per_minute)) {
176 return {};
177 }
178 seconds += value;
179 }
180 }
181 return true;
182}
183
184static constexpr bool GetOffset(const char* name, int& offset, int& value) {
185 bool is_negative{};
186 if (name[offset] == '-') {
187 is_negative = true;
188 offset++;
189 } else if (name[offset] == '+') {
190 offset++;
191 }
192 if (!GetSeconds(name, offset, value)) {
193 return {};
194 }
195 if (is_negative) {
196 value = -value;
197 }
198 return true;
199}
200
201static constexpr bool GetRule(const char* name, int& position, Rule& rule) {
202 bool is_valid{};
203 if (name[position] == 'J') {
204 position++;
205 rule.rule_type = Rule::Type::JulianDay;
206 is_valid = GetInteger(name, position, rule.day, 1, days_per_normal_year);
207 } else if (name[position] == 'M') {
208 position++;
209 rule.rule_type = Rule::Type::MonthNthDayOfWeek;
210 is_valid = GetInteger(name, position, rule.month, 1, months_per_year);
211 if (!is_valid) {
212 return {};
213 }
214 if (name[position++] != '.') {
215 return {};
216 }
217 is_valid = GetInteger(name, position, rule.week, 1, 5);
218 if (!is_valid) {
219 return {};
220 }
221 if (name[position++] != '.') {
222 return {};
223 }
224 is_valid = GetInteger(name, position, rule.day, 0, days_per_week - 1);
225 } else if (isdigit(name[position])) {
226 rule.rule_type = Rule::Type::DayOfYear;
227 is_valid = GetInteger(name, position, rule.day, 0, days_per_leap_year - 1);
228 } else {
229 return {};
230 }
231 if (!is_valid) {
232 return {};
233 }
234 if (name[position] == '/') {
235 position++;
236 return GetOffset(name, position, rule.transition_time);
237 } else {
238 rule.transition_time = 2 * seconds_per_hour;
239 }
240 return true;
241}
242
243static constexpr int TransitionTime(int year, Rule rule, int offset) {
244 int value{};
245 switch (rule.rule_type) {
246 case Rule::Type::JulianDay:
247 value = (rule.day - 1) * seconds_per_day;
248 if (IsLeapYear(year) && rule.day >= 60) {
249 value += seconds_per_day;
250 }
251 break;
252 case Rule::Type::DayOfYear:
253 value = rule.day * seconds_per_day;
254 break;
255 case Rule::Type::MonthNthDayOfWeek: {
256 // Use Zeller's Congruence (https://en.wikipedia.org/wiki/Zeller%27s_congruence) to
257 // calculate the day of the week for any Julian or Gregorian calendar date.
258 const int m1{(rule.month + 9) % 12 + 1};
259 const int yy0{(rule.month <= 2) ? (year - 1) : year};
260 const int yy1{yy0 / 100};
261 const int yy2{yy0 % 100};
262 int day_of_week{((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7};
263
264 if (day_of_week < 0) {
265 day_of_week += days_per_week;
266 }
267 int day{rule.day - day_of_week};
268 if (day < 0) {
269 day += days_per_week;
270 }
271 for (int i{1}; i < rule.week; i++) {
272 if (day + days_per_week >= GetMonthLength(IsLeapYear(year), rule.month - 1)) {
273 break;
274 }
275 day += days_per_week;
276 }
277
278 value = day * seconds_per_day;
279 for (int index{}; index < rule.month - 1; ++index) {
280 value += GetMonthLength(IsLeapYear(year), index) * seconds_per_day;
281 }
282 break;
283 }
284 default:
285 ASSERT(false);
286 break;
287 }
288 return value + rule.transition_time + offset;
289}
290
291static bool ParsePosixName(const char* name, TimeZoneRule& rule) {
292 static constexpr char default_rule[]{",M4.1.0,M10.5.0"};
293 const char* std_name{name};
294 int std_len{};
295 int offset{};
296 int std_offset{};
297
298 if (name[offset] == '<') {
299 offset++;
300 std_name = name + offset;
301 const int std_name_offset{offset};
302 offset = GetQZName(name, offset, '>');
303 if (name[offset] != '>') {
304 return {};
305 }
306 std_len = offset - std_name_offset;
307 offset++;
308 } else {
309 offset = GetTZName(name, offset);
310 std_len = offset;
311 }
312 if (std_len == 0) {
313 return {};
314 }
315 if (!GetOffset(name, offset, std_offset)) {
316 return {};
317 }
318
319 int char_count{std_len + 1};
320 int dest_len{};
321 int dest_offset{};
322 const char* dest_name{name + offset};
323 if (rule.chars.size() < std::size_t(char_count)) {
324 return {};
325 }
326
327 if (name[offset] != '\0') {
328 if (name[offset] == '<') {
329 dest_name = name + (++offset);
330 const int dest_name_offset{offset};
331 offset = GetQZName(name, offset, '>');
332 if (name[offset] != '>') {
333 return {};
334 }
335 dest_len = offset - dest_name_offset;
336 offset++;
337 } else {
338 dest_name = name + (offset);
339 offset = GetTZName(name, offset);
340 dest_len = offset;
341 }
342 if (dest_len == 0) {
343 return {};
344 }
345 char_count += dest_len + 1;
346 if (rule.chars.size() < std::size_t(char_count)) {
347 return {};
348 }
349 if (name[offset] != '\0' && name[offset] != ',' && name[offset] != ';') {
350 if (!GetOffset(name, offset, dest_offset)) {
351 return {};
352 }
353 } else {
354 dest_offset = std_offset - seconds_per_hour;
355 }
356 if (name[offset] == '\0') {
357 name = default_rule;
358 offset = 0;
359 }
360 if (name[offset] == ',' || name[offset] == ';') {
361 offset++;
362
363 Rule start{};
364 if (!GetRule(name, offset, start)) {
365 return {};
366 }
367 if (name[offset++] != ',') {
368 return {};
369 }
370
371 Rule end{};
372 if (!GetRule(name, offset, end)) {
373 return {};
374 }
375 if (name[offset] != '\0') {
376 return {};
377 }
378
379 rule.type_count = 2;
380 rule.ttis[0].gmt_offset = -dest_offset;
381 rule.ttis[0].is_dst = true;
382 rule.ttis[0].abbreviation_list_index = std_len + 1;
383 rule.ttis[1].gmt_offset = -std_offset;
384 rule.ttis[1].is_dst = false;
385 rule.ttis[1].abbreviation_list_index = 0;
386 rule.default_type = 0;
387
388 s64 jan_first{};
389 int time_count{};
390 int jan_offset{};
391 int year_beginning{epoch_year};
392 do {
393 const int year_seconds{GetYearLengthInDays(year_beginning - 1) * seconds_per_day};
394 year_beginning--;
395 if (!SafeAdd(jan_first, -year_seconds)) {
396 jan_offset = -year_seconds;
397 break;
398 }
399 } while (epoch_year - years_per_repeat / 2 < year_beginning);
400
401 int year_limit{year_beginning + years_per_repeat + 1};
402 int year{};
403 for (year = year_beginning; year < year_limit; year++) {
404 int start_time{TransitionTime(year, start, std_offset)};
405 int end_time{TransitionTime(year, end, dest_offset)};
406 const int year_seconds{GetYearLengthInDays(year) * seconds_per_day};
407 const bool is_reversed{end_time < start_time};
408 if (is_reversed) {
409 int swap{start_time};
410 start_time = end_time;
411 end_time = swap;
412 }
413
414 if (is_reversed ||
415 (start_time < end_time &&
416 (end_time - start_time < (year_seconds + (std_offset - dest_offset))))) {
417 if (rule.ats.size() - 2 < std::size_t(time_count)) {
418 break;
419 }
420
421 rule.ats[time_count] = jan_first;
422 if (SafeAdd(rule.ats[time_count], jan_offset + start_time)) {
423 rule.types[time_count++] = is_reversed ? 1 : 0;
424 } else if (jan_offset != 0) {
425 rule.default_type = is_reversed ? 1 : 0;
426 }
427
428 rule.ats[time_count] = jan_first;
429 if (SafeAdd(rule.ats[time_count], jan_offset + end_time)) {
430 rule.types[time_count++] = is_reversed ? 0 : 1;
431 year_limit = year + years_per_repeat + 1;
432 } else if (jan_offset != 0) {
433 rule.default_type = is_reversed ? 0 : 1;
434 }
435 }
436 if (!SafeAdd(jan_first, jan_offset + year_seconds)) {
437 break;
438 }
439 jan_offset = 0;
440 }
441 rule.time_count = time_count;
442 if (time_count == 0) {
443 rule.type_count = 1;
444 } else if (years_per_repeat < year - year_beginning) {
445 rule.go_back = true;
446 rule.go_ahead = true;
447 }
448 } else {
449 if (name[offset] == '\0') {
450 return {};
451 }
452
453 s64 their_std_offset{};
454 for (int index{}; index < rule.time_count; ++index) {
455 const s8 type{rule.types[index]};
456 if (rule.ttis[type].is_standard_time_daylight) {
457 their_std_offset = -rule.ttis[type].gmt_offset;
458 }
459 }
460
461 s64 their_offset{their_std_offset};
462 for (int index{}; index < rule.time_count; ++index) {
463 const s8 type{rule.types[index]};
464 rule.types[index] = rule.ttis[type].is_dst ? 1 : 0;
465 if (!rule.ttis[type].is_gmt) {
466 if (!rule.ttis[type].is_standard_time_daylight) {
467 rule.ats[index] += dest_offset - their_std_offset;
468 } else {
469 rule.ats[index] += std_offset - their_std_offset;
470 }
471 }
472 their_offset = -rule.ttis[type].gmt_offset;
473 if (!rule.ttis[type].is_dst) {
474 their_std_offset = their_offset;
475 }
476 }
477
478 if (rule.time_count > 0) {
479 UNIMPLEMENTED();
480 // TODO (lat9nq): Implement eggert/tz/localtime.c:tzparse:1329
481 // Seems to be unused in yuzu for now: I never hit the UNIMPLEMENTED in testing
482 }
483
484 rule.ttis[0].gmt_offset = -std_offset;
485 rule.ttis[0].is_dst = false;
486 rule.ttis[0].abbreviation_list_index = 0;
487 rule.ttis[1].gmt_offset = -dest_offset;
488 rule.ttis[1].is_dst = true;
489 rule.ttis[1].abbreviation_list_index = std_len + 1;
490 rule.type_count = 2;
491 rule.default_type = 0;
492 }
493 } else {
494 // Default is standard time
495 rule.type_count = 1;
496 rule.time_count = 0;
497 rule.default_type = 0;
498 rule.ttis[0].gmt_offset = -std_offset;
499 rule.ttis[0].is_dst = false;
500 rule.ttis[0].abbreviation_list_index = 0;
501 }
502
503 rule.char_count = char_count;
504 for (int index{}; index < std_len; ++index) {
505 rule.chars[index] = std_name[index];
506 }
507
508 rule.chars[std_len++] = '\0';
509 if (dest_len != 0) {
510 for (int index{}; index < dest_len; ++index) {
511 rule.chars[std_len + index] = dest_name[index];
512 }
513 rule.chars[std_len + dest_len] = '\0';
514 }
515
516 return true;
517}
518
519static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFile& vfs_file) {
520 TzifHeader header{};
521 if (vfs_file->ReadObject<TzifHeader>(&header) != sizeof(TzifHeader)) {
522 return {};
523 }
524
525 constexpr s32 time_zone_max_leaps{50};
526 constexpr s32 time_zone_max_chars{50};
527 constexpr s32 time_zone_max_times{1000};
528 if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps &&
529 0 < header.type_count && header.type_count < s32(time_zone_rule.ttis.size()) &&
530 0 <= header.time_count && header.time_count < s32(time_zone_rule.ats.size()) &&
531 0 <= header.char_count && header.char_count < time_zone_max_chars &&
532 (header.ttis_std_count == header.type_count || header.ttis_std_count == 0) &&
533 (header.ttis_gmt_count == header.type_count || header.ttis_gmt_count == 0))) {
534 return {};
535 }
536 time_zone_rule.time_count = header.time_count;
537 time_zone_rule.type_count = header.type_count;
538 time_zone_rule.char_count = header.char_count;
539
540 int time_count{};
541 u64 read_offset = sizeof(TzifHeader);
542 for (int index{}; index < time_zone_rule.time_count; ++index) {
543 s64_be at{};
544 vfs_file->ReadObject<s64_be>(&at, read_offset);
545 time_zone_rule.types[index] = 1;
546 if (time_count != 0 && at <= time_zone_rule.ats[time_count - 1]) {
547 if (at < time_zone_rule.ats[time_count - 1]) {
548 return {};
549 }
550 time_zone_rule.types[index - 1] = 0;
551 time_count--;
552 }
553 time_zone_rule.ats[time_count++] = at;
554 read_offset += sizeof(s64_be);
555 }
556 time_count = 0;
557 for (int index{}; index < time_zone_rule.time_count; ++index) {
558 const u8 type{*vfs_file->ReadByte(read_offset)};
559 read_offset += sizeof(u8);
560 if (time_zone_rule.type_count <= type) {
561 return {};
562 }
563 if (time_zone_rule.types[index] != 0) {
564 time_zone_rule.types[time_count++] = type;
565 }
566 }
567 time_zone_rule.time_count = time_count;
568 for (int index{}; index < time_zone_rule.type_count; ++index) {
569 TimeTypeInfo& ttis{time_zone_rule.ttis[index]};
570 u32_be gmt_offset{};
571 vfs_file->ReadObject<u32_be>(&gmt_offset, read_offset);
572 read_offset += sizeof(u32_be);
573 ttis.gmt_offset = gmt_offset;
574
575 const u8 dst{*vfs_file->ReadByte(read_offset)};
576 read_offset += sizeof(u8);
577 if (dst >= 2) {
578 return {};
579 }
580 ttis.is_dst = dst != 0;
581
582 const s32 abbreviation_list_index{*vfs_file->ReadByte(read_offset)};
583 read_offset += sizeof(u8);
584 if (abbreviation_list_index >= time_zone_rule.char_count) {
585 return {};
586 }
587 ttis.abbreviation_list_index = abbreviation_list_index;
588 }
589
590 vfs_file->ReadArray(time_zone_rule.chars.data(), time_zone_rule.char_count, read_offset);
591 time_zone_rule.chars[time_zone_rule.char_count] = '\0';
592 read_offset += time_zone_rule.char_count;
593 for (int index{}; index < time_zone_rule.type_count; ++index) {
594 if (header.ttis_std_count == 0) {
595 time_zone_rule.ttis[index].is_standard_time_daylight = false;
596 } else {
597 const u8 dst{*vfs_file->ReadByte(read_offset)};
598 read_offset += sizeof(u8);
599 if (dst >= 2) {
600 return {};
601 }
602 time_zone_rule.ttis[index].is_standard_time_daylight = dst != 0;
603 }
604 }
605
606 for (int index{}; index < time_zone_rule.type_count; ++index) {
607 if (header.ttis_std_count == 0) {
608 time_zone_rule.ttis[index].is_gmt = false;
609 } else {
610 const u8 dst{*vfs_file->ReadByte(read_offset)};
611 read_offset += sizeof(u8);
612 if (dst >= 2) {
613 return {};
614 }
615 time_zone_rule.ttis[index].is_gmt = dst != 0;
616 }
617 }
618
619 const u64 position{(read_offset - sizeof(TzifHeader))};
620 const s64 bytes_read = s64(vfs_file->GetSize() - sizeof(TzifHeader) - position);
621 if (bytes_read < 0) {
622 return {};
623 }
624 constexpr s32 time_zone_name_max{255};
625 if (bytes_read > (time_zone_name_max + 1)) {
626 return {};
627 }
628
629 std::array<char, time_zone_name_max + 1> temp_name{};
630 vfs_file->ReadArray(temp_name.data(), bytes_read, read_offset);
631 if (bytes_read > 2 && temp_name[0] == '\n' && temp_name[bytes_read - 1] == '\n' &&
632 std::size_t(time_zone_rule.type_count) + 2 <= time_zone_rule.ttis.size()) {
633 temp_name[bytes_read - 1] = '\0';
634
635 std::array<char, time_zone_name_max> name{};
636 std::memcpy(name.data(), temp_name.data() + 1, std::size_t(bytes_read - 1));
637
638 // Fill in computed transition times with temp rule
639 TimeZoneRule temp_rule;
640 if (ParsePosixName(name.data(), temp_rule)) {
641 int have_abbreviation = 0;
642 int char_count = time_zone_rule.char_count;
643
644 for (int i = 0; i < temp_rule.type_count; i++) {
645 char* temp_abbreviation =
646 temp_rule.chars.data() + temp_rule.ttis[i].abbreviation_list_index;
647 int j;
648 for (j = 0; j < char_count; j++) {
649 if (std::strcmp(time_zone_rule.chars.data() + j, temp_abbreviation) == 0) {
650 temp_rule.ttis[i].abbreviation_list_index = j;
651 have_abbreviation++;
652 break;
653 }
654 }
655 if (j >= char_count) {
656 int temp_abbreviation_length = static_cast<int>(std::strlen(temp_abbreviation));
657 if (j + temp_abbreviation_length < time_zone_max_chars) {
658 std::strcpy(time_zone_rule.chars.data() + j, temp_abbreviation);
659 char_count = j + temp_abbreviation_length + 1;
660 temp_rule.ttis[i].abbreviation_list_index = j;
661 have_abbreviation++;
662 }
663 }
664 }
665
666 if (have_abbreviation == temp_rule.type_count) {
667 time_zone_rule.char_count = char_count;
668
669 // Original comment:
670 /* Ignore any trailing, no-op transitions generated
671 by zic as they don't help here and can run afoul
672 of bugs in zic 2016j or earlier. */
673 // This is possibly unnecessary for yuzu, since Nintendo doesn't run zic
674 while (1 < time_zone_rule.time_count &&
675 (time_zone_rule.types[time_zone_rule.time_count - 1] ==
676 time_zone_rule.types[time_zone_rule.time_count - 2])) {
677 time_zone_rule.time_count--;
678 }
679
680 for (int i = 0;
681 i < temp_rule.time_count && time_zone_rule.time_count < time_zone_max_times;
682 i++) {
683 const s64 transition_time = temp_rule.ats[i];
684 if (0 < time_zone_rule.time_count &&
685 transition_time <= time_zone_rule.ats[time_zone_rule.time_count - 1]) {
686 continue;
687 }
688
689 time_zone_rule.ats[time_zone_rule.time_count] = transition_time;
690 time_zone_rule.types[time_zone_rule.time_count] =
691 static_cast<s8>(time_zone_rule.type_count + temp_rule.types[i]);
692 time_zone_rule.time_count++;
693 }
694 for (int i = 0; i < temp_rule.type_count; i++) {
695 time_zone_rule.ttis[time_zone_rule.type_count++] = temp_rule.ttis[i];
696 }
697 }
698 }
699 }
700
701 const auto typesequiv = [](TimeZoneRule& rule, int a, int b) -> bool {
702 if (a < 0 || a >= rule.type_count || b < 0 || b >= rule.type_count) {
703 return {};
704 }
705
706 const struct TimeTypeInfo* ap = &rule.ttis[a];
707 const struct TimeTypeInfo* bp = &rule.ttis[b];
708
709 return (ap->gmt_offset == bp->gmt_offset && ap->is_dst == bp->is_dst &&
710 (std::strcmp(&rule.chars[ap->abbreviation_list_index],
711 &rule.chars[bp->abbreviation_list_index]) == 0));
712 };
713
714 if (time_zone_rule.type_count == 0) {
715 return {};
716 }
717 if (time_zone_rule.time_count > 1) {
718 if (time_zone_rule.ats[0] <= std::numeric_limits<s64>::max() - seconds_per_repeat) {
719 s64 repeatat = time_zone_rule.ats[0] + seconds_per_repeat;
720 int repeatattype = time_zone_rule.types[0];
721 for (int i = 1; i < time_zone_rule.time_count; ++i) {
722 if (time_zone_rule.ats[i] == repeatat &&
723 typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) {
724 time_zone_rule.go_back = true;
725 break;
726 }
727 }
728 }
729 if (std::numeric_limits<s64>::min() + seconds_per_repeat <=
730 time_zone_rule.ats[time_zone_rule.time_count - 1]) {
731 s64 repeatat = time_zone_rule.ats[time_zone_rule.time_count - 1] - seconds_per_repeat;
732 int repeatattype = time_zone_rule.types[time_zone_rule.time_count - 1];
733 for (int i = time_zone_rule.time_count; i >= 0; --i) {
734 if (time_zone_rule.ats[i] == repeatat &&
735 typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) {
736 time_zone_rule.go_ahead = true;
737 break;
738 }
739 }
740 }
741 }
742
743 s32 default_type{};
744
745 for (default_type = 0; default_type < time_zone_rule.time_count; default_type++) {
746 if (time_zone_rule.types[default_type] == 0) {
747 break;
748 }
749 }
750
751 default_type = default_type < time_zone_rule.time_count ? -1 : 0;
752 if (default_type < 0 && time_zone_rule.time_count > 0 &&
753 time_zone_rule.ttis[time_zone_rule.types[0]].is_dst) {
754 default_type = time_zone_rule.types[0];
755 while (--default_type >= 0) {
756 if (!time_zone_rule.ttis[default_type].is_dst) {
757 break;
758 }
759 }
760 }
761 if (default_type < 0) {
762 default_type = 0;
763 while (time_zone_rule.ttis[default_type].is_dst) {
764 if (++default_type >= time_zone_rule.type_count) {
765 default_type = 0;
766 break;
767 }
768 }
769 }
770 time_zone_rule.default_type = default_type;
771 return true;
772}
773
774static Result CreateCalendarTime(s64 time, int gmt_offset, CalendarTimeInternal& calendar_time,
775 CalendarAdditionalInfo& calendar_additional_info) {
776 s64 year{epoch_year};
777 s64 time_days{time / seconds_per_day};
778 s64 remaining_seconds{time % seconds_per_day};
779 while (time_days < 0 || time_days >= GetYearLengthInDays(year)) {
780 s64 delta = time_days / days_per_leap_year;
781 if (!delta) {
782 delta = time_days < 0 ? -1 : 1;
783 }
784 s64 new_year{year};
785 if (!SafeAdd(new_year, delta)) {
786 return ERROR_OUT_OF_RANGE;
787 }
788 time_days -= (new_year - year) * days_per_normal_year;
789 time_days -= GetLeapDaysFromYear(new_year - 1) - GetLeapDaysFromYear(year - 1);
790 year = new_year;
791 }
792
793 s64 day_of_year{time_days};
794 remaining_seconds += gmt_offset;
795 while (remaining_seconds < 0) {
796 remaining_seconds += seconds_per_day;
797 day_of_year--;
798 }
799
800 while (remaining_seconds >= seconds_per_day) {
801 remaining_seconds -= seconds_per_day;
802 day_of_year++;
803 }
804
805 while (day_of_year < 0) {
806 if (!SafeAdd(year, -1)) {
807 return ERROR_OUT_OF_RANGE;
808 }
809 day_of_year += GetYearLengthInDays(year);
810 }
811
812 while (day_of_year >= GetYearLengthInDays(year)) {
813 day_of_year -= GetYearLengthInDays(year);
814 if (!SafeAdd(year, 1)) {
815 return ERROR_OUT_OF_RANGE;
816 }
817 }
818
819 calendar_time.year = year;
820 calendar_additional_info.day_of_year = static_cast<u32>(day_of_year);
821 s64 day_of_week{
822 (epoch_week_day +
823 ((year - epoch_year) % days_per_week) * (days_per_normal_year % days_per_week) +
824 GetLeapDaysFromYear(year - 1) - GetLeapDaysFromYear(epoch_year - 1) + day_of_year) %
825 days_per_week};
826 if (day_of_week < 0) {
827 day_of_week += days_per_week;
828 }
829
830 calendar_additional_info.day_of_week = static_cast<u32>(day_of_week);
831 calendar_time.hour = static_cast<s8>((remaining_seconds / seconds_per_hour) % seconds_per_hour);
832 remaining_seconds %= seconds_per_hour;
833 calendar_time.minute = static_cast<s8>(remaining_seconds / seconds_per_minute);
834 calendar_time.second = static_cast<s8>(remaining_seconds % seconds_per_minute);
835
836 for (calendar_time.month = 0;
837 day_of_year >= GetMonthLength(IsLeapYear(year), calendar_time.month);
838 ++calendar_time.month) {
839 day_of_year -= GetMonthLength(IsLeapYear(year), calendar_time.month);
840 }
841
842 calendar_time.day = static_cast<s8>(day_of_year + 1);
843 calendar_additional_info.is_dst = false;
844 calendar_additional_info.gmt_offset = gmt_offset;
845
846 return ResultSuccess;
847}
848
849static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time,
850 CalendarTimeInternal& calendar_time,
851 CalendarAdditionalInfo& calendar_additional_info) {
852 ASSERT(rules.go_ahead ? rules.time_count > 0 : true);
853 if ((rules.go_back && time < rules.ats[0]) ||
854 (rules.go_ahead && time > rules.ats[rules.time_count - 1])) {
855 s64 seconds{};
856 if (time < rules.ats[0]) {
857 seconds = rules.ats[0] - time;
858 } else {
859 seconds = time - rules.ats[rules.time_count - 1];
860 }
861 seconds--;
862
863 const s64 years{(seconds / seconds_per_repeat + 1) * years_per_repeat};
864 seconds = years * average_seconds_per_year;
865
866 s64 new_time{time};
867 if (time < rules.ats[0]) {
868 new_time += seconds;
869 } else {
870 new_time -= seconds;
871 }
872 if (new_time < rules.ats[0] && new_time > rules.ats[rules.time_count - 1]) {
873 return ERROR_TIME_NOT_FOUND;
874 }
875 if (const Result result{
876 ToCalendarTimeInternal(rules, new_time, calendar_time, calendar_additional_info)};
877 result != ResultSuccess) {
878 return result;
879 }
880 if (time < rules.ats[0]) {
881 calendar_time.year -= years;
882 } else {
883 calendar_time.year += years;
884 }
885
886 return ResultSuccess;
887 }
888
889 s32 tti_index{};
890 if (rules.time_count == 0 || time < rules.ats[0]) {
891 tti_index = rules.default_type;
892 } else {
893 s32 low{1};
894 s32 high{rules.time_count};
895 while (low < high) {
896 s32 mid{(low + high) >> 1};
897 if (time < rules.ats[mid]) {
898 high = mid;
899 } else {
900 low = mid + 1;
901 }
902 }
903 tti_index = rules.types[low - 1];
904 }
905
906 if (const Result result{CreateCalendarTime(time, rules.ttis[tti_index].gmt_offset,
907 calendar_time, calendar_additional_info)};
908 result != ResultSuccess) {
909 return result;
910 }
911
912 calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst;
913 const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]};
914 u32 index;
915 for (index = 0; time_zone[index] != '\0' && time_zone[index] != ',' &&
916 index < calendar_additional_info.timezone_name.size() - 1;
917 ++index) {
918 calendar_additional_info.timezone_name[index] = time_zone[index];
919 }
920 calendar_additional_info.timezone_name[index] = '\0';
921 return ResultSuccess;
922}
923
924static Result ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) {
925 CalendarTimeInternal calendar_time{};
926 const Result result{
927 ToCalendarTimeInternal(rules, time, calendar_time, calendar.additional_info)};
928 calendar.time.year = static_cast<s16>(calendar_time.year);
929
930 // Internal impl. uses 0-indexed month
931 calendar.time.month = static_cast<s8>(calendar_time.month + 1);
932
933 calendar.time.day = calendar_time.day;
934 calendar.time.hour = calendar_time.hour;
935 calendar.time.minute = calendar_time.minute;
936 calendar.time.second = calendar_time.second;
937 return result;
938}
939
940TimeZoneManager::TimeZoneManager() = default;
941TimeZoneManager::~TimeZoneManager() = default;
942
943Result TimeZoneManager::ToCalendarTime(const TimeZoneRule& rules, s64 time,
944 CalendarInfo& calendar) const {
945 return ToCalendarTimeImpl(rules, time, calendar);
946}
947
948Result TimeZoneManager::SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name,
949 FileSys::VirtualFile& vfs_file) {
950 TimeZoneRule rule{};
951 if (ParseTimeZoneBinary(rule, vfs_file)) {
952 device_location_name = location_name;
953 time_zone_rule = rule;
954 return ResultSuccess;
955 }
956 return ERROR_TIME_ZONE_CONVERSION_FAILED;
957}
958
959Result TimeZoneManager::SetUpdatedTime(const Clock::SteadyClockTimePoint& value) {
960 time_zone_update_time_point = value;
961 return ResultSuccess;
962}
963
964Result TimeZoneManager::ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const {
965 if (is_initialized) {
966 return ToCalendarTime(time_zone_rule, time, calendar);
967 } else {
968 return ERROR_UNINITIALIZED_CLOCK;
969 }
970}
971
972Result TimeZoneManager::ParseTimeZoneRuleBinary(TimeZoneRule& rules,
973 FileSys::VirtualFile& vfs_file) const {
974 if (!ParseTimeZoneBinary(rules, vfs_file)) {
975 return ERROR_TIME_ZONE_CONVERSION_FAILED;
976 }
977 return ResultSuccess;
978}
979
980Result TimeZoneManager::ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time,
981 s64& posix_time) const {
982 posix_time = 0;
983
984 CalendarTimeInternal internal_time{
985 .year = calendar_time.year,
986 // Internal impl. uses 0-indexed month
987 .month = static_cast<s8>(calendar_time.month - 1),
988 .day = calendar_time.day,
989 .hour = calendar_time.hour,
990 .minute = calendar_time.minute,
991 .second = calendar_time.second,
992 };
993
994 s32 hour{internal_time.hour};
995 s32 minute{internal_time.minute};
996 if (!SafeNormalize(hour, minute, minutes_per_hour)) {
997 return ERROR_OVERFLOW;
998 }
999 internal_time.minute = static_cast<s8>(minute);
1000
1001 s32 day{internal_time.day};
1002 if (!SafeNormalize(day, hour, hours_per_day)) {
1003 return ERROR_OVERFLOW;
1004 }
1005 internal_time.day = static_cast<s8>(day);
1006 internal_time.hour = static_cast<s8>(hour);
1007
1008 s64 year{internal_time.year};
1009 s64 month{internal_time.month};
1010 if (!SafeNormalize(year, month, months_per_year)) {
1011 return ERROR_OVERFLOW;
1012 }
1013 internal_time.month = static_cast<s8>(month);
1014
1015 if (!SafeAdd(year, year_base)) {
1016 return ERROR_OVERFLOW;
1017 }
1018
1019 while (day <= 0) {
1020 if (!SafeAdd(year, -1)) {
1021 return ERROR_OVERFLOW;
1022 }
1023 s64 temp_year{year};
1024 if (1 < internal_time.month) {
1025 ++temp_year;
1026 }
1027 day += static_cast<s32>(GetYearLengthInDays(temp_year));
1028 }
1029
1030 while (day > days_per_leap_year) {
1031 s64 temp_year{year};
1032 if (1 < internal_time.month) {
1033 temp_year++;
1034 }
1035 day -= static_cast<s32>(GetYearLengthInDays(temp_year));
1036 if (!SafeAdd(year, 1)) {
1037 return ERROR_OVERFLOW;
1038 }
1039 }
1040
1041 while (true) {
1042 const s32 month_length{GetMonthLength(IsLeapYear(year), internal_time.month)};
1043 if (day <= month_length) {
1044 break;
1045 }
1046 day -= month_length;
1047 internal_time.month++;
1048 if (internal_time.month >= months_per_year) {
1049 internal_time.month = 0;
1050 if (!SafeAdd(year, 1)) {
1051 return ERROR_OVERFLOW;
1052 }
1053 }
1054 }
1055 internal_time.day = static_cast<s8>(day);
1056
1057 if (!SafeAdd(year, -year_base)) {
1058 return ERROR_OVERFLOW;
1059 }
1060 internal_time.year = year;
1061
1062 s32 saved_seconds{};
1063 if (internal_time.second >= 0 && internal_time.second < seconds_per_minute) {
1064 saved_seconds = 0;
1065 } else if (year + year_base < epoch_year) {
1066 s32 second{internal_time.second};
1067 if (!SafeAdd(second, 1 - seconds_per_minute)) {
1068 return ERROR_OVERFLOW;
1069 }
1070 saved_seconds = second;
1071 internal_time.second = 1 - seconds_per_minute;
1072 } else {
1073 saved_seconds = internal_time.second;
1074 internal_time.second = 0;
1075 }
1076
1077 s64 low{LLONG_MIN};
1078 s64 high{LLONG_MAX};
1079 while (true) {
1080 s64 pivot{low / 2 + high / 2};
1081 if (pivot < low) {
1082 pivot = low;
1083 } else if (pivot > high) {
1084 pivot = high;
1085 }
1086 s32 direction{};
1087 CalendarTimeInternal candidate_calendar_time{};
1088 CalendarAdditionalInfo unused{};
1089 if (ToCalendarTimeInternal(rules, pivot, candidate_calendar_time, unused) !=
1090 ResultSuccess) {
1091 if (pivot > 0) {
1092 direction = 1;
1093 } else {
1094 direction = -1;
1095 }
1096 } else {
1097 direction = candidate_calendar_time.Compare(internal_time);
1098 }
1099 if (!direction) {
1100 const s64 time_result{pivot + saved_seconds};
1101 if ((time_result < pivot) != (saved_seconds < 0)) {
1102 return ERROR_OVERFLOW;
1103 }
1104 posix_time = time_result;
1105 break;
1106 } else {
1107 if (pivot == low) {
1108 if (pivot == LLONG_MAX) {
1109 return ERROR_TIME_NOT_FOUND;
1110 }
1111 pivot++;
1112 low++;
1113 } else if (pivot == high) {
1114 if (pivot == LLONG_MIN) {
1115 return ERROR_TIME_NOT_FOUND;
1116 }
1117 pivot--;
1118 high--;
1119 }
1120 if (low > high) {
1121 return ERROR_TIME_NOT_FOUND;
1122 }
1123 if (direction > 0) {
1124 high = pivot;
1125 } else {
1126 low = pivot;
1127 }
1128 }
1129 }
1130 return ResultSuccess;
1131}
1132
1133Result TimeZoneManager::ToPosixTimeWithMyRule(const CalendarTime& calendar_time,
1134 s64& posix_time) const {
1135 if (is_initialized) {
1136 return ToPosixTime(time_zone_rule, calendar_time, posix_time);
1137 }
1138 posix_time = 0;
1139 return ERROR_UNINITIALIZED_CLOCK;
1140}
1141
1142Result TimeZoneManager::GetDeviceLocationName(LocationName& value) const {
1143 if (!is_initialized) {
1144 return ERROR_UNINITIALIZED_CLOCK;
1145 }
1146 std::memcpy(value.data(), device_location_name.c_str(), device_location_name.size());
1147 return ResultSuccess;
1148}
1149
1150Result TimeZoneManager::GetTotalLocationNameCount(s32& count) const {
1151 if (!is_initialized) {
1152 return ERROR_UNINITIALIZED_CLOCK;
1153 }
1154 count = static_cast<u32>(total_location_name_count);
1155
1156 return ResultSuccess;
1157}
1158
1159Result TimeZoneManager::GetTimeZoneRuleVersion(u128& version) const {
1160 if (!is_initialized) {
1161 return ERROR_UNINITIALIZED_CLOCK;
1162 }
1163 version = time_zone_rule_version;
1164
1165 return ResultSuccess;
1166}
1167
1168Result TimeZoneManager::LoadLocationNameList(std::vector<LocationName>& values) const {
1169 if (!is_initialized) {
1170 return ERROR_UNINITIALIZED_CLOCK;
1171 }
1172
1173 for (const auto& name : total_location_names) {
1174 LocationName entry{};
1175 std::memcpy(entry.data(), name.c_str(), name.size());
1176 values.push_back(entry);
1177 }
1178
1179 return ResultSuccess;
1180}
1181
1182} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_manager.h b/src/core/hle/service/time/time_zone_manager.h
deleted file mode 100644
index 8664f28d1..000000000
--- a/src/core/hle/service/time/time_zone_manager.h
+++ /dev/null
@@ -1,61 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <string>
7
8#include "common/common_types.h"
9#include "core/file_sys/vfs_types.h"
10#include "core/hle/service/time/clock_types.h"
11#include "core/hle/service/time/time_zone_types.h"
12
13namespace Service::Time::TimeZone {
14
15class TimeZoneManager final {
16public:
17 TimeZoneManager();
18 ~TimeZoneManager();
19
20 void SetTotalLocationNameCount(std::size_t value) {
21 total_location_name_count = value;
22 }
23
24 void SetLocationNames(std::vector<std::string> location_names) {
25 total_location_names = location_names;
26 }
27
28 void SetTimeZoneRuleVersion(const u128& value) {
29 time_zone_rule_version = value;
30 }
31
32 void MarkAsInitialized() {
33 is_initialized = true;
34 }
35
36 Result SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name,
37 FileSys::VirtualFile& vfs_file);
38 Result SetUpdatedTime(const Clock::SteadyClockTimePoint& value);
39 Result GetDeviceLocationName(TimeZone::LocationName& value) const;
40 Result GetTotalLocationNameCount(s32& count) const;
41 Result GetTimeZoneRuleVersion(u128& version) const;
42 Result LoadLocationNameList(std::vector<TimeZone::LocationName>& values) const;
43 Result ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const;
44 Result ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const;
45 Result ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const;
46 Result ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time,
47 s64& posix_time) const;
48 Result ToPosixTimeWithMyRule(const CalendarTime& calendar_time, s64& posix_time) const;
49
50private:
51 bool is_initialized{};
52 TimeZoneRule time_zone_rule{};
53 std::string device_location_name{"GMT"};
54 u128 time_zone_rule_version{};
55 std::size_t total_location_name_count{};
56 std::vector<std::string> total_location_names{};
57 Clock::SteadyClockTimePoint time_zone_update_time_point{
58 Clock::SteadyClockTimePoint::GetRandom()};
59};
60
61} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
deleted file mode 100644
index 8171c82a5..000000000
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/ipc_helpers.h"
6#include "core/hle/service/time/time_zone_content_manager.h"
7#include "core/hle/service/time/time_zone_service.h"
8#include "core/hle/service/time/time_zone_types.h"
9
10namespace Service::Time {
11
12ITimeZoneService::ITimeZoneService(Core::System& system_,
13 TimeZone::TimeZoneContentManager& time_zone_manager_)
14 : ServiceFramework{system_, "ITimeZoneService"}, time_zone_content_manager{time_zone_manager_} {
15 static const FunctionInfo functions[] = {
16 {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
17 {1, nullptr, "SetDeviceLocationName"},
18 {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"},
19 {3, &ITimeZoneService::LoadLocationNameList, "LoadLocationNameList"},
20 {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
21 {5, &ITimeZoneService::GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
22 {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
23 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
24 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
25 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
26 {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
27 };
28 RegisterHandlers(functions);
29}
30
31void ITimeZoneService::GetDeviceLocationName(HLERequestContext& ctx) {
32 LOG_DEBUG(Service_Time, "called");
33
34 TimeZone::LocationName location_name{};
35 if (const Result result{
36 time_zone_content_manager.GetTimeZoneManager().GetDeviceLocationName(location_name)};
37 result != ResultSuccess) {
38 IPC::ResponseBuilder rb{ctx, 2};
39 rb.Push(result);
40 return;
41 }
42
43 IPC::ResponseBuilder rb{ctx, (sizeof(location_name) / 4) + 2};
44 rb.Push(ResultSuccess);
45 rb.PushRaw(location_name);
46}
47
48void ITimeZoneService::GetTotalLocationNameCount(HLERequestContext& ctx) {
49 LOG_DEBUG(Service_Time, "called");
50
51 s32 count{};
52 if (const Result result{
53 time_zone_content_manager.GetTimeZoneManager().GetTotalLocationNameCount(count)};
54 result != ResultSuccess) {
55 IPC::ResponseBuilder rb{ctx, 2};
56 rb.Push(result);
57 return;
58 }
59
60 IPC::ResponseBuilder rb{ctx, 3};
61 rb.Push(ResultSuccess);
62 rb.Push(count);
63}
64
65void ITimeZoneService::LoadLocationNameList(HLERequestContext& ctx) {
66 LOG_DEBUG(Service_Time, "called");
67
68 std::vector<TimeZone::LocationName> location_names{};
69 if (const Result result{
70 time_zone_content_manager.GetTimeZoneManager().LoadLocationNameList(location_names)};
71 result != ResultSuccess) {
72 IPC::ResponseBuilder rb{ctx, 2};
73 rb.Push(result);
74 return;
75 }
76
77 ctx.WriteBuffer(location_names);
78 IPC::ResponseBuilder rb{ctx, 3};
79 rb.Push(ResultSuccess);
80 rb.Push(static_cast<s32>(location_names.size()));
81}
82void ITimeZoneService::GetTimeZoneRuleVersion(HLERequestContext& ctx) {
83 LOG_DEBUG(Service_Time, "called");
84
85 u128 rule_version{};
86 if (const Result result{
87 time_zone_content_manager.GetTimeZoneManager().GetTimeZoneRuleVersion(rule_version)};
88 result != ResultSuccess) {
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(result);
91 return;
92 }
93
94 IPC::ResponseBuilder rb{ctx, 6};
95 rb.Push(ResultSuccess);
96 rb.PushRaw(rule_version);
97}
98
99void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) {
100 IPC::RequestParser rp{ctx};
101 const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()};
102
103 std::string location_name;
104 for (const auto& byte : raw_location_name) {
105 // Strip extra bytes
106 if (byte == '\0') {
107 break;
108 }
109 location_name.push_back(byte);
110 }
111
112 LOG_DEBUG(Service_Time, "called, location_name={}", location_name);
113
114 TimeZone::TimeZoneRule time_zone_rule{};
115 const Result result{time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
116
117 std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule));
118 std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule));
119 ctx.WriteBuffer(time_zone_rule_outbuffer);
120
121 IPC::ResponseBuilder rb{ctx, 2};
122 rb.Push(result);
123}
124
125void ITimeZoneService::ToCalendarTime(HLERequestContext& ctx) {
126 IPC::RequestParser rp{ctx};
127 const auto posix_time{rp.Pop<s64>()};
128
129 LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time);
130
131 TimeZone::TimeZoneRule time_zone_rule{};
132 const auto buffer{ctx.ReadBuffer()};
133 std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
134
135 TimeZone::CalendarInfo calendar_info{};
136 if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToCalendarTime(
137 time_zone_rule, posix_time, calendar_info)};
138 result != ResultSuccess) {
139 IPC::ResponseBuilder rb{ctx, 2};
140 rb.Push(result);
141 return;
142 }
143
144 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)};
145 rb.Push(ResultSuccess);
146 rb.PushRaw(calendar_info);
147}
148
149void ITimeZoneService::ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
150 IPC::RequestParser rp{ctx};
151 const auto posix_time{rp.Pop<s64>()};
152
153 LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time);
154
155 TimeZone::CalendarInfo calendar_info{};
156 if (const Result result{
157 time_zone_content_manager.GetTimeZoneManager().ToCalendarTimeWithMyRules(
158 posix_time, calendar_info)};
159 result != ResultSuccess) {
160 IPC::ResponseBuilder rb{ctx, 2};
161 rb.Push(result);
162 return;
163 }
164
165 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)};
166 rb.Push(ResultSuccess);
167 rb.PushRaw(calendar_info);
168}
169
170void ITimeZoneService::ToPosixTime(HLERequestContext& ctx) {
171 LOG_DEBUG(Service_Time, "called");
172
173 IPC::RequestParser rp{ctx};
174 const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()};
175 TimeZone::TimeZoneRule time_zone_rule{};
176 std::memcpy(&time_zone_rule, ctx.ReadBuffer().data(), sizeof(TimeZone::TimeZoneRule));
177
178 s64 posix_time{};
179 if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToPosixTime(
180 time_zone_rule, calendar_time, posix_time)};
181 result != ResultSuccess) {
182 IPC::ResponseBuilder rb{ctx, 2};
183 rb.Push(result);
184 return;
185 }
186
187 ctx.WriteBuffer(posix_time);
188
189 // TODO(bunnei): Handle multiple times
190 IPC::ResponseBuilder rb{ctx, 3};
191 rb.Push(ResultSuccess);
192 rb.PushRaw<u32>(1); // Number of times we're returning
193}
194
195void ITimeZoneService::ToPosixTimeWithMyRule(HLERequestContext& ctx) {
196 LOG_DEBUG(Service_Time, "called");
197
198 IPC::RequestParser rp{ctx};
199 const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()};
200
201 s64 posix_time{};
202 if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToPosixTimeWithMyRule(
203 calendar_time, posix_time)};
204 result != ResultSuccess) {
205 IPC::ResponseBuilder rb{ctx, 2};
206 rb.Push(result);
207 return;
208 }
209
210 ctx.WriteBuffer(posix_time);
211
212 IPC::ResponseBuilder rb{ctx, 3};
213 rb.Push(ResultSuccess);
214 rb.PushRaw<u32>(1); // Number of times we're returning
215}
216
217} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h
deleted file mode 100644
index 952fcb0e2..000000000
--- a/src/core/hle/service/time/time_zone_service.h
+++ /dev/null
@@ -1,38 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Core {
9class System;
10}
11
12namespace Service::Time {
13
14namespace TimeZone {
15class TimeZoneContentManager;
16}
17
18class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
19public:
20 explicit ITimeZoneService(Core::System& system_,
21 TimeZone::TimeZoneContentManager& time_zone_manager_);
22
23private:
24 void GetDeviceLocationName(HLERequestContext& ctx);
25 void GetTotalLocationNameCount(HLERequestContext& ctx);
26 void LoadLocationNameList(HLERequestContext& ctx);
27 void GetTimeZoneRuleVersion(HLERequestContext& ctx);
28 void LoadTimeZoneRule(HLERequestContext& ctx);
29 void ToCalendarTime(HLERequestContext& ctx);
30 void ToCalendarTimeWithMyRule(HLERequestContext& ctx);
31 void ToPosixTime(HLERequestContext& ctx);
32 void ToPosixTimeWithMyRule(HLERequestContext& ctx);
33
34private:
35 TimeZone::TimeZoneContentManager& time_zone_content_manager;
36};
37
38} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_zone_types.h b/src/core/hle/service/time/time_zone_types.h
deleted file mode 100644
index eb4fb52d1..000000000
--- a/src/core/hle/service/time/time_zone_types.h
+++ /dev/null
@@ -1,86 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10#include "common/swap.h"
11
12namespace Service::Time::TimeZone {
13
14using LocationName = std::array<char, 0x24>;
15
16/// https://switchbrew.org/wiki/Glue_services#ttinfo
17struct TimeTypeInfo {
18 s32 gmt_offset{};
19 u8 is_dst{};
20 INSERT_PADDING_BYTES(3);
21 s32 abbreviation_list_index{};
22 u8 is_standard_time_daylight{};
23 u8 is_gmt{};
24 INSERT_PADDING_BYTES(2);
25};
26static_assert(sizeof(TimeTypeInfo) == 0x10, "TimeTypeInfo is incorrect size");
27
28/// https://switchbrew.org/wiki/Glue_services#TimeZoneRule
29struct TimeZoneRule {
30 s32 time_count{};
31 s32 type_count{};
32 s32 char_count{};
33 u8 go_back{};
34 u8 go_ahead{};
35 INSERT_PADDING_BYTES(2);
36 std::array<s64, 1000> ats{};
37 std::array<s8, 1000> types{};
38 std::array<TimeTypeInfo, 128> ttis{};
39 std::array<char, 512> chars{};
40 s32 default_type{};
41 INSERT_PADDING_BYTES(0x12C4);
42};
43static_assert(sizeof(TimeZoneRule) == 0x4000, "TimeZoneRule is incorrect size");
44
45/// https://switchbrew.org/wiki/Glue_services#CalendarAdditionalInfo
46struct CalendarAdditionalInfo {
47 u32 day_of_week;
48 u32 day_of_year;
49 std::array<char, 8> timezone_name;
50 u32 is_dst;
51 s32 gmt_offset;
52};
53static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size");
54
55/// https://switchbrew.org/wiki/Glue_services#CalendarTime
56struct CalendarTime {
57 s16 year;
58 s8 month;
59 s8 day;
60 s8 hour;
61 s8 minute;
62 s8 second;
63 INSERT_PADDING_BYTES_NOINIT(1);
64};
65static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size");
66
67struct CalendarInfo {
68 CalendarTime time;
69 CalendarAdditionalInfo additional_info;
70};
71static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size");
72
73struct TzifHeader {
74 u32_be magic{};
75 u8 version{};
76 INSERT_PADDING_BYTES(15);
77 s32_be ttis_gmt_count{};
78 s32_be ttis_std_count{};
79 s32_be leap_count{};
80 s32_be time_count{};
81 s32_be type_count{};
82 s32_be char_count{};
83};
84static_assert(sizeof(TzifHeader) == 0x2C, "TzifHeader is incorrect size");
85
86} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index bfcc27ddc..1f3d82c57 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -15,6 +15,7 @@
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/math_util.h" 16#include "common/math_util.h"
17#include "common/settings.h" 17#include "common/settings.h"
18#include "common/string_util.h"
18#include "common/swap.h" 19#include "common/swap.h"
19#include "core/core_timing.h" 20#include "core/core_timing.h"
20#include "core/hle/kernel/k_readable_event.h" 21#include "core/hle/kernel/k_readable_event.h"
@@ -694,9 +695,7 @@ private:
694 void OpenLayer(HLERequestContext& ctx) { 695 void OpenLayer(HLERequestContext& ctx) {
695 IPC::RequestParser rp{ctx}; 696 IPC::RequestParser rp{ctx};
696 const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); 697 const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
697 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); 698 const std::string display_name(Common::StringFromBuffer(name_buf));
698
699 const std::string display_name(name_buf.begin(), end);
700 699
701 const u64 layer_id = rp.Pop<u64>(); 700 const u64 layer_id = rp.Pop<u64>();
702 const u64 aruid = rp.Pop<u64>(); 701 const u64 aruid = rp.Pop<u64>();
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 28116ff3a..3016d5f25 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -10,6 +10,7 @@
10#include "core/file_sys/nca_metadata.h" 10#include "core/file_sys/nca_metadata.h"
11#include "core/file_sys/patch_manager.h" 11#include "core/file_sys/patch_manager.h"
12#include "core/file_sys/registered_cache.h" 12#include "core/file_sys/registered_cache.h"
13#include "core/file_sys/romfs_factory.h"
13#include "core/file_sys/submission_package.h" 14#include "core/file_sys/submission_package.h"
14#include "core/hle/kernel/k_process.h" 15#include "core/hle/kernel/k_process.h"
15#include "core/hle/service/filesystem/filesystem.h" 16#include "core/hle/service/filesystem/filesystem.h"
@@ -109,6 +110,13 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
109 return result; 110 return result;
110 } 111 }
111 112
113 if (nsp->IsExtractedType()) {
114 system.GetFileSystemController().RegisterProcess(
115 process.GetProcessId(), {},
116 std::make_shared<FileSys::RomFSFactory>(*this, system.GetContentProvider(),
117 system.GetFileSystemController()));
118 }
119
112 FileSys::VirtualFile update_raw; 120 FileSys::VirtualFile update_raw;
113 if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { 121 if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
114 system.GetFileSystemController().SetPackedUpdate(process.GetProcessId(), 122 system.GetFileSystemController().SetPackedUpdate(process.GetProcessId(),
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 8176a41be..1c218566f 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -24,6 +24,8 @@
24#include "core/hle/kernel/k_process.h" 24#include "core/hle/kernel/k_process.h"
25#include "core/memory.h" 25#include "core/memory.h"
26#include "video_core/gpu.h" 26#include "video_core/gpu.h"
27#include "video_core/host1x/gpu_device_memory_manager.h"
28#include "video_core/host1x/host1x.h"
27#include "video_core/rasterizer_download_area.h" 29#include "video_core/rasterizer_download_area.h"
28 30
29namespace Core::Memory { 31namespace Core::Memory {
@@ -637,17 +639,6 @@ struct Memory::Impl {
637 LOG_DEBUG(HW_Memory, "Mapping {:016X} onto {:016X}-{:016X}", GetInteger(target), 639 LOG_DEBUG(HW_Memory, "Mapping {:016X} onto {:016X}-{:016X}", GetInteger(target),
638 base * YUZU_PAGESIZE, (base + size) * YUZU_PAGESIZE); 640 base * YUZU_PAGESIZE, (base + size) * YUZU_PAGESIZE);
639 641
640 // During boot, current_page_table might not be set yet, in which case we need not flush
641 if (system.IsPoweredOn()) {
642 auto& gpu = system.GPU();
643 for (u64 i = 0; i < size; i++) {
644 const auto page = base + i;
645 if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) {
646 gpu.FlushAndInvalidateRegion(page << YUZU_PAGEBITS, YUZU_PAGESIZE);
647 }
648 }
649 }
650
651 const auto end = base + size; 642 const auto end = base + size;
652 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", 643 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
653 base + page_table.pointers.size()); 644 base + page_table.pointers.size());
@@ -811,21 +802,33 @@ struct Memory::Impl {
811 return true; 802 return true;
812 } 803 }
813 804
814 void HandleRasterizerDownload(VAddr address, size_t size) { 805 void HandleRasterizerDownload(VAddr v_address, size_t size) {
806 const auto* p = GetPointerImpl(
807 v_address, []() {}, []() {});
808 if (!gpu_device_memory) [[unlikely]] {
809 gpu_device_memory = &system.Host1x().MemoryManager();
810 }
815 const size_t core = system.GetCurrentHostThreadID(); 811 const size_t core = system.GetCurrentHostThreadID();
816 auto& current_area = rasterizer_read_areas[core]; 812 auto& current_area = rasterizer_read_areas[core];
817 const VAddr end_address = address + size; 813 gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) {
818 if (current_area.start_address <= address && end_address <= current_area.end_address) 814 const DAddr end_address = address + size;
819 [[likely]] { 815 if (current_area.start_address <= address && end_address <= current_area.end_address)
820 return; 816 [[likely]] {
821 } 817 return;
822 current_area = system.GPU().OnCPURead(address, size); 818 }
819 current_area = system.GPU().OnCPURead(address, size);
820 });
823 } 821 }
824 822
825 void HandleRasterizerWrite(VAddr address, size_t size) { 823 void HandleRasterizerWrite(VAddr v_address, size_t size) {
824 const auto* p = GetPointerImpl(
825 v_address, []() {}, []() {});
826 constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1; 826 constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1;
827 const size_t core = std::min(system.GetCurrentHostThreadID(), 827 const size_t core = std::min(system.GetCurrentHostThreadID(),
828 sys_core); // any other calls threads go to syscore. 828 sys_core); // any other calls threads go to syscore.
829 if (!gpu_device_memory) [[unlikely]] {
830 gpu_device_memory = &system.Host1x().MemoryManager();
831 }
829 // Guard on sys_core; 832 // Guard on sys_core;
830 if (core == sys_core) [[unlikely]] { 833 if (core == sys_core) [[unlikely]] {
831 sys_core_guard.lock(); 834 sys_core_guard.lock();
@@ -835,36 +838,53 @@ struct Memory::Impl {
835 sys_core_guard.unlock(); 838 sys_core_guard.unlock();
836 } 839 }
837 }); 840 });
838 auto& current_area = rasterizer_write_areas[core]; 841 gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) {
839 VAddr subaddress = address >> YUZU_PAGEBITS; 842 auto& current_area = rasterizer_write_areas[core];
840 bool do_collection = current_area.last_address == subaddress; 843 PAddr subaddress = address >> YUZU_PAGEBITS;
841 if (!do_collection) [[unlikely]] { 844 bool do_collection = current_area.last_address == subaddress;
842 do_collection = system.GPU().OnCPUWrite(address, size); 845 if (!do_collection) [[unlikely]] {
843 if (!do_collection) { 846 do_collection = system.GPU().OnCPUWrite(address, size);
844 return; 847 if (!do_collection) {
848 return;
849 }
850 current_area.last_address = subaddress;
845 } 851 }
846 current_area.last_address = subaddress; 852 gpu_dirty_managers[core].Collect(address, size);
847 } 853 });
848 gpu_dirty_managers[core].Collect(address, size);
849 } 854 }
850 855
851 struct GPUDirtyState { 856 struct GPUDirtyState {
852 VAddr last_address; 857 PAddr last_address;
853 }; 858 };
854 859
855 void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) { 860 void InvalidateGPUMemory(u8* p, size_t size) {
856 system.GPU().InvalidateRegion(GetInteger(dest_addr), size); 861 constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1;
857 } 862 const size_t core = std::min(system.GetCurrentHostThreadID(),
858 863 sys_core); // any other calls threads go to syscore.
859 void FlushRegion(Common::ProcessAddress dest_addr, size_t size) { 864 if (!gpu_device_memory) [[unlikely]] {
860 system.GPU().FlushRegion(GetInteger(dest_addr), size); 865 gpu_device_memory = &system.Host1x().MemoryManager();
866 }
867 // Guard on sys_core;
868 if (core == sys_core) [[unlikely]] {
869 sys_core_guard.lock();
870 }
871 SCOPE_EXIT({
872 if (core == sys_core) [[unlikely]] {
873 sys_core_guard.unlock();
874 }
875 });
876 auto& gpu = system.GPU();
877 gpu_device_memory->ApplyOpOnPointer(
878 p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
861 } 879 }
862 880
863 Core::System& system; 881 Core::System& system;
882 Tegra::MaxwellDeviceMemoryManager* gpu_device_memory{};
864 Common::PageTable* current_page_table = nullptr; 883 Common::PageTable* current_page_table = nullptr;
865 std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> 884 std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES>
866 rasterizer_read_areas{}; 885 rasterizer_read_areas{};
867 std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{}; 886 std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
887 std::array<Common::ScratchBuffer<u32>, Core::Hardware::NUM_CPU_CORES> scratch_buffers{};
868 std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers; 888 std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
869 std::mutex sys_core_guard; 889 std::mutex sys_core_guard;
870 890
@@ -1059,14 +1079,6 @@ void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug)
1059 impl->MarkRegionDebug(GetInteger(vaddr), size, debug); 1079 impl->MarkRegionDebug(GetInteger(vaddr), size, debug);
1060} 1080}
1061 1081
1062void Memory::InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) {
1063 impl->InvalidateRegion(dest_addr, size);
1064}
1065
1066void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
1067 impl->FlushRegion(dest_addr, size);
1068}
1069
1070bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { 1082bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
1071 [[maybe_unused]] bool mapped = true; 1083 [[maybe_unused]] bool mapped = true;
1072 [[maybe_unused]] bool rasterizer = false; 1084 [[maybe_unused]] bool rasterizer = false;
@@ -1078,10 +1090,10 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
1078 GetInteger(vaddr)); 1090 GetInteger(vaddr));
1079 mapped = false; 1091 mapped = false;
1080 }, 1092 },
1081 [&] { 1093 [&] { rasterizer = true; });
1082 impl->system.GPU().InvalidateRegion(GetInteger(vaddr), size); 1094 if (rasterizer) {
1083 rasterizer = true; 1095 impl->InvalidateGPUMemory(ptr, size);
1084 }); 1096 }
1085 1097
1086#ifdef __linux__ 1098#ifdef __linux__
1087 if (!rasterizer && mapped) { 1099 if (!rasterizer && mapped) {
diff --git a/src/core/memory.h b/src/core/memory.h
index dddfaf4a4..f7e6b297f 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -12,6 +12,7 @@
12 12
13#include "common/scratch_buffer.h" 13#include "common/scratch_buffer.h"
14#include "common/typed_address.h" 14#include "common/typed_address.h"
15#include "core/guest_memory.h"
15#include "core/hle/result.h" 16#include "core/hle/result.h"
16 17
17namespace Common { 18namespace Common {
@@ -486,10 +487,10 @@ public:
486 void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); 487 void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug);
487 488
488 void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); 489 void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
489 void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size); 490
490 bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); 491 bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
492
491 bool InvalidateSeparateHeap(void* fault_address); 493 bool InvalidateSeparateHeap(void* fault_address);
492 void FlushRegion(Common::ProcessAddress dest_addr, size_t size);
493 494
494private: 495private:
495 Core::System& system; 496 Core::System& system;
@@ -498,209 +499,9 @@ private:
498 std::unique_ptr<Impl> impl; 499 std::unique_ptr<Impl> impl;
499}; 500};
500 501
501enum GuestMemoryFlags : u32 {
502 Read = 1 << 0,
503 Write = 1 << 1,
504 Safe = 1 << 2,
505 Cached = 1 << 3,
506
507 SafeRead = Read | Safe,
508 SafeWrite = Write | Safe,
509 SafeReadWrite = SafeRead | SafeWrite,
510 SafeReadCachedWrite = SafeReadWrite | Cached,
511
512 UnsafeRead = Read,
513 UnsafeWrite = Write,
514 UnsafeReadWrite = UnsafeRead | UnsafeWrite,
515 UnsafeReadCachedWrite = UnsafeReadWrite | Cached,
516};
517
518namespace {
519template <typename M, typename T, GuestMemoryFlags FLAGS>
520class GuestMemory {
521 using iterator = T*;
522 using const_iterator = const T*;
523 using value_type = T;
524 using element_type = T;
525 using iterator_category = std::contiguous_iterator_tag;
526
527public:
528 GuestMemory() = delete;
529 explicit GuestMemory(M& memory, u64 addr, std::size_t size,
530 Common::ScratchBuffer<T>* backup = nullptr)
531 : m_memory{memory}, m_addr{addr}, m_size{size} {
532 static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
533 if constexpr (FLAGS & GuestMemoryFlags::Read) {
534 Read(addr, size, backup);
535 }
536 }
537
538 ~GuestMemory() = default;
539
540 T* data() noexcept {
541 return m_data_span.data();
542 }
543
544 const T* data() const noexcept {
545 return m_data_span.data();
546 }
547
548 size_t size() const noexcept {
549 return m_size;
550 }
551
552 size_t size_bytes() const noexcept {
553 return this->size() * sizeof(T);
554 }
555
556 [[nodiscard]] T* begin() noexcept {
557 return this->data();
558 }
559
560 [[nodiscard]] const T* begin() const noexcept {
561 return this->data();
562 }
563
564 [[nodiscard]] T* end() noexcept {
565 return this->data() + this->size();
566 }
567
568 [[nodiscard]] const T* end() const noexcept {
569 return this->data() + this->size();
570 }
571
572 T& operator[](size_t index) noexcept {
573 return m_data_span[index];
574 }
575
576 const T& operator[](size_t index) const noexcept {
577 return m_data_span[index];
578 }
579
580 void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
581 m_addr = addr;
582 m_size = size;
583 m_addr_changed = true;
584 }
585
586 std::span<T> Read(u64 addr, std::size_t size,
587 Common::ScratchBuffer<T>* backup = nullptr) noexcept {
588 m_addr = addr;
589 m_size = size;
590 if (m_size == 0) {
591 m_is_data_copy = true;
592 return {};
593 }
594
595 if (this->TrySetSpan()) {
596 if constexpr (FLAGS & GuestMemoryFlags::Safe) {
597 m_memory.FlushRegion(m_addr, this->size_bytes());
598 }
599 } else {
600 if (backup) {
601 backup->resize_destructive(this->size());
602 m_data_span = *backup;
603 } else {
604 m_data_copy.resize(this->size());
605 m_data_span = std::span(m_data_copy);
606 }
607 m_is_data_copy = true;
608 m_span_valid = true;
609 if constexpr (FLAGS & GuestMemoryFlags::Safe) {
610 m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
611 } else {
612 m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
613 }
614 }
615 return m_data_span;
616 }
617
618 void Write(std::span<T> write_data) noexcept {
619 if constexpr (FLAGS & GuestMemoryFlags::Cached) {
620 m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
621 } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
622 m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
623 } else {
624 m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
625 }
626 }
627
628 bool TrySetSpan() noexcept {
629 if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
630 m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
631 m_span_valid = true;
632 return true;
633 }
634 return false;
635 }
636
637protected:
638 bool IsDataCopy() const noexcept {
639 return m_is_data_copy;
640 }
641
642 bool AddressChanged() const noexcept {
643 return m_addr_changed;
644 }
645
646 M& m_memory;
647 u64 m_addr{};
648 size_t m_size{};
649 std::span<T> m_data_span{};
650 std::vector<T> m_data_copy{};
651 bool m_span_valid{false};
652 bool m_is_data_copy{false};
653 bool m_addr_changed{false};
654};
655
656template <typename M, typename T, GuestMemoryFlags FLAGS>
657class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
658public:
659 GuestMemoryScoped() = delete;
660 explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
661 Common::ScratchBuffer<T>* backup = nullptr)
662 : GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
663 if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
664 if (!this->TrySetSpan()) {
665 if (backup) {
666 this->m_data_span = *backup;
667 this->m_span_valid = true;
668 this->m_is_data_copy = true;
669 }
670 }
671 }
672 }
673
674 ~GuestMemoryScoped() {
675 if constexpr (FLAGS & GuestMemoryFlags::Write) {
676 if (this->size() == 0) [[unlikely]] {
677 return;
678 }
679
680 if (this->AddressChanged() || this->IsDataCopy()) {
681 ASSERT(this->m_span_valid);
682 if constexpr (FLAGS & GuestMemoryFlags::Cached) {
683 this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
684 } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
685 this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
686 } else {
687 this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
688 }
689 } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
690 (FLAGS & GuestMemoryFlags::Cached)) {
691 this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
692 }
693 }
694 }
695};
696} // namespace
697
698template <typename T, GuestMemoryFlags FLAGS> 502template <typename T, GuestMemoryFlags FLAGS>
699using CpuGuestMemory = GuestMemory<Memory, T, FLAGS>; 503using CpuGuestMemory = GuestMemory<Core::Memory::Memory, T, FLAGS>;
700template <typename T, GuestMemoryFlags FLAGS> 504template <typename T, GuestMemoryFlags FLAGS>
701using CpuGuestMemoryScoped = GuestMemoryScoped<Memory, T, FLAGS>; 505using CpuGuestMemoryScoped = GuestMemoryScoped<Core::Memory::Memory, T, FLAGS>;
702template <typename T, GuestMemoryFlags FLAGS> 506
703using GpuGuestMemory = GuestMemory<Tegra::MemoryManager, T, FLAGS>;
704template <typename T, GuestMemoryFlags FLAGS>
705using GpuGuestMemoryScoped = GuestMemoryScoped<Tegra::MemoryManager, T, FLAGS>;
706} // namespace Core::Memory 507} // namespace Core::Memory
diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp
index 618793668..45b1a91dc 100644
--- a/src/tests/video_core/memory_tracker.cpp
+++ b/src/tests/video_core/memory_tracker.cpp
@@ -24,9 +24,8 @@ constexpr VAddr c = 16 * HIGH_PAGE_SIZE;
24class RasterizerInterface { 24class RasterizerInterface {
25public: 25public:
26 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { 26 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
27 const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS}; 27 const u64 page_start{addr >> Core::DEVICE_PAGEBITS};
28 const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >> 28 const u64 page_end{(addr + size + Core::DEVICE_PAGESIZE - 1) >> Core::DEVICE_PAGEBITS};
29 Core::Memory::YUZU_PAGEBITS};
30 for (u64 page = page_start; page < page_end; ++page) { 29 for (u64 page = page_start; page < page_end; ++page) {
31 int& value = page_table[page]; 30 int& value = page_table[page];
32 value += delta; 31 value += delta;
@@ -40,7 +39,7 @@ public:
40 } 39 }
41 40
42 [[nodiscard]] int Count(VAddr addr) const noexcept { 41 [[nodiscard]] int Count(VAddr addr) const noexcept {
43 const auto it = page_table.find(addr >> Core::Memory::YUZU_PAGEBITS); 42 const auto it = page_table.find(addr >> Core::DEVICE_PAGEBITS);
44 return it == page_table.end() ? 0 : it->second; 43 return it == page_table.end() ? 0 : it->second;
45 } 44 }
46 45
@@ -546,4 +545,4 @@ TEST_CASE("MemoryTracker: Cached write downloads") {
546 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); 545 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE));
547 memory_track->MarkRegionAsCpuModified(c, WORD); 546 memory_track->MarkRegionAsCpuModified(c, WORD);
548 REQUIRE(rasterizer.Count() == 0); 547 REQUIRE(rasterizer.Count() == 0);
549} \ No newline at end of file 548}
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index c22c7631c..5ed0ad0ed 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -71,6 +71,8 @@ add_library(video_core STATIC
71 host1x/ffmpeg/ffmpeg.h 71 host1x/ffmpeg/ffmpeg.h
72 host1x/control.cpp 72 host1x/control.cpp
73 host1x/control.h 73 host1x/control.h
74 host1x/gpu_device_memory_manager.cpp
75 host1x/gpu_device_memory_manager.h
74 host1x/host1x.cpp 76 host1x/host1x.cpp
75 host1x/host1x.h 77 host1x/host1x.h
76 host1x/nvdec.cpp 78 host1x/nvdec.cpp
@@ -93,6 +95,7 @@ add_library(video_core STATIC
93 gpu.h 95 gpu.h
94 gpu_thread.cpp 96 gpu_thread.cpp
95 gpu_thread.h 97 gpu_thread.h
98 guest_memory.h
96 invalidation_accumulator.h 99 invalidation_accumulator.h
97 memory_manager.cpp 100 memory_manager.cpp
98 memory_manager.h 101 memory_manager.h
@@ -105,8 +108,6 @@ add_library(video_core STATIC
105 query_cache/query_stream.h 108 query_cache/query_stream.h
106 query_cache/types.h 109 query_cache/types.h
107 query_cache.h 110 query_cache.h
108 rasterizer_accelerated.cpp
109 rasterizer_accelerated.h
110 rasterizer_interface.h 111 rasterizer_interface.h
111 renderer_base.cpp 112 renderer_base.cpp
112 renderer_base.h 113 renderer_base.h
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h
index 0bb3bf8ae..40e98e395 100644
--- a/src/video_core/buffer_cache/buffer_base.h
+++ b/src/video_core/buffer_cache/buffer_base.h
@@ -33,13 +33,12 @@ struct NullBufferParams {};
33 * 33 *
34 * The buffer size and address is forcefully aligned to CPU page boundaries. 34 * The buffer size and address is forcefully aligned to CPU page boundaries.
35 */ 35 */
36template <class RasterizerInterface>
37class BufferBase { 36class BufferBase {
38public: 37public:
39 static constexpr u64 BASE_PAGE_BITS = 16; 38 static constexpr u64 BASE_PAGE_BITS = 16;
40 static constexpr u64 BASE_PAGE_SIZE = 1ULL << BASE_PAGE_BITS; 39 static constexpr u64 BASE_PAGE_SIZE = 1ULL << BASE_PAGE_BITS;
41 40
42 explicit BufferBase(RasterizerInterface& rasterizer_, VAddr cpu_addr_, u64 size_bytes_) 41 explicit BufferBase(VAddr cpu_addr_, u64 size_bytes_)
43 : cpu_addr{cpu_addr_}, size_bytes{size_bytes_} {} 42 : cpu_addr{cpu_addr_}, size_bytes{size_bytes_} {}
44 43
45 explicit BufferBase(NullBufferParams) {} 44 explicit BufferBase(NullBufferParams) {}
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 6d1fc3887..b4bf369d1 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -8,16 +8,16 @@
8#include <numeric> 8#include <numeric>
9 9
10#include "video_core/buffer_cache/buffer_cache_base.h" 10#include "video_core/buffer_cache/buffer_cache_base.h"
11#include "video_core/guest_memory.h"
12#include "video_core/host1x/gpu_device_memory_manager.h"
11 13
12namespace VideoCommon { 14namespace VideoCommon {
13 15
14using Core::Memory::YUZU_PAGESIZE; 16using Core::DEVICE_PAGESIZE;
15 17
16template <class P> 18template <class P>
17BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_, 19BufferCache<P>::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, Runtime& runtime_)
18 Core::Memory::Memory& cpu_memory_, Runtime& runtime_) 20 : runtime{runtime_}, device_memory{device_memory_}, memory_tracker{device_memory} {
19 : runtime{runtime_}, rasterizer{rasterizer_}, cpu_memory{cpu_memory_}, memory_tracker{
20 rasterizer} {
21 // Ensure the first slot is used for the null buffer 21 // Ensure the first slot is used for the null buffer
22 void(slot_buffers.insert(runtime, NullBufferParams{})); 22 void(slot_buffers.insert(runtime, NullBufferParams{}));
23 common_ranges.clear(); 23 common_ranges.clear();
@@ -29,17 +29,17 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
29 return; 29 return;
30 } 30 }
31 31
32 const s64 device_memory = static_cast<s64>(runtime.GetDeviceLocalMemory()); 32 const s64 device_local_memory = static_cast<s64>(runtime.GetDeviceLocalMemory());
33 const s64 min_spacing_expected = device_memory - 1_GiB; 33 const s64 min_spacing_expected = device_local_memory - 1_GiB;
34 const s64 min_spacing_critical = device_memory - 512_MiB; 34 const s64 min_spacing_critical = device_local_memory - 512_MiB;
35 const s64 mem_threshold = std::min(device_memory, TARGET_THRESHOLD); 35 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
36 const s64 min_vacancy_expected = (6 * mem_threshold) / 10; 36 const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
37 const s64 min_vacancy_critical = (3 * mem_threshold) / 10; 37 const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
38 minimum_memory = static_cast<u64>( 38 minimum_memory = static_cast<u64>(
39 std::max(std::min(device_memory - min_vacancy_expected, min_spacing_expected), 39 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
40 DEFAULT_EXPECTED_MEMORY)); 40 DEFAULT_EXPECTED_MEMORY));
41 critical_memory = static_cast<u64>( 41 critical_memory = static_cast<u64>(
42 std::max(std::min(device_memory - min_vacancy_critical, min_spacing_critical), 42 std::max(std::min(device_local_memory - min_vacancy_critical, min_spacing_critical),
43 DEFAULT_CRITICAL_MEMORY)); 43 DEFAULT_CRITICAL_MEMORY));
44} 44}
45 45
@@ -105,71 +105,71 @@ void BufferCache<P>::TickFrame() {
105} 105}
106 106
107template <class P> 107template <class P>
108void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) { 108void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
109 if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) { 109 if (memory_tracker.IsRegionGpuModified(device_addr, size)) {
110 const IntervalType subtract_interval{cpu_addr, cpu_addr + size}; 110 const IntervalType subtract_interval{device_addr, device_addr + size};
111 ClearDownload(subtract_interval); 111 ClearDownload(subtract_interval);
112 common_ranges.subtract(subtract_interval); 112 common_ranges.subtract(subtract_interval);
113 } 113 }
114 memory_tracker.MarkRegionAsCpuModified(cpu_addr, size); 114 memory_tracker.MarkRegionAsCpuModified(device_addr, size);
115} 115}
116 116
117template <class P> 117template <class P>
118void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) { 118void BufferCache<P>::CachedWriteMemory(DAddr device_addr, u64 size) {
119 const bool is_dirty = IsRegionRegistered(cpu_addr, size); 119 const bool is_dirty = IsRegionRegistered(device_addr, size);
120 if (!is_dirty) { 120 if (!is_dirty) {
121 return; 121 return;
122 } 122 }
123 VAddr aligned_start = Common::AlignDown(cpu_addr, YUZU_PAGESIZE); 123 DAddr aligned_start = Common::AlignDown(device_addr, DEVICE_PAGESIZE);
124 VAddr aligned_end = Common::AlignUp(cpu_addr + size, YUZU_PAGESIZE); 124 DAddr aligned_end = Common::AlignUp(device_addr + size, DEVICE_PAGESIZE);
125 if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) { 125 if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
126 WriteMemory(cpu_addr, size); 126 WriteMemory(device_addr, size);
127 return; 127 return;
128 } 128 }
129 129
130 tmp_buffer.resize_destructive(size); 130 tmp_buffer.resize_destructive(size);
131 cpu_memory.ReadBlockUnsafe(cpu_addr, tmp_buffer.data(), size); 131 device_memory.ReadBlockUnsafe(device_addr, tmp_buffer.data(), size);
132 132
133 InlineMemoryImplementation(cpu_addr, size, tmp_buffer); 133 InlineMemoryImplementation(device_addr, size, tmp_buffer);
134} 134}
135 135
136template <class P> 136template <class P>
137bool BufferCache<P>::OnCPUWrite(VAddr cpu_addr, u64 size) { 137bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
138 const bool is_dirty = IsRegionRegistered(cpu_addr, size); 138 const bool is_dirty = IsRegionRegistered(device_addr, size);
139 if (!is_dirty) { 139 if (!is_dirty) {
140 return false; 140 return false;
141 } 141 }
142 if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) { 142 if (memory_tracker.IsRegionGpuModified(device_addr, size)) {
143 return true; 143 return true;
144 } 144 }
145 WriteMemory(cpu_addr, size); 145 WriteMemory(device_addr, size);
146 return false; 146 return false;
147} 147}
148 148
149template <class P> 149template <class P>
150std::optional<VideoCore::RasterizerDownloadArea> BufferCache<P>::GetFlushArea(VAddr cpu_addr, 150std::optional<VideoCore::RasterizerDownloadArea> BufferCache<P>::GetFlushArea(DAddr device_addr,
151 u64 size) { 151 u64 size) {
152 std::optional<VideoCore::RasterizerDownloadArea> area{}; 152 std::optional<VideoCore::RasterizerDownloadArea> area{};
153 area.emplace(); 153 area.emplace();
154 VAddr cpu_addr_start_aligned = Common::AlignDown(cpu_addr, Core::Memory::YUZU_PAGESIZE); 154 DAddr device_addr_start_aligned = Common::AlignDown(device_addr, Core::DEVICE_PAGESIZE);
155 VAddr cpu_addr_end_aligned = Common::AlignUp(cpu_addr + size, Core::Memory::YUZU_PAGESIZE); 155 DAddr device_addr_end_aligned = Common::AlignUp(device_addr + size, Core::DEVICE_PAGESIZE);
156 area->start_address = cpu_addr_start_aligned; 156 area->start_address = device_addr_start_aligned;
157 area->end_address = cpu_addr_end_aligned; 157 area->end_address = device_addr_end_aligned;
158 if (memory_tracker.IsRegionPreflushable(cpu_addr, size)) { 158 if (memory_tracker.IsRegionPreflushable(device_addr, size)) {
159 area->preemtive = true; 159 area->preemtive = true;
160 return area; 160 return area;
161 }; 161 };
162 area->preemtive = 162 area->preemtive = !IsRegionGpuModified(device_addr_start_aligned,
163 !IsRegionGpuModified(cpu_addr_start_aligned, cpu_addr_end_aligned - cpu_addr_start_aligned); 163 device_addr_end_aligned - device_addr_start_aligned);
164 memory_tracker.MarkRegionAsPreflushable(cpu_addr_start_aligned, 164 memory_tracker.MarkRegionAsPreflushable(device_addr_start_aligned,
165 cpu_addr_end_aligned - cpu_addr_start_aligned); 165 device_addr_end_aligned - device_addr_start_aligned);
166 return area; 166 return area;
167} 167}
168 168
169template <class P> 169template <class P>
170void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) { 170void BufferCache<P>::DownloadMemory(DAddr device_addr, u64 size) {
171 ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) { 171 ForEachBufferInRange(device_addr, size, [&](BufferId, Buffer& buffer) {
172 DownloadBufferMemory(buffer, cpu_addr, size); 172 DownloadBufferMemory(buffer, device_addr, size);
173 }); 173 });
174} 174}
175 175
@@ -184,8 +184,8 @@ void BufferCache<P>::ClearDownload(IntervalType subtract_interval) {
184 184
185template <class P> 185template <class P>
186bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) { 186bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
187 const std::optional<VAddr> cpu_src_address = gpu_memory->GpuToCpuAddress(src_address); 187 const std::optional<DAddr> cpu_src_address = gpu_memory->GpuToCpuAddress(src_address);
188 const std::optional<VAddr> cpu_dest_address = gpu_memory->GpuToCpuAddress(dest_address); 188 const std::optional<DAddr> cpu_dest_address = gpu_memory->GpuToCpuAddress(dest_address);
189 if (!cpu_src_address || !cpu_dest_address) { 189 if (!cpu_src_address || !cpu_dest_address) {
190 return false; 190 return false;
191 } 191 }
@@ -216,10 +216,10 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
216 }}; 216 }};
217 217
218 boost::container::small_vector<IntervalType, 4> tmp_intervals; 218 boost::container::small_vector<IntervalType, 4> tmp_intervals;
219 auto mirror = [&](VAddr base_address, VAddr base_address_end) { 219 auto mirror = [&](DAddr base_address, DAddr base_address_end) {
220 const u64 size = base_address_end - base_address; 220 const u64 size = base_address_end - base_address;
221 const VAddr diff = base_address - *cpu_src_address; 221 const DAddr diff = base_address - *cpu_src_address;
222 const VAddr new_base_address = *cpu_dest_address + diff; 222 const DAddr new_base_address = *cpu_dest_address + diff;
223 const IntervalType add_interval{new_base_address, new_base_address + size}; 223 const IntervalType add_interval{new_base_address, new_base_address + size};
224 tmp_intervals.push_back(add_interval); 224 tmp_intervals.push_back(add_interval);
225 uncommitted_ranges.add(add_interval); 225 uncommitted_ranges.add(add_interval);
@@ -239,15 +239,15 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
239 memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); 239 memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount);
240 } 240 }
241 241
242 Core::Memory::CpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadWrite> tmp( 242 Tegra::Memory::DeviceGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::UnsafeReadWrite>
243 cpu_memory, *cpu_src_address, amount, &tmp_buffer); 243 tmp(device_memory, *cpu_src_address, amount, &tmp_buffer);
244 tmp.SetAddressAndSize(*cpu_dest_address, amount); 244 tmp.SetAddressAndSize(*cpu_dest_address, amount);
245 return true; 245 return true;
246} 246}
247 247
248template <class P> 248template <class P>
249bool BufferCache<P>::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) { 249bool BufferCache<P>::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) {
250 const std::optional<VAddr> cpu_dst_address = gpu_memory->GpuToCpuAddress(dst_address); 250 const std::optional<DAddr> cpu_dst_address = gpu_memory->GpuToCpuAddress(dst_address);
251 if (!cpu_dst_address) { 251 if (!cpu_dst_address) {
252 return false; 252 return false;
253 } 253 }
@@ -273,23 +273,23 @@ template <class P>
273std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_addr, u32 size, 273std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_addr, u32 size,
274 ObtainBufferSynchronize sync_info, 274 ObtainBufferSynchronize sync_info,
275 ObtainBufferOperation post_op) { 275 ObtainBufferOperation post_op) {
276 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 276 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
277 if (!cpu_addr) { 277 if (!device_addr) {
278 return {&slot_buffers[NULL_BUFFER_ID], 0}; 278 return {&slot_buffers[NULL_BUFFER_ID], 0};
279 } 279 }
280 return ObtainCPUBuffer(*cpu_addr, size, sync_info, post_op); 280 return ObtainCPUBuffer(*device_addr, size, sync_info, post_op);
281} 281}
282 282
283template <class P> 283template <class P>
284std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainCPUBuffer( 284std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainCPUBuffer(
285 VAddr cpu_addr, u32 size, ObtainBufferSynchronize sync_info, ObtainBufferOperation post_op) { 285 DAddr device_addr, u32 size, ObtainBufferSynchronize sync_info, ObtainBufferOperation post_op) {
286 const BufferId buffer_id = FindBuffer(cpu_addr, size); 286 const BufferId buffer_id = FindBuffer(device_addr, size);
287 Buffer& buffer = slot_buffers[buffer_id]; 287 Buffer& buffer = slot_buffers[buffer_id];
288 288
289 // synchronize op 289 // synchronize op
290 switch (sync_info) { 290 switch (sync_info) {
291 case ObtainBufferSynchronize::FullSynchronize: 291 case ObtainBufferSynchronize::FullSynchronize:
292 SynchronizeBuffer(buffer, cpu_addr, size); 292 SynchronizeBuffer(buffer, device_addr, size);
293 break; 293 break;
294 default: 294 default:
295 break; 295 break;
@@ -297,12 +297,12 @@ std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainCPUBuffer(
297 297
298 switch (post_op) { 298 switch (post_op) {
299 case ObtainBufferOperation::MarkAsWritten: 299 case ObtainBufferOperation::MarkAsWritten:
300 MarkWrittenBuffer(buffer_id, cpu_addr, size); 300 MarkWrittenBuffer(buffer_id, device_addr, size);
301 break; 301 break;
302 case ObtainBufferOperation::DiscardWrite: { 302 case ObtainBufferOperation::DiscardWrite: {
303 VAddr cpu_addr_start = Common::AlignDown(cpu_addr, 64); 303 DAddr device_addr_start = Common::AlignDown(device_addr, 64);
304 VAddr cpu_addr_end = Common::AlignUp(cpu_addr + size, 64); 304 DAddr device_addr_end = Common::AlignUp(device_addr + size, 64);
305 IntervalType interval{cpu_addr_start, cpu_addr_end}; 305 IntervalType interval{device_addr_start, device_addr_end};
306 ClearDownload(interval); 306 ClearDownload(interval);
307 common_ranges.subtract(interval); 307 common_ranges.subtract(interval);
308 break; 308 break;
@@ -311,15 +311,15 @@ std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainCPUBuffer(
311 break; 311 break;
312 } 312 }
313 313
314 return {&buffer, buffer.Offset(cpu_addr)}; 314 return {&buffer, buffer.Offset(device_addr)};
315} 315}
316 316
317template <class P> 317template <class P>
318void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, 318void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr,
319 u32 size) { 319 u32 size) {
320 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 320 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
321 const Binding binding{ 321 const Binding binding{
322 .cpu_addr = *cpu_addr, 322 .device_addr = *device_addr,
323 .size = size, 323 .size = size,
324 .buffer_id = BufferId{}, 324 .buffer_id = BufferId{},
325 }; 325 };
@@ -555,16 +555,17 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
555 for (const IntervalSet& intervals : committed_ranges) { 555 for (const IntervalSet& intervals : committed_ranges) {
556 for (auto& interval : intervals) { 556 for (auto& interval : intervals) {
557 const std::size_t size = interval.upper() - interval.lower(); 557 const std::size_t size = interval.upper() - interval.lower();
558 const VAddr cpu_addr = interval.lower(); 558 const DAddr device_addr = interval.lower();
559 ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) { 559 ForEachBufferInRange(device_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
560 const VAddr buffer_start = buffer.CpuAddr(); 560 const DAddr buffer_start = buffer.CpuAddr();
561 const VAddr buffer_end = buffer_start + buffer.SizeBytes(); 561 const DAddr buffer_end = buffer_start + buffer.SizeBytes();
562 const VAddr new_start = std::max(buffer_start, cpu_addr); 562 const DAddr new_start = std::max(buffer_start, device_addr);
563 const VAddr new_end = std::min(buffer_end, cpu_addr + size); 563 const DAddr new_end = std::min(buffer_end, device_addr + size);
564 memory_tracker.ForEachDownloadRange( 564 memory_tracker.ForEachDownloadRange(
565 new_start, new_end - new_start, false, [&](u64 cpu_addr_out, u64 range_size) { 565 new_start, new_end - new_start, false,
566 const VAddr buffer_addr = buffer.CpuAddr(); 566 [&](u64 device_addr_out, u64 range_size) {
567 const auto add_download = [&](VAddr start, VAddr end) { 567 const DAddr buffer_addr = buffer.CpuAddr();
568 const auto add_download = [&](DAddr start, DAddr end) {
568 const u64 new_offset = start - buffer_addr; 569 const u64 new_offset = start - buffer_addr;
569 const u64 new_size = end - start; 570 const u64 new_size = end - start;
570 downloads.push_back({ 571 downloads.push_back({
@@ -582,7 +583,7 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
582 largest_copy = std::max(largest_copy, new_size); 583 largest_copy = std::max(largest_copy, new_size);
583 }; 584 };
584 585
585 ForEachInRangeSet(common_ranges, cpu_addr_out, range_size, add_download); 586 ForEachInRangeSet(common_ranges, device_addr_out, range_size, add_download);
586 }); 587 });
587 }); 588 });
588 } 589 }
@@ -605,8 +606,8 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
605 BufferCopy second_copy{copy}; 606 BufferCopy second_copy{copy};
606 Buffer& buffer = slot_buffers[buffer_id]; 607 Buffer& buffer = slot_buffers[buffer_id];
607 second_copy.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset; 608 second_copy.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset;
608 VAddr orig_cpu_addr = static_cast<VAddr>(second_copy.src_offset); 609 DAddr orig_device_addr = static_cast<DAddr>(second_copy.src_offset);
609 const IntervalType base_interval{orig_cpu_addr, orig_cpu_addr + copy.size}; 610 const IntervalType base_interval{orig_device_addr, orig_device_addr + copy.size};
610 async_downloads += std::make_pair(base_interval, 1); 611 async_downloads += std::make_pair(base_interval, 1);
611 buffer.MarkUsage(copy.src_offset, copy.size); 612 buffer.MarkUsage(copy.src_offset, copy.size);
612 runtime.CopyBuffer(download_staging.buffer, buffer, copies, false); 613 runtime.CopyBuffer(download_staging.buffer, buffer, copies, false);
@@ -635,11 +636,11 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
635 runtime.Finish(); 636 runtime.Finish();
636 for (const auto& [copy, buffer_id] : downloads) { 637 for (const auto& [copy, buffer_id] : downloads) {
637 const Buffer& buffer = slot_buffers[buffer_id]; 638 const Buffer& buffer = slot_buffers[buffer_id];
638 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; 639 const DAddr device_addr = buffer.CpuAddr() + copy.src_offset;
639 // Undo the modified offset 640 // Undo the modified offset
640 const u64 dst_offset = copy.dst_offset - download_staging.offset; 641 const u64 dst_offset = copy.dst_offset - download_staging.offset;
641 const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset; 642 const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset;
642 cpu_memory.WriteBlockUnsafe(cpu_addr, read_mapped_memory, copy.size); 643 device_memory.WriteBlockUnsafe(device_addr, read_mapped_memory, copy.size);
643 } 644 }
644 } else { 645 } else {
645 const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy); 646 const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
@@ -647,8 +648,8 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
647 Buffer& buffer = slot_buffers[buffer_id]; 648 Buffer& buffer = slot_buffers[buffer_id];
648 buffer.ImmediateDownload(copy.src_offset, 649 buffer.ImmediateDownload(copy.src_offset,
649 immediate_buffer.subspan(0, copy.size)); 650 immediate_buffer.subspan(0, copy.size));
650 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; 651 const DAddr device_addr = buffer.CpuAddr() + copy.src_offset;
651 cpu_memory.WriteBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size); 652 device_memory.WriteBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
652 } 653 }
653 } 654 }
654 } 655 }
@@ -681,19 +682,19 @@ void BufferCache<P>::PopAsyncBuffers() {
681 u8* base = async_buffer->mapped_span.data(); 682 u8* base = async_buffer->mapped_span.data();
682 const size_t base_offset = async_buffer->offset; 683 const size_t base_offset = async_buffer->offset;
683 for (const auto& copy : downloads) { 684 for (const auto& copy : downloads) {
684 const VAddr cpu_addr = static_cast<VAddr>(copy.src_offset); 685 const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
685 const u64 dst_offset = copy.dst_offset - base_offset; 686 const u64 dst_offset = copy.dst_offset - base_offset;
686 const u8* read_mapped_memory = base + dst_offset; 687 const u8* read_mapped_memory = base + dst_offset;
687 ForEachInOverlapCounter( 688 ForEachInOverlapCounter(
688 async_downloads, cpu_addr, copy.size, [&](VAddr start, VAddr end, int count) { 689 async_downloads, device_addr, copy.size, [&](DAddr start, DAddr end, int count) {
689 cpu_memory.WriteBlockUnsafe(start, &read_mapped_memory[start - cpu_addr], 690 device_memory.WriteBlockUnsafe(start, &read_mapped_memory[start - device_addr],
690 end - start); 691 end - start);
691 if (count == 1) { 692 if (count == 1) {
692 const IntervalType base_interval{start, end}; 693 const IntervalType base_interval{start, end};
693 common_ranges.subtract(base_interval); 694 common_ranges.subtract(base_interval);
694 } 695 }
695 }); 696 });
696 const IntervalType subtract_interval{cpu_addr, cpu_addr + copy.size}; 697 const IntervalType subtract_interval{device_addr, device_addr + copy.size};
697 RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1); 698 RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1);
698 } 699 }
699 async_buffers_death_ring.emplace_back(*async_buffer); 700 async_buffers_death_ring.emplace_back(*async_buffer);
@@ -703,15 +704,15 @@ void BufferCache<P>::PopAsyncBuffers() {
703} 704}
704 705
705template <class P> 706template <class P>
706bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) { 707bool BufferCache<P>::IsRegionGpuModified(DAddr addr, size_t size) {
707 bool is_dirty = false; 708 bool is_dirty = false;
708 ForEachInRangeSet(common_ranges, addr, size, [&](VAddr, VAddr) { is_dirty = true; }); 709 ForEachInRangeSet(common_ranges, addr, size, [&](DAddr, DAddr) { is_dirty = true; });
709 return is_dirty; 710 return is_dirty;
710} 711}
711 712
712template <class P> 713template <class P>
713bool BufferCache<P>::IsRegionRegistered(VAddr addr, size_t size) { 714bool BufferCache<P>::IsRegionRegistered(DAddr addr, size_t size) {
714 const VAddr end_addr = addr + size; 715 const DAddr end_addr = addr + size;
715 const u64 page_end = Common::DivCeil(end_addr, CACHING_PAGESIZE); 716 const u64 page_end = Common::DivCeil(end_addr, CACHING_PAGESIZE);
716 for (u64 page = addr >> CACHING_PAGEBITS; page < page_end;) { 717 for (u64 page = addr >> CACHING_PAGEBITS; page < page_end;) {
717 const BufferId buffer_id = page_table[page]; 718 const BufferId buffer_id = page_table[page];
@@ -720,8 +721,8 @@ bool BufferCache<P>::IsRegionRegistered(VAddr addr, size_t size) {
720 continue; 721 continue;
721 } 722 }
722 Buffer& buffer = slot_buffers[buffer_id]; 723 Buffer& buffer = slot_buffers[buffer_id];
723 const VAddr buf_start_addr = buffer.CpuAddr(); 724 const DAddr buf_start_addr = buffer.CpuAddr();
724 const VAddr buf_end_addr = buf_start_addr + buffer.SizeBytes(); 725 const DAddr buf_end_addr = buf_start_addr + buffer.SizeBytes();
725 if (buf_start_addr < end_addr && addr < buf_end_addr) { 726 if (buf_start_addr < end_addr && addr < buf_end_addr) {
726 return true; 727 return true;
727 } 728 }
@@ -731,7 +732,7 @@ bool BufferCache<P>::IsRegionRegistered(VAddr addr, size_t size) {
731} 732}
732 733
733template <class P> 734template <class P>
734bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) { 735bool BufferCache<P>::IsRegionCpuModified(DAddr addr, size_t size) {
735 return memory_tracker.IsRegionCpuModified(addr, size); 736 return memory_tracker.IsRegionCpuModified(addr, size);
736} 737}
737 738
@@ -739,7 +740,7 @@ template <class P>
739void BufferCache<P>::BindHostIndexBuffer() { 740void BufferCache<P>::BindHostIndexBuffer() {
740 Buffer& buffer = slot_buffers[channel_state->index_buffer.buffer_id]; 741 Buffer& buffer = slot_buffers[channel_state->index_buffer.buffer_id];
741 TouchBuffer(buffer, channel_state->index_buffer.buffer_id); 742 TouchBuffer(buffer, channel_state->index_buffer.buffer_id);
742 const u32 offset = buffer.Offset(channel_state->index_buffer.cpu_addr); 743 const u32 offset = buffer.Offset(channel_state->index_buffer.device_addr);
743 const u32 size = channel_state->index_buffer.size; 744 const u32 size = channel_state->index_buffer.size;
744 const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); 745 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
745 if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] { 746 if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] {
@@ -754,7 +755,7 @@ void BufferCache<P>::BindHostIndexBuffer() {
754 buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes); 755 buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes);
755 } 756 }
756 } else { 757 } else {
757 SynchronizeBuffer(buffer, channel_state->index_buffer.cpu_addr, size); 758 SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size);
758 } 759 }
759 if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { 760 if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
760 const u32 new_offset = 761 const u32 new_offset =
@@ -777,7 +778,7 @@ void BufferCache<P>::BindHostVertexBuffers() {
777 const Binding& binding = channel_state->vertex_buffers[index]; 778 const Binding& binding = channel_state->vertex_buffers[index];
778 Buffer& buffer = slot_buffers[binding.buffer_id]; 779 Buffer& buffer = slot_buffers[binding.buffer_id];
779 TouchBuffer(buffer, binding.buffer_id); 780 TouchBuffer(buffer, binding.buffer_id);
780 SynchronizeBuffer(buffer, binding.cpu_addr, binding.size); 781 SynchronizeBuffer(buffer, binding.device_addr, binding.size);
781 if (!flags[Dirty::VertexBuffer0 + index]) { 782 if (!flags[Dirty::VertexBuffer0 + index]) {
782 continue; 783 continue;
783 } 784 }
@@ -797,7 +798,7 @@ void BufferCache<P>::BindHostVertexBuffers() {
797 Buffer& buffer = slot_buffers[binding.buffer_id]; 798 Buffer& buffer = slot_buffers[binding.buffer_id];
798 799
799 const u32 stride = maxwell3d->regs.vertex_streams[index].stride; 800 const u32 stride = maxwell3d->regs.vertex_streams[index].stride;
800 const u32 offset = buffer.Offset(binding.cpu_addr); 801 const u32 offset = buffer.Offset(binding.device_addr);
801 buffer.MarkUsage(offset, binding.size); 802 buffer.MarkUsage(offset, binding.size);
802 803
803 host_bindings.buffers.push_back(&buffer); 804 host_bindings.buffers.push_back(&buffer);
@@ -814,7 +815,7 @@ void BufferCache<P>::BindHostDrawIndirectBuffers() {
814 const auto bind_buffer = [this](const Binding& binding) { 815 const auto bind_buffer = [this](const Binding& binding) {
815 Buffer& buffer = slot_buffers[binding.buffer_id]; 816 Buffer& buffer = slot_buffers[binding.buffer_id];
816 TouchBuffer(buffer, binding.buffer_id); 817 TouchBuffer(buffer, binding.buffer_id);
817 SynchronizeBuffer(buffer, binding.cpu_addr, binding.size); 818 SynchronizeBuffer(buffer, binding.device_addr, binding.size);
818 }; 819 };
819 if (current_draw_indirect->include_count) { 820 if (current_draw_indirect->include_count) {
820 bind_buffer(channel_state->count_buffer_binding); 821 bind_buffer(channel_state->count_buffer_binding);
@@ -842,13 +843,13 @@ template <class P>
842void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 binding_index, 843void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 binding_index,
843 bool needs_bind) { 844 bool needs_bind) {
844 const Binding& binding = channel_state->uniform_buffers[stage][index]; 845 const Binding& binding = channel_state->uniform_buffers[stage][index];
845 const VAddr cpu_addr = binding.cpu_addr; 846 const DAddr device_addr = binding.device_addr;
846 const u32 size = std::min(binding.size, (*channel_state->uniform_buffer_sizes)[stage][index]); 847 const u32 size = std::min(binding.size, (*channel_state->uniform_buffer_sizes)[stage][index]);
847 Buffer& buffer = slot_buffers[binding.buffer_id]; 848 Buffer& buffer = slot_buffers[binding.buffer_id];
848 TouchBuffer(buffer, binding.buffer_id); 849 TouchBuffer(buffer, binding.buffer_id);
849 const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID && 850 const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID &&
850 size <= channel_state->uniform_buffer_skip_cache_size && 851 size <= channel_state->uniform_buffer_skip_cache_size &&
851 !memory_tracker.IsRegionGpuModified(cpu_addr, size); 852 !memory_tracker.IsRegionGpuModified(device_addr, size);
852 if (use_fast_buffer) { 853 if (use_fast_buffer) {
853 if constexpr (IS_OPENGL) { 854 if constexpr (IS_OPENGL) {
854 if (runtime.HasFastBufferSubData()) { 855 if (runtime.HasFastBufferSubData()) {
@@ -862,7 +863,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
862 channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size; 863 channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
863 runtime.BindFastUniformBuffer(stage, binding_index, size); 864 runtime.BindFastUniformBuffer(stage, binding_index, size);
864 } 865 }
865 const auto span = ImmediateBufferWithData(cpu_addr, size); 866 const auto span = ImmediateBufferWithData(device_addr, size);
866 runtime.PushFastUniformBuffer(stage, binding_index, span); 867 runtime.PushFastUniformBuffer(stage, binding_index, span);
867 return; 868 return;
868 } 869 }
@@ -873,11 +874,11 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
873 } 874 }
874 // Stream buffer path to avoid stalling on non-Nvidia drivers or Vulkan 875 // Stream buffer path to avoid stalling on non-Nvidia drivers or Vulkan
875 const std::span<u8> span = runtime.BindMappedUniformBuffer(stage, binding_index, size); 876 const std::span<u8> span = runtime.BindMappedUniformBuffer(stage, binding_index, size);
876 cpu_memory.ReadBlockUnsafe(cpu_addr, span.data(), size); 877 device_memory.ReadBlockUnsafe(device_addr, span.data(), size);
877 return; 878 return;
878 } 879 }
879 // Classic cached path 880 // Classic cached path
880 const bool sync_cached = SynchronizeBuffer(buffer, cpu_addr, size); 881 const bool sync_cached = SynchronizeBuffer(buffer, device_addr, size);
881 if (sync_cached) { 882 if (sync_cached) {
882 ++channel_state->uniform_cache_hits[0]; 883 ++channel_state->uniform_cache_hits[0];
883 } 884 }
@@ -892,7 +893,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
892 if (!needs_bind) { 893 if (!needs_bind) {
893 return; 894 return;
894 } 895 }
895 const u32 offset = buffer.Offset(cpu_addr); 896 const u32 offset = buffer.Offset(device_addr);
896 if constexpr (IS_OPENGL) { 897 if constexpr (IS_OPENGL) {
897 // Fast buffer will be unbound 898 // Fast buffer will be unbound
898 channel_state->fast_bound_uniform_buffers[stage] &= ~(1U << binding_index); 899 channel_state->fast_bound_uniform_buffers[stage] &= ~(1U << binding_index);
@@ -920,14 +921,14 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
920 Buffer& buffer = slot_buffers[binding.buffer_id]; 921 Buffer& buffer = slot_buffers[binding.buffer_id];
921 TouchBuffer(buffer, binding.buffer_id); 922 TouchBuffer(buffer, binding.buffer_id);
922 const u32 size = binding.size; 923 const u32 size = binding.size;
923 SynchronizeBuffer(buffer, binding.cpu_addr, size); 924 SynchronizeBuffer(buffer, binding.device_addr, size);
924 925
925 const u32 offset = buffer.Offset(binding.cpu_addr); 926 const u32 offset = buffer.Offset(binding.device_addr);
926 buffer.MarkUsage(offset, size); 927 buffer.MarkUsage(offset, size);
927 const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0; 928 const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0;
928 929
929 if (is_written) { 930 if (is_written) {
930 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size); 931 MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
931 } 932 }
932 933
933 if constexpr (NEEDS_BIND_STORAGE_INDEX) { 934 if constexpr (NEEDS_BIND_STORAGE_INDEX) {
@@ -945,14 +946,14 @@ void BufferCache<P>::BindHostGraphicsTextureBuffers(size_t stage) {
945 const TextureBufferBinding& binding = channel_state->texture_buffers[stage][index]; 946 const TextureBufferBinding& binding = channel_state->texture_buffers[stage][index];
946 Buffer& buffer = slot_buffers[binding.buffer_id]; 947 Buffer& buffer = slot_buffers[binding.buffer_id];
947 const u32 size = binding.size; 948 const u32 size = binding.size;
948 SynchronizeBuffer(buffer, binding.cpu_addr, size); 949 SynchronizeBuffer(buffer, binding.device_addr, size);
949 950
950 const bool is_written = ((channel_state->written_texture_buffers[stage] >> index) & 1) != 0; 951 const bool is_written = ((channel_state->written_texture_buffers[stage] >> index) & 1) != 0;
951 if (is_written) { 952 if (is_written) {
952 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size); 953 MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
953 } 954 }
954 955
955 const u32 offset = buffer.Offset(binding.cpu_addr); 956 const u32 offset = buffer.Offset(binding.device_addr);
956 const PixelFormat format = binding.format; 957 const PixelFormat format = binding.format;
957 buffer.MarkUsage(offset, size); 958 buffer.MarkUsage(offset, size);
958 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { 959 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
@@ -982,11 +983,11 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
982 Buffer& buffer = slot_buffers[binding.buffer_id]; 983 Buffer& buffer = slot_buffers[binding.buffer_id];
983 TouchBuffer(buffer, binding.buffer_id); 984 TouchBuffer(buffer, binding.buffer_id);
984 const u32 size = binding.size; 985 const u32 size = binding.size;
985 SynchronizeBuffer(buffer, binding.cpu_addr, size); 986 SynchronizeBuffer(buffer, binding.device_addr, size);
986 987
987 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size); 988 MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
988 989
989 const u32 offset = buffer.Offset(binding.cpu_addr); 990 const u32 offset = buffer.Offset(binding.device_addr);
990 buffer.MarkUsage(offset, size); 991 buffer.MarkUsage(offset, size);
991 host_bindings.buffers.push_back(&buffer); 992 host_bindings.buffers.push_back(&buffer);
992 host_bindings.offsets.push_back(offset); 993 host_bindings.offsets.push_back(offset);
@@ -1011,9 +1012,9 @@ void BufferCache<P>::BindHostComputeUniformBuffers() {
1011 TouchBuffer(buffer, binding.buffer_id); 1012 TouchBuffer(buffer, binding.buffer_id);
1012 const u32 size = 1013 const u32 size =
1013 std::min(binding.size, (*channel_state->compute_uniform_buffer_sizes)[index]); 1014 std::min(binding.size, (*channel_state->compute_uniform_buffer_sizes)[index]);
1014 SynchronizeBuffer(buffer, binding.cpu_addr, size); 1015 SynchronizeBuffer(buffer, binding.device_addr, size);
1015 1016
1016 const u32 offset = buffer.Offset(binding.cpu_addr); 1017 const u32 offset = buffer.Offset(binding.device_addr);
1017 buffer.MarkUsage(offset, size); 1018 buffer.MarkUsage(offset, size);
1018 if constexpr (NEEDS_BIND_UNIFORM_INDEX) { 1019 if constexpr (NEEDS_BIND_UNIFORM_INDEX) {
1019 runtime.BindComputeUniformBuffer(binding_index, buffer, offset, size); 1020 runtime.BindComputeUniformBuffer(binding_index, buffer, offset, size);
@@ -1032,15 +1033,15 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
1032 Buffer& buffer = slot_buffers[binding.buffer_id]; 1033 Buffer& buffer = slot_buffers[binding.buffer_id];
1033 TouchBuffer(buffer, binding.buffer_id); 1034 TouchBuffer(buffer, binding.buffer_id);
1034 const u32 size = binding.size; 1035 const u32 size = binding.size;
1035 SynchronizeBuffer(buffer, binding.cpu_addr, size); 1036 SynchronizeBuffer(buffer, binding.device_addr, size);
1036 1037
1037 const u32 offset = buffer.Offset(binding.cpu_addr); 1038 const u32 offset = buffer.Offset(binding.device_addr);
1038 buffer.MarkUsage(offset, size); 1039 buffer.MarkUsage(offset, size);
1039 const bool is_written = 1040 const bool is_written =
1040 ((channel_state->written_compute_storage_buffers >> index) & 1) != 0; 1041 ((channel_state->written_compute_storage_buffers >> index) & 1) != 0;
1041 1042
1042 if (is_written) { 1043 if (is_written) {
1043 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size); 1044 MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
1044 } 1045 }
1045 1046
1046 if constexpr (NEEDS_BIND_STORAGE_INDEX) { 1047 if constexpr (NEEDS_BIND_STORAGE_INDEX) {
@@ -1058,15 +1059,15 @@ void BufferCache<P>::BindHostComputeTextureBuffers() {
1058 const TextureBufferBinding& binding = channel_state->compute_texture_buffers[index]; 1059 const TextureBufferBinding& binding = channel_state->compute_texture_buffers[index];
1059 Buffer& buffer = slot_buffers[binding.buffer_id]; 1060 Buffer& buffer = slot_buffers[binding.buffer_id];
1060 const u32 size = binding.size; 1061 const u32 size = binding.size;
1061 SynchronizeBuffer(buffer, binding.cpu_addr, size); 1062 SynchronizeBuffer(buffer, binding.device_addr, size);
1062 1063
1063 const bool is_written = 1064 const bool is_written =
1064 ((channel_state->written_compute_texture_buffers >> index) & 1) != 0; 1065 ((channel_state->written_compute_texture_buffers >> index) & 1) != 0;
1065 if (is_written) { 1066 if (is_written) {
1066 MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size); 1067 MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
1067 } 1068 }
1068 1069
1069 const u32 offset = buffer.Offset(binding.cpu_addr); 1070 const u32 offset = buffer.Offset(binding.device_addr);
1070 const PixelFormat format = binding.format; 1071 const PixelFormat format = binding.format;
1071 buffer.MarkUsage(offset, size); 1072 buffer.MarkUsage(offset, size);
1072 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { 1073 if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
@@ -1131,7 +1132,7 @@ void BufferCache<P>::UpdateIndexBuffer() {
1131 inline_buffer_id = CreateBuffer(0, buffer_size); 1132 inline_buffer_id = CreateBuffer(0, buffer_size);
1132 } 1133 }
1133 channel_state->index_buffer = Binding{ 1134 channel_state->index_buffer = Binding{
1134 .cpu_addr = 0, 1135 .device_addr = 0,
1135 .size = inline_index_size, 1136 .size = inline_index_size,
1136 .buffer_id = inline_buffer_id, 1137 .buffer_id = inline_buffer_id,
1137 }; 1138 };
@@ -1140,19 +1141,19 @@ void BufferCache<P>::UpdateIndexBuffer() {
1140 1141
1141 const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress(); 1142 const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress();
1142 const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress(); 1143 const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
1143 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin); 1144 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
1144 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin); 1145 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
1145 const u32 draw_size = 1146 const u32 draw_size =
1146 (index_buffer_ref.count + index_buffer_ref.first) * index_buffer_ref.FormatSizeInBytes(); 1147 (index_buffer_ref.count + index_buffer_ref.first) * index_buffer_ref.FormatSizeInBytes();
1147 const u32 size = std::min(address_size, draw_size); 1148 const u32 size = std::min(address_size, draw_size);
1148 if (size == 0 || !cpu_addr) { 1149 if (size == 0 || !device_addr) {
1149 channel_state->index_buffer = NULL_BINDING; 1150 channel_state->index_buffer = NULL_BINDING;
1150 return; 1151 return;
1151 } 1152 }
1152 channel_state->index_buffer = Binding{ 1153 channel_state->index_buffer = Binding{
1153 .cpu_addr = *cpu_addr, 1154 .device_addr = *device_addr,
1154 .size = size, 1155 .size = size,
1155 .buffer_id = FindBuffer(*cpu_addr, size), 1156 .buffer_id = FindBuffer(*device_addr, size),
1156 }; 1157 };
1157} 1158}
1158 1159
@@ -1178,19 +1179,19 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
1178 const auto& limit = maxwell3d->regs.vertex_stream_limits[index]; 1179 const auto& limit = maxwell3d->regs.vertex_stream_limits[index];
1179 const GPUVAddr gpu_addr_begin = array.Address(); 1180 const GPUVAddr gpu_addr_begin = array.Address();
1180 const GPUVAddr gpu_addr_end = limit.Address() + 1; 1181 const GPUVAddr gpu_addr_end = limit.Address() + 1;
1181 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin); 1182 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
1182 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin); 1183 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
1183 u32 size = address_size; // TODO: Analyze stride and number of vertices 1184 u32 size = address_size; // TODO: Analyze stride and number of vertices
1184 if (array.enable == 0 || size == 0 || !cpu_addr) { 1185 if (array.enable == 0 || size == 0 || !device_addr) {
1185 channel_state->vertex_buffers[index] = NULL_BINDING; 1186 channel_state->vertex_buffers[index] = NULL_BINDING;
1186 return; 1187 return;
1187 } 1188 }
1188 if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) { 1189 if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) {
1189 size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size)); 1190 size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
1190 } 1191 }
1191 const BufferId buffer_id = FindBuffer(*cpu_addr, size); 1192 const BufferId buffer_id = FindBuffer(*device_addr, size);
1192 channel_state->vertex_buffers[index] = Binding{ 1193 channel_state->vertex_buffers[index] = Binding{
1193 .cpu_addr = *cpu_addr, 1194 .device_addr = *device_addr,
1194 .size = size, 1195 .size = size,
1195 .buffer_id = buffer_id, 1196 .buffer_id = buffer_id,
1196 }; 1197 };
@@ -1199,15 +1200,15 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
1199template <class P> 1200template <class P>
1200void BufferCache<P>::UpdateDrawIndirect() { 1201void BufferCache<P>::UpdateDrawIndirect() {
1201 const auto update = [this](GPUVAddr gpu_addr, size_t size, Binding& binding) { 1202 const auto update = [this](GPUVAddr gpu_addr, size_t size, Binding& binding) {
1202 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1203 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
1203 if (!cpu_addr) { 1204 if (!device_addr) {
1204 binding = NULL_BINDING; 1205 binding = NULL_BINDING;
1205 return; 1206 return;
1206 } 1207 }
1207 binding = Binding{ 1208 binding = Binding{
1208 .cpu_addr = *cpu_addr, 1209 .device_addr = *device_addr,
1209 .size = static_cast<u32>(size), 1210 .size = static_cast<u32>(size),
1210 .buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)), 1211 .buffer_id = FindBuffer(*device_addr, static_cast<u32>(size)),
1211 }; 1212 };
1212 }; 1213 };
1213 if (current_draw_indirect->include_count) { 1214 if (current_draw_indirect->include_count) {
@@ -1231,7 +1232,7 @@ void BufferCache<P>::UpdateUniformBuffers(size_t stage) {
1231 channel_state->dirty_uniform_buffers[stage] |= 1U << index; 1232 channel_state->dirty_uniform_buffers[stage] |= 1U << index;
1232 } 1233 }
1233 // Resolve buffer 1234 // Resolve buffer
1234 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1235 binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
1235 }); 1236 });
1236} 1237}
1237 1238
@@ -1240,7 +1241,7 @@ void BufferCache<P>::UpdateStorageBuffers(size_t stage) {
1240 ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) { 1241 ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) {
1241 // Resolve buffer 1242 // Resolve buffer
1242 Binding& binding = channel_state->storage_buffers[stage][index]; 1243 Binding& binding = channel_state->storage_buffers[stage][index];
1243 const BufferId buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1244 const BufferId buffer_id = FindBuffer(binding.device_addr, binding.size);
1244 binding.buffer_id = buffer_id; 1245 binding.buffer_id = buffer_id;
1245 }); 1246 });
1246} 1247}
@@ -1249,7 +1250,7 @@ template <class P>
1249void BufferCache<P>::UpdateTextureBuffers(size_t stage) { 1250void BufferCache<P>::UpdateTextureBuffers(size_t stage) {
1250 ForEachEnabledBit(channel_state->enabled_texture_buffers[stage], [&](u32 index) { 1251 ForEachEnabledBit(channel_state->enabled_texture_buffers[stage], [&](u32 index) {
1251 Binding& binding = channel_state->texture_buffers[stage][index]; 1252 Binding& binding = channel_state->texture_buffers[stage][index];
1252 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1253 binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
1253 }); 1254 });
1254} 1255}
1255 1256
@@ -1268,14 +1269,14 @@ void BufferCache<P>::UpdateTransformFeedbackBuffer(u32 index) {
1268 const auto& binding = maxwell3d->regs.transform_feedback.buffers[index]; 1269 const auto& binding = maxwell3d->regs.transform_feedback.buffers[index];
1269 const GPUVAddr gpu_addr = binding.Address() + binding.start_offset; 1270 const GPUVAddr gpu_addr = binding.Address() + binding.start_offset;
1270 const u32 size = binding.size; 1271 const u32 size = binding.size;
1271 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1272 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
1272 if (binding.enable == 0 || size == 0 || !cpu_addr) { 1273 if (binding.enable == 0 || size == 0 || !device_addr) {
1273 channel_state->transform_feedback_buffers[index] = NULL_BINDING; 1274 channel_state->transform_feedback_buffers[index] = NULL_BINDING;
1274 return; 1275 return;
1275 } 1276 }
1276 const BufferId buffer_id = FindBuffer(*cpu_addr, size); 1277 const BufferId buffer_id = FindBuffer(*device_addr, size);
1277 channel_state->transform_feedback_buffers[index] = Binding{ 1278 channel_state->transform_feedback_buffers[index] = Binding{
1278 .cpu_addr = *cpu_addr, 1279 .device_addr = *device_addr,
1279 .size = size, 1280 .size = size,
1280 .buffer_id = buffer_id, 1281 .buffer_id = buffer_id,
1281 }; 1282 };
@@ -1289,13 +1290,13 @@ void BufferCache<P>::UpdateComputeUniformBuffers() {
1289 const auto& launch_desc = kepler_compute->launch_description; 1290 const auto& launch_desc = kepler_compute->launch_description;
1290 if (((launch_desc.const_buffer_enable_mask >> index) & 1) != 0) { 1291 if (((launch_desc.const_buffer_enable_mask >> index) & 1) != 0) {
1291 const auto& cbuf = launch_desc.const_buffer_config[index]; 1292 const auto& cbuf = launch_desc.const_buffer_config[index];
1292 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(cbuf.Address()); 1293 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(cbuf.Address());
1293 if (cpu_addr) { 1294 if (device_addr) {
1294 binding.cpu_addr = *cpu_addr; 1295 binding.device_addr = *device_addr;
1295 binding.size = cbuf.size; 1296 binding.size = cbuf.size;
1296 } 1297 }
1297 } 1298 }
1298 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1299 binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
1299 }); 1300 });
1300} 1301}
1301 1302
@@ -1304,7 +1305,7 @@ void BufferCache<P>::UpdateComputeStorageBuffers() {
1304 ForEachEnabledBit(channel_state->enabled_compute_storage_buffers, [&](u32 index) { 1305 ForEachEnabledBit(channel_state->enabled_compute_storage_buffers, [&](u32 index) {
1305 // Resolve buffer 1306 // Resolve buffer
1306 Binding& binding = channel_state->compute_storage_buffers[index]; 1307 Binding& binding = channel_state->compute_storage_buffers[index];
1307 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1308 binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
1308 }); 1309 });
1309} 1310}
1310 1311
@@ -1312,45 +1313,63 @@ template <class P>
1312void BufferCache<P>::UpdateComputeTextureBuffers() { 1313void BufferCache<P>::UpdateComputeTextureBuffers() {
1313 ForEachEnabledBit(channel_state->enabled_compute_texture_buffers, [&](u32 index) { 1314 ForEachEnabledBit(channel_state->enabled_compute_texture_buffers, [&](u32 index) {
1314 Binding& binding = channel_state->compute_texture_buffers[index]; 1315 Binding& binding = channel_state->compute_texture_buffers[index];
1315 binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size); 1316 binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
1316 }); 1317 });
1317} 1318}
1318 1319
1319template <class P> 1320template <class P>
1320void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) { 1321void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size) {
1321 memory_tracker.MarkRegionAsGpuModified(cpu_addr, size); 1322 memory_tracker.MarkRegionAsGpuModified(device_addr, size);
1322 1323
1323 const IntervalType base_interval{cpu_addr, cpu_addr + size}; 1324 const IntervalType base_interval{device_addr, device_addr + size};
1324 common_ranges.add(base_interval); 1325 common_ranges.add(base_interval);
1325 uncommitted_ranges.add(base_interval); 1326 uncommitted_ranges.add(base_interval);
1326} 1327}
1327 1328
1328template <class P> 1329template <class P>
1329BufferId BufferCache<P>::FindBuffer(VAddr cpu_addr, u32 size) { 1330BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size) {
1330 if (cpu_addr == 0) { 1331 if (device_addr == 0) {
1331 return NULL_BUFFER_ID; 1332 return NULL_BUFFER_ID;
1332 } 1333 }
1333 const u64 page = cpu_addr >> CACHING_PAGEBITS; 1334 const u64 page = device_addr >> CACHING_PAGEBITS;
1334 const BufferId buffer_id = page_table[page]; 1335 const BufferId buffer_id = page_table[page];
1335 if (!buffer_id) { 1336 if (!buffer_id) {
1336 return CreateBuffer(cpu_addr, size); 1337 return CreateBuffer(device_addr, size);
1337 } 1338 }
1338 const Buffer& buffer = slot_buffers[buffer_id]; 1339 const Buffer& buffer = slot_buffers[buffer_id];
1339 if (buffer.IsInBounds(cpu_addr, size)) { 1340 if (buffer.IsInBounds(device_addr, size)) {
1340 return buffer_id; 1341 return buffer_id;
1341 } 1342 }
1342 return CreateBuffer(cpu_addr, size); 1343 return CreateBuffer(device_addr, size);
1343} 1344}
1344 1345
1345template <class P> 1346template <class P>
1346typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu_addr, 1347typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(DAddr device_addr,
1347 u32 wanted_size) { 1348 u32 wanted_size) {
1348 static constexpr int STREAM_LEAP_THRESHOLD = 16; 1349 static constexpr int STREAM_LEAP_THRESHOLD = 16;
1349 boost::container::small_vector<BufferId, 16> overlap_ids; 1350 boost::container::small_vector<BufferId, 16> overlap_ids;
1350 VAddr begin = cpu_addr; 1351 DAddr begin = device_addr;
1351 VAddr end = cpu_addr + wanted_size; 1352 DAddr end = device_addr + wanted_size;
1352 int stream_score = 0; 1353 int stream_score = 0;
1353 bool has_stream_leap = false; 1354 bool has_stream_leap = false;
1355 auto expand_begin = [&](DAddr add_value) {
1356 static constexpr DAddr min_page = CACHING_PAGESIZE + Core::DEVICE_PAGESIZE;
1357 if (add_value > begin - min_page) {
1358 begin = min_page;
1359 device_addr = Core::DEVICE_PAGESIZE;
1360 return;
1361 }
1362 begin -= add_value;
1363 device_addr = begin - CACHING_PAGESIZE;
1364 };
1365 auto expand_end = [&](DAddr add_value) {
1366 static constexpr DAddr max_page = 1ULL << Tegra::MaxwellDeviceMemoryManager::AS_BITS;
1367 if (add_value > max_page - end) {
1368 end = max_page;
1369 return;
1370 }
1371 end += add_value;
1372 };
1354 if (begin == 0) { 1373 if (begin == 0) {
1355 return OverlapResult{ 1374 return OverlapResult{
1356 .ids = std::move(overlap_ids), 1375 .ids = std::move(overlap_ids),
@@ -1359,9 +1378,9 @@ typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu
1359 .has_stream_leap = has_stream_leap, 1378 .has_stream_leap = has_stream_leap,
1360 }; 1379 };
1361 } 1380 }
1362 for (; cpu_addr >> CACHING_PAGEBITS < Common::DivCeil(end, CACHING_PAGESIZE); 1381 for (; device_addr >> CACHING_PAGEBITS < Common::DivCeil(end, CACHING_PAGESIZE);
1363 cpu_addr += CACHING_PAGESIZE) { 1382 device_addr += CACHING_PAGESIZE) {
1364 const BufferId overlap_id = page_table[cpu_addr >> CACHING_PAGEBITS]; 1383 const BufferId overlap_id = page_table[device_addr >> CACHING_PAGEBITS];
1365 if (!overlap_id) { 1384 if (!overlap_id) {
1366 continue; 1385 continue;
1367 } 1386 }
@@ -1371,12 +1390,12 @@ typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu
1371 } 1390 }
1372 overlap_ids.push_back(overlap_id); 1391 overlap_ids.push_back(overlap_id);
1373 overlap.Pick(); 1392 overlap.Pick();
1374 const VAddr overlap_cpu_addr = overlap.CpuAddr(); 1393 const DAddr overlap_device_addr = overlap.CpuAddr();
1375 const bool expands_left = overlap_cpu_addr < begin; 1394 const bool expands_left = overlap_device_addr < begin;
1376 if (expands_left) { 1395 if (expands_left) {
1377 begin = overlap_cpu_addr; 1396 begin = overlap_device_addr;
1378 } 1397 }
1379 const VAddr overlap_end = overlap_cpu_addr + overlap.SizeBytes(); 1398 const DAddr overlap_end = overlap_device_addr + overlap.SizeBytes();
1380 const bool expands_right = overlap_end > end; 1399 const bool expands_right = overlap_end > end;
1381 if (overlap_end > end) { 1400 if (overlap_end > end) {
1382 end = overlap_end; 1401 end = overlap_end;
@@ -1387,11 +1406,10 @@ typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu
1387 // as a stream buffer. Increase the size to skip constantly recreating buffers. 1406 // as a stream buffer. Increase the size to skip constantly recreating buffers.
1388 has_stream_leap = true; 1407 has_stream_leap = true;
1389 if (expands_right) { 1408 if (expands_right) {
1390 begin -= CACHING_PAGESIZE * 256; 1409 expand_begin(CACHING_PAGESIZE * 128);
1391 cpu_addr = begin - CACHING_PAGESIZE;
1392 } 1410 }
1393 if (expands_left) { 1411 if (expands_left) {
1394 end += CACHING_PAGESIZE * 256; 1412 expand_end(CACHING_PAGESIZE * 128);
1395 } 1413 }
1396 } 1414 }
1397 } 1415 }
@@ -1424,13 +1442,13 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
1424} 1442}
1425 1443
1426template <class P> 1444template <class P>
1427BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) { 1445BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
1428 VAddr cpu_addr_end = Common::AlignUp(cpu_addr + wanted_size, CACHING_PAGESIZE); 1446 DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
1429 cpu_addr = Common::AlignDown(cpu_addr, CACHING_PAGESIZE); 1447 device_addr = Common::AlignDown(device_addr, CACHING_PAGESIZE);
1430 wanted_size = static_cast<u32>(cpu_addr_end - cpu_addr); 1448 wanted_size = static_cast<u32>(device_addr_end - device_addr);
1431 const OverlapResult overlap = ResolveOverlaps(cpu_addr, wanted_size); 1449 const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
1432 const u32 size = static_cast<u32>(overlap.end - overlap.begin); 1450 const u32 size = static_cast<u32>(overlap.end - overlap.begin);
1433 const BufferId new_buffer_id = slot_buffers.insert(runtime, rasterizer, overlap.begin, size); 1451 const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
1434 auto& new_buffer = slot_buffers[new_buffer_id]; 1452 auto& new_buffer = slot_buffers[new_buffer_id];
1435 const size_t size_bytes = new_buffer.SizeBytes(); 1453 const size_t size_bytes = new_buffer.SizeBytes();
1436 runtime.ClearBuffer(new_buffer, 0, size_bytes, 0); 1454 runtime.ClearBuffer(new_buffer, 0, size_bytes, 0);
@@ -1465,10 +1483,10 @@ void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
1465 total_used_memory -= Common::AlignUp(size, 1024); 1483 total_used_memory -= Common::AlignUp(size, 1024);
1466 lru_cache.Free(buffer.getLRUID()); 1484 lru_cache.Free(buffer.getLRUID());
1467 } 1485 }
1468 const VAddr cpu_addr_begin = buffer.CpuAddr(); 1486 const DAddr device_addr_begin = buffer.CpuAddr();
1469 const VAddr cpu_addr_end = cpu_addr_begin + size; 1487 const DAddr device_addr_end = device_addr_begin + size;
1470 const u64 page_begin = cpu_addr_begin / CACHING_PAGESIZE; 1488 const u64 page_begin = device_addr_begin / CACHING_PAGESIZE;
1471 const u64 page_end = Common::DivCeil(cpu_addr_end, CACHING_PAGESIZE); 1489 const u64 page_end = Common::DivCeil(device_addr_end, CACHING_PAGESIZE);
1472 for (u64 page = page_begin; page != page_end; ++page) { 1490 for (u64 page = page_begin; page != page_end; ++page) {
1473 if constexpr (insert) { 1491 if constexpr (insert) {
1474 page_table[page] = buffer_id; 1492 page_table[page] = buffer_id;
@@ -1486,15 +1504,15 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
1486} 1504}
1487 1505
1488template <class P> 1506template <class P>
1489bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) { 1507bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size) {
1490 boost::container::small_vector<BufferCopy, 4> copies; 1508 boost::container::small_vector<BufferCopy, 4> copies;
1491 u64 total_size_bytes = 0; 1509 u64 total_size_bytes = 0;
1492 u64 largest_copy = 0; 1510 u64 largest_copy = 0;
1493 VAddr buffer_start = buffer.CpuAddr(); 1511 DAddr buffer_start = buffer.CpuAddr();
1494 memory_tracker.ForEachUploadRange(cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) { 1512 memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
1495 copies.push_back(BufferCopy{ 1513 copies.push_back(BufferCopy{
1496 .src_offset = total_size_bytes, 1514 .src_offset = total_size_bytes,
1497 .dst_offset = cpu_addr_out - buffer_start, 1515 .dst_offset = device_addr_out - buffer_start,
1498 .size = range_size, 1516 .size = range_size,
1499 }); 1517 });
1500 total_size_bytes += range_size; 1518 total_size_bytes += range_size;
@@ -1526,14 +1544,14 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
1526 std::span<u8> immediate_buffer; 1544 std::span<u8> immediate_buffer;
1527 for (const BufferCopy& copy : copies) { 1545 for (const BufferCopy& copy : copies) {
1528 std::span<const u8> upload_span; 1546 std::span<const u8> upload_span;
1529 const VAddr cpu_addr = buffer.CpuAddr() + copy.dst_offset; 1547 const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
1530 if (IsRangeGranular(cpu_addr, copy.size)) { 1548 if (IsRangeGranular(device_addr, copy.size)) {
1531 upload_span = std::span(cpu_memory.GetPointer(cpu_addr), copy.size); 1549 upload_span = std::span(device_memory.GetPointer<u8>(device_addr), copy.size);
1532 } else { 1550 } else {
1533 if (immediate_buffer.empty()) { 1551 if (immediate_buffer.empty()) {
1534 immediate_buffer = ImmediateBuffer(largest_copy); 1552 immediate_buffer = ImmediateBuffer(largest_copy);
1535 } 1553 }
1536 cpu_memory.ReadBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size); 1554 device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
1537 upload_span = immediate_buffer.subspan(0, copy.size); 1555 upload_span = immediate_buffer.subspan(0, copy.size);
1538 } 1556 }
1539 buffer.ImmediateUpload(copy.dst_offset, upload_span); 1557 buffer.ImmediateUpload(copy.dst_offset, upload_span);
@@ -1550,8 +1568,8 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
1550 const std::span<u8> staging_pointer = upload_staging.mapped_span; 1568 const std::span<u8> staging_pointer = upload_staging.mapped_span;
1551 for (BufferCopy& copy : copies) { 1569 for (BufferCopy& copy : copies) {
1552 u8* const src_pointer = staging_pointer.data() + copy.src_offset; 1570 u8* const src_pointer = staging_pointer.data() + copy.src_offset;
1553 const VAddr cpu_addr = buffer.CpuAddr() + copy.dst_offset; 1571 const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
1554 cpu_memory.ReadBlockUnsafe(cpu_addr, src_pointer, copy.size); 1572 device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
1555 1573
1556 // Apply the staging offset 1574 // Apply the staging offset
1557 copy.src_offset += upload_staging.offset; 1575 copy.src_offset += upload_staging.offset;
@@ -1562,14 +1580,14 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
1562} 1580}
1563 1581
1564template <class P> 1582template <class P>
1565bool BufferCache<P>::InlineMemory(VAddr dest_address, size_t copy_size, 1583bool BufferCache<P>::InlineMemory(DAddr dest_address, size_t copy_size,
1566 std::span<const u8> inlined_buffer) { 1584 std::span<const u8> inlined_buffer) {
1567 const bool is_dirty = IsRegionRegistered(dest_address, copy_size); 1585 const bool is_dirty = IsRegionRegistered(dest_address, copy_size);
1568 if (!is_dirty) { 1586 if (!is_dirty) {
1569 return false; 1587 return false;
1570 } 1588 }
1571 VAddr aligned_start = Common::AlignDown(dest_address, YUZU_PAGESIZE); 1589 DAddr aligned_start = Common::AlignDown(dest_address, DEVICE_PAGESIZE);
1572 VAddr aligned_end = Common::AlignUp(dest_address + copy_size, YUZU_PAGESIZE); 1590 DAddr aligned_end = Common::AlignUp(dest_address + copy_size, DEVICE_PAGESIZE);
1573 if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) { 1591 if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
1574 return false; 1592 return false;
1575 } 1593 }
@@ -1580,7 +1598,7 @@ bool BufferCache<P>::InlineMemory(VAddr dest_address, size_t copy_size,
1580} 1598}
1581 1599
1582template <class P> 1600template <class P>
1583void BufferCache<P>::InlineMemoryImplementation(VAddr dest_address, size_t copy_size, 1601void BufferCache<P>::InlineMemoryImplementation(DAddr dest_address, size_t copy_size,
1584 std::span<const u8> inlined_buffer) { 1602 std::span<const u8> inlined_buffer) {
1585 const IntervalType subtract_interval{dest_address, dest_address + copy_size}; 1603 const IntervalType subtract_interval{dest_address, dest_address + copy_size};
1586 ClearDownload(subtract_interval); 1604 ClearDownload(subtract_interval);
@@ -1612,14 +1630,14 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer) {
1612} 1630}
1613 1631
1614template <class P> 1632template <class P>
1615void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 size) { 1633void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, DAddr device_addr, u64 size) {
1616 boost::container::small_vector<BufferCopy, 1> copies; 1634 boost::container::small_vector<BufferCopy, 1> copies;
1617 u64 total_size_bytes = 0; 1635 u64 total_size_bytes = 0;
1618 u64 largest_copy = 0; 1636 u64 largest_copy = 0;
1619 memory_tracker.ForEachDownloadRangeAndClear( 1637 memory_tracker.ForEachDownloadRangeAndClear(
1620 cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) { 1638 device_addr, size, [&](u64 device_addr_out, u64 range_size) {
1621 const VAddr buffer_addr = buffer.CpuAddr(); 1639 const DAddr buffer_addr = buffer.CpuAddr();
1622 const auto add_download = [&](VAddr start, VAddr end) { 1640 const auto add_download = [&](DAddr start, DAddr end) {
1623 const u64 new_offset = start - buffer_addr; 1641 const u64 new_offset = start - buffer_addr;
1624 const u64 new_size = end - start; 1642 const u64 new_size = end - start;
1625 copies.push_back(BufferCopy{ 1643 copies.push_back(BufferCopy{
@@ -1634,8 +1652,8 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
1634 largest_copy = std::max(largest_copy, new_size); 1652 largest_copy = std::max(largest_copy, new_size);
1635 }; 1653 };
1636 1654
1637 const VAddr start_address = cpu_addr_out; 1655 const DAddr start_address = device_addr_out;
1638 const VAddr end_address = start_address + range_size; 1656 const DAddr end_address = start_address + range_size;
1639 ForEachInRangeSet(common_ranges, start_address, range_size, add_download); 1657 ForEachInRangeSet(common_ranges, start_address, range_size, add_download);
1640 const IntervalType subtract_interval{start_address, end_address}; 1658 const IntervalType subtract_interval{start_address, end_address};
1641 ClearDownload(subtract_interval); 1659 ClearDownload(subtract_interval);
@@ -1658,18 +1676,18 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
1658 runtime.CopyBuffer(download_staging.buffer, buffer, copies_span, true); 1676 runtime.CopyBuffer(download_staging.buffer, buffer, copies_span, true);
1659 runtime.Finish(); 1677 runtime.Finish();
1660 for (const BufferCopy& copy : copies) { 1678 for (const BufferCopy& copy : copies) {
1661 const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset; 1679 const DAddr copy_device_addr = buffer.CpuAddr() + copy.src_offset;
1662 // Undo the modified offset 1680 // Undo the modified offset
1663 const u64 dst_offset = copy.dst_offset - download_staging.offset; 1681 const u64 dst_offset = copy.dst_offset - download_staging.offset;
1664 const u8* copy_mapped_memory = mapped_memory + dst_offset; 1682 const u8* copy_mapped_memory = mapped_memory + dst_offset;
1665 cpu_memory.WriteBlockUnsafe(copy_cpu_addr, copy_mapped_memory, copy.size); 1683 device_memory.WriteBlockUnsafe(copy_device_addr, copy_mapped_memory, copy.size);
1666 } 1684 }
1667 } else { 1685 } else {
1668 const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy); 1686 const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
1669 for (const BufferCopy& copy : copies) { 1687 for (const BufferCopy& copy : copies) {
1670 buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size)); 1688 buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size));
1671 const VAddr copy_cpu_addr = buffer.CpuAddr() + copy.src_offset; 1689 const DAddr copy_device_addr = buffer.CpuAddr() + copy.src_offset;
1672 cpu_memory.WriteBlockUnsafe(copy_cpu_addr, immediate_buffer.data(), copy.size); 1690 device_memory.WriteBlockUnsafe(copy_device_addr, immediate_buffer.data(), copy.size);
1673 } 1691 }
1674 } 1692 }
1675} 1693}
@@ -1758,20 +1776,20 @@ Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index,
1758 const GPUVAddr aligned_gpu_addr = Common::AlignDown(gpu_addr, alignment); 1776 const GPUVAddr aligned_gpu_addr = Common::AlignDown(gpu_addr, alignment);
1759 const u32 aligned_size = static_cast<u32>(gpu_addr - aligned_gpu_addr) + size; 1777 const u32 aligned_size = static_cast<u32>(gpu_addr - aligned_gpu_addr) + size;
1760 1778
1761 const std::optional<VAddr> aligned_cpu_addr = gpu_memory->GpuToCpuAddress(aligned_gpu_addr); 1779 const std::optional<DAddr> aligned_device_addr = gpu_memory->GpuToCpuAddress(aligned_gpu_addr);
1762 if (!aligned_cpu_addr || size == 0) { 1780 if (!aligned_device_addr || size == 0) {
1763 LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index); 1781 LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index);
1764 return NULL_BINDING; 1782 return NULL_BINDING;
1765 } 1783 }
1766 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1784 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
1767 ASSERT_MSG(cpu_addr, "Unaligned storage buffer address not found for cbuf index {}", 1785 ASSERT_MSG(device_addr, "Unaligned storage buffer address not found for cbuf index {}",
1768 cbuf_index); 1786 cbuf_index);
1769 // The end address used for size calculation does not need to be aligned 1787 // The end address used for size calculation does not need to be aligned
1770 const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, Core::Memory::YUZU_PAGESIZE); 1788 const DAddr cpu_end = Common::AlignUp(*device_addr + size, Core::DEVICE_PAGESIZE);
1771 1789
1772 const Binding binding{ 1790 const Binding binding{
1773 .cpu_addr = *aligned_cpu_addr, 1791 .device_addr = *aligned_device_addr,
1774 .size = is_written ? aligned_size : static_cast<u32>(cpu_end - *aligned_cpu_addr), 1792 .size = is_written ? aligned_size : static_cast<u32>(cpu_end - *aligned_device_addr),
1775 .buffer_id = BufferId{}, 1793 .buffer_id = BufferId{},
1776 }; 1794 };
1777 return binding; 1795 return binding;
@@ -1780,15 +1798,15 @@ Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index,
1780template <class P> 1798template <class P>
1781TextureBufferBinding BufferCache<P>::GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size, 1799TextureBufferBinding BufferCache<P>::GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size,
1782 PixelFormat format) { 1800 PixelFormat format) {
1783 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1801 const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
1784 TextureBufferBinding binding; 1802 TextureBufferBinding binding;
1785 if (!cpu_addr || size == 0) { 1803 if (!device_addr || size == 0) {
1786 binding.cpu_addr = 0; 1804 binding.device_addr = 0;
1787 binding.size = 0; 1805 binding.size = 0;
1788 binding.buffer_id = NULL_BUFFER_ID; 1806 binding.buffer_id = NULL_BUFFER_ID;
1789 binding.format = PixelFormat::Invalid; 1807 binding.format = PixelFormat::Invalid;
1790 } else { 1808 } else {
1791 binding.cpu_addr = *cpu_addr; 1809 binding.device_addr = *device_addr;
1792 binding.size = size; 1810 binding.size = size;
1793 binding.buffer_id = BufferId{}; 1811 binding.buffer_id = BufferId{};
1794 binding.format = format; 1812 binding.format = format;
@@ -1797,14 +1815,14 @@ TextureBufferBinding BufferCache<P>::GetTextureBufferBinding(GPUVAddr gpu_addr,
1797} 1815}
1798 1816
1799template <class P> 1817template <class P>
1800std::span<const u8> BufferCache<P>::ImmediateBufferWithData(VAddr cpu_addr, size_t size) { 1818std::span<const u8> BufferCache<P>::ImmediateBufferWithData(DAddr device_addr, size_t size) {
1801 u8* const base_pointer = cpu_memory.GetPointer(cpu_addr); 1819 u8* const base_pointer = device_memory.GetPointer<u8>(device_addr);
1802 if (IsRangeGranular(cpu_addr, size) || 1820 if (IsRangeGranular(device_addr, size) ||
1803 base_pointer + size == cpu_memory.GetPointer(cpu_addr + size)) { 1821 base_pointer + size == device_memory.GetPointer<u8>(device_addr + size)) {
1804 return std::span(base_pointer, size); 1822 return std::span(base_pointer, size);
1805 } else { 1823 } else {
1806 const std::span<u8> span = ImmediateBuffer(size); 1824 const std::span<u8> span = ImmediateBuffer(size);
1807 cpu_memory.ReadBlockUnsafe(cpu_addr, span.data(), size); 1825 device_memory.ReadBlockUnsafe(device_addr, span.data(), size);
1808 return span; 1826 return span;
1809 } 1827 }
1810} 1828}
@@ -1828,13 +1846,14 @@ bool BufferCache<P>::HasFastUniformBufferBound(size_t stage, u32 binding_index)
1828template <class P> 1846template <class P>
1829std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectCount() { 1847std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectCount() {
1830 auto& buffer = slot_buffers[channel_state->count_buffer_binding.buffer_id]; 1848 auto& buffer = slot_buffers[channel_state->count_buffer_binding.buffer_id];
1831 return std::make_pair(&buffer, buffer.Offset(channel_state->count_buffer_binding.cpu_addr)); 1849 return std::make_pair(&buffer, buffer.Offset(channel_state->count_buffer_binding.device_addr));
1832} 1850}
1833 1851
1834template <class P> 1852template <class P>
1835std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectBuffer() { 1853std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectBuffer() {
1836 auto& buffer = slot_buffers[channel_state->indirect_buffer_binding.buffer_id]; 1854 auto& buffer = slot_buffers[channel_state->indirect_buffer_binding.buffer_id];
1837 return std::make_pair(&buffer, buffer.Offset(channel_state->indirect_buffer_binding.cpu_addr)); 1855 return std::make_pair(&buffer,
1856 buffer.Offset(channel_state->indirect_buffer_binding.device_addr));
1838} 1857}
1839 1858
1840} // namespace VideoCommon 1859} // namespace VideoCommon
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index d6d696d8c..80dbb81e7 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -32,7 +32,6 @@
32#include "common/microprofile.h" 32#include "common/microprofile.h"
33#include "common/scope_exit.h" 33#include "common/scope_exit.h"
34#include "common/settings.h" 34#include "common/settings.h"
35#include "core/memory.h"
36#include "video_core/buffer_cache/buffer_base.h" 35#include "video_core/buffer_cache/buffer_base.h"
37#include "video_core/control/channel_state_cache.h" 36#include "video_core/control/channel_state_cache.h"
38#include "video_core/delayed_destruction_ring.h" 37#include "video_core/delayed_destruction_ring.h"
@@ -41,7 +40,6 @@
41#include "video_core/engines/kepler_compute.h" 40#include "video_core/engines/kepler_compute.h"
42#include "video_core/engines/maxwell_3d.h" 41#include "video_core/engines/maxwell_3d.h"
43#include "video_core/memory_manager.h" 42#include "video_core/memory_manager.h"
44#include "video_core/rasterizer_interface.h"
45#include "video_core/surface.h" 43#include "video_core/surface.h"
46#include "video_core/texture_cache/slot_vector.h" 44#include "video_core/texture_cache/slot_vector.h"
47#include "video_core/texture_cache/types.h" 45#include "video_core/texture_cache/types.h"
@@ -94,7 +92,7 @@ static constexpr BufferId NULL_BUFFER_ID{0};
94static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = static_cast<u32>(4_KiB); 92static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = static_cast<u32>(4_KiB);
95 93
96struct Binding { 94struct Binding {
97 VAddr cpu_addr{}; 95 DAddr device_addr{};
98 u32 size{}; 96 u32 size{};
99 BufferId buffer_id; 97 BufferId buffer_id;
100}; 98};
@@ -104,7 +102,7 @@ struct TextureBufferBinding : Binding {
104}; 102};
105 103
106static constexpr Binding NULL_BINDING{ 104static constexpr Binding NULL_BINDING{
107 .cpu_addr = 0, 105 .device_addr = 0,
108 .size = 0, 106 .size = 0,
109 .buffer_id = NULL_BUFFER_ID, 107 .buffer_id = NULL_BUFFER_ID,
110}; 108};
@@ -204,10 +202,10 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf
204 using Async_Buffer = typename P::Async_Buffer; 202 using Async_Buffer = typename P::Async_Buffer;
205 using MemoryTracker = typename P::MemoryTracker; 203 using MemoryTracker = typename P::MemoryTracker;
206 204
207 using IntervalCompare = std::less<VAddr>; 205 using IntervalCompare = std::less<DAddr>;
208 using IntervalInstance = boost::icl::interval_type_default<VAddr, std::less>; 206 using IntervalInstance = boost::icl::interval_type_default<DAddr, std::less>;
209 using IntervalAllocator = boost::fast_pool_allocator<VAddr>; 207 using IntervalAllocator = boost::fast_pool_allocator<DAddr>;
210 using IntervalSet = boost::icl::interval_set<VAddr>; 208 using IntervalSet = boost::icl::interval_set<DAddr>;
211 using IntervalType = typename IntervalSet::interval_type; 209 using IntervalType = typename IntervalSet::interval_type;
212 210
213 template <typename Type> 211 template <typename Type>
@@ -230,32 +228,31 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf
230 228
231 using OverlapCombine = counter_add_functor<int>; 229 using OverlapCombine = counter_add_functor<int>;
232 using OverlapSection = boost::icl::inter_section<int>; 230 using OverlapSection = boost::icl::inter_section<int>;
233 using OverlapCounter = boost::icl::split_interval_map<VAddr, int>; 231 using OverlapCounter = boost::icl::split_interval_map<DAddr, int>;
234 232
235 struct OverlapResult { 233 struct OverlapResult {
236 boost::container::small_vector<BufferId, 16> ids; 234 boost::container::small_vector<BufferId, 16> ids;
237 VAddr begin; 235 DAddr begin;
238 VAddr end; 236 DAddr end;
239 bool has_stream_leap = false; 237 bool has_stream_leap = false;
240 }; 238 };
241 239
242public: 240public:
243 explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_, 241 explicit BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, Runtime& runtime_);
244 Core::Memory::Memory& cpu_memory_, Runtime& runtime_);
245 242
246 void TickFrame(); 243 void TickFrame();
247 244
248 void WriteMemory(VAddr cpu_addr, u64 size); 245 void WriteMemory(DAddr device_addr, u64 size);
249 246
250 void CachedWriteMemory(VAddr cpu_addr, u64 size); 247 void CachedWriteMemory(DAddr device_addr, u64 size);
251 248
252 bool OnCPUWrite(VAddr cpu_addr, u64 size); 249 bool OnCPUWrite(DAddr device_addr, u64 size);
253 250
254 void DownloadMemory(VAddr cpu_addr, u64 size); 251 void DownloadMemory(DAddr device_addr, u64 size);
255 252
256 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(VAddr cpu_addr, u64 size); 253 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(DAddr device_addr, u64 size);
257 254
258 bool InlineMemory(VAddr dest_address, size_t copy_size, std::span<const u8> inlined_buffer); 255 bool InlineMemory(DAddr dest_address, size_t copy_size, std::span<const u8> inlined_buffer);
259 256
260 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size); 257 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size);
261 258
@@ -300,7 +297,7 @@ public:
300 ObtainBufferSynchronize sync_info, 297 ObtainBufferSynchronize sync_info,
301 ObtainBufferOperation post_op); 298 ObtainBufferOperation post_op);
302 299
303 [[nodiscard]] std::pair<Buffer*, u32> ObtainCPUBuffer(VAddr gpu_addr, u32 size, 300 [[nodiscard]] std::pair<Buffer*, u32> ObtainCPUBuffer(DAddr gpu_addr, u32 size,
304 ObtainBufferSynchronize sync_info, 301 ObtainBufferSynchronize sync_info,
305 ObtainBufferOperation post_op); 302 ObtainBufferOperation post_op);
306 void FlushCachedWrites(); 303 void FlushCachedWrites();
@@ -326,13 +323,13 @@ public:
326 bool DMAClear(GPUVAddr src_address, u64 amount, u32 value); 323 bool DMAClear(GPUVAddr src_address, u64 amount, u32 value);
327 324
328 /// Return true when a CPU region is modified from the GPU 325 /// Return true when a CPU region is modified from the GPU
329 [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); 326 [[nodiscard]] bool IsRegionGpuModified(DAddr addr, size_t size);
330 327
331 /// Return true when a region is registered on the cache 328 /// Return true when a region is registered on the cache
332 [[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size); 329 [[nodiscard]] bool IsRegionRegistered(DAddr addr, size_t size);
333 330
334 /// Return true when a CPU region is modified from the CPU 331 /// Return true when a CPU region is modified from the CPU
335 [[nodiscard]] bool IsRegionCpuModified(VAddr addr, size_t size); 332 [[nodiscard]] bool IsRegionCpuModified(DAddr addr, size_t size);
336 333
337 void SetDrawIndirect( 334 void SetDrawIndirect(
338 const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect_) { 335 const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect_) {
@@ -366,9 +363,9 @@ private:
366 } 363 }
367 364
368 template <typename Func> 365 template <typename Func>
369 void ForEachBufferInRange(VAddr cpu_addr, u64 size, Func&& func) { 366 void ForEachBufferInRange(DAddr device_addr, u64 size, Func&& func) {
370 const u64 page_end = Common::DivCeil(cpu_addr + size, CACHING_PAGESIZE); 367 const u64 page_end = Common::DivCeil(device_addr + size, CACHING_PAGESIZE);
371 for (u64 page = cpu_addr >> CACHING_PAGEBITS; page < page_end;) { 368 for (u64 page = device_addr >> CACHING_PAGEBITS; page < page_end;) {
372 const BufferId buffer_id = page_table[page]; 369 const BufferId buffer_id = page_table[page];
373 if (!buffer_id) { 370 if (!buffer_id) {
374 ++page; 371 ++page;
@@ -377,15 +374,15 @@ private:
377 Buffer& buffer = slot_buffers[buffer_id]; 374 Buffer& buffer = slot_buffers[buffer_id];
378 func(buffer_id, buffer); 375 func(buffer_id, buffer);
379 376
380 const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes(); 377 const DAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes();
381 page = Common::DivCeil(end_addr, CACHING_PAGESIZE); 378 page = Common::DivCeil(end_addr, CACHING_PAGESIZE);
382 } 379 }
383 } 380 }
384 381
385 template <typename Func> 382 template <typename Func>
386 void ForEachInRangeSet(IntervalSet& current_range, VAddr cpu_addr, u64 size, Func&& func) { 383 void ForEachInRangeSet(IntervalSet& current_range, DAddr device_addr, u64 size, Func&& func) {
387 const VAddr start_address = cpu_addr; 384 const DAddr start_address = device_addr;
388 const VAddr end_address = start_address + size; 385 const DAddr end_address = start_address + size;
389 const IntervalType search_interval{start_address, end_address}; 386 const IntervalType search_interval{start_address, end_address};
390 auto it = current_range.lower_bound(search_interval); 387 auto it = current_range.lower_bound(search_interval);
391 if (it == current_range.end()) { 388 if (it == current_range.end()) {
@@ -393,8 +390,8 @@ private:
393 } 390 }
394 auto end_it = current_range.upper_bound(search_interval); 391 auto end_it = current_range.upper_bound(search_interval);
395 for (; it != end_it; it++) { 392 for (; it != end_it; it++) {
396 VAddr inter_addr_end = it->upper(); 393 DAddr inter_addr_end = it->upper();
397 VAddr inter_addr = it->lower(); 394 DAddr inter_addr = it->lower();
398 if (inter_addr_end > end_address) { 395 if (inter_addr_end > end_address) {
399 inter_addr_end = end_address; 396 inter_addr_end = end_address;
400 } 397 }
@@ -406,10 +403,10 @@ private:
406 } 403 }
407 404
408 template <typename Func> 405 template <typename Func>
409 void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size, 406 void ForEachInOverlapCounter(OverlapCounter& current_range, DAddr device_addr, u64 size,
410 Func&& func) { 407 Func&& func) {
411 const VAddr start_address = cpu_addr; 408 const DAddr start_address = device_addr;
412 const VAddr end_address = start_address + size; 409 const DAddr end_address = start_address + size;
413 const IntervalType search_interval{start_address, end_address}; 410 const IntervalType search_interval{start_address, end_address};
414 auto it = current_range.lower_bound(search_interval); 411 auto it = current_range.lower_bound(search_interval);
415 if (it == current_range.end()) { 412 if (it == current_range.end()) {
@@ -418,8 +415,8 @@ private:
418 auto end_it = current_range.upper_bound(search_interval); 415 auto end_it = current_range.upper_bound(search_interval);
419 for (; it != end_it; it++) { 416 for (; it != end_it; it++) {
420 auto& inter = it->first; 417 auto& inter = it->first;
421 VAddr inter_addr_end = inter.upper(); 418 DAddr inter_addr_end = inter.upper();
422 VAddr inter_addr = inter.lower(); 419 DAddr inter_addr = inter.lower();
423 if (inter_addr_end > end_address) { 420 if (inter_addr_end > end_address) {
424 inter_addr_end = end_address; 421 inter_addr_end = end_address;
425 } 422 }
@@ -451,9 +448,9 @@ private:
451 } while (any_removals); 448 } while (any_removals);
452 } 449 }
453 450
454 static bool IsRangeGranular(VAddr cpu_addr, size_t size) { 451 static bool IsRangeGranular(DAddr device_addr, size_t size) {
455 return (cpu_addr & ~Core::Memory::YUZU_PAGEMASK) == 452 return (device_addr & ~Core::DEVICE_PAGEMASK) ==
456 ((cpu_addr + size) & ~Core::Memory::YUZU_PAGEMASK); 453 ((device_addr + size) & ~Core::DEVICE_PAGEMASK);
457 } 454 }
458 455
459 void RunGarbageCollector(); 456 void RunGarbageCollector();
@@ -508,15 +505,15 @@ private:
508 505
509 void UpdateComputeTextureBuffers(); 506 void UpdateComputeTextureBuffers();
510 507
511 void MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size); 508 void MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size);
512 509
513 [[nodiscard]] BufferId FindBuffer(VAddr cpu_addr, u32 size); 510 [[nodiscard]] BufferId FindBuffer(DAddr device_addr, u32 size);
514 511
515 [[nodiscard]] OverlapResult ResolveOverlaps(VAddr cpu_addr, u32 wanted_size); 512 [[nodiscard]] OverlapResult ResolveOverlaps(DAddr device_addr, u32 wanted_size);
516 513
517 void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score); 514 void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score);
518 515
519 [[nodiscard]] BufferId CreateBuffer(VAddr cpu_addr, u32 wanted_size); 516 [[nodiscard]] BufferId CreateBuffer(DAddr device_addr, u32 wanted_size);
520 517
521 void Register(BufferId buffer_id); 518 void Register(BufferId buffer_id);
522 519
@@ -527,7 +524,7 @@ private:
527 524
528 void TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept; 525 void TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept;
529 526
530 bool SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size); 527 bool SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size);
531 528
532 void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, 529 void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
533 std::span<BufferCopy> copies); 530 std::span<BufferCopy> copies);
@@ -539,7 +536,7 @@ private:
539 536
540 void DownloadBufferMemory(Buffer& buffer_id); 537 void DownloadBufferMemory(Buffer& buffer_id);
541 538
542 void DownloadBufferMemory(Buffer& buffer_id, VAddr cpu_addr, u64 size); 539 void DownloadBufferMemory(Buffer& buffer_id, DAddr device_addr, u64 size);
543 540
544 void DeleteBuffer(BufferId buffer_id, bool do_not_mark = false); 541 void DeleteBuffer(BufferId buffer_id, bool do_not_mark = false);
545 542
@@ -549,7 +546,7 @@ private:
549 [[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size, 546 [[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size,
550 PixelFormat format); 547 PixelFormat format);
551 548
552 [[nodiscard]] std::span<const u8> ImmediateBufferWithData(VAddr cpu_addr, size_t size); 549 [[nodiscard]] std::span<const u8> ImmediateBufferWithData(DAddr device_addr, size_t size);
553 550
554 [[nodiscard]] std::span<u8> ImmediateBuffer(size_t wanted_capacity); 551 [[nodiscard]] std::span<u8> ImmediateBuffer(size_t wanted_capacity);
555 552
@@ -557,11 +554,10 @@ private:
557 554
558 void ClearDownload(IntervalType subtract_interval); 555 void ClearDownload(IntervalType subtract_interval);
559 556
560 void InlineMemoryImplementation(VAddr dest_address, size_t copy_size, 557 void InlineMemoryImplementation(DAddr dest_address, size_t copy_size,
561 std::span<const u8> inlined_buffer); 558 std::span<const u8> inlined_buffer);
562 559
563 VideoCore::RasterizerInterface& rasterizer; 560 Tegra::MaxwellDeviceMemoryManager& device_memory;
564 Core::Memory::Memory& cpu_memory;
565 561
566 SlotVector<Buffer> slot_buffers; 562 SlotVector<Buffer> slot_buffers;
567 DelayedDestructionRing<Buffer, 8> delayed_destruction_ring; 563 DelayedDestructionRing<Buffer, 8> delayed_destruction_ring;
@@ -598,7 +594,7 @@ private:
598 u64 critical_memory = 0; 594 u64 critical_memory = 0;
599 BufferId inline_buffer_id; 595 BufferId inline_buffer_id;
600 596
601 std::array<BufferId, ((1ULL << 39) >> CACHING_PAGEBITS)> page_table; 597 std::array<BufferId, ((1ULL << 34) >> CACHING_PAGEBITS)> page_table;
602 Common::ScratchBuffer<u8> tmp_buffer; 598 Common::ScratchBuffer<u8> tmp_buffer;
603}; 599};
604 600
diff --git a/src/video_core/buffer_cache/memory_tracker_base.h b/src/video_core/buffer_cache/memory_tracker_base.h
index 6c1c8287b..c95eed1f6 100644
--- a/src/video_core/buffer_cache/memory_tracker_base.h
+++ b/src/video_core/buffer_cache/memory_tracker_base.h
@@ -17,19 +17,19 @@
17 17
18namespace VideoCommon { 18namespace VideoCommon {
19 19
20template <class RasterizerInterface> 20template <typename DeviceTracker>
21class MemoryTrackerBase { 21class MemoryTrackerBase {
22 static constexpr size_t MAX_CPU_PAGE_BITS = 39; 22 static constexpr size_t MAX_CPU_PAGE_BITS = 34;
23 static constexpr size_t HIGHER_PAGE_BITS = 22; 23 static constexpr size_t HIGHER_PAGE_BITS = 22;
24 static constexpr size_t HIGHER_PAGE_SIZE = 1ULL << HIGHER_PAGE_BITS; 24 static constexpr size_t HIGHER_PAGE_SIZE = 1ULL << HIGHER_PAGE_BITS;
25 static constexpr size_t HIGHER_PAGE_MASK = HIGHER_PAGE_SIZE - 1ULL; 25 static constexpr size_t HIGHER_PAGE_MASK = HIGHER_PAGE_SIZE - 1ULL;
26 static constexpr size_t NUM_HIGH_PAGES = 1ULL << (MAX_CPU_PAGE_BITS - HIGHER_PAGE_BITS); 26 static constexpr size_t NUM_HIGH_PAGES = 1ULL << (MAX_CPU_PAGE_BITS - HIGHER_PAGE_BITS);
27 static constexpr size_t MANAGER_POOL_SIZE = 32; 27 static constexpr size_t MANAGER_POOL_SIZE = 32;
28 static constexpr size_t WORDS_STACK_NEEDED = HIGHER_PAGE_SIZE / BYTES_PER_WORD; 28 static constexpr size_t WORDS_STACK_NEEDED = HIGHER_PAGE_SIZE / BYTES_PER_WORD;
29 using Manager = WordManager<RasterizerInterface, WORDS_STACK_NEEDED>; 29 using Manager = WordManager<DeviceTracker, WORDS_STACK_NEEDED>;
30 30
31public: 31public:
32 MemoryTrackerBase(RasterizerInterface& rasterizer_) : rasterizer{&rasterizer_} {} 32 MemoryTrackerBase(DeviceTracker& device_tracker_) : device_tracker{&device_tracker_} {}
33 ~MemoryTrackerBase() = default; 33 ~MemoryTrackerBase() = default;
34 34
35 /// Returns the inclusive CPU modified range in a begin end pair 35 /// Returns the inclusive CPU modified range in a begin end pair
@@ -74,7 +74,7 @@ public:
74 }); 74 });
75 } 75 }
76 76
77 /// Mark region as CPU modified, notifying the rasterizer about this change 77 /// Mark region as CPU modified, notifying the device_tracker about this change
78 void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) { 78 void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) {
79 IteratePages<true>(dirty_cpu_addr, query_size, 79 IteratePages<true>(dirty_cpu_addr, query_size,
80 [](Manager* manager, u64 offset, size_t size) { 80 [](Manager* manager, u64 offset, size_t size) {
@@ -83,7 +83,7 @@ public:
83 }); 83 });
84 } 84 }
85 85
86 /// Unmark region as CPU modified, notifying the rasterizer about this change 86 /// Unmark region as CPU modified, notifying the device_tracker about this change
87 void UnmarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) { 87 void UnmarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) {
88 IteratePages<true>(dirty_cpu_addr, query_size, 88 IteratePages<true>(dirty_cpu_addr, query_size,
89 [](Manager* manager, u64 offset, size_t size) { 89 [](Manager* manager, u64 offset, size_t size) {
@@ -139,7 +139,7 @@ public:
139 }); 139 });
140 } 140 }
141 141
142 /// Flushes cached CPU writes, and notify the rasterizer about the deltas 142 /// Flushes cached CPU writes, and notify the device_tracker about the deltas
143 void FlushCachedWrites(VAddr query_cpu_addr, u64 query_size) noexcept { 143 void FlushCachedWrites(VAddr query_cpu_addr, u64 query_size) noexcept {
144 IteratePages<false>(query_cpu_addr, query_size, 144 IteratePages<false>(query_cpu_addr, query_size,
145 [](Manager* manager, [[maybe_unused]] u64 offset, 145 [](Manager* manager, [[maybe_unused]] u64 offset,
@@ -280,7 +280,7 @@ private:
280 manager_pool.emplace_back(); 280 manager_pool.emplace_back();
281 auto& last_pool = manager_pool.back(); 281 auto& last_pool = manager_pool.back();
282 for (size_t i = 0; i < MANAGER_POOL_SIZE; i++) { 282 for (size_t i = 0; i < MANAGER_POOL_SIZE; i++) {
283 new (&last_pool[i]) Manager(0, *rasterizer, HIGHER_PAGE_SIZE); 283 new (&last_pool[i]) Manager(0, *device_tracker, HIGHER_PAGE_SIZE);
284 free_managers.push_back(&last_pool[i]); 284 free_managers.push_back(&last_pool[i]);
285 } 285 }
286 return on_return(); 286 return on_return();
@@ -293,7 +293,7 @@ private:
293 293
294 std::unordered_set<u32> cached_pages; 294 std::unordered_set<u32> cached_pages;
295 295
296 RasterizerInterface* rasterizer = nullptr; 296 DeviceTracker* device_tracker = nullptr;
297}; 297};
298 298
299} // namespace VideoCommon 299} // namespace VideoCommon
diff --git a/src/video_core/buffer_cache/word_manager.h b/src/video_core/buffer_cache/word_manager.h
index a336bde41..3db9d8b42 100644
--- a/src/video_core/buffer_cache/word_manager.h
+++ b/src/video_core/buffer_cache/word_manager.h
@@ -13,12 +13,12 @@
13#include "common/common_funcs.h" 13#include "common/common_funcs.h"
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/div_ceil.h" 15#include "common/div_ceil.h"
16#include "core/memory.h" 16#include "video_core/host1x/gpu_device_memory_manager.h"
17 17
18namespace VideoCommon { 18namespace VideoCommon {
19 19
20constexpr u64 PAGES_PER_WORD = 64; 20constexpr u64 PAGES_PER_WORD = 64;
21constexpr u64 BYTES_PER_PAGE = Core::Memory::YUZU_PAGESIZE; 21constexpr u64 BYTES_PER_PAGE = Core::DEVICE_PAGESIZE;
22constexpr u64 BYTES_PER_WORD = PAGES_PER_WORD * BYTES_PER_PAGE; 22constexpr u64 BYTES_PER_WORD = PAGES_PER_WORD * BYTES_PER_PAGE;
23 23
24enum class Type { 24enum class Type {
@@ -163,11 +163,11 @@ struct Words {
163 WordsArray<stack_words> preflushable; 163 WordsArray<stack_words> preflushable;
164}; 164};
165 165
166template <class RasterizerInterface, size_t stack_words = 1> 166template <class DeviceTracker, size_t stack_words = 1>
167class WordManager { 167class WordManager {
168public: 168public:
169 explicit WordManager(VAddr cpu_addr_, RasterizerInterface& rasterizer_, u64 size_bytes) 169 explicit WordManager(VAddr cpu_addr_, DeviceTracker& tracker_, u64 size_bytes)
170 : cpu_addr{cpu_addr_}, rasterizer{&rasterizer_}, words{size_bytes} {} 170 : cpu_addr{cpu_addr_}, tracker{&tracker_}, words{size_bytes} {}
171 171
172 explicit WordManager() = default; 172 explicit WordManager() = default;
173 173
@@ -279,7 +279,7 @@ public:
279 } 279 }
280 280
281 /** 281 /**
282 * Loop over each page in the given range, turn off those bits and notify the rasterizer if 282 * Loop over each page in the given range, turn off those bits and notify the tracker if
283 * needed. Call the given function on each turned off range. 283 * needed. Call the given function on each turned off range.
284 * 284 *
285 * @param query_cpu_range Base CPU address to loop over 285 * @param query_cpu_range Base CPU address to loop over
@@ -459,26 +459,26 @@ private:
459 } 459 }
460 460
461 /** 461 /**
462 * Notify rasterizer about changes in the CPU tracking state of a word in the buffer 462 * Notify tracker about changes in the CPU tracking state of a word in the buffer
463 * 463 *
464 * @param word_index Index to the word to notify to the rasterizer 464 * @param word_index Index to the word to notify to the tracker
465 * @param current_bits Current state of the word 465 * @param current_bits Current state of the word
466 * @param new_bits New state of the word 466 * @param new_bits New state of the word
467 * 467 *
468 * @tparam add_to_rasterizer True when the rasterizer should start tracking the new pages 468 * @tparam add_to_tracker True when the tracker should start tracking the new pages
469 */ 469 */
470 template <bool add_to_rasterizer> 470 template <bool add_to_tracker>
471 void NotifyRasterizer(u64 word_index, u64 current_bits, u64 new_bits) const { 471 void NotifyRasterizer(u64 word_index, u64 current_bits, u64 new_bits) const {
472 u64 changed_bits = (add_to_rasterizer ? current_bits : ~current_bits) & new_bits; 472 u64 changed_bits = (add_to_tracker ? current_bits : ~current_bits) & new_bits;
473 VAddr addr = cpu_addr + word_index * BYTES_PER_WORD; 473 VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
474 IteratePages(changed_bits, [&](size_t offset, size_t size) { 474 IteratePages(changed_bits, [&](size_t offset, size_t size) {
475 rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE, 475 tracker->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE, size * BYTES_PER_PAGE,
476 size * BYTES_PER_PAGE, add_to_rasterizer ? 1 : -1); 476 add_to_tracker ? 1 : -1);
477 }); 477 });
478 } 478 }
479 479
480 VAddr cpu_addr = 0; 480 VAddr cpu_addr = 0;
481 RasterizerInterface* rasterizer = nullptr; 481 DeviceTracker* tracker = nullptr;
482 Words<stack_words> words; 482 Words<stack_words> words;
483}; 483};
484 484
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 58ce0d8c2..fb2060ca4 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -5,10 +5,10 @@
5#include "common/microprofile.h" 5#include "common/microprofile.h"
6#include "common/settings.h" 6#include "common/settings.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/memory.h"
9#include "video_core/dma_pusher.h" 8#include "video_core/dma_pusher.h"
10#include "video_core/engines/maxwell_3d.h" 9#include "video_core/engines/maxwell_3d.h"
11#include "video_core/gpu.h" 10#include "video_core/gpu.h"
11#include "video_core/guest_memory.h"
12#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
13 13
14namespace Tegra { 14namespace Tegra {
@@ -85,15 +85,15 @@ bool DmaPusher::Step() {
85 } 85 }
86 } 86 }
87 const auto safe_process = [&] { 87 const auto safe_process = [&] {
88 Core::Memory::GpuGuestMemory<Tegra::CommandHeader, 88 Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader,
89 Core::Memory::GuestMemoryFlags::SafeRead> 89 Tegra::Memory::GuestMemoryFlags::SafeRead>
90 headers(memory_manager, dma_state.dma_get, command_list_header.size, 90 headers(memory_manager, dma_state.dma_get, command_list_header.size,
91 &command_headers); 91 &command_headers);
92 ProcessCommands(headers); 92 ProcessCommands(headers);
93 }; 93 };
94 const auto unsafe_process = [&] { 94 const auto unsafe_process = [&] {
95 Core::Memory::GpuGuestMemory<Tegra::CommandHeader, 95 Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader,
96 Core::Memory::GuestMemoryFlags::UnsafeRead> 96 Tegra::Memory::GuestMemoryFlags::UnsafeRead>
97 headers(memory_manager, dma_state.dma_get, command_list_header.size, 97 headers(memory_manager, dma_state.dma_get, command_list_header.size,
98 &command_headers); 98 &command_headers);
99 ProcessCommands(headers); 99 ProcessCommands(headers);
diff --git a/src/video_core/engines/engine_upload.cpp b/src/video_core/engines/engine_upload.cpp
index bc64d4486..e5cc04ec4 100644
--- a/src/video_core/engines/engine_upload.cpp
+++ b/src/video_core/engines/engine_upload.cpp
@@ -5,8 +5,8 @@
5 5
6#include "common/algorithm.h" 6#include "common/algorithm.h"
7#include "common/assert.h" 7#include "common/assert.h"
8#include "core/memory.h"
9#include "video_core/engines/engine_upload.h" 8#include "video_core/engines/engine_upload.h"
9#include "video_core/guest_memory.h"
10#include "video_core/memory_manager.h" 10#include "video_core/memory_manager.h"
11#include "video_core/rasterizer_interface.h" 11#include "video_core/rasterizer_interface.h"
12#include "video_core/textures/decoders.h" 12#include "video_core/textures/decoders.h"
@@ -68,7 +68,8 @@ void State::ProcessData(std::span<const u8> read_buffer) {
68 true, bytes_per_pixel, width, regs.dest.height, regs.dest.depth, 68 true, bytes_per_pixel, width, regs.dest.height, regs.dest.depth,
69 regs.dest.BlockHeight(), regs.dest.BlockDepth()); 69 regs.dest.BlockHeight(), regs.dest.BlockDepth());
70 70
71 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> 71 Tegra::Memory::GpuGuestMemoryScoped<u8,
72 Tegra::Memory::GuestMemoryFlags::SafeReadCachedWrite>
72 tmp(memory_manager, address, dst_size, &tmp_buffer); 73 tmp(memory_manager, address, dst_size, &tmp_buffer);
73 74
74 Tegra::Texture::SwizzleSubrect(tmp, read_buffer, bytes_per_pixel, width, regs.dest.height, 75 Tegra::Texture::SwizzleSubrect(tmp, read_buffer, bytes_per_pixel, width, regs.dest.height,
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 95ba4f76c..a94e1f043 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -9,7 +9,6 @@
9#include "common/settings.h" 9#include "common/settings.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/core_timing.h" 11#include "core/core_timing.h"
12#include "core/memory.h"
13#include "video_core/dirty_flags.h" 12#include "video_core/dirty_flags.h"
14#include "video_core/engines/draw_manager.h" 13#include "video_core/engines/draw_manager.h"
15#include "video_core/engines/maxwell_3d.h" 14#include "video_core/engines/maxwell_3d.h"
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 56fbff306..2ebd21fc5 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -8,9 +8,9 @@
8#include "common/polyfill_ranges.h" 8#include "common/polyfill_ranges.h"
9#include "common/settings.h" 9#include "common/settings.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/memory.h"
12#include "video_core/engines/maxwell_3d.h" 11#include "video_core/engines/maxwell_3d.h"
13#include "video_core/engines/maxwell_dma.h" 12#include "video_core/engines/maxwell_dma.h"
13#include "video_core/guest_memory.h"
14#include "video_core/memory_manager.h" 14#include "video_core/memory_manager.h"
15#include "video_core/renderer_base.h" 15#include "video_core/renderer_base.h"
16#include "video_core/textures/decoders.h" 16#include "video_core/textures/decoders.h"
@@ -133,8 +133,8 @@ void MaxwellDMA::Launch() {
133 UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); 133 UNIMPLEMENTED_IF(regs.offset_out % 16 != 0);
134 read_buffer.resize_destructive(16); 134 read_buffer.resize_destructive(16);
135 for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { 135 for (u32 offset = 0; offset < regs.line_length_in; offset += 16) {
136 Core::Memory::GpuGuestMemoryScoped< 136 Tegra::Memory::GpuGuestMemoryScoped<
137 u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> 137 u8, Tegra::Memory::GuestMemoryFlags::SafeReadCachedWrite>
138 tmp_write_buffer(memory_manager, 138 tmp_write_buffer(memory_manager,
139 convert_linear_2_blocklinear_addr(regs.offset_in + offset), 139 convert_linear_2_blocklinear_addr(regs.offset_in + offset),
140 16, &read_buffer); 140 16, &read_buffer);
@@ -146,16 +146,16 @@ void MaxwellDMA::Launch() {
146 UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); 146 UNIMPLEMENTED_IF(regs.offset_out % 16 != 0);
147 read_buffer.resize_destructive(16); 147 read_buffer.resize_destructive(16);
148 for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { 148 for (u32 offset = 0; offset < regs.line_length_in; offset += 16) {
149 Core::Memory::GpuGuestMemoryScoped< 149 Tegra::Memory::GpuGuestMemoryScoped<
150 u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> 150 u8, Tegra::Memory::GuestMemoryFlags::SafeReadCachedWrite>
151 tmp_write_buffer(memory_manager, regs.offset_in + offset, 16, &read_buffer); 151 tmp_write_buffer(memory_manager, regs.offset_in + offset, 16, &read_buffer);
152 tmp_write_buffer.SetAddressAndSize( 152 tmp_write_buffer.SetAddressAndSize(
153 convert_linear_2_blocklinear_addr(regs.offset_out + offset), 16); 153 convert_linear_2_blocklinear_addr(regs.offset_out + offset), 16);
154 } 154 }
155 } else { 155 } else {
156 if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { 156 if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) {
157 Core::Memory::GpuGuestMemoryScoped< 157 Tegra::Memory::GpuGuestMemoryScoped<
158 u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> 158 u8, Tegra::Memory::GuestMemoryFlags::SafeReadCachedWrite>
159 tmp_write_buffer(memory_manager, regs.offset_in, regs.line_length_in, 159 tmp_write_buffer(memory_manager, regs.offset_in, regs.line_length_in,
160 &read_buffer); 160 &read_buffer);
161 tmp_write_buffer.SetAddressAndSize(regs.offset_out, regs.line_length_in); 161 tmp_write_buffer.SetAddressAndSize(regs.offset_out, regs.line_length_in);
@@ -226,9 +226,9 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
226 226
227 const size_t dst_size = dst_operand.pitch * regs.line_count; 227 const size_t dst_size = dst_operand.pitch * regs.line_count;
228 228
229 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( 229 Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
230 memory_manager, src_operand.address, src_size, &read_buffer); 230 memory_manager, src_operand.address, src_size, &read_buffer);
231 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadCachedWrite> 231 Tegra::Memory::GpuGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::UnsafeReadCachedWrite>
232 tmp_write_buffer(memory_manager, dst_operand.address, dst_size, &write_buffer); 232 tmp_write_buffer(memory_manager, dst_operand.address, dst_size, &write_buffer);
233 233
234 UnswizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth, 234 UnswizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth,
@@ -290,9 +290,9 @@ void MaxwellDMA::CopyPitchToBlockLinear() {
290 290
291 GPUVAddr src_addr = regs.offset_in; 291 GPUVAddr src_addr = regs.offset_in;
292 GPUVAddr dst_addr = regs.offset_out; 292 GPUVAddr dst_addr = regs.offset_out;
293 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( 293 Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
294 memory_manager, src_addr, src_size, &read_buffer); 294 memory_manager, src_addr, src_size, &read_buffer);
295 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadCachedWrite> 295 Tegra::Memory::GpuGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::UnsafeReadCachedWrite>
296 tmp_write_buffer(memory_manager, dst_addr, dst_size, &write_buffer); 296 tmp_write_buffer(memory_manager, dst_addr, dst_size, &write_buffer);
297 297
298 // If the input is linear and the output is tiled, swizzle the input and copy it over. 298 // If the input is linear and the output is tiled, swizzle the input and copy it over.
@@ -344,9 +344,9 @@ void MaxwellDMA::CopyBlockLinearToBlockLinear() {
344 344
345 intermediate_buffer.resize_destructive(mid_buffer_size); 345 intermediate_buffer.resize_destructive(mid_buffer_size);
346 346
347 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( 347 Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer(
348 memory_manager, regs.offset_in, src_size, &read_buffer); 348 memory_manager, regs.offset_in, src_size, &read_buffer);
349 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> 349 Tegra::Memory::GpuGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::SafeReadCachedWrite>
350 tmp_write_buffer(memory_manager, regs.offset_out, dst_size, &write_buffer); 350 tmp_write_buffer(memory_manager, regs.offset_out, dst_size, &write_buffer);
351 351
352 UnswizzleSubrect(intermediate_buffer, tmp_read_buffer, bytes_per_pixel, src_width, src.height, 352 UnswizzleSubrect(intermediate_buffer, tmp_read_buffer, bytes_per_pixel, src_width, src.height,
diff --git a/src/video_core/engines/sw_blitter/blitter.cpp b/src/video_core/engines/sw_blitter/blitter.cpp
index 67ce9134b..4bc079024 100644
--- a/src/video_core/engines/sw_blitter/blitter.cpp
+++ b/src/video_core/engines/sw_blitter/blitter.cpp
@@ -8,6 +8,7 @@
8#include "common/scratch_buffer.h" 8#include "common/scratch_buffer.h"
9#include "video_core/engines/sw_blitter/blitter.h" 9#include "video_core/engines/sw_blitter/blitter.h"
10#include "video_core/engines/sw_blitter/converter.h" 10#include "video_core/engines/sw_blitter/converter.h"
11#include "video_core/guest_memory.h"
11#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
12#include "video_core/surface.h" 13#include "video_core/surface.h"
13#include "video_core/textures/decoders.h" 14#include "video_core/textures/decoders.h"
@@ -160,7 +161,7 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
160 const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format)); 161 const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format));
161 const size_t src_size = get_surface_size(src, src_bytes_per_pixel); 162 const size_t src_size = get_surface_size(src, src_bytes_per_pixel);
162 163
163 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_buffer( 164 Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::SafeRead> tmp_buffer(
164 memory_manager, src.Address(), src_size, &impl->tmp_buffer); 165 memory_manager, src.Address(), src_size, &impl->tmp_buffer);
165 166
166 const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel; 167 const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel;
@@ -220,7 +221,7 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
220 } 221 }
221 222
222 const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel); 223 const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel);
223 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadWrite> 224 Tegra::Memory::GpuGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::SafeReadWrite>
224 tmp_buffer2(memory_manager, dst.Address(), dst_size, &impl->tmp_buffer); 225 tmp_buffer2(memory_manager, dst.Address(), dst_size, &impl->tmp_buffer);
225 226
226 if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) { 227 if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) {
diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h
index 5f3bffcab..856f4bd52 100644
--- a/src/video_core/framebuffer_config.h
+++ b/src/video_core/framebuffer_config.h
@@ -14,7 +14,7 @@ namespace Tegra {
14 * Struct describing framebuffer configuration 14 * Struct describing framebuffer configuration
15 */ 15 */
16struct FramebufferConfig { 16struct FramebufferConfig {
17 VAddr address{}; 17 DAddr address{};
18 u32 offset{}; 18 u32 offset{};
19 u32 width{}; 19 u32 width{};
20 u32 height{}; 20 u32 height{};
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 11549d448..609704b33 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -85,7 +85,8 @@ struct GPU::Impl {
85 void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) { 85 void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
86 renderer = std::move(renderer_); 86 renderer = std::move(renderer_);
87 rasterizer = renderer->ReadRasterizer(); 87 rasterizer = renderer->ReadRasterizer();
88 host1x.MemoryManager().BindRasterizer(rasterizer); 88 host1x.MemoryManager().BindInterface(rasterizer);
89 host1x.GMMU().BindRasterizer(rasterizer);
89 } 90 }
90 91
91 /// Flush all current written commands into the host GPU for execution. 92 /// Flush all current written commands into the host GPU for execution.
@@ -95,8 +96,8 @@ struct GPU::Impl {
95 96
96 /// Synchronizes CPU writes with Host GPU memory. 97 /// Synchronizes CPU writes with Host GPU memory.
97 void InvalidateGPUCache() { 98 void InvalidateGPUCache() {
98 std::function<void(VAddr, size_t)> callback_writes( 99 std::function<void(PAddr, size_t)> callback_writes(
99 [this](VAddr address, size_t size) { rasterizer->OnCacheInvalidation(address, size); }); 100 [this](PAddr address, size_t size) { rasterizer->OnCacheInvalidation(address, size); });
100 system.GatherGPUDirtyMemory(callback_writes); 101 system.GatherGPUDirtyMemory(callback_writes);
101 } 102 }
102 103
@@ -279,11 +280,11 @@ struct GPU::Impl {
279 } 280 }
280 281
281 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 282 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
282 void FlushRegion(VAddr addr, u64 size) { 283 void FlushRegion(DAddr addr, u64 size) {
283 gpu_thread.FlushRegion(addr, size); 284 gpu_thread.FlushRegion(addr, size);
284 } 285 }
285 286
286 VideoCore::RasterizerDownloadArea OnCPURead(VAddr addr, u64 size) { 287 VideoCore::RasterizerDownloadArea OnCPURead(DAddr addr, u64 size) {
287 auto raster_area = rasterizer->GetFlushArea(addr, size); 288 auto raster_area = rasterizer->GetFlushArea(addr, size);
288 if (raster_area.preemtive) { 289 if (raster_area.preemtive) {
289 return raster_area; 290 return raster_area;
@@ -299,16 +300,16 @@ struct GPU::Impl {
299 } 300 }
300 301
301 /// Notify rasterizer that any caches of the specified region should be invalidated 302 /// Notify rasterizer that any caches of the specified region should be invalidated
302 void InvalidateRegion(VAddr addr, u64 size) { 303 void InvalidateRegion(DAddr addr, u64 size) {
303 gpu_thread.InvalidateRegion(addr, size); 304 gpu_thread.InvalidateRegion(addr, size);
304 } 305 }
305 306
306 bool OnCPUWrite(VAddr addr, u64 size) { 307 bool OnCPUWrite(DAddr addr, u64 size) {
307 return rasterizer->OnCPUWrite(addr, size); 308 return rasterizer->OnCPUWrite(addr, size);
308 } 309 }
309 310
310 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 311 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
311 void FlushAndInvalidateRegion(VAddr addr, u64 size) { 312 void FlushAndInvalidateRegion(DAddr addr, u64 size) {
312 gpu_thread.FlushAndInvalidateRegion(addr, size); 313 gpu_thread.FlushAndInvalidateRegion(addr, size);
313 } 314 }
314 315
@@ -437,7 +438,7 @@ void GPU::OnCommandListEnd() {
437 impl->OnCommandListEnd(); 438 impl->OnCommandListEnd();
438} 439}
439 440
440u64 GPU::RequestFlush(VAddr addr, std::size_t size) { 441u64 GPU::RequestFlush(DAddr addr, std::size_t size) {
441 return impl->RequestSyncOperation( 442 return impl->RequestSyncOperation(
442 [this, addr, size]() { impl->rasterizer->FlushRegion(addr, size); }); 443 [this, addr, size]() { impl->rasterizer->FlushRegion(addr, size); });
443} 444}
@@ -557,23 +558,23 @@ void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
557 impl->SwapBuffers(framebuffer); 558 impl->SwapBuffers(framebuffer);
558} 559}
559 560
560VideoCore::RasterizerDownloadArea GPU::OnCPURead(VAddr addr, u64 size) { 561VideoCore::RasterizerDownloadArea GPU::OnCPURead(PAddr addr, u64 size) {
561 return impl->OnCPURead(addr, size); 562 return impl->OnCPURead(addr, size);
562} 563}
563 564
564void GPU::FlushRegion(VAddr addr, u64 size) { 565void GPU::FlushRegion(DAddr addr, u64 size) {
565 impl->FlushRegion(addr, size); 566 impl->FlushRegion(addr, size);
566} 567}
567 568
568void GPU::InvalidateRegion(VAddr addr, u64 size) { 569void GPU::InvalidateRegion(DAddr addr, u64 size) {
569 impl->InvalidateRegion(addr, size); 570 impl->InvalidateRegion(addr, size);
570} 571}
571 572
572bool GPU::OnCPUWrite(VAddr addr, u64 size) { 573bool GPU::OnCPUWrite(DAddr addr, u64 size) {
573 return impl->OnCPUWrite(addr, size); 574 return impl->OnCPUWrite(addr, size);
574} 575}
575 576
576void GPU::FlushAndInvalidateRegion(VAddr addr, u64 size) { 577void GPU::FlushAndInvalidateRegion(DAddr addr, u64 size) {
577 impl->FlushAndInvalidateRegion(addr, size); 578 impl->FlushAndInvalidateRegion(addr, size);
578} 579}
579 580
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index ba2838b89..b3c1d15bd 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -158,7 +158,7 @@ public:
158 void InitAddressSpace(Tegra::MemoryManager& memory_manager); 158 void InitAddressSpace(Tegra::MemoryManager& memory_manager);
159 159
160 /// Request a host GPU memory flush from the CPU. 160 /// Request a host GPU memory flush from the CPU.
161 [[nodiscard]] u64 RequestFlush(VAddr addr, std::size_t size); 161 [[nodiscard]] u64 RequestFlush(DAddr addr, std::size_t size);
162 162
163 /// Obtains current flush request fence id. 163 /// Obtains current flush request fence id.
164 [[nodiscard]] u64 CurrentSyncRequestFence() const; 164 [[nodiscard]] u64 CurrentSyncRequestFence() const;
@@ -242,20 +242,20 @@ public:
242 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer); 242 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer);
243 243
244 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 244 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
245 [[nodiscard]] VideoCore::RasterizerDownloadArea OnCPURead(VAddr addr, u64 size); 245 [[nodiscard]] VideoCore::RasterizerDownloadArea OnCPURead(DAddr addr, u64 size);
246 246
247 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 247 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
248 void FlushRegion(VAddr addr, u64 size); 248 void FlushRegion(DAddr addr, u64 size);
249 249
250 /// Notify rasterizer that any caches of the specified region should be invalidated 250 /// Notify rasterizer that any caches of the specified region should be invalidated
251 void InvalidateRegion(VAddr addr, u64 size); 251 void InvalidateRegion(DAddr addr, u64 size);
252 252
253 /// Notify rasterizer that CPU is trying to write this area. It returns true if the area is 253 /// Notify rasterizer that CPU is trying to write this area. It returns true if the area is
254 /// sensible, false otherwise 254 /// sensible, false otherwise
255 bool OnCPUWrite(VAddr addr, u64 size); 255 bool OnCPUWrite(DAddr addr, u64 size);
256 256
257 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 257 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
258 void FlushAndInvalidateRegion(VAddr addr, u64 size); 258 void FlushAndInvalidateRegion(DAddr addr, u64 size);
259 259
260private: 260private:
261 struct Impl; 261 struct Impl;
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 2f0f9f593..788d4f61e 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -82,7 +82,7 @@ void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
82 PushCommand(SwapBuffersCommand(framebuffer ? std::make_optional(*framebuffer) : std::nullopt)); 82 PushCommand(SwapBuffersCommand(framebuffer ? std::make_optional(*framebuffer) : std::nullopt));
83} 83}
84 84
85void ThreadManager::FlushRegion(VAddr addr, u64 size) { 85void ThreadManager::FlushRegion(DAddr addr, u64 size) {
86 if (!is_async) { 86 if (!is_async) {
87 // Always flush with synchronous GPU mode 87 // Always flush with synchronous GPU mode
88 PushCommand(FlushRegionCommand(addr, size)); 88 PushCommand(FlushRegionCommand(addr, size));
@@ -101,11 +101,11 @@ void ThreadManager::TickGPU() {
101 PushCommand(GPUTickCommand()); 101 PushCommand(GPUTickCommand());
102} 102}
103 103
104void ThreadManager::InvalidateRegion(VAddr addr, u64 size) { 104void ThreadManager::InvalidateRegion(DAddr addr, u64 size) {
105 rasterizer->OnCacheInvalidation(addr, size); 105 rasterizer->OnCacheInvalidation(addr, size);
106} 106}
107 107
108void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) { 108void ThreadManager::FlushAndInvalidateRegion(DAddr addr, u64 size) {
109 // Skip flush on asynch mode, as FlushAndInvalidateRegion is not used for anything too important 109 // Skip flush on asynch mode, as FlushAndInvalidateRegion is not used for anything too important
110 rasterizer->OnCacheInvalidation(addr, size); 110 rasterizer->OnCacheInvalidation(addr, size);
111} 111}
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 43940bd6d..2de25e9ef 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -54,26 +54,26 @@ struct SwapBuffersCommand final {
54 54
55/// Command to signal to the GPU thread to flush a region 55/// Command to signal to the GPU thread to flush a region
56struct FlushRegionCommand final { 56struct FlushRegionCommand final {
57 explicit constexpr FlushRegionCommand(VAddr addr_, u64 size_) : addr{addr_}, size{size_} {} 57 explicit constexpr FlushRegionCommand(DAddr addr_, u64 size_) : addr{addr_}, size{size_} {}
58 58
59 VAddr addr; 59 DAddr addr;
60 u64 size; 60 u64 size;
61}; 61};
62 62
63/// Command to signal to the GPU thread to invalidate a region 63/// Command to signal to the GPU thread to invalidate a region
64struct InvalidateRegionCommand final { 64struct InvalidateRegionCommand final {
65 explicit constexpr InvalidateRegionCommand(VAddr addr_, u64 size_) : addr{addr_}, size{size_} {} 65 explicit constexpr InvalidateRegionCommand(DAddr addr_, u64 size_) : addr{addr_}, size{size_} {}
66 66
67 VAddr addr; 67 DAddr addr;
68 u64 size; 68 u64 size;
69}; 69};
70 70
71/// Command to signal to the GPU thread to flush and invalidate a region 71/// Command to signal to the GPU thread to flush and invalidate a region
72struct FlushAndInvalidateRegionCommand final { 72struct FlushAndInvalidateRegionCommand final {
73 explicit constexpr FlushAndInvalidateRegionCommand(VAddr addr_, u64 size_) 73 explicit constexpr FlushAndInvalidateRegionCommand(DAddr addr_, u64 size_)
74 : addr{addr_}, size{size_} {} 74 : addr{addr_}, size{size_} {}
75 75
76 VAddr addr; 76 DAddr addr;
77 u64 size; 77 u64 size;
78}; 78};
79 79
@@ -122,13 +122,13 @@ public:
122 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer); 122 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer);
123 123
124 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 124 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
125 void FlushRegion(VAddr addr, u64 size); 125 void FlushRegion(DAddr addr, u64 size);
126 126
127 /// Notify rasterizer that any caches of the specified region should be invalidated 127 /// Notify rasterizer that any caches of the specified region should be invalidated
128 void InvalidateRegion(VAddr addr, u64 size); 128 void InvalidateRegion(DAddr addr, u64 size);
129 129
130 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 130 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
131 void FlushAndInvalidateRegion(VAddr addr, u64 size); 131 void FlushAndInvalidateRegion(DAddr addr, u64 size);
132 132
133 void TickGPU(); 133 void TickGPU();
134 134
diff --git a/src/video_core/guest_memory.h b/src/video_core/guest_memory.h
new file mode 100644
index 000000000..8b6213172
--- /dev/null
+++ b/src/video_core/guest_memory.h
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <iterator>
7#include <memory>
8#include <optional>
9#include <span>
10#include <vector>
11
12#include "common/scratch_buffer.h"
13#include "core/guest_memory.h"
14#include "video_core/memory_manager.h"
15
16namespace Tegra::Memory {
17
18using GuestMemoryFlags = Core::Memory::GuestMemoryFlags;
19
20template <typename T, GuestMemoryFlags FLAGS>
21using DeviceGuestMemory = Core::Memory::GuestMemory<Tegra::MaxwellDeviceMemoryManager, T, FLAGS>;
22template <typename T, GuestMemoryFlags FLAGS>
23using DeviceGuestMemoryScoped =
24 Core::Memory::GuestMemoryScoped<Tegra::MaxwellDeviceMemoryManager, T, FLAGS>;
25template <typename T, GuestMemoryFlags FLAGS>
26using GpuGuestMemory = Core::Memory::GuestMemory<Tegra::MemoryManager, T, FLAGS>;
27template <typename T, GuestMemoryFlags FLAGS>
28using GpuGuestMemoryScoped = Core::Memory::GuestMemoryScoped<Tegra::MemoryManager, T, FLAGS>;
29
30} // namespace Tegra::Memory
diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp
index 309a7f1d5..994591c8d 100644
--- a/src/video_core/host1x/codecs/h264.cpp
+++ b/src/video_core/host1x/codecs/h264.cpp
@@ -32,13 +32,12 @@ H264::~H264() = default;
32std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state, 32std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
33 size_t* out_configuration_size, bool is_first_frame) { 33 size_t* out_configuration_size, bool is_first_frame) {
34 H264DecoderContext context; 34 H264DecoderContext context;
35 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &context, 35 host1x.GMMU().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext));
36 sizeof(H264DecoderContext));
37 36
38 const s64 frame_number = context.h264_parameter_set.frame_number.Value(); 37 const s64 frame_number = context.h264_parameter_set.frame_number.Value();
39 if (!is_first_frame && frame_number != 0) { 38 if (!is_first_frame && frame_number != 0) {
40 frame.resize_destructive(context.stream_len); 39 frame.resize_destructive(context.stream_len);
41 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size()); 40 host1x.GMMU().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size());
42 *out_configuration_size = 0; 41 *out_configuration_size = 0;
43 return frame; 42 return frame;
44 } 43 }
@@ -159,8 +158,8 @@ std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters
159 std::memcpy(frame.data(), encoded_header.data(), encoded_header.size()); 158 std::memcpy(frame.data(), encoded_header.data(), encoded_header.size());
160 159
161 *out_configuration_size = encoded_header.size(); 160 *out_configuration_size = encoded_header.size();
162 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, 161 host1x.GMMU().ReadBlock(state.frame_bitstream_offset, frame.data() + encoded_header.size(),
163 frame.data() + encoded_header.size(), context.stream_len); 162 context.stream_len);
164 163
165 return frame; 164 return frame;
166} 165}
diff --git a/src/video_core/host1x/codecs/vp8.cpp b/src/video_core/host1x/codecs/vp8.cpp
index ee6392ff9..be97e3b00 100644
--- a/src/video_core/host1x/codecs/vp8.cpp
+++ b/src/video_core/host1x/codecs/vp8.cpp
@@ -14,7 +14,7 @@ VP8::~VP8() = default;
14 14
15std::span<const u8> VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state) { 15std::span<const u8> VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state) {
16 VP8PictureInfo info; 16 VP8PictureInfo info;
17 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &info, sizeof(VP8PictureInfo)); 17 host1x.GMMU().ReadBlock(state.picture_info_offset, &info, sizeof(VP8PictureInfo));
18 18
19 const bool is_key_frame = info.key_frame == 1u; 19 const bool is_key_frame = info.key_frame == 1u;
20 const auto bitstream_size = static_cast<size_t>(info.vld_buffer_size); 20 const auto bitstream_size = static_cast<size_t>(info.vld_buffer_size);
@@ -45,7 +45,7 @@ std::span<const u8> VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters&
45 frame[9] = static_cast<u8>(((info.frame_height >> 8) & 0x3f)); 45 frame[9] = static_cast<u8>(((info.frame_height >> 8) & 0x3f));
46 } 46 }
47 const u64 bitstream_offset = state.frame_bitstream_offset; 47 const u64 bitstream_offset = state.frame_bitstream_offset;
48 host1x.MemoryManager().ReadBlock(bitstream_offset, frame.data() + header_size, bitstream_size); 48 host1x.GMMU().ReadBlock(bitstream_offset, frame.data() + header_size, bitstream_size);
49 49
50 return frame; 50 return frame;
51} 51}
diff --git a/src/video_core/host1x/codecs/vp9.cpp b/src/video_core/host1x/codecs/vp9.cpp
index 306c3d0e8..65d6fb2d5 100644
--- a/src/video_core/host1x/codecs/vp9.cpp
+++ b/src/video_core/host1x/codecs/vp9.cpp
@@ -358,7 +358,7 @@ void VP9::WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_
358 358
359Vp9PictureInfo VP9::GetVp9PictureInfo(const Host1x::NvdecCommon::NvdecRegisters& state) { 359Vp9PictureInfo VP9::GetVp9PictureInfo(const Host1x::NvdecCommon::NvdecRegisters& state) {
360 PictureInfo picture_info; 360 PictureInfo picture_info;
361 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo)); 361 host1x.GMMU().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo));
362 Vp9PictureInfo vp9_info = picture_info.Convert(); 362 Vp9PictureInfo vp9_info = picture_info.Convert();
363 363
364 InsertEntropy(state.vp9_entropy_probs_offset, vp9_info.entropy); 364 InsertEntropy(state.vp9_entropy_probs_offset, vp9_info.entropy);
@@ -373,7 +373,7 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const Host1x::NvdecCommon::NvdecRegisters&
373 373
374void VP9::InsertEntropy(u64 offset, Vp9EntropyProbs& dst) { 374void VP9::InsertEntropy(u64 offset, Vp9EntropyProbs& dst) {
375 EntropyProbs entropy; 375 EntropyProbs entropy;
376 host1x.MemoryManager().ReadBlock(offset, &entropy, sizeof(EntropyProbs)); 376 host1x.GMMU().ReadBlock(offset, &entropy, sizeof(EntropyProbs));
377 entropy.Convert(dst); 377 entropy.Convert(dst);
378} 378}
379 379
@@ -383,9 +383,8 @@ Vp9FrameContainer VP9::GetCurrentFrame(const Host1x::NvdecCommon::NvdecRegisters
383 // gpu.SyncGuestHost(); epic, why? 383 // gpu.SyncGuestHost(); epic, why?
384 current_frame.info = GetVp9PictureInfo(state); 384 current_frame.info = GetVp9PictureInfo(state);
385 current_frame.bit_stream.resize(current_frame.info.bitstream_size); 385 current_frame.bit_stream.resize(current_frame.info.bitstream_size);
386 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, 386 host1x.GMMU().ReadBlock(state.frame_bitstream_offset, current_frame.bit_stream.data(),
387 current_frame.bit_stream.data(), 387 current_frame.info.bitstream_size);
388 current_frame.info.bitstream_size);
389 } 388 }
390 if (!next_frame.bit_stream.empty()) { 389 if (!next_frame.bit_stream.empty()) {
391 Vp9FrameContainer temp{ 390 Vp9FrameContainer temp{
diff --git a/src/video_core/host1x/gpu_device_memory_manager.cpp b/src/video_core/host1x/gpu_device_memory_manager.cpp
new file mode 100644
index 000000000..668c2f08b
--- /dev/null
+++ b/src/video_core/host1x/gpu_device_memory_manager.cpp
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/device_memory_manager.inc"
5#include "video_core/host1x/gpu_device_memory_manager.h"
6#include "video_core/rasterizer_interface.h"
7
8namespace Tegra {
9
10struct MaxwellDeviceMethods {
11 static inline void MarkRegionCaching(Core::Memory::Memory* interface, VAddr address,
12 size_t size, bool caching) {
13 interface->RasterizerMarkRegionCached(address, size, caching);
14 }
15};
16
17} // namespace Tegra
18
19template struct Core::DeviceMemoryManagerAllocator<Tegra::MaxwellDeviceTraits>;
20template class Core::DeviceMemoryManager<Tegra::MaxwellDeviceTraits>;
21
22template const u8* Tegra::MaxwellDeviceMemoryManager::GetPointer<u8>(DAddr addr) const;
23template u8* Tegra::MaxwellDeviceMemoryManager::GetPointer<u8>(DAddr addr);
24
25template u8 Tegra::MaxwellDeviceMemoryManager::Read<u8>(DAddr addr) const;
26template u16 Tegra::MaxwellDeviceMemoryManager::Read<u16>(DAddr addr) const;
27template u32 Tegra::MaxwellDeviceMemoryManager::Read<u32>(DAddr addr) const;
28template u64 Tegra::MaxwellDeviceMemoryManager::Read<u64>(DAddr addr) const;
29template void Tegra::MaxwellDeviceMemoryManager::Write<u8>(DAddr addr, u8 data);
30template void Tegra::MaxwellDeviceMemoryManager::Write<u16>(DAddr addr, u16 data);
31template void Tegra::MaxwellDeviceMemoryManager::Write<u32>(DAddr addr, u32 data);
32template void Tegra::MaxwellDeviceMemoryManager::Write<u64>(DAddr addr, u64 data); \ No newline at end of file
diff --git a/src/video_core/host1x/gpu_device_memory_manager.h b/src/video_core/host1x/gpu_device_memory_manager.h
new file mode 100644
index 000000000..a9f249991
--- /dev/null
+++ b/src/video_core/host1x/gpu_device_memory_manager.h
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/device_memory_manager.h"
7
8namespace VideoCore {
9class RasterizerInterface;
10}
11
12namespace Tegra {
13
14struct MaxwellDeviceMethods;
15
16struct MaxwellDeviceTraits {
17 static constexpr size_t device_virtual_bits = 34;
18 using DeviceInterface = typename VideoCore::RasterizerInterface;
19 using DeviceMethods = MaxwellDeviceMethods;
20};
21
22using MaxwellDeviceMemoryManager = Core::DeviceMemoryManager<MaxwellDeviceTraits>;
23
24} // namespace Tegra \ No newline at end of file
diff --git a/src/video_core/host1x/host1x.cpp b/src/video_core/host1x/host1x.cpp
index 7c317a85d..c4c7a5883 100644
--- a/src/video_core/host1x/host1x.cpp
+++ b/src/video_core/host1x/host1x.cpp
@@ -9,9 +9,12 @@ namespace Tegra {
9namespace Host1x { 9namespace Host1x {
10 10
11Host1x::Host1x(Core::System& system_) 11Host1x::Host1x(Core::System& system_)
12 : system{system_}, syncpoint_manager{}, memory_manager{system, 32, 12}, 12 : system{system_}, syncpoint_manager{},
13 memory_manager(system.DeviceMemory()), gmmu_manager{system, memory_manager, 32, 12},
13 allocator{std::make_unique<Common::FlatAllocator<u32, 0, 32>>(1 << 12)} {} 14 allocator{std::make_unique<Common::FlatAllocator<u32, 0, 32>>(1 << 12)} {}
14 15
16Host1x::~Host1x() = default;
17
15} // namespace Host1x 18} // namespace Host1x
16 19
17} // namespace Tegra 20} // namespace Tegra
diff --git a/src/video_core/host1x/host1x.h b/src/video_core/host1x/host1x.h
index 57082ae54..d72d97b7b 100644
--- a/src/video_core/host1x/host1x.h
+++ b/src/video_core/host1x/host1x.h
@@ -6,6 +6,7 @@
6#include "common/common_types.h" 6#include "common/common_types.h"
7 7
8#include "common/address_space.h" 8#include "common/address_space.h"
9#include "video_core/host1x/gpu_device_memory_manager.h"
9#include "video_core/host1x/syncpoint_manager.h" 10#include "video_core/host1x/syncpoint_manager.h"
10#include "video_core/memory_manager.h" 11#include "video_core/memory_manager.h"
11 12
@@ -20,6 +21,7 @@ namespace Host1x {
20class Host1x { 21class Host1x {
21public: 22public:
22 explicit Host1x(Core::System& system); 23 explicit Host1x(Core::System& system);
24 ~Host1x();
23 25
24 SyncpointManager& GetSyncpointManager() { 26 SyncpointManager& GetSyncpointManager() {
25 return syncpoint_manager; 27 return syncpoint_manager;
@@ -29,14 +31,22 @@ public:
29 return syncpoint_manager; 31 return syncpoint_manager;
30 } 32 }
31 33
32 Tegra::MemoryManager& MemoryManager() { 34 Tegra::MaxwellDeviceMemoryManager& MemoryManager() {
33 return memory_manager; 35 return memory_manager;
34 } 36 }
35 37
36 const Tegra::MemoryManager& MemoryManager() const { 38 const Tegra::MaxwellDeviceMemoryManager& MemoryManager() const {
37 return memory_manager; 39 return memory_manager;
38 } 40 }
39 41
42 Tegra::MemoryManager& GMMU() {
43 return gmmu_manager;
44 }
45
46 const Tegra::MemoryManager& GMMU() const {
47 return gmmu_manager;
48 }
49
40 Common::FlatAllocator<u32, 0, 32>& Allocator() { 50 Common::FlatAllocator<u32, 0, 32>& Allocator() {
41 return *allocator; 51 return *allocator;
42 } 52 }
@@ -48,7 +58,8 @@ public:
48private: 58private:
49 Core::System& system; 59 Core::System& system;
50 SyncpointManager syncpoint_manager; 60 SyncpointManager syncpoint_manager;
51 Tegra::MemoryManager memory_manager; 61 Tegra::MaxwellDeviceMemoryManager memory_manager;
62 Tegra::MemoryManager gmmu_manager;
52 std::unique_ptr<Common::FlatAllocator<u32, 0, 32>> allocator; 63 std::unique_ptr<Common::FlatAllocator<u32, 0, 32>> allocator;
53}; 64};
54 65
diff --git a/src/video_core/host1x/vic.cpp b/src/video_core/host1x/vic.cpp
index 2a5eba415..d154746af 100644
--- a/src/video_core/host1x/vic.cpp
+++ b/src/video_core/host1x/vic.cpp
@@ -81,7 +81,7 @@ void Vic::Execute() {
81 LOG_ERROR(Service_NVDRV, "VIC Luma address not set."); 81 LOG_ERROR(Service_NVDRV, "VIC Luma address not set.");
82 return; 82 return;
83 } 83 }
84 const VicConfig config{host1x.MemoryManager().Read<u64>(config_struct_address + 0x20)}; 84 const VicConfig config{host1x.GMMU().Read<u64>(config_struct_address + 0x20)};
85 auto frame = nvdec_processor->GetFrame(); 85 auto frame = nvdec_processor->GetFrame();
86 if (!frame) { 86 if (!frame) {
87 return; 87 return;
@@ -162,12 +162,12 @@ void Vic::WriteRGBFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& c
162 Texture::SwizzleSubrect(luma_buffer, frame_buff, 4, width, height, 1, 0, 0, width, height, 162 Texture::SwizzleSubrect(luma_buffer, frame_buff, 4, width, height, 1, 0, 0, width, height,
163 block_height, 0, width * 4); 163 block_height, 0, width * 4);
164 164
165 host1x.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), size); 165 host1x.GMMU().WriteBlock(output_surface_luma_address, luma_buffer.data(), size);
166 } else { 166 } else {
167 // send pitch linear frame 167 // send pitch linear frame
168 const size_t linear_size = width * height * 4; 168 const size_t linear_size = width * height * 4;
169 host1x.MemoryManager().WriteBlock(output_surface_luma_address, converted_frame_buf_addr, 169 host1x.GMMU().WriteBlock(output_surface_luma_address, converted_frame_buf_addr,
170 linear_size); 170 linear_size);
171 } 171 }
172} 172}
173 173
@@ -193,8 +193,7 @@ void Vic::WriteYUVFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& c
193 const std::size_t dst = y * aligned_width; 193 const std::size_t dst = y * aligned_width;
194 std::memcpy(luma_buffer.data() + dst, luma_src + src, frame_width); 194 std::memcpy(luma_buffer.data() + dst, luma_src + src, frame_width);
195 } 195 }
196 host1x.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), 196 host1x.GMMU().WriteBlock(output_surface_luma_address, luma_buffer.data(), luma_buffer.size());
197 luma_buffer.size());
198 197
199 // Chroma 198 // Chroma
200 const std::size_t half_height = frame_height / 2; 199 const std::size_t half_height = frame_height / 2;
@@ -233,8 +232,8 @@ void Vic::WriteYUVFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& c
233 ASSERT(false); 232 ASSERT(false);
234 break; 233 break;
235 } 234 }
236 host1x.MemoryManager().WriteBlock(output_surface_chroma_address, chroma_buffer.data(), 235 host1x.GMMU().WriteBlock(output_surface_chroma_address, chroma_buffer.data(),
237 chroma_buffer.size()); 236 chroma_buffer.size());
238} 237}
239 238
240} // namespace Host1x 239} // namespace Host1x
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index d16040613..a52f8e486 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -7,25 +7,26 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/device_memory.h"
11#include "core/hle/kernel/k_page_table.h" 10#include "core/hle/kernel/k_page_table.h"
12#include "core/hle/kernel/k_process.h" 11#include "core/hle/kernel/k_process.h"
12#include "video_core/guest_memory.h"
13#include "video_core/host1x/host1x.h"
13#include "video_core/invalidation_accumulator.h" 14#include "video_core/invalidation_accumulator.h"
14#include "video_core/memory_manager.h" 15#include "video_core/memory_manager.h"
15#include "video_core/rasterizer_interface.h" 16#include "video_core/rasterizer_interface.h"
16#include "video_core/renderer_base.h" 17#include "video_core/renderer_base.h"
17 18
18namespace Tegra { 19namespace Tegra {
19using Core::Memory::GuestMemoryFlags; 20using Tegra::Memory::GuestMemoryFlags;
20 21
21std::atomic<size_t> MemoryManager::unique_identifier_generator{}; 22std::atomic<size_t> MemoryManager::unique_identifier_generator{};
22 23
23MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 big_page_bits_, 24MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
24 u64 page_bits_) 25 u64 address_space_bits_, u64 big_page_bits_, u64 page_bits_)
25 : system{system_}, memory{system.ApplicationMemory()}, device_memory{system.DeviceMemory()}, 26 : system{system_}, memory{memory_}, address_space_bits{address_space_bits_},
26 address_space_bits{address_space_bits_}, page_bits{page_bits_}, big_page_bits{big_page_bits_}, 27 page_bits{page_bits_}, big_page_bits{big_page_bits_}, entries{}, big_entries{},
27 entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38, 28 page_table{address_space_bits, address_space_bits + page_bits - 38,
28 page_bits != big_page_bits ? page_bits : 0}, 29 page_bits != big_page_bits ? page_bits : 0},
29 kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add( 30 kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add(
30 1, std::memory_order_acq_rel)}, 31 1, std::memory_order_acq_rel)},
31 accumulator{std::make_unique<VideoCommon::InvalidationAccumulator>()} { 32 accumulator{std::make_unique<VideoCommon::InvalidationAccumulator>()} {
@@ -42,11 +43,16 @@ MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64
42 big_page_table_mask = big_page_table_size - 1; 43 big_page_table_mask = big_page_table_size - 1;
43 44
44 big_entries.resize(big_page_table_size / 32, 0); 45 big_entries.resize(big_page_table_size / 32, 0);
45 big_page_table_cpu.resize(big_page_table_size); 46 big_page_table_dev.resize(big_page_table_size);
46 big_page_continuous.resize(big_page_table_size / continuous_bits, 0); 47 big_page_continuous.resize(big_page_table_size / continuous_bits, 0);
47 entries.resize(page_table_size / 32, 0); 48 entries.resize(page_table_size / 32, 0);
48} 49}
49 50
51MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 big_page_bits_,
52 u64 page_bits_)
53 : MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, big_page_bits_,
54 page_bits_) {}
55
50MemoryManager::~MemoryManager() = default; 56MemoryManager::~MemoryManager() = default;
51 57
52template <bool is_big_page> 58template <bool is_big_page>
@@ -100,7 +106,7 @@ inline void MemoryManager::SetBigPageContinuous(size_t big_page_index, bool valu
100} 106}
101 107
102template <MemoryManager::EntryType entry_type> 108template <MemoryManager::EntryType entry_type>
103GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size, 109GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size,
104 PTEKind kind) { 110 PTEKind kind) {
105 [[maybe_unused]] u64 remaining_size{size}; 111 [[maybe_unused]] u64 remaining_size{size};
106 if constexpr (entry_type == EntryType::Mapped) { 112 if constexpr (entry_type == EntryType::Mapped) {
@@ -114,9 +120,9 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp
114 rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, page_size); 120 rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, page_size);
115 } 121 }
116 if constexpr (entry_type == EntryType::Mapped) { 122 if constexpr (entry_type == EntryType::Mapped) {
117 const VAddr current_cpu_addr = cpu_addr + offset; 123 const DAddr current_dev_addr = dev_addr + offset;
118 const auto index = PageEntryIndex<false>(current_gpu_addr); 124 const auto index = PageEntryIndex<false>(current_gpu_addr);
119 const u32 sub_value = static_cast<u32>(current_cpu_addr >> cpu_page_bits); 125 const u32 sub_value = static_cast<u32>(current_dev_addr >> cpu_page_bits);
120 page_table[index] = sub_value; 126 page_table[index] = sub_value;
121 } 127 }
122 remaining_size -= page_size; 128 remaining_size -= page_size;
@@ -126,7 +132,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp
126} 132}
127 133
128template <MemoryManager::EntryType entry_type> 134template <MemoryManager::EntryType entry_type>
129GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, 135GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr,
130 size_t size, PTEKind kind) { 136 size_t size, PTEKind kind) {
131 [[maybe_unused]] u64 remaining_size{size}; 137 [[maybe_unused]] u64 remaining_size{size};
132 for (u64 offset{}; offset < size; offset += big_page_size) { 138 for (u64 offset{}; offset < size; offset += big_page_size) {
@@ -137,20 +143,20 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr
137 rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, big_page_size); 143 rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, big_page_size);
138 } 144 }
139 if constexpr (entry_type == EntryType::Mapped) { 145 if constexpr (entry_type == EntryType::Mapped) {
140 const VAddr current_cpu_addr = cpu_addr + offset; 146 const DAddr current_dev_addr = dev_addr + offset;
141 const auto index = PageEntryIndex<true>(current_gpu_addr); 147 const auto index = PageEntryIndex<true>(current_gpu_addr);
142 const u32 sub_value = static_cast<u32>(current_cpu_addr >> cpu_page_bits); 148 const u32 sub_value = static_cast<u32>(current_dev_addr >> cpu_page_bits);
143 big_page_table_cpu[index] = sub_value; 149 big_page_table_dev[index] = sub_value;
144 const bool is_continuous = ([&] { 150 const bool is_continuous = ([&] {
145 uintptr_t base_ptr{ 151 uintptr_t base_ptr{
146 reinterpret_cast<uintptr_t>(memory.GetPointerSilent(current_cpu_addr))}; 152 reinterpret_cast<uintptr_t>(memory.GetPointer<u8>(current_dev_addr))};
147 if (base_ptr == 0) { 153 if (base_ptr == 0) {
148 return false; 154 return false;
149 } 155 }
150 for (VAddr start_cpu = current_cpu_addr + page_size; 156 for (DAddr start_cpu = current_dev_addr + page_size;
151 start_cpu < current_cpu_addr + big_page_size; start_cpu += page_size) { 157 start_cpu < current_dev_addr + big_page_size; start_cpu += page_size) {
152 base_ptr += page_size; 158 base_ptr += page_size;
153 auto next_ptr = reinterpret_cast<uintptr_t>(memory.GetPointerSilent(start_cpu)); 159 auto next_ptr = reinterpret_cast<uintptr_t>(memory.GetPointer<u8>(start_cpu));
154 if (next_ptr == 0 || base_ptr != next_ptr) { 160 if (next_ptr == 0 || base_ptr != next_ptr) {
155 return false; 161 return false;
156 } 162 }
@@ -172,12 +178,12 @@ void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_)
172 rasterizer = rasterizer_; 178 rasterizer = rasterizer_;
173} 179}
174 180
175GPUVAddr MemoryManager::Map(GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size, PTEKind kind, 181GPUVAddr MemoryManager::Map(GPUVAddr gpu_addr, DAddr dev_addr, std::size_t size, PTEKind kind,
176 bool is_big_pages) { 182 bool is_big_pages) {
177 if (is_big_pages) [[likely]] { 183 if (is_big_pages) [[likely]] {
178 return BigPageTableOp<EntryType::Mapped>(gpu_addr, cpu_addr, size, kind); 184 return BigPageTableOp<EntryType::Mapped>(gpu_addr, dev_addr, size, kind);
179 } 185 }
180 return PageTableOp<EntryType::Mapped>(gpu_addr, cpu_addr, size, kind); 186 return PageTableOp<EntryType::Mapped>(gpu_addr, dev_addr, size, kind);
181} 187}
182 188
183GPUVAddr MemoryManager::MapSparse(GPUVAddr gpu_addr, std::size_t size, bool is_big_pages) { 189GPUVAddr MemoryManager::MapSparse(GPUVAddr gpu_addr, std::size_t size, bool is_big_pages) {
@@ -202,7 +208,7 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
202 PageTableOp<EntryType::Free>(gpu_addr, 0, size, PTEKind::INVALID); 208 PageTableOp<EntryType::Free>(gpu_addr, 0, size, PTEKind::INVALID);
203} 209}
204 210
205std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const { 211std::optional<DAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const {
206 if (!IsWithinGPUAddressRange(gpu_addr)) [[unlikely]] { 212 if (!IsWithinGPUAddressRange(gpu_addr)) [[unlikely]] {
207 return std::nullopt; 213 return std::nullopt;
208 } 214 }
@@ -211,17 +217,17 @@ std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const {
211 return std::nullopt; 217 return std::nullopt;
212 } 218 }
213 219
214 const VAddr cpu_addr_base = static_cast<VAddr>(page_table[PageEntryIndex<false>(gpu_addr)]) 220 const DAddr dev_addr_base = static_cast<DAddr>(page_table[PageEntryIndex<false>(gpu_addr)])
215 << cpu_page_bits; 221 << cpu_page_bits;
216 return cpu_addr_base + (gpu_addr & page_mask); 222 return dev_addr_base + (gpu_addr & page_mask);
217 } 223 }
218 224
219 const VAddr cpu_addr_base = 225 const DAddr dev_addr_base =
220 static_cast<VAddr>(big_page_table_cpu[PageEntryIndex<true>(gpu_addr)]) << cpu_page_bits; 226 static_cast<DAddr>(big_page_table_dev[PageEntryIndex<true>(gpu_addr)]) << cpu_page_bits;
221 return cpu_addr_base + (gpu_addr & big_page_mask); 227 return dev_addr_base + (gpu_addr & big_page_mask);
222} 228}
223 229
224std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr, std::size_t size) const { 230std::optional<DAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr, std::size_t size) const {
225 size_t page_index{addr >> page_bits}; 231 size_t page_index{addr >> page_bits};
226 const size_t page_last{(addr + size + page_size - 1) >> page_bits}; 232 const size_t page_last{(addr + size + page_size - 1) >> page_bits};
227 while (page_index < page_last) { 233 while (page_index < page_last) {
@@ -274,7 +280,7 @@ u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) {
274 return {}; 280 return {};
275 } 281 }
276 282
277 return memory.GetPointer(*address); 283 return memory.GetPointer<u8>(*address);
278} 284}
279 285
280const u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) const { 286const u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) const {
@@ -283,7 +289,7 @@ const u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) const {
283 return {}; 289 return {};
284 } 290 }
285 291
286 return memory.GetPointer(*address); 292 return memory.GetPointer<u8>(*address);
287} 293}
288 294
289#ifdef _MSC_VER // no need for gcc / clang but msvc's compiler is more conservative with inlining. 295#ifdef _MSC_VER // no need for gcc / clang but msvc's compiler is more conservative with inlining.
@@ -367,25 +373,25 @@ void MemoryManager::ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std:
367 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; 373 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
368 }; 374 };
369 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 375 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
370 const VAddr cpu_addr_base = 376 const DAddr dev_addr_base =
371 (static_cast<VAddr>(page_table[page_index]) << cpu_page_bits) + offset; 377 (static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
372 if constexpr (is_safe) { 378 if constexpr (is_safe) {
373 rasterizer->FlushRegion(cpu_addr_base, copy_amount, which); 379 rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
374 } 380 }
375 u8* physical = memory.GetPointer(cpu_addr_base); 381 u8* physical = memory.GetPointer<u8>(dev_addr_base);
376 std::memcpy(dest_buffer, physical, copy_amount); 382 std::memcpy(dest_buffer, physical, copy_amount);
377 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; 383 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
378 }; 384 };
379 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 385 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
380 const VAddr cpu_addr_base = 386 const DAddr dev_addr_base =
381 (static_cast<VAddr>(big_page_table_cpu[page_index]) << cpu_page_bits) + offset; 387 (static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
382 if constexpr (is_safe) { 388 if constexpr (is_safe) {
383 rasterizer->FlushRegion(cpu_addr_base, copy_amount, which); 389 rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
384 } 390 }
385 if (!IsBigPageContinuous(page_index)) [[unlikely]] { 391 if (!IsBigPageContinuous(page_index)) [[unlikely]] {
386 memory.ReadBlockUnsafe(cpu_addr_base, dest_buffer, copy_amount); 392 memory.ReadBlockUnsafe(dev_addr_base, dest_buffer, copy_amount);
387 } else { 393 } else {
388 u8* physical = memory.GetPointer(cpu_addr_base); 394 u8* physical = memory.GetPointer<u8>(dev_addr_base);
389 std::memcpy(dest_buffer, physical, copy_amount); 395 std::memcpy(dest_buffer, physical, copy_amount);
390 } 396 }
391 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; 397 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
@@ -416,25 +422,25 @@ void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffe
416 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; 422 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
417 }; 423 };
418 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 424 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
419 const VAddr cpu_addr_base = 425 const DAddr dev_addr_base =
420 (static_cast<VAddr>(page_table[page_index]) << cpu_page_bits) + offset; 426 (static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
421 if constexpr (is_safe) { 427 if constexpr (is_safe) {
422 rasterizer->InvalidateRegion(cpu_addr_base, copy_amount, which); 428 rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
423 } 429 }
424 u8* physical = memory.GetPointer(cpu_addr_base); 430 u8* physical = memory.GetPointer<u8>(dev_addr_base);
425 std::memcpy(physical, src_buffer, copy_amount); 431 std::memcpy(physical, src_buffer, copy_amount);
426 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; 432 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
427 }; 433 };
428 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 434 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
429 const VAddr cpu_addr_base = 435 const DAddr dev_addr_base =
430 (static_cast<VAddr>(big_page_table_cpu[page_index]) << cpu_page_bits) + offset; 436 (static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
431 if constexpr (is_safe) { 437 if constexpr (is_safe) {
432 rasterizer->InvalidateRegion(cpu_addr_base, copy_amount, which); 438 rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
433 } 439 }
434 if (!IsBigPageContinuous(page_index)) [[unlikely]] { 440 if (!IsBigPageContinuous(page_index)) [[unlikely]] {
435 memory.WriteBlockUnsafe(cpu_addr_base, src_buffer, copy_amount); 441 memory.WriteBlockUnsafe(dev_addr_base, src_buffer, copy_amount);
436 } else { 442 } else {
437 u8* physical = memory.GetPointer(cpu_addr_base); 443 u8* physical = memory.GetPointer<u8>(dev_addr_base);
438 std::memcpy(physical, src_buffer, copy_amount); 444 std::memcpy(physical, src_buffer, copy_amount);
439 } 445 }
440 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; 446 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
@@ -470,14 +476,14 @@ void MemoryManager::FlushRegion(GPUVAddr gpu_addr, size_t size,
470 [[maybe_unused]] std::size_t copy_amount) {}; 476 [[maybe_unused]] std::size_t copy_amount) {};
471 477
472 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 478 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
473 const VAddr cpu_addr_base = 479 const DAddr dev_addr_base =
474 (static_cast<VAddr>(page_table[page_index]) << cpu_page_bits) + offset; 480 (static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
475 rasterizer->FlushRegion(cpu_addr_base, copy_amount, which); 481 rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
476 }; 482 };
477 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 483 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
478 const VAddr cpu_addr_base = 484 const DAddr dev_addr_base =
479 (static_cast<VAddr>(big_page_table_cpu[page_index]) << cpu_page_bits) + offset; 485 (static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
480 rasterizer->FlushRegion(cpu_addr_base, copy_amount, which); 486 rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
481 }; 487 };
482 auto flush_short_pages = [&](std::size_t page_index, std::size_t offset, 488 auto flush_short_pages = [&](std::size_t page_index, std::size_t offset,
483 std::size_t copy_amount) { 489 std::size_t copy_amount) {
@@ -495,15 +501,15 @@ bool MemoryManager::IsMemoryDirty(GPUVAddr gpu_addr, size_t size,
495 [[maybe_unused]] std::size_t copy_amount) { return false; }; 501 [[maybe_unused]] std::size_t copy_amount) { return false; };
496 502
497 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 503 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
498 const VAddr cpu_addr_base = 504 const DAddr dev_addr_base =
499 (static_cast<VAddr>(page_table[page_index]) << cpu_page_bits) + offset; 505 (static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
500 result |= rasterizer->MustFlushRegion(cpu_addr_base, copy_amount, which); 506 result |= rasterizer->MustFlushRegion(dev_addr_base, copy_amount, which);
501 return result; 507 return result;
502 }; 508 };
503 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 509 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
504 const VAddr cpu_addr_base = 510 const DAddr dev_addr_base =
505 (static_cast<VAddr>(big_page_table_cpu[page_index]) << cpu_page_bits) + offset; 511 (static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
506 result |= rasterizer->MustFlushRegion(cpu_addr_base, copy_amount, which); 512 result |= rasterizer->MustFlushRegion(dev_addr_base, copy_amount, which);
507 return result; 513 return result;
508 }; 514 };
509 auto check_short_pages = [&](std::size_t page_index, std::size_t offset, 515 auto check_short_pages = [&](std::size_t page_index, std::size_t offset,
@@ -517,7 +523,7 @@ bool MemoryManager::IsMemoryDirty(GPUVAddr gpu_addr, size_t size,
517} 523}
518 524
519size_t MemoryManager::MaxContinuousRange(GPUVAddr gpu_addr, size_t size) const { 525size_t MemoryManager::MaxContinuousRange(GPUVAddr gpu_addr, size_t size) const {
520 std::optional<VAddr> old_page_addr{}; 526 std::optional<DAddr> old_page_addr{};
521 size_t range_so_far = 0; 527 size_t range_so_far = 0;
522 bool result{false}; 528 bool result{false};
523 auto fail = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset, 529 auto fail = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset,
@@ -526,24 +532,24 @@ size_t MemoryManager::MaxContinuousRange(GPUVAddr gpu_addr, size_t size) const {
526 return true; 532 return true;
527 }; 533 };
528 auto short_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 534 auto short_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
529 const VAddr cpu_addr_base = 535 const DAddr dev_addr_base =
530 (static_cast<VAddr>(page_table[page_index]) << cpu_page_bits) + offset; 536 (static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
531 if (old_page_addr && *old_page_addr != cpu_addr_base) { 537 if (old_page_addr && *old_page_addr != dev_addr_base) {
532 result = true; 538 result = true;
533 return true; 539 return true;
534 } 540 }
535 range_so_far += copy_amount; 541 range_so_far += copy_amount;
536 old_page_addr = {cpu_addr_base + copy_amount}; 542 old_page_addr = {dev_addr_base + copy_amount};
537 return false; 543 return false;
538 }; 544 };
539 auto big_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 545 auto big_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
540 const VAddr cpu_addr_base = 546 const DAddr dev_addr_base =
541 (static_cast<VAddr>(big_page_table_cpu[page_index]) << cpu_page_bits) + offset; 547 (static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
542 if (old_page_addr && *old_page_addr != cpu_addr_base) { 548 if (old_page_addr && *old_page_addr != dev_addr_base) {
543 return true; 549 return true;
544 } 550 }
545 range_so_far += copy_amount; 551 range_so_far += copy_amount;
546 old_page_addr = {cpu_addr_base + copy_amount}; 552 old_page_addr = {dev_addr_base + copy_amount};
547 return false; 553 return false;
548 }; 554 };
549 auto check_short_pages = [&](std::size_t page_index, std::size_t offset, 555 auto check_short_pages = [&](std::size_t page_index, std::size_t offset,
@@ -568,14 +574,14 @@ void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size,
568 [[maybe_unused]] std::size_t copy_amount) {}; 574 [[maybe_unused]] std::size_t copy_amount) {};
569 575
570 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 576 auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
571 const VAddr cpu_addr_base = 577 const DAddr dev_addr_base =
572 (static_cast<VAddr>(page_table[page_index]) << cpu_page_bits) + offset; 578 (static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
573 rasterizer->InvalidateRegion(cpu_addr_base, copy_amount, which); 579 rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
574 }; 580 };
575 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 581 auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
576 const VAddr cpu_addr_base = 582 const DAddr dev_addr_base =
577 (static_cast<VAddr>(big_page_table_cpu[page_index]) << cpu_page_bits) + offset; 583 (static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
578 rasterizer->InvalidateRegion(cpu_addr_base, copy_amount, which); 584 rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
579 }; 585 };
580 auto invalidate_short_pages = [&](std::size_t page_index, std::size_t offset, 586 auto invalidate_short_pages = [&](std::size_t page_index, std::size_t offset,
581 std::size_t copy_amount) { 587 std::size_t copy_amount) {
@@ -587,7 +593,7 @@ void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size,
587 593
588void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, 594void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size,
589 VideoCommon::CacheType which) { 595 VideoCommon::CacheType which) {
590 Core::Memory::GpuGuestMemoryScoped<u8, GuestMemoryFlags::SafeReadWrite> data( 596 Tegra::Memory::GpuGuestMemoryScoped<u8, GuestMemoryFlags::SafeReadWrite> data(
591 *this, gpu_src_addr, size); 597 *this, gpu_src_addr, size);
592 data.SetAddressAndSize(gpu_dest_addr, size); 598 data.SetAddressAndSize(gpu_dest_addr, size);
593 FlushRegion(gpu_dest_addr, size, which); 599 FlushRegion(gpu_dest_addr, size, which);
@@ -600,18 +606,18 @@ bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const {
600 const std::size_t page{(page_index & big_page_mask) + size}; 606 const std::size_t page{(page_index & big_page_mask) + size};
601 return page <= big_page_size; 607 return page <= big_page_size;
602 } 608 }
603 const std::size_t page{(gpu_addr & Core::Memory::YUZU_PAGEMASK) + size}; 609 const std::size_t page{(gpu_addr & Core::DEVICE_PAGEMASK) + size};
604 return page <= Core::Memory::YUZU_PAGESIZE; 610 return page <= Core::DEVICE_PAGESIZE;
605 } 611 }
606 if (GetEntry<false>(gpu_addr) != EntryType::Mapped) { 612 if (GetEntry<false>(gpu_addr) != EntryType::Mapped) {
607 return false; 613 return false;
608 } 614 }
609 const std::size_t page{(gpu_addr & Core::Memory::YUZU_PAGEMASK) + size}; 615 const std::size_t page{(gpu_addr & Core::DEVICE_PAGEMASK) + size};
610 return page <= Core::Memory::YUZU_PAGESIZE; 616 return page <= Core::DEVICE_PAGESIZE;
611} 617}
612 618
613bool MemoryManager::IsContinuousRange(GPUVAddr gpu_addr, std::size_t size) const { 619bool MemoryManager::IsContinuousRange(GPUVAddr gpu_addr, std::size_t size) const {
614 std::optional<VAddr> old_page_addr{}; 620 std::optional<DAddr> old_page_addr{};
615 bool result{true}; 621 bool result{true};
616 auto fail = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset, 622 auto fail = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset,
617 std::size_t copy_amount) { 623 std::size_t copy_amount) {
@@ -619,23 +625,23 @@ bool MemoryManager::IsContinuousRange(GPUVAddr gpu_addr, std::size_t size) const
619 return true; 625 return true;
620 }; 626 };
621 auto short_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 627 auto short_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
622 const VAddr cpu_addr_base = 628 const DAddr dev_addr_base =
623 (static_cast<VAddr>(page_table[page_index]) << cpu_page_bits) + offset; 629 (static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
624 if (old_page_addr && *old_page_addr != cpu_addr_base) { 630 if (old_page_addr && *old_page_addr != dev_addr_base) {
625 result = false; 631 result = false;
626 return true; 632 return true;
627 } 633 }
628 old_page_addr = {cpu_addr_base + copy_amount}; 634 old_page_addr = {dev_addr_base + copy_amount};
629 return false; 635 return false;
630 }; 636 };
631 auto big_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { 637 auto big_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
632 const VAddr cpu_addr_base = 638 const DAddr dev_addr_base =
633 (static_cast<VAddr>(big_page_table_cpu[page_index]) << cpu_page_bits) + offset; 639 (static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
634 if (old_page_addr && *old_page_addr != cpu_addr_base) { 640 if (old_page_addr && *old_page_addr != dev_addr_base) {
635 result = false; 641 result = false;
636 return true; 642 return true;
637 } 643 }
638 old_page_addr = {cpu_addr_base + copy_amount}; 644 old_page_addr = {dev_addr_base + copy_amount};
639 return false; 645 return false;
640 }; 646 };
641 auto check_short_pages = [&](std::size_t page_index, std::size_t offset, 647 auto check_short_pages = [&](std::size_t page_index, std::size_t offset,
@@ -678,11 +684,11 @@ template <bool is_gpu_address>
678void MemoryManager::GetSubmappedRangeImpl( 684void MemoryManager::GetSubmappedRangeImpl(
679 GPUVAddr gpu_addr, std::size_t size, 685 GPUVAddr gpu_addr, std::size_t size,
680 boost::container::small_vector< 686 boost::container::small_vector<
681 std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>, 32>& result) 687 std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>, 32>& result)
682 const { 688 const {
683 std::optional<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>> 689 std::optional<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>>
684 last_segment{}; 690 last_segment{};
685 std::optional<VAddr> old_page_addr{}; 691 std::optional<DAddr> old_page_addr{};
686 const auto split = [&last_segment, &result]([[maybe_unused]] std::size_t page_index, 692 const auto split = [&last_segment, &result]([[maybe_unused]] std::size_t page_index,
687 [[maybe_unused]] std::size_t offset, 693 [[maybe_unused]] std::size_t offset,
688 [[maybe_unused]] std::size_t copy_amount) { 694 [[maybe_unused]] std::size_t copy_amount) {
@@ -694,20 +700,20 @@ void MemoryManager::GetSubmappedRangeImpl(
694 const auto extend_size_big = [this, &split, &old_page_addr, 700 const auto extend_size_big = [this, &split, &old_page_addr,
695 &last_segment](std::size_t page_index, std::size_t offset, 701 &last_segment](std::size_t page_index, std::size_t offset,
696 std::size_t copy_amount) { 702 std::size_t copy_amount) {
697 const VAddr cpu_addr_base = 703 const DAddr dev_addr_base =
698 (static_cast<VAddr>(big_page_table_cpu[page_index]) << cpu_page_bits) + offset; 704 (static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
699 if (old_page_addr) { 705 if (old_page_addr) {
700 if (*old_page_addr != cpu_addr_base) { 706 if (*old_page_addr != dev_addr_base) {
701 split(0, 0, 0); 707 split(0, 0, 0);
702 } 708 }
703 } 709 }
704 old_page_addr = {cpu_addr_base + copy_amount}; 710 old_page_addr = {dev_addr_base + copy_amount};
705 if (!last_segment) { 711 if (!last_segment) {
706 if constexpr (is_gpu_address) { 712 if constexpr (is_gpu_address) {
707 const GPUVAddr new_base_addr = (page_index << big_page_bits) + offset; 713 const GPUVAddr new_base_addr = (page_index << big_page_bits) + offset;
708 last_segment = {new_base_addr, copy_amount}; 714 last_segment = {new_base_addr, copy_amount};
709 } else { 715 } else {
710 last_segment = {cpu_addr_base, copy_amount}; 716 last_segment = {dev_addr_base, copy_amount};
711 } 717 }
712 } else { 718 } else {
713 last_segment->second += copy_amount; 719 last_segment->second += copy_amount;
@@ -716,20 +722,20 @@ void MemoryManager::GetSubmappedRangeImpl(
716 const auto extend_size_short = [this, &split, &old_page_addr, 722 const auto extend_size_short = [this, &split, &old_page_addr,
717 &last_segment](std::size_t page_index, std::size_t offset, 723 &last_segment](std::size_t page_index, std::size_t offset,
718 std::size_t copy_amount) { 724 std::size_t copy_amount) {
719 const VAddr cpu_addr_base = 725 const DAddr dev_addr_base =
720 (static_cast<VAddr>(page_table[page_index]) << cpu_page_bits) + offset; 726 (static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
721 if (old_page_addr) { 727 if (old_page_addr) {
722 if (*old_page_addr != cpu_addr_base) { 728 if (*old_page_addr != dev_addr_base) {
723 split(0, 0, 0); 729 split(0, 0, 0);
724 } 730 }
725 } 731 }
726 old_page_addr = {cpu_addr_base + copy_amount}; 732 old_page_addr = {dev_addr_base + copy_amount};
727 if (!last_segment) { 733 if (!last_segment) {
728 if constexpr (is_gpu_address) { 734 if constexpr (is_gpu_address) {
729 const GPUVAddr new_base_addr = (page_index << page_bits) + offset; 735 const GPUVAddr new_base_addr = (page_index << page_bits) + offset;
730 last_segment = {new_base_addr, copy_amount}; 736 last_segment = {new_base_addr, copy_amount};
731 } else { 737 } else {
732 last_segment = {cpu_addr_base, copy_amount}; 738 last_segment = {dev_addr_base, copy_amount};
733 } 739 }
734 } else { 740 } else {
735 last_segment->second += copy_amount; 741 last_segment->second += copy_amount;
@@ -756,9 +762,12 @@ void MemoryManager::FlushCaching() {
756} 762}
757 763
758const u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) const { 764const u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) const {
759 auto cpu_addr = GpuToCpuAddress(src_addr); 765 if (!IsContinuousRange(src_addr, size)) {
760 if (cpu_addr) { 766 return nullptr;
761 return memory.GetSpan(*cpu_addr, size); 767 }
768 auto dev_addr = GpuToCpuAddress(src_addr);
769 if (dev_addr) {
770 return memory.GetSpan(*dev_addr, size);
762 } 771 }
763 return nullptr; 772 return nullptr;
764} 773}
@@ -767,9 +776,9 @@ u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) {
767 if (!IsContinuousRange(src_addr, size)) { 776 if (!IsContinuousRange(src_addr, size)) {
768 return nullptr; 777 return nullptr;
769 } 778 }
770 auto cpu_addr = GpuToCpuAddress(src_addr); 779 auto dev_addr = GpuToCpuAddress(src_addr);
771 if (cpu_addr) { 780 if (dev_addr) {
772 return memory.GetSpan(*cpu_addr, size); 781 return memory.GetSpan(*dev_addr, size);
773 } 782 }
774 return nullptr; 783 return nullptr;
775} 784}
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 9b311b9e5..c5255f36c 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -15,8 +15,8 @@
15#include "common/range_map.h" 15#include "common/range_map.h"
16#include "common/scratch_buffer.h" 16#include "common/scratch_buffer.h"
17#include "common/virtual_buffer.h" 17#include "common/virtual_buffer.h"
18#include "core/memory.h"
19#include "video_core/cache_types.h" 18#include "video_core/cache_types.h"
19#include "video_core/host1x/gpu_device_memory_manager.h"
20#include "video_core/pte_kind.h" 20#include "video_core/pte_kind.h"
21 21
22namespace VideoCore { 22namespace VideoCore {
@@ -28,10 +28,6 @@ class InvalidationAccumulator;
28} 28}
29 29
30namespace Core { 30namespace Core {
31class DeviceMemory;
32namespace Memory {
33class Memory;
34} // namespace Memory
35class System; 31class System;
36} // namespace Core 32} // namespace Core
37 33
@@ -41,6 +37,9 @@ class MemoryManager final {
41public: 37public:
42 explicit MemoryManager(Core::System& system_, u64 address_space_bits_ = 40, 38 explicit MemoryManager(Core::System& system_, u64 address_space_bits_ = 40,
43 u64 big_page_bits_ = 16, u64 page_bits_ = 12); 39 u64 big_page_bits_ = 16, u64 page_bits_ = 12);
40 explicit MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
41 u64 address_space_bits_ = 40, u64 big_page_bits_ = 16,
42 u64 page_bits_ = 12);
44 ~MemoryManager(); 43 ~MemoryManager();
45 44
46 size_t GetID() const { 45 size_t GetID() const {
@@ -50,9 +49,9 @@ public:
50 /// Binds a renderer to the memory manager. 49 /// Binds a renderer to the memory manager.
51 void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); 50 void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
52 51
53 [[nodiscard]] std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const; 52 [[nodiscard]] std::optional<DAddr> GpuToCpuAddress(GPUVAddr addr) const;
54 53
55 [[nodiscard]] std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr, std::size_t size) const; 54 [[nodiscard]] std::optional<DAddr> GpuToCpuAddress(GPUVAddr addr, std::size_t size) const;
56 55
57 template <typename T> 56 template <typename T>
58 [[nodiscard]] T Read(GPUVAddr addr) const; 57 [[nodiscard]] T Read(GPUVAddr addr) const;
@@ -69,7 +68,7 @@ public:
69 if (!address) { 68 if (!address) {
70 return {}; 69 return {};
71 } 70 }
72 return memory.GetPointer(*address); 71 return memory.GetPointer<T>(*address);
73 } 72 }
74 73
75 template <typename T> 74 template <typename T>
@@ -110,7 +109,7 @@ public:
110 [[nodiscard]] bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const; 109 [[nodiscard]] bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const;
111 110
112 /** 111 /**
113 * Checks if a gpu region is mapped by a single range of cpu addresses. 112 * Checks if a gpu region is mapped by a single range of device addresses.
114 */ 113 */
115 [[nodiscard]] bool IsContinuousRange(GPUVAddr gpu_addr, std::size_t size) const; 114 [[nodiscard]] bool IsContinuousRange(GPUVAddr gpu_addr, std::size_t size) const;
116 115
@@ -120,14 +119,14 @@ public:
120 [[nodiscard]] bool IsFullyMappedRange(GPUVAddr gpu_addr, std::size_t size) const; 119 [[nodiscard]] bool IsFullyMappedRange(GPUVAddr gpu_addr, std::size_t size) const;
121 120
122 /** 121 /**
123 * Returns a vector with all the subranges of cpu addresses mapped beneath. 122 * Returns a vector with all the subranges of device addresses mapped beneath.
124 * if the region is continuous, a single pair will be returned. If it's unmapped, an empty 123 * if the region is continuous, a single pair will be returned. If it's unmapped, an empty
125 * vector will be returned; 124 * vector will be returned;
126 */ 125 */
127 boost::container::small_vector<std::pair<GPUVAddr, std::size_t>, 32> GetSubmappedRange( 126 boost::container::small_vector<std::pair<GPUVAddr, std::size_t>, 32> GetSubmappedRange(
128 GPUVAddr gpu_addr, std::size_t size) const; 127 GPUVAddr gpu_addr, std::size_t size) const;
129 128
130 GPUVAddr Map(GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size, 129 GPUVAddr Map(GPUVAddr gpu_addr, DAddr dev_addr, std::size_t size,
131 PTEKind kind = PTEKind::INVALID, bool is_big_pages = true); 130 PTEKind kind = PTEKind::INVALID, bool is_big_pages = true);
132 GPUVAddr MapSparse(GPUVAddr gpu_addr, std::size_t size, bool is_big_pages = true); 131 GPUVAddr MapSparse(GPUVAddr gpu_addr, std::size_t size, bool is_big_pages = true);
133 void Unmap(GPUVAddr gpu_addr, std::size_t size); 132 void Unmap(GPUVAddr gpu_addr, std::size_t size);
@@ -186,12 +185,11 @@ private:
186 void GetSubmappedRangeImpl( 185 void GetSubmappedRangeImpl(
187 GPUVAddr gpu_addr, std::size_t size, 186 GPUVAddr gpu_addr, std::size_t size,
188 boost::container::small_vector< 187 boost::container::small_vector<
189 std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>, 32>& 188 std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>, 32>&
190 result) const; 189 result) const;
191 190
192 Core::System& system; 191 Core::System& system;
193 Core::Memory::Memory& memory; 192 MaxwellDeviceMemoryManager& memory;
194 Core::DeviceMemory& device_memory;
195 193
196 const u64 address_space_bits; 194 const u64 address_space_bits;
197 const u64 page_bits; 195 const u64 page_bits;
@@ -218,11 +216,11 @@ private:
218 std::vector<u64> big_entries; 216 std::vector<u64> big_entries;
219 217
220 template <EntryType entry_type> 218 template <EntryType entry_type>
221 GPUVAddr PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size, 219 GPUVAddr PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size,
222 PTEKind kind); 220 PTEKind kind);
223 221
224 template <EntryType entry_type> 222 template <EntryType entry_type>
225 GPUVAddr BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size, 223 GPUVAddr BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size,
226 PTEKind kind); 224 PTEKind kind);
227 225
228 template <bool is_big_page> 226 template <bool is_big_page>
@@ -233,11 +231,11 @@ private:
233 231
234 Common::MultiLevelPageTable<u32> page_table; 232 Common::MultiLevelPageTable<u32> page_table;
235 Common::RangeMap<GPUVAddr, PTEKind> kind_map; 233 Common::RangeMap<GPUVAddr, PTEKind> kind_map;
236 Common::VirtualBuffer<u32> big_page_table_cpu; 234 Common::VirtualBuffer<u32> big_page_table_dev;
237 235
238 std::vector<u64> big_page_continuous; 236 std::vector<u64> big_page_continuous;
239 boost::container::small_vector<std::pair<VAddr, std::size_t>, 32> page_stash{}; 237 boost::container::small_vector<std::pair<DAddr, std::size_t>, 32> page_stash{};
240 boost::container::small_vector<std::pair<VAddr, std::size_t>, 32> page_stash2{}; 238 boost::container::small_vector<std::pair<DAddr, std::size_t>, 32> page_stash2{};
241 239
242 mutable std::mutex guard; 240 mutable std::mutex guard;
243 241
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index a64404ce4..4861b123a 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -18,9 +18,9 @@
18 18
19#include "common/assert.h" 19#include "common/assert.h"
20#include "common/settings.h" 20#include "common/settings.h"
21#include "core/memory.h"
22#include "video_core/control/channel_state_cache.h" 21#include "video_core/control/channel_state_cache.h"
23#include "video_core/engines/maxwell_3d.h" 22#include "video_core/engines/maxwell_3d.h"
23#include "video_core/host1x/gpu_device_memory_manager.h"
24#include "video_core/memory_manager.h" 24#include "video_core/memory_manager.h"
25#include "video_core/rasterizer_interface.h" 25#include "video_core/rasterizer_interface.h"
26#include "video_core/texture_cache/slot_vector.h" 26#include "video_core/texture_cache/slot_vector.h"
@@ -102,18 +102,19 @@ template <class QueryCache, class CachedQuery, class CounterStream, class HostCo
102class QueryCacheLegacy : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { 102class QueryCacheLegacy : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
103public: 103public:
104 explicit QueryCacheLegacy(VideoCore::RasterizerInterface& rasterizer_, 104 explicit QueryCacheLegacy(VideoCore::RasterizerInterface& rasterizer_,
105 Core::Memory::Memory& cpu_memory_) 105 Tegra::MaxwellDeviceMemoryManager& device_memory_)
106 : rasterizer{rasterizer_}, 106 : rasterizer{rasterizer_},
107 // Use reinterpret_cast instead of static_cast as workaround for 107 // Use reinterpret_cast instead of static_cast as workaround for
108 // UBSan bug (https://github.com/llvm/llvm-project/issues/59060) 108 // UBSan bug (https://github.com/llvm/llvm-project/issues/59060)
109 cpu_memory{cpu_memory_}, streams{{ 109 device_memory{device_memory_},
110 {CounterStream{reinterpret_cast<QueryCache&>(*this), 110 streams{{
111 VideoCore::QueryType::SamplesPassed}}, 111 {CounterStream{reinterpret_cast<QueryCache&>(*this),
112 {CounterStream{reinterpret_cast<QueryCache&>(*this), 112 VideoCore::QueryType::SamplesPassed}},
113 VideoCore::QueryType::PrimitivesGenerated}}, 113 {CounterStream{reinterpret_cast<QueryCache&>(*this),
114 {CounterStream{reinterpret_cast<QueryCache&>(*this), 114 VideoCore::QueryType::PrimitivesGenerated}},
115 VideoCore::QueryType::TfbPrimitivesWritten}}, 115 {CounterStream{reinterpret_cast<QueryCache&>(*this),
116 }} { 116 VideoCore::QueryType::TfbPrimitivesWritten}},
117 }} {
117 (void)slot_async_jobs.insert(); // Null value 118 (void)slot_async_jobs.insert(); // Null value
118 } 119 }
119 120
@@ -322,13 +323,14 @@ private:
322 local_lock.unlock(); 323 local_lock.unlock();
323 if (timestamp) { 324 if (timestamp) {
324 u64 timestamp_value = *timestamp; 325 u64 timestamp_value = *timestamp;
325 cpu_memory.WriteBlockUnsafe(address + sizeof(u64), &timestamp_value, sizeof(u64)); 326 device_memory.WriteBlockUnsafe(address + sizeof(u64), &timestamp_value,
326 cpu_memory.WriteBlockUnsafe(address, &value, sizeof(u64)); 327 sizeof(u64));
328 device_memory.WriteBlockUnsafe(address, &value, sizeof(u64));
327 rasterizer.InvalidateRegion(address, sizeof(u64) * 2, 329 rasterizer.InvalidateRegion(address, sizeof(u64) * 2,
328 VideoCommon::CacheType::NoQueryCache); 330 VideoCommon::CacheType::NoQueryCache);
329 } else { 331 } else {
330 u32 small_value = static_cast<u32>(value); 332 u32 small_value = static_cast<u32>(value);
331 cpu_memory.WriteBlockUnsafe(address, &small_value, sizeof(u32)); 333 device_memory.WriteBlockUnsafe(address, &small_value, sizeof(u32));
332 rasterizer.InvalidateRegion(address, sizeof(u32), 334 rasterizer.InvalidateRegion(address, sizeof(u32),
333 VideoCommon::CacheType::NoQueryCache); 335 VideoCommon::CacheType::NoQueryCache);
334 } 336 }
@@ -342,7 +344,7 @@ private:
342 SlotVector<AsyncJob> slot_async_jobs; 344 SlotVector<AsyncJob> slot_async_jobs;
343 345
344 VideoCore::RasterizerInterface& rasterizer; 346 VideoCore::RasterizerInterface& rasterizer;
345 Core::Memory::Memory& cpu_memory; 347 Tegra::MaxwellDeviceMemoryManager& device_memory;
346 348
347 mutable std::recursive_mutex mutex; 349 mutable std::recursive_mutex mutex;
348 350
diff --git a/src/video_core/query_cache/query_base.h b/src/video_core/query_cache/query_base.h
index 1d786b3a7..d5d21beaa 100644
--- a/src/video_core/query_cache/query_base.h
+++ b/src/video_core/query_cache/query_base.h
@@ -23,7 +23,7 @@ DECLARE_ENUM_FLAG_OPERATORS(QueryFlagBits)
23 23
24class QueryBase { 24class QueryBase {
25public: 25public:
26 VAddr guest_address{}; 26 DAddr guest_address{};
27 QueryFlagBits flags{}; 27 QueryFlagBits flags{};
28 u64 value{}; 28 u64 value{};
29 29
@@ -32,7 +32,7 @@ protected:
32 QueryBase() = default; 32 QueryBase() = default;
33 33
34 // Parameterized constructor 34 // Parameterized constructor
35 QueryBase(VAddr address, QueryFlagBits flags_, u64 value_) 35 QueryBase(DAddr address, QueryFlagBits flags_, u64 value_)
36 : guest_address(address), flags(flags_), value{value_} {} 36 : guest_address(address), flags(flags_), value{value_} {}
37}; 37};
38 38
@@ -67,4 +67,4 @@ public:
67 size_t size_slots{}; 67 size_t size_slots{};
68}; 68};
69 69
70} // namespace VideoCommon \ No newline at end of file 70} // namespace VideoCommon
diff --git a/src/video_core/query_cache/query_cache.h b/src/video_core/query_cache/query_cache.h
index 94f0c4466..08b779055 100644
--- a/src/video_core/query_cache/query_cache.h
+++ b/src/video_core/query_cache/query_cache.h
@@ -15,9 +15,9 @@
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/scope_exit.h" 16#include "common/scope_exit.h"
17#include "common/settings.h" 17#include "common/settings.h"
18#include "core/memory.h"
19#include "video_core/engines/maxwell_3d.h" 18#include "video_core/engines/maxwell_3d.h"
20#include "video_core/gpu.h" 19#include "video_core/gpu.h"
20#include "video_core/host1x/gpu_device_memory_manager.h"
21#include "video_core/memory_manager.h" 21#include "video_core/memory_manager.h"
22#include "video_core/query_cache/bank_base.h" 22#include "video_core/query_cache/bank_base.h"
23#include "video_core/query_cache/query_base.h" 23#include "video_core/query_cache/query_base.h"
@@ -113,9 +113,10 @@ struct QueryCacheBase<Traits>::QueryCacheBaseImpl {
113 using RuntimeType = typename Traits::RuntimeType; 113 using RuntimeType = typename Traits::RuntimeType;
114 114
115 QueryCacheBaseImpl(QueryCacheBase<Traits>* owner_, VideoCore::RasterizerInterface& rasterizer_, 115 QueryCacheBaseImpl(QueryCacheBase<Traits>* owner_, VideoCore::RasterizerInterface& rasterizer_,
116 Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_, Tegra::GPU& gpu_) 116 Tegra::MaxwellDeviceMemoryManager& device_memory_, RuntimeType& runtime_,
117 Tegra::GPU& gpu_)
117 : owner{owner_}, rasterizer{rasterizer_}, 118 : owner{owner_}, rasterizer{rasterizer_},
118 cpu_memory{cpu_memory_}, runtime{runtime_}, gpu{gpu_} { 119 device_memory{device_memory_}, runtime{runtime_}, gpu{gpu_} {
119 streamer_mask = 0; 120 streamer_mask = 0;
120 for (size_t i = 0; i < static_cast<size_t>(QueryType::MaxQueryTypes); i++) { 121 for (size_t i = 0; i < static_cast<size_t>(QueryType::MaxQueryTypes); i++) {
121 streamers[i] = runtime.GetStreamerInterface(static_cast<QueryType>(i)); 122 streamers[i] = runtime.GetStreamerInterface(static_cast<QueryType>(i));
@@ -158,7 +159,7 @@ struct QueryCacheBase<Traits>::QueryCacheBaseImpl {
158 159
159 QueryCacheBase<Traits>* owner; 160 QueryCacheBase<Traits>* owner;
160 VideoCore::RasterizerInterface& rasterizer; 161 VideoCore::RasterizerInterface& rasterizer;
161 Core::Memory::Memory& cpu_memory; 162 Tegra::MaxwellDeviceMemoryManager& device_memory;
162 RuntimeType& runtime; 163 RuntimeType& runtime;
163 Tegra::GPU& gpu; 164 Tegra::GPU& gpu;
164 std::array<StreamerInterface*, static_cast<size_t>(QueryType::MaxQueryTypes)> streamers; 165 std::array<StreamerInterface*, static_cast<size_t>(QueryType::MaxQueryTypes)> streamers;
@@ -171,10 +172,11 @@ struct QueryCacheBase<Traits>::QueryCacheBaseImpl {
171template <typename Traits> 172template <typename Traits>
172QueryCacheBase<Traits>::QueryCacheBase(Tegra::GPU& gpu_, 173QueryCacheBase<Traits>::QueryCacheBase(Tegra::GPU& gpu_,
173 VideoCore::RasterizerInterface& rasterizer_, 174 VideoCore::RasterizerInterface& rasterizer_,
174 Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_) 175 Tegra::MaxwellDeviceMemoryManager& device_memory_,
176 RuntimeType& runtime_)
175 : cached_queries{} { 177 : cached_queries{} {
176 impl = std::make_unique<QueryCacheBase<Traits>::QueryCacheBaseImpl>( 178 impl = std::make_unique<QueryCacheBase<Traits>::QueryCacheBaseImpl>(
177 this, rasterizer_, cpu_memory_, runtime_, gpu_); 179 this, rasterizer_, device_memory_, runtime_, gpu_);
178} 180}
179 181
180template <typename Traits> 182template <typename Traits>
@@ -240,7 +242,7 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
240 if (!cpu_addr_opt) [[unlikely]] { 242 if (!cpu_addr_opt) [[unlikely]] {
241 return; 243 return;
242 } 244 }
243 VAddr cpu_addr = *cpu_addr_opt; 245 DAddr cpu_addr = *cpu_addr_opt;
244 const size_t new_query_id = streamer->WriteCounter(cpu_addr, has_timestamp, payload, subreport); 246 const size_t new_query_id = streamer->WriteCounter(cpu_addr, has_timestamp, payload, subreport);
245 auto* query = streamer->GetQuery(new_query_id); 247 auto* query = streamer->GetQuery(new_query_id);
246 if (is_fence) { 248 if (is_fence) {
@@ -250,13 +252,12 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
250 query_location.stream_id.Assign(static_cast<u32>(streamer_id)); 252 query_location.stream_id.Assign(static_cast<u32>(streamer_id));
251 query_location.query_id.Assign(static_cast<u32>(new_query_id)); 253 query_location.query_id.Assign(static_cast<u32>(new_query_id));
252 const auto gen_caching_indexing = [](VAddr cur_addr) { 254 const auto gen_caching_indexing = [](VAddr cur_addr) {
253 return std::make_pair<u64, u32>(cur_addr >> Core::Memory::YUZU_PAGEBITS, 255 return std::make_pair<u64, u32>(cur_addr >> Core::DEVICE_PAGEBITS,
254 static_cast<u32>(cur_addr & Core::Memory::YUZU_PAGEMASK)); 256 static_cast<u32>(cur_addr & Core::DEVICE_PAGEMASK));
255 }; 257 };
256 u8* pointer = impl->cpu_memory.GetPointer(cpu_addr); 258 u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
257 u8* pointer_timestamp = impl->cpu_memory.GetPointer(cpu_addr + 8); 259 u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
258 bool is_synced = !Settings::IsGPULevelHigh() && is_fence; 260 bool is_synced = !Settings::IsGPULevelHigh() && is_fence;
259
260 std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location, 261 std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location,
261 pointer, pointer_timestamp] { 262 pointer, pointer_timestamp] {
262 if (True(query_base->flags & QueryFlagBits::IsInvalidated)) { 263 if (True(query_base->flags & QueryFlagBits::IsInvalidated)) {
@@ -323,8 +324,8 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
323template <typename Traits> 324template <typename Traits>
324void QueryCacheBase<Traits>::UnregisterPending() { 325void QueryCacheBase<Traits>::UnregisterPending() {
325 const auto gen_caching_indexing = [](VAddr cur_addr) { 326 const auto gen_caching_indexing = [](VAddr cur_addr) {
326 return std::make_pair<u64, u32>(cur_addr >> Core::Memory::YUZU_PAGEBITS, 327 return std::make_pair<u64, u32>(cur_addr >> Core::DEVICE_PAGEBITS,
327 static_cast<u32>(cur_addr & Core::Memory::YUZU_PAGEMASK)); 328 static_cast<u32>(cur_addr & Core::DEVICE_PAGEMASK));
328 }; 329 };
329 std::scoped_lock lock(cache_mutex); 330 std::scoped_lock lock(cache_mutex);
330 for (QueryLocation loc : impl->pending_unregister) { 331 for (QueryLocation loc : impl->pending_unregister) {
@@ -388,7 +389,7 @@ bool QueryCacheBase<Traits>::AccelerateHostConditionalRendering() {
388 } 389 }
389 VAddr cpu_addr = *cpu_addr_opt; 390 VAddr cpu_addr = *cpu_addr_opt;
390 std::scoped_lock lock(cache_mutex); 391 std::scoped_lock lock(cache_mutex);
391 auto it1 = cached_queries.find(cpu_addr >> Core::Memory::YUZU_PAGEBITS); 392 auto it1 = cached_queries.find(cpu_addr >> Core::DEVICE_PAGEBITS);
392 if (it1 == cached_queries.end()) { 393 if (it1 == cached_queries.end()) {
393 return VideoCommon::LookupData{ 394 return VideoCommon::LookupData{
394 .address = cpu_addr, 395 .address = cpu_addr,
@@ -396,10 +397,10 @@ bool QueryCacheBase<Traits>::AccelerateHostConditionalRendering() {
396 }; 397 };
397 } 398 }
398 auto& sub_container = it1->second; 399 auto& sub_container = it1->second;
399 auto it_current = sub_container.find(cpu_addr & Core::Memory::YUZU_PAGEMASK); 400 auto it_current = sub_container.find(cpu_addr & Core::DEVICE_PAGEMASK);
400 401
401 if (it_current == sub_container.end()) { 402 if (it_current == sub_container.end()) {
402 auto it_current_2 = sub_container.find((cpu_addr & Core::Memory::YUZU_PAGEMASK) + 4); 403 auto it_current_2 = sub_container.find((cpu_addr & Core::DEVICE_PAGEMASK) + 4);
403 if (it_current_2 == sub_container.end()) { 404 if (it_current_2 == sub_container.end()) {
404 return VideoCommon::LookupData{ 405 return VideoCommon::LookupData{
405 .address = cpu_addr, 406 .address = cpu_addr,
@@ -559,7 +560,7 @@ bool QueryCacheBase<Traits>::SemiFlushQueryDirty(QueryCacheBase<Traits>::QueryLo
559 } 560 }
560 if (True(query_base->flags & QueryFlagBits::IsFinalValueSynced) && 561 if (True(query_base->flags & QueryFlagBits::IsFinalValueSynced) &&
561 False(query_base->flags & QueryFlagBits::IsGuestSynced)) { 562 False(query_base->flags & QueryFlagBits::IsGuestSynced)) {
562 auto* ptr = impl->cpu_memory.GetPointer(query_base->guest_address); 563 auto* ptr = impl->device_memory.template GetPointer<u8>(query_base->guest_address);
563 if (True(query_base->flags & QueryFlagBits::HasTimestamp)) { 564 if (True(query_base->flags & QueryFlagBits::HasTimestamp)) {
564 std::memcpy(ptr, &query_base->value, sizeof(query_base->value)); 565 std::memcpy(ptr, &query_base->value, sizeof(query_base->value));
565 return false; 566 return false;
diff --git a/src/video_core/query_cache/query_cache_base.h b/src/video_core/query_cache/query_cache_base.h
index 07be421c6..00c25c8d6 100644
--- a/src/video_core/query_cache/query_cache_base.h
+++ b/src/video_core/query_cache/query_cache_base.h
@@ -13,15 +13,11 @@
13#include "common/assert.h" 13#include "common/assert.h"
14#include "common/bit_field.h" 14#include "common/bit_field.h"
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/memory.h"
17#include "video_core/control/channel_state_cache.h" 16#include "video_core/control/channel_state_cache.h"
17#include "video_core/host1x/gpu_device_memory_manager.h"
18#include "video_core/query_cache/query_base.h" 18#include "video_core/query_cache/query_base.h"
19#include "video_core/query_cache/types.h" 19#include "video_core/query_cache/types.h"
20 20
21namespace Core::Memory {
22class Memory;
23}
24
25namespace VideoCore { 21namespace VideoCore {
26class RasterizerInterface; 22class RasterizerInterface;
27} 23}
@@ -53,7 +49,8 @@ public:
53 }; 49 };
54 50
55 explicit QueryCacheBase(Tegra::GPU& gpu, VideoCore::RasterizerInterface& rasterizer_, 51 explicit QueryCacheBase(Tegra::GPU& gpu, VideoCore::RasterizerInterface& rasterizer_,
56 Core::Memory::Memory& cpu_memory_, RuntimeType& runtime_); 52 Tegra::MaxwellDeviceMemoryManager& device_memory_,
53 RuntimeType& runtime_);
57 54
58 ~QueryCacheBase(); 55 ~QueryCacheBase();
59 56
@@ -125,10 +122,10 @@ protected:
125 const u64 addr_begin = addr; 122 const u64 addr_begin = addr;
126 const u64 addr_end = addr_begin + size; 123 const u64 addr_end = addr_begin + size;
127 124
128 const u64 page_end = addr_end >> Core::Memory::YUZU_PAGEBITS; 125 const u64 page_end = addr_end >> Core::DEVICE_PAGEBITS;
129 std::scoped_lock lock(cache_mutex); 126 std::scoped_lock lock(cache_mutex);
130 for (u64 page = addr_begin >> Core::Memory::YUZU_PAGEBITS; page <= page_end; ++page) { 127 for (u64 page = addr_begin >> Core::DEVICE_PAGEBITS; page <= page_end; ++page) {
131 const u64 page_start = page << Core::Memory::YUZU_PAGEBITS; 128 const u64 page_start = page << Core::DEVICE_PAGEBITS;
132 const auto in_range = [page_start, addr_begin, addr_end](const u32 query_location) { 129 const auto in_range = [page_start, addr_begin, addr_end](const u32 query_location) {
133 const u64 cache_begin = page_start + query_location; 130 const u64 cache_begin = page_start + query_location;
134 const u64 cache_end = cache_begin + sizeof(u32); 131 const u64 cache_end = cache_begin + sizeof(u32);
@@ -178,4 +175,4 @@ protected:
178 std::unique_ptr<QueryCacheBaseImpl> impl; 175 std::unique_ptr<QueryCacheBaseImpl> impl;
179}; 176};
180 177
181} // namespace VideoCommon \ No newline at end of file 178} // namespace VideoCommon
diff --git a/src/video_core/query_cache/query_stream.h b/src/video_core/query_cache/query_stream.h
index d9040acd2..1d11b1275 100644
--- a/src/video_core/query_cache/query_stream.h
+++ b/src/video_core/query_cache/query_stream.h
@@ -146,4 +146,4 @@ protected:
146 std::deque<size_t> old_queries; 146 std::deque<size_t> old_queries;
147}; 147};
148 148
149} // namespace VideoCommon \ No newline at end of file 149} // namespace VideoCommon
diff --git a/src/video_core/query_cache/types.h b/src/video_core/query_cache/types.h
index e9226bbfc..0c6a882e2 100644
--- a/src/video_core/query_cache/types.h
+++ b/src/video_core/query_cache/types.h
@@ -71,4 +71,4 @@ enum class ReductionOp : u32 {
71 MaxReductionOp, 71 MaxReductionOp,
72}; 72};
73 73
74} // namespace VideoCommon \ No newline at end of file 74} // namespace VideoCommon
diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp
deleted file mode 100644
index f200a650f..000000000
--- a/src/video_core/rasterizer_accelerated.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <atomic>
5
6#include "common/assert.h"
7#include "common/common_types.h"
8#include "common/div_ceil.h"
9#include "core/memory.h"
10#include "video_core/rasterizer_accelerated.h"
11
12namespace VideoCore {
13
14using namespace Core::Memory;
15
16RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_)
17 : cached_pages(std::make_unique<CachedPages>()), cpu_memory{cpu_memory_} {}
18
19RasterizerAccelerated::~RasterizerAccelerated() = default;
20
21void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
22 u64 uncache_begin = 0;
23 u64 cache_begin = 0;
24 u64 uncache_bytes = 0;
25 u64 cache_bytes = 0;
26
27 std::atomic_thread_fence(std::memory_order_acquire);
28 const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE);
29 for (u64 page = addr >> YUZU_PAGEBITS; page != page_end; ++page) {
30 std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page);
31
32 if (delta > 0) {
33 ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!");
34 } else if (delta < 0) {
35 ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
36 } else {
37 ASSERT_MSG(false, "Delta must be non-zero!");
38 }
39
40 // Adds or subtracts 1, as count is a unsigned 8-bit value
41 count.fetch_add(static_cast<u16>(delta), std::memory_order_release);
42
43 // Assume delta is either -1 or 1
44 if (count.load(std::memory_order::relaxed) == 0) {
45 if (uncache_bytes == 0) {
46 uncache_begin = page;
47 }
48 uncache_bytes += YUZU_PAGESIZE;
49 } else if (uncache_bytes > 0) {
50 cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes,
51 false);
52 uncache_bytes = 0;
53 }
54 if (count.load(std::memory_order::relaxed) == 1 && delta > 0) {
55 if (cache_bytes == 0) {
56 cache_begin = page;
57 }
58 cache_bytes += YUZU_PAGESIZE;
59 } else if (cache_bytes > 0) {
60 cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true);
61 cache_bytes = 0;
62 }
63 }
64 if (uncache_bytes > 0) {
65 cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, false);
66 }
67 if (cache_bytes > 0) {
68 cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true);
69 }
70}
71
72} // namespace VideoCore
diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h
deleted file mode 100644
index e6c0ea87a..000000000
--- a/src/video_core/rasterizer_accelerated.h
+++ /dev/null
@@ -1,49 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <atomic>
8
9#include "common/common_types.h"
10#include "video_core/rasterizer_interface.h"
11
12namespace Core::Memory {
13class Memory;
14}
15
16namespace VideoCore {
17
18/// Implements the shared part in GPU accelerated rasterizers in RasterizerInterface.
19class RasterizerAccelerated : public RasterizerInterface {
20public:
21 explicit RasterizerAccelerated(Core::Memory::Memory& cpu_memory_);
22 ~RasterizerAccelerated() override;
23
24 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
25
26private:
27 class CacheEntry final {
28 public:
29 CacheEntry() = default;
30
31 std::atomic_uint16_t& Count(std::size_t page) {
32 return values[page & 3];
33 }
34
35 const std::atomic_uint16_t& Count(std::size_t page) const {
36 return values[page & 3];
37 }
38
39 private:
40 std::array<std::atomic_uint16_t, 4> values{};
41 };
42 static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
43
44 using CachedPages = std::array<CacheEntry, 0x2000000>;
45 std::unique_ptr<CachedPages> cached_pages;
46 Core::Memory::Memory& cpu_memory;
47};
48
49} // namespace VideoCore
diff --git a/src/video_core/rasterizer_download_area.h b/src/video_core/rasterizer_download_area.h
index 2d7425c79..d28826043 100644
--- a/src/video_core/rasterizer_download_area.h
+++ b/src/video_core/rasterizer_download_area.h
@@ -13,4 +13,4 @@ struct RasterizerDownloadArea {
13 bool preemtive; 13 bool preemtive;
14}; 14};
15 15
16} // namespace VideoCore \ No newline at end of file 16} // namespace VideoCore
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 49224ca85..8fa4e4d9a 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -86,35 +86,35 @@ public:
86 virtual void FlushAll() = 0; 86 virtual void FlushAll() = 0;
87 87
88 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 88 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
89 virtual void FlushRegion(VAddr addr, u64 size, 89 virtual void FlushRegion(DAddr addr, u64 size,
90 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0; 90 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0;
91 91
92 /// Check if the the specified memory area requires flushing to CPU Memory. 92 /// Check if the the specified memory area requires flushing to CPU Memory.
93 virtual bool MustFlushRegion(VAddr addr, u64 size, 93 virtual bool MustFlushRegion(DAddr addr, u64 size,
94 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0; 94 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0;
95 95
96 virtual RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) = 0; 96 virtual RasterizerDownloadArea GetFlushArea(DAddr addr, u64 size) = 0;
97 97
98 /// Notify rasterizer that any caches of the specified region should be invalidated 98 /// Notify rasterizer that any caches of the specified region should be invalidated
99 virtual void InvalidateRegion(VAddr addr, u64 size, 99 virtual void InvalidateRegion(DAddr addr, u64 size,
100 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0; 100 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0;
101 101
102 virtual void InnerInvalidation(std::span<const std::pair<VAddr, std::size_t>> sequences) { 102 virtual void InnerInvalidation(std::span<const std::pair<DAddr, std::size_t>> sequences) {
103 for (const auto& [cpu_addr, size] : sequences) { 103 for (const auto& [cpu_addr, size] : sequences) {
104 InvalidateRegion(cpu_addr, size); 104 InvalidateRegion(cpu_addr, size);
105 } 105 }
106 } 106 }
107 107
108 /// Notify rasterizer that any caches of the specified region are desync with guest 108 /// Notify rasterizer that any caches of the specified region are desync with guest
109 virtual void OnCacheInvalidation(VAddr addr, u64 size) = 0; 109 virtual void OnCacheInvalidation(PAddr addr, u64 size) = 0;
110 110
111 virtual bool OnCPUWrite(VAddr addr, u64 size) = 0; 111 virtual bool OnCPUWrite(PAddr addr, u64 size) = 0;
112 112
113 /// Sync memory between guest and host. 113 /// Sync memory between guest and host.
114 virtual void InvalidateGPUCache() = 0; 114 virtual void InvalidateGPUCache() = 0;
115 115
116 /// Unmap memory range 116 /// Unmap memory range
117 virtual void UnmapMemory(VAddr addr, u64 size) = 0; 117 virtual void UnmapMemory(DAddr addr, u64 size) = 0;
118 118
119 /// Remap GPU memory range. This means underneath backing memory changed 119 /// Remap GPU memory range. This means underneath backing memory changed
120 virtual void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) = 0; 120 virtual void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) = 0;
@@ -122,7 +122,7 @@ public:
122 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 122 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
123 /// and invalidated 123 /// and invalidated
124 virtual void FlushAndInvalidateRegion( 124 virtual void FlushAndInvalidateRegion(
125 VAddr addr, u64 size, VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0; 125 DAddr addr, u64 size, VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0;
126 126
127 /// Notify the host renderer to wait for previous primitive and compute operations. 127 /// Notify the host renderer to wait for previous primitive and compute operations.
128 virtual void WaitForIdle() = 0; 128 virtual void WaitForIdle() = 0;
@@ -157,13 +157,10 @@ public:
157 157
158 /// Attempt to use a faster method to display the framebuffer to screen 158 /// Attempt to use a faster method to display the framebuffer to screen
159 [[nodiscard]] virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config, 159 [[nodiscard]] virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config,
160 VAddr framebuffer_addr, u32 pixel_stride) { 160 DAddr framebuffer_addr, u32 pixel_stride) {
161 return false; 161 return false;
162 } 162 }
163 163
164 /// Increase/decrease the number of object in pages touching the specified region
165 virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
166
167 /// Initialize disk cached resources for the game being emulated 164 /// Initialize disk cached resources for the game being emulated
168 virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 165 virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
169 const DiskResourceLoadCallback& callback) {} 166 const DiskResourceLoadCallback& callback) {}
diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp
index 4f1d5b548..abfabb65b 100644
--- a/src/video_core/renderer_null/null_rasterizer.cpp
+++ b/src/video_core/renderer_null/null_rasterizer.cpp
@@ -2,7 +2,6 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/alignment.h" 4#include "common/alignment.h"
5#include "core/memory.h"
6#include "video_core/control/channel_state.h" 5#include "video_core/control/channel_state.h"
7#include "video_core/host1x/host1x.h" 6#include "video_core/host1x/host1x.h"
8#include "video_core/memory_manager.h" 7#include "video_core/memory_manager.h"
@@ -19,8 +18,7 @@ bool AccelerateDMA::BufferClear(GPUVAddr src_address, u64 amount, u32 value) {
19 return true; 18 return true;
20} 19}
21 20
22RasterizerNull::RasterizerNull(Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu) 21RasterizerNull::RasterizerNull(Tegra::GPU& gpu) : m_gpu{gpu} {}
23 : RasterizerAccelerated(cpu_memory_), m_gpu{gpu} {}
24RasterizerNull::~RasterizerNull() = default; 22RasterizerNull::~RasterizerNull() = default;
25 23
26void RasterizerNull::Draw(bool is_indexed, u32 instance_count) {} 24void RasterizerNull::Draw(bool is_indexed, u32 instance_count) {}
@@ -45,25 +43,25 @@ void RasterizerNull::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr
45 u32 size) {} 43 u32 size) {}
46void RasterizerNull::DisableGraphicsUniformBuffer(size_t stage, u32 index) {} 44void RasterizerNull::DisableGraphicsUniformBuffer(size_t stage, u32 index) {}
47void RasterizerNull::FlushAll() {} 45void RasterizerNull::FlushAll() {}
48void RasterizerNull::FlushRegion(VAddr addr, u64 size, VideoCommon::CacheType) {} 46void RasterizerNull::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType) {}
49bool RasterizerNull::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheType) { 47bool RasterizerNull::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheType) {
50 return false; 48 return false;
51} 49}
52void RasterizerNull::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType) {} 50void RasterizerNull::InvalidateRegion(DAddr addr, u64 size, VideoCommon::CacheType) {}
53bool RasterizerNull::OnCPUWrite(VAddr addr, u64 size) { 51bool RasterizerNull::OnCPUWrite(PAddr addr, u64 size) {
54 return false; 52 return false;
55} 53}
56void RasterizerNull::OnCacheInvalidation(VAddr addr, u64 size) {} 54void RasterizerNull::OnCacheInvalidation(PAddr addr, u64 size) {}
57VideoCore::RasterizerDownloadArea RasterizerNull::GetFlushArea(VAddr addr, u64 size) { 55VideoCore::RasterizerDownloadArea RasterizerNull::GetFlushArea(PAddr addr, u64 size) {
58 VideoCore::RasterizerDownloadArea new_area{ 56 VideoCore::RasterizerDownloadArea new_area{
59 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE), 57 .start_address = Common::AlignDown(addr, Core::DEVICE_PAGESIZE),
60 .end_address = Common::AlignUp(addr + size, Core::Memory::YUZU_PAGESIZE), 58 .end_address = Common::AlignUp(addr + size, Core::DEVICE_PAGESIZE),
61 .preemtive = true, 59 .preemtive = true,
62 }; 60 };
63 return new_area; 61 return new_area;
64} 62}
65void RasterizerNull::InvalidateGPUCache() {} 63void RasterizerNull::InvalidateGPUCache() {}
66void RasterizerNull::UnmapMemory(VAddr addr, u64 size) {} 64void RasterizerNull::UnmapMemory(DAddr addr, u64 size) {}
67void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {} 65void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {}
68void RasterizerNull::SignalFence(std::function<void()>&& func) { 66void RasterizerNull::SignalFence(std::function<void()>&& func) {
69 func(); 67 func();
@@ -78,7 +76,7 @@ void RasterizerNull::SignalSyncPoint(u32 value) {
78} 76}
79void RasterizerNull::SignalReference() {} 77void RasterizerNull::SignalReference() {}
80void RasterizerNull::ReleaseFences(bool) {} 78void RasterizerNull::ReleaseFences(bool) {}
81void RasterizerNull::FlushAndInvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType) {} 79void RasterizerNull::FlushAndInvalidateRegion(DAddr addr, u64 size, VideoCommon::CacheType) {}
82void RasterizerNull::WaitForIdle() {} 80void RasterizerNull::WaitForIdle() {}
83void RasterizerNull::FragmentBarrier() {} 81void RasterizerNull::FragmentBarrier() {}
84void RasterizerNull::TiledCacheBarrier() {} 82void RasterizerNull::TiledCacheBarrier() {}
@@ -95,7 +93,7 @@ bool RasterizerNull::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surfac
95void RasterizerNull::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, 93void RasterizerNull::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
96 std::span<const u8> memory) {} 94 std::span<const u8> memory) {}
97bool RasterizerNull::AccelerateDisplay(const Tegra::FramebufferConfig& config, 95bool RasterizerNull::AccelerateDisplay(const Tegra::FramebufferConfig& config,
98 VAddr framebuffer_addr, u32 pixel_stride) { 96 DAddr framebuffer_addr, u32 pixel_stride) {
99 return true; 97 return true;
100} 98}
101void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, 99void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h
index 23001eeb8..a5789604f 100644
--- a/src/video_core/renderer_null/null_rasterizer.h
+++ b/src/video_core/renderer_null/null_rasterizer.h
@@ -6,7 +6,6 @@
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "video_core/control/channel_state_cache.h" 7#include "video_core/control/channel_state_cache.h"
8#include "video_core/engines/maxwell_dma.h" 8#include "video_core/engines/maxwell_dma.h"
9#include "video_core/rasterizer_accelerated.h"
10#include "video_core/rasterizer_interface.h" 9#include "video_core/rasterizer_interface.h"
11 10
12namespace Core { 11namespace Core {
@@ -32,10 +31,10 @@ public:
32 } 31 }
33}; 32};
34 33
35class RasterizerNull final : public VideoCore::RasterizerAccelerated, 34class RasterizerNull final : public VideoCore::RasterizerInterface,
36 protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { 35 protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
37public: 36public:
38 explicit RasterizerNull(Core::Memory::Memory& cpu_memory, Tegra::GPU& gpu); 37 explicit RasterizerNull(Tegra::GPU& gpu);
39 ~RasterizerNull() override; 38 ~RasterizerNull() override;
40 39
41 void Draw(bool is_indexed, u32 instance_count) override; 40 void Draw(bool is_indexed, u32 instance_count) override;
@@ -48,17 +47,17 @@ public:
48 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override; 47 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
49 void DisableGraphicsUniformBuffer(size_t stage, u32 index) override; 48 void DisableGraphicsUniformBuffer(size_t stage, u32 index) override;
50 void FlushAll() override; 49 void FlushAll() override;
51 void FlushRegion(VAddr addr, u64 size, 50 void FlushRegion(DAddr addr, u64 size,
52 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 51 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
53 bool MustFlushRegion(VAddr addr, u64 size, 52 bool MustFlushRegion(DAddr addr, u64 size,
54 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 53 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
55 void InvalidateRegion(VAddr addr, u64 size, 54 void InvalidateRegion(DAddr addr, u64 size,
56 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 55 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
57 void OnCacheInvalidation(VAddr addr, u64 size) override; 56 void OnCacheInvalidation(DAddr addr, u64 size) override;
58 bool OnCPUWrite(VAddr addr, u64 size) override; 57 bool OnCPUWrite(DAddr addr, u64 size) override;
59 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override; 58 VideoCore::RasterizerDownloadArea GetFlushArea(DAddr addr, u64 size) override;
60 void InvalidateGPUCache() override; 59 void InvalidateGPUCache() override;
61 void UnmapMemory(VAddr addr, u64 size) override; 60 void UnmapMemory(DAddr addr, u64 size) override;
62 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; 61 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
63 void SignalFence(std::function<void()>&& func) override; 62 void SignalFence(std::function<void()>&& func) override;
64 void SyncOperation(std::function<void()>&& func) override; 63 void SyncOperation(std::function<void()>&& func) override;
@@ -66,7 +65,7 @@ public:
66 void SignalReference() override; 65 void SignalReference() override;
67 void ReleaseFences(bool force) override; 66 void ReleaseFences(bool force) override;
68 void FlushAndInvalidateRegion( 67 void FlushAndInvalidateRegion(
69 VAddr addr, u64 size, VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 68 DAddr addr, u64 size, VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
70 void WaitForIdle() override; 69 void WaitForIdle() override;
71 void FragmentBarrier() override; 70 void FragmentBarrier() override;
72 void TiledCacheBarrier() override; 71 void TiledCacheBarrier() override;
@@ -78,7 +77,7 @@ public:
78 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; 77 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
79 void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, 78 void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
80 std::span<const u8> memory) override; 79 std::span<const u8> memory) override;
81 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 80 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr,
82 u32 pixel_stride) override; 81 u32 pixel_stride) override;
83 void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 82 void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
84 const VideoCore::DiskResourceLoadCallback& callback) override; 83 const VideoCore::DiskResourceLoadCallback& callback) override;
diff --git a/src/video_core/renderer_null/renderer_null.cpp b/src/video_core/renderer_null/renderer_null.cpp
index be92cc2f4..078feb925 100644
--- a/src/video_core/renderer_null/renderer_null.cpp
+++ b/src/video_core/renderer_null/renderer_null.cpp
@@ -7,10 +7,9 @@
7 7
8namespace Null { 8namespace Null {
9 9
10RendererNull::RendererNull(Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory, 10RendererNull::RendererNull(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
11 Tegra::GPU& gpu,
12 std::unique_ptr<Core::Frontend::GraphicsContext> context_) 11 std::unique_ptr<Core::Frontend::GraphicsContext> context_)
13 : RendererBase(emu_window, std::move(context_)), m_gpu(gpu), m_rasterizer(cpu_memory, gpu) {} 12 : RendererBase(emu_window, std::move(context_)), m_gpu(gpu), m_rasterizer(gpu) {}
14 13
15RendererNull::~RendererNull() = default; 14RendererNull::~RendererNull() = default;
16 15
diff --git a/src/video_core/renderer_null/renderer_null.h b/src/video_core/renderer_null/renderer_null.h
index 967ff5645..9531b43f6 100644
--- a/src/video_core/renderer_null/renderer_null.h
+++ b/src/video_core/renderer_null/renderer_null.h
@@ -13,8 +13,7 @@ namespace Null {
13 13
14class RendererNull final : public VideoCore::RendererBase { 14class RendererNull final : public VideoCore::RendererBase {
15public: 15public:
16 explicit RendererNull(Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory, 16 explicit RendererNull(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
17 Tegra::GPU& gpu,
18 std::unique_ptr<Core::Frontend::GraphicsContext> context); 17 std::unique_ptr<Core::Frontend::GraphicsContext> context);
19 ~RendererNull() override; 18 ~RendererNull() override;
20 19
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index 517ac14dd..ade72e1f9 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -47,11 +47,10 @@ constexpr std::array PROGRAM_LUT{
47} // Anonymous namespace 47} // Anonymous namespace
48 48
49Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) 49Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params)
50 : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params) {} 50 : VideoCommon::BufferBase(null_params) {}
51 51
52Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, 52Buffer::Buffer(BufferCacheRuntime& runtime, DAddr cpu_addr_, u64 size_bytes_)
53 VAddr cpu_addr_, u64 size_bytes_) 53 : VideoCommon::BufferBase(cpu_addr_, size_bytes_) {
54 : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_) {
55 buffer.Create(); 54 buffer.Create();
56 if (runtime.device.HasDebuggingToolAttached()) { 55 if (runtime.device.HasDebuggingToolAttached()) {
57 const std::string name = fmt::format("Buffer 0x{:x}", CpuAddr()); 56 const std::string name = fmt::format("Buffer 0x{:x}", CpuAddr());
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 2c18de166..af34c272b 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -10,7 +10,6 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/buffer_cache/buffer_cache_base.h" 11#include "video_core/buffer_cache/buffer_cache_base.h"
12#include "video_core/buffer_cache/memory_tracker_base.h" 12#include "video_core/buffer_cache/memory_tracker_base.h"
13#include "video_core/rasterizer_interface.h"
14#include "video_core/renderer_opengl/gl_device.h" 13#include "video_core/renderer_opengl/gl_device.h"
15#include "video_core/renderer_opengl/gl_resource_manager.h" 14#include "video_core/renderer_opengl/gl_resource_manager.h"
16#include "video_core/renderer_opengl/gl_staging_buffer_pool.h" 15#include "video_core/renderer_opengl/gl_staging_buffer_pool.h"
@@ -19,10 +18,9 @@ namespace OpenGL {
19 18
20class BufferCacheRuntime; 19class BufferCacheRuntime;
21 20
22class Buffer : public VideoCommon::BufferBase<VideoCore::RasterizerInterface> { 21class Buffer : public VideoCommon::BufferBase {
23public: 22public:
24 explicit Buffer(BufferCacheRuntime&, VideoCore::RasterizerInterface& rasterizer, VAddr cpu_addr, 23 explicit Buffer(BufferCacheRuntime&, DAddr cpu_addr, u64 size_bytes);
25 u64 size_bytes);
26 explicit Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams); 24 explicit Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams);
27 25
28 void ImmediateUpload(size_t offset, std::span<const u8> data) noexcept; 26 void ImmediateUpload(size_t offset, std::span<const u8> data) noexcept;
@@ -244,7 +242,7 @@ struct BufferCacheParams {
244 using Runtime = OpenGL::BufferCacheRuntime; 242 using Runtime = OpenGL::BufferCacheRuntime;
245 using Buffer = OpenGL::Buffer; 243 using Buffer = OpenGL::Buffer;
246 using Async_Buffer = OpenGL::StagingBufferMap; 244 using Async_Buffer = OpenGL::StagingBufferMap;
247 using MemoryTracker = VideoCommon::MemoryTrackerBase<VideoCore::RasterizerInterface>; 245 using MemoryTracker = VideoCommon::MemoryTrackerBase<Tegra::MaxwellDeviceMemoryManager>;
248 246
249 static constexpr bool IS_OPENGL = true; 247 static constexpr bool IS_OPENGL = true;
250 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = true; 248 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = true;
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp
index fef7360ed..2147d587f 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_query_cache.cpp
@@ -35,8 +35,9 @@ constexpr GLenum GetTarget(VideoCore::QueryType type) {
35 35
36} // Anonymous namespace 36} // Anonymous namespace
37 37
38QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_) 38QueryCache::QueryCache(RasterizerOpenGL& rasterizer_,
39 : QueryCacheLegacy(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} { 39 Tegra::MaxwellDeviceMemoryManager& device_memory_)
40 : QueryCacheLegacy(rasterizer_, device_memory_), gl_rasterizer{rasterizer_} {
40 EnableCounters(); 41 EnableCounters();
41} 42}
42 43
diff --git a/src/video_core/renderer_opengl/gl_query_cache.h b/src/video_core/renderer_opengl/gl_query_cache.h
index 0721e0b3d..38118f355 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.h
+++ b/src/video_core/renderer_opengl/gl_query_cache.h
@@ -8,6 +8,7 @@
8#include <vector> 8#include <vector>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/host1x/gpu_device_memory_manager.h"
11#include "video_core/query_cache.h" 12#include "video_core/query_cache.h"
12#include "video_core/rasterizer_interface.h" 13#include "video_core/rasterizer_interface.h"
13#include "video_core/renderer_opengl/gl_resource_manager.h" 14#include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -28,7 +29,8 @@ using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>;
28class QueryCache final 29class QueryCache final
29 : public VideoCommon::QueryCacheLegacy<QueryCache, CachedQuery, CounterStream, HostCounter> { 30 : public VideoCommon::QueryCacheLegacy<QueryCache, CachedQuery, CounterStream, HostCounter> {
30public: 31public:
31 explicit QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_); 32 explicit QueryCache(RasterizerOpenGL& rasterizer_,
33 Tegra::MaxwellDeviceMemoryManager& device_memory_);
32 ~QueryCache(); 34 ~QueryCache();
33 35
34 OGLQuery AllocateQuery(VideoCore::QueryType type); 36 OGLQuery AllocateQuery(VideoCore::QueryType type);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 7a5fad735..d5354ef2d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -70,18 +70,18 @@ std::optional<VideoCore::QueryType> MaxwellToVideoCoreQuery(VideoCommon::QueryTy
70} // Anonymous namespace 70} // Anonymous namespace
71 71
72RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 72RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
73 Core::Memory::Memory& cpu_memory_, const Device& device_, 73 Tegra::MaxwellDeviceMemoryManager& device_memory_,
74 ScreenInfo& screen_info_, ProgramManager& program_manager_, 74 const Device& device_, ScreenInfo& screen_info_,
75 StateTracker& state_tracker_) 75 ProgramManager& program_manager_, StateTracker& state_tracker_)
76 : RasterizerAccelerated(cpu_memory_), gpu(gpu_), device(device_), screen_info(screen_info_), 76 : gpu(gpu_), device_memory(device_memory_), device(device_), screen_info(screen_info_),
77 program_manager(program_manager_), state_tracker(state_tracker_), 77 program_manager(program_manager_), state_tracker(state_tracker_),
78 texture_cache_runtime(device, program_manager, state_tracker, staging_buffer_pool), 78 texture_cache_runtime(device, program_manager, state_tracker, staging_buffer_pool),
79 texture_cache(texture_cache_runtime, *this), 79 texture_cache(texture_cache_runtime, device_memory_),
80 buffer_cache_runtime(device, staging_buffer_pool), 80 buffer_cache_runtime(device, staging_buffer_pool),
81 buffer_cache(*this, cpu_memory_, buffer_cache_runtime), 81 buffer_cache(device_memory_, buffer_cache_runtime),
82 shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager, 82 shader_cache(device_memory_, emu_window_, device, texture_cache, buffer_cache,
83 state_tracker, gpu.ShaderNotify()), 83 program_manager, state_tracker, gpu.ShaderNotify()),
84 query_cache(*this, cpu_memory_), accelerate_dma(buffer_cache, texture_cache), 84 query_cache(*this, device_memory_), accelerate_dma(buffer_cache, texture_cache),
85 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache), 85 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
86 blit_image(program_manager_) {} 86 blit_image(program_manager_) {}
87 87
@@ -475,7 +475,7 @@ void RasterizerOpenGL::DisableGraphicsUniformBuffer(size_t stage, u32 index) {
475 475
476void RasterizerOpenGL::FlushAll() {} 476void RasterizerOpenGL::FlushAll() {}
477 477
478void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 478void RasterizerOpenGL::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
479 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 479 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
480 if (addr == 0 || size == 0) { 480 if (addr == 0 || size == 0) {
481 return; 481 return;
@@ -493,7 +493,7 @@ void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size, VideoCommon::CacheType
493 } 493 }
494} 494}
495 495
496bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 496bool RasterizerOpenGL::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
497 if ((True(which & VideoCommon::CacheType::BufferCache))) { 497 if ((True(which & VideoCommon::CacheType::BufferCache))) {
498 std::scoped_lock lock{buffer_cache.mutex}; 498 std::scoped_lock lock{buffer_cache.mutex};
499 if (buffer_cache.IsRegionGpuModified(addr, size)) { 499 if (buffer_cache.IsRegionGpuModified(addr, size)) {
@@ -510,7 +510,7 @@ bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheT
510 return false; 510 return false;
511} 511}
512 512
513VideoCore::RasterizerDownloadArea RasterizerOpenGL::GetFlushArea(VAddr addr, u64 size) { 513VideoCore::RasterizerDownloadArea RasterizerOpenGL::GetFlushArea(DAddr addr, u64 size) {
514 { 514 {
515 std::scoped_lock lock{texture_cache.mutex}; 515 std::scoped_lock lock{texture_cache.mutex};
516 auto area = texture_cache.GetFlushArea(addr, size); 516 auto area = texture_cache.GetFlushArea(addr, size);
@@ -526,14 +526,14 @@ VideoCore::RasterizerDownloadArea RasterizerOpenGL::GetFlushArea(VAddr addr, u64
526 } 526 }
527 } 527 }
528 VideoCore::RasterizerDownloadArea new_area{ 528 VideoCore::RasterizerDownloadArea new_area{
529 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE), 529 .start_address = Common::AlignDown(addr, Core::DEVICE_PAGESIZE),
530 .end_address = Common::AlignUp(addr + size, Core::Memory::YUZU_PAGESIZE), 530 .end_address = Common::AlignUp(addr + size, Core::DEVICE_PAGESIZE),
531 .preemtive = true, 531 .preemtive = true,
532 }; 532 };
533 return new_area; 533 return new_area;
534} 534}
535 535
536void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 536void RasterizerOpenGL::InvalidateRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
537 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 537 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
538 if (addr == 0 || size == 0) { 538 if (addr == 0 || size == 0) {
539 return; 539 return;
@@ -554,7 +554,7 @@ void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size, VideoCommon::Cache
554 } 554 }
555} 555}
556 556
557bool RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) { 557bool RasterizerOpenGL::OnCPUWrite(DAddr addr, u64 size) {
558 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 558 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
559 if (addr == 0 || size == 0) { 559 if (addr == 0 || size == 0) {
560 return false; 560 return false;
@@ -576,8 +576,9 @@ bool RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) {
576 return false; 576 return false;
577} 577}
578 578
579void RasterizerOpenGL::OnCacheInvalidation(VAddr addr, u64 size) { 579void RasterizerOpenGL::OnCacheInvalidation(DAddr addr, u64 size) {
580 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 580 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
581
581 if (addr == 0 || size == 0) { 582 if (addr == 0 || size == 0) {
582 return; 583 return;
583 } 584 }
@@ -596,7 +597,7 @@ void RasterizerOpenGL::InvalidateGPUCache() {
596 gpu.InvalidateGPUCache(); 597 gpu.InvalidateGPUCache();
597} 598}
598 599
599void RasterizerOpenGL::UnmapMemory(VAddr addr, u64 size) { 600void RasterizerOpenGL::UnmapMemory(DAddr addr, u64 size) {
600 { 601 {
601 std::scoped_lock lock{texture_cache.mutex}; 602 std::scoped_lock lock{texture_cache.mutex};
602 texture_cache.UnmapMemory(addr, size); 603 texture_cache.UnmapMemory(addr, size);
@@ -635,7 +636,7 @@ void RasterizerOpenGL::ReleaseFences(bool force) {
635 fence_manager.WaitPendingFences(force); 636 fence_manager.WaitPendingFences(force);
636} 637}
637 638
638void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size, 639void RasterizerOpenGL::FlushAndInvalidateRegion(DAddr addr, u64 size,
639 VideoCommon::CacheType which) { 640 VideoCommon::CacheType which) {
640 if (Settings::IsGPULevelExtreme()) { 641 if (Settings::IsGPULevelExtreme()) {
641 FlushRegion(addr, size, which); 642 FlushRegion(addr, size, which);
@@ -739,7 +740,7 @@ void RasterizerOpenGL::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si
739} 740}
740 741
741bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, 742bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
742 VAddr framebuffer_addr, u32 pixel_stride) { 743 DAddr framebuffer_addr, u32 pixel_stride) {
743 if (framebuffer_addr == 0) { 744 if (framebuffer_addr == 0) {
744 return false; 745 return false;
745 } 746 }
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index ce3460938..34aa73526 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -14,7 +14,6 @@
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "video_core/control/channel_state_cache.h" 15#include "video_core/control/channel_state_cache.h"
16#include "video_core/engines/maxwell_dma.h" 16#include "video_core/engines/maxwell_dma.h"
17#include "video_core/rasterizer_accelerated.h"
18#include "video_core/rasterizer_interface.h" 17#include "video_core/rasterizer_interface.h"
19#include "video_core/renderer_opengl/blit_image.h" 18#include "video_core/renderer_opengl/blit_image.h"
20#include "video_core/renderer_opengl/gl_buffer_cache.h" 19#include "video_core/renderer_opengl/gl_buffer_cache.h"
@@ -72,13 +71,13 @@ private:
72 TextureCache& texture_cache; 71 TextureCache& texture_cache;
73}; 72};
74 73
75class RasterizerOpenGL : public VideoCore::RasterizerAccelerated, 74class RasterizerOpenGL : public VideoCore::RasterizerInterface,
76 protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { 75 protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
77public: 76public:
78 explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 77 explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
79 Core::Memory::Memory& cpu_memory_, const Device& device_, 78 Tegra::MaxwellDeviceMemoryManager& device_memory_,
80 ScreenInfo& screen_info_, ProgramManager& program_manager_, 79 const Device& device_, ScreenInfo& screen_info_,
81 StateTracker& state_tracker_); 80 ProgramManager& program_manager_, StateTracker& state_tracker_);
82 ~RasterizerOpenGL() override; 81 ~RasterizerOpenGL() override;
83 82
84 void Draw(bool is_indexed, u32 instance_count) override; 83 void Draw(bool is_indexed, u32 instance_count) override;
@@ -92,17 +91,17 @@ public:
92 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override; 91 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
93 void DisableGraphicsUniformBuffer(size_t stage, u32 index) override; 92 void DisableGraphicsUniformBuffer(size_t stage, u32 index) override;
94 void FlushAll() override; 93 void FlushAll() override;
95 void FlushRegion(VAddr addr, u64 size, 94 void FlushRegion(DAddr addr, u64 size,
96 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 95 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
97 bool MustFlushRegion(VAddr addr, u64 size, 96 bool MustFlushRegion(DAddr addr, u64 size,
98 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 97 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
99 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override; 98 VideoCore::RasterizerDownloadArea GetFlushArea(PAddr addr, u64 size) override;
100 void InvalidateRegion(VAddr addr, u64 size, 99 void InvalidateRegion(DAddr addr, u64 size,
101 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 100 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
102 void OnCacheInvalidation(VAddr addr, u64 size) override; 101 void OnCacheInvalidation(PAddr addr, u64 size) override;
103 bool OnCPUWrite(VAddr addr, u64 size) override; 102 bool OnCPUWrite(PAddr addr, u64 size) override;
104 void InvalidateGPUCache() override; 103 void InvalidateGPUCache() override;
105 void UnmapMemory(VAddr addr, u64 size) override; 104 void UnmapMemory(DAddr addr, u64 size) override;
106 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; 105 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
107 void SignalFence(std::function<void()>&& func) override; 106 void SignalFence(std::function<void()>&& func) override;
108 void SyncOperation(std::function<void()>&& func) override; 107 void SyncOperation(std::function<void()>&& func) override;
@@ -110,7 +109,7 @@ public:
110 void SignalReference() override; 109 void SignalReference() override;
111 void ReleaseFences(bool force = true) override; 110 void ReleaseFences(bool force = true) override;
112 void FlushAndInvalidateRegion( 111 void FlushAndInvalidateRegion(
113 VAddr addr, u64 size, VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 112 DAddr addr, u64 size, VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
114 void WaitForIdle() override; 113 void WaitForIdle() override;
115 void FragmentBarrier() override; 114 void FragmentBarrier() override;
116 void TiledCacheBarrier() override; 115 void TiledCacheBarrier() override;
@@ -123,7 +122,7 @@ public:
123 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; 122 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
124 void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, 123 void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
125 std::span<const u8> memory) override; 124 std::span<const u8> memory) override;
126 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 125 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr,
127 u32 pixel_stride) override; 126 u32 pixel_stride) override;
128 void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 127 void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
129 const VideoCore::DiskResourceLoadCallback& callback) override; 128 const VideoCore::DiskResourceLoadCallback& callback) override;
@@ -235,6 +234,7 @@ private:
235 VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport); 234 VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport);
236 235
237 Tegra::GPU& gpu; 236 Tegra::GPU& gpu;
237 Tegra::MaxwellDeviceMemoryManager& device_memory;
238 238
239 const Device& device; 239 const Device& device;
240 ScreenInfo& screen_info; 240 ScreenInfo& screen_info;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 30df41b7d..50462cdde 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -168,11 +168,12 @@ void SetXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& regs
168} 168}
169} // Anonymous namespace 169} // Anonymous namespace
170 170
171ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindow& emu_window_, 171ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
172 const Device& device_, TextureCache& texture_cache_, 172 Core::Frontend::EmuWindow& emu_window_, const Device& device_,
173 BufferCache& buffer_cache_, ProgramManager& program_manager_, 173 TextureCache& texture_cache_, BufferCache& buffer_cache_,
174 StateTracker& state_tracker_, VideoCore::ShaderNotify& shader_notify_) 174 ProgramManager& program_manager_, StateTracker& state_tracker_,
175 : VideoCommon::ShaderCache{rasterizer_}, emu_window{emu_window_}, device{device_}, 175 VideoCore::ShaderNotify& shader_notify_)
176 : VideoCommon::ShaderCache{device_memory_}, emu_window{emu_window_}, device{device_},
176 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_}, 177 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_},
177 state_tracker{state_tracker_}, shader_notify{shader_notify_}, 178 state_tracker{state_tracker_}, shader_notify{shader_notify_},
178 use_asynchronous_shaders{device.UseAsynchronousShaders()}, 179 use_asynchronous_shaders{device.UseAsynchronousShaders()},
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 6b9732fca..5ac413529 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -17,7 +17,7 @@
17 17
18namespace Tegra { 18namespace Tegra {
19class MemoryManager; 19class MemoryManager;
20} 20} // namespace Tegra
21 21
22namespace OpenGL { 22namespace OpenGL {
23 23
@@ -28,10 +28,11 @@ using ShaderWorker = Common::StatefulThreadWorker<ShaderContext::Context>;
28 28
29class ShaderCache : public VideoCommon::ShaderCache { 29class ShaderCache : public VideoCommon::ShaderCache {
30public: 30public:
31 explicit ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindow& emu_window_, 31 explicit ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
32 const Device& device_, TextureCache& texture_cache_, 32 Core::Frontend::EmuWindow& emu_window_, const Device& device_,
33 BufferCache& buffer_cache_, ProgramManager& program_manager_, 33 TextureCache& texture_cache_, BufferCache& buffer_cache_,
34 StateTracker& state_tracker_, VideoCore::ShaderNotify& shader_notify_); 34 ProgramManager& program_manager_, StateTracker& state_tracker_,
35 VideoCore::ShaderNotify& shader_notify_);
35 ~ShaderCache(); 36 ~ShaderCache();
36 37
37 void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 38 void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 2933718b6..b75376fdb 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -15,7 +15,6 @@
15#include "common/telemetry.h" 15#include "common/telemetry.h"
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/frontend/emu_window.h" 17#include "core/frontend/emu_window.h"
18#include "core/memory.h"
19#include "core/telemetry_session.h" 18#include "core/telemetry_session.h"
20#include "video_core/host_shaders/ffx_a_h.h" 19#include "video_core/host_shaders/ffx_a_h.h"
21#include "video_core/host_shaders/ffx_fsr1_h.h" 20#include "video_core/host_shaders/ffx_fsr1_h.h"
@@ -144,12 +143,13 @@ void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severit
144 143
145RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, 144RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
146 Core::Frontend::EmuWindow& emu_window_, 145 Core::Frontend::EmuWindow& emu_window_,
147 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, 146 Tegra::MaxwellDeviceMemoryManager& device_memory_, Tegra::GPU& gpu_,
148 std::unique_ptr<Core::Frontend::GraphicsContext> context_) 147 std::unique_ptr<Core::Frontend::GraphicsContext> context_)
149 : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_}, 148 : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_},
150 emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, device{emu_window_}, 149 emu_window{emu_window_}, device_memory{device_memory_}, gpu{gpu_}, device{emu_window_},
151 state_tracker{}, program_manager{device}, 150 state_tracker{}, program_manager{device},
152 rasterizer(emu_window, gpu, cpu_memory, device, screen_info, program_manager, state_tracker) { 151 rasterizer(emu_window, gpu, device_memory, device, screen_info, program_manager,
152 state_tracker) {
153 if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) { 153 if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) {
154 glEnable(GL_DEBUG_OUTPUT); 154 glEnable(GL_DEBUG_OUTPUT);
155 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 155 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
@@ -242,7 +242,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
242 const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; 242 const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)};
243 const u64 size_in_bytes{Tegra::Texture::CalculateSize( 243 const u64 size_in_bytes{Tegra::Texture::CalculateSize(
244 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; 244 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
245 const u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)}; 245 const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)};
246 const std::span<const u8> input_data(host_ptr, size_in_bytes); 246 const std::span<const u8> input_data(host_ptr, size_in_bytes);
247 Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, 247 Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
248 framebuffer.width, framebuffer.height, 1, block_height_log2, 248 framebuffer.width, framebuffer.height, 1, block_height_log2,
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index b70607635..18699610a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -61,7 +61,7 @@ class RendererOpenGL final : public VideoCore::RendererBase {
61public: 61public:
62 explicit RendererOpenGL(Core::TelemetrySession& telemetry_session_, 62 explicit RendererOpenGL(Core::TelemetrySession& telemetry_session_,
63 Core::Frontend::EmuWindow& emu_window_, 63 Core::Frontend::EmuWindow& emu_window_,
64 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, 64 Tegra::MaxwellDeviceMemoryManager& device_memory_, Tegra::GPU& gpu_,
65 std::unique_ptr<Core::Frontend::GraphicsContext> context_); 65 std::unique_ptr<Core::Frontend::GraphicsContext> context_);
66 ~RendererOpenGL() override; 66 ~RendererOpenGL() override;
67 67
@@ -101,7 +101,7 @@ private:
101 101
102 Core::TelemetrySession& telemetry_session; 102 Core::TelemetrySession& telemetry_session;
103 Core::Frontend::EmuWindow& emu_window; 103 Core::Frontend::EmuWindow& emu_window;
104 Core::Memory::Memory& cpu_memory; 104 Tegra::MaxwellDeviceMemoryManager& device_memory;
105 Tegra::GPU& gpu; 105 Tegra::GPU& gpu;
106 106
107 Device device; 107 Device device;
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h
index 71c783709..850c34a3a 100644
--- a/src/video_core/renderer_vulkan/pipeline_helper.h
+++ b/src/video_core/renderer_vulkan/pipeline_helper.h
@@ -12,7 +12,6 @@
12#include "shader_recompiler/shader_info.h" 12#include "shader_recompiler/shader_info.h"
13#include "video_core/renderer_vulkan/vk_texture_cache.h" 13#include "video_core/renderer_vulkan/vk_texture_cache.h"
14#include "video_core/renderer_vulkan/vk_update_descriptor.h" 14#include "video_core/renderer_vulkan/vk_update_descriptor.h"
15#include "video_core/texture_cache/texture_cache.h"
16#include "video_core/texture_cache/types.h" 15#include "video_core/texture_cache/types.h"
17#include "video_core/vulkan_common/vulkan_device.h" 16#include "video_core/vulkan_common/vulkan_device.h"
18 17
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 100b70918..1631276c6 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -82,10 +82,10 @@ Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dl
82 82
83RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, 83RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
84 Core::Frontend::EmuWindow& emu_window, 84 Core::Frontend::EmuWindow& emu_window,
85 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, 85 Tegra::MaxwellDeviceMemoryManager& device_memory_, Tegra::GPU& gpu_,
86 std::unique_ptr<Core::Frontend::GraphicsContext> context_) try 86 std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
87 : RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_), 87 : RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_),
88 cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())), 88 device_memory(device_memory_), gpu(gpu_), library(OpenLibrary(context.get())),
89 instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, 89 instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
90 Settings::values.renderer_debug.GetValue())), 90 Settings::values.renderer_debug.GetValue())),
91 debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance) 91 debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance)
@@ -97,9 +97,9 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
97 render_window.GetFramebufferLayout().height), 97 render_window.GetFramebufferLayout().height),
98 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, 98 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
99 surface), 99 surface),
100 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager, 100 blit_screen(device_memory, render_window, device, memory_allocator, swapchain,
101 scheduler, screen_info), 101 present_manager, scheduler, screen_info),
102 rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator, 102 rasterizer(render_window, gpu, device_memory, screen_info, device, memory_allocator,
103 state_tracker, scheduler) { 103 state_tracker, scheduler) {
104 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { 104 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
105 turbo_mode.emplace(instance, dld); 105 turbo_mode.emplace(instance, dld);
@@ -128,7 +128,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
128 screen_info.width = framebuffer->width; 128 screen_info.width = framebuffer->width;
129 screen_info.height = framebuffer->height; 129 screen_info.height = framebuffer->height;
130 130
131 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; 131 const DAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
132 const bool use_accelerated = 132 const bool use_accelerated =
133 rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); 133 rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
134 RenderScreenshot(*framebuffer, use_accelerated); 134 RenderScreenshot(*framebuffer, use_accelerated);
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 14e257cf7..11c52287a 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -7,12 +7,12 @@
7#include <string> 7#include <string>
8#include <variant> 8#include <variant>
9 9
10#include "video_core/renderer_vulkan/vk_rasterizer.h"
11
12#include "common/dynamic_library.h" 10#include "common/dynamic_library.h"
11#include "video_core/host1x/gpu_device_memory_manager.h"
13#include "video_core/renderer_base.h" 12#include "video_core/renderer_base.h"
14#include "video_core/renderer_vulkan/vk_blit_screen.h" 13#include "video_core/renderer_vulkan/vk_blit_screen.h"
15#include "video_core/renderer_vulkan/vk_present_manager.h" 14#include "video_core/renderer_vulkan/vk_present_manager.h"
15#include "video_core/renderer_vulkan/vk_rasterizer.h"
16#include "video_core/renderer_vulkan/vk_scheduler.h" 16#include "video_core/renderer_vulkan/vk_scheduler.h"
17#include "video_core/renderer_vulkan/vk_state_tracker.h" 17#include "video_core/renderer_vulkan/vk_state_tracker.h"
18#include "video_core/renderer_vulkan/vk_swapchain.h" 18#include "video_core/renderer_vulkan/vk_swapchain.h"
@@ -42,7 +42,7 @@ class RendererVulkan final : public VideoCore::RendererBase {
42public: 42public:
43 explicit RendererVulkan(Core::TelemetrySession& telemtry_session, 43 explicit RendererVulkan(Core::TelemetrySession& telemtry_session,
44 Core::Frontend::EmuWindow& emu_window, 44 Core::Frontend::EmuWindow& emu_window,
45 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, 45 Tegra::MaxwellDeviceMemoryManager& device_memory_, Tegra::GPU& gpu_,
46 std::unique_ptr<Core::Frontend::GraphicsContext> context_); 46 std::unique_ptr<Core::Frontend::GraphicsContext> context_);
47 ~RendererVulkan() override; 47 ~RendererVulkan() override;
48 48
@@ -62,7 +62,7 @@ private:
62 void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated); 62 void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated);
63 63
64 Core::TelemetrySession& telemetry_session; 64 Core::TelemetrySession& telemetry_session;
65 Core::Memory::Memory& cpu_memory; 65 Tegra::MaxwellDeviceMemoryManager& device_memory;
66 Tegra::GPU& gpu; 66 Tegra::GPU& gpu;
67 67
68 std::shared_ptr<Common::DynamicLibrary> library; 68 std::shared_ptr<Common::DynamicLibrary> library;
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 60432f5ad..610f27c84 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -14,8 +14,8 @@
14#include "common/settings.h" 14#include "common/settings.h"
15#include "core/core.h" 15#include "core/core.h"
16#include "core/frontend/emu_window.h" 16#include "core/frontend/emu_window.h"
17#include "core/memory.h"
18#include "video_core/gpu.h" 17#include "video_core/gpu.h"
18#include "video_core/host1x/gpu_device_memory_manager.h"
19#include "video_core/host_shaders/fxaa_frag_spv.h" 19#include "video_core/host_shaders/fxaa_frag_spv.h"
20#include "video_core/host_shaders/fxaa_vert_spv.h" 20#include "video_core/host_shaders/fxaa_vert_spv.h"
21#include "video_core/host_shaders/present_bicubic_frag_spv.h" 21#include "video_core/host_shaders/present_bicubic_frag_spv.h"
@@ -121,11 +121,12 @@ struct BlitScreen::BufferData {
121 // Unaligned image data goes here 121 // Unaligned image data goes here
122}; 122};
123 123
124BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_, 124BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_,
125 const Device& device_, MemoryAllocator& memory_allocator_, 125 Core::Frontend::EmuWindow& render_window_, const Device& device_,
126 Swapchain& swapchain_, PresentManager& present_manager_, 126 MemoryAllocator& memory_allocator_, Swapchain& swapchain_,
127 Scheduler& scheduler_, const ScreenInfo& screen_info_) 127 PresentManager& present_manager_, Scheduler& scheduler_,
128 : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_}, 128 const ScreenInfo& screen_info_)
129 : device_memory{device_memory_}, render_window{render_window_}, device{device_},
129 memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, 130 memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_},
130 scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { 131 scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} {
131 resource_ticks.resize(image_count); 132 resource_ticks.resize(image_count);
@@ -219,8 +220,8 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
219 if (!use_accelerated) { 220 if (!use_accelerated) {
220 const u64 image_offset = GetRawImageOffset(framebuffer); 221 const u64 image_offset = GetRawImageOffset(framebuffer);
221 222
222 const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset; 223 const DAddr framebuffer_addr = framebuffer.address + framebuffer.offset;
223 const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr); 224 const u8* const host_ptr = device_memory.GetPointer<u8>(framebuffer_addr);
224 225
225 // TODO(Rodrigo): Read this from HLE 226 // TODO(Rodrigo): Read this from HLE
226 constexpr u32 block_height_log2 = 4; 227 constexpr u32 block_height_log2 = 4;
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 78b32416d..3eff76009 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -6,6 +6,7 @@
6#include <memory> 6#include <memory>
7 7
8#include "core/frontend/framebuffer_layout.h" 8#include "core/frontend/framebuffer_layout.h"
9#include "video_core/host1x/gpu_device_memory_manager.h"
9#include "video_core/vulkan_common/vulkan_memory_allocator.h" 10#include "video_core/vulkan_common/vulkan_memory_allocator.h"
10#include "video_core/vulkan_common/vulkan_wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
11 12
@@ -13,10 +14,6 @@ namespace Core {
13class System; 14class System;
14} 15}
15 16
16namespace Core::Memory {
17class Memory;
18}
19
20namespace Core::Frontend { 17namespace Core::Frontend {
21class EmuWindow; 18class EmuWindow;
22} 19}
@@ -56,8 +53,9 @@ struct ScreenInfo {
56 53
57class BlitScreen { 54class BlitScreen {
58public: 55public:
59 explicit BlitScreen(Core::Memory::Memory& cpu_memory, Core::Frontend::EmuWindow& render_window, 56 explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory,
60 const Device& device, MemoryAllocator& memory_manager, Swapchain& swapchain, 57 Core::Frontend::EmuWindow& render_window, const Device& device,
58 MemoryAllocator& memory_manager, Swapchain& swapchain,
61 PresentManager& present_manager, Scheduler& scheduler, 59 PresentManager& present_manager, Scheduler& scheduler,
62 const ScreenInfo& screen_info); 60 const ScreenInfo& screen_info);
63 ~BlitScreen(); 61 ~BlitScreen();
@@ -109,7 +107,7 @@ private:
109 u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; 107 u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const;
110 u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const; 108 u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const;
111 109
112 Core::Memory::Memory& cpu_memory; 110 Tegra::MaxwellDeviceMemoryManager& device_memory;
113 Core::Frontend::EmuWindow& render_window; 111 Core::Frontend::EmuWindow& render_window;
114 const Device& device; 112 const Device& device;
115 MemoryAllocator& memory_allocator; 113 MemoryAllocator& memory_allocator;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 3c61799fa..31001d142 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -79,7 +79,7 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo
79} // Anonymous namespace 79} // Anonymous namespace
80 80
81Buffer::Buffer(BufferCacheRuntime& runtime, VideoCommon::NullBufferParams null_params) 81Buffer::Buffer(BufferCacheRuntime& runtime, VideoCommon::NullBufferParams null_params)
82 : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params), tracker{4096} { 82 : VideoCommon::BufferBase(null_params), tracker{4096} {
83 if (runtime.device.HasNullDescriptor()) { 83 if (runtime.device.HasNullDescriptor()) {
84 return; 84 return;
85 } 85 }
@@ -88,11 +88,9 @@ Buffer::Buffer(BufferCacheRuntime& runtime, VideoCommon::NullBufferParams null_p
88 is_null = true; 88 is_null = true;
89} 89}
90 90
91Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, 91Buffer::Buffer(BufferCacheRuntime& runtime, DAddr cpu_addr_, u64 size_bytes_)
92 VAddr cpu_addr_, u64 size_bytes_) 92 : VideoCommon::BufferBase(cpu_addr_, size_bytes_), device{&runtime.device},
93 : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), 93 buffer{CreateBuffer(*device, runtime.memory_allocator, SizeBytes())}, tracker{SizeBytes()} {
94 device{&runtime.device}, buffer{CreateBuffer(*device, runtime.memory_allocator, SizeBytes())},
95 tracker{SizeBytes()} {
96 if (runtime.device.HasDebuggingToolAttached()) { 94 if (runtime.device.HasDebuggingToolAttached()) {
97 buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); 95 buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str());
98 } 96 }
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index dc300d7cb..e273f4988 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -23,11 +23,10 @@ struct HostVertexBinding;
23 23
24class BufferCacheRuntime; 24class BufferCacheRuntime;
25 25
26class Buffer : public VideoCommon::BufferBase<VideoCore::RasterizerInterface> { 26class Buffer : public VideoCommon::BufferBase {
27public: 27public:
28 explicit Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params); 28 explicit Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params);
29 explicit Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, 29 explicit Buffer(BufferCacheRuntime& runtime, VAddr cpu_addr_, u64 size_bytes_);
30 VAddr cpu_addr_, u64 size_bytes_);
31 30
32 [[nodiscard]] VkBufferView View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format); 31 [[nodiscard]] VkBufferView View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format);
33 32
@@ -173,7 +172,7 @@ struct BufferCacheParams {
173 using Runtime = Vulkan::BufferCacheRuntime; 172 using Runtime = Vulkan::BufferCacheRuntime;
174 using Buffer = Vulkan::Buffer; 173 using Buffer = Vulkan::Buffer;
175 using Async_Buffer = Vulkan::StagingBufferRef; 174 using Async_Buffer = Vulkan::StagingBufferRef;
176 using MemoryTracker = VideoCommon::MemoryTrackerBase<VideoCore::RasterizerInterface>; 175 using MemoryTracker = VideoCommon::MemoryTrackerBase<Tegra::MaxwellDeviceMemoryManager>;
177 176
178 static constexpr bool IS_OPENGL = false; 177 static constexpr bool IS_OPENGL = false;
179 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = false; 178 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = false;
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
index bd6696b07..4aada5a00 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
@@ -84,4 +84,4 @@ private:
84 std::vector<std::unique_ptr<DescriptorBank>> banks; 84 std::vector<std::unique_ptr<DescriptorBank>> banks;
85}; 85};
86 86
87} // namespace Vulkan \ No newline at end of file 87} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index f2fd2670f..ec6b3a4b0 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -19,6 +19,7 @@
19#include "video_core/renderer_vulkan/vk_texture_cache.h" 19#include "video_core/renderer_vulkan/vk_texture_cache.h"
20#include "video_core/renderer_vulkan/vk_update_descriptor.h" 20#include "video_core/renderer_vulkan/vk_update_descriptor.h"
21#include "video_core/shader_notify.h" 21#include "video_core/shader_notify.h"
22#include "video_core/texture_cache/texture_cache.h"
22#include "video_core/vulkan_common/vulkan_device.h" 23#include "video_core/vulkan_common/vulkan_device.h"
23 24
24#if defined(_MSC_VER) && defined(NDEBUG) 25#if defined(_MSC_VER) && defined(NDEBUG)
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index d1841198d..1e1821b10 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -30,7 +30,6 @@
30#include "video_core/renderer_vulkan/vk_compute_pipeline.h" 30#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
31#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 31#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
32#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 32#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
33#include "video_core/renderer_vulkan/vk_rasterizer.h"
34#include "video_core/renderer_vulkan/vk_scheduler.h" 33#include "video_core/renderer_vulkan/vk_scheduler.h"
35#include "video_core/renderer_vulkan/vk_shader_util.h" 34#include "video_core/renderer_vulkan/vk_shader_util.h"
36#include "video_core/renderer_vulkan/vk_update_descriptor.h" 35#include "video_core/renderer_vulkan/vk_update_descriptor.h"
@@ -299,12 +298,13 @@ bool GraphicsPipelineCacheKey::operator==(const GraphicsPipelineCacheKey& rhs) c
299 return std::memcmp(&rhs, this, Size()) == 0; 298 return std::memcmp(&rhs, this, Size()) == 0;
300} 299}
301 300
302PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device_, 301PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
303 Scheduler& scheduler_, DescriptorPool& descriptor_pool_, 302 const Device& device_, Scheduler& scheduler_,
303 DescriptorPool& descriptor_pool_,
304 GuestDescriptorQueue& guest_descriptor_queue_, 304 GuestDescriptorQueue& guest_descriptor_queue_,
305 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_, 305 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_,
306 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_) 306 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_)
307 : VideoCommon::ShaderCache{rasterizer_}, device{device_}, scheduler{scheduler_}, 307 : VideoCommon::ShaderCache{device_memory_}, device{device_}, scheduler{scheduler_},
308 descriptor_pool{descriptor_pool_}, guest_descriptor_queue{guest_descriptor_queue_}, 308 descriptor_pool{descriptor_pool_}, guest_descriptor_queue{guest_descriptor_queue_},
309 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_}, 309 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_},
310 texture_cache{texture_cache_}, shader_notify{shader_notify_}, 310 texture_cache{texture_cache_}, shader_notify{shader_notify_},
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index e323ea0fd..797700128 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -20,6 +20,7 @@
20#include "shader_recompiler/object_pool.h" 20#include "shader_recompiler/object_pool.h"
21#include "shader_recompiler/profile.h" 21#include "shader_recompiler/profile.h"
22#include "video_core/engines/maxwell_3d.h" 22#include "video_core/engines/maxwell_3d.h"
23#include "video_core/host1x/gpu_device_memory_manager.h"
23#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 24#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
24#include "video_core/renderer_vulkan/vk_buffer_cache.h" 25#include "video_core/renderer_vulkan/vk_buffer_cache.h"
25#include "video_core/renderer_vulkan/vk_compute_pipeline.h" 26#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
@@ -79,7 +80,6 @@ class ComputePipeline;
79class DescriptorPool; 80class DescriptorPool;
80class Device; 81class Device;
81class PipelineStatistics; 82class PipelineStatistics;
82class RasterizerVulkan;
83class RenderPassCache; 83class RenderPassCache;
84class Scheduler; 84class Scheduler;
85 85
@@ -99,8 +99,8 @@ struct ShaderPools {
99 99
100class PipelineCache : public VideoCommon::ShaderCache { 100class PipelineCache : public VideoCommon::ShaderCache {
101public: 101public:
102 explicit PipelineCache(RasterizerVulkan& rasterizer, const Device& device, Scheduler& scheduler, 102 explicit PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device,
103 DescriptorPool& descriptor_pool, 103 Scheduler& scheduler, DescriptorPool& descriptor_pool,
104 GuestDescriptorQueue& guest_descriptor_queue, 104 GuestDescriptorQueue& guest_descriptor_queue,
105 RenderPassCache& render_pass_cache, BufferCache& buffer_cache, 105 RenderPassCache& render_pass_cache, BufferCache& buffer_cache,
106 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_); 106 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_);
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index ad4caf688..7cbc9c73c 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -13,9 +13,10 @@
13 13
14#include "common/bit_util.h" 14#include "common/bit_util.h"
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/memory.h"
17#include "video_core/engines/draw_manager.h" 16#include "video_core/engines/draw_manager.h"
17#include "video_core/host1x/gpu_device_memory_manager.h"
18#include "video_core/query_cache/query_cache.h" 18#include "video_core/query_cache/query_cache.h"
19#include "video_core/rasterizer_interface.h"
19#include "video_core/renderer_vulkan/vk_buffer_cache.h" 20#include "video_core/renderer_vulkan/vk_buffer_cache.h"
20#include "video_core/renderer_vulkan/vk_compute_pass.h" 21#include "video_core/renderer_vulkan/vk_compute_pass.h"
21#include "video_core/renderer_vulkan/vk_query_cache.h" 22#include "video_core/renderer_vulkan/vk_query_cache.h"
@@ -102,7 +103,7 @@ private:
102using BaseStreamer = VideoCommon::SimpleStreamer<VideoCommon::HostQueryBase>; 103using BaseStreamer = VideoCommon::SimpleStreamer<VideoCommon::HostQueryBase>;
103 104
104struct HostSyncValues { 105struct HostSyncValues {
105 VAddr address; 106 DAddr address;
106 size_t size; 107 size_t size;
107 size_t offset; 108 size_t offset;
108 109
@@ -317,7 +318,7 @@ public:
317 pending_sync.clear(); 318 pending_sync.clear();
318 } 319 }
319 320
320 size_t WriteCounter(VAddr address, bool has_timestamp, u32 value, 321 size_t WriteCounter(DAddr address, bool has_timestamp, u32 value,
321 [[maybe_unused]] std::optional<u32> subreport) override { 322 [[maybe_unused]] std::optional<u32> subreport) override {
322 PauseCounter(); 323 PauseCounter();
323 auto index = BuildQuery(); 324 auto index = BuildQuery();
@@ -738,7 +739,7 @@ public:
738 pending_sync.clear(); 739 pending_sync.clear();
739 } 740 }
740 741
741 size_t WriteCounter(VAddr address, bool has_timestamp, u32 value, 742 size_t WriteCounter(DAddr address, bool has_timestamp, u32 value,
742 std::optional<u32> subreport_) override { 743 std::optional<u32> subreport_) override {
743 auto index = BuildQuery(); 744 auto index = BuildQuery();
744 auto* new_query = GetQuery(index); 745 auto* new_query = GetQuery(index);
@@ -769,9 +770,9 @@ public:
769 return index; 770 return index;
770 } 771 }
771 772
772 std::optional<std::pair<VAddr, size_t>> GetLastQueryStream(size_t stream) { 773 std::optional<std::pair<DAddr, size_t>> GetLastQueryStream(size_t stream) {
773 if (last_queries[stream] != 0) { 774 if (last_queries[stream] != 0) {
774 std::pair<VAddr, size_t> result(last_queries[stream], last_queries_stride[stream]); 775 std::pair<DAddr, size_t> result(last_queries[stream], last_queries_stride[stream]);
775 return result; 776 return result;
776 } 777 }
777 return std::nullopt; 778 return std::nullopt;
@@ -974,7 +975,7 @@ private:
974 size_t buffers_count{}; 975 size_t buffers_count{};
975 std::array<VkBuffer, NUM_STREAMS> counter_buffers{}; 976 std::array<VkBuffer, NUM_STREAMS> counter_buffers{};
976 std::array<VkDeviceSize, NUM_STREAMS> offsets{}; 977 std::array<VkDeviceSize, NUM_STREAMS> offsets{};
977 std::array<VAddr, NUM_STREAMS> last_queries; 978 std::array<DAddr, NUM_STREAMS> last_queries;
978 std::array<size_t, NUM_STREAMS> last_queries_stride; 979 std::array<size_t, NUM_STREAMS> last_queries_stride;
979 Maxwell3D::Regs::PrimitiveTopology out_topology; 980 Maxwell3D::Regs::PrimitiveTopology out_topology;
980 u64 streams_mask; 981 u64 streams_mask;
@@ -987,7 +988,7 @@ public:
987 : VideoCommon::QueryBase(0, VideoCommon::QueryFlagBits::IsHostManaged, 0) {} 988 : VideoCommon::QueryBase(0, VideoCommon::QueryFlagBits::IsHostManaged, 0) {}
988 989
989 // Parameterized constructor 990 // Parameterized constructor
990 PrimitivesQueryBase(bool has_timestamp, VAddr address) 991 PrimitivesQueryBase(bool has_timestamp, DAddr address)
991 : VideoCommon::QueryBase(address, VideoCommon::QueryFlagBits::IsHostManaged, 0) { 992 : VideoCommon::QueryBase(address, VideoCommon::QueryFlagBits::IsHostManaged, 0) {
992 if (has_timestamp) { 993 if (has_timestamp) {
993 flags |= VideoCommon::QueryFlagBits::HasTimestamp; 994 flags |= VideoCommon::QueryFlagBits::HasTimestamp;
@@ -995,7 +996,7 @@ public:
995 } 996 }
996 997
997 u64 stride{}; 998 u64 stride{};
998 VAddr dependant_address{}; 999 DAddr dependant_address{};
999 Maxwell3D::Regs::PrimitiveTopology topology{Maxwell3D::Regs::PrimitiveTopology::Points}; 1000 Maxwell3D::Regs::PrimitiveTopology topology{Maxwell3D::Regs::PrimitiveTopology::Points};
1000 size_t dependant_index{}; 1001 size_t dependant_index{};
1001 bool dependant_manage{}; 1002 bool dependant_manage{};
@@ -1005,15 +1006,15 @@ class PrimitivesSucceededStreamer : public VideoCommon::SimpleStreamer<Primitive
1005public: 1006public:
1006 explicit PrimitivesSucceededStreamer(size_t id_, QueryCacheRuntime& runtime_, 1007 explicit PrimitivesSucceededStreamer(size_t id_, QueryCacheRuntime& runtime_,
1007 TFBCounterStreamer& tfb_streamer_, 1008 TFBCounterStreamer& tfb_streamer_,
1008 Core::Memory::Memory& cpu_memory_) 1009 Tegra::MaxwellDeviceMemoryManager& device_memory_)
1009 : VideoCommon::SimpleStreamer<PrimitivesQueryBase>(id_), runtime{runtime_}, 1010 : VideoCommon::SimpleStreamer<PrimitivesQueryBase>(id_), runtime{runtime_},
1010 tfb_streamer{tfb_streamer_}, cpu_memory{cpu_memory_} { 1011 tfb_streamer{tfb_streamer_}, device_memory{device_memory_} {
1011 MakeDependent(&tfb_streamer); 1012 MakeDependent(&tfb_streamer);
1012 } 1013 }
1013 1014
1014 ~PrimitivesSucceededStreamer() = default; 1015 ~PrimitivesSucceededStreamer() = default;
1015 1016
1016 size_t WriteCounter(VAddr address, bool has_timestamp, u32 value, 1017 size_t WriteCounter(DAddr address, bool has_timestamp, u32 value,
1017 std::optional<u32> subreport_) override { 1018 std::optional<u32> subreport_) override {
1018 auto index = BuildQuery(); 1019 auto index = BuildQuery();
1019 auto* new_query = GetQuery(index); 1020 auto* new_query = GetQuery(index);
@@ -1063,6 +1064,8 @@ public:
1063 } 1064 }
1064 }); 1065 });
1065 } 1066 }
1067 auto* ptr = device_memory.GetPointer<u8>(new_query->dependant_address);
1068 ASSERT(ptr != nullptr);
1066 1069
1067 new_query->dependant_manage = must_manage_dependance; 1070 new_query->dependant_manage = must_manage_dependance;
1068 pending_flush_queries.push_back(index); 1071 pending_flush_queries.push_back(index);
@@ -1100,7 +1103,7 @@ public:
1100 num_vertices = dependant_query->value / query->stride; 1103 num_vertices = dependant_query->value / query->stride;
1101 tfb_streamer.Free(query->dependant_index); 1104 tfb_streamer.Free(query->dependant_index);
1102 } else { 1105 } else {
1103 u8* pointer = cpu_memory.GetPointer(query->dependant_address); 1106 u8* pointer = device_memory.GetPointer<u8>(query->dependant_address);
1104 u32 result; 1107 u32 result;
1105 std::memcpy(&result, pointer, sizeof(u32)); 1108 std::memcpy(&result, pointer, sizeof(u32));
1106 num_vertices = static_cast<u64>(result) / query->stride; 1109 num_vertices = static_cast<u64>(result) / query->stride;
@@ -1137,7 +1140,7 @@ public:
1137private: 1140private:
1138 QueryCacheRuntime& runtime; 1141 QueryCacheRuntime& runtime;
1139 TFBCounterStreamer& tfb_streamer; 1142 TFBCounterStreamer& tfb_streamer;
1140 Core::Memory::Memory& cpu_memory; 1143 Tegra::MaxwellDeviceMemoryManager& device_memory;
1141 1144
1142 // syncing queue 1145 // syncing queue
1143 std::vector<size_t> pending_sync; 1146 std::vector<size_t> pending_sync;
@@ -1152,12 +1155,13 @@ private:
1152 1155
1153struct QueryCacheRuntimeImpl { 1156struct QueryCacheRuntimeImpl {
1154 QueryCacheRuntimeImpl(QueryCacheRuntime& runtime, VideoCore::RasterizerInterface* rasterizer_, 1157 QueryCacheRuntimeImpl(QueryCacheRuntime& runtime, VideoCore::RasterizerInterface* rasterizer_,
1155 Core::Memory::Memory& cpu_memory_, Vulkan::BufferCache& buffer_cache_, 1158 Tegra::MaxwellDeviceMemoryManager& device_memory_,
1156 const Device& device_, const MemoryAllocator& memory_allocator_, 1159 Vulkan::BufferCache& buffer_cache_, const Device& device_,
1157 Scheduler& scheduler_, StagingBufferPool& staging_pool_, 1160 const MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
1161 StagingBufferPool& staging_pool_,
1158 ComputePassDescriptorQueue& compute_pass_descriptor_queue, 1162 ComputePassDescriptorQueue& compute_pass_descriptor_queue,
1159 DescriptorPool& descriptor_pool) 1163 DescriptorPool& descriptor_pool)
1160 : rasterizer{rasterizer_}, cpu_memory{cpu_memory_}, 1164 : rasterizer{rasterizer_}, device_memory{device_memory_},
1161 buffer_cache{buffer_cache_}, device{device_}, 1165 buffer_cache{buffer_cache_}, device{device_},
1162 memory_allocator{memory_allocator_}, scheduler{scheduler_}, staging_pool{staging_pool_}, 1166 memory_allocator{memory_allocator_}, scheduler{scheduler_}, staging_pool{staging_pool_},
1163 guest_streamer(0, runtime), 1167 guest_streamer(0, runtime),
@@ -1168,7 +1172,7 @@ struct QueryCacheRuntimeImpl {
1168 scheduler, memory_allocator, staging_pool), 1172 scheduler, memory_allocator, staging_pool),
1169 primitives_succeeded_streamer( 1173 primitives_succeeded_streamer(
1170 static_cast<size_t>(QueryType::StreamingPrimitivesSucceeded), runtime, tfb_streamer, 1174 static_cast<size_t>(QueryType::StreamingPrimitivesSucceeded), runtime, tfb_streamer,
1171 cpu_memory_), 1175 device_memory_),
1172 primitives_needed_minus_succeeded_streamer( 1176 primitives_needed_minus_succeeded_streamer(
1173 static_cast<size_t>(QueryType::StreamingPrimitivesNeededMinusSucceeded), runtime, 0u), 1177 static_cast<size_t>(QueryType::StreamingPrimitivesNeededMinusSucceeded), runtime, 0u),
1174 hcr_setup{}, hcr_is_set{}, is_hcr_running{}, maxwell3d{} { 1178 hcr_setup{}, hcr_is_set{}, is_hcr_running{}, maxwell3d{} {
@@ -1195,7 +1199,7 @@ struct QueryCacheRuntimeImpl {
1195 } 1199 }
1196 1200
1197 VideoCore::RasterizerInterface* rasterizer; 1201 VideoCore::RasterizerInterface* rasterizer;
1198 Core::Memory::Memory& cpu_memory; 1202 Tegra::MaxwellDeviceMemoryManager& device_memory;
1199 Vulkan::BufferCache& buffer_cache; 1203 Vulkan::BufferCache& buffer_cache;
1200 1204
1201 const Device& device; 1205 const Device& device;
@@ -1210,7 +1214,7 @@ struct QueryCacheRuntimeImpl {
1210 PrimitivesSucceededStreamer primitives_succeeded_streamer; 1214 PrimitivesSucceededStreamer primitives_succeeded_streamer;
1211 VideoCommon::StubStreamer<QueryCacheParams> primitives_needed_minus_succeeded_streamer; 1215 VideoCommon::StubStreamer<QueryCacheParams> primitives_needed_minus_succeeded_streamer;
1212 1216
1213 std::vector<std::pair<VAddr, VAddr>> little_cache; 1217 std::vector<std::pair<DAddr, DAddr>> little_cache;
1214 std::vector<std::pair<VkBuffer, VkDeviceSize>> buffers_to_upload_to; 1218 std::vector<std::pair<VkBuffer, VkDeviceSize>> buffers_to_upload_to;
1215 std::vector<size_t> redirect_cache; 1219 std::vector<size_t> redirect_cache;
1216 std::vector<std::vector<VkBufferCopy>> copies_setup; 1220 std::vector<std::vector<VkBufferCopy>> copies_setup;
@@ -1229,14 +1233,14 @@ struct QueryCacheRuntimeImpl {
1229}; 1233};
1230 1234
1231QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer, 1235QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer,
1232 Core::Memory::Memory& cpu_memory_, 1236 Tegra::MaxwellDeviceMemoryManager& device_memory_,
1233 Vulkan::BufferCache& buffer_cache_, const Device& device_, 1237 Vulkan::BufferCache& buffer_cache_, const Device& device_,
1234 const MemoryAllocator& memory_allocator_, 1238 const MemoryAllocator& memory_allocator_,
1235 Scheduler& scheduler_, StagingBufferPool& staging_pool_, 1239 Scheduler& scheduler_, StagingBufferPool& staging_pool_,
1236 ComputePassDescriptorQueue& compute_pass_descriptor_queue, 1240 ComputePassDescriptorQueue& compute_pass_descriptor_queue,
1237 DescriptorPool& descriptor_pool) { 1241 DescriptorPool& descriptor_pool) {
1238 impl = std::make_unique<QueryCacheRuntimeImpl>( 1242 impl = std::make_unique<QueryCacheRuntimeImpl>(
1239 *this, rasterizer, cpu_memory_, buffer_cache_, device_, memory_allocator_, scheduler_, 1243 *this, rasterizer, device_memory_, buffer_cache_, device_, memory_allocator_, scheduler_,
1240 staging_pool_, compute_pass_descriptor_queue, descriptor_pool); 1244 staging_pool_, compute_pass_descriptor_queue, descriptor_pool);
1241} 1245}
1242 1246
@@ -1309,7 +1313,7 @@ void QueryCacheRuntime::HostConditionalRenderingCompareValueImpl(VideoCommon::Lo
1309 ResumeHostConditionalRendering(); 1313 ResumeHostConditionalRendering();
1310} 1314}
1311 1315
1312void QueryCacheRuntime::HostConditionalRenderingCompareBCImpl(VAddr address, bool is_equal) { 1316void QueryCacheRuntime::HostConditionalRenderingCompareBCImpl(DAddr address, bool is_equal) {
1313 VkBuffer to_resolve; 1317 VkBuffer to_resolve;
1314 u32 to_resolve_offset; 1318 u32 to_resolve_offset;
1315 { 1319 {
@@ -1350,11 +1354,11 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
1350 return false; 1354 return false;
1351 } 1355 }
1352 1356
1353 const auto check_in_bc = [&](VAddr address) { 1357 const auto check_in_bc = [&](DAddr address) {
1354 return impl->buffer_cache.IsRegionGpuModified(address, 8); 1358 return impl->buffer_cache.IsRegionGpuModified(address, 8);
1355 }; 1359 };
1356 const auto check_value = [&](VAddr address) { 1360 const auto check_value = [&](DAddr address) {
1357 u8* ptr = impl->cpu_memory.GetPointer(address); 1361 u8* ptr = impl->device_memory.GetPointer<u8>(address);
1358 u64 value{}; 1362 u64 value{};
1359 std::memcpy(&value, ptr, sizeof(value)); 1363 std::memcpy(&value, ptr, sizeof(value));
1360 return value == 0; 1364 return value == 0;
@@ -1477,8 +1481,8 @@ void QueryCacheRuntime::SyncValues(std::span<SyncValuesType> values, VkBuffer ba
1477 for (auto& sync_val : values) { 1481 for (auto& sync_val : values) {
1478 total_size += sync_val.size; 1482 total_size += sync_val.size;
1479 bool found = false; 1483 bool found = false;
1480 VAddr base = Common::AlignDown(sync_val.address, Core::Memory::YUZU_PAGESIZE); 1484 DAddr base = Common::AlignDown(sync_val.address, Core::DEVICE_PAGESIZE);
1481 VAddr base_end = base + Core::Memory::YUZU_PAGESIZE; 1485 DAddr base_end = base + Core::DEVICE_PAGESIZE;
1482 for (size_t i = 0; i < impl->little_cache.size(); i++) { 1486 for (size_t i = 0; i < impl->little_cache.size(); i++) {
1483 const auto set_found = [&] { 1487 const auto set_found = [&] {
1484 impl->redirect_cache.push_back(i); 1488 impl->redirect_cache.push_back(i);
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h
index e9a1ea169..f6151123e 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.h
+++ b/src/video_core/renderer_vulkan/vk_query_cache.h
@@ -27,7 +27,7 @@ struct QueryCacheRuntimeImpl;
27class QueryCacheRuntime { 27class QueryCacheRuntime {
28public: 28public:
29 explicit QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer, 29 explicit QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer,
30 Core::Memory::Memory& cpu_memory_, 30 Tegra::MaxwellDeviceMemoryManager& device_memory_,
31 Vulkan::BufferCache& buffer_cache_, const Device& device_, 31 Vulkan::BufferCache& buffer_cache_, const Device& device_,
32 const MemoryAllocator& memory_allocator_, Scheduler& scheduler_, 32 const MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
33 StagingBufferPool& staging_pool_, 33 StagingBufferPool& staging_pool_,
@@ -61,7 +61,7 @@ public:
61 61
62private: 62private:
63 void HostConditionalRenderingCompareValueImpl(VideoCommon::LookupData object, bool is_equal); 63 void HostConditionalRenderingCompareValueImpl(VideoCommon::LookupData object, bool is_equal);
64 void HostConditionalRenderingCompareBCImpl(VAddr address, bool is_equal); 64 void HostConditionalRenderingCompareBCImpl(DAddr address, bool is_equal);
65 friend struct QueryCacheRuntimeImpl; 65 friend struct QueryCacheRuntimeImpl;
66 std::unique_ptr<QueryCacheRuntimeImpl> impl; 66 std::unique_ptr<QueryCacheRuntimeImpl> impl;
67}; 67};
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 241fc34be..5bf41b81f 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -18,6 +18,7 @@
18#include "video_core/engines/draw_manager.h" 18#include "video_core/engines/draw_manager.h"
19#include "video_core/engines/kepler_compute.h" 19#include "video_core/engines/kepler_compute.h"
20#include "video_core/engines/maxwell_3d.h" 20#include "video_core/engines/maxwell_3d.h"
21#include "video_core/host1x/gpu_device_memory_manager.h"
21#include "video_core/renderer_vulkan/blit_image.h" 22#include "video_core/renderer_vulkan/blit_image.h"
22#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 23#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
23#include "video_core/renderer_vulkan/maxwell_to_vk.h" 24#include "video_core/renderer_vulkan/maxwell_to_vk.h"
@@ -163,10 +164,11 @@ DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances,
163} // Anonymous namespace 164} // Anonymous namespace
164 165
165RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 166RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
166 Core::Memory::Memory& cpu_memory_, ScreenInfo& screen_info_, 167 Tegra::MaxwellDeviceMemoryManager& device_memory_,
167 const Device& device_, MemoryAllocator& memory_allocator_, 168 ScreenInfo& screen_info_, const Device& device_,
168 StateTracker& state_tracker_, Scheduler& scheduler_) 169 MemoryAllocator& memory_allocator_, StateTracker& state_tracker_,
169 : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, screen_info{screen_info_}, device{device_}, 170 Scheduler& scheduler_)
171 : gpu{gpu_}, device_memory{device_memory_}, screen_info{screen_info_}, device{device_},
170 memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, 172 memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_},
171 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), 173 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
172 guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler), 174 guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler),
@@ -174,14 +176,14 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
174 texture_cache_runtime{ 176 texture_cache_runtime{
175 device, scheduler, memory_allocator, staging_pool, 177 device, scheduler, memory_allocator, staging_pool,
176 blit_image, render_pass_cache, descriptor_pool, compute_pass_descriptor_queue}, 178 blit_image, render_pass_cache, descriptor_pool, compute_pass_descriptor_queue},
177 texture_cache(texture_cache_runtime, *this), 179 texture_cache(texture_cache_runtime, device_memory),
178 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool, 180 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
179 guest_descriptor_queue, compute_pass_descriptor_queue, descriptor_pool), 181 guest_descriptor_queue, compute_pass_descriptor_queue, descriptor_pool),
180 buffer_cache(*this, cpu_memory_, buffer_cache_runtime), 182 buffer_cache(device_memory, buffer_cache_runtime),
181 query_cache_runtime(this, cpu_memory_, buffer_cache, device, memory_allocator, scheduler, 183 query_cache_runtime(this, device_memory, buffer_cache, device, memory_allocator, scheduler,
182 staging_pool, compute_pass_descriptor_queue, descriptor_pool), 184 staging_pool, compute_pass_descriptor_queue, descriptor_pool),
183 query_cache(gpu, *this, cpu_memory_, query_cache_runtime), 185 query_cache(gpu, *this, device_memory, query_cache_runtime),
184 pipeline_cache(*this, device, scheduler, descriptor_pool, guest_descriptor_queue, 186 pipeline_cache(device_memory, device, scheduler, descriptor_pool, guest_descriptor_queue,
185 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), 187 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()),
186 accelerate_dma(buffer_cache, texture_cache, scheduler), 188 accelerate_dma(buffer_cache, texture_cache, scheduler),
187 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), 189 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
@@ -508,7 +510,7 @@ void Vulkan::RasterizerVulkan::DisableGraphicsUniformBuffer(size_t stage, u32 in
508 510
509void RasterizerVulkan::FlushAll() {} 511void RasterizerVulkan::FlushAll() {}
510 512
511void RasterizerVulkan::FlushRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 513void RasterizerVulkan::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
512 if (addr == 0 || size == 0) { 514 if (addr == 0 || size == 0) {
513 return; 515 return;
514 } 516 }
@@ -525,7 +527,7 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size, VideoCommon::CacheType
525 } 527 }
526} 528}
527 529
528bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 530bool RasterizerVulkan::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
529 if ((True(which & VideoCommon::CacheType::BufferCache))) { 531 if ((True(which & VideoCommon::CacheType::BufferCache))) {
530 std::scoped_lock lock{buffer_cache.mutex}; 532 std::scoped_lock lock{buffer_cache.mutex};
531 if (buffer_cache.IsRegionGpuModified(addr, size)) { 533 if (buffer_cache.IsRegionGpuModified(addr, size)) {
@@ -542,7 +544,7 @@ bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheT
542 return false; 544 return false;
543} 545}
544 546
545VideoCore::RasterizerDownloadArea RasterizerVulkan::GetFlushArea(VAddr addr, u64 size) { 547VideoCore::RasterizerDownloadArea RasterizerVulkan::GetFlushArea(DAddr addr, u64 size) {
546 { 548 {
547 std::scoped_lock lock{texture_cache.mutex}; 549 std::scoped_lock lock{texture_cache.mutex};
548 auto area = texture_cache.GetFlushArea(addr, size); 550 auto area = texture_cache.GetFlushArea(addr, size);
@@ -551,14 +553,14 @@ VideoCore::RasterizerDownloadArea RasterizerVulkan::GetFlushArea(VAddr addr, u64
551 } 553 }
552 } 554 }
553 VideoCore::RasterizerDownloadArea new_area{ 555 VideoCore::RasterizerDownloadArea new_area{
554 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE), 556 .start_address = Common::AlignDown(addr, Core::DEVICE_PAGESIZE),
555 .end_address = Common::AlignUp(addr + size, Core::Memory::YUZU_PAGESIZE), 557 .end_address = Common::AlignUp(addr + size, Core::DEVICE_PAGESIZE),
556 .preemtive = true, 558 .preemtive = true,
557 }; 559 };
558 return new_area; 560 return new_area;
559} 561}
560 562
561void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 563void RasterizerVulkan::InvalidateRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
562 if (addr == 0 || size == 0) { 564 if (addr == 0 || size == 0) {
563 return; 565 return;
564 } 566 }
@@ -578,7 +580,7 @@ void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size, VideoCommon::Cache
578 } 580 }
579} 581}
580 582
581void RasterizerVulkan::InnerInvalidation(std::span<const std::pair<VAddr, std::size_t>> sequences) { 583void RasterizerVulkan::InnerInvalidation(std::span<const std::pair<DAddr, std::size_t>> sequences) {
582 { 584 {
583 std::scoped_lock lock{texture_cache.mutex}; 585 std::scoped_lock lock{texture_cache.mutex};
584 for (const auto& [addr, size] : sequences) { 586 for (const auto& [addr, size] : sequences) {
@@ -599,7 +601,7 @@ void RasterizerVulkan::InnerInvalidation(std::span<const std::pair<VAddr, std::s
599 } 601 }
600} 602}
601 603
602bool RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) { 604bool RasterizerVulkan::OnCPUWrite(DAddr addr, u64 size) {
603 if (addr == 0 || size == 0) { 605 if (addr == 0 || size == 0) {
604 return false; 606 return false;
605 } 607 }
@@ -620,7 +622,7 @@ bool RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
620 return false; 622 return false;
621} 623}
622 624
623void RasterizerVulkan::OnCacheInvalidation(VAddr addr, u64 size) { 625void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) {
624 if (addr == 0 || size == 0) { 626 if (addr == 0 || size == 0) {
625 return; 627 return;
626 } 628 }
@@ -640,7 +642,7 @@ void RasterizerVulkan::InvalidateGPUCache() {
640 gpu.InvalidateGPUCache(); 642 gpu.InvalidateGPUCache();
641} 643}
642 644
643void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) { 645void RasterizerVulkan::UnmapMemory(DAddr addr, u64 size) {
644 { 646 {
645 std::scoped_lock lock{texture_cache.mutex}; 647 std::scoped_lock lock{texture_cache.mutex};
646 texture_cache.UnmapMemory(addr, size); 648 texture_cache.UnmapMemory(addr, size);
@@ -679,7 +681,7 @@ void RasterizerVulkan::ReleaseFences(bool force) {
679 fence_manager.WaitPendingFences(force); 681 fence_manager.WaitPendingFences(force);
680} 682}
681 683
682void RasterizerVulkan::FlushAndInvalidateRegion(VAddr addr, u64 size, 684void RasterizerVulkan::FlushAndInvalidateRegion(DAddr addr, u64 size,
683 VideoCommon::CacheType which) { 685 VideoCommon::CacheType which) {
684 if (Settings::IsGPULevelExtreme()) { 686 if (Settings::IsGPULevelExtreme()) {
685 FlushRegion(addr, size, which); 687 FlushRegion(addr, size, which);
@@ -782,7 +784,7 @@ void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si
782} 784}
783 785
784bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, 786bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
785 VAddr framebuffer_addr, u32 pixel_stride) { 787 DAddr framebuffer_addr, u32 pixel_stride) {
786 if (!framebuffer_addr) { 788 if (!framebuffer_addr) {
787 return false; 789 return false;
788 } 790 }
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index ad069556c..881ee0993 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -7,14 +7,13 @@
7 7
8#include <boost/container/static_vector.hpp> 8#include <boost/container/static_vector.hpp>
9 9
10#include "video_core/renderer_vulkan/vk_buffer_cache.h"
11
12#include "common/common_types.h" 10#include "common/common_types.h"
13#include "video_core/control/channel_state_cache.h" 11#include "video_core/control/channel_state_cache.h"
14#include "video_core/engines/maxwell_dma.h" 12#include "video_core/engines/maxwell_dma.h"
15#include "video_core/rasterizer_accelerated.h" 13#include "video_core/host1x/gpu_device_memory_manager.h"
16#include "video_core/rasterizer_interface.h" 14#include "video_core/rasterizer_interface.h"
17#include "video_core/renderer_vulkan/blit_image.h" 15#include "video_core/renderer_vulkan/blit_image.h"
16#include "video_core/renderer_vulkan/vk_buffer_cache.h"
18#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 17#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
19#include "video_core/renderer_vulkan/vk_fence_manager.h" 18#include "video_core/renderer_vulkan/vk_fence_manager.h"
20#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 19#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
@@ -34,10 +33,14 @@ namespace Core::Frontend {
34class EmuWindow; 33class EmuWindow;
35} 34}
36 35
37namespace Tegra::Engines { 36namespace Tegra {
37
38namespace Engines {
38class Maxwell3D; 39class Maxwell3D;
39} 40}
40 41
42} // namespace Tegra
43
41namespace Vulkan { 44namespace Vulkan {
42 45
43struct ScreenInfo; 46struct ScreenInfo;
@@ -70,13 +73,14 @@ private:
70 Scheduler& scheduler; 73 Scheduler& scheduler;
71}; 74};
72 75
73class RasterizerVulkan final : public VideoCore::RasterizerAccelerated, 76class RasterizerVulkan final : public VideoCore::RasterizerInterface,
74 protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { 77 protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
75public: 78public:
76 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 79 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
77 Core::Memory::Memory& cpu_memory_, ScreenInfo& screen_info_, 80 Tegra::MaxwellDeviceMemoryManager& device_memory_,
78 const Device& device_, MemoryAllocator& memory_allocator_, 81 ScreenInfo& screen_info_, const Device& device_,
79 StateTracker& state_tracker_, Scheduler& scheduler_); 82 MemoryAllocator& memory_allocator_, StateTracker& state_tracker_,
83 Scheduler& scheduler_);
80 ~RasterizerVulkan() override; 84 ~RasterizerVulkan() override;
81 85
82 void Draw(bool is_indexed, u32 instance_count) override; 86 void Draw(bool is_indexed, u32 instance_count) override;
@@ -90,18 +94,18 @@ public:
90 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override; 94 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
91 void DisableGraphicsUniformBuffer(size_t stage, u32 index) override; 95 void DisableGraphicsUniformBuffer(size_t stage, u32 index) override;
92 void FlushAll() override; 96 void FlushAll() override;
93 void FlushRegion(VAddr addr, u64 size, 97 void FlushRegion(DAddr addr, u64 size,
94 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 98 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
95 bool MustFlushRegion(VAddr addr, u64 size, 99 bool MustFlushRegion(DAddr addr, u64 size,
96 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 100 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
97 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override; 101 VideoCore::RasterizerDownloadArea GetFlushArea(DAddr addr, u64 size) override;
98 void InvalidateRegion(VAddr addr, u64 size, 102 void InvalidateRegion(DAddr addr, u64 size,
99 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 103 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
100 void InnerInvalidation(std::span<const std::pair<VAddr, std::size_t>> sequences) override; 104 void InnerInvalidation(std::span<const std::pair<DAddr, std::size_t>> sequences) override;
101 void OnCacheInvalidation(VAddr addr, u64 size) override; 105 void OnCacheInvalidation(DAddr addr, u64 size) override;
102 bool OnCPUWrite(VAddr addr, u64 size) override; 106 bool OnCPUWrite(DAddr addr, u64 size) override;
103 void InvalidateGPUCache() override; 107 void InvalidateGPUCache() override;
104 void UnmapMemory(VAddr addr, u64 size) override; 108 void UnmapMemory(DAddr addr, u64 size) override;
105 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; 109 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
106 void SignalFence(std::function<void()>&& func) override; 110 void SignalFence(std::function<void()>&& func) override;
107 void SyncOperation(std::function<void()>&& func) override; 111 void SyncOperation(std::function<void()>&& func) override;
@@ -109,7 +113,7 @@ public:
109 void SignalReference() override; 113 void SignalReference() override;
110 void ReleaseFences(bool force = true) override; 114 void ReleaseFences(bool force = true) override;
111 void FlushAndInvalidateRegion( 115 void FlushAndInvalidateRegion(
112 VAddr addr, u64 size, VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 116 DAddr addr, u64 size, VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
113 void WaitForIdle() override; 117 void WaitForIdle() override;
114 void FragmentBarrier() override; 118 void FragmentBarrier() override;
115 void TiledCacheBarrier() override; 119 void TiledCacheBarrier() override;
@@ -122,7 +126,7 @@ public:
122 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; 126 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
123 void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, 127 void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
124 std::span<const u8> memory) override; 128 std::span<const u8> memory) override;
125 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 129 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr,
126 u32 pixel_stride) override; 130 u32 pixel_stride) override;
127 void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 131 void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
128 const VideoCore::DiskResourceLoadCallback& callback) override; 132 const VideoCore::DiskResourceLoadCallback& callback) override;
@@ -176,6 +180,7 @@ private:
176 void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); 180 void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs);
177 181
178 Tegra::GPU& gpu; 182 Tegra::GPU& gpu;
183 Tegra::MaxwellDeviceMemoryManager& device_memory;
179 184
180 ScreenInfo& screen_info; 185 ScreenInfo& screen_info;
181 const Device& device; 186 const Device& device;
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp
index e81cd031b..2af32c8f2 100644
--- a/src/video_core/shader_cache.cpp
+++ b/src/video_core/shader_cache.cpp
@@ -12,6 +12,7 @@
12#include "video_core/dirty_flags.h" 12#include "video_core/dirty_flags.h"
13#include "video_core/engines/kepler_compute.h" 13#include "video_core/engines/kepler_compute.h"
14#include "video_core/engines/maxwell_3d.h" 14#include "video_core/engines/maxwell_3d.h"
15#include "video_core/host1x/gpu_device_memory_manager.h"
15#include "video_core/memory_manager.h" 16#include "video_core/memory_manager.h"
16#include "video_core/shader_cache.h" 17#include "video_core/shader_cache.h"
17#include "video_core/shader_environment.h" 18#include "video_core/shader_environment.h"
@@ -34,7 +35,8 @@ void ShaderCache::SyncGuestHost() {
34 RemovePendingShaders(); 35 RemovePendingShaders();
35} 36}
36 37
37ShaderCache::ShaderCache(VideoCore::RasterizerInterface& rasterizer_) : rasterizer{rasterizer_} {} 38ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_)
39 : device_memory{device_memory_} {}
38 40
39bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) { 41bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) {
40 auto& dirty{maxwell3d->dirty.flags}; 42 auto& dirty{maxwell3d->dirty.flags};
@@ -132,7 +134,7 @@ void ShaderCache::Register(std::unique_ptr<ShaderInfo> data, VAddr addr, size_t
132 134
133 storage.push_back(std::move(data)); 135 storage.push_back(std::move(data));
134 136
135 rasterizer.UpdatePagesCachedCount(addr, size, 1); 137 device_memory.UpdatePagesCachedCount(addr, size, 1);
136} 138}
137 139
138void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) { 140void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) {
@@ -209,7 +211,7 @@ void ShaderCache::UnmarkMemory(Entry* entry) {
209 211
210 const VAddr addr = entry->addr_start; 212 const VAddr addr = entry->addr_start;
211 const size_t size = entry->addr_end - addr; 213 const size_t size = entry->addr_end - addr;
212 rasterizer.UpdatePagesCachedCount(addr, size, -1); 214 device_memory.UpdatePagesCachedCount(addr, size, -1);
213} 215}
214 216
215void ShaderCache::RemoveShadersFromStorage(std::span<ShaderInfo*> removed_shaders) { 217void ShaderCache::RemoveShadersFromStorage(std::span<ShaderInfo*> removed_shaders) {
diff --git a/src/video_core/shader_cache.h b/src/video_core/shader_cache.h
index a76896620..fd9bf2562 100644
--- a/src/video_core/shader_cache.h
+++ b/src/video_core/shader_cache.h
@@ -14,6 +14,7 @@
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/polyfill_ranges.h" 15#include "common/polyfill_ranges.h"
16#include "video_core/control/channel_state_cache.h" 16#include "video_core/control/channel_state_cache.h"
17#include "video_core/host1x/gpu_device_memory_manager.h"
17#include "video_core/rasterizer_interface.h" 18#include "video_core/rasterizer_interface.h"
18#include "video_core/shader_environment.h" 19#include "video_core/shader_environment.h"
19 20
@@ -77,7 +78,7 @@ protected:
77 } 78 }
78 }; 79 };
79 80
80 explicit ShaderCache(VideoCore::RasterizerInterface& rasterizer_); 81 explicit ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory);
81 82
82 /// @brief Update the hashes and information of shader stages 83 /// @brief Update the hashes and information of shader stages
83 /// @param unique_hashes Shader hashes to store into when a stage is enabled 84 /// @param unique_hashes Shader hashes to store into when a stage is enabled
@@ -145,7 +146,7 @@ private:
145 /// @brief Create a new shader entry and register it 146 /// @brief Create a new shader entry and register it
146 const ShaderInfo* MakeShaderInfo(GenericEnvironment& env, VAddr cpu_addr); 147 const ShaderInfo* MakeShaderInfo(GenericEnvironment& env, VAddr cpu_addr);
147 148
148 VideoCore::RasterizerInterface& rasterizer; 149 Tegra::MaxwellDeviceMemoryManager& device_memory;
149 150
150 mutable std::mutex lookup_mutex; 151 mutable std::mutex lookup_mutex;
151 std::mutex invalidation_mutex; 152 std::mutex invalidation_mutex;
diff --git a/src/video_core/texture_cache/accelerated_swizzle.cpp b/src/video_core/texture_cache/accelerated_swizzle.cpp
index 70be1657e..4c3f724d7 100644
--- a/src/video_core/texture_cache/accelerated_swizzle.cpp
+++ b/src/video_core/texture_cache/accelerated_swizzle.cpp
@@ -66,4 +66,4 @@ BlockLinearSwizzle3DParams MakeBlockLinearSwizzle3DParams(const SwizzleParameter
66 }; 66 };
67} 67}
68 68
69} // namespace VideoCommon::Accelerated \ No newline at end of file 69} // namespace VideoCommon::Accelerated
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 0d5a1709f..7398ed2ec 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -8,10 +8,11 @@
8 8
9#include "common/alignment.h" 9#include "common/alignment.h"
10#include "common/settings.h" 10#include "common/settings.h"
11#include "core/memory.h"
12#include "video_core/control/channel_state.h" 11#include "video_core/control/channel_state.h"
13#include "video_core/dirty_flags.h" 12#include "video_core/dirty_flags.h"
14#include "video_core/engines/kepler_compute.h" 13#include "video_core/engines/kepler_compute.h"
14#include "video_core/guest_memory.h"
15#include "video_core/host1x/gpu_device_memory_manager.h"
15#include "video_core/texture_cache/image_view_base.h" 16#include "video_core/texture_cache/image_view_base.h"
16#include "video_core/texture_cache/samples_helper.h" 17#include "video_core/texture_cache/samples_helper.h"
17#include "video_core/texture_cache/texture_cache_base.h" 18#include "video_core/texture_cache/texture_cache_base.h"
@@ -27,8 +28,8 @@ using VideoCore::Surface::SurfaceType;
27using namespace Common::Literals; 28using namespace Common::Literals;
28 29
29template <class P> 30template <class P>
30TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface& rasterizer_) 31TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManager& device_memory_)
31 : runtime{runtime_}, rasterizer{rasterizer_} { 32 : runtime{runtime_}, device_memory{device_memory_} {
32 // Configure null sampler 33 // Configure null sampler
33 TSCEntry sampler_descriptor{}; 34 TSCEntry sampler_descriptor{};
34 sampler_descriptor.min_filter.Assign(Tegra::Texture::TextureFilter::Linear); 35 sampler_descriptor.min_filter.Assign(Tegra::Texture::TextureFilter::Linear);
@@ -49,19 +50,19 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface&
49 void(slot_samplers.insert(runtime, sampler_descriptor)); 50 void(slot_samplers.insert(runtime, sampler_descriptor));
50 51
51 if constexpr (HAS_DEVICE_MEMORY_INFO) { 52 if constexpr (HAS_DEVICE_MEMORY_INFO) {
52 const s64 device_memory = static_cast<s64>(runtime.GetDeviceLocalMemory()); 53 const s64 device_local_memory = static_cast<s64>(runtime.GetDeviceLocalMemory());
53 const s64 min_spacing_expected = device_memory - 1_GiB; 54 const s64 min_spacing_expected = device_local_memory - 1_GiB;
54 const s64 min_spacing_critical = device_memory - 512_MiB; 55 const s64 min_spacing_critical = device_local_memory - 512_MiB;
55 const s64 mem_threshold = std::min(device_memory, TARGET_THRESHOLD); 56 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
56 const s64 min_vacancy_expected = (6 * mem_threshold) / 10; 57 const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
57 const s64 min_vacancy_critical = (3 * mem_threshold) / 10; 58 const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
58 expected_memory = static_cast<u64>( 59 expected_memory = static_cast<u64>(
59 std::max(std::min(device_memory - min_vacancy_expected, min_spacing_expected), 60 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
60 DEFAULT_EXPECTED_MEMORY)); 61 DEFAULT_EXPECTED_MEMORY));
61 critical_memory = static_cast<u64>( 62 critical_memory = static_cast<u64>(
62 std::max(std::min(device_memory - min_vacancy_critical, min_spacing_critical), 63 std::max(std::min(device_local_memory - min_vacancy_critical, min_spacing_critical),
63 DEFAULT_CRITICAL_MEMORY)); 64 DEFAULT_CRITICAL_MEMORY));
64 minimum_memory = static_cast<u64>((device_memory - mem_threshold) / 2); 65 minimum_memory = static_cast<u64>((device_local_memory - mem_threshold) / 2);
65 } else { 66 } else {
66 expected_memory = DEFAULT_EXPECTED_MEMORY + 512_MiB; 67 expected_memory = DEFAULT_EXPECTED_MEMORY + 512_MiB;
67 critical_memory = DEFAULT_CRITICAL_MEMORY + 1_GiB; 68 critical_memory = DEFAULT_CRITICAL_MEMORY + 1_GiB;
@@ -513,7 +514,7 @@ FramebufferId TextureCache<P>::GetFramebufferId(const RenderTargets& key) {
513} 514}
514 515
515template <class P> 516template <class P>
516void TextureCache<P>::WriteMemory(VAddr cpu_addr, size_t size) { 517void TextureCache<P>::WriteMemory(DAddr cpu_addr, size_t size) {
517 ForEachImageInRegion(cpu_addr, size, [this](ImageId image_id, Image& image) { 518 ForEachImageInRegion(cpu_addr, size, [this](ImageId image_id, Image& image) {
518 if (True(image.flags & ImageFlagBits::CpuModified)) { 519 if (True(image.flags & ImageFlagBits::CpuModified)) {
519 return; 520 return;
@@ -526,7 +527,7 @@ void TextureCache<P>::WriteMemory(VAddr cpu_addr, size_t size) {
526} 527}
527 528
528template <class P> 529template <class P>
529void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) { 530void TextureCache<P>::DownloadMemory(DAddr cpu_addr, size_t size) {
530 boost::container::small_vector<ImageId, 16> images; 531 boost::container::small_vector<ImageId, 16> images;
531 ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) { 532 ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) {
532 if (!image.IsSafeDownload()) { 533 if (!image.IsSafeDownload()) {
@@ -553,7 +554,7 @@ void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) {
553} 554}
554 555
555template <class P> 556template <class P>
556std::optional<VideoCore::RasterizerDownloadArea> TextureCache<P>::GetFlushArea(VAddr cpu_addr, 557std::optional<VideoCore::RasterizerDownloadArea> TextureCache<P>::GetFlushArea(DAddr cpu_addr,
557 u64 size) { 558 u64 size) {
558 std::optional<VideoCore::RasterizerDownloadArea> area{}; 559 std::optional<VideoCore::RasterizerDownloadArea> area{};
559 ForEachImageInRegion(cpu_addr, size, [&](ImageId, ImageBase& image) { 560 ForEachImageInRegion(cpu_addr, size, [&](ImageId, ImageBase& image) {
@@ -579,7 +580,7 @@ std::optional<VideoCore::RasterizerDownloadArea> TextureCache<P>::GetFlushArea(V
579} 580}
580 581
581template <class P> 582template <class P>
582void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) { 583void TextureCache<P>::UnmapMemory(DAddr cpu_addr, size_t size) {
583 boost::container::small_vector<ImageId, 16> deleted_images; 584 boost::container::small_vector<ImageId, 16> deleted_images;
584 ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); }); 585 ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); });
585 for (const ImageId id : deleted_images) { 586 for (const ImageId id : deleted_images) {
@@ -713,7 +714,7 @@ bool TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
713 714
714template <class P> 715template <class P>
715typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView( 716typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(
716 const Tegra::FramebufferConfig& config, VAddr cpu_addr) { 717 const Tegra::FramebufferConfig& config, DAddr cpu_addr) {
717 // TODO: Properly implement this 718 // TODO: Properly implement this
718 const auto it = page_table.find(cpu_addr >> YUZU_PAGEBITS); 719 const auto it = page_table.find(cpu_addr >> YUZU_PAGEBITS);
719 if (it == page_table.end()) { 720 if (it == page_table.end()) {
@@ -940,7 +941,7 @@ bool TextureCache<P>::IsRescaling(const ImageViewBase& image_view) const noexcep
940} 941}
941 942
942template <class P> 943template <class P>
943bool TextureCache<P>::IsRegionGpuModified(VAddr addr, size_t size) { 944bool TextureCache<P>::IsRegionGpuModified(DAddr addr, size_t size) {
944 bool is_modified = false; 945 bool is_modified = false;
945 ForEachImageInRegion(addr, size, [&is_modified](ImageId, ImageBase& image) { 946 ForEachImageInRegion(addr, size, [&is_modified](ImageId, ImageBase& image) {
946 if (False(image.flags & ImageFlagBits::GpuModified)) { 947 if (False(image.flags & ImageFlagBits::GpuModified)) {
@@ -1059,7 +1060,7 @@ void TextureCache<P>::UploadImageContents(Image& image, StagingBuffer& staging)
1059 return; 1060 return;
1060 } 1061 }
1061 1062
1062 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data( 1063 Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data(
1063 *gpu_memory, gpu_addr, image.guest_size_bytes, &swizzle_data_buffer); 1064 *gpu_memory, gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
1064 1065
1065 if (True(image.flags & ImageFlagBits::Converted)) { 1066 if (True(image.flags & ImageFlagBits::Converted)) {
@@ -1124,7 +1125,7 @@ ImageId TextureCache<P>::FindOrInsertImage(const ImageInfo& info, GPUVAddr gpu_a
1124template <class P> 1125template <class P>
1125ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, 1126ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
1126 RelaxedOptions options) { 1127 RelaxedOptions options) {
1127 std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1128 std::optional<DAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
1128 if (!cpu_addr) { 1129 if (!cpu_addr) {
1129 cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, CalculateGuestSizeInBytes(info)); 1130 cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, CalculateGuestSizeInBytes(info));
1130 if (!cpu_addr) { 1131 if (!cpu_addr) {
@@ -1265,7 +1266,7 @@ void TextureCache<P>::QueueAsyncDecode(Image& image, ImageId image_id) {
1265 1266
1266 static Common::ScratchBuffer<u8> local_unswizzle_data_buffer; 1267 static Common::ScratchBuffer<u8> local_unswizzle_data_buffer;
1267 local_unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes); 1268 local_unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes);
1268 Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data( 1269 Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data(
1269 *gpu_memory, image.gpu_addr, image.guest_size_bytes, &swizzle_data_buffer); 1270 *gpu_memory, image.gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
1270 1271
1271 auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data, 1272 auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data,
@@ -1339,14 +1340,14 @@ bool TextureCache<P>::ScaleDown(Image& image) {
1339template <class P> 1340template <class P>
1340ImageId TextureCache<P>::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr, 1341ImageId TextureCache<P>::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
1341 RelaxedOptions options) { 1342 RelaxedOptions options) {
1342 std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1343 std::optional<DAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
1343 if (!cpu_addr) { 1344 if (!cpu_addr) {
1344 const auto size = CalculateGuestSizeInBytes(info); 1345 const auto size = CalculateGuestSizeInBytes(info);
1345 cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, size); 1346 cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, size);
1346 if (!cpu_addr) { 1347 if (!cpu_addr) {
1347 const VAddr fake_addr = ~(1ULL << 40ULL) + virtual_invalid_space; 1348 const DAddr fake_addr = ~(1ULL << 40ULL) + virtual_invalid_space;
1348 virtual_invalid_space += Common::AlignUp(size, 32); 1349 virtual_invalid_space += Common::AlignUp(size, 32);
1349 cpu_addr = std::optional<VAddr>(fake_addr); 1350 cpu_addr = std::optional<DAddr>(fake_addr);
1350 } 1351 }
1351 } 1352 }
1352 ASSERT_MSG(cpu_addr, "Tried to insert an image to an invalid gpu_addr=0x{:x}", gpu_addr); 1353 ASSERT_MSG(cpu_addr, "Tried to insert an image to an invalid gpu_addr=0x{:x}", gpu_addr);
@@ -1362,7 +1363,7 @@ ImageId TextureCache<P>::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
1362} 1363}
1363 1364
1364template <class P> 1365template <class P>
1365ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr) { 1366ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DAddr cpu_addr) {
1366 ImageInfo new_info = info; 1367 ImageInfo new_info = info;
1367 const size_t size_bytes = CalculateGuestSizeInBytes(new_info); 1368 const size_t size_bytes = CalculateGuestSizeInBytes(new_info);
1368 const bool broken_views = runtime.HasBrokenTextureViewFormats(); 1369 const bool broken_views = runtime.HasBrokenTextureViewFormats();
@@ -1650,7 +1651,7 @@ std::optional<typename TextureCache<P>::BlitImages> TextureCache<P>::GetBlitImag
1650 1651
1651template <class P> 1652template <class P>
1652ImageId TextureCache<P>::FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr) { 1653ImageId TextureCache<P>::FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr) {
1653 std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1654 std::optional<DAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
1654 if (!cpu_addr) { 1655 if (!cpu_addr) {
1655 cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, CalculateGuestSizeInBytes(info)); 1656 cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, CalculateGuestSizeInBytes(info));
1656 if (!cpu_addr) { 1657 if (!cpu_addr) {
@@ -1780,7 +1781,7 @@ ImageViewId TextureCache<P>::FindRenderTargetView(const ImageInfo& info, GPUVAdd
1780 1781
1781template <class P> 1782template <class P>
1782template <typename Func> 1783template <typename Func>
1783void TextureCache<P>::ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func) { 1784void TextureCache<P>::ForEachImageInRegion(DAddr cpu_addr, size_t size, Func&& func) {
1784 using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type; 1785 using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type;
1785 static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>; 1786 static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
1786 boost::container::small_vector<ImageId, 32> images; 1787 boost::container::small_vector<ImageId, 32> images;
@@ -1924,11 +1925,11 @@ void TextureCache<P>::ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size,
1924template <class P> 1925template <class P>
1925template <typename Func> 1926template <typename Func>
1926void TextureCache<P>::ForEachSparseSegment(ImageBase& image, Func&& func) { 1927void TextureCache<P>::ForEachSparseSegment(ImageBase& image, Func&& func) {
1927 using FuncReturn = typename std::invoke_result<Func, GPUVAddr, VAddr, size_t>::type; 1928 using FuncReturn = typename std::invoke_result<Func, GPUVAddr, DAddr, size_t>::type;
1928 static constexpr bool RETURNS_BOOL = std::is_same_v<FuncReturn, bool>; 1929 static constexpr bool RETURNS_BOOL = std::is_same_v<FuncReturn, bool>;
1929 const auto segments = gpu_memory->GetSubmappedRange(image.gpu_addr, image.guest_size_bytes); 1930 const auto segments = gpu_memory->GetSubmappedRange(image.gpu_addr, image.guest_size_bytes);
1930 for (const auto& [gpu_addr, size] : segments) { 1931 for (const auto& [gpu_addr, size] : segments) {
1931 std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1932 std::optional<DAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
1932 ASSERT(cpu_addr); 1933 ASSERT(cpu_addr);
1933 if constexpr (RETURNS_BOOL) { 1934 if constexpr (RETURNS_BOOL) {
1934 if (func(gpu_addr, *cpu_addr, size)) { 1935 if (func(gpu_addr, *cpu_addr, size)) {
@@ -1980,7 +1981,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
1980 } 1981 }
1981 boost::container::small_vector<ImageViewId, 16> sparse_maps; 1982 boost::container::small_vector<ImageViewId, 16> sparse_maps;
1982 ForEachSparseSegment( 1983 ForEachSparseSegment(
1983 image, [this, image_id, &sparse_maps](GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { 1984 image, [this, image_id, &sparse_maps](GPUVAddr gpu_addr, DAddr cpu_addr, size_t size) {
1984 auto map_id = slot_map_views.insert(gpu_addr, cpu_addr, size, image_id); 1985 auto map_id = slot_map_views.insert(gpu_addr, cpu_addr, size, image_id);
1985 ForEachCPUPage(cpu_addr, size, 1986 ForEachCPUPage(cpu_addr, size,
1986 [this, map_id](u64 page) { page_table[page].push_back(map_id); }); 1987 [this, map_id](u64 page) { page_table[page].push_back(map_id); });
@@ -2048,7 +2049,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
2048 auto& sparse_maps = it->second; 2049 auto& sparse_maps = it->second;
2049 for (auto& map_view_id : sparse_maps) { 2050 for (auto& map_view_id : sparse_maps) {
2050 const auto& map_range = slot_map_views[map_view_id]; 2051 const auto& map_range = slot_map_views[map_view_id];
2051 const VAddr cpu_addr = map_range.cpu_addr; 2052 const DAddr cpu_addr = map_range.cpu_addr;
2052 const std::size_t size = map_range.size; 2053 const std::size_t size = map_range.size;
2053 ForEachCPUPage(cpu_addr, size, [this, image_id](u64 page) { 2054 ForEachCPUPage(cpu_addr, size, [this, image_id](u64 page) {
2054 const auto page_it = page_table.find(page); 2055 const auto page_it = page_table.find(page);
@@ -2080,7 +2081,7 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
2080 ASSERT(False(image.flags & ImageFlagBits::Tracked)); 2081 ASSERT(False(image.flags & ImageFlagBits::Tracked));
2081 image.flags |= ImageFlagBits::Tracked; 2082 image.flags |= ImageFlagBits::Tracked;
2082 if (False(image.flags & ImageFlagBits::Sparse)) { 2083 if (False(image.flags & ImageFlagBits::Sparse)) {
2083 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1); 2084 device_memory.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1);
2084 return; 2085 return;
2085 } 2086 }
2086 if (True(image.flags & ImageFlagBits::Registered)) { 2087 if (True(image.flags & ImageFlagBits::Registered)) {
@@ -2089,15 +2090,15 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
2089 auto& sparse_maps = it->second; 2090 auto& sparse_maps = it->second;
2090 for (auto& map_view_id : sparse_maps) { 2091 for (auto& map_view_id : sparse_maps) {
2091 const auto& map = slot_map_views[map_view_id]; 2092 const auto& map = slot_map_views[map_view_id];
2092 const VAddr cpu_addr = map.cpu_addr; 2093 const DAddr cpu_addr = map.cpu_addr;
2093 const std::size_t size = map.size; 2094 const std::size_t size = map.size;
2094 rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); 2095 device_memory.UpdatePagesCachedCount(cpu_addr, size, 1);
2095 } 2096 }
2096 return; 2097 return;
2097 } 2098 }
2098 ForEachSparseSegment(image, 2099 ForEachSparseSegment(image,
2099 [this]([[maybe_unused]] GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { 2100 [this]([[maybe_unused]] GPUVAddr gpu_addr, DAddr cpu_addr, size_t size) {
2100 rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); 2101 device_memory.UpdatePagesCachedCount(cpu_addr, size, 1);
2101 }); 2102 });
2102} 2103}
2103 2104
@@ -2106,7 +2107,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
2106 ASSERT(True(image.flags & ImageFlagBits::Tracked)); 2107 ASSERT(True(image.flags & ImageFlagBits::Tracked));
2107 image.flags &= ~ImageFlagBits::Tracked; 2108 image.flags &= ~ImageFlagBits::Tracked;
2108 if (False(image.flags & ImageFlagBits::Sparse)) { 2109 if (False(image.flags & ImageFlagBits::Sparse)) {
2109 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1); 2110 device_memory.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1);
2110 return; 2111 return;
2111 } 2112 }
2112 ASSERT(True(image.flags & ImageFlagBits::Registered)); 2113 ASSERT(True(image.flags & ImageFlagBits::Registered));
@@ -2115,9 +2116,9 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
2115 auto& sparse_maps = it->second; 2116 auto& sparse_maps = it->second;
2116 for (auto& map_view_id : sparse_maps) { 2117 for (auto& map_view_id : sparse_maps) {
2117 const auto& map = slot_map_views[map_view_id]; 2118 const auto& map = slot_map_views[map_view_id];
2118 const VAddr cpu_addr = map.cpu_addr; 2119 const DAddr cpu_addr = map.cpu_addr;
2119 const std::size_t size = map.size; 2120 const std::size_t size = map.size;
2120 rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1); 2121 device_memory.UpdatePagesCachedCount(cpu_addr, size, -1);
2121 } 2122 }
2122} 2123}
2123 2124
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index 6caf75b46..8699d40d4 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -36,9 +36,11 @@
36#include "video_core/texture_cache/types.h" 36#include "video_core/texture_cache/types.h"
37#include "video_core/textures/texture.h" 37#include "video_core/textures/texture.h"
38 38
39namespace Tegra::Control { 39namespace Tegra {
40namespace Control {
40struct ChannelState; 41struct ChannelState;
41} 42}
43} // namespace Tegra
42 44
43namespace VideoCommon { 45namespace VideoCommon {
44 46
@@ -126,7 +128,7 @@ class TextureCache : public VideoCommon::ChannelSetupCaches<TextureCacheChannelI
126 }; 128 };
127 129
128public: 130public:
129 explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&); 131 explicit TextureCache(Runtime&, Tegra::MaxwellDeviceMemoryManager&);
130 132
131 /// Notify the cache that a new frame has been queued 133 /// Notify the cache that a new frame has been queued
132 void TickFrame(); 134 void TickFrame();
@@ -190,15 +192,15 @@ public:
190 Framebuffer* GetFramebuffer(); 192 Framebuffer* GetFramebuffer();
191 193
192 /// Mark images in a range as modified from the CPU 194 /// Mark images in a range as modified from the CPU
193 void WriteMemory(VAddr cpu_addr, size_t size); 195 void WriteMemory(DAddr cpu_addr, size_t size);
194 196
195 /// Download contents of host images to guest memory in a region 197 /// Download contents of host images to guest memory in a region
196 void DownloadMemory(VAddr cpu_addr, size_t size); 198 void DownloadMemory(DAddr cpu_addr, size_t size);
197 199
198 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(VAddr cpu_addr, u64 size); 200 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(DAddr cpu_addr, u64 size);
199 201
200 /// Remove images in a region 202 /// Remove images in a region
201 void UnmapMemory(VAddr cpu_addr, size_t size); 203 void UnmapMemory(DAddr cpu_addr, size_t size);
202 204
203 /// Remove images in a region 205 /// Remove images in a region
204 void UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t size); 206 void UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t size);
@@ -210,7 +212,7 @@ public:
210 212
211 /// Try to find a cached image view in the given CPU address 213 /// Try to find a cached image view in the given CPU address
212 [[nodiscard]] ImageView* TryFindFramebufferImageView(const Tegra::FramebufferConfig& config, 214 [[nodiscard]] ImageView* TryFindFramebufferImageView(const Tegra::FramebufferConfig& config,
213 VAddr cpu_addr); 215 DAddr cpu_addr);
214 216
215 /// Return true when there are uncommitted images to be downloaded 217 /// Return true when there are uncommitted images to be downloaded
216 [[nodiscard]] bool HasUncommittedFlushes() const noexcept; 218 [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
@@ -235,7 +237,7 @@ public:
235 GPUVAddr address = 0, size_t size = 0); 237 GPUVAddr address = 0, size_t size = 0);
236 238
237 /// Return true when a CPU region is modified from the GPU 239 /// Return true when a CPU region is modified from the GPU
238 [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); 240 [[nodiscard]] bool IsRegionGpuModified(DAddr addr, size_t size);
239 241
240 [[nodiscard]] bool IsRescaling() const noexcept; 242 [[nodiscard]] bool IsRescaling() const noexcept;
241 243
@@ -252,7 +254,7 @@ public:
252private: 254private:
253 /// Iterate over all page indices in a range 255 /// Iterate over all page indices in a range
254 template <typename Func> 256 template <typename Func>
255 static void ForEachCPUPage(VAddr addr, size_t size, Func&& func) { 257 static void ForEachCPUPage(DAddr addr, size_t size, Func&& func) {
256 static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>; 258 static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
257 const u64 page_end = (addr + size - 1) >> YUZU_PAGEBITS; 259 const u64 page_end = (addr + size - 1) >> YUZU_PAGEBITS;
258 for (u64 page = addr >> YUZU_PAGEBITS; page <= page_end; ++page) { 260 for (u64 page = addr >> YUZU_PAGEBITS; page <= page_end; ++page) {
@@ -326,7 +328,7 @@ private:
326 328
327 /// Create a new image and join perfectly matching existing images 329 /// Create a new image and join perfectly matching existing images
328 /// Remove joined images from the cache 330 /// Remove joined images from the cache
329 [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr); 331 [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DAddr cpu_addr);
330 332
331 [[nodiscard]] ImageId FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr); 333 [[nodiscard]] ImageId FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr);
332 334
@@ -349,7 +351,7 @@ private:
349 351
350 /// Iterates over all the images in a region calling func 352 /// Iterates over all the images in a region calling func
351 template <typename Func> 353 template <typename Func>
352 void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func); 354 void ForEachImageInRegion(DAddr cpu_addr, size_t size, Func&& func);
353 355
354 template <typename Func> 356 template <typename Func>
355 void ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, size_t size, Func&& func); 357 void ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, size_t size, Func&& func);
@@ -421,7 +423,7 @@ private:
421 423
422 Runtime& runtime; 424 Runtime& runtime;
423 425
424 VideoCore::RasterizerInterface& rasterizer; 426 Tegra::MaxwellDeviceMemoryManager& device_memory;
425 std::deque<TextureCacheGPUMap> gpu_page_table_storage; 427 std::deque<TextureCacheGPUMap> gpu_page_table_storage;
426 428
427 RenderTargets render_targets; 429 RenderTargets render_targets;
@@ -432,7 +434,7 @@ private:
432 std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>> sparse_page_table; 434 std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>> sparse_page_table;
433 std::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views; 435 std::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views;
434 436
435 VAddr virtual_invalid_space{}; 437 DAddr virtual_invalid_space{};
436 438
437 bool has_deleted_images = false; 439 bool has_deleted_images = false;
438 bool is_rescaling = false; 440 bool is_rescaling = false;
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index fcf70068e..1a6f0d1ad 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -20,9 +20,9 @@
20#include "common/div_ceil.h" 20#include "common/div_ceil.h"
21#include "common/scratch_buffer.h" 21#include "common/scratch_buffer.h"
22#include "common/settings.h" 22#include "common/settings.h"
23#include "core/memory.h"
24#include "video_core/compatible_formats.h" 23#include "video_core/compatible_formats.h"
25#include "video_core/engines/maxwell_3d.h" 24#include "video_core/engines/maxwell_3d.h"
25#include "video_core/guest_memory.h"
26#include "video_core/memory_manager.h" 26#include "video_core/memory_manager.h"
27#include "video_core/surface.h" 27#include "video_core/surface.h"
28#include "video_core/texture_cache/decode_bc.h" 28#include "video_core/texture_cache/decode_bc.h"
@@ -552,7 +552,8 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr
552 for (s32 layer = 0; layer < info.resources.layers; ++layer) { 552 for (s32 layer = 0; layer < info.resources.layers; ++layer) {
553 const std::span<const u8> src = input.subspan(host_offset); 553 const std::span<const u8> src = input.subspan(host_offset);
554 { 554 {
555 Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadWrite> 555 Tegra::Memory::GpuGuestMemoryScoped<u8,
556 Tegra::Memory::GuestMemoryFlags::UnsafeReadWrite>
556 dst(gpu_memory, gpu_addr + guest_offset, subresource_size, &tmp_buffer); 557 dst(gpu_memory, gpu_addr + guest_offset, subresource_size, &tmp_buffer);
557 558
558 SwizzleTexture(dst, src, bytes_per_block, num_tiles.width, num_tiles.height, 559 SwizzleTexture(dst, src, bytes_per_block, num_tiles.width, num_tiles.height,
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index b42d48416..0efb7b49d 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -6,6 +6,8 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "common/settings.h" 7#include "common/settings.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "video_core/host1x/gpu_device_memory_manager.h"
10#include "video_core/host1x/host1x.h"
9#include "video_core/renderer_base.h" 11#include "video_core/renderer_base.h"
10#include "video_core/renderer_null/renderer_null.h" 12#include "video_core/renderer_null/renderer_null.h"
11#include "video_core/renderer_opengl/renderer_opengl.h" 13#include "video_core/renderer_opengl/renderer_opengl.h"
@@ -18,18 +20,17 @@ std::unique_ptr<VideoCore::RendererBase> CreateRenderer(
18 Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu, 20 Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
19 std::unique_ptr<Core::Frontend::GraphicsContext> context) { 21 std::unique_ptr<Core::Frontend::GraphicsContext> context) {
20 auto& telemetry_session = system.TelemetrySession(); 22 auto& telemetry_session = system.TelemetrySession();
21 auto& cpu_memory = system.ApplicationMemory(); 23 auto& device_memory = system.Host1x().MemoryManager();
22 24
23 switch (Settings::values.renderer_backend.GetValue()) { 25 switch (Settings::values.renderer_backend.GetValue()) {
24 case Settings::RendererBackend::OpenGL: 26 case Settings::RendererBackend::OpenGL:
25 return std::make_unique<OpenGL::RendererOpenGL>(telemetry_session, emu_window, cpu_memory, 27 return std::make_unique<OpenGL::RendererOpenGL>(telemetry_session, emu_window,
26 gpu, std::move(context)); 28 device_memory, gpu, std::move(context));
27 case Settings::RendererBackend::Vulkan: 29 case Settings::RendererBackend::Vulkan:
28 return std::make_unique<Vulkan::RendererVulkan>(telemetry_session, emu_window, cpu_memory, 30 return std::make_unique<Vulkan::RendererVulkan>(telemetry_session, emu_window,
29 gpu, std::move(context)); 31 device_memory, gpu, std::move(context));
30 case Settings::RendererBackend::Null: 32 case Settings::RendererBackend::Null:
31 return std::make_unique<Null::RendererNull>(emu_window, cpu_memory, gpu, 33 return std::make_unique<Null::RendererNull>(emu_window, gpu, std::move(context));
32 std::move(context));
33 default: 34 default:
34 return nullptr; 35 return nullptr;
35 } 36 }
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 074aed964..3966bd61e 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -39,6 +39,10 @@ void SortPhysicalDevicesPerVendor(std::vector<VkPhysicalDevice>& devices,
39 } 39 }
40} 40}
41 41
42bool IsMicrosoftDozen(const char* device_name) {
43 return std::strstr(device_name, "Microsoft") != nullptr;
44}
45
42void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) { 46void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) {
43 // Sort by name, this will set a base and make GPUs with higher numbers appear first 47 // Sort by name, this will set a base and make GPUs with higher numbers appear first
44 // (e.g. GTX 1650 will intentionally be listed before a GTX 1080). 48 // (e.g. GTX 1650 will intentionally be listed before a GTX 1080).
@@ -52,6 +56,12 @@ void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceD
52 }); 56 });
53 // Prefer Nvidia over AMD, AMD over Intel, Intel over the rest. 57 // Prefer Nvidia over AMD, AMD over Intel, Intel over the rest.
54 SortPhysicalDevicesPerVendor(devices, dld, {0x10DE, 0x1002, 0x8086}); 58 SortPhysicalDevicesPerVendor(devices, dld, {0x10DE, 0x1002, 0x8086});
59 // Demote Microsoft's Dozen devices to the bottom.
60 SortPhysicalDevices(
61 devices, dld,
62 [](const VkPhysicalDeviceProperties& lhs, const VkPhysicalDeviceProperties& rhs) {
63 return IsMicrosoftDozen(rhs.deviceName) && !IsMicrosoftDozen(lhs.deviceName);
64 });
55} 65}
56 66
57template <typename T> 67template <typename T>
diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp
index 3a7f6101d..9fd094ab6 100644
--- a/src/yuzu/configuration/configure_ringcon.cpp
+++ b/src/yuzu/configuration/configure_ringcon.cpp
@@ -494,4 +494,4 @@ QString ConfigureRingController::AnalogToText(const Common::ParamPackage& param,
494 } 494 }
495 495
496 return QObject::tr("[unknown]"); 496 return QObject::tr("[unknown]");
497} \ No newline at end of file 497}
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index b0b84f967..e193b5f95 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -12,9 +12,10 @@
12#include <QGraphicsItem> 12#include <QGraphicsItem>
13#include <QLineEdit> 13#include <QLineEdit>
14#include <QMessageBox> 14#include <QMessageBox>
15#include <QSpinBox>
16
15#include "common/settings.h" 17#include "common/settings.h"
16#include "core/core.h" 18#include "core/core.h"
17#include "core/hle/service/time/time_manager.h"
18#include "ui_configure_system.h" 19#include "ui_configure_system.h"
19#include "yuzu/configuration/configuration_shared.h" 20#include "yuzu/configuration/configuration_shared.h"
20#include "yuzu/configuration/configure_system.h" 21#include "yuzu/configuration/configure_system.h"
@@ -49,6 +50,11 @@ ConfigureSystem::ConfigureSystem(Core::System& system_,
49 : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} { 50 : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} {
50 ui->setupUi(this); 51 ui->setupUi(this);
51 52
53 const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
54 const auto current_time_s =
55 std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
56 previous_time = current_time_s + Settings::values.custom_rtc_offset.GetValue();
57
52 Setup(builder); 58 Setup(builder);
53 59
54 const auto locale_check = [this]() { 60 const auto locale_check = [this]() {
@@ -64,13 +70,28 @@ ConfigureSystem::ConfigureSystem(Core::System& system_,
64 } 70 }
65 }; 71 };
66 72
73 const auto update_date_offset = [this]() {
74 if (!checkbox_rtc->isChecked()) {
75 return;
76 }
77 auto offset = date_rtc_offset->value();
78 offset += date_rtc->dateTime().toSecsSinceEpoch() - previous_time;
79 previous_time = date_rtc->dateTime().toSecsSinceEpoch();
80 date_rtc_offset->setValue(offset);
81 };
82 const auto update_rtc_date = [this]() { UpdateRtcTime(); };
83
67 connect(combo_language, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check); 84 connect(combo_language, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check);
68 connect(combo_region, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check); 85 connect(combo_region, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check);
86 connect(checkbox_rtc, qOverload<int>(&QCheckBox::stateChanged), this, update_rtc_date);
87 connect(date_rtc_offset, qOverload<int>(&QSpinBox::valueChanged), this, update_rtc_date);
88 connect(date_rtc, &QDateTimeEdit::dateTimeChanged, this, update_date_offset);
69 89
70 ui->label_warn_invalid_locale->setVisible(false); 90 ui->label_warn_invalid_locale->setVisible(false);
71 locale_check(); 91 locale_check();
72 92
73 SetConfiguration(); 93 SetConfiguration();
94 UpdateRtcTime();
74} 95}
75 96
76ConfigureSystem::~ConfigureSystem() = default; 97ConfigureSystem::~ConfigureSystem() = default;
@@ -120,14 +141,28 @@ void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) {
120 continue; 141 continue;
121 } 142 }
122 143
144 // Keep track of the region_index (and language_index) combobox to validate the selected
145 // settings
123 if (setting->Id() == Settings::values.region_index.Id()) { 146 if (setting->Id() == Settings::values.region_index.Id()) {
124 // Keep track of the region_index (and language_index) combobox to validate the selected
125 // settings
126 combo_region = widget->combobox; 147 combo_region = widget->combobox;
127 } else if (setting->Id() == Settings::values.language_index.Id()) { 148 }
149
150 if (setting->Id() == Settings::values.language_index.Id()) {
128 combo_language = widget->combobox; 151 combo_language = widget->combobox;
129 } 152 }
130 153
154 if (setting->Id() == Settings::values.custom_rtc.Id()) {
155 checkbox_rtc = widget->checkbox;
156 }
157
158 if (setting->Id() == Settings::values.custom_rtc.Id()) {
159 date_rtc = widget->date_time_edit;
160 }
161
162 if (setting->Id() == Settings::values.custom_rtc_offset.Id()) {
163 date_rtc_offset = widget->spinbox;
164 }
165
131 switch (setting->GetCategory()) { 166 switch (setting->GetCategory()) {
132 case Settings::Category::Core: 167 case Settings::Category::Core:
133 core_hold.emplace(setting->Id(), widget); 168 core_hold.emplace(setting->Id(), widget);
@@ -147,6 +182,19 @@ void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) {
147 } 182 }
148} 183}
149 184
185void ConfigureSystem::UpdateRtcTime() {
186 const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
187 previous_time = std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
188 date_rtc_offset->setEnabled(checkbox_rtc->isChecked());
189
190 if (checkbox_rtc->isChecked()) {
191 previous_time += date_rtc_offset->value();
192 }
193
194 const auto date = QDateTime::fromSecsSinceEpoch(previous_time);
195 date_rtc->setDateTime(date);
196}
197
150void ConfigureSystem::SetConfiguration() {} 198void ConfigureSystem::SetConfiguration() {}
151 199
152void ConfigureSystem::ApplyConfiguration() { 200void ConfigureSystem::ApplyConfiguration() {
@@ -154,4 +202,5 @@ void ConfigureSystem::ApplyConfiguration() {
154 for (const auto& func : apply_funcs) { 202 for (const auto& func : apply_funcs) {
155 func(powered_on); 203 func(powered_on);
156 } 204 }
205 UpdateRtcTime();
157} 206}
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index eab99a48a..4334211f9 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -43,6 +43,8 @@ private:
43 43
44 void Setup(const ConfigurationShared::Builder& builder); 44 void Setup(const ConfigurationShared::Builder& builder);
45 45
46 void UpdateRtcTime();
47
46 std::vector<std::function<void(bool)>> apply_funcs{}; 48 std::vector<std::function<void(bool)>> apply_funcs{};
47 49
48 std::unique_ptr<Ui::ConfigureSystem> ui; 50 std::unique_ptr<Ui::ConfigureSystem> ui;
@@ -52,4 +54,8 @@ private:
52 54
53 QComboBox* combo_region; 55 QComboBox* combo_region;
54 QComboBox* combo_language; 56 QComboBox* combo_language;
57 QCheckBox* checkbox_rtc;
58 QDateTimeEdit* date_rtc;
59 QSpinBox* date_rtc_offset;
60 u64 previous_time;
55}; 61};
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp
index 922eb1b1a..ed9c7d859 100644
--- a/src/yuzu/configuration/shared_translation.cpp
+++ b/src/yuzu/configuration/shared_translation.cpp
@@ -143,8 +143,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
143 INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral()); 143 INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral());
144 INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral()); 144 INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral());
145 INSERT(Settings, device_name, tr("Device Name"), QStringLiteral()); 145 INSERT(Settings, device_name, tr("Device Name"), QStringLiteral());
146 INSERT(Settings, custom_rtc, tr("Custom RTC"), QStringLiteral()); 146 INSERT(Settings, custom_rtc, tr("Custom RTC Date:"), QStringLiteral());
147 INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral()); 147 INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral());
148 INSERT(Settings, custom_rtc_offset, QStringLiteral(" "),
149 QStringLiteral("The number of seconds from the current unix time"));
148 INSERT(Settings, language_index, tr("Language:"), 150 INSERT(Settings, language_index, tr("Language:"),
149 tr("Note: this can be overridden when region setting is auto-select")); 151 tr("Note: this can be overridden when region setting is auto-select"));
150 INSERT(Settings, region_index, tr("Region:"), QStringLiteral()); 152 INSERT(Settings, region_index, tr("Region:"), QStringLiteral());
diff --git a/src/yuzu/debugger/console.h b/src/yuzu/debugger/console.h
index fdb7d174c..2491d1ec1 100644
--- a/src/yuzu/debugger/console.h
+++ b/src/yuzu/debugger/console.h
@@ -10,4 +10,4 @@ namespace Debugger {
10 * get a real qt logging window which would work for all platforms. 10 * get a real qt logging window which would work for all platforms.
11 */ 11 */
12void ToggleConsole(); 12void ToggleConsole();
13} // namespace Debugger \ No newline at end of file 13} // namespace Debugger