summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/android/app/src/main/jni/native.cpp6
-rw-r--r--src/audio_core/audio_in_manager.cpp7
-rw-r--r--src/audio_core/audio_in_manager.h4
-rw-r--r--src/audio_core/device/audio_buffers.h6
-rw-r--r--src/audio_core/opus/decoder.cpp6
-rw-r--r--src/audio_core/opus/decoder.h6
-rw-r--r--src/audio_core/opus/decoder_manager.cpp18
-rw-r--r--src/audio_core/opus/decoder_manager.h16
-rw-r--r--src/audio_core/opus/hardware_opus.cpp13
-rw-r--r--src/audio_core/opus/hardware_opus.h6
-rw-r--r--src/audio_core/opus/parameters.h4
-rw-r--r--src/audio_core/renderer/audio_device.cpp14
-rw-r--r--src/audio_core/renderer/audio_device.h6
-rw-r--r--src/audio_core/renderer/audio_renderer.cpp7
-rw-r--r--src/audio_core/renderer/audio_renderer.h4
-rw-r--r--src/audio_core/renderer/behavior/info_updater.cpp2
-rw-r--r--src/audio_core/renderer/behavior/info_updater.h10
-rw-r--r--src/audio_core/renderer/memory/pool_mapper.cpp18
-rw-r--r--src/audio_core/renderer/memory/pool_mapper.h14
-rw-r--r--src/audio_core/renderer/system.cpp10
-rw-r--r--src/audio_core/renderer/system.h8
-rw-r--r--src/audio_core/sink/oboe_sink.cpp8
-rw-r--r--src/common/settings.h6
-rw-r--r--src/common/settings_enums.h2
-rw-r--r--src/common/string_util.cpp4
-rw-r--r--src/common/string_util.h1
-rw-r--r--src/core/CMakeLists.txt64
-rw-r--r--src/core/device_memory_manager.inc12
-rw-r--r--src/core/file_sys/fs_filesystem.h27
-rw-r--r--src/core/file_sys/fs_memory_management.h8
-rw-r--r--src/core/file_sys/fs_path.h2
-rw-r--r--src/core/file_sys/fs_path_utility.h7
-rw-r--r--src/core/file_sys/fs_save_data_types.h175
-rw-r--r--src/core/file_sys/fs_string_util.h15
-rw-r--r--src/core/file_sys/fsa/fs_i_directory.h91
-rw-r--r--src/core/file_sys/fsa/fs_i_file.h167
-rw-r--r--src/core/file_sys/fsa/fs_i_filesystem.h206
-rw-r--r--src/core/file_sys/fssrv/fssrv_sf_path.h36
-rw-r--r--src/core/file_sys/savedata_factory.cpp90
-rw-r--r--src/core/file_sys/savedata_factory.h68
-rw-r--r--src/core/hle/service/am/service/application_functions.cpp6
-rw-r--r--src/core/hle/service/audio/audin_u.cpp393
-rw-r--r--src/core/hle/service/audio/audin_u.h38
-rw-r--r--src/core/hle/service/audio/audio.cpp28
-rw-r--r--src/core/hle/service/audio/audio_controller.cpp31
-rw-r--r--src/core/hle/service/audio/audio_controller.h1
-rw-r--r--src/core/hle/service/audio/audio_device.cpp163
-rw-r--r--src/core/hle/service/audio/audio_device.h58
-rw-r--r--src/core/hle/service/audio/audio_in.cpp146
-rw-r--r--src/core/hle/service/audio/audio_in.h53
-rw-r--r--src/core/hle/service/audio/audio_in_manager.cpp125
-rw-r--r--src/core/hle/service/audio/audio_in_manager.h57
-rw-r--r--src/core/hle/service/audio/audio_out.cpp146
-rw-r--r--src/core/hle/service/audio/audio_out.h58
-rw-r--r--src/core/hle/service/audio/audio_out_manager.cpp101
-rw-r--r--src/core/hle/service/audio/audio_out_manager.h44
-rw-r--r--src/core/hle/service/audio/audio_renderer.cpp139
-rw-r--r--src/core/hle/service/audio/audio_renderer.h54
-rw-r--r--src/core/hle/service/audio/audio_renderer_manager.cpp104
-rw-r--r--src/core/hle/service/audio/audio_renderer_manager.h37
-rw-r--r--src/core/hle/service/audio/audout_u.cpp323
-rw-r--r--src/core/hle/service/audio/audout_u.h37
-rw-r--r--src/core/hle/service/audio/audren_u.cpp552
-rw-r--r--src/core/hle/service/audio/audren_u.h35
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager.cpp (renamed from src/core/hle/service/audio/audrec_u.cpp)7
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager.h (renamed from src/core/hle/service/audio/audrec_a.h)6
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp (renamed from src/core/hle/service/audio/audrec_a.cpp)7
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager_for_applet.h (renamed from src/core/hle/service/audio/audrec_u.h)7
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder.cpp145
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder.h63
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder_manager.cpp156
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder_manager.h53
-rw-r--r--src/core/hle/service/audio/hwopus.cpp502
-rw-r--r--src/core/hle/service/audio/hwopus.h36
-rw-r--r--src/core/hle/service/cmif_serialization.h2
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.cpp72
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.h13
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.cpp124
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.h21
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp283
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.h62
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp33
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h23
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp161
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h50
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.cpp47
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.h7
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp589
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.h72
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_types.h (renamed from src/core/hle/service/filesystem/fsp/fsp_util.h)12
-rw-r--r--src/core/hle/service/psc/ovln/ovln_types.h21
-rw-r--r--src/core/hle/service/psc/ovln/receiver.cpp24
-rw-r--r--src/core/hle/service/psc/ovln/receiver.h16
-rw-r--r--src/core/hle/service/psc/ovln/receiver_service.cpp28
-rw-r--r--src/core/hle/service/psc/ovln/receiver_service.h22
-rw-r--r--src/core/hle/service/psc/ovln/sender.cpp32
-rw-r--r--src/core/hle/service/psc/ovln/sender.h21
-rw-r--r--src/core/hle/service/psc/ovln/sender_service.cpp30
-rw-r--r--src/core/hle/service/psc/ovln/sender_service.h23
-rw-r--r--src/core/hle/service/psc/pm_control.cpp28
-rw-r--r--src/core/hle/service/psc/pm_control.h16
-rw-r--r--src/core/hle/service/psc/pm_module.cpp24
-rw-r--r--src/core/hle/service/psc/pm_module.h16
-rw-r--r--src/core/hle/service/psc/pm_service.cpp28
-rw-r--r--src/core/hle/service/psc/pm_service.h22
-rw-r--r--src/core/hle/service/psc/psc.cpp71
-rw-r--r--src/core/hle/service/psc/psc.h4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_special.cpp8
-rw-r--r--src/shader_recompiler/profile.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp1
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp14
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h5
-rw-r--r--src/yuzu/configuration/shared_translation.cpp10
-rw-r--r--src/yuzu/main.cpp94
116 files changed, 3819 insertions, 3201 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index edca221b1..cf05a3fe3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -121,6 +121,7 @@ else()
121 -Wno-attributes 121 -Wno-attributes
122 -Wno-invalid-offsetof 122 -Wno-invalid-offsetof
123 -Wno-unused-parameter 123 -Wno-unused-parameter
124 -Wno-missing-field-initializers
124 ) 125 )
125 126
126 if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang 127 if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 1226219ad..5d484a85e 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -668,7 +668,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
668 ASSERT(user_id); 668 ASSERT(user_id);
669 669
670 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 670 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
671 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1, 671 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1,
672 user_id->AsU128(), 0); 672 user_id->AsU128(), 0);
673 673
674 const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); 674 const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
@@ -836,8 +836,8 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
836 FileSys::OpenMode::Read); 836 FileSys::OpenMode::Read);
837 837
838 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 838 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
839 {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 839 {}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
840 program_id, user_id->AsU128(), 0); 840 user_id->AsU128(), 0);
841 return Common::Android::ToJString(env, user_save_data_path); 841 return Common::Android::ToJString(env, user_save_data_path);
842} 842}
843 843
diff --git a/src/audio_core/audio_in_manager.cpp b/src/audio_core/audio_in_manager.cpp
index a3667524f..63b064922 100644
--- a/src/audio_core/audio_in_manager.cpp
+++ b/src/audio_core/audio_in_manager.cpp
@@ -73,16 +73,15 @@ void Manager::BufferReleaseAndRegister() {
73 } 73 }
74} 74}
75 75
76u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, 76u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
77 [[maybe_unused]] const u32 max_count,
78 [[maybe_unused]] const bool filter) { 77 [[maybe_unused]] const bool filter) {
79 std::scoped_lock l{mutex}; 78 std::scoped_lock l{mutex};
80 79
81 LinkToManager(); 80 LinkToManager();
82 81
83 auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)}; 82 auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
84 if (input_devices.size() > 1) { 83 if (!input_devices.empty() && !names.empty()) {
85 names.emplace_back("Uac"); 84 names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
86 return 1; 85 return 1;
87 } 86 }
88 return 0; 87 return 0;
diff --git a/src/audio_core/audio_in_manager.h b/src/audio_core/audio_in_manager.h
index 5c4614cd1..2179990e0 100644
--- a/src/audio_core/audio_in_manager.h
+++ b/src/audio_core/audio_in_manager.h
@@ -60,13 +60,11 @@ public:
60 * Get a list of audio in device names. 60 * Get a list of audio in device names.
61 * 61 *
62 * @param names - Output container to write names to. 62 * @param names - Output container to write names to.
63 * @param max_count - Maximum number of device names to write. Unused
64 * @param filter - Should the list be filtered? Unused. 63 * @param filter - Should the list be filtered? Unused.
65 * 64 *
66 * @return Number of names written. 65 * @return Number of names written.
67 */ 66 */
68 u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count, 67 u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
69 bool filter);
70 68
71 /// Core system 69 /// Core system
72 Core::System& system; 70 Core::System& system;
diff --git a/src/audio_core/device/audio_buffers.h b/src/audio_core/device/audio_buffers.h
index 5d8ed0ef7..9e84a9c05 100644
--- a/src/audio_core/device/audio_buffers.h
+++ b/src/audio_core/device/audio_buffers.h
@@ -146,7 +146,11 @@ public:
146 break; 146 break;
147 } 147 }
148 148
149 tags[released++] = tag; 149 if (released < tags.size()) {
150 tags[released] = tag;
151 }
152
153 released++;
150 154
151 if (released >= tags.size()) { 155 if (released >= tags.size()) {
152 break; 156 break;
diff --git a/src/audio_core/opus/decoder.cpp b/src/audio_core/opus/decoder.cpp
index b7fed5304..0c110cbeb 100644
--- a/src/audio_core/opus/decoder.cpp
+++ b/src/audio_core/opus/decoder.cpp
@@ -28,8 +28,8 @@ OpusDecoder::~OpusDecoder() {
28 } 28 }
29} 29}
30 30
31Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, 31Result OpusDecoder::Initialize(const OpusParametersEx& params,
32 u64 transfer_memory_size) { 32 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
33 auto frame_size{params.use_large_frame_size ? 5760 : 1920}; 33 auto frame_size{params.use_large_frame_size ? 5760 : 1920};
34 shared_buffer_size = transfer_memory_size; 34 shared_buffer_size = transfer_memory_size;
35 shared_buffer = std::make_unique<u8[]>(shared_buffer_size); 35 shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
@@ -59,7 +59,7 @@ Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory
59 R_SUCCEED(); 59 R_SUCCEED();
60} 60}
61 61
62Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params, 62Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
63 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { 63 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
64 auto frame_size{params.use_large_frame_size ? 5760 : 1920}; 64 auto frame_size{params.use_large_frame_size ? 5760 : 1920};
65 shared_buffer_size = transfer_memory_size; 65 shared_buffer_size = transfer_memory_size;
diff --git a/src/audio_core/opus/decoder.h b/src/audio_core/opus/decoder.h
index fd728958a..1b8c257d4 100644
--- a/src/audio_core/opus/decoder.h
+++ b/src/audio_core/opus/decoder.h
@@ -22,10 +22,10 @@ public:
22 explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_); 22 explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
23 ~OpusDecoder(); 23 ~OpusDecoder();
24 24
25 Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, 25 Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
26 u64 transfer_memory_size);
27 Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
28 u64 transfer_memory_size); 26 u64 transfer_memory_size);
27 Result Initialize(const OpusMultiStreamParametersEx& params,
28 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
29 Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count, 29 Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
30 std::span<const u8> input_data, std::span<u8> output_data, bool reset); 30 std::span<const u8> input_data, std::span<u8> output_data, bool reset);
31 Result SetContext([[maybe_unused]] std::span<const u8> context); 31 Result SetContext([[maybe_unused]] std::span<const u8> context);
diff --git a/src/audio_core/opus/decoder_manager.cpp b/src/audio_core/opus/decoder_manager.cpp
index 1464880a1..89eec1298 100644
--- a/src/audio_core/opus/decoder_manager.cpp
+++ b/src/audio_core/opus/decoder_manager.cpp
@@ -38,7 +38,7 @@ OpusDecoderManager::OpusDecoderManager(Core::System& system_)
38 } 38 }
39} 39}
40 40
41Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) { 41Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) {
42 OpusParametersEx ex{ 42 OpusParametersEx ex{
43 .sample_rate = params.sample_rate, 43 .sample_rate = params.sample_rate,
44 .channel_count = params.channel_count, 44 .channel_count = params.channel_count,
@@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_si
47 R_RETURN(GetWorkBufferSizeExEx(ex, out_size)); 47 R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
48} 48}
49 49
50Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) { 50Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) {
51 R_RETURN(GetWorkBufferSizeExEx(params, out_size)); 51 R_RETURN(GetWorkBufferSizeExEx(params, out_size));
52} 52}
53 53
54Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) { 54Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) {
55 R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount); 55 R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
56 R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); 56 R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
57 57
@@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64&
63 R_SUCCEED(); 63 R_SUCCEED();
64} 64}
65 65
66Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, 66Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params,
67 u64& out_size) { 67 u32& out_size) {
68 OpusMultiStreamParametersEx ex{ 68 OpusMultiStreamParametersEx ex{
69 .sample_rate = params.sample_rate, 69 .sample_rate = params.sample_rate,
70 .channel_count = params.channel_count, 70 .channel_count = params.channel_count,
@@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParame
76 R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size)); 76 R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
77} 77}
78 78
79Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, 79Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
80 u64& out_size) { 80 const OpusMultiStreamParametersEx& params, u32& out_size) {
81 R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size)); 81 R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
82} 82}
83 83
84Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, 84Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
85 u64& out_size) { 85 const OpusMultiStreamParametersEx& params, u32& out_size) {
86 R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount); 86 R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
87 R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); 87 R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
88 R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count, 88 R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,
diff --git a/src/audio_core/opus/decoder_manager.h b/src/audio_core/opus/decoder_manager.h
index 70ebc4bab..8f6876d5c 100644
--- a/src/audio_core/opus/decoder_manager.h
+++ b/src/audio_core/opus/decoder_manager.h
@@ -22,17 +22,19 @@ public:
22 return hardware_opus; 22 return hardware_opus;
23 } 23 }
24 24
25 Result GetWorkBufferSize(OpusParameters& params, u64& out_size); 25 Result GetWorkBufferSize(const OpusParameters& params, u32& out_size);
26 Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size); 26 Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size);
27 Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size); 27 Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size);
28 Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size); 28 Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size);
29 Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size); 29 Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params,
30 Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size); 30 u32& out_size);
31 Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params,
32 u32& out_size);
31 33
32private: 34private:
33 Core::System& system; 35 Core::System& system;
34 HardwareOpus hardware_opus; 36 HardwareOpus hardware_opus;
35 std::array<u64, MaxChannels> required_workbuffer_sizes{}; 37 std::array<u32, MaxChannels> required_workbuffer_sizes{};
36}; 38};
37 39
38} // namespace AudioCore::OpusDecoder 40} // namespace AudioCore::OpusDecoder
diff --git a/src/audio_core/opus/hardware_opus.cpp b/src/audio_core/opus/hardware_opus.cpp
index 5ff71ab2d..30805f4a3 100644
--- a/src/audio_core/opus/hardware_opus.cpp
+++ b/src/audio_core/opus/hardware_opus.cpp
@@ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_)
42 opus_decoder.SetSharedMemory(shared_memory); 42 opus_decoder.SetSharedMemory(shared_memory);
43} 43}
44 44
45u64 HardwareOpus::GetWorkBufferSize(u32 channel) { 45u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
46 if (!opus_decoder.IsRunning()) { 46 if (!opus_decoder.IsRunning()) {
47 return 0; 47 return 0;
48 } 48 }
@@ -55,10 +55,10 @@ u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
55 ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg); 55 ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
56 return 0; 56 return 0;
57 } 57 }
58 return shared_memory.dsp_return_data[0]; 58 return static_cast<u32>(shared_memory.dsp_return_data[0]);
59} 59}
60 60
61u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { 61u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
62 std::scoped_lock l{mutex}; 62 std::scoped_lock l{mutex};
63 shared_memory.host_send_data[0] = total_stream_count; 63 shared_memory.host_send_data[0] = total_stream_count;
64 shared_memory.host_send_data[1] = stereo_stream_count; 64 shared_memory.host_send_data[1] = stereo_stream_count;
@@ -70,7 +70,7 @@ u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
70 ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg); 70 ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
71 return 0; 71 return 0;
72 } 72 }
73 return shared_memory.dsp_return_data[0]; 73 return static_cast<u32>(shared_memory.dsp_return_data[0]);
74} 74}
75 75
76Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, 76Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
@@ -94,8 +94,9 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count,
94 94
95Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, 95Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
96 u32 total_stream_count, 96 u32 total_stream_count,
97 u32 stereo_stream_count, void* mappings, 97 u32 stereo_stream_count,
98 void* buffer, u64 buffer_size) { 98 const void* mappings, void* buffer,
99 u64 buffer_size) {
99 std::scoped_lock l{mutex}; 100 std::scoped_lock l{mutex};
100 shared_memory.host_send_data[0] = (u64)buffer; 101 shared_memory.host_send_data[0] = (u64)buffer;
101 shared_memory.host_send_data[1] = buffer_size; 102 shared_memory.host_send_data[1] = buffer_size;
diff --git a/src/audio_core/opus/hardware_opus.h b/src/audio_core/opus/hardware_opus.h
index b10184baa..caa746840 100644
--- a/src/audio_core/opus/hardware_opus.h
+++ b/src/audio_core/opus/hardware_opus.h
@@ -16,14 +16,14 @@ class HardwareOpus {
16public: 16public:
17 HardwareOpus(Core::System& system); 17 HardwareOpus(Core::System& system);
18 18
19 u64 GetWorkBufferSize(u32 channel); 19 u32 GetWorkBufferSize(u32 channel);
20 u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count); 20 u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
21 21
22 Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, 22 Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
23 u64 buffer_size); 23 u64 buffer_size);
24 Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, 24 Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
25 u32 totaL_stream_count, u32 stereo_stream_count, 25 u32 totaL_stream_count, u32 stereo_stream_count,
26 void* mappings, void* buffer, u64 buffer_size); 26 const void* mappings, void* buffer, u64 buffer_size);
27 Result ShutdownDecodeObject(void* buffer, u64 buffer_size); 27 Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
28 Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size); 28 Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
29 Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size, 29 Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,
diff --git a/src/audio_core/opus/parameters.h b/src/audio_core/opus/parameters.h
index 4c54b2825..47c418b9f 100644
--- a/src/audio_core/opus/parameters.h
+++ b/src/audio_core/opus/parameters.h
@@ -20,7 +20,7 @@ struct OpusParametersEx {
20 /* 0x00 */ u32 sample_rate; 20 /* 0x00 */ u32 sample_rate;
21 /* 0x04 */ u32 channel_count; 21 /* 0x04 */ u32 channel_count;
22 /* 0x08 */ bool use_large_frame_size; 22 /* 0x08 */ bool use_large_frame_size;
23 /* 0x09 */ INSERT_PADDING_BYTES(7); 23 /* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7);
24}; // size = 0x10 24}; // size = 0x10
25static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!"); 25static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
26 26
@@ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx {
40 /* 0x08 */ u32 total_stream_count; 40 /* 0x08 */ u32 total_stream_count;
41 /* 0x0C */ u32 stereo_stream_count; 41 /* 0x0C */ u32 stereo_stream_count;
42 /* 0x10 */ bool use_large_frame_size; 42 /* 0x10 */ bool use_large_frame_size;
43 /* 0x11 */ INSERT_PADDING_BYTES(7); 43 /* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7);
44 /* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings; 44 /* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
45}; // size = 0x118 45}; // size = 0x118
46static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118, 46static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,
diff --git a/src/audio_core/renderer/audio_device.cpp b/src/audio_core/renderer/audio_device.cpp
index 2d9bf82bb..5be5594f6 100644
--- a/src/audio_core/renderer/audio_device.cpp
+++ b/src/audio_core/renderer/audio_device.cpp
@@ -36,8 +36,7 @@ AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id
36 : output_sink{system.AudioCore().GetOutputSink()}, 36 : output_sink{system.AudioCore().GetOutputSink()},
37 applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {} 37 applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
38 38
39u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, 39u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const {
40 const size_t max_count) const {
41 std::span<const AudioDeviceName> names{}; 40 std::span<const AudioDeviceName> names{};
42 41
43 if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) { 42 if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
@@ -46,19 +45,18 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
46 names = device_names; 45 names = device_names;
47 } 46 }
48 47
49 const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))}; 48 const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))};
50 for (u32 i = 0; i < out_count; i++) { 49 for (u32 i = 0; i < out_count; i++) {
51 out_buffer.push_back(names[i]); 50 out_buffer[i] = names[i];
52 } 51 }
53 return out_count; 52 return out_count;
54} 53}
55 54
56u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, 55u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const {
57 const size_t max_count) const { 56 const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))};
58 const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
59 57
60 for (u32 i = 0; i < out_count; i++) { 58 for (u32 i = 0; i < out_count; i++) {
61 out_buffer.push_back(output_device_names[i]); 59 out_buffer[i] = output_device_names[i];
62 } 60 }
63 return out_count; 61 return out_count;
64} 62}
diff --git a/src/audio_core/renderer/audio_device.h b/src/audio_core/renderer/audio_device.h
index ca4040add..4242dad30 100644
--- a/src/audio_core/renderer/audio_device.h
+++ b/src/audio_core/renderer/audio_device.h
@@ -36,20 +36,18 @@ public:
36 * Get a list of the available output devices. 36 * Get a list of the available output devices.
37 * 37 *
38 * @param out_buffer - Output buffer to write the available device names. 38 * @param out_buffer - Output buffer to write the available device names.
39 * @param max_count - Maximum number of devices to write (count of out_buffer).
40 * @return Number of device names written. 39 * @return Number of device names written.
41 */ 40 */
42 u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const; 41 u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const;
43 42
44 /** 43 /**
45 * Get a list of the available output devices. 44 * Get a list of the available output devices.
46 * Different to above somehow... 45 * Different to above somehow...
47 * 46 *
48 * @param out_buffer - Output buffer to write the available device names. 47 * @param out_buffer - Output buffer to write the available device names.
49 * @param max_count - Maximum number of devices to write (count of out_buffer).
50 * @return Number of device names written. 48 * @return Number of device names written.
51 */ 49 */
52 u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const; 50 u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const;
53 51
54 /** 52 /**
55 * Set the volume of all streams in the backend sink. 53 * Set the volume of all streams in the backend sink.
diff --git a/src/audio_core/renderer/audio_renderer.cpp b/src/audio_core/renderer/audio_renderer.cpp
index df03d03aa..7c728cb86 100644
--- a/src/audio_core/renderer/audio_renderer.cpp
+++ b/src/audio_core/renderer/audio_renderer.cpp
@@ -17,9 +17,8 @@ Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* ren
17 17
18Result Renderer::Initialize(const AudioRendererParameterInternal& params, 18Result Renderer::Initialize(const AudioRendererParameterInternal& params,
19 Kernel::KTransferMemory* transfer_memory, 19 Kernel::KTransferMemory* transfer_memory,
20 const u64 transfer_memory_size, const u32 process_handle, 20 const u64 transfer_memory_size, Kernel::KProcess* process_handle,
21 Kernel::KProcess& process, const u64 applet_resource_user_id, 21 const u64 applet_resource_user_id, const s32 session_id) {
22 const s32 session_id) {
23 if (params.execution_mode == ExecutionMode::Auto) { 22 if (params.execution_mode == ExecutionMode::Auto) {
24 if (!manager.AddSystem(system)) { 23 if (!manager.AddSystem(system)) {
25 LOG_ERROR(Service_Audio, 24 LOG_ERROR(Service_Audio,
@@ -30,7 +29,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
30 } 29 }
31 30
32 initialized = true; 31 initialized = true;
33 system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process, 32 system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
34 applet_resource_user_id, session_id); 33 applet_resource_user_id, session_id);
35 34
36 return ResultSuccess; 35 return ResultSuccess;
diff --git a/src/audio_core/renderer/audio_renderer.h b/src/audio_core/renderer/audio_renderer.h
index 1219f74ca..f16adeda7 100644
--- a/src/audio_core/renderer/audio_renderer.h
+++ b/src/audio_core/renderer/audio_renderer.h
@@ -38,14 +38,14 @@ public:
38 * @param params - Input parameters to initialize the system with. 38 * @param params - Input parameters to initialize the system with.
39 * @param transfer_memory - Game-supplied memory for all workbuffers. Unused. 39 * @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
40 * @param transfer_memory_size - Size of the transfer memory. Unused. 40 * @param transfer_memory_size - Size of the transfer memory. Unused.
41 * @param process_handle - Process handle, also used for memory. Unused. 41 * @param process_handle - Process handle, also used for memory.
42 * @param applet_resource_user_id - Applet id for this renderer. Unused. 42 * @param applet_resource_user_id - Applet id for this renderer. Unused.
43 * @param session_id - Session id of this renderer. 43 * @param session_id - Session id of this renderer.
44 * @return Result code. 44 * @return Result code.
45 */ 45 */
46 Result Initialize(const AudioRendererParameterInternal& params, 46 Result Initialize(const AudioRendererParameterInternal& params,
47 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, 47 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
48 u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id, 48 Kernel::KProcess* process_handle, u64 applet_resource_user_id,
49 s32 session_id); 49 s32 session_id);
50 50
51 /** 51 /**
diff --git a/src/audio_core/renderer/behavior/info_updater.cpp b/src/audio_core/renderer/behavior/info_updater.cpp
index 667711e17..3dae6069f 100644
--- a/src/audio_core/renderer/behavior/info_updater.cpp
+++ b/src/audio_core/renderer/behavior/info_updater.cpp
@@ -18,7 +18,7 @@
18namespace AudioCore::Renderer { 18namespace AudioCore::Renderer {
19 19
20InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_, 20InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
21 const u32 process_handle_, BehaviorInfo& behaviour_) 21 Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_)
22 : input{input_.data() + sizeof(UpdateDataHeader)}, 22 : input{input_.data() + sizeof(UpdateDataHeader)},
23 input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)}, 23 input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
24 output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>( 24 output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>(
diff --git a/src/audio_core/renderer/behavior/info_updater.h b/src/audio_core/renderer/behavior/info_updater.h
index fb4b7d25a..4f27a817e 100644
--- a/src/audio_core/renderer/behavior/info_updater.h
+++ b/src/audio_core/renderer/behavior/info_updater.h
@@ -8,6 +8,10 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hle/service/audio/errors.h" 9#include "core/hle/service/audio/errors.h"
10 10
11namespace Kernel {
12class KProcess;
13}
14
11namespace AudioCore::Renderer { 15namespace AudioCore::Renderer {
12class BehaviorInfo; 16class BehaviorInfo;
13class VoiceContext; 17class VoiceContext;
@@ -39,8 +43,8 @@ class InfoUpdater {
39 static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!"); 43 static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
40 44
41public: 45public:
42 explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle, 46 explicit InfoUpdater(std::span<const u8> input, std::span<u8> output,
43 BehaviorInfo& behaviour); 47 Kernel::KProcess* process_handle, BehaviorInfo& behaviour);
44 48
45 /** 49 /**
46 * Update the voice channel resources. 50 * Update the voice channel resources.
@@ -197,7 +201,7 @@ private:
197 /// Expected output size, see CheckConsumedSize 201 /// Expected output size, see CheckConsumedSize
198 u64 expected_output_size; 202 u64 expected_output_size;
199 /// Unused 203 /// Unused
200 u32 process_handle; 204 Kernel::KProcess* process_handle;
201 /// Behaviour 205 /// Behaviour
202 BehaviorInfo& behaviour; 206 BehaviorInfo& behaviour;
203}; 207};
diff --git a/src/audio_core/renderer/memory/pool_mapper.cpp b/src/audio_core/renderer/memory/pool_mapper.cpp
index 999bb746b..e47eb66d5 100644
--- a/src/audio_core/renderer/memory/pool_mapper.cpp
+++ b/src/audio_core/renderer/memory/pool_mapper.cpp
@@ -8,11 +8,11 @@
8 8
9namespace AudioCore::Renderer { 9namespace AudioCore::Renderer {
10 10
11PoolMapper::PoolMapper(u32 process_handle_, bool force_map_) 11PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_)
12 : process_handle{process_handle_}, force_map{force_map_} {} 12 : process_handle{process_handle_}, force_map{force_map_} {}
13 13
14PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_, 14PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_,
15 bool force_map_) 15 u32 pool_count_, bool force_map_)
16 : process_handle{process_handle_}, pool_infos{pool_infos_.data()}, 16 : process_handle{process_handle_}, pool_infos{pool_infos_.data()},
17 pool_count{pool_count_}, force_map{force_map_} {} 17 pool_count{pool_count_}, force_map{force_map_} {}
18 18
@@ -106,15 +106,17 @@ bool PoolMapper::IsForceMapEnabled() const {
106 return force_map; 106 return force_map;
107} 107}
108 108
109u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const { 109Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
110 switch (pool->GetLocation()) { 110 switch (pool->GetLocation()) {
111 case MemoryPoolInfo::Location::CPU: 111 case MemoryPoolInfo::Location::CPU:
112 return process_handle; 112 return process_handle;
113 case MemoryPoolInfo::Location::DSP: 113 case MemoryPoolInfo::Location::DSP:
114 return Kernel::Svc::CurrentProcess; 114 // return Kernel::Svc::CurrentProcess;
115 return nullptr;
115 } 116 }
116 LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!"); 117 LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
117 return Kernel::Svc::CurrentProcess; 118 // return Kernel::Svc::CurrentProcess;
119 return nullptr;
118} 120}
119 121
120bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr, 122bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr,
@@ -147,14 +149,14 @@ bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const
147} 149}
148 150
149bool PoolMapper::Unmap(MemoryPoolInfo& pool) const { 151bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
150 [[maybe_unused]] u32 handle{0}; 152 [[maybe_unused]] Kernel::KProcess* handle{};
151 153
152 switch (pool.GetLocation()) { 154 switch (pool.GetLocation()) {
153 case MemoryPoolInfo::Location::CPU: 155 case MemoryPoolInfo::Location::CPU:
154 handle = process_handle; 156 handle = process_handle;
155 break; 157 break;
156 case MemoryPoolInfo::Location::DSP: 158 case MemoryPoolInfo::Location::DSP:
157 handle = Kernel::Svc::CurrentProcess; 159 // handle = Kernel::Svc::CurrentProcess;
158 break; 160 break;
159 } 161 }
160 // nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size); 162 // nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);
diff --git a/src/audio_core/renderer/memory/pool_mapper.h b/src/audio_core/renderer/memory/pool_mapper.h
index 95ae5d8ea..fb5122b73 100644
--- a/src/audio_core/renderer/memory/pool_mapper.h
+++ b/src/audio_core/renderer/memory/pool_mapper.h
@@ -10,6 +10,10 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/service/audio/errors.h" 11#include "core/hle/service/audio/errors.h"
12 12
13namespace Kernel {
14class KProcess;
15}
16
13namespace AudioCore::Renderer { 17namespace AudioCore::Renderer {
14class AddressInfo; 18class AddressInfo;
15 19
@@ -18,9 +22,9 @@ class AddressInfo;
18 */ 22 */
19class PoolMapper { 23class PoolMapper {
20public: 24public:
21 explicit PoolMapper(u32 process_handle, bool force_map); 25 explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map);
22 explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count, 26 explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos,
23 bool force_map); 27 u32 pool_count, bool force_map);
24 28
25 /** 29 /**
26 * Clear the usage state for all given pools. 30 * Clear the usage state for all given pools.
@@ -98,7 +102,7 @@ public:
98 * @return CurrentProcessHandle if location == DSP, 102 * @return CurrentProcessHandle if location == DSP,
99 * the PoolMapper's process_handle if location == CPU 103 * the PoolMapper's process_handle if location == CPU
100 */ 104 */
101 u32 GetProcessHandle(const MemoryPoolInfo* pool) const; 105 Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const;
102 106
103 /** 107 /**
104 * Map the given region with the given handle. This is a no-op. 108 * Map the given region with the given handle. This is a no-op.
@@ -167,7 +171,7 @@ public:
167 171
168private: 172private:
169 /// Process handle for this mapper, used when location == CPU 173 /// Process handle for this mapper, used when location == CPU
170 u32 process_handle; 174 Kernel::KProcess* process_handle{};
171 /// List of memory pools assigned to this mapper 175 /// List of memory pools assigned to this mapper
172 MemoryPoolInfo* pool_infos{}; 176 MemoryPoolInfo* pool_infos{};
173 /// The number of pools 177 /// The number of pools
diff --git a/src/audio_core/renderer/system.cpp b/src/audio_core/renderer/system.cpp
index ca656edae..c30d68426 100644
--- a/src/audio_core/renderer/system.cpp
+++ b/src/audio_core/renderer/system.cpp
@@ -102,8 +102,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_)
102 102
103Result System::Initialize(const AudioRendererParameterInternal& params, 103Result System::Initialize(const AudioRendererParameterInternal& params,
104 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, 104 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
105 u32 process_handle_, Kernel::KProcess& process_, 105 Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
106 u64 applet_resource_user_id_, s32 session_id_) { 106 s32 session_id_) {
107 if (!CheckValidRevision(params.revision)) { 107 if (!CheckValidRevision(params.revision)) {
108 return Service::Audio::ResultInvalidRevision; 108 return Service::Audio::ResultInvalidRevision;
109 } 109 }
@@ -119,7 +119,6 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
119 behavior.SetUserLibRevision(params.revision); 119 behavior.SetUserLibRevision(params.revision);
120 120
121 process_handle = process_handle_; 121 process_handle = process_handle_;
122 process = &process_;
123 applet_resource_user_id = applet_resource_user_id_; 122 applet_resource_user_id = applet_resource_user_id_;
124 session_id = session_id_; 123 session_id = session_id_;
125 124
@@ -132,7 +131,8 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
132 render_device = params.rendering_device; 131 render_device = params.rendering_device;
133 execution_mode = params.execution_mode; 132 execution_mode = params.execution_mode;
134 133
135 process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size); 134 process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
135 transfer_memory_size);
136 136
137 // Note: We're not actually using the transfer memory because it's a pain to code for. 137 // Note: We're not actually using the transfer memory because it's a pain to code for.
138 // Allocate the memory normally instead and hope the game doesn't try to read anything back 138 // Allocate the memory normally instead and hope the game doesn't try to read anything back
@@ -616,7 +616,7 @@ void System::SendCommandToDsp() {
616 static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 * 616 static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
617 (static_cast<f32>(render_time_limit_percent) / 100.0f))}; 617 (static_cast<f32>(render_time_limit_percent) / 100.0f))};
618 audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit, 618 audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
619 applet_resource_user_id, process, 619 applet_resource_user_id, process_handle,
620 reset_command_buffers); 620 reset_command_buffers);
621 reset_command_buffers = false; 621 reset_command_buffers = false;
622 command_buffer_size = command_size; 622 command_buffer_size = command_size;
diff --git a/src/audio_core/renderer/system.h b/src/audio_core/renderer/system.h
index 753a0b796..3533a74ef 100644
--- a/src/audio_core/renderer/system.h
+++ b/src/audio_core/renderer/system.h
@@ -74,14 +74,14 @@ public:
74 * @param params - Input parameters to initialize the system with. 74 * @param params - Input parameters to initialize the system with.
75 * @param transfer_memory - Game-supplied memory for all workbuffers. Unused. 75 * @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
76 * @param transfer_memory_size - Size of the transfer memory. Unused. 76 * @param transfer_memory_size - Size of the transfer memory. Unused.
77 * @param process_handle - Process handle, also used for memory. Unused. 77 * @param process_handle - Process handle, also used for memory.
78 * @param applet_resource_user_id - Applet id for this renderer. Unused. 78 * @param applet_resource_user_id - Applet id for this renderer. Unused.
79 * @param session_id - Session id of this renderer. 79 * @param session_id - Session id of this renderer.
80 * @return Result code. 80 * @return Result code.
81 */ 81 */
82 Result Initialize(const AudioRendererParameterInternal& params, 82 Result Initialize(const AudioRendererParameterInternal& params,
83 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, 83 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
84 u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id, 84 Kernel::KProcess* process_handle, u64 applet_resource_user_id,
85 s32 session_id); 85 s32 session_id);
86 86
87 /** 87 /**
@@ -278,9 +278,7 @@ private:
278 /// Does what locks do 278 /// Does what locks do
279 std::mutex lock{}; 279 std::mutex lock{};
280 /// Process this audio render is operating within, used for memory reads/writes. 280 /// Process this audio render is operating within, used for memory reads/writes.
281 Kernel::KProcess* process{}; 281 Kernel::KProcess* process_handle{};
282 /// Handle for the process for this system, unused
283 u32 process_handle{};
284 /// Applet resource id for this system, unused 282 /// Applet resource id for this system, unused
285 u64 applet_resource_user_id{}; 283 u64 applet_resource_user_id{};
286 /// Controls performance input and output 284 /// Controls performance input and output
diff --git a/src/audio_core/sink/oboe_sink.cpp b/src/audio_core/sink/oboe_sink.cpp
index e61841172..466a9cc8e 100644
--- a/src/audio_core/sink/oboe_sink.cpp
+++ b/src/audio_core/sink/oboe_sink.cpp
@@ -67,9 +67,13 @@ public:
67 oboe::AudioStreamBuilder builder; 67 oboe::AudioStreamBuilder builder;
68 68
69 const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream); 69 const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
70 ASSERT(result == oboe::Result::OK); 70 if (result == oboe::Result::OK) {
71 return temp_stream->getChannelCount() >= 6 ? 6 : 2;
72 }
71 73
72 return temp_stream->getChannelCount() >= 6 ? 6 : 2; 74 LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
75 direction == oboe::Direction::Output ? "output" : "input");
76 return 2;
73 } 77 }
74 78
75protected: 79protected:
diff --git a/src/common/settings.h b/src/common/settings.h
index aa054dc24..b2b071e7e 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -384,6 +384,12 @@ struct Values {
384 AstcRecompression::Bc3, 384 AstcRecompression::Bc3,
385 "astc_recompression", 385 "astc_recompression",
386 Category::RendererAdvanced}; 386 Category::RendererAdvanced};
387 SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
388 VramUsageMode::Conservative,
389 VramUsageMode::Conservative,
390 VramUsageMode::Aggressive,
391 "vram_usage_mode",
392 Category::RendererAdvanced};
387 SwitchableSetting<bool> async_presentation{linkage, 393 SwitchableSetting<bool> async_presentation{linkage,
388#ifdef ANDROID 394#ifdef ANDROID
389 true, 395 true,
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
index f42367e67..6e247e930 100644
--- a/src/common/settings_enums.h
+++ b/src/common/settings_enums.h
@@ -122,6 +122,8 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
122 122
123ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed); 123ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
124 124
125ENUM(VramUsageMode, Conservative, Aggressive);
126
125ENUM(RendererBackend, OpenGL, Vulkan, Null); 127ENUM(RendererBackend, OpenGL, Vulkan, Null);
126 128
127ENUM(ShaderBackend, Glsl, Glasm, SpirV); 129ENUM(ShaderBackend, Glsl, Glasm, SpirV);
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 72c481798..1909aced5 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -38,6 +38,10 @@ std::string StringFromBuffer(std::span<const u8> data) {
38 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); 38 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
39} 39}
40 40
41std::string StringFromBuffer(std::span<const char> data) {
42 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
43}
44
41// Turns " hej " into "hej". Also handles tabs. 45// Turns " hej " into "hej". Also handles tabs.
42std::string StripSpaces(const std::string& str) { 46std::string StripSpaces(const std::string& str) {
43 const std::size_t s = str.find_first_not_of(" \t\r\n"); 47 const std::size_t s = str.find_first_not_of(" \t\r\n");
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 9da1ca4e9..53d0549ca 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -19,6 +19,7 @@ namespace Common {
19[[nodiscard]] std::string ToUpper(std::string str); 19[[nodiscard]] std::string ToUpper(std::string str);
20 20
21[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data); 21[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
22[[nodiscard]] std::string StringFromBuffer(std::span<const char> data);
22 23
23[[nodiscard]] std::string StripSpaces(const std::string& s); 24[[nodiscard]] std::string StripSpaces(const std::string& s);
24[[nodiscard]] std::string StripQuotes(const std::string& s); 25[[nodiscard]] std::string StripQuotes(const std::string& s);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 45b4b203d..0393eff33 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -58,9 +58,14 @@ add_library(core STATIC
58 file_sys/fs_operate_range.h 58 file_sys/fs_operate_range.h
59 file_sys/fs_path.h 59 file_sys/fs_path.h
60 file_sys/fs_path_utility.h 60 file_sys/fs_path_utility.h
61 file_sys/fs_save_data_types.h
61 file_sys/fs_string_util.h 62 file_sys/fs_string_util.h
63 file_sys/fsa/fs_i_directory.h
64 file_sys/fsa/fs_i_file.h
65 file_sys/fsa/fs_i_filesystem.h
62 file_sys/fsmitm_romfsbuild.cpp 66 file_sys/fsmitm_romfsbuild.cpp
63 file_sys/fsmitm_romfsbuild.h 67 file_sys/fsmitm_romfsbuild.h
68 file_sys/fssrv/fssrv_sf_path.h
64 file_sys/fssystem/fs_i_storage.h 69 file_sys/fssystem/fs_i_storage.h
65 file_sys/fssystem/fs_types.h 70 file_sys/fssystem/fs_types.h
66 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp 71 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@@ -489,23 +494,33 @@ add_library(core STATIC
489 hle/service/apm/apm_controller.h 494 hle/service/apm/apm_controller.h
490 hle/service/apm/apm_interface.cpp 495 hle/service/apm/apm_interface.cpp
491 hle/service/apm/apm_interface.h 496 hle/service/apm/apm_interface.h
492 hle/service/audio/audin_u.cpp
493 hle/service/audio/audin_u.h
494 hle/service/audio/audio.cpp
495 hle/service/audio/audio.h
496 hle/service/audio/audio_controller.cpp 497 hle/service/audio/audio_controller.cpp
497 hle/service/audio/audio_controller.h 498 hle/service/audio/audio_controller.h
498 hle/service/audio/audout_u.cpp 499 hle/service/audio/audio_device.cpp
499 hle/service/audio/audout_u.h 500 hle/service/audio/audio_device.h
500 hle/service/audio/audrec_a.cpp 501 hle/service/audio/audio_in_manager.cpp
501 hle/service/audio/audrec_a.h 502 hle/service/audio/audio_in_manager.h
502 hle/service/audio/audrec_u.cpp 503 hle/service/audio/audio_in.cpp
503 hle/service/audio/audrec_u.h 504 hle/service/audio/audio_in.h
504 hle/service/audio/audren_u.cpp 505 hle/service/audio/audio_out_manager.cpp
505 hle/service/audio/audren_u.h 506 hle/service/audio/audio_out_manager.h
507 hle/service/audio/audio_out.cpp
508 hle/service/audio/audio_out.h
509 hle/service/audio/audio_renderer_manager.cpp
510 hle/service/audio/audio_renderer_manager.h
511 hle/service/audio/audio_renderer.cpp
512 hle/service/audio/audio_renderer.h
513 hle/service/audio/audio.cpp
514 hle/service/audio/audio.h
506 hle/service/audio/errors.h 515 hle/service/audio/errors.h
507 hle/service/audio/hwopus.cpp 516 hle/service/audio/final_output_recorder_manager_for_applet.cpp
508 hle/service/audio/hwopus.h 517 hle/service/audio/final_output_recorder_manager_for_applet.h
518 hle/service/audio/final_output_recorder_manager.cpp
519 hle/service/audio/final_output_recorder_manager.h
520 hle/service/audio/hardware_opus_decoder_manager.cpp
521 hle/service/audio/hardware_opus_decoder_manager.h
522 hle/service/audio/hardware_opus_decoder.cpp
523 hle/service/audio/hardware_opus_decoder.h
509 hle/service/bcat/backend/backend.cpp 524 hle/service/bcat/backend/backend.cpp
510 hle/service/bcat/backend/backend.h 525 hle/service/bcat/backend/backend.h
511 hle/service/bcat/bcat.cpp 526 hle/service/bcat/bcat.cpp
@@ -595,6 +610,10 @@ add_library(core STATIC
595 hle/service/filesystem/fsp/fs_i_file.h 610 hle/service/filesystem/fsp/fs_i_file.h
596 hle/service/filesystem/fsp/fs_i_filesystem.cpp 611 hle/service/filesystem/fsp/fs_i_filesystem.cpp
597 hle/service/filesystem/fsp/fs_i_filesystem.h 612 hle/service/filesystem/fsp/fs_i_filesystem.h
613 hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
614 hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
615 hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
616 hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
598 hle/service/filesystem/fsp/fs_i_storage.cpp 617 hle/service/filesystem/fsp/fs_i_storage.cpp
599 hle/service/filesystem/fsp/fs_i_storage.h 618 hle/service/filesystem/fsp/fs_i_storage.h
600 hle/service/filesystem/fsp/fsp_ldr.cpp 619 hle/service/filesystem/fsp/fsp_ldr.cpp
@@ -603,7 +622,7 @@ add_library(core STATIC
603 hle/service/filesystem/fsp/fsp_pr.h 622 hle/service/filesystem/fsp/fsp_pr.h
604 hle/service/filesystem/fsp/fsp_srv.cpp 623 hle/service/filesystem/fsp/fsp_srv.cpp
605 hle/service/filesystem/fsp/fsp_srv.h 624 hle/service/filesystem/fsp/fsp_srv.h
606 hle/service/filesystem/fsp/fsp_util.h 625 hle/service/filesystem/fsp/fsp_types.h
607 hle/service/filesystem/romfs_controller.cpp 626 hle/service/filesystem/romfs_controller.cpp
608 hle/service/filesystem/romfs_controller.h 627 hle/service/filesystem/romfs_controller.h
609 hle/service/filesystem/save_data_controller.cpp 628 hle/service/filesystem/save_data_controller.cpp
@@ -907,6 +926,21 @@ add_library(core STATIC
907 hle/service/pm/pm.h 926 hle/service/pm/pm.h
908 hle/service/prepo/prepo.cpp 927 hle/service/prepo/prepo.cpp
909 hle/service/prepo/prepo.h 928 hle/service/prepo/prepo.h
929 hle/service/psc/ovln/ovln_types.h
930 hle/service/psc/ovln/receiver_service.cpp
931 hle/service/psc/ovln/receiver_service.h
932 hle/service/psc/ovln/receiver.cpp
933 hle/service/psc/ovln/receiver.h
934 hle/service/psc/ovln/sender_service.cpp
935 hle/service/psc/ovln/sender_service.h
936 hle/service/psc/ovln/sender.cpp
937 hle/service/psc/ovln/sender.h
938 hle/service/psc/pm_control.cpp
939 hle/service/psc/pm_control.h
940 hle/service/psc/pm_module.cpp
941 hle/service/psc/pm_module.h
942 hle/service/psc/pm_service.cpp
943 hle/service/psc/pm_service.h
910 hle/service/psc/psc.cpp 944 hle/service/psc/psc.cpp
911 hle/service/psc/psc.h 945 hle/service/psc/psc.h
912 hle/service/psc/time/alarms.cpp 946 hle/service/psc/time/alarms.cpp
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
index 37c1e69c3..f104d495b 100644
--- a/src/core/device_memory_manager.inc
+++ b/src/core/device_memory_manager.inc
@@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
522 auto* memory_device_inter = registered_processes[asid.id]; 522 auto* memory_device_inter = registered_processes[asid.id];
523 const auto release_pending = [&] { 523 const auto release_pending = [&] {
524 if (uncache_bytes > 0) { 524 if (uncache_bytes > 0) {
525 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, 525 if (memory_device_inter != nullptr) {
526 uncache_bytes, false); 526 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
527 uncache_bytes, false);
528 }
527 uncache_bytes = 0; 529 uncache_bytes = 0;
528 } 530 }
529 if (cache_bytes > 0) { 531 if (cache_bytes > 0) {
530 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, 532 if (memory_device_inter != nullptr) {
531 cache_bytes, true); 533 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
534 cache_bytes, true);
535 }
532 cache_bytes = 0; 536 cache_bytes = 0;
533 } 537 }
534 }; 538 };
diff --git a/src/core/file_sys/fs_filesystem.h b/src/core/file_sys/fs_filesystem.h
index 7f237b7fa..329b5aca5 100644
--- a/src/core/file_sys/fs_filesystem.h
+++ b/src/core/file_sys/fs_filesystem.h
@@ -23,6 +23,8 @@ enum class OpenDirectoryMode : u64 {
23 File = (1 << 1), 23 File = (1 << 1),
24 24
25 All = (Directory | File), 25 All = (Directory | File),
26
27 NotRequireFileSize = (1ULL << 31),
26}; 28};
27DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode) 29DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
28 30
@@ -36,4 +38,29 @@ enum class CreateOption : u8 {
36 BigFile = (1 << 0), 38 BigFile = (1 << 0),
37}; 39};
38 40
41struct FileSystemAttribute {
42 u8 dir_entry_name_length_max_defined;
43 u8 file_entry_name_length_max_defined;
44 u8 dir_path_name_length_max_defined;
45 u8 file_path_name_length_max_defined;
46 INSERT_PADDING_BYTES_NOINIT(0x5);
47 u8 utf16_dir_entry_name_length_max_defined;
48 u8 utf16_file_entry_name_length_max_defined;
49 u8 utf16_dir_path_name_length_max_defined;
50 u8 utf16_file_path_name_length_max_defined;
51 INSERT_PADDING_BYTES_NOINIT(0x18);
52 s32 dir_entry_name_length_max;
53 s32 file_entry_name_length_max;
54 s32 dir_path_name_length_max;
55 s32 file_path_name_length_max;
56 INSERT_PADDING_WORDS_NOINIT(0x5);
57 s32 utf16_dir_entry_name_length_max;
58 s32 utf16_file_entry_name_length_max;
59 s32 utf16_dir_path_name_length_max;
60 s32 utf16_file_path_name_length_max;
61 INSERT_PADDING_WORDS_NOINIT(0x18);
62 INSERT_PADDING_WORDS_NOINIT(0x1);
63};
64static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
65
39} // namespace FileSys 66} // namespace FileSys
diff --git a/src/core/file_sys/fs_memory_management.h b/src/core/file_sys/fs_memory_management.h
index f03c6354b..080017c5d 100644
--- a/src/core/file_sys/fs_memory_management.h
+++ b/src/core/file_sys/fs_memory_management.h
@@ -10,7 +10,7 @@ namespace FileSys {
10 10
11constexpr size_t RequiredAlignment = alignof(u64); 11constexpr size_t RequiredAlignment = alignof(u64);
12 12
13void* AllocateUnsafe(size_t size) { 13inline void* AllocateUnsafe(size_t size) {
14 // Allocate 14 // Allocate
15 void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment}); 15 void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
16 16
@@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {
21 return ptr; 21 return ptr;
22} 22}
23 23
24void DeallocateUnsafe(void* ptr, size_t size) { 24inline void DeallocateUnsafe(void* ptr, size_t size) {
25 // Deallocate the pointer 25 // Deallocate the pointer
26 ::operator delete(ptr, std::align_val_t{RequiredAlignment}); 26 ::operator delete(ptr, std::align_val_t{RequiredAlignment});
27} 27}
28 28
29void* Allocate(size_t size) { 29inline void* Allocate(size_t size) {
30 return AllocateUnsafe(size); 30 return AllocateUnsafe(size);
31} 31}
32 32
33void Deallocate(void* ptr, size_t size) { 33inline void Deallocate(void* ptr, size_t size) {
34 // If the pointer is non-null, deallocate it 34 // If the pointer is non-null, deallocate it
35 if (ptr != nullptr) { 35 if (ptr != nullptr) {
36 DeallocateUnsafe(ptr, size); 36 DeallocateUnsafe(ptr, size);
diff --git a/src/core/file_sys/fs_path.h b/src/core/file_sys/fs_path.h
index 56ba08a6a..1566e82b9 100644
--- a/src/core/file_sys/fs_path.h
+++ b/src/core/file_sys/fs_path.h
@@ -381,7 +381,7 @@ public:
381 381
382 // Check that it's possible for us to remove a child 382 // Check that it's possible for us to remove a child
383 auto* p = m_write_buffer.Get(); 383 auto* p = m_write_buffer.Get();
384 s32 len = std::strlen(p); 384 s32 len = static_cast<s32>(std::strlen(p));
385 R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented); 385 R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
386 386
387 // Handle a trailing separator 387 // Handle a trailing separator
diff --git a/src/core/file_sys/fs_path_utility.h b/src/core/file_sys/fs_path_utility.h
index 5643141f9..cdfd8c772 100644
--- a/src/core/file_sys/fs_path_utility.h
+++ b/src/core/file_sys/fs_path_utility.h
@@ -426,9 +426,10 @@ public:
426 R_SUCCEED(); 426 R_SUCCEED();
427 } 427 }
428 428
429 static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size, 429 static constexpr Result Normalize(char* dst, size_t* out_len, const char* path,
430 bool is_windows_path, bool is_drive_relative_path, 430 size_t max_out_size, bool is_windows_path,
431 bool allow_all_characters = false) { 431 bool is_drive_relative_path,
432 bool allow_all_characters = false) {
432 // Use StringTraits names for remainder of scope 433 // Use StringTraits names for remainder of scope
433 using namespace StringTraits; 434 using namespace StringTraits;
434 435
diff --git a/src/core/file_sys/fs_save_data_types.h b/src/core/file_sys/fs_save_data_types.h
new file mode 100644
index 000000000..86a83d217
--- /dev/null
+++ b/src/core/file_sys/fs_save_data_types.h
@@ -0,0 +1,175 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <fmt/format.h>
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11namespace FileSys {
12
13using SaveDataId = u64;
14using SystemSaveDataId = u64;
15using SystemBcatSaveDataId = SystemSaveDataId;
16using ProgramId = u64;
17
18enum class SaveDataSpaceId : u8 {
19 System = 0,
20 User = 1,
21 SdSystem = 2,
22 Temporary = 3,
23 SdUser = 4,
24
25 ProperSystem = 100,
26 SafeMode = 101,
27};
28
29enum class SaveDataType : u8 {
30 System = 0,
31 Account = 1,
32 Bcat = 2,
33 Device = 3,
34 Temporary = 4,
35 Cache = 5,
36 SystemBcat = 6,
37};
38
39enum class SaveDataRank : u8 {
40 Primary = 0,
41 Secondary = 1,
42};
43
44struct SaveDataSize {
45 u64 normal;
46 u64 journal;
47};
48static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size.");
49
50using UserId = u128;
51static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable.");
52static_assert(sizeof(UserId) == 0x10, "UserId has invalid size.");
53
54constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
55constexpr inline UserId InvalidUserId = {};
56
57enum class SaveDataFlags : u32 {
58 None = (0 << 0),
59 KeepAfterResettingSystemSaveData = (1 << 0),
60 KeepAfterRefurbishment = (1 << 1),
61 KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
62 NeedsSecureDelete = (1 << 3),
63};
64
65enum class SaveDataMetaType : u8 {
66 None = 0,
67 Thumbnail = 1,
68 ExtensionContext = 2,
69};
70
71struct SaveDataMetaInfo {
72 u32 size;
73 SaveDataMetaType type;
74 INSERT_PADDING_BYTES(0xB);
75};
76static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>,
77 "Data type must be trivially copyable.");
78static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size.");
79
80struct SaveDataCreationInfo {
81 s64 size;
82 s64 journal_size;
83 s64 block_size;
84 u64 owner_id;
85 u32 flags;
86 SaveDataSpaceId space_id;
87 bool pseudo;
88 INSERT_PADDING_BYTES(0x1A);
89};
90static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>,
91 "Data type must be trivially copyable.");
92static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size.");
93
94struct SaveDataAttribute {
95 ProgramId program_id;
96 UserId user_id;
97 SystemSaveDataId system_save_data_id;
98 SaveDataType type;
99 SaveDataRank rank;
100 u16 index;
101 INSERT_PADDING_BYTES(0x1C);
102
103 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
104 SystemSaveDataId system_save_data_id, u16 index,
105 SaveDataRank rank) {
106 return {
107 .program_id = program_id,
108 .user_id = user_id,
109 .system_save_data_id = system_save_data_id,
110 .type = type,
111 .rank = rank,
112 .index = index,
113 };
114 }
115
116 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
117 SystemSaveDataId system_save_data_id, u16 index) {
118 return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
119 }
120
121 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
122 SystemSaveDataId system_save_data_id) {
123 return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
124 }
125
126 std::string DebugInfo() const {
127 return fmt::format(
128 "[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
129 "rank={}, index={}]",
130 program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type),
131 static_cast<u8>(rank), index);
132 }
133};
134static_assert(sizeof(SaveDataAttribute) == 0x40);
135static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
136
137constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
138 return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
139 std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
140}
141
142constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
143 return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank,
144 lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id,
145 rhs.type, rhs.rank, rhs.index);
146}
147
148constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
149 return !(lhs == rhs);
150}
151
152struct SaveDataExtraData {
153 SaveDataAttribute attr;
154 u64 owner_id;
155 s64 timestamp;
156 u32 flags;
157 INSERT_PADDING_BYTES(4);
158 s64 available_size;
159 s64 journal_size;
160 s64 commit_id;
161 INSERT_PADDING_BYTES(0x190);
162};
163static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size.");
164static_assert(std::is_trivially_copyable_v<SaveDataExtraData>,
165 "Data type must be trivially copyable.");
166
167struct HashSalt {
168 static constexpr size_t Size = 32;
169
170 std::array<u8, Size> value;
171};
172static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
173static_assert(sizeof(HashSalt) == HashSalt::Size);
174
175} // namespace FileSys
diff --git a/src/core/file_sys/fs_string_util.h b/src/core/file_sys/fs_string_util.h
index 874e09054..c751a8f1a 100644
--- a/src/core/file_sys/fs_string_util.h
+++ b/src/core/file_sys/fs_string_util.h
@@ -20,6 +20,11 @@ constexpr int Strlen(const T* str) {
20} 20}
21 21
22template <typename T> 22template <typename T>
23constexpr int Strnlen(const T* str, std::size_t count) {
24 return Strnlen(str, static_cast<int>(count));
25}
26
27template <typename T>
23constexpr int Strnlen(const T* str, int count) { 28constexpr int Strnlen(const T* str, int count) {
24 ASSERT(str != nullptr); 29 ASSERT(str != nullptr);
25 ASSERT(count >= 0); 30 ASSERT(count >= 0);
@@ -33,6 +38,11 @@ constexpr int Strnlen(const T* str, int count) {
33} 38}
34 39
35template <typename T> 40template <typename T>
41constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
42 return Strncmp(lhs, rhs, static_cast<int>(count));
43}
44
45template <typename T>
36constexpr int Strncmp(const T* lhs, const T* rhs, int count) { 46constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
37 ASSERT(lhs != nullptr); 47 ASSERT(lhs != nullptr);
38 ASSERT(rhs != nullptr); 48 ASSERT(rhs != nullptr);
@@ -52,6 +62,11 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
52} 62}
53 63
54template <typename T> 64template <typename T>
65static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
66 return Strlcpy<T>(dst, src, static_cast<int>(count));
67}
68
69template <typename T>
55static constexpr int Strlcpy(T* dst, const T* src, int count) { 70static constexpr int Strlcpy(T* dst, const T* src, int count) {
56 ASSERT(dst != nullptr); 71 ASSERT(dst != nullptr);
57 ASSERT(src != nullptr); 72 ASSERT(src != nullptr);
diff --git a/src/core/file_sys/fsa/fs_i_directory.h b/src/core/file_sys/fsa/fs_i_directory.h
new file mode 100644
index 000000000..c8e895eab
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_directory.h
@@ -0,0 +1,91 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/file_sys/errors.h"
8#include "core/file_sys/fs_directory.h"
9#include "core/file_sys/fs_file.h"
10#include "core/file_sys/fs_filesystem.h"
11#include "core/file_sys/savedata_factory.h"
12#include "core/file_sys/vfs/vfs.h"
13#include "core/hle/result.h"
14
15namespace FileSys::Fsa {
16
17class IDirectory {
18public:
19 explicit IDirectory(VirtualDir backend_, OpenDirectoryMode mode)
20 : backend(std::move(backend_)) {
21 // TODO(DarkLordZach): Verify that this is the correct behavior.
22 // Build entry index now to save time later.
23 if (True(mode & OpenDirectoryMode::Directory)) {
24 BuildEntryIndex(backend->GetSubdirectories(), DirectoryEntryType::Directory);
25 }
26 if (True(mode & OpenDirectoryMode::File)) {
27 BuildEntryIndex(backend->GetFiles(), DirectoryEntryType::File);
28 }
29 }
30 virtual ~IDirectory() {}
31
32 Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
33 R_UNLESS(out_count != nullptr, ResultNullptrArgument);
34 if (max_entries == 0) {
35 *out_count = 0;
36 R_SUCCEED();
37 }
38 R_UNLESS(out_entries != nullptr, ResultNullptrArgument);
39 R_UNLESS(max_entries > 0, ResultInvalidArgument);
40 R_RETURN(this->DoRead(out_count, out_entries, max_entries));
41 }
42
43 Result GetEntryCount(s64* out) {
44 R_UNLESS(out != nullptr, ResultNullptrArgument);
45 R_RETURN(this->DoGetEntryCount(out));
46 }
47
48private:
49 Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
50 const u64 actual_entries =
51 std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index);
52 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
53 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
54 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
55
56 next_entry_index += actual_entries;
57 *out_count = actual_entries;
58
59 std::memcpy(out_entries, begin, range_size);
60
61 R_SUCCEED();
62 }
63
64 Result DoGetEntryCount(s64* out) {
65 *out = entries.size() - next_entry_index;
66 R_SUCCEED();
67 }
68
69 // TODO: Remove this when VFS is gone
70 template <typename T>
71 void BuildEntryIndex(const std::vector<T>& new_data, DirectoryEntryType type) {
72 entries.reserve(entries.size() + new_data.size());
73
74 for (const auto& new_entry : new_data) {
75 auto name = new_entry->GetName();
76
77 if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) {
78 continue;
79 }
80
81 entries.emplace_back(name, static_cast<s8>(type),
82 type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize());
83 }
84 }
85
86 VirtualDir backend;
87 std::vector<DirectoryEntry> entries;
88 u64 next_entry_index = 0;
89};
90
91} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fsa/fs_i_file.h b/src/core/file_sys/fsa/fs_i_file.h
new file mode 100644
index 000000000..1188ae8ca
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_file.h
@@ -0,0 +1,167 @@
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/overflow.h"
7#include "core/file_sys/errors.h"
8#include "core/file_sys/fs_file.h"
9#include "core/file_sys/fs_filesystem.h"
10#include "core/file_sys/fs_operate_range.h"
11#include "core/file_sys/vfs/vfs.h"
12#include "core/file_sys/vfs/vfs_types.h"
13#include "core/hle/result.h"
14
15namespace FileSys::Fsa {
16
17class IFile {
18public:
19 explicit IFile(VirtualFile backend_) : backend(std::move(backend_)) {}
20 virtual ~IFile() {}
21
22 Result Read(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
23 // Check that we have an output pointer
24 R_UNLESS(out != nullptr, ResultNullptrArgument);
25
26 // If we have nothing to read, just succeed
27 if (size == 0) {
28 *out = 0;
29 R_SUCCEED();
30 }
31
32 // Check that the read is valid
33 R_UNLESS(buffer != nullptr, ResultNullptrArgument);
34 R_UNLESS(offset >= 0, ResultOutOfRange);
35 R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
36
37 // Do the read
38 R_RETURN(this->DoRead(out, offset, buffer, size, option));
39 }
40
41 Result Read(size_t* out, s64 offset, void* buffer, size_t size) {
42 R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None));
43 }
44
45 Result GetSize(s64* out) {
46 R_UNLESS(out != nullptr, ResultNullptrArgument);
47 R_RETURN(this->DoGetSize(out));
48 }
49
50 Result Flush() {
51 R_RETURN(this->DoFlush());
52 }
53
54 Result Write(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
55 // Handle the zero-size case
56 if (size == 0) {
57 if (option.HasFlushFlag()) {
58 R_TRY(this->Flush());
59 }
60 R_SUCCEED();
61 }
62
63 // Check the write is valid
64 R_UNLESS(buffer != nullptr, ResultNullptrArgument);
65 R_UNLESS(offset >= 0, ResultOutOfRange);
66 R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
67
68 R_RETURN(this->DoWrite(offset, buffer, size, option));
69 }
70
71 Result SetSize(s64 size) {
72 R_UNLESS(size >= 0, ResultOutOfRange);
73 R_RETURN(this->DoSetSize(size));
74 }
75
76 Result OperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
77 const void* src, size_t src_size) {
78 R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size));
79 }
80
81 Result OperateRange(OperationId op_id, s64 offset, s64 size) {
82 R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0));
83 }
84
85protected:
86 Result DryRead(size_t* out, s64 offset, size_t size, const ReadOption& option,
87 OpenMode open_mode) {
88 // Check that we can read
89 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Read) != 0, ResultReadNotPermitted);
90
91 // Get the file size, and validate our offset
92 s64 file_size = 0;
93 R_TRY(this->DoGetSize(std::addressof(file_size)));
94 R_UNLESS(offset <= file_size, ResultOutOfRange);
95
96 *out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
97 R_SUCCEED();
98 }
99
100 Result DrySetSize(s64 size, OpenMode open_mode) {
101 // Check that we can write
102 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
103 R_SUCCEED();
104 }
105
106 Result DryWrite(bool* out_append, s64 offset, size_t size, const WriteOption& option,
107 OpenMode open_mode) {
108 // Check that we can write
109 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
110
111 // Get the file size
112 s64 file_size = 0;
113 R_TRY(this->DoGetSize(&file_size));
114
115 // Determine if we need to append
116 *out_append = false;
117 if (file_size < offset + static_cast<s64>(size)) {
118 R_UNLESS(static_cast<u32>(open_mode & OpenMode::AllowAppend) != 0,
119 ResultFileExtensionWithoutOpenModeAllowAppend);
120 *out_append = true;
121 }
122
123 R_SUCCEED();
124 }
125
126private:
127 Result DoRead(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
128 const auto read_size = backend->Read(static_cast<u8*>(buffer), size, offset);
129 *out = read_size;
130
131 R_SUCCEED();
132 }
133
134 Result DoGetSize(s64* out) {
135 *out = backend->GetSize();
136 R_SUCCEED();
137 }
138
139 Result DoFlush() {
140 // Exists for SDK compatibiltity -- No need to flush file.
141 R_SUCCEED();
142 }
143
144 Result DoWrite(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
145 const std::size_t written = backend->Write(static_cast<const u8*>(buffer), size, offset);
146
147 ASSERT_MSG(written == size,
148 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", size,
149 written);
150
151 R_SUCCEED();
152 }
153
154 Result DoSetSize(s64 size) {
155 backend->Resize(size);
156 R_SUCCEED();
157 }
158
159 Result DoOperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
160 const void* src, size_t src_size) {
161 R_THROW(ResultNotImplemented);
162 }
163
164 VirtualFile backend;
165};
166
167} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fsa/fs_i_filesystem.h b/src/core/file_sys/fsa/fs_i_filesystem.h
new file mode 100644
index 000000000..8172190f4
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_filesystem.h
@@ -0,0 +1,206 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/errors.h"
7#include "core/file_sys/fs_filesystem.h"
8#include "core/file_sys/fs_path.h"
9#include "core/file_sys/vfs/vfs_types.h"
10#include "core/hle/result.h"
11#include "core/hle/service/filesystem/filesystem.h"
12
13namespace FileSys::Fsa {
14
15class IFile;
16class IDirectory;
17
18enum class QueryId : u32 {
19 SetConcatenationFileAttribute = 0,
20 UpdateMac = 1,
21 IsSignedSystemPartitionOnSdCardValid = 2,
22 QueryUnpreparedFileInformation = 3,
23};
24
25class IFileSystem {
26public:
27 explicit IFileSystem(VirtualDir backend_) : backend{std::move(backend_)} {}
28 virtual ~IFileSystem() {}
29
30 Result CreateFile(const Path& path, s64 size, CreateOption option) {
31 R_UNLESS(size >= 0, ResultOutOfRange);
32 R_RETURN(this->DoCreateFile(path, size, static_cast<int>(option)));
33 }
34
35 Result CreateFile(const Path& path, s64 size) {
36 R_RETURN(this->CreateFile(path, size, CreateOption::None));
37 }
38
39 Result DeleteFile(const Path& path) {
40 R_RETURN(this->DoDeleteFile(path));
41 }
42
43 Result CreateDirectory(const Path& path) {
44 R_RETURN(this->DoCreateDirectory(path));
45 }
46
47 Result DeleteDirectory(const Path& path) {
48 R_RETURN(this->DoDeleteDirectory(path));
49 }
50
51 Result DeleteDirectoryRecursively(const Path& path) {
52 R_RETURN(this->DoDeleteDirectoryRecursively(path));
53 }
54
55 Result RenameFile(const Path& old_path, const Path& new_path) {
56 R_RETURN(this->DoRenameFile(old_path, new_path));
57 }
58
59 Result RenameDirectory(const Path& old_path, const Path& new_path) {
60 R_RETURN(this->DoRenameDirectory(old_path, new_path));
61 }
62
63 Result GetEntryType(DirectoryEntryType* out, const Path& path) {
64 R_RETURN(this->DoGetEntryType(out, path));
65 }
66
67 Result OpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
68 R_UNLESS(out_file != nullptr, ResultNullptrArgument);
69 R_UNLESS(static_cast<u32>(mode & OpenMode::ReadWrite) != 0, ResultInvalidOpenMode);
70 R_UNLESS(static_cast<u32>(mode & ~OpenMode::All) == 0, ResultInvalidOpenMode);
71 R_RETURN(this->DoOpenFile(out_file, path, mode));
72 }
73
74 Result OpenDirectory(VirtualDir* out_dir, const Path& path, OpenDirectoryMode mode) {
75 R_UNLESS(out_dir != nullptr, ResultNullptrArgument);
76 R_UNLESS(static_cast<u64>(mode & OpenDirectoryMode::All) != 0, ResultInvalidOpenMode);
77 R_UNLESS(static_cast<u64>(
78 mode & ~(OpenDirectoryMode::All | OpenDirectoryMode::NotRequireFileSize)) == 0,
79 ResultInvalidOpenMode);
80 R_RETURN(this->DoOpenDirectory(out_dir, path, mode));
81 }
82
83 Result Commit() {
84 R_RETURN(this->DoCommit());
85 }
86
87 Result GetFreeSpaceSize(s64* out, const Path& path) {
88 R_UNLESS(out != nullptr, ResultNullptrArgument);
89 R_RETURN(this->DoGetFreeSpaceSize(out, path));
90 }
91
92 Result GetTotalSpaceSize(s64* out, const Path& path) {
93 R_UNLESS(out != nullptr, ResultNullptrArgument);
94 R_RETURN(this->DoGetTotalSpaceSize(out, path));
95 }
96
97 Result CleanDirectoryRecursively(const Path& path) {
98 R_RETURN(this->DoCleanDirectoryRecursively(path));
99 }
100
101 Result GetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
102 R_UNLESS(out != nullptr, ResultNullptrArgument);
103 R_RETURN(this->DoGetFileTimeStampRaw(out, path));
104 }
105
106 Result QueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
107 const Path& path) {
108 R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path));
109 }
110
111 // These aren't accessible as commands
112 Result CommitProvisionally(s64 counter) {
113 R_RETURN(this->DoCommitProvisionally(counter));
114 }
115
116 Result Rollback() {
117 R_RETURN(this->DoRollback());
118 }
119
120 Result Flush() {
121 R_RETURN(this->DoFlush());
122 }
123
124private:
125 Result DoCreateFile(const Path& path, s64 size, int flags) {
126 R_RETURN(backend.CreateFile(path.GetString(), size));
127 }
128
129 Result DoDeleteFile(const Path& path) {
130 R_RETURN(backend.DeleteFile(path.GetString()));
131 }
132
133 Result DoCreateDirectory(const Path& path) {
134 R_RETURN(backend.CreateDirectory(path.GetString()));
135 }
136
137 Result DoDeleteDirectory(const Path& path) {
138 R_RETURN(backend.DeleteDirectory(path.GetString()));
139 }
140
141 Result DoDeleteDirectoryRecursively(const Path& path) {
142 R_RETURN(backend.DeleteDirectoryRecursively(path.GetString()));
143 }
144
145 Result DoRenameFile(const Path& old_path, const Path& new_path) {
146 R_RETURN(backend.RenameFile(old_path.GetString(), new_path.GetString()));
147 }
148
149 Result DoRenameDirectory(const Path& old_path, const Path& new_path) {
150 R_RETURN(backend.RenameDirectory(old_path.GetString(), new_path.GetString()));
151 }
152
153 Result DoGetEntryType(DirectoryEntryType* out, const Path& path) {
154 R_RETURN(backend.GetEntryType(out, path.GetString()));
155 }
156
157 Result DoOpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
158 R_RETURN(backend.OpenFile(out_file, path.GetString(), mode));
159 }
160
161 Result DoOpenDirectory(VirtualDir* out_directory, const Path& path, OpenDirectoryMode mode) {
162 R_RETURN(backend.OpenDirectory(out_directory, path.GetString()));
163 }
164
165 Result DoCommit() {
166 R_THROW(ResultNotImplemented);
167 }
168
169 Result DoGetFreeSpaceSize(s64* out, const Path& path) {
170 R_THROW(ResultNotImplemented);
171 }
172
173 Result DoGetTotalSpaceSize(s64* out, const Path& path) {
174 R_THROW(ResultNotImplemented);
175 }
176
177 Result DoCleanDirectoryRecursively(const Path& path) {
178 R_RETURN(backend.CleanDirectoryRecursively(path.GetString()));
179 }
180
181 Result DoGetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
182 R_RETURN(backend.GetFileTimeStampRaw(out, path.GetString()));
183 }
184
185 Result DoQueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
186 const Path& path) {
187 R_THROW(ResultNotImplemented);
188 }
189
190 // These aren't accessible as commands
191 Result DoCommitProvisionally(s64 counter) {
192 R_THROW(ResultNotImplemented);
193 }
194
195 Result DoRollback() {
196 R_THROW(ResultNotImplemented);
197 }
198
199 Result DoFlush() {
200 R_THROW(ResultNotImplemented);
201 }
202
203 Service::FileSystem::VfsDirectoryServiceWrapper backend;
204};
205
206} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fssrv/fssrv_sf_path.h b/src/core/file_sys/fssrv/fssrv_sf_path.h
new file mode 100644
index 000000000..a0c0b2dac
--- /dev/null
+++ b/src/core/file_sys/fssrv/fssrv_sf_path.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/fs_directory.h"
7
8namespace FileSys::Sf {
9
10struct Path {
11 char str[EntryNameLengthMax + 1];
12
13 static constexpr Path Encode(const char* p) {
14 Path path = {};
15 for (size_t i = 0; i < sizeof(path) - 1; i++) {
16 path.str[i] = p[i];
17 if (p[i] == '\x00') {
18 break;
19 }
20 }
21 return path;
22 }
23
24 static constexpr size_t GetPathLength(const Path& path) {
25 size_t len = 0;
26 for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
27 len++;
28 }
29 return len;
30 }
31};
32static_assert(std::is_trivially_copyable_v<Path>, "Path must be trivially copyable.");
33
34using FspPath = Path;
35
36} // namespace FileSys::Sf
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index cbf411a20..106922e04 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -14,48 +14,11 @@ namespace FileSys {
14 14
15namespace { 15namespace {
16 16
17void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
18 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
19 if (meta.zero_1 != 0) {
20 LOG_WARNING(Service_FS,
21 "Possibly incorrect SaveDataAttribute, type is "
22 "SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
23 meta.zero_1);
24 }
25 if (meta.zero_2 != 0) {
26 LOG_WARNING(Service_FS,
27 "Possibly incorrect SaveDataAttribute, type is "
28 "SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
29 meta.zero_2);
30 }
31 if (meta.zero_3 != 0) {
32 LOG_WARNING(Service_FS,
33 "Possibly incorrect SaveDataAttribute, type is "
34 "SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
35 meta.zero_3);
36 }
37 }
38
39 if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
40 LOG_WARNING(Service_FS,
41 "Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
42 "non-zero ({:016X}).",
43 meta.title_id);
44 }
45
46 if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
47 LOG_WARNING(Service_FS,
48 "Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
49 "non-zero ({:016X}{:016X})",
50 meta.user_id[1], meta.user_id[0]);
51 }
52}
53
54bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) { 17bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
55 return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage || 18 return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary ||
56 (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User 19 (space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User
57 (attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) && 20 (attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) &&
58 attr.title_id == 0 && attr.save_id == 0); 21 attr.program_id == 0 && attr.system_save_data_id == 0);
59} 22}
60 23
61std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id, 24std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
@@ -63,7 +26,7 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
63 // Only detect nand user saves. 26 // Only detect nand user saves.
64 const auto space_id_path = [space_id]() -> std::string_view { 27 const auto space_id_path = [space_id]() -> std::string_view {
65 switch (space_id) { 28 switch (space_id) {
66 case SaveDataSpaceId::NandUser: 29 case SaveDataSpaceId::User:
67 return "/user/save"; 30 return "/user/save";
68 default: 31 default:
69 return ""; 32 return "";
@@ -79,9 +42,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
79 42
80 // Only detect account/device saves from the future location. 43 // Only detect account/device saves from the future location.
81 switch (type) { 44 switch (type) {
82 case SaveDataType::SaveData: 45 case SaveDataType::Account:
83 return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id); 46 return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
84 case SaveDataType::DeviceSaveData: 47 case SaveDataType::Device:
85 return fmt::format("{}/device/{:016X}/0", space_id_path, title_id); 48 return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
86 default: 49 default:
87 return ""; 50 return "";
@@ -90,13 +53,6 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
90 53
91} // Anonymous namespace 54} // Anonymous namespace
92 55
93std::string SaveDataAttribute::DebugInfo() const {
94 return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
95 "rank={}, index={}]",
96 title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
97 static_cast<u8>(rank), index);
98}
99
100SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_, 56SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
101 VirtualDir save_directory_) 57 VirtualDir save_directory_)
102 : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} { 58 : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
@@ -108,18 +64,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
108SaveDataFactory::~SaveDataFactory() = default; 64SaveDataFactory::~SaveDataFactory() = default;
109 65
110VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const { 66VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
111 PrintSaveDataAttributeWarnings(meta); 67 const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
112 68 meta.user_id, meta.system_save_data_id);
113 const auto save_directory =
114 GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
115 69
116 return dir->CreateDirectoryRelative(save_directory); 70 return dir->CreateDirectoryRelative(save_directory);
117} 71}
118 72
119VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { 73VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
120 74
121 const auto save_directory = 75 const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
122 GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); 76 meta.user_id, meta.system_save_data_id);
123 77
124 auto out = dir->GetDirectoryRelative(save_directory); 78 auto out = dir->GetDirectoryRelative(save_directory);
125 79
@@ -136,11 +90,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
136 90
137std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { 91std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
138 switch (space) { 92 switch (space) {
139 case SaveDataSpaceId::NandSystem: 93 case SaveDataSpaceId::System:
140 return "/system/"; 94 return "/system/";
141 case SaveDataSpaceId::NandUser: 95 case SaveDataSpaceId::User:
142 return "/user/"; 96 return "/user/";
143 case SaveDataSpaceId::TemporaryStorage: 97 case SaveDataSpaceId::Temporary:
144 return "/temp/"; 98 return "/temp/";
145 default: 99 default:
146 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); 100 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@@ -153,7 +107,7 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
153 u128 user_id, u64 save_id) { 107 u128 user_id, u64 save_id) {
154 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should 108 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
155 // be interpreted as the title id of the current process. 109 // be interpreted as the title id of the current process.
156 if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { 110 if (type == SaveDataType::Account || type == SaveDataType::Device) {
157 if (title_id == 0) { 111 if (title_id == 0) {
158 title_id = program_id; 112 title_id = program_id;
159 } 113 }
@@ -173,16 +127,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
173 std::string out = GetSaveDataSpaceIdPath(space); 127 std::string out = GetSaveDataSpaceIdPath(space);
174 128
175 switch (type) { 129 switch (type) {
176 case SaveDataType::SystemSaveData: 130 case SaveDataType::System:
177 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); 131 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
178 case SaveDataType::SaveData: 132 case SaveDataType::Account:
179 case SaveDataType::DeviceSaveData: 133 case SaveDataType::Device:
180 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 134 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
181 title_id); 135 title_id);
182 case SaveDataType::TemporaryStorage: 136 case SaveDataType::Temporary:
183 return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 137 return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
184 title_id); 138 title_id);
185 case SaveDataType::CacheStorage: 139 case SaveDataType::Cache:
186 return fmt::format("{}save/cache/{:016X}", out, title_id); 140 return fmt::format("{}save/cache/{:016X}", out, title_id);
187 default: 141 default:
188 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type)); 142 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
@@ -202,7 +156,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
202SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, 156SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
203 u128 user_id) const { 157 u128 user_id) const {
204 const auto path = 158 const auto path =
205 GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 159 GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
206 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); 160 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
207 161
208 const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); 162 const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
@@ -221,7 +175,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
221void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, 175void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
222 SaveDataSize new_value) const { 176 SaveDataSize new_value) const {
223 const auto path = 177 const auto path =
224 GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 178 GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
225 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); 179 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
226 180
227 const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); 181 const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 5ab7e4d32..15dd4ec7d 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -7,6 +7,7 @@
7#include <string> 7#include <string>
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/fs_save_data_types.h"
10#include "core/file_sys/vfs/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
11#include "core/hle/result.h" 12#include "core/hle/result.h"
12 13
@@ -16,73 +17,6 @@ class System;
16 17
17namespace FileSys { 18namespace FileSys {
18 19
19enum class SaveDataSpaceId : u8 {
20 NandSystem = 0,
21 NandUser = 1,
22 SdCardSystem = 2,
23 TemporaryStorage = 3,
24 SdCardUser = 4,
25 ProperSystem = 100,
26 SafeMode = 101,
27};
28
29enum class SaveDataType : u8 {
30 SystemSaveData = 0,
31 SaveData = 1,
32 BcatDeliveryCacheStorage = 2,
33 DeviceSaveData = 3,
34 TemporaryStorage = 4,
35 CacheStorage = 5,
36 SystemBcat = 6,
37};
38
39enum class SaveDataRank : u8 {
40 Primary = 0,
41 Secondary = 1,
42};
43
44enum class SaveDataFlags : u32 {
45 None = (0 << 0),
46 KeepAfterResettingSystemSaveData = (1 << 0),
47 KeepAfterRefurbishment = (1 << 1),
48 KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
49 NeedsSecureDelete = (1 << 3),
50};
51
52struct SaveDataAttribute {
53 u64 title_id;
54 u128 user_id;
55 u64 save_id;
56 SaveDataType type;
57 SaveDataRank rank;
58 u16 index;
59 INSERT_PADDING_BYTES_NOINIT(4);
60 u64 zero_1;
61 u64 zero_2;
62 u64 zero_3;
63
64 std::string DebugInfo() const;
65};
66static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
67
68struct SaveDataExtraData {
69 SaveDataAttribute attr;
70 u64 owner_id;
71 s64 timestamp;
72 SaveDataFlags flags;
73 INSERT_PADDING_BYTES_NOINIT(4);
74 s64 available_size;
75 s64 journal_size;
76 s64 commit_id;
77 std::array<u8, 0x190> unused;
78};
79static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
80
81struct SaveDataSize {
82 u64 normal;
83 u64 journal;
84};
85
86constexpr const char* GetSaveDataSizeFileName() { 20constexpr const char* GetSaveDataSizeFileName() {
87 return ".yuzu_save_size"; 21 return ".yuzu_save_size";
88} 22}
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
index cb53b07e0..bfccb6b09 100644
--- a/src/core/hle/service/am/service/application_functions.cpp
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -123,13 +123,13 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
123 LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString()); 123 LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
124 124
125 FileSys::SaveDataAttribute attribute{}; 125 FileSys::SaveDataAttribute attribute{};
126 attribute.title_id = m_applet->program_id; 126 attribute.program_id = m_applet->program_id;
127 attribute.user_id = user_id.AsU128(); 127 attribute.user_id = user_id.AsU128();
128 attribute.type = FileSys::SaveDataType::SaveData; 128 attribute.type = FileSys::SaveDataType::Account;
129 129
130 FileSys::VirtualDir save_data{}; 130 FileSys::VirtualDir save_data{};
131 R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( 131 R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
132 &save_data, FileSys::SaveDataSpaceId::NandUser, attribute)); 132 &save_data, FileSys::SaveDataSpaceId::User, attribute));
133 133
134 *out_size = 0; 134 *out_size = 0;
135 R_SUCCEED(); 135 R_SUCCEED();
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
deleted file mode 100644
index de2aa6906..000000000
--- a/src/core/hle/service/audio/audin_u.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/in/audio_in_system.h"
5#include "audio_core/renderer/audio_device.h"
6#include "common/common_funcs.h"
7#include "common/logging/log.h"
8#include "common/scratch_buffer.h"
9#include "common/string_util.h"
10#include "core/core.h"
11#include "core/hle/kernel/k_event.h"
12#include "core/hle/service/audio/audin_u.h"
13#include "core/hle/service/ipc_helpers.h"
14
15namespace Service::Audio {
16using namespace AudioCore::AudioIn;
17
18class IAudioIn final : public ServiceFramework<IAudioIn> {
19public:
20 explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
21 const std::string& device_name, const AudioInParameter& in_params,
22 Kernel::KProcess* handle, u64 applet_resource_user_id)
23 : ServiceFramework{system_, "IAudioIn"},
24 service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")},
25 process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} {
26 // clang-format off
27 static const FunctionInfo functions[] = {
28 {0, &IAudioIn::GetAudioInState, "GetAudioInState"},
29 {1, &IAudioIn::Start, "Start"},
30 {2, &IAudioIn::Stop, "Stop"},
31 {3, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBuffer"},
32 {4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"},
33 {5, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffer"},
34 {6, &IAudioIn::ContainsAudioInBuffer, "ContainsAudioInBuffer"},
35 {7, &IAudioIn::AppendAudioInBuffer, "AppendUacInBuffer"},
36 {8, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBufferAuto"},
37 {9, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffersAuto"},
38 {10, &IAudioIn::AppendAudioInBuffer, "AppendUacInBufferAuto"},
39 {11, &IAudioIn::GetAudioInBufferCount, "GetAudioInBufferCount"},
40 {12, &IAudioIn::SetDeviceGain, "SetDeviceGain"},
41 {13, &IAudioIn::GetDeviceGain, "GetDeviceGain"},
42 {14, &IAudioIn::FlushAudioInBuffers, "FlushAudioInBuffers"},
43 };
44 // clang-format on
45
46 RegisterHandlers(functions);
47
48 process->Open();
49
50 if (impl->GetSystem()
51 .Initialize(device_name, in_params, handle, applet_resource_user_id)
52 .IsError()) {
53 LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
54 }
55 }
56
57 ~IAudioIn() override {
58 impl->Free();
59 service_context.CloseEvent(event);
60 process->Close();
61 }
62
63 [[nodiscard]] std::shared_ptr<In> GetImpl() {
64 return impl;
65 }
66
67private:
68 void GetAudioInState(HLERequestContext& ctx) {
69 const auto state = static_cast<u32>(impl->GetState());
70
71 LOG_DEBUG(Service_Audio, "called. State={}", state);
72
73 IPC::ResponseBuilder rb{ctx, 3};
74 rb.Push(ResultSuccess);
75 rb.Push(state);
76 }
77
78 void Start(HLERequestContext& ctx) {
79 LOG_DEBUG(Service_Audio, "called");
80
81 auto result = impl->StartSystem();
82
83 IPC::ResponseBuilder rb{ctx, 2};
84 rb.Push(result);
85 }
86
87 void Stop(HLERequestContext& ctx) {
88 LOG_DEBUG(Service_Audio, "called");
89
90 auto result = impl->StopSystem();
91
92 IPC::ResponseBuilder rb{ctx, 2};
93 rb.Push(result);
94 }
95
96 void AppendAudioInBuffer(HLERequestContext& ctx) {
97 IPC::RequestParser rp{ctx};
98 u64 tag = rp.PopRaw<u64>();
99
100 const auto in_buffer_size{ctx.GetReadBufferSize()};
101 if (in_buffer_size < sizeof(AudioInBuffer)) {
102 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
103 }
104
105 const auto& in_buffer = ctx.ReadBuffer();
106 AudioInBuffer buffer{};
107 std::memcpy(&buffer, in_buffer.data(), sizeof(AudioInBuffer));
108
109 [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
110 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag);
111
112 auto result = impl->AppendBuffer(buffer, tag);
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(result);
116 }
117
118 void RegisterBufferEvent(HLERequestContext& ctx) {
119 LOG_DEBUG(Service_Audio, "called");
120
121 auto& buffer_event = impl->GetBufferEvent();
122
123 IPC::ResponseBuilder rb{ctx, 2, 1};
124 rb.Push(ResultSuccess);
125 rb.PushCopyObjects(buffer_event);
126 }
127
128 void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
129 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
130 released_buffer.resize_destructive(write_buffer_size);
131 released_buffer[0] = 0;
132
133 const auto count = impl->GetReleasedBuffers(released_buffer);
134
135 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
136 impl->GetSystem().GetSessionId(), count);
137
138 ctx.WriteBuffer(released_buffer);
139
140 IPC::ResponseBuilder rb{ctx, 3};
141 rb.Push(ResultSuccess);
142 rb.Push(count);
143 }
144
145 void ContainsAudioInBuffer(HLERequestContext& ctx) {
146 IPC::RequestParser rp{ctx};
147
148 const u64 tag{rp.Pop<u64>()};
149 const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
150
151 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
152
153 IPC::ResponseBuilder rb{ctx, 3};
154 rb.Push(ResultSuccess);
155 rb.Push(buffer_queued);
156 }
157
158 void GetAudioInBufferCount(HLERequestContext& ctx) {
159 const auto buffer_count = impl->GetBufferCount();
160
161 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
162
163 IPC::ResponseBuilder rb{ctx, 3};
164 rb.Push(ResultSuccess);
165 rb.Push(buffer_count);
166 }
167
168 void SetDeviceGain(HLERequestContext& ctx) {
169 IPC::RequestParser rp{ctx};
170
171 const auto volume{rp.Pop<f32>()};
172 LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
173
174 impl->SetVolume(volume);
175
176 IPC::ResponseBuilder rb{ctx, 2};
177 rb.Push(ResultSuccess);
178 }
179
180 void GetDeviceGain(HLERequestContext& ctx) {
181 auto volume{impl->GetVolume()};
182
183 LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
184
185 IPC::ResponseBuilder rb{ctx, 3};
186 rb.Push(ResultSuccess);
187 rb.Push(volume);
188 }
189
190 void FlushAudioInBuffers(HLERequestContext& ctx) {
191 bool flushed{impl->FlushAudioInBuffers()};
192
193 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
194
195 IPC::ResponseBuilder rb{ctx, 3};
196 rb.Push(ResultSuccess);
197 rb.Push(flushed);
198 }
199
200 KernelHelpers::ServiceContext service_context;
201 Kernel::KEvent* event;
202 Kernel::KProcess* process;
203 std::shared_ptr<AudioCore::AudioIn::In> impl;
204 Common::ScratchBuffer<u64> released_buffer;
205};
206
207AudInU::AudInU(Core::System& system_)
208 : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"},
209 impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {
210 // clang-format off
211 static const FunctionInfo functions[] = {
212 {0, &AudInU::ListAudioIns, "ListAudioIns"},
213 {1, &AudInU::OpenAudioIn, "OpenAudioIn"},
214 {2, &AudInU::ListAudioIns, "ListAudioInsAuto"},
215 {3, &AudInU::OpenAudioIn, "OpenAudioInAuto"},
216 {4, &AudInU::ListAudioInsAutoFiltered, "ListAudioInsAutoFiltered"},
217 {5, &AudInU::OpenAudioInProtocolSpecified, "OpenAudioInProtocolSpecified"},
218 };
219 // clang-format on
220
221 RegisterHandlers(functions);
222}
223
224AudInU::~AudInU() = default;
225
226void AudInU::ListAudioIns(HLERequestContext& ctx) {
227 using namespace AudioCore::Renderer;
228
229 LOG_DEBUG(Service_Audio, "called");
230
231 const auto write_count =
232 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
233 std::vector<AudioDevice::AudioDeviceName> device_names{};
234
235 u32 out_count{0};
236 if (write_count > 0) {
237 out_count = impl->GetDeviceNames(device_names, write_count, false);
238 ctx.WriteBuffer(device_names);
239 }
240
241 IPC::ResponseBuilder rb{ctx, 3};
242 rb.Push(ResultSuccess);
243 rb.Push(out_count);
244}
245
246void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) {
247 using namespace AudioCore::Renderer;
248
249 LOG_DEBUG(Service_Audio, "called");
250
251 const auto write_count =
252 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
253 std::vector<AudioDevice::AudioDeviceName> device_names{};
254
255 u32 out_count{0};
256 if (write_count > 0) {
257 out_count = impl->GetDeviceNames(device_names, write_count, true);
258 ctx.WriteBuffer(device_names);
259 }
260
261 IPC::ResponseBuilder rb{ctx, 3};
262 rb.Push(ResultSuccess);
263 rb.Push(out_count);
264}
265
266void AudInU::OpenAudioIn(HLERequestContext& ctx) {
267 IPC::RequestParser rp{ctx};
268 auto in_params{rp.PopRaw<AudioInParameter>()};
269 auto applet_resource_user_id{rp.PopRaw<u64>()};
270 const auto device_name_data{ctx.ReadBuffer()};
271 auto device_name = Common::StringFromBuffer(device_name_data);
272 auto handle{ctx.GetCopyHandle(0)};
273
274 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
275 if (process.IsNull()) {
276 LOG_ERROR(Service_Audio, "Failed to get process handle");
277 IPC::ResponseBuilder rb{ctx, 2};
278 rb.Push(ResultUnknown);
279 return;
280 }
281
282 std::scoped_lock l{impl->mutex};
283 auto link{impl->LinkToManager()};
284 if (link.IsError()) {
285 LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
286 IPC::ResponseBuilder rb{ctx, 2};
287 rb.Push(link);
288 return;
289 }
290
291 size_t new_session_id{};
292 auto result{impl->AcquireSessionId(new_session_id)};
293 if (result.IsError()) {
294 IPC::ResponseBuilder rb{ctx, 2};
295 rb.Push(result);
296 return;
297 }
298
299 LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
300 impl->num_free_sessions);
301
302 auto audio_in =
303 std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
304 process.GetPointerUnsafe(), applet_resource_user_id);
305 impl->sessions[new_session_id] = audio_in->GetImpl();
306 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
307
308 auto& out_system = impl->sessions[new_session_id]->GetSystem();
309 AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
310 .channel_count = out_system.GetChannelCount(),
311 .sample_format =
312 static_cast<u32>(out_system.GetSampleFormat()),
313 .state = static_cast<u32>(out_system.GetState())};
314
315 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
316
317 std::string out_name{out_system.GetName()};
318 ctx.WriteBuffer(out_name);
319
320 rb.Push(ResultSuccess);
321 rb.PushRaw<AudioInParameterInternal>(out_params);
322 rb.PushIpcInterface<IAudioIn>(audio_in);
323}
324
325void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
326 IPC::RequestParser rp{ctx};
327 auto protocol_specified{rp.PopRaw<u64>()};
328 auto in_params{rp.PopRaw<AudioInParameter>()};
329 auto applet_resource_user_id{rp.PopRaw<u64>()};
330 const auto device_name_data{ctx.ReadBuffer()};
331 auto device_name = Common::StringFromBuffer(device_name_data);
332 auto handle{ctx.GetCopyHandle(0)};
333
334 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
335 if (process.IsNull()) {
336 LOG_ERROR(Service_Audio, "Failed to get process handle");
337 IPC::ResponseBuilder rb{ctx, 2};
338 rb.Push(ResultUnknown);
339 return;
340 }
341
342 std::scoped_lock l{impl->mutex};
343 auto link{impl->LinkToManager()};
344 if (link.IsError()) {
345 LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
346 IPC::ResponseBuilder rb{ctx, 2};
347 rb.Push(link);
348 return;
349 }
350
351 size_t new_session_id{};
352 auto result{impl->AcquireSessionId(new_session_id)};
353 if (result.IsError()) {
354 IPC::ResponseBuilder rb{ctx, 2};
355 rb.Push(result);
356 return;
357 }
358
359 LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
360 impl->num_free_sessions);
361
362 auto audio_in =
363 std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
364 process.GetPointerUnsafe(), applet_resource_user_id);
365 impl->sessions[new_session_id] = audio_in->GetImpl();
366 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
367
368 auto& out_system = impl->sessions[new_session_id]->GetSystem();
369 AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
370 .channel_count = out_system.GetChannelCount(),
371 .sample_format =
372 static_cast<u32>(out_system.GetSampleFormat()),
373 .state = static_cast<u32>(out_system.GetState())};
374
375 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
376
377 std::string out_name{out_system.GetName()};
378 if (protocol_specified == 0) {
379 if (out_system.IsUac()) {
380 out_name = "UacIn";
381 } else {
382 out_name = "DeviceIn";
383 }
384 }
385
386 ctx.WriteBuffer(out_name);
387
388 rb.Push(ResultSuccess);
389 rb.PushRaw<AudioInParameterInternal>(out_params);
390 rb.PushIpcInterface<IAudioIn>(audio_in);
391}
392
393} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
deleted file mode 100644
index 51e770ff9..000000000
--- a/src/core/hle/service/audio/audin_u.h
+++ /dev/null
@@ -1,38 +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 "audio_core/audio_in_manager.h"
7#include "audio_core/in/audio_in.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace AudioCore::AudioOut {
16class Manager;
17class In;
18} // namespace AudioCore::AudioOut
19
20namespace Service::Audio {
21
22class AudInU final : public ServiceFramework<AudInU> {
23public:
24 explicit AudInU(Core::System& system_);
25 ~AudInU() override;
26
27private:
28 void ListAudioIns(HLERequestContext& ctx);
29 void ListAudioInsAutoFiltered(HLERequestContext& ctx);
30 void OpenInOutImpl(HLERequestContext& ctx);
31 void OpenAudioIn(HLERequestContext& ctx);
32 void OpenAudioInProtocolSpecified(HLERequestContext& ctx);
33
34 KernelHelpers::ServiceContext service_context;
35 std::unique_ptr<AudioCore::AudioIn::Manager> impl;
36};
37
38} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 44af030eb..331176bf7 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -2,14 +2,14 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/core.h" 4#include "core/core.h"
5#include "core/hle/service/audio/audin_u.h"
6#include "core/hle/service/audio/audio.h" 5#include "core/hle/service/audio/audio.h"
7#include "core/hle/service/audio/audio_controller.h" 6#include "core/hle/service/audio/audio_controller.h"
8#include "core/hle/service/audio/audout_u.h" 7#include "core/hle/service/audio/audio_in_manager.h"
9#include "core/hle/service/audio/audrec_a.h" 8#include "core/hle/service/audio/audio_out_manager.h"
10#include "core/hle/service/audio/audrec_u.h" 9#include "core/hle/service/audio/audio_renderer_manager.h"
11#include "core/hle/service/audio/audren_u.h" 10#include "core/hle/service/audio/final_output_recorder_manager.h"
12#include "core/hle/service/audio/hwopus.h" 11#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
12#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
13#include "core/hle/service/server_manager.h" 13#include "core/hle/service/server_manager.h"
14#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
15 15
@@ -19,12 +19,16 @@ void LoopProcess(Core::System& system) {
19 auto server_manager = std::make_unique<ServerManager>(system); 19 auto server_manager = std::make_unique<ServerManager>(system);
20 20
21 server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system)); 21 server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
22 server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system)); 22 server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system));
23 server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system)); 23 server_manager->RegisterNamedService("audout:u", std::make_shared<IAudioOutManager>(system));
24 server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system)); 24 server_manager->RegisterNamedService(
25 server_manager->RegisterNamedService("audrec:u", std::make_shared<AudRecU>(system)); 25 "audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system));
26 server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system)); 26 server_manager->RegisterNamedService("audrec:u",
27 server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system)); 27 std::make_shared<IFinalOutputRecorderManager>(system));
28 server_manager->RegisterNamedService("audren:u",
29 std::make_shared<IAudioRendererManager>(system));
30 server_manager->RegisterNamedService("hwopus",
31 std::make_shared<IHardwareOpusDecoderManager>(system));
28 ServerManager::RunServer(std::move(server_manager)); 32 ServerManager::RunServer(std::move(server_manager));
29} 33}
30 34
diff --git a/src/core/hle/service/audio/audio_controller.cpp b/src/core/hle/service/audio/audio_controller.cpp
index a6da66d0f..c9804cf9c 100644
--- a/src/core/hle/service/audio/audio_controller.cpp
+++ b/src/core/hle/service/audio/audio_controller.cpp
@@ -16,27 +16,27 @@ IAudioController::IAudioController(Core::System& system_)
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GetTargetVolume"}, 17 {0, nullptr, "GetTargetVolume"},
18 {1, nullptr, "SetTargetVolume"}, 18 {1, nullptr, "SetTargetVolume"},
19 {2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"}, 19 {2, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
20 {3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"}, 20 {3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
21 {4, nullptr, "IsTargetMute"}, 21 {4, nullptr, "IsTargetMute"},
22 {5, nullptr, "SetTargetMute"}, 22 {5, nullptr, "SetTargetMute"},
23 {6, nullptr, "IsTargetConnected"}, 23 {6, nullptr, "IsTargetConnected"},
24 {7, nullptr, "SetDefaultTarget"}, 24 {7, nullptr, "SetDefaultTarget"},
25 {8, nullptr, "GetDefaultTarget"}, 25 {8, nullptr, "GetDefaultTarget"},
26 {9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"}, 26 {9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
27 {10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"}, 27 {10, D<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
28 {11, nullptr, "SetForceMutePolicy"}, 28 {11, nullptr, "SetForceMutePolicy"},
29 {12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"}, 29 {12, D<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
30 {13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"}, 30 {13, D<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
31 {14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"}, 31 {14, D<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
32 {15, nullptr, "SetOutputTarget"}, 32 {15, nullptr, "SetOutputTarget"},
33 {16, nullptr, "SetInputTargetForceEnabled"}, 33 {16, nullptr, "SetInputTargetForceEnabled"},
34 {17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"}, 34 {17, D<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
35 {18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"}, 35 {18, D<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
36 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"}, 36 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
37 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"}, 37 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
38 {21, nullptr, "GetAudioOutputTargetForPlayReport"}, 38 {21, nullptr, "GetAudioOutputTargetForPlayReport"},
39 {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"}, 39 {22, D<&IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent>, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
40 {23, nullptr, "SetSystemOutputMasterVolume"}, 40 {23, nullptr, "SetSystemOutputMasterVolume"},
41 {24, nullptr, "GetSystemOutputMasterVolume"}, 41 {24, nullptr, "GetSystemOutputMasterVolume"},
42 {25, nullptr, "GetAudioVolumeDataForPlayReport"}, 42 {25, nullptr, "GetAudioVolumeDataForPlayReport"},
@@ -44,11 +44,11 @@ IAudioController::IAudioController(Core::System& system_)
44 {27, nullptr, "SetVolumeMappingTableForDev"}, 44 {27, nullptr, "SetVolumeMappingTableForDev"},
45 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, 45 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
46 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, 46 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
47 {30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"}, 47 {30, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
48 {31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"}, 48 {31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
49 {32, nullptr, "GetActiveOutputTarget"}, 49 {32, nullptr, "GetActiveOutputTarget"},
50 {33, nullptr, "GetTargetDeviceInfo"}, 50 {33, nullptr, "GetTargetDeviceInfo"},
51 {34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"}, 51 {34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
52 {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, 52 {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
53 {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, 53 {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
54 {37, nullptr, "SetHearingProtectionSafeguardEnabled"}, 54 {37, nullptr, "SetHearingProtectionSafeguardEnabled"},
@@ -150,6 +150,11 @@ Result IAudioController::GetHeadphoneOutputLevelMode(
150 R_SUCCEED(); 150 R_SUCCEED();
151} 151}
152 152
153Result IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent() {
154 LOG_WARNING(Service_Audio, "(STUBBED) called");
155 R_SUCCEED();
156}
157
153Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) { 158Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
154 LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled); 159 LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
155 160
diff --git a/src/core/hle/service/audio/audio_controller.h b/src/core/hle/service/audio/audio_controller.h
index 9e8514373..d37c4843e 100644
--- a/src/core/hle/service/audio/audio_controller.h
+++ b/src/core/hle/service/audio/audio_controller.h
@@ -45,6 +45,7 @@ private:
45 Set::AudioOutputMode output_mode); 45 Set::AudioOutputMode output_mode);
46 Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode); 46 Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
47 Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode); 47 Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
48 Result NotifyHeadphoneVolumeWarningDisplayedEvent();
48 Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled); 49 Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
49 Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled); 50 Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
50 Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event); 51 Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event);
diff --git a/src/core/hle/service/audio/audio_device.cpp b/src/core/hle/service/audio/audio_device.cpp
new file mode 100644
index 000000000..438f3cccd
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.cpp
@@ -0,0 +1,163 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/audio_core.h"
5#include "common/string_util.h"
6#include "core/hle/service/audio/audio_device.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::Audio {
10using namespace AudioCore::Renderer;
11
12IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
13 u32 device_num)
14 : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
15 impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
16 event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
17 static const FunctionInfo functions[] = {
18 {0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"},
19 {1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"},
20 {2, D<&IAudioDevice::GetAudioDeviceOutputVolume>, "GetAudioDeviceOutputVolume"},
21 {3, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioDeviceName"},
22 {4, D<&IAudioDevice::QueryAudioDeviceSystemEvent>, "QueryAudioDeviceSystemEvent"},
23 {5, D<&IAudioDevice::GetActiveChannelCount>, "GetActiveChannelCount"},
24 {6, D<&IAudioDevice::ListAudioDeviceNameAuto>, "ListAudioDeviceNameAuto"},
25 {7, D<&IAudioDevice::SetAudioDeviceOutputVolumeAuto>, "SetAudioDeviceOutputVolumeAuto"},
26 {8, D<&IAudioDevice::GetAudioDeviceOutputVolumeAuto>, "GetAudioDeviceOutputVolumeAuto"},
27 {10, D<&IAudioDevice::GetActiveAudioDeviceNameAuto>, "GetActiveAudioDeviceNameAuto"},
28 {11, D<&IAudioDevice::QueryAudioDeviceInputEvent>, "QueryAudioDeviceInputEvent"},
29 {12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
30 {13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
31 {14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
32 };
33 RegisterHandlers(functions);
34
35 event->Signal();
36}
37
38IAudioDevice::~IAudioDevice() {
39 service_context.CloseEvent(event);
40}
41
42Result IAudioDevice::ListAudioDeviceName(
43 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
44 R_RETURN(this->ListAudioDeviceNameAuto(out_names, out_count));
45}
46
47Result IAudioDevice::SetAudioDeviceOutputVolume(
48 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume) {
49 R_RETURN(this->SetAudioDeviceOutputVolumeAuto(name, volume));
50}
51
52Result IAudioDevice::GetAudioDeviceOutputVolume(
53 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name) {
54 R_RETURN(this->GetAudioDeviceOutputVolumeAuto(out_volume, name));
55}
56
57Result IAudioDevice::GetActiveAudioDeviceName(
58 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name) {
59 R_RETURN(this->GetActiveAudioDeviceNameAuto(out_name));
60}
61
62Result IAudioDevice::ListAudioDeviceNameAuto(
63 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
64 Out<s32> out_count) {
65 *out_count = impl->ListAudioDeviceName(out_names);
66
67 std::string out{};
68 for (s32 i = 0; i < *out_count; i++) {
69 std::string a{};
70 u32 j = 0;
71 while (out_names[i].name[j] != '\0') {
72 a += out_names[i].name[j];
73 j++;
74 }
75 out += "\n\t" + a;
76 }
77
78 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
79 R_SUCCEED();
80}
81
82Result IAudioDevice::SetAudioDeviceOutputVolumeAuto(
83 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume) {
84 R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
85
86 const std::string device_name = Common::StringFromBuffer(name[0].name);
87 LOG_DEBUG(Service_Audio, "called. name={}, volume={}", device_name, volume);
88
89 if (device_name == "AudioTvOutput") {
90 impl->SetDeviceVolumes(volume);
91 }
92
93 R_SUCCEED();
94}
95
96Result IAudioDevice::GetAudioDeviceOutputVolumeAuto(
97 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name) {
98 R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
99
100 const std::string device_name = Common::StringFromBuffer(name[0].name);
101 LOG_DEBUG(Service_Audio, "called. Name={}", device_name);
102
103 *out_volume = 1.0f;
104 if (device_name == "AudioTvOutput") {
105 *out_volume = impl->GetDeviceVolume(device_name);
106 }
107
108 R_SUCCEED();
109}
110
111Result IAudioDevice::GetActiveAudioDeviceNameAuto(
112 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name) {
113 R_UNLESS(!out_name.empty(), Audio::ResultInsufficientBuffer);
114 out_name[0] = AudioDevice::AudioDeviceName("AudioTvOutput");
115 LOG_DEBUG(Service_Audio, "(STUBBED) called");
116 R_SUCCEED();
117}
118
119Result IAudioDevice::QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
120 LOG_DEBUG(Service_Audio, "(STUBBED) called");
121 event->Signal();
122 *out_event = &event->GetReadableEvent();
123 R_SUCCEED();
124}
125
126Result IAudioDevice::QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
127 LOG_DEBUG(Service_Audio, "(STUBBED) called");
128 *out_event = &event->GetReadableEvent();
129 R_SUCCEED();
130}
131
132Result IAudioDevice::QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
133 LOG_DEBUG(Service_Audio, "called");
134 *out_event = &event->GetReadableEvent();
135 R_SUCCEED();
136}
137
138Result IAudioDevice::GetActiveChannelCount(Out<u32> out_active_channel_count) {
139 *out_active_channel_count = system.AudioCore().GetOutputSink().GetSystemChannels();
140 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", *out_active_channel_count);
141 R_SUCCEED();
142}
143
144Result IAudioDevice::ListAudioOutputDeviceName(
145 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
146 *out_count = impl->ListAudioOutputDeviceName(out_names);
147
148 std::string out{};
149 for (s32 i = 0; i < *out_count; i++) {
150 std::string a{};
151 u32 j = 0;
152 while (out_names[i].name[j] != '\0') {
153 a += out_names[i].name[j];
154 j++;
155 }
156 out += "\n\t" + a;
157 }
158
159 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
160 R_SUCCEED();
161}
162
163} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_device.h b/src/core/hle/service/audio/audio_device.h
new file mode 100644
index 000000000..752157272
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/audio_device.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KReadableEvent;
13}
14
15namespace Service::Audio {
16
17using AudioCore::Renderer::AudioDevice;
18
19class IAudioDevice final : public ServiceFramework<IAudioDevice> {
20
21public:
22 explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
23 u32 device_num);
24 ~IAudioDevice() override;
25
26private:
27 Result ListAudioDeviceName(
28 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
29 Out<s32> out_count);
30 Result SetAudioDeviceOutputVolume(
31 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume);
32 Result GetAudioDeviceOutputVolume(
33 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name);
34 Result GetActiveAudioDeviceName(
35 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name);
36 Result ListAudioDeviceNameAuto(
37 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
38 Out<s32> out_count);
39 Result SetAudioDeviceOutputVolumeAuto(
40 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume);
41 Result GetAudioDeviceOutputVolumeAuto(
42 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name);
43 Result GetActiveAudioDeviceNameAuto(
44 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name);
45 Result QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
46 Result QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
47 Result QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
48 Result GetActiveChannelCount(Out<u32> out_active_channel_count);
49 Result ListAudioOutputDeviceName(
50 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
51 Out<s32> out_count);
52
53 KernelHelpers::ServiceContext service_context;
54 std::unique_ptr<AudioCore::Renderer::AudioDevice> impl;
55 Kernel::KEvent* event;
56};
57
58} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in.cpp b/src/core/hle/service/audio/audio_in.cpp
new file mode 100644
index 000000000..416803acc
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in.cpp
@@ -0,0 +1,146 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/audio_in.h"
5#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::Audio {
9using namespace AudioCore::AudioIn;
10
11IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
12 const std::string& device_name, const AudioInParameter& in_params,
13 Kernel::KProcess* handle, u64 applet_resource_user_id)
14 : ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
15 event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_,
16 manager, event,
17 session_id)} {
18 // clang-format off
19 static const FunctionInfo functions[] = {
20 {0, D<&IAudioIn::GetAudioInState>, "GetAudioInState"},
21 {1, D<&IAudioIn::Start>, "Start"},
22 {2, D<&IAudioIn::Stop>, "Stop"},
23 {3, D<&IAudioIn::AppendAudioInBuffer>, "AppendAudioInBuffer"},
24 {4, D<&IAudioIn::RegisterBufferEvent>, "RegisterBufferEvent"},
25 {5, D<&IAudioIn::GetReleasedAudioInBuffers>, "GetReleasedAudioInBuffers"},
26 {6, D<&IAudioIn::ContainsAudioInBuffer>, "ContainsAudioInBuffer"},
27 {7, D<&IAudioIn::AppendAudioInBuffer>, "AppendUacInBuffer"},
28 {8, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendAudioInBufferAuto"},
29 {9, D<&IAudioIn::GetReleasedAudioInBuffersAuto>, "GetReleasedAudioInBuffersAuto"},
30 {10, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendUacInBufferAuto"},
31 {11, D<&IAudioIn::GetAudioInBufferCount>, "GetAudioInBufferCount"},
32 {12, D<&IAudioIn::SetDeviceGain>, "SetDeviceGain"},
33 {13, D<&IAudioIn::GetDeviceGain>, "GetDeviceGain"},
34 {14, D<&IAudioIn::FlushAudioInBuffers>, "FlushAudioInBuffers"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39
40 process->Open();
41
42 if (impl->GetSystem()
43 .Initialize(device_name, in_params, handle, applet_resource_user_id)
44 .IsError()) {
45 LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
46 }
47}
48
49IAudioIn::~IAudioIn() {
50 impl->Free();
51 service_context.CloseEvent(event);
52 process->Close();
53}
54
55Result IAudioIn::GetAudioInState(Out<u32> out_state) {
56 *out_state = static_cast<u32>(impl->GetState());
57 LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
58 R_SUCCEED();
59}
60
61Result IAudioIn::Start() {
62 LOG_DEBUG(Service_Audio, "called");
63 R_RETURN(impl->StartSystem());
64}
65
66Result IAudioIn::Stop() {
67 LOG_DEBUG(Service_Audio, "called");
68 R_RETURN(impl->StopSystem());
69}
70
71Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
72 u64 buffer_client_ptr) {
73 R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
74}
75
76Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
77 u64 buffer_client_ptr) {
78 if (buffer.empty()) {
79 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
80 R_THROW(Audio::ResultInsufficientBuffer);
81 }
82
83 [[maybe_unused]] const auto session_id{impl->GetSystem().GetSessionId()};
84 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", session_id,
85 buffer_client_ptr);
86
87 R_RETURN(impl->AppendBuffer(buffer[0], buffer_client_ptr));
88}
89
90Result IAudioIn::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
91 LOG_DEBUG(Service_Audio, "called");
92 *out_event = &impl->GetBufferEvent();
93 R_SUCCEED();
94}
95
96Result IAudioIn::GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
97 Out<u32> out_count) {
98 R_RETURN(this->GetReleasedAudioInBuffersAuto(out_audio_buffer, out_count));
99}
100
101Result IAudioIn::GetReleasedAudioInBuffersAuto(
102 OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
103
104 if (!out_audio_buffer.empty()) {
105 out_audio_buffer[0] = 0;
106 }
107 *out_count = impl->GetReleasedBuffers(out_audio_buffer);
108
109 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
110 impl->GetSystem().GetSessionId(), *out_count);
111 R_SUCCEED();
112}
113
114Result IAudioIn::ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
115 *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
116
117 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
118 *out_contains_buffer);
119 R_SUCCEED();
120}
121
122Result IAudioIn::GetAudioInBufferCount(Out<u32> out_buffer_count) {
123 *out_buffer_count = impl->GetBufferCount();
124 LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
125 R_SUCCEED();
126}
127
128Result IAudioIn::SetDeviceGain(f32 device_gain) {
129 impl->SetVolume(device_gain);
130 LOG_DEBUG(Service_Audio, "called. Gain {}", device_gain);
131 R_SUCCEED();
132}
133
134Result IAudioIn::GetDeviceGain(Out<f32> out_device_gain) {
135 *out_device_gain = impl->GetVolume();
136 LOG_DEBUG(Service_Audio, "called. Gain {}", *out_device_gain);
137 R_SUCCEED();
138}
139
140Result IAudioIn::FlushAudioInBuffers(Out<bool> out_flushed) {
141 *out_flushed = impl->FlushAudioInBuffers();
142 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
143 R_SUCCEED();
144}
145
146} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in.h b/src/core/hle/service/audio/audio_in.h
new file mode 100644
index 000000000..3fe1e1e87
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in.h
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/in/audio_in.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13class IAudioIn final : public ServiceFramework<IAudioIn> {
14public:
15 explicit IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager,
16 size_t session_id, const std::string& device_name,
17 const AudioCore::AudioIn::AudioInParameter& in_params,
18 Kernel::KProcess* handle, u64 applet_resource_user_id);
19 ~IAudioIn() override;
20
21 std::shared_ptr<AudioCore::AudioIn::In> GetImpl() {
22 return impl;
23 }
24
25 Result GetAudioInState(Out<u32> out_state);
26 Result Start();
27 Result Stop();
28 Result AppendAudioInBuffer(
29 InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
30 u64 buffer_client_ptr);
31 Result AppendAudioInBufferAuto(
32 InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
33 u64 buffer_client_ptr);
34 Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
35 Result GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
36 Out<u32> out_count);
37 Result GetReleasedAudioInBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
38 Out<u32> out_count);
39 Result ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
40 Result GetAudioInBufferCount(Out<u32> out_buffer_count);
41 Result SetDeviceGain(f32 device_gain);
42 Result GetDeviceGain(Out<f32> out_device_gain);
43 Result FlushAudioInBuffers(Out<bool> out_flushed);
44
45private:
46 Kernel::KProcess* process;
47 KernelHelpers::ServiceContext service_context;
48 Kernel::KEvent* event;
49 std::shared_ptr<AudioCore::AudioIn::In> impl;
50 Common::ScratchBuffer<u64> released_buffer;
51};
52
53} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in_manager.cpp b/src/core/hle/service/audio/audio_in_manager.cpp
new file mode 100644
index 000000000..2675a5773
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in_manager.cpp
@@ -0,0 +1,125 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/audio/audio_in.h"
6#include "core/hle/service/audio/audio_in_manager.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::Audio {
10using namespace AudioCore::AudioIn;
11
12IAudioInManager::IAudioInManager(Core::System& system_)
13 : ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
14 system_)} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, D<&IAudioInManager::ListAudioIns>, "ListAudioIns"},
18 {1, D<&IAudioInManager::OpenAudioIn>, "OpenAudioIn"},
19 {2, D<&IAudioInManager::ListAudioIns>, "ListAudioInsAuto"},
20 {3, D<&IAudioInManager::OpenAudioIn>, "OpenAudioInAuto"},
21 {4, D<&IAudioInManager::ListAudioInsAutoFiltered>, "ListAudioInsAutoFiltered"},
22 {5, D<&IAudioInManager::OpenAudioInProtocolSpecified>, "OpenAudioInProtocolSpecified"},
23 };
24 // clang-format on
25
26 RegisterHandlers(functions);
27}
28
29IAudioInManager::~IAudioInManager() = default;
30
31Result IAudioInManager::ListAudioIns(
32 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, Out<u32> out_count) {
33 LOG_DEBUG(Service_Audio, "called");
34 R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
35}
36
37Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal,
38 Out<SharedPointer<IAudioIn>> out_audio_in,
39 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
40 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
41 AudioInParameter parameter,
42 InCopyHandle<Kernel::KProcess> process_handle,
43 ClientAppletResourceUserId aruid) {
44 LOG_DEBUG(Service_Audio, "called");
45 R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
46 name, {}, parameter, process_handle, aruid));
47}
48
49Result IAudioInManager::ListAudioInsAuto(
50 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
51 LOG_DEBUG(Service_Audio, "called");
52 R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
53}
54
55Result IAudioInManager::OpenAudioInAuto(
56 Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
57 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
58 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter,
59 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
60 LOG_DEBUG(Service_Audio, "called");
61 R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
62 name, {}, parameter, process_handle, aruid));
63}
64
65Result IAudioInManager::ListAudioInsAutoFiltered(
66 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
67 LOG_DEBUG(Service_Audio, "called");
68 *out_count = impl->GetDeviceNames(out_audio_ins, true);
69 R_SUCCEED();
70}
71
72Result IAudioInManager::OpenAudioInProtocolSpecified(
73 Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
74 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
75 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
76 AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
77 ClientAppletResourceUserId aruid) {
78 LOG_DEBUG(Service_Audio, "called");
79
80 if (!process_handle) {
81 LOG_ERROR(Service_Audio, "Failed to get process handle");
82 R_THROW(ResultUnknown);
83 }
84 if (name.empty() || out_name.empty()) {
85 LOG_ERROR(Service_Audio, "Invalid buffers");
86 R_THROW(ResultUnknown);
87 }
88
89 std::scoped_lock l{impl->mutex};
90
91 size_t new_session_id{};
92
93 R_TRY(impl->LinkToManager());
94 R_TRY(impl->AcquireSessionId(new_session_id));
95
96 LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
97 impl->num_free_sessions);
98
99 const auto device_name = Common::StringFromBuffer(name[0].name);
100 *out_audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name,
101 parameter, process_handle.Get(), aruid.pid);
102 impl->sessions[new_session_id] = (*out_audio_in)->GetImpl();
103 impl->applet_resource_user_ids[new_session_id] = aruid.pid;
104
105 auto& out_system = impl->sessions[new_session_id]->GetSystem();
106 *out_parameter_internal =
107 AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
108 .channel_count = out_system.GetChannelCount(),
109 .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
110 .state = static_cast<u32>(out_system.GetState())};
111
112 out_name[0] = AudioDeviceName(out_system.GetName());
113
114 if (protocol == Protocol{}) {
115 if (out_system.IsUac()) {
116 out_name[0] = AudioDeviceName("UacIn");
117 } else {
118 out_name[0] = AudioDeviceName("DeviceIn");
119 }
120 }
121
122 R_SUCCEED();
123}
124
125} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in_manager.h b/src/core/hle/service/audio/audio_in_manager.h
new file mode 100644
index 000000000..2a983bc60
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in_manager.h
@@ -0,0 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_in_manager.h"
7#include "audio_core/in/audio_in_system.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
14using Protocol = std::array<u32, 2>;
15
16class IAudioIn;
17
18class IAudioInManager final : public ServiceFramework<IAudioInManager> {
19public:
20 explicit IAudioInManager(Core::System& system_);
21 ~IAudioInManager() override;
22
23private:
24 Result ListAudioIns(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins,
25 Out<u32> out_count);
26 Result OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
27 Out<SharedPointer<IAudioIn>> out_audio_in,
28 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
29 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
30 AudioCore::AudioIn::AudioInParameter parameter,
31 InCopyHandle<Kernel::KProcess> process_handle,
32 ClientAppletResourceUserId aruid);
33
34 Result ListAudioInsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins,
35 Out<u32> out_count);
36 Result OpenAudioInAuto(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
37 Out<SharedPointer<IAudioIn>> out_audio_in,
38 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
39 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
40 AudioCore::AudioIn::AudioInParameter parameter,
41 InCopyHandle<Kernel::KProcess> process_handle,
42 ClientAppletResourceUserId aruid);
43
44 Result ListAudioInsAutoFiltered(
45 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count);
46 Result OpenAudioInProtocolSpecified(
47 Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
48 Out<SharedPointer<IAudioIn>> out_audio_in,
49 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
50 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
51 AudioCore::AudioIn::AudioInParameter parameter,
52 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
53
54 std::unique_ptr<AudioCore::AudioIn::Manager> impl;
55};
56
57} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out.cpp b/src/core/hle/service/audio/audio_out.cpp
new file mode 100644
index 000000000..53009d5d7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out.cpp
@@ -0,0 +1,146 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/out/audio_out.h"
5#include "audio_core/out/audio_out_system.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/service/audio/audio_out.h"
8#include "core/hle/service/cmif_serialization.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h"
11
12namespace Service::Audio {
13using namespace AudioCore::AudioOut;
14
15IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
16 const std::string& device_name, const AudioOutParameter& in_params,
17 Kernel::KProcess* handle, u64 applet_resource_user_id)
18 : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
19 event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
20 impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
21
22 // clang-format off
23 static const FunctionInfo functions[] = {
24 {0, D<&IAudioOut::GetAudioOutState>, "GetAudioOutState"},
25 {1, D<&IAudioOut::Start>, "Start"},
26 {2, D<&IAudioOut::Stop>, "Stop"},
27 {3, D<&IAudioOut::AppendAudioOutBuffer>, "AppendAudioOutBuffer"},
28 {4, D<&IAudioOut::RegisterBufferEvent>, "RegisterBufferEvent"},
29 {5, D<&IAudioOut::GetReleasedAudioOutBuffers>, "GetReleasedAudioOutBuffers"},
30 {6, D<&IAudioOut::ContainsAudioOutBuffer>, "ContainsAudioOutBuffer"},
31 {7, D<&IAudioOut::AppendAudioOutBufferAuto>, "AppendAudioOutBufferAuto"},
32 {8, D<&IAudioOut::GetReleasedAudioOutBuffersAuto>, "GetReleasedAudioOutBuffersAuto"},
33 {9, D<&IAudioOut::GetAudioOutBufferCount>, "GetAudioOutBufferCount"},
34 {10, D<&IAudioOut::GetAudioOutPlayedSampleCount>, "GetAudioOutPlayedSampleCount"},
35 {11, D<&IAudioOut::FlushAudioOutBuffers>, "FlushAudioOutBuffers"},
36 {12, D<&IAudioOut::SetAudioOutVolume>, "SetAudioOutVolume"},
37 {13, D<&IAudioOut::GetAudioOutVolume>, "GetAudioOutVolume"},
38 };
39 // clang-format on
40 RegisterHandlers(functions);
41
42 process->Open();
43}
44
45IAudioOut::~IAudioOut() {
46 impl->Free();
47 service_context.CloseEvent(event);
48 process->Close();
49}
50
51Result IAudioOut::GetAudioOutState(Out<u32> out_state) {
52 *out_state = static_cast<u32>(impl->GetState());
53 LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
54 R_SUCCEED();
55}
56
57Result IAudioOut::Start() {
58 LOG_DEBUG(Service_Audio, "called");
59 R_RETURN(impl->StartSystem());
60}
61
62Result IAudioOut::Stop() {
63 LOG_DEBUG(Service_Audio, "called");
64 R_RETURN(impl->StopSystem());
65}
66
67Result IAudioOut::AppendAudioOutBuffer(
68 InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
69 R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
70}
71
72Result IAudioOut::AppendAudioOutBufferAuto(
73 InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
74 if (audio_out_buffer.empty()) {
75 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
76 R_THROW(Audio::ResultInsufficientBuffer);
77 }
78
79 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
80 impl->GetSystem().GetSessionId(), buffer_client_ptr);
81 R_RETURN(impl->AppendBuffer(audio_out_buffer[0], buffer_client_ptr));
82}
83
84Result IAudioOut::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
85 LOG_DEBUG(Service_Audio, "called");
86 *out_event = &impl->GetBufferEvent();
87 R_SUCCEED();
88}
89
90Result IAudioOut::GetReleasedAudioOutBuffers(
91 OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, Out<u32> out_count) {
92 R_RETURN(this->GetReleasedAudioOutBuffersAuto(out_audio_buffer, out_count));
93}
94
95Result IAudioOut::GetReleasedAudioOutBuffersAuto(
96 OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
97
98 if (!out_audio_buffer.empty()) {
99 out_audio_buffer[0] = 0;
100 }
101 *out_count = impl->GetReleasedBuffers(out_audio_buffer);
102
103 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
104 impl->GetSystem().GetSessionId(), *out_count);
105 R_SUCCEED();
106}
107
108Result IAudioOut::ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
109 *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
110
111 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
112 *out_contains_buffer);
113 R_SUCCEED();
114}
115
116Result IAudioOut::GetAudioOutBufferCount(Out<u32> out_buffer_count) {
117 *out_buffer_count = impl->GetBufferCount();
118 LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
119 R_SUCCEED();
120}
121
122Result IAudioOut::GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count) {
123 *out_played_sample_count = impl->GetPlayedSampleCount();
124 LOG_DEBUG(Service_Audio, "called. Played samples={}", *out_played_sample_count);
125 R_SUCCEED();
126}
127
128Result IAudioOut::FlushAudioOutBuffers(Out<bool> out_flushed) {
129 *out_flushed = impl->FlushAudioOutBuffers();
130 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
131 R_SUCCEED();
132}
133
134Result IAudioOut::SetAudioOutVolume(f32 volume) {
135 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
136 impl->SetVolume(volume);
137 R_SUCCEED();
138}
139
140Result IAudioOut::GetAudioOutVolume(Out<f32> out_volume) {
141 *out_volume = impl->GetVolume();
142 LOG_DEBUG(Service_Audio, "called. Volume={}", *out_volume);
143 R_SUCCEED();
144}
145
146} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out.h b/src/core/hle/service/audio/audio_out.h
new file mode 100644
index 000000000..779b213e7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out_system.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h"
11
12namespace Kernel {
13class KReadableEvent;
14}
15
16namespace Service::Audio {
17
18class IAudioOut : public ServiceFramework<IAudioOut> {
19public:
20 explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
21 size_t session_id, const std::string& device_name,
22 const AudioCore::AudioOut::AudioOutParameter& in_params,
23 Kernel::KProcess* handle, u64 applet_resource_user_id);
24 ~IAudioOut() override;
25
26 std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
27 return impl;
28 }
29
30 Result GetAudioOutState(Out<u32> out_state);
31 Result Start();
32 Result Stop();
33 Result AppendAudioOutBuffer(
34 InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer,
35 u64 buffer_client_ptr);
36 Result AppendAudioOutBufferAuto(
37 InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer,
38 u64 buffer_client_ptr);
39 Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
40 Result GetReleasedAudioOutBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
41 Out<u32> out_count);
42 Result GetReleasedAudioOutBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
43 Out<u32> out_count);
44 Result ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
45 Result GetAudioOutBufferCount(Out<u32> out_buffer_count);
46 Result GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count);
47 Result FlushAudioOutBuffers(Out<bool> out_flushed);
48 Result SetAudioOutVolume(f32 volume);
49 Result GetAudioOutVolume(Out<f32> out_volume);
50
51private:
52 KernelHelpers::ServiceContext service_context;
53 Kernel::KEvent* event;
54 Kernel::KProcess* process;
55 std::shared_ptr<AudioCore::AudioOut::Out> impl;
56};
57
58} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out_manager.cpp b/src/core/hle/service/audio/audio_out_manager.cpp
new file mode 100644
index 000000000..153445097
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out_manager.cpp
@@ -0,0 +1,101 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/audio/audio_out.h"
6#include "core/hle/service/audio/audio_out_manager.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/memory.h"
9
10namespace Service::Audio {
11using namespace AudioCore::AudioOut;
12
13IAudioOutManager::IAudioOutManager(Core::System& system_)
14 : ServiceFramework{system_, "audout:u"}, impl{std::make_unique<Manager>(system_)} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"},
18 {1, D<&IAudioOutManager::OpenAudioOut>, "OpenAudioOut"},
19 {2, D<&IAudioOutManager::ListAudioOutsAuto>, "ListAudioOutsAuto"},
20 {3, D<&IAudioOutManager::OpenAudioOutAuto>, "OpenAudioOutAuto"},
21 };
22 // clang-format on
23
24 RegisterHandlers(functions);
25}
26
27IAudioOutManager::~IAudioOutManager() = default;
28
29Result IAudioOutManager::ListAudioOuts(
30 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, Out<u32> out_count) {
31 R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
32}
33
34Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal,
35 Out<SharedPointer<IAudioOut>> out_audio_out,
36 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
37 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
38 AudioOutParameter parameter,
39 InCopyHandle<Kernel::KProcess> process_handle,
40 ClientAppletResourceUserId aruid) {
41 R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
42 parameter, process_handle, aruid));
43}
44
45Result IAudioOutManager::ListAudioOutsAuto(
46 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, Out<u32> out_count) {
47 if (!out_audio_outs.empty()) {
48 out_audio_outs[0] = AudioDeviceName("DeviceOut");
49 *out_count = 1;
50 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
51 } else {
52 *out_count = 0;
53 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
54 }
55
56 R_SUCCEED();
57}
58
59Result IAudioOutManager::OpenAudioOutAuto(
60 Out<AudioOutParameterInternal> out_parameter_internal,
61 Out<SharedPointer<IAudioOut>> out_audio_out,
62 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
63 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter,
64 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
65 if (!process_handle) {
66 LOG_ERROR(Service_Audio, "Failed to get process handle");
67 R_THROW(ResultUnknown);
68 }
69 if (name.empty() || out_name.empty()) {
70 LOG_ERROR(Service_Audio, "Invalid buffers");
71 R_THROW(ResultUnknown);
72 }
73
74 size_t new_session_id{};
75 R_TRY(impl->LinkToManager());
76 R_TRY(impl->AcquireSessionId(new_session_id));
77
78 const auto device_name = Common::StringFromBuffer(name[0].name);
79 LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
80 impl->num_free_sessions);
81
82 auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name,
83 parameter, process_handle.Get(), aruid.pid);
84 R_TRY(audio_out->GetImpl()->GetSystem().Initialize(device_name, parameter, process_handle.Get(),
85 aruid.pid));
86
87 *out_audio_out = audio_out;
88 impl->sessions[new_session_id] = audio_out->GetImpl();
89 impl->applet_resource_user_ids[new_session_id] = aruid.pid;
90
91 auto& out_system = impl->sessions[new_session_id]->GetSystem();
92 *out_parameter_internal =
93 AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
94 .channel_count = out_system.GetChannelCount(),
95 .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
96 .state = static_cast<u32>(out_system.GetState())};
97
98 R_SUCCEED();
99}
100
101} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out_manager.h b/src/core/hle/service/audio/audio_out_manager.h
new file mode 100644
index 000000000..eaa27bc79
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out_manager.h
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
14class IAudioOut;
15
16class IAudioOutManager final : public ServiceFramework<IAudioOutManager> {
17public:
18 explicit IAudioOutManager(Core::System& system_);
19 ~IAudioOutManager() override;
20
21private:
22 Result ListAudioOuts(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs,
23 Out<u32> out_count);
24 Result OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
25 Out<SharedPointer<IAudioOut>> out_audio_out,
26 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
27 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
28 AudioCore::AudioOut::AudioOutParameter parameter,
29 InCopyHandle<Kernel::KProcess> process_handle,
30 ClientAppletResourceUserId aruid);
31 Result ListAudioOutsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs,
32 Out<u32> out_count);
33 Result OpenAudioOutAuto(
34 Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
35 Out<SharedPointer<IAudioOut>> out_audio_out,
36 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
37 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
38 AudioCore::AudioOut::AudioOutParameter parameter,
39 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
40
41 std::unique_ptr<AudioCore::AudioOut::Manager> impl;
42};
43
44} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.cpp b/src/core/hle/service/audio/audio_renderer.cpp
new file mode 100644
index 000000000..fc4aad233
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.cpp
@@ -0,0 +1,139 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/audio_renderer.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::Audio {
8using namespace AudioCore::Renderer;
9
10IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_,
11 AudioCore::AudioRendererParameterInternal& params,
12 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
13 Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
14 s32 session_id)
15 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
16 rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
17 impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{
18 process_handle_} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
22 {1, D<&IAudioRenderer::GetSampleCount>, "GetSampleCount"},
23 {2, D<&IAudioRenderer::GetMixBufferCount>, "GetMixBufferCount"},
24 {3, D<&IAudioRenderer::GetState>, "GetState"},
25 {4, D<&IAudioRenderer::RequestUpdate>, "RequestUpdate"},
26 {5, D<&IAudioRenderer::Start>, "Start"},
27 {6, D<&IAudioRenderer::Stop>, "Stop"},
28 {7, D<&IAudioRenderer::QuerySystemEvent>, "QuerySystemEvent"},
29 {8, D<&IAudioRenderer::SetRenderingTimeLimit>, "SetRenderingTimeLimit"},
30 {9, D<&IAudioRenderer::GetRenderingTimeLimit>, "GetRenderingTimeLimit"},
31 {10, D<&IAudioRenderer::RequestUpdateAuto>, "RequestUpdateAuto"},
32 {11, nullptr, "ExecuteAudioRendererRendering"},
33 {12, D<&IAudioRenderer::SetVoiceDropParameter>, "SetVoiceDropParameter"},
34 {13, D<&IAudioRenderer::GetVoiceDropParameter>, "GetVoiceDropParameter"},
35 };
36 // clang-format on
37 RegisterHandlers(functions);
38
39 process_handle->Open();
40 impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle,
41 applet_resource_user_id, session_id);
42}
43
44IAudioRenderer::~IAudioRenderer() {
45 impl->Finalize();
46 service_context.CloseEvent(rendered_event);
47 process_handle->Close();
48}
49
50Result IAudioRenderer::GetSampleRate(Out<u32> out_sample_rate) {
51 *out_sample_rate = impl->GetSystem().GetSampleRate();
52 LOG_DEBUG(Service_Audio, "called. Sample rate {}", *out_sample_rate);
53 R_SUCCEED();
54}
55
56Result IAudioRenderer::GetSampleCount(Out<u32> out_sample_count) {
57 *out_sample_count = impl->GetSystem().GetSampleCount();
58 LOG_DEBUG(Service_Audio, "called. Sample count {}", *out_sample_count);
59 R_SUCCEED();
60}
61
62Result IAudioRenderer::GetState(Out<u32> out_state) {
63 *out_state = !impl->GetSystem().IsActive();
64 LOG_DEBUG(Service_Audio, "called, state {}", *out_state);
65 R_SUCCEED();
66}
67
68Result IAudioRenderer::GetMixBufferCount(Out<u32> out_mix_buffer_count) {
69 LOG_DEBUG(Service_Audio, "called");
70 *out_mix_buffer_count = impl->GetSystem().GetMixBufferCount();
71 R_SUCCEED();
72}
73
74Result IAudioRenderer::RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
75 OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
76 InBuffer<BufferAttr_HipcMapAlias> input) {
77 R_RETURN(this->RequestUpdateAuto(out_buffer, out_performance_buffer, input));
78}
79
80Result IAudioRenderer::RequestUpdateAuto(
81 OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
82 OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
83 InBuffer<BufferAttr_HipcAutoSelect> input) {
84 LOG_TRACE(Service_Audio, "called");
85
86 const auto result = impl->RequestUpdate(input, out_performance_buffer, out_buffer);
87 if (result.IsFailure()) {
88 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.GetDescription());
89 }
90
91 R_RETURN(result);
92}
93
94Result IAudioRenderer::Start() {
95 LOG_DEBUG(Service_Audio, "called");
96 impl->Start();
97 R_SUCCEED();
98}
99
100Result IAudioRenderer::Stop() {
101 LOG_DEBUG(Service_Audio, "called");
102 impl->Stop();
103 R_SUCCEED();
104}
105
106Result IAudioRenderer::QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
107 LOG_DEBUG(Service_Audio, "called");
108 R_UNLESS(impl->GetSystem().GetExecutionMode() != AudioCore::ExecutionMode::Manual,
109 Audio::ResultNotSupported);
110 *out_event = &rendered_event->GetReadableEvent();
111 R_SUCCEED();
112}
113
114Result IAudioRenderer::SetRenderingTimeLimit(u32 rendering_time_limit) {
115 LOG_DEBUG(Service_Audio, "called");
116 impl->GetSystem().SetRenderingTimeLimit(rendering_time_limit);
117 ;
118 R_SUCCEED();
119}
120
121Result IAudioRenderer::GetRenderingTimeLimit(Out<u32> out_rendering_time_limit) {
122 LOG_DEBUG(Service_Audio, "called");
123 *out_rendering_time_limit = impl->GetSystem().GetRenderingTimeLimit();
124 R_SUCCEED();
125}
126
127Result IAudioRenderer::SetVoiceDropParameter(f32 voice_drop_parameter) {
128 LOG_DEBUG(Service_Audio, "called");
129 impl->GetSystem().SetVoiceDropParameter(voice_drop_parameter);
130 R_SUCCEED();
131}
132
133Result IAudioRenderer::GetVoiceDropParameter(Out<f32> out_voice_drop_parameter) {
134 LOG_DEBUG(Service_Audio, "called");
135 *out_voice_drop_parameter = impl->GetSystem().GetVoiceDropParameter();
136 R_SUCCEED();
137}
138
139} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.h b/src/core/hle/service/audio/audio_renderer.h
new file mode 100644
index 000000000..f25c50ce8
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.h
@@ -0,0 +1,54 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/audio_renderer.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KReadableEvent;
13}
14
15namespace Service::Audio {
16
17class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
18public:
19 explicit IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
20 AudioCore::AudioRendererParameterInternal& params,
21 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
22 Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
23 s32 session_id);
24 ~IAudioRenderer() override;
25
26private:
27 Result GetSampleRate(Out<u32> out_sample_rate);
28 Result GetSampleCount(Out<u32> out_sample_count);
29 Result GetState(Out<u32> out_state);
30 Result GetMixBufferCount(Out<u32> out_mix_buffer_count);
31 Result RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
32 OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
33 InBuffer<BufferAttr_HipcMapAlias> input);
34 Result RequestUpdateAuto(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
35 OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
36 InBuffer<BufferAttr_HipcAutoSelect> input);
37 Result Start();
38 Result Stop();
39 Result QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
40 Result SetRenderingTimeLimit(u32 rendering_time_limit);
41 Result GetRenderingTimeLimit(Out<u32> out_rendering_time_limit);
42 Result SetVoiceDropParameter(f32 voice_drop_parameter);
43 Result GetVoiceDropParameter(Out<f32> out_voice_drop_parameter);
44
45 KernelHelpers::ServiceContext service_context;
46 Kernel::KEvent* rendered_event;
47 AudioCore::Renderer::Manager& manager;
48 std::unique_ptr<AudioCore::Renderer::Renderer> impl;
49 Kernel::KProcess* process_handle;
50 Common::ScratchBuffer<u8> output_buffer;
51 Common::ScratchBuffer<u8> performance_buffer;
52};
53
54} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.cpp b/src/core/hle/service/audio/audio_renderer_manager.cpp
new file mode 100644
index 000000000..6a1345c07
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.cpp
@@ -0,0 +1,104 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/audio_render_manager.h"
5#include "audio_core/common/feature_support.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/k_transfer_memory.h"
8#include "core/hle/service/audio/audio_device.h"
9#include "core/hle/service/audio/audio_renderer.h"
10#include "core/hle/service/audio/audio_renderer_manager.h"
11#include "core/hle/service/cmif_serialization.h"
12
13namespace Service::Audio {
14
15using namespace AudioCore::Renderer;
16
17IAudioRendererManager::IAudioRendererManager(Core::System& system_)
18 : ServiceFramework{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"},
22 {1, D<&IAudioRendererManager::GetWorkBufferSize>, "GetWorkBufferSize"},
23 {2, D<&IAudioRendererManager::GetAudioDeviceService>, "GetAudioDeviceService"},
24 {3, nullptr, "OpenAudioRendererForManualExecution"},
25 {4, D<&IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo>, "GetAudioDeviceServiceWithRevisionInfo"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IAudioRendererManager::~IAudioRendererManager() = default;
33
34Result IAudioRendererManager::OpenAudioRenderer(
35 Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
36 AudioCore::AudioRendererParameterInternal parameter,
37 InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
38 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
39 LOG_DEBUG(Service_Audio, "called");
40
41 if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
42 LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
43 R_THROW(Audio::ResultOutOfSessions);
44 }
45
46 const auto session_id{impl->GetSessionId()};
47 if (session_id == -1) {
48 LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
49 R_THROW(Audio::ResultOutOfSessions);
50 }
51
52 LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
53 impl->GetSessionCount());
54
55 *out_audio_renderer =
56 std::make_shared<IAudioRenderer>(system, *impl, parameter, tmem_handle.Get(), tmem_size,
57 process_handle.Get(), aruid.pid, session_id);
58 R_SUCCEED();
59}
60
61Result IAudioRendererManager::GetWorkBufferSize(Out<u64> out_size,
62 AudioCore::AudioRendererParameterInternal params) {
63 LOG_DEBUG(Service_Audio, "called");
64
65 R_TRY(impl->GetWorkBufferSize(params, *out_size))
66
67 std::string output_info{};
68 output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
69 output_info +=
70 fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
71 output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
72 static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
73 output_info += fmt::format(
74 "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
75 "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
76 "Context {:04X}",
77 params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
78 params.splitter_destinations, params.voices, params.perf_frames,
79 params.external_context_size);
80
81 LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
82 output_info, *out_size);
83 R_SUCCEED();
84}
85
86Result IAudioRendererManager::GetAudioDeviceService(
87 Out<SharedPointer<IAudioDevice>> out_audio_device, ClientAppletResourceUserId aruid) {
88 LOG_DEBUG(Service_Audio, "called, aruid={:#x}", aruid.pid);
89 *out_audio_device = std::make_shared<IAudioDevice>(
90 system, aruid.pid, Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
91 R_SUCCEED();
92}
93
94Result IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo(
95 Out<SharedPointer<IAudioDevice>> out_audio_device, u32 revision,
96 ClientAppletResourceUserId aruid) {
97 LOG_DEBUG(Service_Audio, "called, revision={} aruid={:#x}", AudioCore::GetRevisionNum(revision),
98 aruid.pid);
99 *out_audio_device =
100 std::make_shared<IAudioDevice>(system, aruid.pid, revision, num_audio_devices++);
101 R_SUCCEED();
102}
103
104} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.h b/src/core/hle/service/audio/audio_renderer_manager.h
new file mode 100644
index 000000000..69eee664c
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.h
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_render_manager.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IAudioDevice;
13class IAudioRenderer;
14
15class IAudioRendererManager final : public ServiceFramework<IAudioRendererManager> {
16public:
17 explicit IAudioRendererManager(Core::System& system_);
18 ~IAudioRendererManager() override;
19
20private:
21 Result OpenAudioRenderer(Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
22 AudioCore::AudioRendererParameterInternal parameter,
23 InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
24 InCopyHandle<Kernel::KProcess> process_handle,
25 ClientAppletResourceUserId aruid);
26 Result GetWorkBufferSize(Out<u64> out_size,
27 AudioCore::AudioRendererParameterInternal parameter);
28 Result GetAudioDeviceService(Out<SharedPointer<IAudioDevice>> out_audio_device,
29 ClientAppletResourceUserId aruid);
30 Result GetAudioDeviceServiceWithRevisionInfo(Out<SharedPointer<IAudioDevice>> out_audio_device,
31 u32 revision, ClientAppletResourceUserId aruid);
32
33 std::unique_ptr<AudioCore::Renderer::Manager> impl;
34 u32 num_audio_devices{0};
35};
36
37} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
deleted file mode 100644
index 8cc7b69f4..000000000
--- a/src/core/hle/service/audio/audout_u.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <cstring>
6#include <vector>
7
8#include "audio_core/out/audio_out_system.h"
9#include "audio_core/renderer/audio_device.h"
10#include "common/common_funcs.h"
11#include "common/logging/log.h"
12#include "common/scratch_buffer.h"
13#include "common/string_util.h"
14#include "common/swap.h"
15#include "core/core.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/service/audio/audout_u.h"
18#include "core/hle/service/audio/errors.h"
19#include "core/hle/service/ipc_helpers.h"
20#include "core/memory.h"
21
22namespace Service::Audio {
23using namespace AudioCore::AudioOut;
24
25class IAudioOut final : public ServiceFramework<IAudioOut> {
26public:
27 explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
28 size_t session_id, const std::string& device_name,
29 const AudioOutParameter& in_params, Kernel::KProcess* handle,
30 u64 applet_resource_user_id)
31 : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
32 event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
33 impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
34
35 // clang-format off
36 static const FunctionInfo functions[] = {
37 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
38 {1, &IAudioOut::Start, "Start"},
39 {2, &IAudioOut::Stop, "Stop"},
40 {3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"},
41 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
42 {5, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffers"},
43 {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
44 {7, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBufferAuto"},
45 {8, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffersAuto"},
46 {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
47 {10, &IAudioOut::GetAudioOutPlayedSampleCount, "GetAudioOutPlayedSampleCount"},
48 {11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"},
49 {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"},
50 {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"},
51 };
52 // clang-format on
53 RegisterHandlers(functions);
54
55 process->Open();
56 }
57
58 ~IAudioOut() override {
59 impl->Free();
60 service_context.CloseEvent(event);
61 process->Close();
62 }
63
64 [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
65 return impl;
66 }
67
68private:
69 void GetAudioOutState(HLERequestContext& ctx) {
70 const auto state = static_cast<u32>(impl->GetState());
71
72 LOG_DEBUG(Service_Audio, "called. State={}", state);
73
74 IPC::ResponseBuilder rb{ctx, 3};
75 rb.Push(ResultSuccess);
76 rb.Push(state);
77 }
78
79 void Start(HLERequestContext& ctx) {
80 LOG_DEBUG(Service_Audio, "called");
81
82 auto result = impl->StartSystem();
83
84 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(result);
86 }
87
88 void Stop(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_Audio, "called");
90
91 auto result = impl->StopSystem();
92
93 IPC::ResponseBuilder rb{ctx, 2};
94 rb.Push(result);
95 }
96
97 void AppendAudioOutBuffer(HLERequestContext& ctx) {
98 IPC::RequestParser rp{ctx};
99 u64 tag = rp.PopRaw<u64>();
100
101 const auto in_buffer_size{ctx.GetReadBufferSize()};
102 if (in_buffer_size < sizeof(AudioOutBuffer)) {
103 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
104 }
105
106 const auto& in_buffer = ctx.ReadBuffer();
107 AudioOutBuffer buffer{};
108 std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer));
109
110 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
111 impl->GetSystem().GetSessionId(), tag);
112
113 auto result = impl->AppendBuffer(buffer, tag);
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(result);
117 }
118
119 void RegisterBufferEvent(HLERequestContext& ctx) {
120 LOG_DEBUG(Service_Audio, "called");
121
122 auto& buffer_event = impl->GetBufferEvent();
123
124 IPC::ResponseBuilder rb{ctx, 2, 1};
125 rb.Push(ResultSuccess);
126 rb.PushCopyObjects(buffer_event);
127 }
128
129 void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
130 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
131 released_buffer.resize_destructive(write_buffer_size);
132 released_buffer[0] = 0;
133
134 const auto count = impl->GetReleasedBuffers(released_buffer);
135
136 ctx.WriteBuffer(released_buffer);
137
138 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
139 impl->GetSystem().GetSessionId(), count);
140
141 IPC::ResponseBuilder rb{ctx, 3};
142 rb.Push(ResultSuccess);
143 rb.Push(count);
144 }
145
146 void ContainsAudioOutBuffer(HLERequestContext& ctx) {
147 IPC::RequestParser rp{ctx};
148
149 const u64 tag{rp.Pop<u64>()};
150 const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
151
152 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
153
154 IPC::ResponseBuilder rb{ctx, 3};
155 rb.Push(ResultSuccess);
156 rb.Push(buffer_queued);
157 }
158
159 void GetAudioOutBufferCount(HLERequestContext& ctx) {
160 const auto buffer_count = impl->GetBufferCount();
161
162 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
163
164 IPC::ResponseBuilder rb{ctx, 3};
165 rb.Push(ResultSuccess);
166 rb.Push(buffer_count);
167 }
168
169 void GetAudioOutPlayedSampleCount(HLERequestContext& ctx) {
170 const auto samples_played = impl->GetPlayedSampleCount();
171
172 LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
173
174 IPC::ResponseBuilder rb{ctx, 4};
175 rb.Push(ResultSuccess);
176 rb.Push(samples_played);
177 }
178
179 void FlushAudioOutBuffers(HLERequestContext& ctx) {
180 bool flushed{impl->FlushAudioOutBuffers()};
181
182 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
183
184 IPC::ResponseBuilder rb{ctx, 3};
185 rb.Push(ResultSuccess);
186 rb.Push(flushed);
187 }
188
189 void SetAudioOutVolume(HLERequestContext& ctx) {
190 IPC::RequestParser rp{ctx};
191 const auto volume = rp.Pop<f32>();
192
193 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
194
195 impl->SetVolume(volume);
196
197 IPC::ResponseBuilder rb{ctx, 2};
198 rb.Push(ResultSuccess);
199 }
200
201 void GetAudioOutVolume(HLERequestContext& ctx) {
202 const auto volume = impl->GetVolume();
203
204 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
205
206 IPC::ResponseBuilder rb{ctx, 3};
207 rb.Push(ResultSuccess);
208 rb.Push(volume);
209 }
210
211 KernelHelpers::ServiceContext service_context;
212 Kernel::KEvent* event;
213 Kernel::KProcess* process;
214 std::shared_ptr<AudioCore::AudioOut::Out> impl;
215 Common::ScratchBuffer<u64> released_buffer;
216};
217
218AudOutU::AudOutU(Core::System& system_)
219 : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"},
220 impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} {
221 // clang-format off
222 static const FunctionInfo functions[] = {
223 {0, &AudOutU::ListAudioOuts, "ListAudioOuts"},
224 {1, &AudOutU::OpenAudioOut, "OpenAudioOut"},
225 {2, &AudOutU::ListAudioOuts, "ListAudioOutsAuto"},
226 {3, &AudOutU::OpenAudioOut, "OpenAudioOutAuto"},
227 };
228 // clang-format on
229
230 RegisterHandlers(functions);
231}
232
233AudOutU::~AudOutU() = default;
234
235void AudOutU::ListAudioOuts(HLERequestContext& ctx) {
236 using namespace AudioCore::Renderer;
237
238 std::scoped_lock l{impl->mutex};
239
240 const auto write_count =
241 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
242 std::vector<AudioDevice::AudioDeviceName> device_names{};
243 if (write_count > 0) {
244 device_names.emplace_back("DeviceOut");
245 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
246 } else {
247 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
248 }
249
250 ctx.WriteBuffer(device_names);
251
252 IPC::ResponseBuilder rb{ctx, 3};
253 rb.Push(ResultSuccess);
254 rb.Push<u32>(static_cast<u32>(device_names.size()));
255}
256
257void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
258 IPC::RequestParser rp{ctx};
259 auto in_params{rp.PopRaw<AudioOutParameter>()};
260 auto applet_resource_user_id{rp.PopRaw<u64>()};
261 const auto device_name_data{ctx.ReadBuffer()};
262 auto device_name = Common::StringFromBuffer(device_name_data);
263 auto handle{ctx.GetCopyHandle(0)};
264
265 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
266 if (process.IsNull()) {
267 LOG_ERROR(Service_Audio, "Failed to get process handle");
268 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(ResultUnknown);
270 return;
271 }
272
273 auto link{impl->LinkToManager()};
274 if (link.IsError()) {
275 LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager");
276 IPC::ResponseBuilder rb{ctx, 2};
277 rb.Push(link);
278 return;
279 }
280
281 size_t new_session_id{};
282 auto result{impl->AcquireSessionId(new_session_id)};
283 if (result.IsError()) {
284 IPC::ResponseBuilder rb{ctx, 2};
285 rb.Push(result);
286 return;
287 }
288
289 LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
290 impl->num_free_sessions);
291
292 auto audio_out =
293 std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params,
294 process.GetPointerUnsafe(), applet_resource_user_id);
295 result = audio_out->GetImpl()->GetSystem().Initialize(
296 device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id);
297 if (result.IsError()) {
298 LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
299 IPC::ResponseBuilder rb{ctx, 2};
300 rb.Push(result);
301 return;
302 }
303
304 impl->sessions[new_session_id] = audio_out->GetImpl();
305 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
306
307 auto& out_system = impl->sessions[new_session_id]->GetSystem();
308 AudioOutParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
309 .channel_count = out_system.GetChannelCount(),
310 .sample_format =
311 static_cast<u32>(out_system.GetSampleFormat()),
312 .state = static_cast<u32>(out_system.GetState())};
313
314 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
315
316 ctx.WriteBuffer(out_system.GetName());
317
318 rb.Push(ResultSuccess);
319 rb.PushRaw<AudioOutParameterInternal>(out_params);
320 rb.PushIpcInterface<IAudioOut>(audio_out);
321}
322
323} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
deleted file mode 100644
index 8f288c6e0..000000000
--- a/src/core/hle/service/audio/audout_u.h
+++ /dev/null
@@ -1,37 +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 "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace AudioCore::AudioOut {
16class Manager;
17class Out;
18} // namespace AudioCore::AudioOut
19
20namespace Service::Audio {
21
22class IAudioOut;
23
24class AudOutU final : public ServiceFramework<AudOutU> {
25public:
26 explicit AudOutU(Core::System& system_);
27 ~AudOutU() override;
28
29private:
30 void ListAudioOuts(HLERequestContext& ctx);
31 void OpenAudioOut(HLERequestContext& ctx);
32
33 KernelHelpers::ServiceContext service_context;
34 std::unique_ptr<AudioCore::AudioOut::Manager> impl;
35};
36
37} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
deleted file mode 100644
index 10108abc0..000000000
--- a/src/core/hle/service/audio/audren_u.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <memory>
6
7#include "audio_core/audio_core.h"
8#include "audio_core/common/audio_renderer_parameter.h"
9#include "audio_core/common/feature_support.h"
10#include "audio_core/renderer/audio_device.h"
11#include "audio_core/renderer/audio_renderer.h"
12#include "audio_core/renderer/voice/voice_info.h"
13#include "common/alignment.h"
14#include "common/bit_util.h"
15#include "common/common_funcs.h"
16#include "common/logging/log.h"
17#include "common/polyfill_ranges.h"
18#include "common/scratch_buffer.h"
19#include "common/string_util.h"
20#include "core/core.h"
21#include "core/hle/kernel/k_event.h"
22#include "core/hle/kernel/k_process.h"
23#include "core/hle/kernel/k_transfer_memory.h"
24#include "core/hle/service/audio/audren_u.h"
25#include "core/hle/service/audio/errors.h"
26#include "core/hle/service/ipc_helpers.h"
27#include "core/memory.h"
28
29using namespace AudioCore::Renderer;
30
31namespace Service::Audio {
32
33class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
34public:
35 explicit IAudioRenderer(Core::System& system_, Manager& manager_,
36 AudioCore::AudioRendererParameterInternal& params,
37 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
38 u32 process_handle, Kernel::KProcess& process_,
39 u64 applet_resource_user_id, s32 session_id)
40 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
41 rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
42 impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} {
43 // clang-format off
44 static const FunctionInfo functions[] = {
45 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
46 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
47 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
48 {3, &IAudioRenderer::GetState, "GetState"},
49 {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
50 {5, &IAudioRenderer::Start, "Start"},
51 {6, &IAudioRenderer::Stop, "Stop"},
52 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
53 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
54 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
55 {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"},
56 {11, nullptr, "ExecuteAudioRendererRendering"},
57 {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"},
58 {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"},
59 };
60 // clang-format on
61 RegisterHandlers(functions);
62
63 process.Open();
64 impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
65 applet_resource_user_id, session_id);
66 }
67
68 ~IAudioRenderer() override {
69 impl->Finalize();
70 service_context.CloseEvent(rendered_event);
71 process.Close();
72 }
73
74private:
75 void GetSampleRate(HLERequestContext& ctx) {
76 const auto sample_rate{impl->GetSystem().GetSampleRate()};
77
78 LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate);
79
80 IPC::ResponseBuilder rb{ctx, 3};
81 rb.Push(ResultSuccess);
82 rb.Push(sample_rate);
83 }
84
85 void GetSampleCount(HLERequestContext& ctx) {
86 const auto sample_count{impl->GetSystem().GetSampleCount()};
87
88 LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count);
89
90 IPC::ResponseBuilder rb{ctx, 3};
91 rb.Push(ResultSuccess);
92 rb.Push(sample_count);
93 }
94
95 void GetState(HLERequestContext& ctx) {
96 const u32 state{!impl->GetSystem().IsActive()};
97
98 LOG_DEBUG(Service_Audio, "called, state {}", state);
99
100 IPC::ResponseBuilder rb{ctx, 3};
101 rb.Push(ResultSuccess);
102 rb.Push(state);
103 }
104
105 void GetMixBufferCount(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_Audio, "called");
107
108 const auto buffer_count{impl->GetSystem().GetMixBufferCount()};
109
110 IPC::ResponseBuilder rb{ctx, 3};
111 rb.Push(ResultSuccess);
112 rb.Push(buffer_count);
113 }
114
115 void RequestUpdate(HLERequestContext& ctx) {
116 LOG_TRACE(Service_Audio, "called");
117
118 const auto input{ctx.ReadBuffer(0)};
119
120 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
121 // checking size 0. Performance size is 0 for most games.
122
123 auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
124 if (is_buffer_b) {
125 const auto buffersB{ctx.BufferDescriptorB()};
126 output_buffer.resize_destructive(buffersB[0].Size());
127 performance_buffer.resize_destructive(buffersB[1].Size());
128 } else {
129 const auto buffersC{ctx.BufferDescriptorC()};
130 output_buffer.resize_destructive(buffersC[0].Size());
131 performance_buffer.resize_destructive(buffersC[1].Size());
132 }
133
134 auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
135
136 if (result.IsSuccess()) {
137 if (is_buffer_b) {
138 ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
139 ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
140 } else {
141 ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
142 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
143 }
144 } else {
145 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!",
146 result.GetDescription());
147 }
148
149 IPC::ResponseBuilder rb{ctx, 2};
150 rb.Push(result);
151 }
152
153 void Start(HLERequestContext& ctx) {
154 LOG_DEBUG(Service_Audio, "called");
155
156 impl->Start();
157
158 IPC::ResponseBuilder rb{ctx, 2};
159 rb.Push(ResultSuccess);
160 }
161
162 void Stop(HLERequestContext& ctx) {
163 LOG_DEBUG(Service_Audio, "called");
164
165 impl->Stop();
166
167 IPC::ResponseBuilder rb{ctx, 2};
168 rb.Push(ResultSuccess);
169 }
170
171 void QuerySystemEvent(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Audio, "called");
173
174 if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) {
175 IPC::ResponseBuilder rb{ctx, 2};
176 rb.Push(Audio::ResultNotSupported);
177 return;
178 }
179
180 IPC::ResponseBuilder rb{ctx, 2, 1};
181 rb.Push(ResultSuccess);
182 rb.PushCopyObjects(rendered_event->GetReadableEvent());
183 }
184
185 void SetRenderingTimeLimit(HLERequestContext& ctx) {
186 LOG_DEBUG(Service_Audio, "called");
187
188 IPC::RequestParser rp{ctx};
189 auto limit = rp.PopRaw<u32>();
190
191 auto& system_ = impl->GetSystem();
192 system_.SetRenderingTimeLimit(limit);
193
194 IPC::ResponseBuilder rb{ctx, 2};
195 rb.Push(ResultSuccess);
196 }
197
198 void GetRenderingTimeLimit(HLERequestContext& ctx) {
199 LOG_DEBUG(Service_Audio, "called");
200
201 auto& system_ = impl->GetSystem();
202 auto time = system_.GetRenderingTimeLimit();
203
204 IPC::ResponseBuilder rb{ctx, 3};
205 rb.Push(ResultSuccess);
206 rb.Push(time);
207 }
208
209 void ExecuteAudioRendererRendering(HLERequestContext& ctx) {
210 LOG_DEBUG(Service_Audio, "called");
211 }
212
213 void SetVoiceDropParameter(HLERequestContext& ctx) {
214 LOG_DEBUG(Service_Audio, "called");
215
216 IPC::RequestParser rp{ctx};
217 auto voice_drop_param{rp.Pop<f32>()};
218
219 auto& system_ = impl->GetSystem();
220 system_.SetVoiceDropParameter(voice_drop_param);
221
222 IPC::ResponseBuilder rb{ctx, 2};
223 rb.Push(ResultSuccess);
224 }
225
226 void GetVoiceDropParameter(HLERequestContext& ctx) {
227 LOG_DEBUG(Service_Audio, "called");
228
229 auto& system_ = impl->GetSystem();
230 auto voice_drop_param{system_.GetVoiceDropParameter()};
231
232 IPC::ResponseBuilder rb{ctx, 3};
233 rb.Push(ResultSuccess);
234 rb.Push(voice_drop_param);
235 }
236
237 KernelHelpers::ServiceContext service_context;
238 Kernel::KEvent* rendered_event;
239 Manager& manager;
240 std::unique_ptr<Renderer> impl;
241 Kernel::KProcess& process;
242 Common::ScratchBuffer<u8> output_buffer;
243 Common::ScratchBuffer<u8> performance_buffer;
244};
245
246class IAudioDevice final : public ServiceFramework<IAudioDevice> {
247
248public:
249 explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
250 u32 device_num)
251 : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
252 impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
253 event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
254 static const FunctionInfo functions[] = {
255 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
256 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
257 {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
258 {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
259 {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
260 {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
261 {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
262 {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
263 {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
264 {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
265 {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
266 {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
267 {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"},
268 {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"},
269 };
270 RegisterHandlers(functions);
271
272 event->Signal();
273 }
274
275 ~IAudioDevice() override {
276 service_context.CloseEvent(event);
277 }
278
279private:
280 void ListAudioDeviceName(HLERequestContext& ctx) {
281 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
282
283 std::vector<AudioDevice::AudioDeviceName> out_names{};
284
285 const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
286
287 std::string out{};
288 for (u32 i = 0; i < out_count; i++) {
289 std::string a{};
290 u32 j = 0;
291 while (out_names[i].name[j] != '\0') {
292 a += out_names[i].name[j];
293 j++;
294 }
295 out += "\n\t" + a;
296 }
297
298 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
299
300 IPC::ResponseBuilder rb{ctx, 3};
301
302 ctx.WriteBuffer(out_names);
303
304 rb.Push(ResultSuccess);
305 rb.Push(out_count);
306 }
307
308 void SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
309 IPC::RequestParser rp{ctx};
310 const f32 volume = rp.Pop<f32>();
311
312 const auto device_name_buffer = ctx.ReadBuffer();
313 const std::string name = Common::StringFromBuffer(device_name_buffer);
314
315 LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume);
316
317 if (name == "AudioTvOutput") {
318 impl->SetDeviceVolumes(volume);
319 }
320
321 IPC::ResponseBuilder rb{ctx, 2};
322 rb.Push(ResultSuccess);
323 }
324
325 void GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
326 const auto device_name_buffer = ctx.ReadBuffer();
327 const std::string name = Common::StringFromBuffer(device_name_buffer);
328
329 LOG_DEBUG(Service_Audio, "called. Name={}", name);
330
331 f32 volume{1.0f};
332 if (name == "AudioTvOutput") {
333 volume = impl->GetDeviceVolume(name);
334 }
335
336 IPC::ResponseBuilder rb{ctx, 3};
337 rb.Push(ResultSuccess);
338 rb.Push(volume);
339 }
340
341 void GetActiveAudioDeviceName(HLERequestContext& ctx) {
342 const auto write_size = ctx.GetWriteBufferSize();
343 std::string out_name{"AudioTvOutput"};
344
345 LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);
346
347 out_name.resize(write_size);
348
349 ctx.WriteBuffer(out_name);
350
351 IPC::ResponseBuilder rb{ctx, 2};
352 rb.Push(ResultSuccess);
353 }
354
355 void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
356 LOG_DEBUG(Service_Audio, "(STUBBED) called");
357
358 event->Signal();
359
360 IPC::ResponseBuilder rb{ctx, 2, 1};
361 rb.Push(ResultSuccess);
362 rb.PushCopyObjects(event->GetReadableEvent());
363 }
364
365 void GetActiveChannelCount(HLERequestContext& ctx) {
366 const auto& sink{system.AudioCore().GetOutputSink()};
367 u32 channel_count{sink.GetSystemChannels()};
368
369 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);
370
371 IPC::ResponseBuilder rb{ctx, 3};
372
373 rb.Push(ResultSuccess);
374 rb.Push<u32>(channel_count);
375 }
376
377 void QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
378 LOG_DEBUG(Service_Audio, "(STUBBED) called");
379
380 IPC::ResponseBuilder rb{ctx, 2, 1};
381 rb.Push(ResultSuccess);
382 rb.PushCopyObjects(event->GetReadableEvent());
383 }
384
385 void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
386 LOG_DEBUG(Service_Audio, "called");
387
388 IPC::ResponseBuilder rb{ctx, 2, 1};
389 rb.Push(ResultSuccess);
390 rb.PushCopyObjects(event->GetReadableEvent());
391 }
392
393 void ListAudioOutputDeviceName(HLERequestContext& ctx) {
394 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
395
396 std::vector<AudioDevice::AudioDeviceName> out_names{};
397
398 const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
399
400 std::string out{};
401 for (u32 i = 0; i < out_count; i++) {
402 std::string a{};
403 u32 j = 0;
404 while (out_names[i].name[j] != '\0') {
405 a += out_names[i].name[j];
406 j++;
407 }
408 out += "\n\t" + a;
409 }
410
411 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
412
413 IPC::ResponseBuilder rb{ctx, 3};
414
415 ctx.WriteBuffer(out_names);
416
417 rb.Push(ResultSuccess);
418 rb.Push(out_count);
419 }
420
421 KernelHelpers::ServiceContext service_context;
422 std::unique_ptr<AudioDevice> impl;
423 Kernel::KEvent* event;
424};
425
426AudRenU::AudRenU(Core::System& system_)
427 : ServiceFramework{system_, "audren:u"},
428 service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
429 // clang-format off
430 static const FunctionInfo functions[] = {
431 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
432 {1, &AudRenU::GetWorkBufferSize, "GetWorkBufferSize"},
433 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
434 {3, nullptr, "OpenAudioRendererForManualExecution"},
435 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
436 };
437 // clang-format on
438
439 RegisterHandlers(functions);
440}
441
442AudRenU::~AudRenU() = default;
443
444void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
445 IPC::RequestParser rp{ctx};
446
447 AudioCore::AudioRendererParameterInternal params;
448 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
449 rp.Skip(1, false);
450 auto transfer_memory_size = rp.Pop<u64>();
451 auto applet_resource_user_id = rp.Pop<u64>();
452 auto transfer_memory_handle = ctx.GetCopyHandle(0);
453 auto process_handle = ctx.GetCopyHandle(1);
454
455 if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
456 LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
457 IPC::ResponseBuilder rb{ctx, 2};
458 rb.Push(Audio::ResultOutOfSessions);
459 return;
460 }
461
462 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()};
463 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
464
465 const auto session_id{impl->GetSessionId()};
466 if (session_id == -1) {
467 LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
468 IPC::ResponseBuilder rb{ctx, 2};
469 rb.Push(Audio::ResultOutOfSessions);
470 return;
471 }
472
473 LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
474 impl->GetSessionCount());
475
476 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
477 rb.Push(ResultSuccess);
478 rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(),
479 transfer_memory_size, process_handle, *process,
480 applet_resource_user_id, session_id);
481}
482
483void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) {
484 AudioCore::AudioRendererParameterInternal params;
485
486 IPC::RequestParser rp{ctx};
487 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
488
489 u64 size{0};
490 auto result = impl->GetWorkBufferSize(params, size);
491
492 std::string output_info{};
493 output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
494 output_info +=
495 fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
496 output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
497 static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
498 output_info += fmt::format(
499 "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
500 "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
501 "Context {:04X}",
502 params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
503 params.splitter_destinations, params.voices, params.perf_frames,
504 params.external_context_size);
505
506 LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
507 output_info, size);
508
509 IPC::ResponseBuilder rb{ctx, 4};
510 rb.Push(result);
511 rb.Push<u64>(size);
512}
513
514void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) {
515 IPC::RequestParser rp{ctx};
516
517 const auto applet_resource_user_id = rp.Pop<u64>();
518
519 LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id);
520
521 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
522
523 rb.Push(ResultSuccess);
524 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id,
525 ::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
526}
527
528void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) {
529 LOG_ERROR(Service_Audio, "called. Implement me!");
530}
531
532void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) {
533 struct Parameters {
534 u32 revision;
535 u64 applet_resource_user_id;
536 };
537
538 IPC::RequestParser rp{ctx};
539
540 const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>();
541
542 LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}",
543 AudioCore::GetRevisionNum(revision), applet_resource_user_id);
544
545 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
546
547 rb.Push(ResultSuccess);
548 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision,
549 num_audio_devices++);
550}
551
552} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
deleted file mode 100644
index 3d7993a16..000000000
--- a/src/core/hle/service/audio/audren_u.h
+++ /dev/null
@@ -1,35 +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 "audio_core/audio_render_manager.h"
7#include "common/scratch_buffer.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::Audio {
16class IAudioRenderer;
17
18class AudRenU final : public ServiceFramework<AudRenU> {
19public:
20 explicit AudRenU(Core::System& system_);
21 ~AudRenU() override;
22
23private:
24 void OpenAudioRenderer(HLERequestContext& ctx);
25 void GetWorkBufferSize(HLERequestContext& ctx);
26 void GetAudioDeviceService(HLERequestContext& ctx);
27 void OpenAudioRendererForManualExecution(HLERequestContext& ctx);
28 void GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx);
29
30 KernelHelpers::ServiceContext service_context;
31 std::unique_ptr<AudioCore::Renderer::Manager> impl;
32 u32 num_audio_devices{0};
33};
34
35} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/final_output_recorder_manager.cpp
index bc55cec17..f70a0e62d 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/final_output_recorder_manager.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/audio/audrec_u.h" 4#include "core/hle/service/audio/final_output_recorder_manager.h"
5 5
6namespace Service::Audio { 6namespace Service::Audio {
7 7
@@ -30,13 +30,14 @@ public:
30 } 30 }
31}; 31};
32 32
33AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} { 33IFinalOutputRecorderManager::IFinalOutputRecorderManager(Core::System& system_)
34 : ServiceFramework{system_, "audrec:u"} {
34 static const FunctionInfo functions[] = { 35 static const FunctionInfo functions[] = {
35 {0, nullptr, "OpenFinalOutputRecorder"}, 36 {0, nullptr, "OpenFinalOutputRecorder"},
36 }; 37 };
37 RegisterHandlers(functions); 38 RegisterHandlers(functions);
38} 39}
39 40
40AudRecU::~AudRecU() = default; 41IFinalOutputRecorderManager::~IFinalOutputRecorderManager() = default;
41 42
42} // namespace Service::Audio 43} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/final_output_recorder_manager.h
index 9edf89f6c..0663b894e 100644
--- a/src/core/hle/service/audio/audrec_a.h
+++ b/src/core/hle/service/audio/final_output_recorder_manager.h
@@ -11,10 +11,10 @@ class System;
11 11
12namespace Service::Audio { 12namespace Service::Audio {
13 13
14class AudRecA final : public ServiceFramework<AudRecA> { 14class IFinalOutputRecorderManager final : public ServiceFramework<IFinalOutputRecorderManager> {
15public: 15public:
16 explicit AudRecA(Core::System& system_); 16 explicit IFinalOutputRecorderManager(Core::System& system_);
17 ~AudRecA() override; 17 ~IFinalOutputRecorderManager() override;
18}; 18};
19 19
20} // namespace Service::Audio 20} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
index fa82e9ac7..7e2e42bbe 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
@@ -1,11 +1,12 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/audio/audrec_a.h" 4#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
5 5
6namespace Service::Audio { 6namespace Service::Audio {
7 7
8AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} { 8IFinalOutputRecorderManagerForApplet::IFinalOutputRecorderManagerForApplet(Core::System& system_)
9 : ServiceFramework{system_, "audrec:a"} {
9 // clang-format off 10 // clang-format off
10 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
11 {0, nullptr, "RequestSuspend"}, 12 {0, nullptr, "RequestSuspend"},
@@ -16,6 +17,6 @@ AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"}
16 RegisterHandlers(functions); 17 RegisterHandlers(functions);
17} 18}
18 19
19AudRecA::~AudRecA() = default; 20IFinalOutputRecorderManagerForApplet::~IFinalOutputRecorderManagerForApplet() = default;
20 21
21} // namespace Service::Audio 22} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
index 8b4817884..27940f7e0 100644
--- a/src/core/hle/service/audio/audrec_u.h
+++ b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
@@ -11,10 +11,11 @@ class System;
11 11
12namespace Service::Audio { 12namespace Service::Audio {
13 13
14class AudRecU final : public ServiceFramework<AudRecU> { 14class IFinalOutputRecorderManagerForApplet final
15 : public ServiceFramework<IFinalOutputRecorderManagerForApplet> {
15public: 16public:
16 explicit AudRecU(Core::System& system_); 17 explicit IFinalOutputRecorderManagerForApplet(Core::System& system_);
17 ~AudRecU() override; 18 ~IFinalOutputRecorderManagerForApplet() override;
18}; 19};
19 20
20} // namespace Service::Audio 21} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder.cpp b/src/core/hle/service/audio/hardware_opus_decoder.cpp
new file mode 100644
index 000000000..03d3374c1
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder.cpp
@@ -0,0 +1,145 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/hardware_opus_decoder.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::Audio {
8
9using namespace AudioCore::OpusDecoder;
10
11IHardwareOpusDecoder::IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
12 : ServiceFramework{system_, "IHardwareOpusDecoder"},
13 impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IHardwareOpusDecoder::DecodeInterleavedOld>, "DecodeInterleavedOld"},
17 {1, D<&IHardwareOpusDecoder::SetContext>, "SetContext"},
18 {2, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld>, "DecodeInterleavedForMultiStreamOld"},
19 {3, D<&IHardwareOpusDecoder::SetContextForMultiStream>, "SetContextForMultiStream"},
20 {4, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfOld>, "DecodeInterleavedWithPerfOld"},
21 {5, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld>, "DecodeInterleavedForMultiStreamWithPerfOld"},
22 {6, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld>, "DecodeInterleavedWithPerfAndResetOld"},
23 {7, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld>, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
24 {8, D<&IHardwareOpusDecoder::DecodeInterleaved>, "DecodeInterleaved"},
25 {9, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStream>, "DecodeInterleavedForMultiStream"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IHardwareOpusDecoder::~IHardwareOpusDecoder() = default;
33
34Result IHardwareOpusDecoder::Initialize(const OpusParametersEx& params,
35 Kernel::KTransferMemory* transfer_memory,
36 u64 transfer_memory_size) {
37 return impl->Initialize(params, transfer_memory, transfer_memory_size);
38}
39
40Result IHardwareOpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
41 Kernel::KTransferMemory* transfer_memory,
42 u64 transfer_memory_size) {
43 return impl->Initialize(params, transfer_memory, transfer_memory_size);
44}
45
46Result IHardwareOpusDecoder::DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
47 Out<u32> out_data_size, Out<u32> out_sample_count,
48 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
49 R_TRY(impl->DecodeInterleaved(out_data_size, nullptr, out_sample_count, opus_data, out_pcm_data,
50 false));
51 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
52 *out_sample_count);
53 R_SUCCEED();
54}
55
56Result IHardwareOpusDecoder::SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
57 LOG_DEBUG(Service_Audio, "called");
58 R_RETURN(impl->SetContext(decoder_context));
59}
60
61Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld(
62 OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, Out<u32> out_data_size,
63 Out<u32> out_sample_count, InBuffer<BufferAttr_HipcMapAlias> opus_data) {
64 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, nullptr, out_sample_count, opus_data,
65 out_pcm_data, false));
66 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
67 *out_sample_count);
68 R_SUCCEED();
69}
70
71Result IHardwareOpusDecoder::SetContextForMultiStream(
72 InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
73 LOG_DEBUG(Service_Audio, "called");
74 R_RETURN(impl->SetContext(decoder_context));
75}
76
77Result IHardwareOpusDecoder::DecodeInterleavedWithPerfOld(
78 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
79 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
80 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
81 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
82 out_pcm_data, false));
83 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
84 *out_sample_count, *out_time_taken);
85 R_SUCCEED();
86}
87
88Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld(
89 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
90 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
91 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
92 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
93 opus_data, out_pcm_data, false));
94 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
95 *out_sample_count, *out_time_taken);
96 R_SUCCEED();
97}
98
99Result IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld(
100 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
101 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
102 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
103 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
104 out_pcm_data, reset));
105 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
106 *out_data_size, *out_sample_count, *out_time_taken);
107 R_SUCCEED();
108}
109
110Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld(
111 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
112 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
113 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
114 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
115 opus_data, out_pcm_data, reset));
116 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
117 *out_data_size, *out_sample_count, *out_time_taken);
118 R_SUCCEED();
119}
120
121Result IHardwareOpusDecoder::DecodeInterleaved(
122 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
123 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
124 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
125 bool reset) {
126 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
127 out_pcm_data, reset));
128 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
129 *out_data_size, *out_sample_count, *out_time_taken);
130 R_SUCCEED();
131}
132
133Result IHardwareOpusDecoder::DecodeInterleavedForMultiStream(
134 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
135 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
136 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
137 bool reset) {
138 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
139 opus_data, out_pcm_data, reset));
140 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
141 *out_data_size, *out_sample_count, *out_time_taken);
142 R_SUCCEED();
143}
144
145} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder.h b/src/core/hle/service/audio/hardware_opus_decoder.h
new file mode 100644
index 000000000..511bf46bd
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder.h
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/opus/decoder.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
13public:
14 explicit IHardwareOpusDecoder(Core::System& system_,
15 AudioCore::OpusDecoder::HardwareOpus& hardware_opus);
16 ~IHardwareOpusDecoder() override;
17
18 Result Initialize(const AudioCore::OpusDecoder::OpusParametersEx& params,
19 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
20 Result Initialize(const AudioCore::OpusDecoder::OpusMultiStreamParametersEx& params,
21 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
22
23private:
24 Result DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
25 Out<u32> out_data_size, Out<u32> out_sample_count,
26 InBuffer<BufferAttr_HipcMapAlias> opus_data);
27 Result SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
28 Result DecodeInterleavedForMultiStreamOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
29 Out<u32> out_data_size, Out<u32> out_sample_count,
30 InBuffer<BufferAttr_HipcMapAlias> opus_data);
31 Result SetContextForMultiStream(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
32 Result DecodeInterleavedWithPerfOld(
33 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
34 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
35 InBuffer<BufferAttr_HipcMapAlias> opus_data);
36 Result DecodeInterleavedForMultiStreamWithPerfOld(
37 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
38 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
39 InBuffer<BufferAttr_HipcMapAlias> opus_data);
40 Result DecodeInterleavedWithPerfAndResetOld(
41 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
42 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
43 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
44 Result DecodeInterleavedForMultiStreamWithPerfAndResetOld(
45 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
46 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
47 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
48 Result DecodeInterleaved(
49 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
50 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
51 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
52 bool reset);
53 Result DecodeInterleavedForMultiStream(
54 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
55 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
56 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
57 bool reset);
58
59 std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
60 Common::ScratchBuffer<u8> output_data;
61};
62
63} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp b/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
new file mode 100644
index 000000000..9de72e30f
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
@@ -0,0 +1,156 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/hardware_opus_decoder.h"
5#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
6#include "core/hle/service/cmif_serialization.h"
7
8namespace Service::Audio {
9
10using namespace AudioCore::OpusDecoder;
11
12IHardwareOpusDecoderManager::IHardwareOpusDecoderManager(Core::System& system_)
13 : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoder>, "OpenHardwareOpusDecoder"},
17 {1, D<&IHardwareOpusDecoderManager::GetWorkBufferSize>, "GetWorkBufferSize"},
18 {2, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream>, "OpenOpusDecoderForMultiStream"},
19 {3, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream>, "GetWorkBufferSizeForMultiStream"},
20 {4, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx>, "OpenHardwareOpusDecoderEx"},
21 {5, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeEx>, "GetWorkBufferSizeEx"},
22 {6, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx>, "OpenHardwareOpusDecoderForMultiStreamEx"},
23 {7, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx>, "GetWorkBufferSizeForMultiStreamEx"},
24 {8, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeExEx>, "GetWorkBufferSizeExEx"},
25 {9, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx>, "GetWorkBufferSizeForMultiStreamExEx"},
26 };
27 // clang-format on
28 RegisterHandlers(functions);
29}
30
31IHardwareOpusDecoderManager::~IHardwareOpusDecoderManager() = default;
32
33Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoder(
34 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParameters params, u32 tmem_size,
35 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
36 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
37 params.sample_rate, params.channel_count, tmem_size);
38
39 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
40 OpusParametersEx ex{
41 .sample_rate = params.sample_rate,
42 .channel_count = params.channel_count,
43 .use_large_frame_size = false,
44 };
45 R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
46
47 *out_decoder = decoder;
48 R_SUCCEED();
49}
50
51Result IHardwareOpusDecoderManager::GetWorkBufferSize(Out<u32> out_size, OpusParameters params) {
52 R_TRY(impl.GetWorkBufferSize(params, *out_size));
53 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size {:#x}",
54 params.sample_rate, params.channel_count, *out_size);
55 R_SUCCEED();
56}
57
58Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream(
59 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
60 InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
61 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
62 LOG_DEBUG(Service_Audio,
63 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
64 "transfer_memory_size {:#x}",
65 params->sample_rate, params->channel_count, params->total_stream_count,
66 params->stereo_stream_count, tmem_size);
67
68 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
69
70 OpusMultiStreamParametersEx ex{
71 .sample_rate = params->sample_rate,
72 .channel_count = params->channel_count,
73 .total_stream_count = params->total_stream_count,
74 .stereo_stream_count = params->stereo_stream_count,
75 .use_large_frame_size = false,
76 .mappings{},
77 };
78 std::memcpy(ex.mappings.data(), params->mappings.data(), sizeof(params->mappings));
79 R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
80
81 *out_decoder = decoder;
82 R_SUCCEED();
83}
84
85Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream(
86 Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params) {
87 R_TRY(impl.GetWorkBufferSizeForMultiStream(*params, *out_size));
88 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
89 R_SUCCEED();
90}
91
92Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx(
93 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParametersEx params, u32 tmem_size,
94 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
95 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
96 params.sample_rate, params.channel_count, tmem_size);
97
98 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
99 R_TRY(decoder->Initialize(params, tmem_handle.Get(), tmem_size));
100
101 *out_decoder = decoder;
102 R_SUCCEED();
103}
104
105Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(Out<u32> out_size,
106 OpusParametersEx params) {
107 R_TRY(impl.GetWorkBufferSizeEx(params, *out_size));
108 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
109 R_SUCCEED();
110}
111
112Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx(
113 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
114 InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
115 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
116 LOG_DEBUG(Service_Audio,
117 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
118 "use_large_frame_size {}"
119 "transfer_memory_size {:#x}",
120 params->sample_rate, params->channel_count, params->total_stream_count,
121 params->stereo_stream_count, params->use_large_frame_size, tmem_size);
122
123 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
124
125 R_TRY(decoder->Initialize(*params, tmem_handle.Get(), tmem_size));
126
127 *out_decoder = decoder;
128 R_SUCCEED();
129}
130
131Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
132 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
133 R_TRY(impl.GetWorkBufferSizeForMultiStreamEx(*params, *out_size));
134 LOG_DEBUG(Service_Audio,
135 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
136 "use_large_frame_size {} -- returned size {:#x}",
137 params->sample_rate, params->channel_count, params->total_stream_count,
138 params->stereo_stream_count, params->use_large_frame_size, *out_size);
139 R_SUCCEED();
140}
141
142Result IHardwareOpusDecoderManager::GetWorkBufferSizeExEx(Out<u32> out_size,
143 OpusParametersEx params) {
144 R_TRY(impl.GetWorkBufferSizeExEx(params, *out_size));
145 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
146 R_SUCCEED();
147}
148
149Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
150 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
151 R_TRY(impl.GetWorkBufferSizeForMultiStreamExEx(*params, *out_size));
152 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
153 R_SUCCEED();
154}
155
156} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder_manager.h b/src/core/hle/service/audio/hardware_opus_decoder_manager.h
new file mode 100644
index 000000000..4f869c517
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder_manager.h
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/opus/decoder_manager.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IHardwareOpusDecoder;
13
14using AudioCore::OpusDecoder::OpusMultiStreamParameters;
15using AudioCore::OpusDecoder::OpusMultiStreamParametersEx;
16using AudioCore::OpusDecoder::OpusParameters;
17using AudioCore::OpusDecoder::OpusParametersEx;
18
19class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
20public:
21 explicit IHardwareOpusDecoderManager(Core::System& system_);
22 ~IHardwareOpusDecoderManager() override;
23
24private:
25 Result OpenHardwareOpusDecoder(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
26 OpusParameters params, u32 tmem_size,
27 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
28 Result GetWorkBufferSize(Out<u32> out_size, OpusParameters params);
29 Result OpenHardwareOpusDecoderForMultiStream(
30 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
31 InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
32 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
33 Result GetWorkBufferSizeForMultiStream(
34 Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params);
35 Result OpenHardwareOpusDecoderEx(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
36 OpusParametersEx params, u32 tmem_size,
37 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
38 Result GetWorkBufferSizeEx(Out<u32> out_size, OpusParametersEx params);
39 Result OpenHardwareOpusDecoderForMultiStreamEx(
40 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
41 InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
42 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
43 Result GetWorkBufferSizeForMultiStreamEx(
44 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
45 Result GetWorkBufferSizeExEx(Out<u32> out_size, OpusParametersEx params);
46 Result GetWorkBufferSizeForMultiStreamExEx(
47 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
48
49 Core::System& system;
50 AudioCore::OpusDecoder::OpusDecoderManager impl;
51};
52
53} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
deleted file mode 100644
index 91f33aabd..000000000
--- a/src/core/hle/service/audio/hwopus.cpp
+++ /dev/null
@@ -1,502 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <memory>
5#include <vector>
6
7#include "audio_core/opus/decoder.h"
8#include "audio_core/opus/parameters.h"
9#include "common/assert.h"
10#include "common/logging/log.h"
11#include "common/scratch_buffer.h"
12#include "core/core.h"
13#include "core/hle/service/audio/hwopus.h"
14#include "core/hle/service/ipc_helpers.h"
15
16namespace Service::Audio {
17using namespace AudioCore::OpusDecoder;
18
19class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
20public:
21 explicit IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
22 : ServiceFramework{system_, "IHardwareOpusDecoder"},
23 impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
24 // clang-format off
25 static const FunctionInfo functions[] = {
26 {0, &IHardwareOpusDecoder::DecodeInterleavedOld, "DecodeInterleavedOld"},
27 {1, &IHardwareOpusDecoder::SetContext, "SetContext"},
28 {2, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld, "DecodeInterleavedForMultiStreamOld"},
29 {3, &IHardwareOpusDecoder::SetContextForMultiStream, "SetContextForMultiStream"},
30 {4, &IHardwareOpusDecoder::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
31 {5, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld, "DecodeInterleavedForMultiStreamWithPerfOld"},
32 {6, &IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld, "DecodeInterleavedWithPerfAndResetOld"},
33 {7, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
34 {8, &IHardwareOpusDecoder::DecodeInterleaved, "DecodeInterleaved"},
35 {9, &IHardwareOpusDecoder::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"},
36 };
37 // clang-format on
38
39 RegisterHandlers(functions);
40 }
41
42 Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
43 u64 transfer_memory_size) {
44 return impl->Initialize(params, transfer_memory, transfer_memory_size);
45 }
46
47 Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
48 u64 transfer_memory_size) {
49 return impl->Initialize(params, transfer_memory, transfer_memory_size);
50 }
51
52private:
53 void DecodeInterleavedOld(HLERequestContext& ctx) {
54 IPC::RequestParser rp{ctx};
55
56 auto input_data{ctx.ReadBuffer(0)};
57 output_data.resize_destructive(ctx.GetWriteBufferSize());
58
59 u32 size{};
60 u32 sample_count{};
61 auto result =
62 impl->DecodeInterleaved(&size, nullptr, &sample_count, input_data, output_data, false);
63
64 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
65
66 ctx.WriteBuffer(output_data);
67
68 IPC::ResponseBuilder rb{ctx, 4};
69 rb.Push(result);
70 rb.Push(size);
71 rb.Push(sample_count);
72 }
73
74 void SetContext(HLERequestContext& ctx) {
75 IPC::RequestParser rp{ctx};
76
77 LOG_DEBUG(Service_Audio, "called");
78
79 auto input_data{ctx.ReadBuffer(0)};
80 auto result = impl->SetContext(input_data);
81
82 IPC::ResponseBuilder rb{ctx, 2};
83 rb.Push(result);
84 }
85
86 void DecodeInterleavedForMultiStreamOld(HLERequestContext& ctx) {
87 IPC::RequestParser rp{ctx};
88
89 auto input_data{ctx.ReadBuffer(0)};
90 output_data.resize_destructive(ctx.GetWriteBufferSize());
91
92 u32 size{};
93 u32 sample_count{};
94 auto result = impl->DecodeInterleavedForMultiStream(&size, nullptr, &sample_count,
95 input_data, output_data, false);
96
97 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
98
99 ctx.WriteBuffer(output_data);
100
101 IPC::ResponseBuilder rb{ctx, 4};
102 rb.Push(result);
103 rb.Push(size);
104 rb.Push(sample_count);
105 }
106
107 void SetContextForMultiStream(HLERequestContext& ctx) {
108 IPC::RequestParser rp{ctx};
109
110 LOG_DEBUG(Service_Audio, "called");
111
112 auto input_data{ctx.ReadBuffer(0)};
113 auto result = impl->SetContext(input_data);
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(result);
117 }
118
119 void DecodeInterleavedWithPerfOld(HLERequestContext& ctx) {
120 IPC::RequestParser rp{ctx};
121
122 auto input_data{ctx.ReadBuffer(0)};
123 output_data.resize_destructive(ctx.GetWriteBufferSize());
124
125 u32 size{};
126 u32 sample_count{};
127 u64 time_taken{};
128 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
129 output_data, false);
130
131 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
132 sample_count, time_taken);
133
134 ctx.WriteBuffer(output_data);
135
136 IPC::ResponseBuilder rb{ctx, 6};
137 rb.Push(result);
138 rb.Push(size);
139 rb.Push(sample_count);
140 rb.Push(time_taken);
141 }
142
143 void DecodeInterleavedForMultiStreamWithPerfOld(HLERequestContext& ctx) {
144 IPC::RequestParser rp{ctx};
145
146 auto input_data{ctx.ReadBuffer(0)};
147 output_data.resize_destructive(ctx.GetWriteBufferSize());
148
149 u32 size{};
150 u32 sample_count{};
151 u64 time_taken{};
152 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
153 input_data, output_data, false);
154
155 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
156 sample_count, time_taken);
157
158 ctx.WriteBuffer(output_data);
159
160 IPC::ResponseBuilder rb{ctx, 6};
161 rb.Push(result);
162 rb.Push(size);
163 rb.Push(sample_count);
164 rb.Push(time_taken);
165 }
166
167 void DecodeInterleavedWithPerfAndResetOld(HLERequestContext& ctx) {
168 IPC::RequestParser rp{ctx};
169
170 auto reset{rp.Pop<bool>()};
171
172 auto input_data{ctx.ReadBuffer(0)};
173 output_data.resize_destructive(ctx.GetWriteBufferSize());
174
175 u32 size{};
176 u32 sample_count{};
177 u64 time_taken{};
178 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
179 output_data, reset);
180
181 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
182 reset, size, sample_count, time_taken);
183
184 ctx.WriteBuffer(output_data);
185
186 IPC::ResponseBuilder rb{ctx, 6};
187 rb.Push(result);
188 rb.Push(size);
189 rb.Push(sample_count);
190 rb.Push(time_taken);
191 }
192
193 void DecodeInterleavedForMultiStreamWithPerfAndResetOld(HLERequestContext& ctx) {
194 IPC::RequestParser rp{ctx};
195
196 auto reset{rp.Pop<bool>()};
197
198 auto input_data{ctx.ReadBuffer(0)};
199 output_data.resize_destructive(ctx.GetWriteBufferSize());
200
201 u32 size{};
202 u32 sample_count{};
203 u64 time_taken{};
204 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
205 input_data, output_data, reset);
206
207 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
208 reset, size, sample_count, time_taken);
209
210 ctx.WriteBuffer(output_data);
211
212 IPC::ResponseBuilder rb{ctx, 6};
213 rb.Push(result);
214 rb.Push(size);
215 rb.Push(sample_count);
216 rb.Push(time_taken);
217 }
218
219 void DecodeInterleaved(HLERequestContext& ctx) {
220 IPC::RequestParser rp{ctx};
221
222 auto reset{rp.Pop<bool>()};
223
224 auto input_data{ctx.ReadBuffer(0)};
225 output_data.resize_destructive(ctx.GetWriteBufferSize());
226
227 u32 size{};
228 u32 sample_count{};
229 u64 time_taken{};
230 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
231 output_data, reset);
232
233 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
234 reset, size, sample_count, time_taken);
235
236 ctx.WriteBuffer(output_data);
237
238 IPC::ResponseBuilder rb{ctx, 6};
239 rb.Push(result);
240 rb.Push(size);
241 rb.Push(sample_count);
242 rb.Push(time_taken);
243 }
244
245 void DecodeInterleavedForMultiStream(HLERequestContext& ctx) {
246 IPC::RequestParser rp{ctx};
247
248 auto reset{rp.Pop<bool>()};
249
250 auto input_data{ctx.ReadBuffer(0)};
251 output_data.resize_destructive(ctx.GetWriteBufferSize());
252
253 u32 size{};
254 u32 sample_count{};
255 u64 time_taken{};
256 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
257 input_data, output_data, reset);
258
259 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
260 reset, size, sample_count, time_taken);
261
262 ctx.WriteBuffer(output_data);
263
264 IPC::ResponseBuilder rb{ctx, 6};
265 rb.Push(result);
266 rb.Push(size);
267 rb.Push(sample_count);
268 rb.Push(time_taken);
269 }
270
271 std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
272 Common::ScratchBuffer<u8> output_data;
273};
274
275void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
276 IPC::RequestParser rp{ctx};
277
278 auto params = rp.PopRaw<OpusParameters>();
279 auto transfer_memory_size{rp.Pop<u32>()};
280 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
281 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
282
283 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
284 params.sample_rate, params.channel_count, transfer_memory_size);
285
286 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
287
288 OpusParametersEx ex{
289 .sample_rate = params.sample_rate,
290 .channel_count = params.channel_count,
291 .use_large_frame_size = false,
292 };
293 auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
294
295 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
296 rb.Push(result);
297 rb.PushIpcInterface(decoder);
298}
299
300void HwOpus::GetWorkBufferSize(HLERequestContext& ctx) {
301 IPC::RequestParser rp{ctx};
302 auto params = rp.PopRaw<OpusParameters>();
303
304 u64 size{};
305 auto result = impl.GetWorkBufferSize(params, size);
306
307 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size 0x{:X}",
308 params.sample_rate, params.channel_count, size);
309
310 IPC::ResponseBuilder rb{ctx, 4};
311 rb.Push(result);
312 rb.Push(size);
313}
314
315void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
316 IPC::RequestParser rp{ctx};
317
318 auto input{ctx.ReadBuffer()};
319 OpusMultiStreamParameters params;
320 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
321
322 auto transfer_memory_size{rp.Pop<u32>()};
323 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
324 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
325
326 LOG_DEBUG(Service_Audio,
327 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
328 "transfer_memory_size 0x{:X}",
329 params.sample_rate, params.channel_count, params.total_stream_count,
330 params.stereo_stream_count, transfer_memory_size);
331
332 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
333
334 OpusMultiStreamParametersEx ex{
335 .sample_rate = params.sample_rate,
336 .channel_count = params.channel_count,
337 .total_stream_count = params.total_stream_count,
338 .stereo_stream_count = params.stereo_stream_count,
339 .use_large_frame_size = false,
340 .mappings{},
341 };
342 std::memcpy(ex.mappings.data(), params.mappings.data(), sizeof(params.mappings));
343 auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
344
345 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
346 rb.Push(result);
347 rb.PushIpcInterface(decoder);
348}
349
350void HwOpus::GetWorkBufferSizeForMultiStream(HLERequestContext& ctx) {
351 IPC::RequestParser rp{ctx};
352
353 auto input{ctx.ReadBuffer()};
354 OpusMultiStreamParameters params;
355 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
356
357 u64 size{};
358 auto result = impl.GetWorkBufferSizeForMultiStream(params, size);
359
360 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
361
362 IPC::ResponseBuilder rb{ctx, 4};
363 rb.Push(result);
364 rb.Push(size);
365}
366
367void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
368 IPC::RequestParser rp{ctx};
369
370 auto params = rp.PopRaw<OpusParametersEx>();
371 auto transfer_memory_size{rp.Pop<u32>()};
372 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
373 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
374
375 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
376 params.sample_rate, params.channel_count, transfer_memory_size);
377
378 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
379
380 auto result =
381 decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
382
383 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
384 rb.Push(result);
385 rb.PushIpcInterface(decoder);
386}
387
388void HwOpus::GetWorkBufferSizeEx(HLERequestContext& ctx) {
389 IPC::RequestParser rp{ctx};
390 auto params = rp.PopRaw<OpusParametersEx>();
391
392 u64 size{};
393 auto result = impl.GetWorkBufferSizeEx(params, size);
394
395 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
396
397 IPC::ResponseBuilder rb{ctx, 4};
398 rb.Push(result);
399 rb.Push(size);
400}
401
402void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
403 IPC::RequestParser rp{ctx};
404
405 auto input{ctx.ReadBuffer()};
406 OpusMultiStreamParametersEx params;
407 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
408
409 auto transfer_memory_size{rp.Pop<u32>()};
410 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
411 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
412
413 LOG_DEBUG(Service_Audio,
414 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
415 "use_large_frame_size {}"
416 "transfer_memory_size 0x{:X}",
417 params.sample_rate, params.channel_count, params.total_stream_count,
418 params.stereo_stream_count, params.use_large_frame_size, transfer_memory_size);
419
420 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
421
422 auto result =
423 decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
424
425 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
426 rb.Push(result);
427 rb.PushIpcInterface(decoder);
428}
429
430void HwOpus::GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx) {
431 IPC::RequestParser rp{ctx};
432
433 auto input{ctx.ReadBuffer()};
434 OpusMultiStreamParametersEx params;
435 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
436
437 u64 size{};
438 auto result = impl.GetWorkBufferSizeForMultiStreamEx(params, size);
439
440 LOG_DEBUG(Service_Audio,
441 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
442 "use_large_frame_size {} -- returned size 0x{:X}",
443 params.sample_rate, params.channel_count, params.total_stream_count,
444 params.stereo_stream_count, params.use_large_frame_size, size);
445
446 IPC::ResponseBuilder rb{ctx, 4};
447 rb.Push(result);
448 rb.Push(size);
449}
450
451void HwOpus::GetWorkBufferSizeExEx(HLERequestContext& ctx) {
452 IPC::RequestParser rp{ctx};
453 auto params = rp.PopRaw<OpusParametersEx>();
454
455 u64 size{};
456 auto result = impl.GetWorkBufferSizeExEx(params, size);
457
458 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
459
460 IPC::ResponseBuilder rb{ctx, 4};
461 rb.Push(result);
462 rb.Push(size);
463}
464
465void HwOpus::GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx) {
466 IPC::RequestParser rp{ctx};
467
468 auto input{ctx.ReadBuffer()};
469 OpusMultiStreamParametersEx params;
470 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
471
472 u64 size{};
473 auto result = impl.GetWorkBufferSizeForMultiStreamExEx(params, size);
474
475 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
476
477 IPC::ResponseBuilder rb{ctx, 4};
478 rb.Push(result);
479 rb.Push(size);
480}
481
482HwOpus::HwOpus(Core::System& system_)
483 : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
484 static const FunctionInfo functions[] = {
485 {0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
486 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
487 {2, &HwOpus::OpenHardwareOpusDecoderForMultiStream, "OpenOpusDecoderForMultiStream"},
488 {3, &HwOpus::GetWorkBufferSizeForMultiStream, "GetWorkBufferSizeForMultiStream"},
489 {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
490 {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
491 {6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx,
492 "OpenHardwareOpusDecoderForMultiStreamEx"},
493 {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
494 {8, &HwOpus::GetWorkBufferSizeExEx, "GetWorkBufferSizeExEx"},
495 {9, &HwOpus::GetWorkBufferSizeForMultiStreamExEx, "GetWorkBufferSizeForMultiStreamExEx"},
496 };
497 RegisterHandlers(functions);
498}
499
500HwOpus::~HwOpus() = default;
501
502} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
deleted file mode 100644
index d3960065e..000000000
--- a/src/core/hle/service/audio/hwopus.h
+++ /dev/null
@@ -1,36 +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 "audio_core/opus/decoder_manager.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Audio {
14
15class HwOpus final : public ServiceFramework<HwOpus> {
16public:
17 explicit HwOpus(Core::System& system_);
18 ~HwOpus() override;
19
20private:
21 void OpenHardwareOpusDecoder(HLERequestContext& ctx);
22 void GetWorkBufferSize(HLERequestContext& ctx);
23 void OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx);
24 void GetWorkBufferSizeForMultiStream(HLERequestContext& ctx);
25 void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
26 void GetWorkBufferSizeEx(HLERequestContext& ctx);
27 void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx);
28 void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
29 void GetWorkBufferSizeExEx(HLERequestContext& ctx);
30 void GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx);
31
32 Core::System& system;
33 AudioCore::OpusDecoder::OpusDecoderManager impl;
34};
35
36} // namespace Service::Audio
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
index f24682c34..5a5f610f3 100644
--- a/src/core/hle/service/cmif_serialization.h
+++ b/src/core/hle/service/cmif_serialization.h
@@ -415,7 +415,7 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
415 auto& buffer = temp[OutBufferIndex]; 415 auto& buffer = temp[OutBufferIndex];
416 const size_t size = buffer.size(); 416 const size_t size = buffer.size();
417 417
418 if (ctx.CanWriteBuffer(OutBufferIndex)) { 418 if (size > 0 && ctx.CanWriteBuffer(OutBufferIndex)) {
419 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { 419 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
420 ctx.WriteBuffer(buffer.data(), size, OutBufferIndex); 420 ctx.WriteBuffer(buffer.data(), size, OutBufferIndex);
421 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { 421 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) {
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
index 39690018b..8483394d0 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
@@ -3,82 +3,34 @@
3 3
4#include "core/file_sys/fs_filesystem.h" 4#include "core/file_sys/fs_filesystem.h"
5#include "core/file_sys/savedata_factory.h" 5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/filesystem/fsp/fs_i_directory.h" 7#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
7#include "core/hle/service/ipc_helpers.h"
8 8
9namespace Service::FileSystem { 9namespace Service::FileSystem {
10 10
11template <typename T> 11IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
12static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries,
13 const std::vector<T>& new_data, FileSys::DirectoryEntryType type) {
14 entries.reserve(entries.size() + new_data.size());
15
16 for (const auto& new_entry : new_data) {
17 auto name = new_entry->GetName();
18
19 if (type == FileSys::DirectoryEntryType::File &&
20 name == FileSys::GetSaveDataSizeFileName()) {
21 continue;
22 }
23
24 entries.emplace_back(name, static_cast<s8>(type),
25 type == FileSys::DirectoryEntryType::Directory ? 0
26 : new_entry->GetSize());
27 }
28}
29
30IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
31 FileSys::OpenDirectoryMode mode) 12 FileSys::OpenDirectoryMode mode)
32 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { 13 : ServiceFramework{system_, "IDirectory"},
14 backend(std::make_unique<FileSys::Fsa::IDirectory>(directory_, mode)) {
33 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
34 {0, &IDirectory::Read, "Read"}, 16 {0, D<&IDirectory::Read>, "Read"},
35 {1, &IDirectory::GetEntryCount, "GetEntryCount"}, 17 {1, D<&IDirectory::GetEntryCount>, "GetEntryCount"},
36 }; 18 };
37 RegisterHandlers(functions); 19 RegisterHandlers(functions);
38
39 // TODO(DarkLordZach): Verify that this is the correct behavior.
40 // Build entry index now to save time later.
41 if (True(mode & FileSys::OpenDirectoryMode::Directory)) {
42 BuildEntryIndex(entries, backend->GetSubdirectories(),
43 FileSys::DirectoryEntryType::Directory);
44 }
45 if (True(mode & FileSys::OpenDirectoryMode::File)) {
46 BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File);
47 }
48} 20}
49 21
50void IDirectory::Read(HLERequestContext& ctx) { 22Result IDirectory::Read(
23 Out<s64> out_count,
24 const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries) {
51 LOG_DEBUG(Service_FS, "called."); 25 LOG_DEBUG(Service_FS, "called.");
52 26
53 // Calculate how many entries we can fit in the output buffer 27 R_RETURN(backend->Read(out_count, out_entries.data(), out_entries.size()));
54 const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>();
55
56 // Cap at total number of entries.
57 const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
58
59 // Determine data start and end
60 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
61 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
62 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
63
64 next_entry_index += actual_entries;
65
66 // Write the data to memory
67 ctx.WriteBuffer(begin, range_size);
68
69 IPC::ResponseBuilder rb{ctx, 4};
70 rb.Push(ResultSuccess);
71 rb.Push(actual_entries);
72} 28}
73 29
74void IDirectory::GetEntryCount(HLERequestContext& ctx) { 30Result IDirectory::GetEntryCount(Out<s64> out_count) {
75 LOG_DEBUG(Service_FS, "called"); 31 LOG_DEBUG(Service_FS, "called");
76 32
77 u64 count = entries.size() - next_entry_index; 33 R_RETURN(backend->GetEntryCount(out_count));
78
79 IPC::ResponseBuilder rb{ctx, 4};
80 rb.Push(ResultSuccess);
81 rb.Push(count);
82} 34}
83 35
84} // namespace Service::FileSystem 36} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.h b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
index 793ecfcd7..b6251f7fd 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_directory.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
@@ -3,7 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/fsa/fs_i_directory.h"
6#include "core/file_sys/vfs/vfs.h" 7#include "core/file_sys/vfs/vfs.h"
8#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 9#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
9 11
@@ -15,16 +17,15 @@ namespace Service::FileSystem {
15 17
16class IDirectory final : public ServiceFramework<IDirectory> { 18class IDirectory final : public ServiceFramework<IDirectory> {
17public: 19public:
18 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, 20 explicit IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
19 FileSys::OpenDirectoryMode mode); 21 FileSys::OpenDirectoryMode mode);
20 22
21private: 23private:
22 FileSys::VirtualDir backend; 24 std::unique_ptr<FileSys::Fsa::IDirectory> backend;
23 std::vector<FileSys::DirectoryEntry> entries;
24 u64 next_entry_index = 0;
25 25
26 void Read(HLERequestContext& ctx); 26 Result Read(Out<s64> out_count,
27 void GetEntryCount(HLERequestContext& ctx); 27 const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries);
28 Result GetEntryCount(Out<s64> out_count);
28}; 29};
29 30
30} // namespace Service::FileSystem 31} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
index 9a18f6ec5..a355d46ae 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
@@ -2,126 +2,64 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/errors.h" 4#include "core/file_sys/errors.h"
5#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_file.h" 6#include "core/hle/service/filesystem/fsp/fs_i_file.h"
6#include "core/hle/service/ipc_helpers.h"
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_) 10IFile::IFile(Core::System& system_, FileSys::VirtualFile file_)
11 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { 11 : ServiceFramework{system_, "IFile"}, backend{std::make_unique<FileSys::Fsa::IFile>(file_)} {
12 // clang-format off
12 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
13 {0, &IFile::Read, "Read"}, 14 {0, D<&IFile::Read>, "Read"},
14 {1, &IFile::Write, "Write"}, 15 {1, D<&IFile::Write>, "Write"},
15 {2, &IFile::Flush, "Flush"}, 16 {2, D<&IFile::Flush>, "Flush"},
16 {3, &IFile::SetSize, "SetSize"}, 17 {3, D<&IFile::SetSize>, "SetSize"},
17 {4, &IFile::GetSize, "GetSize"}, 18 {4, D<&IFile::GetSize>, "GetSize"},
18 {5, nullptr, "OperateRange"}, 19 {5, nullptr, "OperateRange"},
19 {6, nullptr, "OperateRangeWithBuffer"}, 20 {6, nullptr, "OperateRangeWithBuffer"},
20 }; 21 };
22 // clang-format on
21 RegisterHandlers(functions); 23 RegisterHandlers(functions);
22} 24}
23 25
24void IFile::Read(HLERequestContext& ctx) { 26Result IFile::Read(
25 IPC::RequestParser rp{ctx}; 27 FileSys::ReadOption option, Out<s64> out_size, s64 offset,
26 const u64 option = rp.Pop<u64>(); 28 const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer,
27 const s64 offset = rp.Pop<s64>(); 29 s64 size) {
28 const s64 length = rp.Pop<s64>(); 30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
29 31 size);
30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
31
32 // Error checking
33 if (length < 0) {
34 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
35 IPC::ResponseBuilder rb{ctx, 2};
36 rb.Push(FileSys::ResultInvalidSize);
37 return;
38 }
39 if (offset < 0) {
40 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
41 IPC::ResponseBuilder rb{ctx, 2};
42 rb.Push(FileSys::ResultInvalidOffset);
43 return;
44 }
45 32
46 // Read the data from the Storage backend 33 // Read the data from the Storage backend
47 std::vector<u8> output = backend->ReadBytes(length, offset); 34 R_RETURN(
48 35 backend->Read(reinterpret_cast<size_t*>(out_size.Get()), offset, out_buffer.data(), size));
49 // Write the data to memory
50 ctx.WriteBuffer(output);
51
52 IPC::ResponseBuilder rb{ctx, 4};
53 rb.Push(ResultSuccess);
54 rb.Push(static_cast<u64>(output.size()));
55} 36}
56 37
57void IFile::Write(HLERequestContext& ctx) { 38Result IFile::Write(
58 IPC::RequestParser rp{ctx}; 39 const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
59 const u64 option = rp.Pop<u64>(); 40 FileSys::WriteOption option, s64 offset, s64 size) {
60 const s64 offset = rp.Pop<s64>(); 41 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
61 const s64 length = rp.Pop<s64>(); 42 size);
62
63 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
64
65 // Error checking
66 if (length < 0) {
67 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
68 IPC::ResponseBuilder rb{ctx, 2};
69 rb.Push(FileSys::ResultInvalidSize);
70 return;
71 }
72 if (offset < 0) {
73 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(FileSys::ResultInvalidOffset);
76 return;
77 }
78
79 const auto data = ctx.ReadBuffer();
80 43
81 ASSERT_MSG(static_cast<s64>(data.size()) <= length, 44 R_RETURN(backend->Write(offset, buffer.data(), size, option));
82 "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
83 length, data.size());
84
85 // Write the data to the Storage backend
86 const auto write_size =
87 static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
88 const std::size_t written = backend->Write(data.data(), write_size, offset);
89
90 ASSERT_MSG(static_cast<s64>(written) == length,
91 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
92 written);
93
94 IPC::ResponseBuilder rb{ctx, 2};
95 rb.Push(ResultSuccess);
96} 45}
97 46
98void IFile::Flush(HLERequestContext& ctx) { 47Result IFile::Flush() {
99 LOG_DEBUG(Service_FS, "called"); 48 LOG_DEBUG(Service_FS, "called");
100 49
101 // Exists for SDK compatibiltity -- No need to flush file. 50 R_RETURN(backend->Flush());
102
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(ResultSuccess);
105} 51}
106 52
107void IFile::SetSize(HLERequestContext& ctx) { 53Result IFile::SetSize(s64 size) {
108 IPC::RequestParser rp{ctx};
109 const u64 size = rp.Pop<u64>();
110 LOG_DEBUG(Service_FS, "called, size={}", size); 54 LOG_DEBUG(Service_FS, "called, size={}", size);
111 55
112 backend->Resize(size); 56 R_RETURN(backend->SetSize(size));
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(ResultSuccess);
116} 57}
117 58
118void IFile::GetSize(HLERequestContext& ctx) { 59Result IFile::GetSize(Out<s64> out_size) {
119 const u64 size = backend->GetSize(); 60 LOG_DEBUG(Service_FS, "called");
120 LOG_DEBUG(Service_FS, "called, size={}", size);
121 61
122 IPC::ResponseBuilder rb{ctx, 4}; 62 R_RETURN(backend->GetSize(out_size));
123 rb.Push(ResultSuccess);
124 rb.Push<u64>(size);
125} 63}
126 64
127} // namespace Service::FileSystem 65} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.h b/src/core/hle/service/filesystem/fsp/fs_i_file.h
index 5e5430c67..e8599ee2f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_file.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h
@@ -3,6 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/fsa/fs_i_file.h"
7#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/filesystem/filesystem.h" 8#include "core/hle/service/filesystem/filesystem.h"
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
@@ -10,16 +12,21 @@ namespace Service::FileSystem {
10 12
11class IFile final : public ServiceFramework<IFile> { 13class IFile final : public ServiceFramework<IFile> {
12public: 14public:
13 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_); 15 explicit IFile(Core::System& system_, FileSys::VirtualFile file_);
14 16
15private: 17private:
16 FileSys::VirtualFile backend; 18 std::unique_ptr<FileSys::Fsa::IFile> backend;
17 19
18 void Read(HLERequestContext& ctx); 20 Result Read(FileSys::ReadOption option, Out<s64> out_size, s64 offset,
19 void Write(HLERequestContext& ctx); 21 const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure>
20 void Flush(HLERequestContext& ctx); 22 out_buffer,
21 void SetSize(HLERequestContext& ctx); 23 s64 size);
22 void GetSize(HLERequestContext& ctx); 24 Result Write(
25 const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
26 FileSys::WriteOption option, s64 offset, s64 size);
27 Result Flush();
28 Result SetSize(s64 size);
29 Result GetSize(Out<s64> out_size);
23}; 30};
24 31
25} // namespace Service::FileSystem 32} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
index efa394dd1..d881e144d 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
@@ -2,261 +2,172 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/string_util.h" 4#include "common/string_util.h"
5#include "core/file_sys/fssrv/fssrv_sf_path.h"
6#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_directory.h" 7#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
6#include "core/hle/service/filesystem/fsp/fs_i_file.h" 8#include "core/hle/service/filesystem/fsp/fs_i_file.h"
7#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" 9#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
8#include "core/hle/service/ipc_helpers.h"
9 10
10namespace Service::FileSystem { 11namespace Service::FileSystem {
11 12
12IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) 13IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_)
13 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( 14 : ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>(
14 size_)} { 15 dir_)},
16 size_getter{std::move(size_getter_)} {
15 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
16 {0, &IFileSystem::CreateFile, "CreateFile"}, 18 {0, D<&IFileSystem::CreateFile>, "CreateFile"},
17 {1, &IFileSystem::DeleteFile, "DeleteFile"}, 19 {1, D<&IFileSystem::DeleteFile>, "DeleteFile"},
18 {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, 20 {2, D<&IFileSystem::CreateDirectory>, "CreateDirectory"},
19 {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, 21 {3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"},
20 {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, 22 {4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"},
21 {5, &IFileSystem::RenameFile, "RenameFile"}, 23 {5, D<&IFileSystem::RenameFile>, "RenameFile"},
22 {6, nullptr, "RenameDirectory"}, 24 {6, nullptr, "RenameDirectory"},
23 {7, &IFileSystem::GetEntryType, "GetEntryType"}, 25 {7, D<&IFileSystem::GetEntryType>, "GetEntryType"},
24 {8, &IFileSystem::OpenFile, "OpenFile"}, 26 {8, D<&IFileSystem::OpenFile>, "OpenFile"},
25 {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, 27 {9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"},
26 {10, &IFileSystem::Commit, "Commit"}, 28 {10, D<&IFileSystem::Commit>, "Commit"},
27 {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, 29 {11, D<&IFileSystem::GetFreeSpaceSize>, "GetFreeSpaceSize"},
28 {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, 30 {12, D<&IFileSystem::GetTotalSpaceSize>, "GetTotalSpaceSize"},
29 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, 31 {13, D<&IFileSystem::CleanDirectoryRecursively>, "CleanDirectoryRecursively"},
30 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, 32 {14, D<&IFileSystem::GetFileTimeStampRaw>, "GetFileTimeStampRaw"},
31 {15, nullptr, "QueryEntry"}, 33 {15, nullptr, "QueryEntry"},
32 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, 34 {16, D<&IFileSystem::GetFileSystemAttribute>, "GetFileSystemAttribute"},
33 }; 35 };
34 RegisterHandlers(functions); 36 RegisterHandlers(functions);
35} 37}
36 38
37void IFileSystem::CreateFile(HLERequestContext& ctx) { 39Result IFileSystem::CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
38 IPC::RequestParser rp{ctx}; 40 s32 option, s64 size) {
41 LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size);
39 42
40 const auto file_buffer = ctx.ReadBuffer(); 43 R_RETURN(backend->CreateFile(FileSys::Path(path->str), size));
41 const std::string name = Common::StringFromBuffer(file_buffer);
42
43 const u64 file_mode = rp.Pop<u64>();
44 const u32 file_size = rp.Pop<u32>();
45
46 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
47 file_size);
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(backend.CreateFile(name, file_size));
51} 44}
52 45
53void IFileSystem::DeleteFile(HLERequestContext& ctx) { 46Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
54 const auto file_buffer = ctx.ReadBuffer(); 47 LOG_DEBUG(Service_FS, "called. file={}", path->str);
55 const std::string name = Common::StringFromBuffer(file_buffer);
56 48
57 LOG_DEBUG(Service_FS, "called. file={}", name); 49 R_RETURN(backend->DeleteFile(FileSys::Path(path->str)));
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(backend.DeleteFile(name));
61} 50}
62 51
63void IFileSystem::CreateDirectory(HLERequestContext& ctx) { 52Result IFileSystem::CreateDirectory(
64 const auto file_buffer = ctx.ReadBuffer(); 53 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
65 const std::string name = Common::StringFromBuffer(file_buffer); 54 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
66
67 LOG_DEBUG(Service_FS, "called. directory={}", name);
68 55
69 IPC::ResponseBuilder rb{ctx, 2}; 56 R_RETURN(backend->CreateDirectory(FileSys::Path(path->str)));
70 rb.Push(backend.CreateDirectory(name));
71} 57}
72 58
73void IFileSystem::DeleteDirectory(HLERequestContext& ctx) { 59Result IFileSystem::DeleteDirectory(
74 const auto file_buffer = ctx.ReadBuffer(); 60 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
75 const std::string name = Common::StringFromBuffer(file_buffer); 61 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
76
77 LOG_DEBUG(Service_FS, "called. directory={}", name);
78 62
79 IPC::ResponseBuilder rb{ctx, 2}; 63 R_RETURN(backend->DeleteDirectory(FileSys::Path(path->str)));
80 rb.Push(backend.DeleteDirectory(name));
81} 64}
82 65
83void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) { 66Result IFileSystem::DeleteDirectoryRecursively(
84 const auto file_buffer = ctx.ReadBuffer(); 67 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
85 const std::string name = Common::StringFromBuffer(file_buffer); 68 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
86 69
87 LOG_DEBUG(Service_FS, "called. directory={}", name); 70 R_RETURN(backend->DeleteDirectoryRecursively(FileSys::Path(path->str)));
88
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(backend.DeleteDirectoryRecursively(name));
91} 71}
92 72
93void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) { 73Result IFileSystem::CleanDirectoryRecursively(
94 const auto file_buffer = ctx.ReadBuffer(); 74 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
95 const std::string name = Common::StringFromBuffer(file_buffer); 75 LOG_DEBUG(Service_FS, "called. Directory: {}", path->str);
96
97 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
98 76
99 IPC::ResponseBuilder rb{ctx, 2}; 77 R_RETURN(backend->CleanDirectoryRecursively(FileSys::Path(path->str)));
100 rb.Push(backend.CleanDirectoryRecursively(name));
101} 78}
102 79
103void IFileSystem::RenameFile(HLERequestContext& ctx) { 80Result IFileSystem::RenameFile(
104 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); 81 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
105 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); 82 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path) {
106 83 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", old_path->str, new_path->str);
107 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
108 84
109 IPC::ResponseBuilder rb{ctx, 2}; 85 R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));
110 rb.Push(backend.RenameFile(src_name, dst_name));
111} 86}
112 87
113void IFileSystem::OpenFile(HLERequestContext& ctx) { 88Result IFileSystem::OpenFile(OutInterface<IFile> out_interface,
114 IPC::RequestParser rp{ctx}; 89 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
115 90 u32 mode) {
116 const auto file_buffer = ctx.ReadBuffer(); 91 LOG_DEBUG(Service_FS, "called. file={}, mode={}", path->str, mode);
117 const std::string name = Common::StringFromBuffer(file_buffer);
118
119 const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>());
120
121 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
122 92
123 FileSys::VirtualFile vfs_file{}; 93 FileSys::VirtualFile vfs_file{};
124 auto result = backend.OpenFile(&vfs_file, name, mode); 94 R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str),
125 if (result != ResultSuccess) { 95 static_cast<FileSys::OpenMode>(mode)));
126 IPC::ResponseBuilder rb{ctx, 2};
127 rb.Push(result);
128 return;
129 }
130
131 auto file = std::make_shared<IFile>(system, vfs_file);
132
133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
134 rb.Push(ResultSuccess);
135 rb.PushIpcInterface<IFile>(std::move(file));
136}
137
138void IFileSystem::OpenDirectory(HLERequestContext& ctx) {
139 IPC::RequestParser rp{ctx};
140 96
141 const auto file_buffer = ctx.ReadBuffer(); 97 *out_interface = std::make_shared<IFile>(system, vfs_file);
142 const std::string name = Common::StringFromBuffer(file_buffer); 98 R_SUCCEED();
143 const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>(); 99}
144 100
145 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); 101Result IFileSystem::OpenDirectory(OutInterface<IDirectory> out_interface,
102 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
103 u32 mode) {
104 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", path->str, mode);
146 105
147 FileSys::VirtualDir vfs_dir{}; 106 FileSys::VirtualDir vfs_dir{};
148 auto result = backend.OpenDirectory(&vfs_dir, name); 107 R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str),
149 if (result != ResultSuccess) { 108 static_cast<FileSys::OpenDirectoryMode>(mode)));
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(result);
152 return;
153 }
154
155 auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
156
157 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
158 rb.Push(ResultSuccess);
159 rb.PushIpcInterface<IDirectory>(std::move(directory));
160}
161 109
162void IFileSystem::GetEntryType(HLERequestContext& ctx) { 110 *out_interface = std::make_shared<IDirectory>(system, vfs_dir,
163 const auto file_buffer = ctx.ReadBuffer(); 111 static_cast<FileSys::OpenDirectoryMode>(mode));
164 const std::string name = Common::StringFromBuffer(file_buffer); 112 R_SUCCEED();
113}
165 114
166 LOG_DEBUG(Service_FS, "called. file={}", name); 115Result IFileSystem::GetEntryType(
116 Out<u32> out_type, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
117 LOG_DEBUG(Service_FS, "called. file={}", path->str);
167 118
168 FileSys::DirectoryEntryType vfs_entry_type{}; 119 FileSys::DirectoryEntryType vfs_entry_type{};
169 auto result = backend.GetEntryType(&vfs_entry_type, name); 120 R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str)));
170 if (result != ResultSuccess) { 121
171 IPC::ResponseBuilder rb{ctx, 2}; 122 *out_type = static_cast<u32>(vfs_entry_type);
172 rb.Push(result); 123 R_SUCCEED();
173 return;
174 }
175
176 IPC::ResponseBuilder rb{ctx, 3};
177 rb.Push(ResultSuccess);
178 rb.Push<u32>(static_cast<u32>(vfs_entry_type));
179} 124}
180 125
181void IFileSystem::Commit(HLERequestContext& ctx) { 126Result IFileSystem::Commit() {
182 LOG_WARNING(Service_FS, "(STUBBED) called"); 127 LOG_WARNING(Service_FS, "(STUBBED) called");
183 128
184 IPC::ResponseBuilder rb{ctx, 2}; 129 R_SUCCEED();
185 rb.Push(ResultSuccess);
186} 130}
187 131
188void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) { 132Result IFileSystem::GetFreeSpaceSize(
133 Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
189 LOG_DEBUG(Service_FS, "called"); 134 LOG_DEBUG(Service_FS, "called");
190 135
191 IPC::ResponseBuilder rb{ctx, 4}; 136 *out_size = size_getter.get_free_size();
192 rb.Push(ResultSuccess); 137 R_SUCCEED();
193 rb.Push(size.get_free_size());
194} 138}
195 139
196void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) { 140Result IFileSystem::GetTotalSpaceSize(
141 Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
197 LOG_DEBUG(Service_FS, "called"); 142 LOG_DEBUG(Service_FS, "called");
198 143
199 IPC::ResponseBuilder rb{ctx, 4}; 144 *out_size = size_getter.get_total_size();
200 rb.Push(ResultSuccess); 145 R_SUCCEED();
201 rb.Push(size.get_total_size());
202} 146}
203 147
204void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) { 148Result IFileSystem::GetFileTimeStampRaw(
205 const auto file_buffer = ctx.ReadBuffer(); 149 Out<FileSys::FileTimeStampRaw> out_timestamp,
206 const std::string name = Common::StringFromBuffer(file_buffer); 150 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
207 151 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", path->str);
208 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
209 152
210 FileSys::FileTimeStampRaw vfs_timestamp{}; 153 FileSys::FileTimeStampRaw vfs_timestamp{};
211 auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); 154 R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str)));
212 if (result != ResultSuccess) { 155
213 IPC::ResponseBuilder rb{ctx, 2}; 156 *out_timestamp = vfs_timestamp;
214 rb.Push(result); 157 R_SUCCEED();
215 return;
216 }
217
218 IPC::ResponseBuilder rb{ctx, 10};
219 rb.Push(ResultSuccess);
220 rb.PushRaw(vfs_timestamp);
221} 158}
222 159
223void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) { 160Result IFileSystem::GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute) {
224 LOG_WARNING(Service_FS, "(STUBBED) called"); 161 LOG_WARNING(Service_FS, "(STUBBED) called");
225 162
226 struct FileSystemAttribute { 163 FileSys::FileSystemAttribute savedata_attribute{};
227 u8 dir_entry_name_length_max_defined;
228 u8 file_entry_name_length_max_defined;
229 u8 dir_path_name_length_max_defined;
230 u8 file_path_name_length_max_defined;
231 INSERT_PADDING_BYTES_NOINIT(0x5);
232 u8 utf16_dir_entry_name_length_max_defined;
233 u8 utf16_file_entry_name_length_max_defined;
234 u8 utf16_dir_path_name_length_max_defined;
235 u8 utf16_file_path_name_length_max_defined;
236 INSERT_PADDING_BYTES_NOINIT(0x18);
237 s32 dir_entry_name_length_max;
238 s32 file_entry_name_length_max;
239 s32 dir_path_name_length_max;
240 s32 file_path_name_length_max;
241 INSERT_PADDING_WORDS_NOINIT(0x5);
242 s32 utf16_dir_entry_name_length_max;
243 s32 utf16_file_entry_name_length_max;
244 s32 utf16_dir_path_name_length_max;
245 s32 utf16_file_path_name_length_max;
246 INSERT_PADDING_WORDS_NOINIT(0x18);
247 INSERT_PADDING_WORDS_NOINIT(0x1);
248 };
249 static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size");
250
251 FileSystemAttribute savedata_attribute{};
252 savedata_attribute.dir_entry_name_length_max_defined = true; 164 savedata_attribute.dir_entry_name_length_max_defined = true;
253 savedata_attribute.file_entry_name_length_max_defined = true; 165 savedata_attribute.file_entry_name_length_max_defined = true;
254 savedata_attribute.dir_entry_name_length_max = 0x40; 166 savedata_attribute.dir_entry_name_length_max = 0x40;
255 savedata_attribute.file_entry_name_length_max = 0x40; 167 savedata_attribute.file_entry_name_length_max = 0x40;
256 168
257 IPC::ResponseBuilder rb{ctx, 50}; 169 *out_attribute = savedata_attribute;
258 rb.Push(ResultSuccess); 170 R_SUCCEED();
259 rb.PushRaw(savedata_attribute);
260} 171}
261 172
262} // namespace Service::FileSystem 173} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
index b06b3ef0e..dd069f36f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
@@ -3,36 +3,58 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_funcs.h"
7#include "core/file_sys/fs_filesystem.h"
8#include "core/file_sys/fsa/fs_i_filesystem.h"
6#include "core/file_sys/vfs/vfs.h" 9#include "core/file_sys/vfs/vfs.h"
10#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 11#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/filesystem/fsp/fsp_util.h" 12#include "core/hle/service/filesystem/fsp/fsp_types.h"
9#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
10 14
15namespace FileSys::Sf {
16struct Path;
17}
18
11namespace Service::FileSystem { 19namespace Service::FileSystem {
12 20
21class IFile;
22class IDirectory;
23
13class IFileSystem final : public ServiceFramework<IFileSystem> { 24class IFileSystem final : public ServiceFramework<IFileSystem> {
14public: 25public:
15 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_); 26 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_);
16 27
17 void CreateFile(HLERequestContext& ctx); 28 Result CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, s32 option,
18 void DeleteFile(HLERequestContext& ctx); 29 s64 size);
19 void CreateDirectory(HLERequestContext& ctx); 30 Result DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
20 void DeleteDirectory(HLERequestContext& ctx); 31 Result CreateDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
21 void DeleteDirectoryRecursively(HLERequestContext& ctx); 32 Result DeleteDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
22 void CleanDirectoryRecursively(HLERequestContext& ctx); 33 Result DeleteDirectoryRecursively(
23 void RenameFile(HLERequestContext& ctx); 34 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
24 void OpenFile(HLERequestContext& ctx); 35 Result CleanDirectoryRecursively(
25 void OpenDirectory(HLERequestContext& ctx); 36 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
26 void GetEntryType(HLERequestContext& ctx); 37 Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
27 void Commit(HLERequestContext& ctx); 38 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path);
28 void GetFreeSpaceSize(HLERequestContext& ctx); 39 Result OpenFile(OutInterface<IFile> out_interface,
29 void GetTotalSpaceSize(HLERequestContext& ctx); 40 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode);
30 void GetFileTimeStampRaw(HLERequestContext& ctx); 41 Result OpenDirectory(OutInterface<IDirectory> out_interface,
31 void GetFileSystemAttribute(HLERequestContext& ctx); 42 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
43 u32 mode);
44 Result GetEntryType(Out<u32> out_type,
45 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
46 Result Commit();
47 Result GetFreeSpaceSize(Out<s64> out_size,
48 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
49 Result GetTotalSpaceSize(Out<s64> out_size,
50 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
51 Result GetFileTimeStampRaw(Out<FileSys::FileTimeStampRaw> out_timestamp,
52 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
53 Result GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute);
32 54
33private: 55private:
34 VfsDirectoryServiceWrapper backend; 56 std::unique_ptr<FileSys::Fsa::IFileSystem> backend;
35 SizeGetter size; 57 SizeGetter size_getter;
36}; 58};
37 59
38} // namespace Service::FileSystem 60} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
new file mode 100644
index 000000000..626328234
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
6#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
7
8namespace Service::FileSystem {
9
10IMultiCommitManager::IMultiCommitManager(Core::System& system_)
11 : ServiceFramework{system_, "IMultiCommitManager"} {
12 static const FunctionInfo functions[] = {
13 {1, D<&IMultiCommitManager::Add>, "Add"},
14 {2, D<&IMultiCommitManager::Commit>, "Commit"},
15 };
16 RegisterHandlers(functions);
17}
18
19IMultiCommitManager::~IMultiCommitManager() = default;
20
21Result IMultiCommitManager::Add(std::shared_ptr<IFileSystem> filesystem) {
22 LOG_WARNING(Service_FS, "(STUBBED) called");
23
24 R_SUCCEED();
25}
26
27Result IMultiCommitManager::Commit() {
28 LOG_WARNING(Service_FS, "(STUBBED) called");
29
30 R_SUCCEED();
31}
32
33} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
new file mode 100644
index 000000000..8ebf7c7d9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
@@ -0,0 +1,23 @@
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/file_sys/vfs/vfs.h"
7#include "core/hle/service/service.h"
8
9namespace Service::FileSystem {
10
11class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
12public:
13 explicit IMultiCommitManager(Core::System& system_);
14 ~IMultiCommitManager() override;
15
16private:
17 Result Add(std::shared_ptr<IFileSystem> filesystem);
18 Result Commit();
19
20 FileSys::VirtualFile backend;
21};
22
23} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
new file mode 100644
index 000000000..ff823586b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
@@ -0,0 +1,161 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/hex_util.h"
5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
8#include "core/hle/service/filesystem/save_data_controller.h"
9
10namespace Service::FileSystem {
11
12ISaveDataInfoReader::ISaveDataInfoReader(Core::System& system_,
13 std::shared_ptr<SaveDataController> save_data_controller_,
14 FileSys::SaveDataSpaceId space)
15 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
16 save_data_controller_} {
17 static const FunctionInfo functions[] = {
18 {0, D<&ISaveDataInfoReader::ReadSaveDataInfo>, "ReadSaveDataInfo"},
19 };
20 RegisterHandlers(functions);
21
22 FindAllSaves(space);
23}
24
25ISaveDataInfoReader::~ISaveDataInfoReader() = default;
26
27static u64 stoull_be(std::string_view str) {
28 if (str.size() != 16) {
29 return 0;
30 }
31
32 const auto bytes = Common::HexStringToArray<0x8>(str);
33 u64 out{};
34 std::memcpy(&out, bytes.data(), sizeof(u64));
35
36 return Common::swap64(out);
37}
38
39Result ISaveDataInfoReader::ReadSaveDataInfo(
40 Out<u64> out_count, OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries) {
41 LOG_DEBUG(Service_FS, "called");
42
43 // Calculate how many entries we can fit in the output buffer
44 const u64 count_entries = out_entries.size();
45
46 // Cap at total number of entries.
47 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
48
49 // Determine data start and end
50 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
51 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
52 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
53
54 next_entry_index += actual_entries;
55
56 // Write the data to memory
57 std::memcpy(out_entries.data(), begin, range_size);
58 *out_count = actual_entries;
59
60 R_SUCCEED();
61}
62
63void ISaveDataInfoReader::FindAllSaves(FileSys::SaveDataSpaceId space) {
64 FileSys::VirtualDir save_root{};
65 const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
66
67 if (result != ResultSuccess || save_root == nullptr) {
68 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
69 return;
70 }
71
72 for (const auto& type : save_root->GetSubdirectories()) {
73 if (type->GetName() == "save") {
74 FindNormalSaves(space, type);
75 } else if (space == FileSys::SaveDataSpaceId::Temporary) {
76 FindTemporaryStorageSaves(space, type);
77 }
78 }
79}
80
81void ISaveDataInfoReader::FindNormalSaves(FileSys::SaveDataSpaceId space,
82 const FileSys::VirtualDir& type) {
83 for (const auto& save_id : type->GetSubdirectories()) {
84 for (const auto& user_id : save_id->GetSubdirectories()) {
85 // Skip non user id subdirectories
86 if (user_id->GetName().size() != 0x20) {
87 continue;
88 }
89
90 const auto save_id_numeric = stoull_be(save_id->GetName());
91 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
92 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
93
94 if (save_id_numeric != 0) {
95 // System Save Data
96 info.emplace_back(SaveDataInfo{
97 0,
98 space,
99 FileSys::SaveDataType::System,
100 {},
101 user_id_numeric,
102 save_id_numeric,
103 0,
104 user_id->GetSize(),
105 {},
106 {},
107 });
108
109 continue;
110 }
111
112 for (const auto& title_id : user_id->GetSubdirectories()) {
113 const auto device = std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
114 [](u8 val) { return val == 0; });
115 info.emplace_back(SaveDataInfo{
116 0,
117 space,
118 device ? FileSys::SaveDataType::Device : FileSys::SaveDataType::Account,
119 {},
120 user_id_numeric,
121 save_id_numeric,
122 stoull_be(title_id->GetName()),
123 title_id->GetSize(),
124 {},
125 {},
126 });
127 }
128 }
129 }
130}
131
132void ISaveDataInfoReader::FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space,
133 const FileSys::VirtualDir& type) {
134 for (const auto& user_id : type->GetSubdirectories()) {
135 // Skip non user id subdirectories
136 if (user_id->GetName().size() != 0x20) {
137 continue;
138 }
139 for (const auto& title_id : user_id->GetSubdirectories()) {
140 if (!title_id->GetFiles().empty() || !title_id->GetSubdirectories().empty()) {
141 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
142 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
143
144 info.emplace_back(SaveDataInfo{
145 0,
146 space,
147 FileSys::SaveDataType::Temporary,
148 {},
149 user_id_numeric,
150 stoull_be(type->GetName()),
151 stoull_be(title_id->GetName()),
152 title_id->GetSize(),
153 {},
154 {},
155 });
156 }
157 }
158 }
159}
160
161} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
new file mode 100644
index 000000000..e45ad852b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <vector>
7#include "common/common_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::FileSystem {
12
13class SaveDataController;
14
15class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
16public:
17 explicit ISaveDataInfoReader(Core::System& system_,
18 std::shared_ptr<SaveDataController> save_data_controller_,
19 FileSys::SaveDataSpaceId space);
20 ~ISaveDataInfoReader() override;
21
22 struct SaveDataInfo {
23 u64_le save_id_unknown;
24 FileSys::SaveDataSpaceId space;
25 FileSys::SaveDataType type;
26 INSERT_PADDING_BYTES(0x6);
27 std::array<u8, 0x10> user_id;
28 u64_le save_id;
29 u64_le title_id;
30 u64_le save_image_size;
31 u16_le index;
32 FileSys::SaveDataRank rank;
33 INSERT_PADDING_BYTES(0x25);
34 };
35 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
36
37 Result ReadSaveDataInfo(Out<u64> out_count,
38 OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries);
39
40private:
41 void FindAllSaves(FileSys::SaveDataSpaceId space);
42 void FindNormalSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
43 void FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
44
45 std::shared_ptr<SaveDataController> save_data_controller;
46 std::vector<SaveDataInfo> info;
47 u64 next_entry_index = 0;
48};
49
50} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
index 98223c1f9..213f19808 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
@@ -2,61 +2,44 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/errors.h" 4#include "core/file_sys/errors.h"
5#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_storage.h" 6#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
6#include "core/hle/service/ipc_helpers.h"
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) 10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { 11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &IStorage::Read, "Read"}, 13 {0, D<&IStorage::Read>, "Read"},
14 {1, nullptr, "Write"}, 14 {1, nullptr, "Write"},
15 {2, nullptr, "Flush"}, 15 {2, nullptr, "Flush"},
16 {3, nullptr, "SetSize"}, 16 {3, nullptr, "SetSize"},
17 {4, &IStorage::GetSize, "GetSize"}, 17 {4, D<&IStorage::GetSize>, "GetSize"},
18 {5, nullptr, "OperateRange"}, 18 {5, nullptr, "OperateRange"},
19 }; 19 };
20 RegisterHandlers(functions); 20 RegisterHandlers(functions);
21} 21}
22 22
23void IStorage::Read(HLERequestContext& ctx) { 23Result IStorage::Read(
24 IPC::RequestParser rp{ctx}; 24 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
25 const s64 offset = rp.Pop<s64>(); 25 s64 offset, s64 length) {
26 const s64 length = rp.Pop<s64>();
27
28 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); 26 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
29 27
30 // Error checking 28 R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
31 if (length < 0) { 29 R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset);
32 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
33 IPC::ResponseBuilder rb{ctx, 2};
34 rb.Push(FileSys::ResultInvalidSize);
35 return;
36 }
37 if (offset < 0) {
38 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(FileSys::ResultInvalidOffset);
41 return;
42 }
43 30
44 // Read the data from the Storage backend 31 // Read the data from the Storage backend
45 std::vector<u8> output = backend->ReadBytes(length, offset); 32 backend->Read(out_bytes.data(), length, offset);
46 // Write the data to memory
47 ctx.WriteBuffer(output);
48 33
49 IPC::ResponseBuilder rb{ctx, 2}; 34 R_SUCCEED();
50 rb.Push(ResultSuccess);
51} 35}
52 36
53void IStorage::GetSize(HLERequestContext& ctx) { 37Result IStorage::GetSize(Out<u64> out_size) {
54 const u64 size = backend->GetSize(); 38 *out_size = backend->GetSize();
55 LOG_DEBUG(Service_FS, "called, size={}", size); 39
40 LOG_DEBUG(Service_FS, "called, size={}", *out_size);
56 41
57 IPC::ResponseBuilder rb{ctx, 4}; 42 R_SUCCEED();
58 rb.Push(ResultSuccess);
59 rb.Push<u64>(size);
60} 43}
61 44
62} // namespace Service::FileSystem 45} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
index cb5bebcc9..74d879386 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs/vfs.h" 6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 8#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
@@ -16,8 +17,10 @@ public:
16private: 17private:
17 FileSys::VirtualFile backend; 18 FileSys::VirtualFile backend;
18 19
19 void Read(HLERequestContext& ctx); 20 Result Read(
20 void GetSize(HLERequestContext& ctx); 21 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
22 s64 offset, s64 length);
23 Result GetSize(Out<u64> out_size);
21}; 24};
22 25
23} // namespace Service::FileSystem 26} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index 2d49f30c8..fc67a4713 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -27,8 +27,11 @@
27#include "core/file_sys/system_archive/system_archive.h" 27#include "core/file_sys/system_archive/system_archive.h"
28#include "core/file_sys/vfs/vfs.h" 28#include "core/file_sys/vfs/vfs.h"
29#include "core/hle/result.h" 29#include "core/hle/result.h"
30#include "core/hle/service/cmif_serialization.h"
30#include "core/hle/service/filesystem/filesystem.h" 31#include "core/hle/service/filesystem/filesystem.h"
31#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" 32#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
33#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
34#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
32#include "core/hle/service/filesystem/fsp/fs_i_storage.h" 35#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
33#include "core/hle/service/filesystem/fsp/fsp_srv.h" 36#include "core/hle/service/filesystem/fsp/fsp_srv.h"
34#include "core/hle/service/filesystem/romfs_controller.h" 37#include "core/hle/service/filesystem/romfs_controller.h"
@@ -39,182 +42,6 @@
39#include "core/reporter.h" 42#include "core/reporter.h"
40 43
41namespace Service::FileSystem { 44namespace Service::FileSystem {
42enum class FileSystemProxyType : u8 {
43 Code = 0,
44 Rom = 1,
45 Logo = 2,
46 Control = 3,
47 Manual = 4,
48 Meta = 5,
49 Data = 6,
50 Package = 7,
51 RegisteredUpdate = 8,
52};
53
54class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
55public:
56 explicit ISaveDataInfoReader(Core::System& system_,
57 std::shared_ptr<SaveDataController> save_data_controller_,
58 FileSys::SaveDataSpaceId space)
59 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
60 save_data_controller_} {
61 static const FunctionInfo functions[] = {
62 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
63 };
64 RegisterHandlers(functions);
65
66 FindAllSaves(space);
67 }
68
69 void ReadSaveDataInfo(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_FS, "called");
71
72 // Calculate how many entries we can fit in the output buffer
73 const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
74
75 // Cap at total number of entries.
76 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
77
78 // Determine data start and end
79 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
80 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
81 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
82
83 next_entry_index += actual_entries;
84
85 // Write the data to memory
86 ctx.WriteBuffer(begin, range_size);
87
88 IPC::ResponseBuilder rb{ctx, 4};
89 rb.Push(ResultSuccess);
90 rb.Push<u64>(actual_entries);
91 }
92
93private:
94 static u64 stoull_be(std::string_view str) {
95 if (str.size() != 16)
96 return 0;
97
98 const auto bytes = Common::HexStringToArray<0x8>(str);
99 u64 out{};
100 std::memcpy(&out, bytes.data(), sizeof(u64));
101
102 return Common::swap64(out);
103 }
104
105 void FindAllSaves(FileSys::SaveDataSpaceId space) {
106 FileSys::VirtualDir save_root{};
107 const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
108
109 if (result != ResultSuccess || save_root == nullptr) {
110 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
111 return;
112 }
113
114 for (const auto& type : save_root->GetSubdirectories()) {
115 if (type->GetName() == "save") {
116 for (const auto& save_id : type->GetSubdirectories()) {
117 for (const auto& user_id : save_id->GetSubdirectories()) {
118 // Skip non user id subdirectories
119 if (user_id->GetName().size() != 0x20) {
120 continue;
121 }
122
123 const auto save_id_numeric = stoull_be(save_id->GetName());
124 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
125 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
126
127 if (save_id_numeric != 0) {
128 // System Save Data
129 info.emplace_back(SaveDataInfo{
130 0,
131 space,
132 FileSys::SaveDataType::SystemSaveData,
133 {},
134 user_id_numeric,
135 save_id_numeric,
136 0,
137 user_id->GetSize(),
138 {},
139 {},
140 });
141
142 continue;
143 }
144
145 for (const auto& title_id : user_id->GetSubdirectories()) {
146 const auto device =
147 std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
148 [](u8 val) { return val == 0; });
149 info.emplace_back(SaveDataInfo{
150 0,
151 space,
152 device ? FileSys::SaveDataType::DeviceSaveData
153 : FileSys::SaveDataType::SaveData,
154 {},
155 user_id_numeric,
156 save_id_numeric,
157 stoull_be(title_id->GetName()),
158 title_id->GetSize(),
159 {},
160 {},
161 });
162 }
163 }
164 }
165 } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
166 // Temporary Storage
167 for (const auto& user_id : type->GetSubdirectories()) {
168 // Skip non user id subdirectories
169 if (user_id->GetName().size() != 0x20) {
170 continue;
171 }
172 for (const auto& title_id : user_id->GetSubdirectories()) {
173 if (!title_id->GetFiles().empty() ||
174 !title_id->GetSubdirectories().empty()) {
175 auto user_id_numeric =
176 Common::HexStringToArray<0x10>(user_id->GetName());
177 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
178
179 info.emplace_back(SaveDataInfo{
180 0,
181 space,
182 FileSys::SaveDataType::TemporaryStorage,
183 {},
184 user_id_numeric,
185 stoull_be(type->GetName()),
186 stoull_be(title_id->GetName()),
187 title_id->GetSize(),
188 {},
189 {},
190 });
191 }
192 }
193 }
194 }
195 }
196 }
197
198 struct SaveDataInfo {
199 u64_le save_id_unknown;
200 FileSys::SaveDataSpaceId space;
201 FileSys::SaveDataType type;
202 INSERT_PADDING_BYTES(0x6);
203 std::array<u8, 0x10> user_id;
204 u64_le save_id;
205 u64_le title_id;
206 u64_le save_image_size;
207 u16_le index;
208 FileSys::SaveDataRank rank;
209 INSERT_PADDING_BYTES(0x25);
210 };
211 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
212
213 ProcessId process_id = 0;
214 std::shared_ptr<SaveDataController> save_data_controller;
215 std::vector<SaveDataInfo> info;
216 u64 next_entry_index = 0;
217};
218 45
219FSP_SRV::FSP_SRV(Core::System& system_) 46FSP_SRV::FSP_SRV(Core::System& system_)
220 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()}, 47 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
@@ -222,20 +49,20 @@ FSP_SRV::FSP_SRV(Core::System& system_)
222 // clang-format off 49 // clang-format off
223 static const FunctionInfo functions[] = { 50 static const FunctionInfo functions[] = {
224 {0, nullptr, "OpenFileSystem"}, 51 {0, nullptr, "OpenFileSystem"},
225 {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"}, 52 {1, D<&FSP_SRV::SetCurrentProcess>, "SetCurrentProcess"},
226 {2, nullptr, "OpenDataFileSystemByCurrentProcess"}, 53 {2, nullptr, "OpenDataFileSystemByCurrentProcess"},
227 {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"}, 54 {7, D<&FSP_SRV::OpenFileSystemWithPatch>, "OpenFileSystemWithPatch"},
228 {8, nullptr, "OpenFileSystemWithId"}, 55 {8, nullptr, "OpenFileSystemWithId"},
229 {9, nullptr, "OpenDataFileSystemByApplicationId"}, 56 {9, nullptr, "OpenDataFileSystemByApplicationId"},
230 {11, nullptr, "OpenBisFileSystem"}, 57 {11, nullptr, "OpenBisFileSystem"},
231 {12, nullptr, "OpenBisStorage"}, 58 {12, nullptr, "OpenBisStorage"},
232 {13, nullptr, "InvalidateBisCache"}, 59 {13, nullptr, "InvalidateBisCache"},
233 {17, nullptr, "OpenHostFileSystem"}, 60 {17, nullptr, "OpenHostFileSystem"},
234 {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"}, 61 {18, D<&FSP_SRV::OpenSdCardFileSystem>, "OpenSdCardFileSystem"},
235 {19, nullptr, "FormatSdCardFileSystem"}, 62 {19, nullptr, "FormatSdCardFileSystem"},
236 {21, nullptr, "DeleteSaveDataFileSystem"}, 63 {21, nullptr, "DeleteSaveDataFileSystem"},
237 {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"}, 64 {22, D<&FSP_SRV::CreateSaveDataFileSystem>, "CreateSaveDataFileSystem"},
238 {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"}, 65 {23, D<&FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId>, "CreateSaveDataFileSystemBySystemSaveDataId"},
239 {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"}, 66 {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
240 {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"}, 67 {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
241 {26, nullptr, "FormatSdCardDryRun"}, 68 {26, nullptr, "FormatSdCardDryRun"},
@@ -245,26 +72,26 @@ FSP_SRV::FSP_SRV(Core::System& system_)
245 {31, nullptr, "OpenGameCardFileSystem"}, 72 {31, nullptr, "OpenGameCardFileSystem"},
246 {32, nullptr, "ExtendSaveDataFileSystem"}, 73 {32, nullptr, "ExtendSaveDataFileSystem"},
247 {33, nullptr, "DeleteCacheStorage"}, 74 {33, nullptr, "DeleteCacheStorage"},
248 {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"}, 75 {34, D<&FSP_SRV::GetCacheStorageSize>, "GetCacheStorageSize"},
249 {35, nullptr, "CreateSaveDataFileSystemByHashSalt"}, 76 {35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
250 {36, nullptr, "OpenHostFileSystemWithOption"}, 77 {36, nullptr, "OpenHostFileSystemWithOption"},
251 {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"}, 78 {51, D<&FSP_SRV::OpenSaveDataFileSystem>, "OpenSaveDataFileSystem"},
252 {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"}, 79 {52, D<&FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId>, "OpenSaveDataFileSystemBySystemSaveDataId"},
253 {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"}, 80 {53, D<&FSP_SRV::OpenReadOnlySaveDataFileSystem>, "OpenReadOnlySaveDataFileSystem"},
254 {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"}, 81 {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
255 {58, nullptr, "ReadSaveDataFileSystemExtraData"}, 82 {58, nullptr, "ReadSaveDataFileSystemExtraData"},
256 {59, nullptr, "WriteSaveDataFileSystemExtraData"}, 83 {59, nullptr, "WriteSaveDataFileSystemExtraData"},
257 {60, nullptr, "OpenSaveDataInfoReader"}, 84 {60, nullptr, "OpenSaveDataInfoReader"},
258 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, 85 {61, D<&FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId>, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
259 {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"}, 86 {62, D<&FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage>, "OpenSaveDataInfoReaderOnlyCacheStorage"},
260 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, 87 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
261 {65, nullptr, "UpdateSaveDataMacForDebug"}, 88 {65, nullptr, "UpdateSaveDataMacForDebug"},
262 {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, 89 {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
263 {67, nullptr, "FindSaveDataWithFilter"}, 90 {67, nullptr, "FindSaveDataWithFilter"},
264 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"}, 91 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
265 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"}, 92 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
266 {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"}, 93 {70, D<&FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute>, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
267 {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"}, 94 {71, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute>, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
268 {80, nullptr, "OpenSaveDataMetaFile"}, 95 {80, nullptr, "OpenSaveDataMetaFile"},
269 {81, nullptr, "OpenSaveDataTransferManager"}, 96 {81, nullptr, "OpenSaveDataTransferManager"},
270 {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, 97 {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
@@ -279,12 +106,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
279 {110, nullptr, "OpenContentStorageFileSystem"}, 106 {110, nullptr, "OpenContentStorageFileSystem"},
280 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, 107 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
281 {130, nullptr, "OpenCustomStorageFileSystem"}, 108 {130, nullptr, "OpenCustomStorageFileSystem"},
282 {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, 109 {200, D<&FSP_SRV::OpenDataStorageByCurrentProcess>, "OpenDataStorageByCurrentProcess"},
283 {201, nullptr, "OpenDataStorageByProgramId"}, 110 {201, nullptr, "OpenDataStorageByProgramId"},
284 {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, 111 {202, D<&FSP_SRV::OpenDataStorageByDataId>, "OpenDataStorageByDataId"},
285 {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, 112 {203, D<&FSP_SRV::OpenPatchDataStorageByCurrentProcess>, "OpenPatchDataStorageByCurrentProcess"},
286 {204, nullptr, "OpenDataFileSystemByProgramIndex"}, 113 {204, nullptr, "OpenDataFileSystemByProgramIndex"},
287 {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, 114 {205, D<&FSP_SRV::OpenDataStorageWithProgramIndex>, "OpenDataStorageWithProgramIndex"},
288 {206, nullptr, "OpenDataStorageByPath"}, 115 {206, nullptr, "OpenDataStorageByPath"},
289 {400, nullptr, "OpenDeviceOperator"}, 116 {400, nullptr, "OpenDeviceOperator"},
290 {500, nullptr, "OpenSdCardDetectionEventNotifier"}, 117 {500, nullptr, "OpenSdCardDetectionEventNotifier"},
@@ -324,25 +151,25 @@ FSP_SRV::FSP_SRV(Core::System& system_)
324 {1000, nullptr, "SetBisRootForHost"}, 151 {1000, nullptr, "SetBisRootForHost"},
325 {1001, nullptr, "SetSaveDataSize"}, 152 {1001, nullptr, "SetSaveDataSize"},
326 {1002, nullptr, "SetSaveDataRootPath"}, 153 {1002, nullptr, "SetSaveDataRootPath"},
327 {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"}, 154 {1003, D<&FSP_SRV::DisableAutoSaveDataCreation>, "DisableAutoSaveDataCreation"},
328 {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"}, 155 {1004, D<&FSP_SRV::SetGlobalAccessLogMode>, "SetGlobalAccessLogMode"},
329 {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, 156 {1005, D<&FSP_SRV::GetGlobalAccessLogMode>, "GetGlobalAccessLogMode"},
330 {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"}, 157 {1006, D<&FSP_SRV::OutputAccessLogToSdCard>, "OutputAccessLogToSdCard"},
331 {1007, nullptr, "RegisterUpdatePartition"}, 158 {1007, nullptr, "RegisterUpdatePartition"},
332 {1008, nullptr, "OpenRegisteredUpdatePartition"}, 159 {1008, nullptr, "OpenRegisteredUpdatePartition"},
333 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 160 {1009, nullptr, "GetAndClearMemoryReportInfo"},
334 {1010, nullptr, "SetDataStorageRedirectTarget"}, 161 {1010, nullptr, "SetDataStorageRedirectTarget"},
335 {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"}, 162 {1011, D<&FSP_SRV::GetProgramIndexForAccessLog>, "GetProgramIndexForAccessLog"},
336 {1012, nullptr, "GetFsStackUsage"}, 163 {1012, nullptr, "GetFsStackUsage"},
337 {1013, nullptr, "UnsetSaveDataRootPath"}, 164 {1013, nullptr, "UnsetSaveDataRootPath"},
338 {1014, nullptr, "OutputMultiProgramTagAccessLog"}, 165 {1014, nullptr, "OutputMultiProgramTagAccessLog"},
339 {1016, &FSP_SRV::FlushAccessLogOnSdCard, "FlushAccessLogOnSdCard"}, 166 {1016, D<&FSP_SRV::FlushAccessLogOnSdCard>, "FlushAccessLogOnSdCard"},
340 {1017, nullptr, "OutputApplicationInfoAccessLog"}, 167 {1017, nullptr, "OutputApplicationInfoAccessLog"},
341 {1018, nullptr, "SetDebugOption"}, 168 {1018, nullptr, "SetDebugOption"},
342 {1019, nullptr, "UnsetDebugOption"}, 169 {1019, nullptr, "UnsetDebugOption"},
343 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 170 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
344 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, 171 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
345 {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, 172 {1200, D<&FSP_SRV::OpenMultiCommitManager>, "OpenMultiCommitManager"},
346 {1300, nullptr, "OpenBisWiper"}, 173 {1300, nullptr, "OpenBisWiper"},
347 }; 174 };
348 // clang-format on 175 // clang-format on
@@ -355,234 +182,177 @@ FSP_SRV::FSP_SRV(Core::System& system_)
355 182
356FSP_SRV::~FSP_SRV() = default; 183FSP_SRV::~FSP_SRV() = default;
357 184
358void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { 185Result FSP_SRV::SetCurrentProcess(ClientProcessId pid) {
359 current_process_id = ctx.GetPID(); 186 current_process_id = *pid;
360 187
361 LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); 188 LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
362 189
363 const auto res = 190 R_RETURN(
364 fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id); 191 fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id));
365
366 IPC::ResponseBuilder rb{ctx, 2};
367 rb.Push(res);
368} 192}
369 193
370void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { 194Result FSP_SRV::OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
371 IPC::RequestParser rp{ctx}; 195 FileSystemProxyType type, u64 open_program_id) {
372 196 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", type,
373 struct InputParameters { 197 open_program_id);
374 FileSystemProxyType type;
375 u64 program_id;
376 };
377 static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size");
378
379 const auto params = rp.PopRaw<InputParameters>();
380 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type,
381 params.program_id);
382 198
383 // FIXME: many issues with this 199 // FIXME: many issues with this
384 ASSERT(params.type == FileSystemProxyType::Manual); 200 ASSERT(type == FileSystemProxyType::Manual);
385 const auto manual_romfs = romfs_controller->OpenPatchedRomFS( 201 const auto manual_romfs = romfs_controller->OpenPatchedRomFS(
386 params.program_id, FileSys::ContentRecordType::HtmlDocument); 202 open_program_id, FileSys::ContentRecordType::HtmlDocument);
387 203
388 ASSERT(manual_romfs != nullptr); 204 ASSERT(manual_romfs != nullptr);
389 205
390 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs); 206 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs);
391 ASSERT(extracted_romfs != nullptr); 207 ASSERT(extracted_romfs != nullptr);
392 208
393 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 209 *out_interface = std::make_shared<IFileSystem>(
394 rb.Push(ResultSuccess); 210 system, extracted_romfs, SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
395 rb.PushIpcInterface<IFileSystem>(system, extracted_romfs, 211
396 SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser)); 212 R_SUCCEED();
397} 213}
398 214
399void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { 215Result FSP_SRV::OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface) {
400 LOG_DEBUG(Service_FS, "called"); 216 LOG_DEBUG(Service_FS, "called");
401 217
402 FileSys::VirtualDir sdmc_dir{}; 218 FileSys::VirtualDir sdmc_dir{};
403 fsc.OpenSDMC(&sdmc_dir); 219 fsc.OpenSDMC(&sdmc_dir);
404 220
405 auto filesystem = std::make_shared<IFileSystem>( 221 *out_interface = std::make_shared<IFileSystem>(
406 system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); 222 system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
407 223
408 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 224 R_SUCCEED();
409 rb.Push(ResultSuccess);
410 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
411} 225}
412 226
413void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) { 227Result FSP_SRV::CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
414 IPC::RequestParser rp{ctx}; 228 FileSys::SaveDataAttribute save_struct, u128 uid) {
415
416 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
417 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
418 u128 uid = rp.PopRaw<u128>();
419
420 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), 229 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
421 uid[1], uid[0]); 230 uid[1], uid[0]);
422 231
423 FileSys::VirtualDir save_data_dir{}; 232 FileSys::VirtualDir save_data_dir{};
424 save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, 233 R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::User,
425 save_struct); 234 save_struct));
426
427 IPC::ResponseBuilder rb{ctx, 2};
428 rb.Push(ResultSuccess);
429} 235}
430 236
431void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { 237Result FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(
432 IPC::RequestParser rp{ctx}; 238 FileSys::SaveDataCreationInfo save_create_struct, FileSys::SaveDataAttribute save_struct) {
433
434 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
435 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
436
437 LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); 239 LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
438 240
439 FileSys::VirtualDir save_data_dir{}; 241 FileSys::VirtualDir save_data_dir{};
440 save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, 242 R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::System,
441 save_struct); 243 save_struct));
442
443 IPC::ResponseBuilder rb{ctx, 2};
444 rb.Push(ResultSuccess);
445} 244}
446 245
447void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { 246Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
448 IPC::RequestParser rp{ctx}; 247 FileSys::SaveDataSpaceId space_id,
449 248 FileSys::SaveDataAttribute attribute) {
450 struct Parameters {
451 FileSys::SaveDataSpaceId space_id;
452 FileSys::SaveDataAttribute attribute;
453 };
454
455 const auto parameters = rp.PopRaw<Parameters>();
456
457 LOG_INFO(Service_FS, "called."); 249 LOG_INFO(Service_FS, "called.");
458 250
459 FileSys::VirtualDir dir{}; 251 FileSys::VirtualDir dir{};
460 auto result = 252 R_TRY(save_data_controller->OpenSaveData(&dir, space_id, attribute));
461 save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
462 if (result != ResultSuccess) {
463 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
464 rb.Push(FileSys::ResultTargetNotFound);
465 return;
466 }
467 253
468 FileSys::StorageId id{}; 254 FileSys::StorageId id{};
469 switch (parameters.space_id) { 255 switch (space_id) {
470 case FileSys::SaveDataSpaceId::NandUser: 256 case FileSys::SaveDataSpaceId::User:
471 id = FileSys::StorageId::NandUser; 257 id = FileSys::StorageId::NandUser;
472 break; 258 break;
473 case FileSys::SaveDataSpaceId::SdCardSystem: 259 case FileSys::SaveDataSpaceId::SdSystem:
474 case FileSys::SaveDataSpaceId::SdCardUser: 260 case FileSys::SaveDataSpaceId::SdUser:
475 id = FileSys::StorageId::SdCard; 261 id = FileSys::StorageId::SdCard;
476 break; 262 break;
477 case FileSys::SaveDataSpaceId::NandSystem: 263 case FileSys::SaveDataSpaceId::System:
478 id = FileSys::StorageId::NandSystem; 264 id = FileSys::StorageId::NandSystem;
479 break; 265 break;
480 case FileSys::SaveDataSpaceId::TemporaryStorage: 266 case FileSys::SaveDataSpaceId::Temporary:
481 case FileSys::SaveDataSpaceId::ProperSystem: 267 case FileSys::SaveDataSpaceId::ProperSystem:
482 case FileSys::SaveDataSpaceId::SafeMode: 268 case FileSys::SaveDataSpaceId::SafeMode:
483 ASSERT(false); 269 ASSERT(false);
484 } 270 }
485 271
486 auto filesystem = 272 *out_interface =
487 std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id)); 273 std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
488 274
489 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 275 R_SUCCEED();
490 rb.Push(ResultSuccess);
491 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
492} 276}
493 277
494void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { 278Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
279 FileSys::SaveDataSpaceId space_id,
280 FileSys::SaveDataAttribute attribute) {
495 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); 281 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
496 OpenSaveDataFileSystem(ctx); 282 R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
497} 283}
498 284
499void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) { 285Result FSP_SRV::OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
286 FileSys::SaveDataSpaceId space_id,
287 FileSys::SaveDataAttribute attribute) {
500 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); 288 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
501 OpenSaveDataFileSystem(ctx); 289 R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
502} 290}
503 291
504void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) { 292Result FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(
505 IPC::RequestParser rp{ctx}; 293 OutInterface<ISaveDataInfoReader> out_interface, FileSys::SaveDataSpaceId space) {
506 const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
507 LOG_INFO(Service_FS, "called, space={}", space); 294 LOG_INFO(Service_FS, "called, space={}", space);
508 295
509 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 296 *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space);
510 rb.Push(ResultSuccess); 297
511 rb.PushIpcInterface<ISaveDataInfoReader>( 298 R_SUCCEED();
512 std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space));
513} 299}
514 300
515void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { 301Result FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(
302 OutInterface<ISaveDataInfoReader> out_interface) {
516 LOG_WARNING(Service_FS, "(STUBBED) called"); 303 LOG_WARNING(Service_FS, "(STUBBED) called");
517 304
518 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 305 *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller,
519 rb.Push(ResultSuccess); 306 FileSys::SaveDataSpaceId::Temporary);
520 rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller, 307
521 FileSys::SaveDataSpaceId::TemporaryStorage); 308 R_SUCCEED();
522} 309}
523 310
524void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { 311Result FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute() {
525 LOG_WARNING(Service_FS, "(STUBBED) called."); 312 LOG_WARNING(Service_FS, "(STUBBED) called.");
526 313
527 IPC::ResponseBuilder rb{ctx, 2}; 314 R_SUCCEED();
528 rb.Push(ResultSuccess);
529} 315}
530 316
531void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) { 317Result FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
532 IPC::RequestParser rp{ctx}; 318 FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
533 319 InBuffer<BufferAttr_HipcMapAlias> mask_buffer, OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
534 struct Parameters {
535 FileSys::SaveDataSpaceId space_id;
536 FileSys::SaveDataAttribute attribute;
537 };
538
539 const auto parameters = rp.PopRaw<Parameters>();
540 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData 320 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
541 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None); 321 // In an earlier version of the code, this was returned as an out argument, but this is not
322 // correct
323 [[maybe_unused]] constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
542 324
543 LOG_WARNING(Service_FS, 325 LOG_WARNING(Service_FS,
544 "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" 326 "(STUBBED) called, flags={}, space_id={}, attribute.program_id={:016X}\n"
545 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" 327 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
546 "attribute.type={}, attribute.rank={}, attribute.index={}", 328 "attribute.type={}, attribute.rank={}, attribute.index={}",
547 flags, parameters.space_id, parameters.attribute.title_id, 329 flags, space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
548 parameters.attribute.user_id[1], parameters.attribute.user_id[0], 330 attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
549 parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank, 331
550 parameters.attribute.index); 332 R_SUCCEED();
551
552 IPC::ResponseBuilder rb{ctx, 3};
553 rb.Push(ResultSuccess);
554 rb.Push(flags);
555} 333}
556 334
557void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { 335Result FSP_SRV::OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface) {
558 LOG_DEBUG(Service_FS, "called"); 336 LOG_DEBUG(Service_FS, "called");
559 337
560 if (!romfs) { 338 if (!romfs) {
561 auto current_romfs = romfs_controller->OpenRomFSCurrentProcess(); 339 auto current_romfs = romfs_controller->OpenRomFSCurrentProcess();
562 if (!current_romfs) { 340 if (!current_romfs) {
563 // TODO (bunnei): Find the right error code to use here 341 // TODO (bunnei): Find the right error code to use here
564 LOG_CRITICAL(Service_FS, "no file system interface available!"); 342 LOG_CRITICAL(Service_FS, "No file system interface available!");
565 IPC::ResponseBuilder rb{ctx, 2}; 343 R_RETURN(ResultUnknown);
566 rb.Push(ResultUnknown);
567 return;
568 } 344 }
569 345
570 romfs = current_romfs; 346 romfs = current_romfs;
571 } 347 }
572 348
573 auto storage = std::make_shared<IStorage>(system, romfs); 349 *out_interface = std::make_shared<IStorage>(system, romfs);
574 350
575 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 351 R_SUCCEED();
576 rb.Push(ResultSuccess);
577 rb.PushIpcInterface<IStorage>(std::move(storage));
578} 352}
579 353
580void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { 354Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
581 IPC::RequestParser rp{ctx}; 355 FileSys::StorageId storage_id, u32 unknown, u64 title_id) {
582 const auto storage_id = rp.PopRaw<FileSys::StorageId>();
583 const auto unknown = rp.PopRaw<u32>();
584 const auto title_id = rp.PopRaw<u64>();
585
586 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", 356 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
587 storage_id, unknown, title_id); 357 storage_id, unknown, title_id);
588 358
@@ -592,19 +362,15 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
592 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); 362 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
593 363
594 if (archive != nullptr) { 364 if (archive != nullptr) {
595 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 365 *out_interface = std::make_shared<IStorage>(system, archive);
596 rb.Push(ResultSuccess); 366 R_SUCCEED();
597 rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
598 return;
599 } 367 }
600 368
601 // TODO(DarkLordZach): Find the right error code to use here 369 // TODO(DarkLordZach): Find the right error code to use here
602 LOG_ERROR(Service_FS, 370 LOG_ERROR(Service_FS,
603 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, 371 "Could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
604 storage_id); 372 storage_id);
605 IPC::ResponseBuilder rb{ctx, 2}; 373 R_RETURN(ResultUnknown);
606 rb.Push(ResultUnknown);
607 return;
608 } 374 }
609 375
610 const FileSys::PatchManager pm{title_id, fsc, content_provider}; 376 const FileSys::PatchManager pm{title_id, fsc, content_provider};
@@ -614,28 +380,20 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
614 auto storage = std::make_shared<IStorage>( 380 auto storage = std::make_shared<IStorage>(
615 system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); 381 system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
616 382
617 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 383 *out_interface = std::move(storage);
618 rb.Push(ResultSuccess); 384 R_SUCCEED();
619 rb.PushIpcInterface<IStorage>(std::move(storage));
620} 385}
621 386
622void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) { 387Result FSP_SRV::OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
623 IPC::RequestParser rp{ctx}; 388 FileSys::StorageId storage_id, u64 title_id) {
624 389 LOG_WARNING(Service_FS, "(STUBBED) called with storage_id={:02X}, title_id={:016X}", storage_id,
625 const auto storage_id = rp.PopRaw<FileSys::StorageId>(); 390 title_id);
626 const auto title_id = rp.PopRaw<u64>();
627 391
628 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id); 392 R_RETURN(FileSys::ResultTargetNotFound);
629
630 IPC::ResponseBuilder rb{ctx, 2};
631 rb.Push(FileSys::ResultTargetNotFound);
632} 393}
633 394
634void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { 395Result FSP_SRV::OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface,
635 IPC::RequestParser rp{ctx}; 396 u8 program_index) {
636
637 const auto program_index = rp.PopRaw<u8>();
638
639 LOG_DEBUG(Service_FS, "called, program_index={}", program_index); 397 LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
640 398
641 auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex( 399 auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex(
@@ -643,123 +401,80 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
643 401
644 if (!patched_romfs) { 402 if (!patched_romfs) {
645 // TODO: Find the right error code to use here 403 // TODO: Find the right error code to use here
646 LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index); 404 LOG_ERROR(Service_FS, "Could not open storage with program_index={}", program_index);
647 405 R_RETURN(ResultUnknown);
648 IPC::ResponseBuilder rb{ctx, 2};
649 rb.Push(ResultUnknown);
650 return;
651 } 406 }
652 407
653 auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs)); 408 *out_interface = std::make_shared<IStorage>(system, std::move(patched_romfs));
654 409
655 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 410 R_SUCCEED();
656 rb.Push(ResultSuccess);
657 rb.PushIpcInterface<IStorage>(std::move(storage));
658} 411}
659 412
660void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { 413Result FSP_SRV::DisableAutoSaveDataCreation() {
661 LOG_DEBUG(Service_FS, "called"); 414 LOG_DEBUG(Service_FS, "called");
662 415
663 save_data_controller->SetAutoCreate(false); 416 save_data_controller->SetAutoCreate(false);
664 417
665 IPC::ResponseBuilder rb{ctx, 2}; 418 R_SUCCEED();
666 rb.Push(ResultSuccess);
667} 419}
668 420
669void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) { 421Result FSP_SRV::SetGlobalAccessLogMode(AccessLogMode access_log_mode_) {
670 IPC::RequestParser rp{ctx}; 422 LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode_);
671 access_log_mode = rp.PopEnum<AccessLogMode>();
672 423
673 LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode); 424 access_log_mode = access_log_mode_;
674 425
675 IPC::ResponseBuilder rb{ctx, 2}; 426 R_SUCCEED();
676 rb.Push(ResultSuccess);
677} 427}
678 428
679void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) { 429Result FSP_SRV::GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode) {
680 LOG_DEBUG(Service_FS, "called"); 430 LOG_DEBUG(Service_FS, "called");
681 431
682 IPC::ResponseBuilder rb{ctx, 3}; 432 *out_access_log_mode = access_log_mode;
683 rb.Push(ResultSuccess);
684 rb.PushEnum(access_log_mode);
685}
686 433
687void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) { 434 R_SUCCEED();
688 const auto raw = ctx.ReadBufferCopy(); 435}
689 auto log = Common::StringFromFixedZeroTerminatedBuffer(
690 reinterpret_cast<const char*>(raw.data()), raw.size());
691 436
437Result FSP_SRV::OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer) {
692 LOG_DEBUG(Service_FS, "called"); 438 LOG_DEBUG(Service_FS, "called");
693 439
440 auto log = Common::StringFromFixedZeroTerminatedBuffer(
441 reinterpret_cast<const char*>(log_message_buffer.data()), log_message_buffer.size());
694 reporter.SaveFSAccessLog(log); 442 reporter.SaveFSAccessLog(log);
695 443
696 IPC::ResponseBuilder rb{ctx, 2}; 444 R_SUCCEED();
697 rb.Push(ResultSuccess);
698} 445}
699 446
700void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) { 447Result FSP_SRV::GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
701 LOG_DEBUG(Service_FS, "called"); 448 Out<u32> out_access_log_program_index) {
449 LOG_DEBUG(Service_FS, "(STUBBED) called");
450
451 *out_access_log_version = AccessLogVersion::Latest;
452 *out_access_log_program_index = access_log_program_index;
702 453
703 IPC::ResponseBuilder rb{ctx, 4}; 454 R_SUCCEED();
704 rb.Push(ResultSuccess);
705 rb.PushEnum(AccessLogVersion::Latest);
706 rb.Push(access_log_program_index);
707} 455}
708 456
709void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) { 457Result FSP_SRV::FlushAccessLogOnSdCard() {
710 LOG_DEBUG(Service_FS, "(STUBBED) called"); 458 LOG_DEBUG(Service_FS, "(STUBBED) called");
711 459
712 IPC::ResponseBuilder rb{ctx, 2}; 460 R_SUCCEED();
713 rb.Push(ResultSuccess);
714} 461}
715 462
716void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) { 463Result FSP_SRV::GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size) {
717 IPC::RequestParser rp{ctx};
718 const auto index{rp.Pop<s32>()};
719
720 LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index); 464 LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
721 465
722 IPC::ResponseBuilder rb{ctx, 6}; 466 *out_data_size = 0;
723 rb.Push(ResultSuccess); 467 *out_journal_size = 0;
724 rb.Push(s64{0});
725 rb.Push(s64{0});
726}
727
728class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
729public:
730 explicit IMultiCommitManager(Core::System& system_)
731 : ServiceFramework{system_, "IMultiCommitManager"} {
732 static const FunctionInfo functions[] = {
733 {1, &IMultiCommitManager::Add, "Add"},
734 {2, &IMultiCommitManager::Commit, "Commit"},
735 };
736 RegisterHandlers(functions);
737 }
738 468
739private: 469 R_SUCCEED();
740 FileSys::VirtualFile backend; 470}
741
742 void Add(HLERequestContext& ctx) {
743 LOG_WARNING(Service_FS, "(STUBBED) called");
744
745 IPC::ResponseBuilder rb{ctx, 2};
746 rb.Push(ResultSuccess);
747 }
748
749 void Commit(HLERequestContext& ctx) {
750 LOG_WARNING(Service_FS, "(STUBBED) called");
751
752 IPC::ResponseBuilder rb{ctx, 2};
753 rb.Push(ResultSuccess);
754 }
755};
756 471
757void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) { 472Result FSP_SRV::OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface) {
758 LOG_DEBUG(Service_FS, "called"); 473 LOG_DEBUG(Service_FS, "called");
759 474
760 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 475 *out_interface = std::make_shared<IMultiCommitManager>(system);
761 rb.Push(ResultSuccess); 476
762 rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system)); 477 R_SUCCEED();
763} 478}
764 479
765} // namespace Service::FileSystem 480} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h
index 59406e6f9..ee67f6bc1 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h
@@ -4,6 +4,9 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include "core/file_sys/fs_save_data_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/filesystem/fsp/fsp_types.h"
7#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
8 11
9namespace Core { 12namespace Core {
@@ -20,6 +23,11 @@ namespace Service::FileSystem {
20class RomFsController; 23class RomFsController;
21class SaveDataController; 24class SaveDataController;
22 25
26class IFileSystem;
27class ISaveDataInfoReader;
28class IStorage;
29class IMultiCommitManager;
30
23enum class AccessLogVersion : u32 { 31enum class AccessLogVersion : u32 {
24 V7_0_0 = 2, 32 V7_0_0 = 2,
25 33
@@ -38,30 +46,46 @@ public:
38 ~FSP_SRV() override; 46 ~FSP_SRV() override;
39 47
40private: 48private:
41 void SetCurrentProcess(HLERequestContext& ctx); 49 Result SetCurrentProcess(ClientProcessId pid);
42 void OpenFileSystemWithPatch(HLERequestContext& ctx); 50 Result OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
43 void OpenSdCardFileSystem(HLERequestContext& ctx); 51 FileSystemProxyType type, u64 open_program_id);
44 void CreateSaveDataFileSystem(HLERequestContext& ctx); 52 Result OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface);
45 void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); 53 Result CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
46 void OpenSaveDataFileSystem(HLERequestContext& ctx); 54 FileSys::SaveDataAttribute save_struct, u128 uid);
47 void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); 55 Result CreateSaveDataFileSystemBySystemSaveDataId(
48 void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx); 56 FileSys::SaveDataCreationInfo save_create_struct, FileSys::SaveDataAttribute save_struct);
49 void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx); 57 Result OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
50 void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx); 58 FileSys::SaveDataSpaceId space_id,
51 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx); 59 FileSys::SaveDataAttribute attribute);
52 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx); 60 Result OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
53 void OpenDataStorageByCurrentProcess(HLERequestContext& ctx); 61 FileSys::SaveDataSpaceId space_id,
54 void OpenDataStorageByDataId(HLERequestContext& ctx); 62 FileSys::SaveDataAttribute attribute);
55 void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx); 63 Result OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
56 void OpenDataStorageWithProgramIndex(HLERequestContext& ctx); 64 FileSys::SaveDataSpaceId space_id,
57 void DisableAutoSaveDataCreation(HLERequestContext& ctx); 65 FileSys::SaveDataAttribute attribute);
58 void SetGlobalAccessLogMode(HLERequestContext& ctx); 66 Result OpenSaveDataInfoReaderBySaveDataSpaceId(OutInterface<ISaveDataInfoReader> out_interface,
59 void GetGlobalAccessLogMode(HLERequestContext& ctx); 67 FileSys::SaveDataSpaceId space);
60 void OutputAccessLogToSdCard(HLERequestContext& ctx); 68 Result OpenSaveDataInfoReaderOnlyCacheStorage(OutInterface<ISaveDataInfoReader> out_interface);
61 void FlushAccessLogOnSdCard(HLERequestContext& ctx); 69 Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute();
62 void GetProgramIndexForAccessLog(HLERequestContext& ctx); 70 Result ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
63 void OpenMultiCommitManager(HLERequestContext& ctx); 71 FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
64 void GetCacheStorageSize(HLERequestContext& ctx); 72 InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
73 OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
74 Result OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface);
75 Result OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
76 FileSys::StorageId storage_id, u32 unknown, u64 title_id);
77 Result OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
78 FileSys::StorageId storage_id, u64 title_id);
79 Result OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface, u8 program_index);
80 Result DisableAutoSaveDataCreation();
81 Result SetGlobalAccessLogMode(AccessLogMode access_log_mode_);
82 Result GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode);
83 Result OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer);
84 Result FlushAccessLogOnSdCard();
85 Result GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
86 Out<u32> out_access_log_program_index);
87 Result OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface);
88 Result GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size);
65 89
66 FileSystemController& fsc; 90 FileSystemController& fsc;
67 const FileSys::ContentProvider& content_provider; 91 const FileSys::ContentProvider& content_provider;
diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_types.h
index 253f866db..294da6a2d 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_util.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_types.h
@@ -7,6 +7,18 @@
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10enum class FileSystemProxyType : u8 {
11 Code = 0,
12 Rom = 1,
13 Logo = 2,
14 Control = 3,
15 Manual = 4,
16 Meta = 5,
17 Data = 6,
18 Package = 7,
19 RegisteredUpdate = 8,
20};
21
10struct SizeGetter { 22struct SizeGetter {
11 std::function<u64()> get_free_size; 23 std::function<u64()> get_free_size;
12 std::function<u64()> get_total_size; 24 std::function<u64()> get_total_size;
diff --git a/src/core/hle/service/psc/ovln/ovln_types.h b/src/core/hle/service/psc/ovln/ovln_types.h
new file mode 100644
index 000000000..343b05dcc
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/ovln_types.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8
9namespace Service::PSC {
10
11using OverlayNotification = std::array<u64, 0x10>;
12static_assert(sizeof(OverlayNotification) == 0x80, "OverlayNotification has incorrect size");
13
14union MessageFlags {
15 u64 raw;
16 BitField<0, 8, u64> message_type;
17 BitField<8, 8, u64> queue_type;
18};
19static_assert(sizeof(MessageFlags) == 0x8, "MessageFlags has incorrect size");
20
21} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver.cpp b/src/core/hle/service/psc/ovln/receiver.cpp
new file mode 100644
index 000000000..85f62816d
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver.cpp
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/ovln/receiver.h"
5
6namespace Service::PSC {
7
8IReceiver::IReceiver(Core::System& system_) : ServiceFramework{system_, "IReceiver"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "AddSource"},
12 {1, nullptr, "RemoveSource"},
13 {2, nullptr, "GetReceiveEventHandle"},
14 {3, nullptr, "Receive"},
15 {4, nullptr, "ReceiveWithTick"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IReceiver::~IReceiver() = default;
23
24} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver.h b/src/core/hle/service/psc/ovln/receiver.h
new file mode 100644
index 000000000..c47a4ff7e
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IReceiver final : public ServiceFramework<IReceiver> {
11public:
12 explicit IReceiver(Core::System& system_);
13 ~IReceiver() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver_service.cpp b/src/core/hle/service/psc/ovln/receiver_service.cpp
new file mode 100644
index 000000000..bb988e905
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver_service.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/receiver.h"
6#include "core/hle/service/psc/ovln/receiver_service.h"
7
8namespace Service::PSC {
9
10IReceiverService::IReceiverService(Core::System& system_) : ServiceFramework{system_, "ovln:rcv"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IReceiverService::OpenReceiver>, "OpenReceiver"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20IReceiverService::~IReceiverService() = default;
21
22Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
23 LOG_DEBUG(Service_PSC, "called");
24 *out_receiver = std::make_shared<IReceiver>(system);
25 R_SUCCEED();
26}
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver_service.h b/src/core/hle/service/psc/ovln/receiver_service.h
new file mode 100644
index 000000000..b3b31ba4a
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver_service.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class IReceiver;
12
13class IReceiverService final : public ServiceFramework<IReceiverService> {
14public:
15 explicit IReceiverService(Core::System& system_);
16 ~IReceiverService() override;
17
18private:
19 Result OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver);
20};
21
22} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender.cpp b/src/core/hle/service/psc/ovln/sender.cpp
new file mode 100644
index 000000000..3227a56f2
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender.cpp
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/sender.h"
6
7namespace Service::PSC {
8
9ISender::ISender(Core::System& system_) : ServiceFramework{system_, "ISender"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, D<&ISender::Send>, "Send"},
13 {1, nullptr, "GetUnreceivedMessageCount"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20ISender::~ISender() = default;
21
22Result ISender::Send(const OverlayNotification& notification, MessageFlags flags) {
23 std::string data;
24 for (const auto m : notification) {
25 data += fmt::format("{:016X} ", m);
26 }
27
28 LOG_WARNING(Service_PSC, "(STUBBED) called, flags={} notification={}", flags.raw, data);
29 R_SUCCEED();
30}
31
32} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender.h b/src/core/hle/service/psc/ovln/sender.h
new file mode 100644
index 000000000..c1575428e
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/psc/ovln/ovln_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::PSC {
11
12class ISender final : public ServiceFramework<ISender> {
13public:
14 explicit ISender(Core::System& system_);
15 ~ISender() override;
16
17private:
18 Result Send(const OverlayNotification& notification, MessageFlags flags);
19};
20
21} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender_service.cpp b/src/core/hle/service/psc/ovln/sender_service.cpp
new file mode 100644
index 000000000..18d2c83a3
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender_service.cpp
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/sender.h"
6#include "core/hle/service/psc/ovln/sender_service.h"
7
8namespace Service::PSC {
9
10ISenderService::ISenderService(Core::System& system_) : ServiceFramework{system_, "ovln:snd"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&ISenderService::OpenSender>, "OpenSender"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20ISenderService::~ISenderService() = default;
21
22Result ISenderService::OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
23 std::array<u64, 2> data) {
24 LOG_WARNING(Service_PSC, "(STUBBED) called, sender_id={}, data={:016X} {:016X}", sender_id,
25 data[0], data[1]);
26 *out_sender = std::make_shared<ISender>(system);
27 R_SUCCEED();
28}
29
30} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender_service.h b/src/core/hle/service/psc/ovln/sender_service.h
new file mode 100644
index 000000000..10027701f
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender_service.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class ISender;
12
13class ISenderService final : public ServiceFramework<ISenderService> {
14public:
15 explicit ISenderService(Core::System& system_);
16 ~ISenderService() override;
17
18private:
19 Result OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
20 std::array<u64, 2> data);
21};
22
23} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_control.cpp b/src/core/hle/service/psc/pm_control.cpp
new file mode 100644
index 000000000..7dedb7662
--- /dev/null
+++ b/src/core/hle/service/psc/pm_control.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/pm_control.h"
5
6namespace Service::PSC {
7
8IPmControl::IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {1, nullptr, "DispatchRequest"},
13 {2, nullptr, "GetResult"},
14 {3, nullptr, "GetState"},
15 {4, nullptr, "Cancel"},
16 {5, nullptr, "PrintModuleInformation"},
17 {6, nullptr, "GetModuleInformation"},
18 {10, nullptr, "AcquireStateLock"},
19 {11, nullptr, "HasStateLock"},
20 };
21 // clang-format on
22
23 RegisterHandlers(functions);
24}
25
26IPmControl::~IPmControl() = default;
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_control.h b/src/core/hle/service/psc/pm_control.h
new file mode 100644
index 000000000..e0ae2f39c
--- /dev/null
+++ b/src/core/hle/service/psc/pm_control.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IPmControl final : public ServiceFramework<IPmControl> {
11public:
12 explicit IPmControl(Core::System& system_);
13 ~IPmControl() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_module.cpp b/src/core/hle/service/psc/pm_module.cpp
new file mode 100644
index 000000000..74dc7ed4e
--- /dev/null
+++ b/src/core/hle/service/psc/pm_module.cpp
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/pm_module.h"
5
6namespace Service::PSC {
7
8IPmModule::IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {1, nullptr, "GetRequest"},
13 {2, nullptr, "Acknowledge"},
14 {3, nullptr, "Finalize"},
15 {4, nullptr, "AcknowledgeEx"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IPmModule::~IPmModule() = default;
23
24} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_module.h b/src/core/hle/service/psc/pm_module.h
new file mode 100644
index 000000000..b3a2d2584
--- /dev/null
+++ b/src/core/hle/service/psc/pm_module.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IPmModule final : public ServiceFramework<IPmModule> {
11public:
12 explicit IPmModule(Core::System& system_);
13 ~IPmModule() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_service.cpp b/src/core/hle/service/psc/pm_service.cpp
new file mode 100644
index 000000000..c4e0ad228
--- /dev/null
+++ b/src/core/hle/service/psc/pm_service.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/pm_module.h"
6#include "core/hle/service/psc/pm_service.h"
7
8namespace Service::PSC {
9
10IPmService::IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IPmService::GetPmModule>, "GetPmModule"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20IPmService::~IPmService() = default;
21
22Result IPmService::GetPmModule(Out<SharedPointer<IPmModule>> out_module) {
23 LOG_DEBUG(Service_PSC, "called");
24 *out_module = std::make_shared<IPmModule>(system);
25 R_SUCCEED();
26}
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_service.h b/src/core/hle/service/psc/pm_service.h
new file mode 100644
index 000000000..08e14c6f8
--- /dev/null
+++ b/src/core/hle/service/psc/pm_service.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class IPmModule;
12
13class IPmService final : public ServiceFramework<IPmService> {
14public:
15 explicit IPmService(Core::System& system_);
16 ~IPmService() override;
17
18private:
19 Result GetPmModule(Out<SharedPointer<IPmModule>> out_module);
20};
21
22} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index 44310756b..e1762d694 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -1,11 +1,10 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <memory> 4#include "core/hle/service/psc/ovln/receiver_service.h"
5 5#include "core/hle/service/psc/ovln/sender_service.h"
6#include "common/logging/log.h" 6#include "core/hle/service/psc/pm_control.h"
7#include "core/core.h" 7#include "core/hle/service/psc/pm_service.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/psc/psc.h" 8#include "core/hle/service/psc/psc.h"
10#include "core/hle/service/psc/time/manager.h" 9#include "core/hle/service/psc/time/manager.h"
11#include "core/hle/service/psc/time/power_state_service.h" 10#include "core/hle/service/psc/time/power_state_service.h"
@@ -15,71 +14,13 @@
15 14
16namespace Service::PSC { 15namespace Service::PSC {
17 16
18class IPmControl final : public ServiceFramework<IPmControl> {
19public:
20 explicit IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, nullptr, "Initialize"},
24 {1, nullptr, "DispatchRequest"},
25 {2, nullptr, "GetResult"},
26 {3, nullptr, "GetState"},
27 {4, nullptr, "Cancel"},
28 {5, nullptr, "PrintModuleInformation"},
29 {6, nullptr, "GetModuleInformation"},
30 {10, nullptr, "AcquireStateLock"},
31 {11, nullptr, "HasStateLock"},
32 };
33 // clang-format on
34
35 RegisterHandlers(functions);
36 }
37};
38
39class IPmModule final : public ServiceFramework<IPmModule> {
40public:
41 explicit IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
42 // clang-format off
43 static const FunctionInfo functions[] = {
44 {0, nullptr, "Initialize"},
45 {1, nullptr, "GetRequest"},
46 {2, nullptr, "Acknowledge"},
47 {3, nullptr, "Finalize"},
48 {4, nullptr, "AcknowledgeEx"},
49 };
50 // clang-format on
51
52 RegisterHandlers(functions);
53 }
54};
55
56class IPmService final : public ServiceFramework<IPmService> {
57public:
58 explicit IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
59 // clang-format off
60 static const FunctionInfo functions[] = {
61 {0, &IPmService::GetPmModule, "GetPmModule"},
62 };
63 // clang-format on
64
65 RegisterHandlers(functions);
66 }
67
68private:
69 void GetPmModule(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_PSC, "called");
71
72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
73 rb.Push(ResultSuccess);
74 rb.PushIpcInterface<IPmModule>(system);
75 }
76};
77
78void LoopProcess(Core::System& system) { 17void LoopProcess(Core::System& system) {
79 auto server_manager = std::make_unique<ServerManager>(system); 18 auto server_manager = std::make_unique<ServerManager>(system);
80 19
81 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); 20 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
82 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); 21 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
22 server_manager->RegisterNamedService("ovln:rcv", std::make_shared<IReceiverService>(system));
23 server_manager->RegisterNamedService("ovln:snd", std::make_shared<ISenderService>(system));
83 24
84 auto time = std::make_shared<Time::TimeManager>(system); 25 auto time = std::make_shared<Time::TimeManager>(system);
85 26
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h
index 459137f42..c83d07ca8 100644
--- a/src/core/hle/service/psc/psc.h
+++ b/src/core/hle/service/psc/psc.h
@@ -7,10 +7,6 @@ namespace Core {
7class System; 7class System;
8} 8}
9 9
10namespace Service::SM {
11class ServiceManager;
12}
13
14namespace Service::PSC { 10namespace Service::PSC {
15 11
16void LoopProcess(Core::System& system); 12void LoopProcess(Core::System& system);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 0031fa5fb..3f9698d6b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -261,7 +261,9 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
261 case Stage::Geometry: 261 case Stage::Geometry:
262 execution_model = spv::ExecutionModel::Geometry; 262 execution_model = spv::ExecutionModel::Geometry;
263 ctx.AddCapability(spv::Capability::Geometry); 263 ctx.AddCapability(spv::Capability::Geometry);
264 ctx.AddCapability(spv::Capability::GeometryStreams); 264 if (ctx.profile.support_geometry_streams) {
265 ctx.AddCapability(spv::Capability::GeometryStreams);
266 }
265 switch (ctx.runtime_info.input_topology) { 267 switch (ctx.runtime_info.input_topology) {
266 case InputTopology::Points: 268 case InputTopology::Points:
267 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints); 269 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
index 9f7b6bb4b..f60da758e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
@@ -129,7 +129,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { 129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) {
130 ConvertDepthMode(ctx); 130 ConvertDepthMode(ctx);
131 } 131 }
132 if (stream.IsImmediate()) { 132 if (!ctx.profile.support_geometry_streams) {
133 throw NotImplementedException("Geometry streams");
134 } else if (stream.IsImmediate()) {
133 ctx.OpEmitStreamVertex(ctx.Def(stream)); 135 ctx.OpEmitStreamVertex(ctx.Def(stream));
134 } else { 136 } else {
135 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 137 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
@@ -140,7 +142,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
140} 142}
141 143
142void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { 144void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
143 if (stream.IsImmediate()) { 145 if (!ctx.profile.support_geometry_streams) {
146 throw NotImplementedException("Geometry streams");
147 } else if (stream.IsImmediate()) {
144 ctx.OpEndStreamPrimitive(ctx.Def(stream)); 148 ctx.OpEndStreamPrimitive(ctx.Def(stream));
145 } else { 149 } else {
146 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 150 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 7578d41cc..90e46bb1b 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -44,6 +44,7 @@ struct Profile {
44 bool support_gl_derivative_control{}; 44 bool support_gl_derivative_control{};
45 bool support_scaled_attributes{}; 45 bool support_scaled_attributes{};
46 bool support_multi_viewport{}; 46 bool support_multi_viewport{};
47 bool support_geometry_streams{};
47 48
48 bool warp_size_potentially_larger_than_guest{}; 49 bool warp_size_potentially_larger_than_guest{};
49 50
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 20f7a9702..d34b585d6 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -352,6 +352,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
352 .support_native_ndc = device.IsExtDepthClipControlSupported(), 352 .support_native_ndc = device.IsExtDepthClipControlSupported(),
353 .support_scaled_attributes = !device.MustEmulateScaledFormats(), 353 .support_scaled_attributes = !device.MustEmulateScaledFormats(),
354 .support_multi_viewport = device.SupportsMultiViewport(), 354 .support_multi_viewport = device.SupportsMultiViewport(),
355 .support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
355 356
356 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), 357 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
357 358
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index d7216d349..b94924a58 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -1297,10 +1297,6 @@ u64 Device::GetDeviceMemoryUsage() const {
1297} 1297}
1298 1298
1299void Device::CollectPhysicalMemoryInfo() { 1299void Device::CollectPhysicalMemoryInfo() {
1300 // Account for resolution scaling in memory limits
1301 const size_t normal_memory = 6_GiB;
1302 const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
1303
1304 // Calculate limits using memory budget 1300 // Calculate limits using memory budget
1305 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{}; 1301 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
1306 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; 1302 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
@@ -1331,7 +1327,15 @@ void Device::CollectPhysicalMemoryInfo() {
1331 if (!is_integrated) { 1327 if (!is_integrated) {
1332 const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB); 1328 const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
1333 device_access_memory -= reserve_memory; 1329 device_access_memory -= reserve_memory;
1334 device_access_memory = std::min<u64>(device_access_memory, normal_memory + scaler_memory); 1330
1331 if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) {
1332 // Account for resolution scaling in memory limits
1333 const size_t normal_memory = 6_GiB;
1334 const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
1335 device_access_memory =
1336 std::min<u64>(device_access_memory, normal_memory + scaler_memory);
1337 }
1338
1335 return; 1339 return;
1336 } 1340 }
1337 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage); 1341 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index a2ec26697..e3abe8ddf 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -499,6 +499,11 @@ public:
499 return extensions.transform_feedback; 499 return extensions.transform_feedback;
500 } 500 }
501 501
502 /// Returns true if the device supports VK_EXT_transform_feedback properly.
503 bool AreTransformFeedbackGeometryStreamsSupported() const {
504 return features.transform_feedback.geometryStreams;
505 }
506
502 /// Returns true if the device supports VK_EXT_custom_border_color. 507 /// Returns true if the device supports VK_EXT_custom_border_color.
503 bool IsExtCustomBorderColorSupported() const { 508 bool IsExtCustomBorderColorSupported() const {
504 return extensions.custom_border_color; 509 return extensions.custom_border_color;
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp
index d138b53c8..0549e8ae4 100644
--- a/src/yuzu/configuration/shared_translation.cpp
+++ b/src/yuzu/configuration/shared_translation.cpp
@@ -164,6 +164,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
164 "the emulator to decompress to an intermediate format any card supports, RGBA8.\n" 164 "the emulator to decompress to an intermediate format any card supports, RGBA8.\n"
165 "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but " 165 "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but "
166 "negatively affecting image quality.")); 166 "negatively affecting image quality."));
167 INSERT(Settings, vram_usage_mode, tr("VRAM Usage Mode:"),
168 tr("Selects whether the emulator should prefer to conserve memory or make maximum usage "
169 "of available video memory for performance. Has no effect on integrated graphics. "
170 "Aggressive mode may severely impact the performance of other applications such as "
171 "recording software."));
167 INSERT( 172 INSERT(
168 Settings, vsync_mode, tr("VSync Mode:"), 173 Settings, vsync_mode, tr("VSync Mode:"),
169 tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " 174 tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
@@ -315,6 +320,11 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
315 PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")), 320 PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
316 PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")), 321 PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
317 }}); 322 }});
323 translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
324 {
325 PAIR(VramUsageMode, Conservative, tr("Conservative")),
326 PAIR(VramUsageMode, Aggressive, tr("Aggressive")),
327 }});
318 translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(), 328 translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
319 { 329 {
320#ifdef HAS_OPENGL 330#ifdef HAS_OPENGL
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b2ae3db52..c0c0a19b8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2325,15 +2325,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
2325 ASSERT(user_id); 2325 ASSERT(user_id);
2326 2326
2327 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 2327 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
2328 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, 2328 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
2329 FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0); 2329 program_id, user_id->AsU128(), 0);
2330 2330
2331 path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); 2331 path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
2332 } else { 2332 } else {
2333 // Device save data 2333 // Device save data
2334 const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath( 2334 const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath(
2335 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, 2335 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
2336 FileSys::SaveDataType::SaveData, program_id, {}, 0); 2336 program_id, {}, 0);
2337 2337
2338 path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path); 2338 path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path);
2339 } 2339 }
@@ -2674,7 +2674,7 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) {
2674 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); 2674 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
2675 2675
2676 const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( 2676 const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath(
2677 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage, 2677 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache,
2678 0 /* program_id */, {}, 0); 2678 0 /* program_id */, {}, 0);
2679 2679
2680 const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); 2680 const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path);
@@ -3010,9 +3010,6 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi
3010 3010
3011void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, 3011void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
3012 GameListShortcutTarget target) { 3012 GameListShortcutTarget target) {
3013 std::string game_title;
3014 QString qt_game_title;
3015 std::filesystem::path out_icon_path;
3016 // Get path to yuzu executable 3013 // Get path to yuzu executable
3017 const QStringList args = QApplication::arguments(); 3014 const QStringList args = QApplication::arguments();
3018 std::filesystem::path yuzu_command = args[0].toStdString(); 3015 std::filesystem::path yuzu_command = args[0].toStdString();
@@ -3029,48 +3026,51 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
3029 shortcut_path = 3026 shortcut_path =
3030 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); 3027 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
3031 } 3028 }
3032 // Icon path and title 3029
3033 if (std::filesystem::exists(shortcut_path)) { 3030 if (!std::filesystem::exists(shortcut_path)) {
3034 // Get title from game file 3031 GMainWindow::CreateShortcutMessagesGUI(
3035 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), 3032 this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
3036 system->GetContentProvider()}; 3033 QString::fromStdString(shortcut_path.generic_string()));
3037 const auto control = pm.GetControlMetadata(); 3034 LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string());
3038 const auto loader = 3035 return;
3039 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); 3036 }
3040 game_title = fmt::format("{:016X}", program_id); 3037
3041 if (control.first != nullptr) { 3038 // Get title from game file
3042 game_title = control.first->GetApplicationName(); 3039 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
3043 } else { 3040 system->GetContentProvider()};
3044 loader->ReadTitle(game_title); 3041 const auto control = pm.GetControlMetadata();
3045 } 3042 const auto loader =
3046 // Delete illegal characters from title 3043 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
3047 const std::string illegal_chars = "<>:\"/\\|?*."; 3044 std::string game_title = fmt::format("{:016X}", program_id);
3048 for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { 3045 if (control.first != nullptr) {
3049 if (illegal_chars.find(*it) != std::string::npos) { 3046 game_title = control.first->GetApplicationName();
3050 game_title.erase(it.base() - 1); 3047 } else {
3051 } 3048 loader->ReadTitle(game_title);
3052 } 3049 }
3053 qt_game_title = QString::fromStdString(game_title); 3050 // Delete illegal characters from title
3054 // Get icon from game file 3051 const std::string illegal_chars = "<>:\"/\\|?*.";
3055 std::vector<u8> icon_image_file{}; 3052 for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) {
3056 if (control.second != nullptr) { 3053 if (illegal_chars.find(*it) != std::string::npos) {
3057 icon_image_file = control.second->ReadAllBytes(); 3054 game_title.erase(it.base() - 1);
3058 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
3059 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
3060 } 3055 }
3061 QImage icon_data = 3056 }
3062 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size())); 3057 const QString qt_game_title = QString::fromStdString(game_title);
3063 if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { 3058 // Get icon from game file
3064 if (!SaveIconToFile(out_icon_path, icon_data)) { 3059 std::vector<u8> icon_image_file{};
3065 LOG_ERROR(Frontend, "Could not write icon to file"); 3060 if (control.second != nullptr) {
3066 } 3061 icon_image_file = control.second->ReadAllBytes();
3062 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
3063 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
3064 }
3065 QImage icon_data =
3066 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
3067 std::filesystem::path out_icon_path;
3068 if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
3069 if (!SaveIconToFile(out_icon_path, icon_data)) {
3070 LOG_ERROR(Frontend, "Could not write icon to file");
3067 } 3071 }
3068 } else {
3069 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
3070 qt_game_title);
3071 LOG_ERROR(Frontend, "Invalid shortcut target");
3072 return;
3073 } 3072 }
3073
3074#if defined(__linux__) 3074#if defined(__linux__)
3075 // Special case for AppImages 3075 // Special case for AppImages
3076 // Warn once if we are making a shortcut to a volatile AppImage 3076 // Warn once if we are making a shortcut to a volatile AppImage