Compare commits

...

120 Commits

Author SHA1 Message Date
dffc08bd15 Android 271 2024-02-27 00:57:12 +00:00
597a1da426 Merge yuzu-emu#13171 2024-02-27 00:57:11 +00:00
4052ffb97b Merge yuzu-emu#13166 2024-02-27 00:57:11 +00:00
29fa1417fa Merge yuzu-emu#13135 2024-02-27 00:57:11 +00:00
54737ce166 Merge yuzu-emu#13122 2024-02-27 00:57:11 +00:00
cb64ec8b78 Merge yuzu-emu#13096 2024-02-27 00:57:11 +00:00
c4b57450a1 Merge yuzu-emu#13018 2024-02-27 00:57:11 +00:00
26c9d345a2 Merge yuzu-emu#12749 2024-02-27 00:57:11 +00:00
7375bf85b8 Merge yuzu-emu#12461 2024-02-27 00:57:11 +00:00
1bec420695 Merge pull request #13172 from liamwhite/gl-streams
renderer_opengl: declare geometry stream support in profile
2024-02-26 11:51:25 -06:00
79edad2533 Merge pull request #13159 from liamwhite/web-error
core: enable error applet, add stubs for web applet
2024-02-26 12:44:55 -05:00
ce62fa6f7b Merge pull request #13149 from liamwhite/per-channel-program
video_core: make gpu context aware of rendering program
2024-02-26 12:44:46 -05:00
a0e254e7c4 renderer_opengl: declare geometry stream support in profile 2024-02-26 11:18:30 -05:00
25c3bbba0e settings: remove global override for smash on amdvlk 2024-02-26 11:16:18 -05:00
d66ca8b731 video_core: make gpu context aware of rendering program 2024-02-26 11:16:14 -05:00
f9bfdb1555 Merge pull request #13164 from merryhime/reset-submodules
tools: Add reset submodules script
2024-02-25 14:01:11 -05:00
15831b19a3 Merge pull request #13163 from german77/ring
core: hid: hid_core doesn't have access to LIBUSB
2024-02-25 14:01:05 -05:00
8416d1c028 Merge pull request #13154 from german77/vibration-filter
core: hid: Reintroduce vibration filter
2024-02-25 14:00:59 -05:00
4d5d37ae61 tools: Add reset submodules script 2024-02-25 17:17:01 +00:00
e62cea20d1 core: hid: hid_core doesn't have access to LIBUSB 2024-02-25 10:06:43 -06:00
9e27dbb53b Merge pull request #13160 from liamwhite/time
glue: load initial year setting as s32
2024-02-25 08:47:16 -06:00
dc50b95a47 settings: enable error applet 2024-02-24 22:56:08 -05:00
4050242cf3 ldn: return no connection from GetStateForMonitor 2024-02-24 22:56:08 -05:00
fd718f350c ssl: add cert store 2024-02-24 22:56:05 -05:00
0d6fd12231 glue: load initial year setting as s32 2024-02-24 22:49:38 -05:00
f297e98a9e acc: add account manager for acc:u1 2024-02-24 22:25:34 -05:00
637c54e205 fs: add stubs for online web applet 2024-02-24 22:25:34 -05:00
f045fa576b erpt: stub report creation 2024-02-24 22:25:34 -05:00
692ba0fa7d set: add GetPlatformRegion 2024-02-24 22:25:34 -05:00
a93d249ac1 Merge pull request #13155 from german77/GetSettingsItemValue
service: set: Fix GetSettingsItemValue
2024-02-24 16:24:01 -05:00
9fccccedee service: set: Fix GetSettingsItemValue 2024-02-24 14:44:21 -06:00
ca7f949ee8 core: hid: Reintroduce vibration filter 2024-02-24 12:19:51 -06:00
05f94dc5fc Merge pull request #13153 from german77/defaultset
service: set: Enable nfc and others by default and bump version
2024-02-24 12:48:31 -05:00
dcf7698924 Merge pull request #13081 from FearlessTobi/aoc-ipc
aoc: Migrate to use cmif serialization
2024-02-24 12:48:26 -05:00
7b68d7d467 Merge pull request #13150 from liamwhite/region
set: fix region code for system settings
2024-02-24 11:40:31 -06:00
4741e50047 service: set: Enable nfc and others by default and bump version 2024-02-24 11:19:51 -06:00
7836c0867d set: fix region code for system settings 2024-02-24 00:48:44 -05:00
d1e0039bc8 Merge pull request #13142 from t895/vibration-queue
android: Play vibrations asynchronously
2024-02-24 00:38:13 -05:00
7a51eaa727 Merge pull request #13146 from wheremyfoodat/patch-1
common/ring_buffer: Include <limits> header
2024-02-23 20:32:40 -05:00
6c40d75e47 Merge pull request #13140 from german77/yet-more-qlaunch
service: Stub multiple function for qlaunch
2024-02-23 20:32:32 -05:00
0a0c257206 service: audio: Add missing logging properties of SetHeadphoneOutputLevelMode 2024-02-23 18:58:51 -06:00
7019023cbc service: btdrv: Add EnableRadio for Qlaunch 2024-02-23 18:58:51 -06:00
c48c182fe0 service: friend: Add GetFriendCount, GetNewlyFriendCount, GetReceivedFriendRequestCount, GetPlayHistoryStatistics, GetReceivedFriendInvitationCountCache for QLaunch 2024-02-23 18:58:51 -06:00
98be02898b service: hid: Add IsAnyCustomButtonConfigEnabled for QLaunch 2024-02-23 18:58:51 -06:00
e1bdeb2942 service: lbl: Add SaveCurrentSetting, LoadCurrentSetting and IsAutoBrightnessControlSupported for QLaunch 2024-02-23 18:58:50 -06:00
015d666a4d service: nfc: Implement SetNfcEnabled 2024-02-23 18:58:50 -06:00
624c90a439 service: npns: Add ListenTo and GetReceiveEvent for QLaunch 2024-02-23 18:58:39 -06:00
0fb26acccc service: set: Add default eula setting 2024-02-23 18:58:19 -06:00
ed315fb8a5 common/ring_buffer: Include <limits> header 2024-02-24 02:34:09 +02:00
0369c65870 android: Play vibrations asynchronously 2024-02-23 16:41:59 -05:00
975d6f1ec4 Merge pull request #13141 from liamwhite/swap
fs: fix argument order
2024-02-23 15:23:06 -05:00
7c9e2255be Merge pull request #13137 from liamwhite/mac-ci
ci: fix mac build
2024-02-23 15:21:18 -05:00
9f6818a6e5 Merge pull request #13136 from liamwhite/fs-launch
fs: add ISaveDataTransferProhibiter, stub FindSaveDataWithFilter
2024-02-23 15:21:12 -05:00
f1c16b487a fs: fix argument order 2024-02-23 15:10:35 -05:00
6512f39061 ci: fix mac build 2024-02-23 13:25:48 -05:00
22b91afa69 fs: add ISaveDataTransferProhibiter, stub FindSaveDataWithFilter 2024-02-23 12:17:24 -05:00
77107ba124 Merge pull request #13133 from liamwhite/libstdcxx-issue
vi: workaround conductor includes
2024-02-23 11:34:34 -05:00
fa4dec9fe9 Merge pull request #13115 from liamwhite/olsc-pctl
olsc, pctl: move to new ipc
2024-02-23 11:34:29 -05:00
215e887be0 Merge pull request #13100 from liamwhite/audio-ipc
audio: move to new ipc
2024-02-23 11:34:21 -05:00
0da6704fc2 Merge pull request #13073 from FearlessTobi/fsp-srv-ipc
fsp: Migrate remaining interfaces to cmif serialization
2024-02-23 11:34:06 -05:00
812754edec vi: workaround conductor includes 2024-02-23 10:34:49 -05:00
964e19ab56 oboe_sink: handle temporary stream creation failure 2024-02-23 10:30:52 -05:00
9dc624f5dc Merge pull request #13121 from german77/clean-shortcut
yuzu: Fix shortcut error message
2024-02-22 23:04:28 -05:00
dad9ea3e07 Merge pull request #13117 from liamwhite/ovln
psc: stub overlay notification channel
2024-02-22 20:26:03 -05:00
2c00599a53 audio: fix released buffer bounds check 2024-02-22 20:20:31 -05:00
2786d34dd7 aoc: Rename AOC_U to IAddOnContentManager 2024-02-23 01:19:18 +01:00
864b046500 yuzu: Fix shortcut error message 2024-02-22 17:52:30 -06:00
d12d9dad40 Merge pull request #12982 from FearlessTobi/fs-rewrite-part0
fs: Add FileSystemAccessor and use cmif serialization
2024-02-22 12:34:47 -05:00
2b3f1d3fc5 Merge pull request #13000 from liamwhite/skip-null-memory
device_memory_manager: skip unregistered interfaces on invalidate
2024-02-22 11:34:23 -06:00
984396a21a Merge pull request #13001 from liamwhite/scaled-availability
vulkan_device: don't use fixed cap for memory limits
2024-02-22 11:31:17 -06:00
4f95ee5209 Merge pull request #13075 from liamwhite/mali-having-a-bad-time
shader_recompiler: throw on missing geometry streams in geometry shaders
2024-02-22 11:30:26 -06:00
c04567fad4 audio: add NotifyHeadphoneVolumeWarningDisplayedEvent 2024-02-21 23:54:10 -05:00
89c2fd3d28 pctl: rewrite IParentalControlService 2024-02-21 23:42:33 -05:00
5ab49c833d pctl: rewrite IParentalControlServiceFactory 2024-02-21 23:00:01 -05:00
0e74204aad pctl: move IParentalControlServiceFactory 2024-02-21 23:00:01 -05:00
a37bd0b9a7 pctl: move IParentalControlService 2024-02-21 23:00:01 -05:00
01d89acd13 pctl: move types and results 2024-02-21 22:58:20 -05:00
e85466c1ae psc: stub overlay notification channel 2024-02-21 22:54:05 -05:00
352297d361 psc: rewrite IPmService 2024-02-21 22:26:32 -05:00
6c2d6cff19 psc: move IPmControl, IPmModule, IPmService 2024-02-21 22:26:12 -05:00
e540757279 olsc: rewrite IOlscServiceForSystemService 2024-02-21 20:02:00 -05:00
a8bca24292 olsc: add IRemoteStorageController 2024-02-21 19:47:54 -05:00
5f3c03d6a8 olsc: add IDaemonController 2024-02-21 19:05:19 -05:00
6b956a6951 olsc: rewrite ITransferTaskListController 2024-02-21 18:36:17 -05:00
8689370830 olsc: rewrite INativeHandleHolder 2024-02-21 18:19:48 -05:00
8ffa27b311 olsc: rewrite IOlscServiceForApplication 2024-02-21 18:19:12 -05:00
6334616b44 olsc: move INativeHandleHolder, IOlscServiceForApplication, IOlscServiceForSystemService, ITransferTaskListController 2024-02-21 16:13:01 -05:00
8bbc209950 Merge pull request #13105 from t895/connection-fix
android: Misc controller fixes
2024-02-21 10:43:46 -05:00
9e1a67b950 fs: add missing mutex header for member (#13106) 2024-02-21 16:43:05 +01:00
de5422b1fd android: Connect controllers with supported styles
If you tried to connect a controller that was previously configured with an unsupported style for your game, when you try to connect that controller, it will immediately disconnect. This ensures that the controller that is being connected will be changed to the first supported style index before being connected.
2024-02-21 08:37:55 -05:00
45f450fca5 android: Add additional check for hasMapping
Controls can have no mapping if they are either "[empty]" or and empty string. This was causing an issue if you reset mapping on all controllers and then tried to play a game. The check to determine whether auto mapping was required would fail and leave you will no mapped controllers. This feels a bit like user error but it smooths things out if you forget so I see it as necessary.
2024-02-21 08:17:30 -05:00
9a3fd76b25 android: Enable all controller styles on emulation shutdown 2024-02-21 08:13:54 -05:00
2e4a6b7f92 audio: format 2024-02-20 22:51:39 -05:00
5f90bd88da audio: rewrite IHardwareOpusDecoder 2024-02-20 22:15:38 -05:00
c575a85233 audio: rewrite IAudioDevice 2024-02-20 22:15:38 -05:00
ea4703cb31 audio: rewrite IHardwareOpusDecoderManager 2024-02-20 22:15:38 -05:00
0471e54e5a audio: rewrite IAudioRenderer 2024-02-20 22:15:38 -05:00
6012c9fe3a audio: rewrite IAudioRendererManager 2024-02-20 22:15:37 -05:00
f65539504f audio: split IHardwarweOpusDecoder, move IHardwareOpusDecoderManager 2024-02-20 22:15:37 -05:00
62083fcafd audio: split IAudioDevice, IAudioRenderer, move IAudioRendererManager 2024-02-20 22:15:37 -05:00
2e5a9cf119 audio: move IFinalOutputRecorderManager{,ForApplet} 2024-02-20 22:15:37 -05:00
a45b8bc9bc audio: rewrite IAudioOutManager 2024-02-20 22:15:37 -05:00
a05bd3c47e audio: rewrite IAudioOut 2024-02-20 22:15:37 -05:00
2a2c92f181 audio: rewrite IAudioInManager 2024-02-20 22:15:37 -05:00
f54277364c audio: rewrite IAudioIn 2024-02-20 22:15:37 -05:00
ef50277124 Address review comments pt. 2 2024-02-19 19:22:51 +01:00
ba70dc4c13 Address review comments 2024-02-19 19:20:46 +01:00
934e420e36 fs: Refactor to use cmif serialization 2024-02-19 19:20:46 +01:00
d5e4617ab5 fs: Add FileSystemAccessor classes 2024-02-19 19:20:40 +01:00
b5a17b501b Address review comments 2024-02-19 19:11:07 +01:00
2b18957365 fs: Add and use fs_save_data_types.h 2024-02-19 19:06:31 +01:00
4c71bf3d90 fsp: Migrate remaining interfaces to cmif serialization 2024-02-19 19:06:31 +01:00
fdf4a5bc90 fsp-srv: Migrate to use cmif serialization 2024-02-19 19:06:31 +01:00
b7d9eba72b fsp: Move IMultiCommitManager to a seperate file 2024-02-19 19:06:31 +01:00
380475af32 fsp: Move ISaveDataInfoReader to a seperate file 2024-02-19 19:06:31 +01:00
a2a0be4246 aoc: Migrate to use cmif serialization 2024-02-19 17:20:02 +01:00
aa6532cf34 core/aoc: Move IPurchaseEventManager to separate file 2024-02-19 16:36:24 +01:00
f46dc31683 shader_recompiler: throw on missing geometry streams in geometry shaders 2024-02-19 00:34:00 -05:00
56810541f0 vulkan_device: don't use fixed cap for memory limits 2024-02-18 18:59:13 -05:00
461eaca7e8 device_memory_manager: skip unregistered interfaces on invalidate 2024-02-12 20:02:59 -05:00
321 changed files with 22219 additions and 8589 deletions

View File

@ -81,8 +81,7 @@ jobs:
fetch-depth: 0
- name: Install dependencies
run: |
# workaround for https://github.com/actions/setup-python/issues/577
brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd || brew link --overwrite python@3.12
brew install autoconf automake boost ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd
- name: Build
run: |
mkdir build

View File

@ -1,3 +1,19 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`a84e8e26f`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13018](https://github.com/yuzu-emu/yuzu//pull/13018) | [`01cbc638a`](https://github.com/yuzu-emu/yuzu//pull/13018/files) | am: rewrite part 2 | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13096](https://github.com/yuzu-emu/yuzu//pull/13096) | [`0a8759057`](https://github.com/yuzu-emu/yuzu//pull/13096/files) | texture_cache: use two-pass collection for costly load resources | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13122](https://github.com/yuzu-emu/yuzu//pull/13122) | [`5dc08c7fe`](https://github.com/yuzu-emu/yuzu//pull/13122/files) | vk_rasterizer: flip scissor y on lower left origin mode | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13135](https://github.com/yuzu-emu/yuzu//pull/13135) | [`fc6a87bba`](https://github.com/yuzu-emu/yuzu//pull/13135/files) | service: hid: Migrate HidServer to new IPC | [german77](https://github.com/german77/) | Yes |
| [13166](https://github.com/yuzu-emu/yuzu//pull/13166) | [`4eecad914`](https://github.com/yuzu-emu/yuzu//pull/13166/files) | buffer_cache: avoid overflow in usage tracker | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13171](https://github.com/yuzu-emu/yuzu//pull/13171) | [`fd9ed54f2`](https://github.com/yuzu-emu/yuzu//pull/13171/files) | texture_cache: do not track invalid addresses | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.
-----
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -314,3 +314,10 @@ endif()
if (NOT TARGET SimpleIni::SimpleIni)
add_subdirectory(simpleini)
endif()
# sse2neon
if (ARCHITECTURE_arm64 AND NOT TARGET sse2neon)
add_library(sse2neon INTERFACE)
target_include_directories(sse2neon INTERFACE sse2neon)
endif()

9285
externals/sse2neon/sse2neon.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -121,6 +121,7 @@ else()
-Wno-attributes
-Wno-invalid-offsetof
-Wno-unused-parameter
-Wno-missing-field-initializers
)
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
@ -164,6 +165,7 @@ else()
if (MINGW)
add_definitions(-DMINGW_HAS_SECURE_API)
add_compile_options("-msse4.1")
if (MINGW_STATIC_BUILD)
add_definitions(-DQT_STATICPLUGIN)

View File

@ -64,17 +64,17 @@ data class PlayerInput(
fun hasMapping(): Boolean {
var hasMapping = false
buttons.forEach {
if (it != "[empty]") {
if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}
analogs.forEach {
if (it != "[empty]") {
if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}
motions.forEach {
if (it != "[empty]") {
if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}

View File

@ -292,6 +292,9 @@ void EmulationSession::ShutdownEmulation() {
// Unload user input.
m_system.HIDCore().UnloadInputDevices();
// Enable all controllers
m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
// Shutdown the main emulated process
if (m_load_result == Core::SystemResultStatus::Success) {
m_system.DetachDebugger();
@ -665,7 +668,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1,
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1,
user_id->AsU128(), 0);
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
@ -833,8 +836,8 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
FileSys::OpenMode::Read);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
program_id, user_id->AsU128(), 0);
{}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
user_id->AsU128(), 0);
return Common::Android::ToJString(env, user_save_data_path);
}

View File

@ -102,8 +102,50 @@ void ApplyControllerConfig(size_t player_index,
}
}
std::vector<s32> GetSupportedStyles(int player_index) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
const auto npad_style_set = hid_core.GetSupportedStyleTag();
std::vector<s32> supported_indexes;
if (npad_style_set.fullkey == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey));
}
if (npad_style_set.joycon_dual == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual));
}
if (npad_style_set.joycon_left == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft));
}
if (npad_style_set.joycon_right == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight));
}
if (player_index == 0 && npad_style_set.handheld == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld));
}
if (npad_style_set.gamecube == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube));
}
return supported_indexes;
}
void ConnectController(size_t player_index, bool connected) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) {
auto supported_styles = GetSupportedStyles(player_index);
auto controller_style = controller->GetNpadStyleIndex(true);
auto style = std::find(supported_styles.begin(), supported_styles.end(),
static_cast<int>(controller_style));
if (style == supported_styles.end() && !supported_styles.empty()) {
controller->SetNpadStyleIndex(
static_cast<Core::HID::NpadStyleIndex>(supported_styles[0]));
}
});
if (player_index == 0) {
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
@ -522,36 +564,10 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv
jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
JNIEnv* env, jobject j_obj, jint j_player_index) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
const auto npad_style_set = hid_core.GetSupportedStyleTag();
std::vector<s32> supported_indexes;
if (npad_style_set.fullkey == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey));
}
if (npad_style_set.joycon_dual == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual));
}
if (npad_style_set.joycon_left == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft));
}
if (npad_style_set.joycon_right == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight));
}
if (j_player_index == 0 && npad_style_set.handheld == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld));
}
if (npad_style_set.gamecube == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube));
}
jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size());
env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(),
supported_indexes.data());
auto supported_styles = GetSupportedStyles(j_player_index);
jintArray j_supported_indexes = env->NewIntArray(supported_styles.size());
env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(),
supported_styles.data());
return j_supported_indexes;
}

View File

@ -73,16 +73,15 @@ void Manager::BufferReleaseAndRegister() {
}
}
u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names,
[[maybe_unused]] const u32 max_count,
u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
[[maybe_unused]] const bool filter) {
std::scoped_lock l{mutex};
LinkToManager();
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
if (input_devices.size() > 1) {
names.emplace_back("Uac");
if (!input_devices.empty() && !names.empty()) {
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
return 1;
}
return 0;

View File

@ -60,13 +60,11 @@ public:
* Get a list of audio in device names.
*
* @param names - Output container to write names to.
* @param max_count - Maximum number of device names to write. Unused
* @param filter - Should the list be filtered? Unused.
*
* @return Number of names written.
*/
u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count,
bool filter);
u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
/// Core system
Core::System& system;

View File

@ -146,7 +146,11 @@ public:
break;
}
tags[released++] = tag;
if (released < tags.size()) {
tags[released] = tag;
}
released++;
if (released >= tags.size()) {
break;

View File

@ -28,8 +28,8 @@ OpusDecoder::~OpusDecoder() {
}
}
Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size) {
Result OpusDecoder::Initialize(const OpusParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size;
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
@ -59,7 +59,7 @@ Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory
R_SUCCEED();
}
Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params,
Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size;

View File

@ -22,10 +22,10 @@ public:
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
~OpusDecoder();
Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size);
Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size);
Result Initialize(const OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
std::span<const u8> input_data, std::span<u8> output_data, bool reset);
Result SetContext([[maybe_unused]] std::span<const u8> context);

View File

@ -38,7 +38,7 @@ OpusDecoderManager::OpusDecoderManager(Core::System& system_)
}
}
Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) {
OpusParametersEx ex{
.sample_rate = params.sample_rate,
.channel_count = params.channel_count,
@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_si
R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) {
R_RETURN(GetWorkBufferSizeExEx(params, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) {
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64&
R_SUCCEED();
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params,
u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params,
u32& out_size) {
OpusMultiStreamParametersEx ex{
.sample_rate = params.sample_rate,
.channel_count = params.channel_count,
@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParame
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params,
u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
const OpusMultiStreamParametersEx& params, u32& out_size) {
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params,
u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
const OpusMultiStreamParametersEx& params, u32& out_size) {
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,

View File

@ -22,17 +22,19 @@ public:
return hardware_opus;
}
Result GetWorkBufferSize(OpusParameters& params, u64& out_size);
Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size);
Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size);
Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size);
Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size);
Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size);
Result GetWorkBufferSize(const OpusParameters& params, u32& out_size);
Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size);
Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size);
Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size);
Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params,
u32& out_size);
Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params,
u32& out_size);
private:
Core::System& system;
HardwareOpus hardware_opus;
std::array<u64, MaxChannels> required_workbuffer_sizes{};
std::array<u32, MaxChannels> required_workbuffer_sizes{};
};
} // namespace AudioCore::OpusDecoder

View File

@ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_)
opus_decoder.SetSharedMemory(shared_memory);
}
u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
if (!opus_decoder.IsRunning()) {
return 0;
}
@ -55,10 +55,10 @@ u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
return 0;
}
return shared_memory.dsp_return_data[0];
return static_cast<u32>(shared_memory.dsp_return_data[0]);
}
u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = total_stream_count;
shared_memory.host_send_data[1] = stereo_stream_count;
@ -70,7 +70,7 @@ u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
return 0;
}
return shared_memory.dsp_return_data[0];
return static_cast<u32>(shared_memory.dsp_return_data[0]);
}
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
@ -94,8 +94,9 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count,
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 total_stream_count,
u32 stereo_stream_count, void* mappings,
void* buffer, u64 buffer_size) {
u32 stereo_stream_count,
const void* mappings, void* buffer,
u64 buffer_size) {
std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = (u64)buffer;
shared_memory.host_send_data[1] = buffer_size;

View File

@ -16,14 +16,14 @@ class HardwareOpus {
public:
HardwareOpus(Core::System& system);
u64 GetWorkBufferSize(u32 channel);
u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
u32 GetWorkBufferSize(u32 channel);
u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
u64 buffer_size);
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 totaL_stream_count, u32 stereo_stream_count,
void* mappings, void* buffer, u64 buffer_size);
const void* mappings, void* buffer, u64 buffer_size);
Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,

View File

@ -20,7 +20,7 @@ struct OpusParametersEx {
/* 0x00 */ u32 sample_rate;
/* 0x04 */ u32 channel_count;
/* 0x08 */ bool use_large_frame_size;
/* 0x09 */ INSERT_PADDING_BYTES(7);
/* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7);
}; // size = 0x10
static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
@ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx {
/* 0x08 */ u32 total_stream_count;
/* 0x0C */ u32 stereo_stream_count;
/* 0x10 */ bool use_large_frame_size;
/* 0x11 */ INSERT_PADDING_BYTES(7);
/* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7);
/* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
}; // size = 0x118
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,

View File

@ -36,8 +36,7 @@ AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id
: output_sink{system.AudioCore().GetOutputSink()},
applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
const size_t max_count) const {
u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const {
std::span<const AudioDeviceName> names{};
if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
@ -46,19 +45,18 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
names = device_names;
}
const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))};
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))};
for (u32 i = 0; i < out_count; i++) {
out_buffer.push_back(names[i]);
out_buffer[i] = names[i];
}
return out_count;
}
u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer,
const size_t max_count) const {
const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const {
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))};
for (u32 i = 0; i < out_count; i++) {
out_buffer.push_back(output_device_names[i]);
out_buffer[i] = output_device_names[i];
}
return out_count;
}

View File

@ -36,20 +36,18 @@ public:
* Get a list of the available output devices.
*
* @param out_buffer - Output buffer to write the available device names.
* @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written.
*/
u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const;
/**
* Get a list of the available output devices.
* Different to above somehow...
*
* @param out_buffer - Output buffer to write the available device names.
* @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written.
*/
u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const;
/**
* Set the volume of all streams in the backend sink.

View File

@ -17,9 +17,8 @@ Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* ren
Result Renderer::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory,
const u64 transfer_memory_size, const u32 process_handle,
Kernel::KProcess& process, const u64 applet_resource_user_id,
const s32 session_id) {
const u64 transfer_memory_size, Kernel::KProcess* process_handle,
const u64 applet_resource_user_id, const s32 session_id) {
if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio,
@ -30,7 +29,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
}
initialized = true;
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
applet_resource_user_id, session_id);
return ResultSuccess;

View File

@ -38,14 +38,14 @@ public:
* @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. Unused.
* @param process_handle - Process handle, also used for memory.
* @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer.
* @return Result code.
*/
Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
Kernel::KProcess* process_handle, u64 applet_resource_user_id,
s32 session_id);
/**

View File

@ -18,7 +18,7 @@
namespace AudioCore::Renderer {
InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
const u32 process_handle_, BehaviorInfo& behaviour_)
Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_)
: input{input_.data() + sizeof(UpdateDataHeader)},
input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>(

View File

@ -8,6 +8,10 @@
#include "common/common_types.h"
#include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer {
class BehaviorInfo;
class VoiceContext;
@ -39,8 +43,8 @@ class InfoUpdater {
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
public:
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle,
BehaviorInfo& behaviour);
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output,
Kernel::KProcess* process_handle, BehaviorInfo& behaviour);
/**
* Update the voice channel resources.
@ -197,7 +201,7 @@ private:
/// Expected output size, see CheckConsumedSize
u64 expected_output_size;
/// Unused
u32 process_handle;
Kernel::KProcess* process_handle;
/// Behaviour
BehaviorInfo& behaviour;
};

View File

@ -8,11 +8,11 @@
namespace AudioCore::Renderer {
PoolMapper::PoolMapper(u32 process_handle_, bool force_map_)
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_)
: process_handle{process_handle_}, force_map{force_map_} {}
PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_,
bool force_map_)
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_,
u32 pool_count_, bool force_map_)
: process_handle{process_handle_}, pool_infos{pool_infos_.data()},
pool_count{pool_count_}, force_map{force_map_} {}
@ -106,15 +106,17 @@ bool PoolMapper::IsForceMapEnabled() const {
return force_map;
}
u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
switch (pool->GetLocation()) {
case MemoryPoolInfo::Location::CPU:
return process_handle;
case MemoryPoolInfo::Location::DSP:
return Kernel::Svc::CurrentProcess;
// return Kernel::Svc::CurrentProcess;
return nullptr;
}
LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
return Kernel::Svc::CurrentProcess;
// return Kernel::Svc::CurrentProcess;
return nullptr;
}
bool 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
}
bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
[[maybe_unused]] u32 handle{0};
[[maybe_unused]] Kernel::KProcess* handle{};
switch (pool.GetLocation()) {
case MemoryPoolInfo::Location::CPU:
handle = process_handle;
break;
case MemoryPoolInfo::Location::DSP:
handle = Kernel::Svc::CurrentProcess;
// handle = Kernel::Svc::CurrentProcess;
break;
}
// nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);

View File

@ -10,6 +10,10 @@
#include "common/common_types.h"
#include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer {
class AddressInfo;
@ -18,9 +22,9 @@ class AddressInfo;
*/
class PoolMapper {
public:
explicit PoolMapper(u32 process_handle, bool force_map);
explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count,
bool force_map);
explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map);
explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos,
u32 pool_count, bool force_map);
/**
* Clear the usage state for all given pools.
@ -98,7 +102,7 @@ public:
* @return CurrentProcessHandle if location == DSP,
* the PoolMapper's process_handle if location == CPU
*/
u32 GetProcessHandle(const MemoryPoolInfo* pool) const;
Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const;
/**
* Map the given region with the given handle. This is a no-op.
@ -167,7 +171,7 @@ public:
private:
/// Process handle for this mapper, used when location == CPU
u32 process_handle;
Kernel::KProcess* process_handle{};
/// List of memory pools assigned to this mapper
MemoryPoolInfo* pool_infos{};
/// The number of pools

View File

@ -102,8 +102,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_)
Result System::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle_, Kernel::KProcess& process_,
u64 applet_resource_user_id_, s32 session_id_) {
Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
s32 session_id_) {
if (!CheckValidRevision(params.revision)) {
return Service::Audio::ResultInvalidRevision;
}
@ -119,7 +119,6 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
behavior.SetUserLibRevision(params.revision);
process_handle = process_handle_;
process = &process_;
applet_resource_user_id = applet_resource_user_id_;
session_id = session_id_;
@ -132,7 +131,8 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
render_device = params.rendering_device;
execution_mode = params.execution_mode;
process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size);
process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
transfer_memory_size);
// Note: We're not actually using the transfer memory because it's a pain to code for.
// Allocate the memory normally instead and hope the game doesn't try to read anything back
@ -616,7 +616,7 @@ void System::SendCommandToDsp() {
static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
(static_cast<f32>(render_time_limit_percent) / 100.0f))};
audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
applet_resource_user_id, process,
applet_resource_user_id, process_handle,
reset_command_buffers);
reset_command_buffers = false;
command_buffer_size = command_size;

View File

@ -74,14 +74,14 @@ public:
* @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. Unused.
* @param process_handle - Process handle, also used for memory.
* @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer.
* @return Result code.
*/
Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
Kernel::KProcess* process_handle, u64 applet_resource_user_id,
s32 session_id);
/**
@ -278,9 +278,7 @@ private:
/// Does what locks do
std::mutex lock{};
/// Process this audio render is operating within, used for memory reads/writes.
Kernel::KProcess* process{};
/// Handle for the process for this system, unused
u32 process_handle{};
Kernel::KProcess* process_handle{};
/// Applet resource id for this system, unused
u64 applet_resource_user_id{};
/// Controls performance input and output

View File

@ -67,9 +67,13 @@ public:
oboe::AudioStreamBuilder builder;
const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
ASSERT(result == oboe::Result::OK);
if (result == oboe::Result::OK) {
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
}
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
direction == oboe::Direction::Output ? "output" : "input");
return 2;
}
protected:

View File

@ -8,6 +8,7 @@
#include <atomic>
#include <cstddef>
#include <cstring>
#include <limits>
#include <new>
#include <span>
#include <type_traits>

View File

@ -140,7 +140,7 @@ struct Values {
Category::LibraryApplet};
Setting<AppletMode> data_erase_applet_mode{linkage, AppletMode::HLE, "data_erase_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> error_applet_mode{linkage, AppletMode::HLE, "error_applet_mode",
Setting<AppletMode> error_applet_mode{linkage, AppletMode::LLE, "error_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> net_connect_applet_mode{linkage, AppletMode::HLE, "net_connect_applet_mode",
Category::LibraryApplet};
@ -384,6 +384,12 @@ struct Values {
AstcRecompression::Bc3,
"astc_recompression",
Category::RendererAdvanced};
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
VramUsageMode::Conservative,
VramUsageMode::Conservative,
VramUsageMode::Aggressive,
"vram_usage_mode",
Category::RendererAdvanced};
SwitchableSetting<bool> async_presentation{linkage,
#ifdef ANDROID
true,
@ -429,8 +435,6 @@ struct Values {
linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug};
Setting<bool> enable_renderdoc_hotkey{linkage, false, "renderdoc_hotkey",
Category::RendererDebug};
// TODO: remove this once AMDVLK supports VK_EXT_depth_bias_control
bool renderer_amdvlk_depth_bias_workaround{};
Setting<bool> disable_buffer_reorder{linkage, false, "disable_buffer_reorder",
Category::RendererDebug};

View File

@ -122,6 +122,8 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL, Vulkan, Null);
ENUM(ShaderBackend, Glsl, Glasm, SpirV);

View File

@ -38,6 +38,10 @@ std::string StringFromBuffer(std::span<const u8> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
std::string StringFromBuffer(std::span<const char> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
// Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string& str) {
const std::size_t s = str.find_first_not_of(" \t\r\n");

View File

@ -19,6 +19,7 @@ namespace Common {
[[nodiscard]] std::string ToUpper(std::string str);
[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
[[nodiscard]] std::string StringFromBuffer(std::span<const char> data);
[[nodiscard]] std::string StripSpaces(const std::string& s);
[[nodiscard]] std::string StripQuotes(const std::string& s);

View File

@ -58,9 +58,14 @@ add_library(core STATIC
file_sys/fs_operate_range.h
file_sys/fs_path.h
file_sys/fs_path_utility.h
file_sys/fs_save_data_types.h
file_sys/fs_string_util.h
file_sys/fsa/fs_i_directory.h
file_sys/fsa/fs_i_file.h
file_sys/fsa/fs_i_filesystem.h
file_sys/fsmitm_romfsbuild.cpp
file_sys/fsmitm_romfsbuild.h
file_sys/fssrv/fssrv_sf_path.h
file_sys/fssystem/fs_i_storage.h
file_sys/fssystem/fs_types.h
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@ -396,14 +401,16 @@ add_library(core STATIC
hle/service/am/am_types.h
hle/service/am/applet.cpp
hle/service/am/applet.h
hle/service/am/applet_manager.cpp
hle/service/am/applet_data_broker.cpp
hle/service/am/applet_data_broker.h
hle/service/am/applet_manager.cpp
hle/service/am/applet_manager.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/button_poller.cpp
hle/service/am/button_poller.h
hle/service/am/display_layer_manager.cpp
hle/service/am/display_layer_manager.h
hle/service/am/event_observer.cpp
hle/service/am/event_observer.h
hle/service/am/frontend/applet_cabinet.cpp
hle/service/am/frontend/applet_cabinet.h
hle/service/am/frontend/applet_controller.cpp
@ -429,8 +436,12 @@ add_library(core STATIC
hle/service/am/hid_registration.h
hle/service/am/library_applet_storage.cpp
hle/service/am/library_applet_storage.h
hle/service/am/process.cpp
hle/service/am/process.h
hle/service/am/lifecycle_manager.cpp
hle/service/am/lifecycle_manager.h
hle/service/am/process_creation.cpp
hle/service/am/process_creation.h
hle/service/am/process_holder.cpp
hle/service/am/process_holder.h
hle/service/am/service/all_system_applet_proxies_service.cpp
hle/service/am/service/all_system_applet_proxies_service.h
hle/service/am/service/applet_common_functions.cpp
@ -481,31 +492,45 @@ add_library(core STATIC
hle/service/am/service/system_applet_proxy.h
hle/service/am/service/window_controller.cpp
hle/service/am/service/window_controller.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/am/window_system.cpp
hle/service/am/window_system.h
hle/service/aoc/addon_content_manager.cpp
hle/service/aoc/addon_content_manager.h
hle/service/aoc/purchase_event_manager.cpp
hle/service/aoc/purchase_event_manager.h
hle/service/apm/apm.cpp
hle/service/apm/apm.h
hle/service/apm/apm_controller.cpp
hle/service/apm/apm_controller.h
hle/service/apm/apm_interface.cpp
hle/service/apm/apm_interface.h
hle/service/audio/audin_u.cpp
hle/service/audio/audin_u.h
hle/service/audio/audio.cpp
hle/service/audio/audio.h
hle/service/audio/audio_controller.cpp
hle/service/audio/audio_controller.h
hle/service/audio/audout_u.cpp
hle/service/audio/audout_u.h
hle/service/audio/audrec_a.cpp
hle/service/audio/audrec_a.h
hle/service/audio/audrec_u.cpp
hle/service/audio/audrec_u.h
hle/service/audio/audren_u.cpp
hle/service/audio/audren_u.h
hle/service/audio/audio_device.cpp
hle/service/audio/audio_device.h
hle/service/audio/audio_in_manager.cpp
hle/service/audio/audio_in_manager.h
hle/service/audio/audio_in.cpp
hle/service/audio/audio_in.h
hle/service/audio/audio_out_manager.cpp
hle/service/audio/audio_out_manager.h
hle/service/audio/audio_out.cpp
hle/service/audio/audio_out.h
hle/service/audio/audio_renderer_manager.cpp
hle/service/audio/audio_renderer_manager.h
hle/service/audio/audio_renderer.cpp
hle/service/audio/audio_renderer.h
hle/service/audio/audio.cpp
hle/service/audio/audio.h
hle/service/audio/errors.h
hle/service/audio/hwopus.cpp
hle/service/audio/hwopus.h
hle/service/audio/final_output_recorder_manager_for_applet.cpp
hle/service/audio/final_output_recorder_manager_for_applet.h
hle/service/audio/final_output_recorder_manager.cpp
hle/service/audio/final_output_recorder_manager.h
hle/service/audio/hardware_opus_decoder_manager.cpp
hle/service/audio/hardware_opus_decoder_manager.h
hle/service/audio/hardware_opus_decoder.cpp
hle/service/audio/hardware_opus_decoder.h
hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h
hle/service/bcat/bcat.cpp
@ -595,6 +620,10 @@ add_library(core STATIC
hle/service/filesystem/fsp/fs_i_file.h
hle/service/filesystem/fsp/fs_i_filesystem.cpp
hle/service/filesystem/fsp/fs_i_filesystem.h
hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
hle/service/filesystem/fsp/fs_i_storage.cpp
hle/service/filesystem/fsp/fs_i_storage.h
hle/service/filesystem/fsp/fsp_ldr.cpp
@ -603,7 +632,9 @@ add_library(core STATIC
hle/service/filesystem/fsp/fsp_pr.h
hle/service/filesystem/fsp/fsp_srv.cpp
hle/service/filesystem/fsp/fsp_srv.h
hle/service/filesystem/fsp/fsp_util.h
hle/service/filesystem/fsp/fsp_types.h
hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp
hle/service/filesystem/fsp/save_data_transfer_prohibiter.h
hle/service/filesystem/romfs_controller.cpp
hle/service/filesystem/romfs_controller.h
hle/service/filesystem/save_data_controller.cpp
@ -645,6 +676,10 @@ add_library(core STATIC
hle/service/glue/time/worker.h
hle/service/grc/grc.cpp
hle/service/grc/grc.h
hle/service/hid/active_vibration_device_list.cpp
hle/service/hid/active_vibration_device_list.h
hle/service/hid/applet_resource.cpp
hle/service/hid/applet_resource.h
hle/service/hid/hid.cpp
hle/service/hid/hid.h
hle/service/hid/hid_debug_server.cpp
@ -860,8 +895,20 @@ add_library(core STATIC
hle/service/nvnflinger/ui/graphic_buffer.cpp
hle/service/nvnflinger/ui/graphic_buffer.h
hle/service/nvnflinger/window.h
hle/service/olsc/daemon_controller.cpp
hle/service/olsc/daemon_controller.h
hle/service/olsc/native_handle_holder.cpp
hle/service/olsc/native_handle_holder.h
hle/service/olsc/olsc_service_for_application.cpp
hle/service/olsc/olsc_service_for_application.h
hle/service/olsc/olsc_service_for_system_service.cpp
hle/service/olsc/olsc_service_for_system_service.h
hle/service/olsc/olsc.cpp
hle/service/olsc/olsc.h
hle/service/olsc/remote_storage_controller.cpp
hle/service/olsc/remote_storage_controller.h
hle/service/olsc/transfer_task_list_controller.cpp
hle/service/olsc/transfer_task_list_controller.h
hle/service/omm/omm.cpp
hle/service/omm/omm.h
hle/service/omm/operation_mode_manager.cpp
@ -879,18 +926,39 @@ add_library(core STATIC
hle/service/os/multi_wait_utils.h
hle/service/os/mutex.cpp
hle/service/os/mutex.h
hle/service/os/process.cpp
hle/service/os/process.h
hle/service/pcie/pcie.cpp
hle/service/pcie/pcie.h
hle/service/pctl/parental_control_service_factory.cpp
hle/service/pctl/parental_control_service_factory.h
hle/service/pctl/parental_control_service.cpp
hle/service/pctl/parental_control_service.h
hle/service/pctl/pctl.cpp
hle/service/pctl/pctl.h
hle/service/pctl/pctl_module.cpp
hle/service/pctl/pctl_module.h
hle/service/pctl/pctl_results.h
hle/service/pctl/pctl_types.h
hle/service/pcv/pcv.cpp
hle/service/pcv/pcv.h
hle/service/pm/pm.cpp
hle/service/pm/pm.h
hle/service/prepo/prepo.cpp
hle/service/prepo/prepo.h
hle/service/psc/ovln/ovln_types.h
hle/service/psc/ovln/receiver_service.cpp
hle/service/psc/ovln/receiver_service.h
hle/service/psc/ovln/receiver.cpp
hle/service/psc/ovln/receiver.h
hle/service/psc/ovln/sender_service.cpp
hle/service/psc/ovln/sender_service.h
hle/service/psc/ovln/sender.cpp
hle/service/psc/ovln/sender.h
hle/service/psc/pm_control.cpp
hle/service/psc/pm_control.h
hle/service/psc/pm_module.cpp
hle/service/psc/pm_module.h
hle/service/psc/pm_service.cpp
hle/service/psc/pm_service.h
hle/service/psc/psc.cpp
hle/service/psc/psc.h
hle/service/psc/time/alarms.cpp
@ -993,9 +1061,12 @@ add_library(core STATIC
hle/service/spl/spl_module.h
hle/service/spl/spl_results.h
hle/service/spl/spl_types.h
hle/service/ssl/cert_store.cpp
hle/service/ssl/cert_store.h
hle/service/ssl/ssl.cpp
hle/service/ssl/ssl.h
hle/service/ssl/ssl_backend.h
hle/service/ssl/ssl_types.h
hle/service/usb/usb.cpp
hle/service/usb/usb.h
hle/service/vi/application_display_service.cpp

View File

@ -3,7 +3,6 @@
#include <array>
#include <atomic>
#include <exception>
#include <memory>
#include <utility>
@ -20,7 +19,6 @@
#include "core/cpu_manager.h"
#include "core/debugger/debugger.h"
#include "core/device_memory.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
@ -38,6 +36,7 @@
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h"
@ -72,30 +71,6 @@ MICROPROFILE_DEFINE(ARM_CPU3, "ARM", "CPU 3", MP_RGB(255, 64, 64));
namespace Core {
namespace {
FileSys::StorageId GetStorageIdForFrontendSlot(
std::optional<FileSys::ContentProviderUnionSlot> slot) {
if (!slot.has_value()) {
return FileSys::StorageId::None;
}
switch (*slot) {
case FileSys::ContentProviderUnionSlot::UserNAND:
return FileSys::StorageId::NandUser;
case FileSys::ContentProviderUnionSlot::SysNAND:
return FileSys::StorageId::NandSystem;
case FileSys::ContentProviderUnionSlot::SDMC:
return FileSys::StorageId::SdCard;
case FileSys::ContentProviderUnionSlot::FrontendManual:
return FileSys::StorageId::Host;
default:
return FileSys::StorageId::None;
}
}
} // Anonymous namespace
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
const std::string& path) {
// To account for split 00+01+etc files.
@ -297,9 +272,6 @@ struct System::Impl {
}
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
/// Reset all glue registrations
arp_manager.ResetAll();
telemetry_session = std::make_unique<Core::TelemetrySession>();
host1x_core = std::make_unique<Tegra::Host1x::Host1x>(system);
@ -335,33 +307,17 @@ struct System::Impl {
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath,
Service::AM::FrontendAppletParameters& params) {
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
params.program_id, params.program_index);
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return SystemResultStatus::ErrorGetLoader;
}
if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find title id for ROM!");
}
std::string name = "Unknown program";
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to read title for ROM!");
}
LOG_INFO(Core, "Loading {} ({})", name, params.program_id);
InitializeKernel(system);
// Create the application process.
auto main_process = Kernel::KProcess::Create(system.Kernel());
Kernel::KProcess::Register(system.Kernel(), main_process);
kernel.AppendNewProcess(main_process);
kernel.MakeApplicationProcess(main_process);
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
const auto file = GetGameFileFromPath(virtual_filesystem, filepath);
// Create the application process
Loader::ResultStatus load_result{};
std::vector<u8> control;
auto process =
Service::AM::CreateApplicationProcess(control, app_loader, load_result, system, file,
params.program_id, params.program_index);
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
ShutdownMainProcess();
@ -370,6 +326,25 @@ struct System::Impl {
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
}
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return SystemResultStatus::ErrorGetLoader;
}
if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find program id for ROM!");
}
std::string name = "Unknown program";
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to read title for ROM!");
}
LOG_INFO(Core, "Loading {} ({:016X}) ...", name, params.program_id);
// Make the process created be the application
kernel.MakeApplicationProcess(process->GetHandle());
// Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
@ -379,7 +354,6 @@ struct System::Impl {
return init_result;
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Initialize cheat engine
@ -387,14 +361,9 @@ struct System::Impl {
cheat_engine->Initialize();
}
// Register with applet manager.
applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(),
params);
// All threads are started, begin main process execution, now that we're in the clear.
main_process->Run(load_parameters->main_thread_priority,
load_parameters->main_thread_stack_size);
main_process->Close();
// Register with applet manager
// All threads are started, begin main process execution, now that we're in the clear
applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
if (Settings::values.gamecard_inserted) {
if (Settings::values.gamecard_current_game) {
@ -425,11 +394,6 @@ struct System::Impl {
room_member->SendGameInfo(game_info);
}
// Workarounds:
// Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK
Settings::values.renderer_amdvlk_depth_bias_workaround =
params.program_id == 0x1006A800016E000ULL;
status = SystemResultStatus::Success;
return status;
}
@ -466,7 +430,6 @@ struct System::Impl {
kernel.SuspendEmulation(true);
kernel.CloseServices();
kernel.ShutdownCores();
applet_manager.Reset();
services.reset();
service_manager.reset();
fs_controller.Reset();
@ -489,8 +452,8 @@ struct System::Impl {
room_member->SendGameInfo(game_info);
}
// Workarounds
Settings::values.renderer_amdvlk_depth_bias_workaround = false;
// Reset all glue registrations
arp_manager.ResetAll();
LOG_DEBUG(Core, "Shutdown OK");
}
@ -509,31 +472,6 @@ struct System::Impl {
return app_loader->ReadTitle(out);
}
void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::KProcess& process) {
std::vector<u8> nacp_data;
FileSys::NACP nacp;
if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) {
nacp_data = nacp.GetRawBytes();
} else {
nacp_data.resize(sizeof(FileSys::RawNACP));
}
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process.GetProgramId();
FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(content_provider->GetSlotForEntry(
launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(content_provider->GetSlotForEntry(
FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
arp_manager.Register(launch.title_id, launch, std::move(nacp_data));
}
void SetStatus(SystemResultStatus new_status, const char* details = nullptr) {
status = new_status;
if (details) {

View File

@ -43,6 +43,8 @@ public:
DeviceMemoryManager(const DeviceMemory& device_memory);
~DeviceMemoryManager();
static constexpr bool HAS_FLUSH_INVALIDATION = true;
void BindInterface(DeviceInterface* device_inter);
DAddr Allocate(size_t size);

View File

@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
auto* memory_device_inter = registered_processes[asid.id];
const auto release_pending = [&] {
if (uncache_bytes > 0) {
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false);
if (memory_device_inter != nullptr) {
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false);
}
uncache_bytes = 0;
}
if (cache_bytes > 0) {
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
cache_bytes, true);
if (memory_device_inter != nullptr) {
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
cache_bytes, true);
}
cache_bytes = 0;
}
};

View File

@ -23,6 +23,8 @@ enum class OpenDirectoryMode : u64 {
File = (1 << 1),
All = (Directory | File),
NotRequireFileSize = (1ULL << 31),
};
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
@ -36,4 +38,29 @@ enum class CreateOption : u8 {
BigFile = (1 << 0),
};
struct FileSystemAttribute {
u8 dir_entry_name_length_max_defined;
u8 file_entry_name_length_max_defined;
u8 dir_path_name_length_max_defined;
u8 file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x5);
u8 utf16_dir_entry_name_length_max_defined;
u8 utf16_file_entry_name_length_max_defined;
u8 utf16_dir_path_name_length_max_defined;
u8 utf16_file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x18);
s32 dir_entry_name_length_max;
s32 file_entry_name_length_max;
s32 dir_path_name_length_max;
s32 file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x5);
s32 utf16_dir_entry_name_length_max;
s32 utf16_file_entry_name_length_max;
s32 utf16_dir_path_name_length_max;
s32 utf16_file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x18);
INSERT_PADDING_WORDS_NOINIT(0x1);
};
static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
} // namespace FileSys

View File

@ -10,7 +10,7 @@ namespace FileSys {
constexpr size_t RequiredAlignment = alignof(u64);
void* AllocateUnsafe(size_t size) {
inline void* AllocateUnsafe(size_t size) {
// Allocate
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {
return ptr;
}
void DeallocateUnsafe(void* ptr, size_t size) {
inline void DeallocateUnsafe(void* ptr, size_t size) {
// Deallocate the pointer
::operator delete(ptr, std::align_val_t{RequiredAlignment});
}
void* Allocate(size_t size) {
inline void* Allocate(size_t size) {
return AllocateUnsafe(size);
}
void Deallocate(void* ptr, size_t size) {
inline void Deallocate(void* ptr, size_t size) {
// If the pointer is non-null, deallocate it
if (ptr != nullptr) {
DeallocateUnsafe(ptr, size);

View File

@ -381,7 +381,7 @@ public:
// Check that it's possible for us to remove a child
auto* p = m_write_buffer.Get();
s32 len = std::strlen(p);
s32 len = static_cast<s32>(std::strlen(p));
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
// Handle a trailing separator

View File

@ -426,9 +426,10 @@ public:
R_SUCCEED();
}
static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size,
bool is_windows_path, bool is_drive_relative_path,
bool allow_all_characters = false) {
static constexpr Result Normalize(char* dst, size_t* out_len, const char* path,
size_t max_out_size, bool is_windows_path,
bool is_drive_relative_path,
bool allow_all_characters = false) {
// Use StringTraits names for remainder of scope
using namespace StringTraits;

View File

@ -0,0 +1,188 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <fmt/format.h>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace FileSys {
using SaveDataId = u64;
using SystemSaveDataId = u64;
using SystemBcatSaveDataId = SystemSaveDataId;
using ProgramId = u64;
enum class SaveDataSpaceId : u8 {
System = 0,
User = 1,
SdSystem = 2,
Temporary = 3,
SdUser = 4,
ProperSystem = 100,
SafeMode = 101,
};
enum class SaveDataType : u8 {
System = 0,
Account = 1,
Bcat = 2,
Device = 3,
Temporary = 4,
Cache = 5,
SystemBcat = 6,
};
enum class SaveDataRank : u8 {
Primary = 0,
Secondary = 1,
};
struct SaveDataSize {
u64 normal;
u64 journal;
};
static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size.");
using UserId = u128;
static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable.");
static_assert(sizeof(UserId) == 0x10, "UserId has invalid size.");
constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
constexpr inline UserId InvalidUserId = {};
enum class SaveDataFlags : u32 {
None = (0 << 0),
KeepAfterResettingSystemSaveData = (1 << 0),
KeepAfterRefurbishment = (1 << 1),
KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
NeedsSecureDelete = (1 << 3),
};
enum class SaveDataMetaType : u8 {
None = 0,
Thumbnail = 1,
ExtensionContext = 2,
};
struct SaveDataMetaInfo {
u32 size;
SaveDataMetaType type;
INSERT_PADDING_BYTES(0xB);
};
static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>,
"Data type must be trivially copyable.");
static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size.");
struct SaveDataCreationInfo {
s64 size;
s64 journal_size;
s64 block_size;
u64 owner_id;
u32 flags;
SaveDataSpaceId space_id;
bool pseudo;
INSERT_PADDING_BYTES(0x1A);
};
static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>,
"Data type must be trivially copyable.");
static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size.");
struct SaveDataAttribute {
ProgramId program_id;
UserId user_id;
SystemSaveDataId system_save_data_id;
SaveDataType type;
SaveDataRank rank;
u16 index;
INSERT_PADDING_BYTES(0x1C);
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id, u16 index,
SaveDataRank rank) {
return {
.program_id = program_id,
.user_id = user_id,
.system_save_data_id = system_save_data_id,
.type = type,
.rank = rank,
.index = index,
};
}
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id, u16 index) {
return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
}
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id) {
return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
}
std::string DebugInfo() const {
return fmt::format(
"[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
"rank={}, index={}]",
program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type),
static_cast<u8>(rank), index);
}
};
static_assert(sizeof(SaveDataAttribute) == 0x40);
static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
}
constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank,
lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id,
rhs.type, rhs.rank, rhs.index);
}
constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return !(lhs == rhs);
}
struct SaveDataExtraData {
SaveDataAttribute attr;
u64 owner_id;
s64 timestamp;
u32 flags;
INSERT_PADDING_BYTES(4);
s64 available_size;
s64 journal_size;
s64 commit_id;
INSERT_PADDING_BYTES(0x190);
};
static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size.");
static_assert(std::is_trivially_copyable_v<SaveDataExtraData>,
"Data type must be trivially copyable.");
struct SaveDataFilter {
bool use_program_id;
bool use_save_data_type;
bool use_user_id;
bool use_save_data_id;
bool use_index;
SaveDataRank rank;
SaveDataAttribute attribute;
};
static_assert(sizeof(SaveDataFilter) == 0x48, "SaveDataFilter has invalid size.");
static_assert(std::is_trivially_copyable_v<SaveDataFilter>,
"Data type must be trivially copyable.");
struct HashSalt {
static constexpr size_t Size = 32;
std::array<u8, Size> value;
};
static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
static_assert(sizeof(HashSalt) == HashSalt::Size);
} // namespace FileSys

View File

@ -19,6 +19,11 @@ constexpr int Strlen(const T* str) {
return length;
}
template <typename T>
constexpr int Strnlen(const T* str, std::size_t count) {
return Strnlen(str, static_cast<int>(count));
}
template <typename T>
constexpr int Strnlen(const T* str, int count) {
ASSERT(str != nullptr);
@ -32,6 +37,11 @@ constexpr int Strnlen(const T* str, int count) {
return length;
}
template <typename T>
constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
return Strncmp(lhs, rhs, static_cast<int>(count));
}
template <typename T>
constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
ASSERT(lhs != nullptr);
@ -51,6 +61,11 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
return l - r;
}
template <typename T>
static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
return Strlcpy<T>(dst, src, static_cast<int>(count));
}
template <typename T>
static constexpr int Strlcpy(T* dst, const T* src, int count) {
ASSERT(dst != nullptr);

View File

@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_directory.h"
#include "core/file_sys/fs_file.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"
namespace FileSys::Fsa {
class IDirectory {
public:
explicit IDirectory(VirtualDir backend_, OpenDirectoryMode mode)
: backend(std::move(backend_)) {
// TODO(DarkLordZach): Verify that this is the correct behavior.
// Build entry index now to save time later.
if (True(mode & OpenDirectoryMode::Directory)) {
BuildEntryIndex(backend->GetSubdirectories(), DirectoryEntryType::Directory);
}
if (True(mode & OpenDirectoryMode::File)) {
BuildEntryIndex(backend->GetFiles(), DirectoryEntryType::File);
}
}
virtual ~IDirectory() {}
Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
R_UNLESS(out_count != nullptr, ResultNullptrArgument);
if (max_entries == 0) {
*out_count = 0;
R_SUCCEED();
}
R_UNLESS(out_entries != nullptr, ResultNullptrArgument);
R_UNLESS(max_entries > 0, ResultInvalidArgument);
R_RETURN(this->DoRead(out_count, out_entries, max_entries));
}
Result GetEntryCount(s64* out) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetEntryCount(out));
}
private:
Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
const u64 actual_entries =
std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index);
const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
next_entry_index += actual_entries;
*out_count = actual_entries;
std::memcpy(out_entries, begin, range_size);
R_SUCCEED();
}
Result DoGetEntryCount(s64* out) {
*out = entries.size() - next_entry_index;
R_SUCCEED();
}
// TODO: Remove this when VFS is gone
template <typename T>
void BuildEntryIndex(const std::vector<T>& new_data, DirectoryEntryType type) {
entries.reserve(entries.size() + new_data.size());
for (const auto& new_entry : new_data) {
auto name = new_entry->GetName();
if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) {
continue;
}
entries.emplace_back(name, static_cast<s8>(type),
type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize());
}
}
VirtualDir backend;
std::vector<DirectoryEntry> entries;
u64 next_entry_index = 0;
};
} // namespace FileSys::Fsa

View File

@ -0,0 +1,167 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/overflow.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_file.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/fs_operate_range.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/result.h"
namespace FileSys::Fsa {
class IFile {
public:
explicit IFile(VirtualFile backend_) : backend(std::move(backend_)) {}
virtual ~IFile() {}
Result Read(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
// Check that we have an output pointer
R_UNLESS(out != nullptr, ResultNullptrArgument);
// If we have nothing to read, just succeed
if (size == 0) {
*out = 0;
R_SUCCEED();
}
// Check that the read is valid
R_UNLESS(buffer != nullptr, ResultNullptrArgument);
R_UNLESS(offset >= 0, ResultOutOfRange);
R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
// Do the read
R_RETURN(this->DoRead(out, offset, buffer, size, option));
}
Result Read(size_t* out, s64 offset, void* buffer, size_t size) {
R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None));
}
Result GetSize(s64* out) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetSize(out));
}
Result Flush() {
R_RETURN(this->DoFlush());
}
Result Write(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
// Handle the zero-size case
if (size == 0) {
if (option.HasFlushFlag()) {
R_TRY(this->Flush());
}
R_SUCCEED();
}
// Check the write is valid
R_UNLESS(buffer != nullptr, ResultNullptrArgument);
R_UNLESS(offset >= 0, ResultOutOfRange);
R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
R_RETURN(this->DoWrite(offset, buffer, size, option));
}
Result SetSize(s64 size) {
R_UNLESS(size >= 0, ResultOutOfRange);
R_RETURN(this->DoSetSize(size));
}
Result OperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
const void* src, size_t src_size) {
R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size));
}
Result OperateRange(OperationId op_id, s64 offset, s64 size) {
R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0));
}
protected:
Result DryRead(size_t* out, s64 offset, size_t size, const ReadOption& option,
OpenMode open_mode) {
// Check that we can read
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Read) != 0, ResultReadNotPermitted);
// Get the file size, and validate our offset
s64 file_size = 0;
R_TRY(this->DoGetSize(std::addressof(file_size)));
R_UNLESS(offset <= file_size, ResultOutOfRange);
*out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
R_SUCCEED();
}
Result DrySetSize(s64 size, OpenMode open_mode) {
// Check that we can write
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
R_SUCCEED();
}
Result DryWrite(bool* out_append, s64 offset, size_t size, const WriteOption& option,
OpenMode open_mode) {
// Check that we can write
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
// Get the file size
s64 file_size = 0;
R_TRY(this->DoGetSize(&file_size));
// Determine if we need to append
*out_append = false;
if (file_size < offset + static_cast<s64>(size)) {
R_UNLESS(static_cast<u32>(open_mode & OpenMode::AllowAppend) != 0,
ResultFileExtensionWithoutOpenModeAllowAppend);
*out_append = true;
}
R_SUCCEED();
}
private:
Result DoRead(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
const auto read_size = backend->Read(static_cast<u8*>(buffer), size, offset);
*out = read_size;
R_SUCCEED();
}
Result DoGetSize(s64* out) {
*out = backend->GetSize();
R_SUCCEED();
}
Result DoFlush() {
// Exists for SDK compatibiltity -- No need to flush file.
R_SUCCEED();
}
Result DoWrite(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
const std::size_t written = backend->Write(static_cast<const u8*>(buffer), size, offset);
ASSERT_MSG(written == size,
"Could not write all bytes to file (requested={:016X}, actual={:016X}).", size,
written);
R_SUCCEED();
}
Result DoSetSize(s64 size) {
backend->Resize(size);
R_SUCCEED();
}
Result DoOperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
const void* src, size_t src_size) {
R_THROW(ResultNotImplemented);
}
VirtualFile backend;
};
} // namespace FileSys::Fsa

View File

@ -0,0 +1,206 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/fs_path.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/result.h"
#include "core/hle/service/filesystem/filesystem.h"
namespace FileSys::Fsa {
class IFile;
class IDirectory;
enum class QueryId : u32 {
SetConcatenationFileAttribute = 0,
UpdateMac = 1,
IsSignedSystemPartitionOnSdCardValid = 2,
QueryUnpreparedFileInformation = 3,
};
class IFileSystem {
public:
explicit IFileSystem(VirtualDir backend_) : backend{std::move(backend_)} {}
virtual ~IFileSystem() {}
Result CreateFile(const Path& path, s64 size, CreateOption option) {
R_UNLESS(size >= 0, ResultOutOfRange);
R_RETURN(this->DoCreateFile(path, size, static_cast<int>(option)));
}
Result CreateFile(const Path& path, s64 size) {
R_RETURN(this->CreateFile(path, size, CreateOption::None));
}
Result DeleteFile(const Path& path) {
R_RETURN(this->DoDeleteFile(path));
}
Result CreateDirectory(const Path& path) {
R_RETURN(this->DoCreateDirectory(path));
}
Result DeleteDirectory(const Path& path) {
R_RETURN(this->DoDeleteDirectory(path));
}
Result DeleteDirectoryRecursively(const Path& path) {
R_RETURN(this->DoDeleteDirectoryRecursively(path));
}
Result RenameFile(const Path& old_path, const Path& new_path) {
R_RETURN(this->DoRenameFile(old_path, new_path));
}
Result RenameDirectory(const Path& old_path, const Path& new_path) {
R_RETURN(this->DoRenameDirectory(old_path, new_path));
}
Result GetEntryType(DirectoryEntryType* out, const Path& path) {
R_RETURN(this->DoGetEntryType(out, path));
}
Result OpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
R_UNLESS(out_file != nullptr, ResultNullptrArgument);
R_UNLESS(static_cast<u32>(mode & OpenMode::ReadWrite) != 0, ResultInvalidOpenMode);
R_UNLESS(static_cast<u32>(mode & ~OpenMode::All) == 0, ResultInvalidOpenMode);
R_RETURN(this->DoOpenFile(out_file, path, mode));
}
Result OpenDirectory(VirtualDir* out_dir, const Path& path, OpenDirectoryMode mode) {
R_UNLESS(out_dir != nullptr, ResultNullptrArgument);
R_UNLESS(static_cast<u64>(mode & OpenDirectoryMode::All) != 0, ResultInvalidOpenMode);
R_UNLESS(static_cast<u64>(
mode & ~(OpenDirectoryMode::All | OpenDirectoryMode::NotRequireFileSize)) == 0,
ResultInvalidOpenMode);
R_RETURN(this->DoOpenDirectory(out_dir, path, mode));
}
Result Commit() {
R_RETURN(this->DoCommit());
}
Result GetFreeSpaceSize(s64* out, const Path& path) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetFreeSpaceSize(out, path));
}
Result GetTotalSpaceSize(s64* out, const Path& path) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetTotalSpaceSize(out, path));
}
Result CleanDirectoryRecursively(const Path& path) {
R_RETURN(this->DoCleanDirectoryRecursively(path));
}
Result GetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetFileTimeStampRaw(out, path));
}
Result QueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
const Path& path) {
R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path));
}
// These aren't accessible as commands
Result CommitProvisionally(s64 counter) {
R_RETURN(this->DoCommitProvisionally(counter));
}
Result Rollback() {
R_RETURN(this->DoRollback());
}
Result Flush() {
R_RETURN(this->DoFlush());
}
private:
Result DoCreateFile(const Path& path, s64 size, int flags) {
R_RETURN(backend.CreateFile(path.GetString(), size));
}
Result DoDeleteFile(const Path& path) {
R_RETURN(backend.DeleteFile(path.GetString()));
}
Result DoCreateDirectory(const Path& path) {
R_RETURN(backend.CreateDirectory(path.GetString()));
}
Result DoDeleteDirectory(const Path& path) {
R_RETURN(backend.DeleteDirectory(path.GetString()));
}
Result DoDeleteDirectoryRecursively(const Path& path) {
R_RETURN(backend.DeleteDirectoryRecursively(path.GetString()));
}
Result DoRenameFile(const Path& old_path, const Path& new_path) {
R_RETURN(backend.RenameFile(old_path.GetString(), new_path.GetString()));
}
Result DoRenameDirectory(const Path& old_path, const Path& new_path) {
R_RETURN(backend.RenameDirectory(old_path.GetString(), new_path.GetString()));
}
Result DoGetEntryType(DirectoryEntryType* out, const Path& path) {
R_RETURN(backend.GetEntryType(out, path.GetString()));
}
Result DoOpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
R_RETURN(backend.OpenFile(out_file, path.GetString(), mode));
}
Result DoOpenDirectory(VirtualDir* out_directory, const Path& path, OpenDirectoryMode mode) {
R_RETURN(backend.OpenDirectory(out_directory, path.GetString()));
}
Result DoCommit() {
R_THROW(ResultNotImplemented);
}
Result DoGetFreeSpaceSize(s64* out, const Path& path) {
R_THROW(ResultNotImplemented);
}
Result DoGetTotalSpaceSize(s64* out, const Path& path) {
R_THROW(ResultNotImplemented);
}
Result DoCleanDirectoryRecursively(const Path& path) {
R_RETURN(backend.CleanDirectoryRecursively(path.GetString()));
}
Result DoGetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
R_RETURN(backend.GetFileTimeStampRaw(out, path.GetString()));
}
Result DoQueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
const Path& path) {
R_THROW(ResultNotImplemented);
}
// These aren't accessible as commands
Result DoCommitProvisionally(s64 counter) {
R_THROW(ResultNotImplemented);
}
Result DoRollback() {
R_THROW(ResultNotImplemented);
}
Result DoFlush() {
R_THROW(ResultNotImplemented);
}
Service::FileSystem::VfsDirectoryServiceWrapper backend;
};
} // namespace FileSys::Fsa

View File

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/file_sys/fs_directory.h"
namespace FileSys::Sf {
struct Path {
char str[EntryNameLengthMax + 1];
static constexpr Path Encode(const char* p) {
Path path = {};
for (size_t i = 0; i < sizeof(path) - 1; i++) {
path.str[i] = p[i];
if (p[i] == '\x00') {
break;
}
}
return path;
}
static constexpr size_t GetPathLength(const Path& path) {
size_t len = 0;
for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
len++;
}
return len;
}
};
static_assert(std::is_trivially_copyable_v<Path>, "Path must be trivially copyable.");
using FspPath = Path;
} // namespace FileSys::Sf

View File

@ -3,6 +3,7 @@
#pragma once
#include <mutex>
#include <optional>
#include "core/crypto/aes_util.h"

View File

@ -14,48 +14,11 @@ namespace FileSys {
namespace {
void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is "
"SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
meta.zero_1);
}
if (meta.zero_2 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is "
"SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
meta.zero_2);
}
if (meta.zero_3 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is "
"SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
meta.zero_3);
}
}
if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
"non-zero ({:016X}).",
meta.title_id);
}
if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
"non-zero ({:016X}{:016X})",
meta.user_id[1], meta.user_id[0]);
}
}
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage ||
(space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
(attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) &&
attr.title_id == 0 && attr.save_id == 0);
return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary ||
(space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User
(attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) &&
attr.program_id == 0 && attr.system_save_data_id == 0);
}
std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
@ -63,7 +26,7 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
// Only detect nand user saves.
const auto space_id_path = [space_id]() -> std::string_view {
switch (space_id) {
case SaveDataSpaceId::NandUser:
case SaveDataSpaceId::User:
return "/user/save";
default:
return "";
@ -79,9 +42,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
// Only detect account/device saves from the future location.
switch (type) {
case SaveDataType::SaveData:
case SaveDataType::Account:
return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
case SaveDataType::DeviceSaveData:
case SaveDataType::Device:
return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
default:
return "";
@ -90,13 +53,6 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
} // Anonymous namespace
std::string SaveDataAttribute::DebugInfo() const {
return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
"rank={}, index={}]",
title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
static_cast<u8>(rank), index);
}
SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
VirtualDir save_directory_)
: system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
@ -108,18 +64,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
SaveDataFactory::~SaveDataFactory() = default;
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
PrintSaveDataAttributeWarnings(meta);
const auto save_directory =
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
meta.user_id, meta.system_save_data_id);
return dir->CreateDirectoryRelative(save_directory);
}
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
const auto save_directory =
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
meta.user_id, meta.system_save_data_id);
auto out = dir->GetDirectoryRelative(save_directory);
@ -136,11 +90,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
switch (space) {
case SaveDataSpaceId::NandSystem:
case SaveDataSpaceId::System:
return "/system/";
case SaveDataSpaceId::NandUser:
case SaveDataSpaceId::User:
return "/user/";
case SaveDataSpaceId::TemporaryStorage:
case SaveDataSpaceId::Temporary:
return "/temp/";
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@ -153,7 +107,7 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
u128 user_id, u64 save_id) {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
if (type == SaveDataType::Account || type == SaveDataType::Device) {
if (title_id == 0) {
title_id = program_id;
}
@ -173,16 +127,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
std::string out = GetSaveDataSpaceIdPath(space);
switch (type) {
case SaveDataType::SystemSaveData:
case SaveDataType::System:
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
case SaveDataType::SaveData:
case SaveDataType::DeviceSaveData:
case SaveDataType::Account:
case SaveDataType::Device:
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
case SaveDataType::TemporaryStorage:
case SaveDataType::Temporary:
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
case SaveDataType::CacheStorage:
case SaveDataType::Cache:
return fmt::format("{}save/cache/{:016X}", out, title_id);
default:
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
@ -202,7 +156,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const {
const auto path =
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
@ -221,7 +175,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) const {
const auto path =
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());

View File

@ -7,6 +7,7 @@
#include <string>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/file_sys/fs_save_data_types.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"
@ -16,73 +17,6 @@ class System;
namespace FileSys {
enum class SaveDataSpaceId : u8 {
NandSystem = 0,
NandUser = 1,
SdCardSystem = 2,
TemporaryStorage = 3,
SdCardUser = 4,
ProperSystem = 100,
SafeMode = 101,
};
enum class SaveDataType : u8 {
SystemSaveData = 0,
SaveData = 1,
BcatDeliveryCacheStorage = 2,
DeviceSaveData = 3,
TemporaryStorage = 4,
CacheStorage = 5,
SystemBcat = 6,
};
enum class SaveDataRank : u8 {
Primary = 0,
Secondary = 1,
};
enum class SaveDataFlags : u32 {
None = (0 << 0),
KeepAfterResettingSystemSaveData = (1 << 0),
KeepAfterRefurbishment = (1 << 1),
KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
NeedsSecureDelete = (1 << 3),
};
struct SaveDataAttribute {
u64 title_id;
u128 user_id;
u64 save_id;
SaveDataType type;
SaveDataRank rank;
u16 index;
INSERT_PADDING_BYTES_NOINIT(4);
u64 zero_1;
u64 zero_2;
u64 zero_3;
std::string DebugInfo() const;
};
static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
struct SaveDataExtraData {
SaveDataAttribute attr;
u64 owner_id;
s64 timestamp;
SaveDataFlags flags;
INSERT_PADDING_BYTES_NOINIT(4);
s64 available_size;
s64 journal_size;
s64 commit_id;
std::array<u8, 0x190> unused;
};
static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
struct SaveDataSize {
u64 normal;
u64 journal;
};
constexpr const char* GetSaveDataSizeFileName() {
return ".yuzu_save_size";
}

View File

@ -44,15 +44,32 @@ public:
GuestMemory() = delete;
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: m_memory{memory}, m_addr{addr}, m_size{size} {
: m_memory{&memory}, m_addr{addr}, m_size{size} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (FLAGS & GuestMemoryFlags::Read) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
m_span_valid = true;
m_is_data_copy = true;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
m_span_valid = true;
m_is_data_copy = true;
}
}
} else if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup);
}
}
~GuestMemory() = default;
GuestMemory(GuestMemory&& rhs) = default;
GuestMemory& operator=(GuestMemory&& rhs) = default;
T* data() noexcept {
return m_data_span.data();
}
@ -109,8 +126,8 @@ public:
}
if (this->TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.FlushRegion(m_addr, this->size_bytes());
if constexpr (FLAGS & GuestMemoryFlags::Safe && M::HAS_FLUSH_INVALIDATION) {
m_memory->FlushRegion(m_addr, this->size_bytes());
}
} else {
if (backup) {
@ -123,9 +140,9 @@ public:
m_is_data_copy = true;
m_span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
m_memory->ReadBlock(m_addr, this->data(), this->size_bytes());
} else {
m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
m_memory->ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
}
}
return m_data_span;
@ -133,18 +150,19 @@ public:
void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlock(m_addr, write_data.data(), this->size_bytes());
} else {
m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
}
}
bool TrySetSpan() noexcept {
if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
if (u8* ptr = m_memory->GetSpan(m_addr, this->size_bytes()); ptr) {
m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
m_span_valid = true;
m_is_data_copy = false;
return true;
}
return false;
@ -159,7 +177,7 @@ protected:
return m_addr_changed;
}
M& m_memory;
M* m_memory;
u64 m_addr{};
size_t m_size{};
std::span<T> m_data_span{};
@ -175,17 +193,7 @@ public:
GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
this->m_data_span = *backup;
this->m_span_valid = true;
this->m_is_data_copy = true;
}
}
}
}
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {}
~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
@ -196,15 +204,17 @@ public:
if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlockCached(this->m_addr, this->data(),
this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlockUnsafe(this->m_addr, this->data(),
this->size_bytes());
}
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
(FLAGS & GuestMemoryFlags::Cached)) {
this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
this->m_memory->InvalidateRegion(this->m_addr, this->size_bytes());
}
}
}

View File

@ -1170,6 +1170,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
// Determine if we are an application.
if (pool == KMemoryManager::Pool::Application) {
flag |= Svc::CreateProcessFlag::IsApplication;
m_is_application = true;
}
// If we are 64-bit, create as such.

View File

@ -25,8 +25,8 @@
#include "core/hle/service/acc/async_context.h"
#include "core/hle/service/acc/errors.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/loader/loader.h"
@ -74,12 +74,12 @@ static void SanitizeJPEGImageSize(std::vector<u8>& image) {
class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> {
public:
explicit IManagerForSystemService(Core::System& system_, Common::UUID)
: ServiceFramework{system_, "IManagerForSystemService"} {
explicit IManagerForSystemService(Core::System& system_, Common::UUID uuid)
: ServiceFramework{system_, "IManagerForSystemService"}, account_id{uuid} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IManagerForSystemService::CheckAvailability, "CheckAvailability"},
{1, nullptr, "GetAccountId"},
{0, D<&IManagerForSystemService::CheckAvailability>, "CheckAvailability"},
{1, D<&IManagerForSystemService::GetAccountId>, "GetAccountId"},
{2, nullptr, "EnsureIdTokenCacheAsync"},
{3, nullptr, "LoadIdTokenCache"},
{100, nullptr, "SetSystemProgramIdentification"},
@ -109,11 +109,18 @@ public:
}
private:
void CheckAvailability(HLERequestContext& ctx) {
Result CheckAvailability() {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
Result GetAccountId(Out<u64> out_account_id) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
*out_account_id = account_id.Hash();
R_SUCCEED();
}
Common::UUID account_id;
};
// 3.0.0+

View File

@ -23,7 +23,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
{99, nullptr, "DebugActivateOpenContextRetention"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
{102, nullptr, "GetBaasAccountManagerForSystemService"},
{102, &ACC_U1::GetBaasAccountManagerForSystemService, "GetBaasAccountManagerForSystemService"},
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
{104, nullptr, "GetProfileUpdateNotifier"},
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},

View File

@ -2,19 +2,26 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/button_poller.h"
#include "core/hle/service/am/event_observer.h"
#include "core/hle/service/am/service/all_system_applet_proxies_service.h"
#include "core/hle/service/am/service/application_proxy_service.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/server_manager.h"
namespace Service::AM {
void LoopProcess(Core::System& system) {
WindowSystem window_system(system);
ButtonPoller button_poller(system, window_system);
EventObserver event_observer(system, window_system);
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("appletAE",
std::make_shared<IAllSystemAppletProxiesService>(system));
server_manager->RegisterNamedService("appletOE",
std::make_shared<IApplicationProxyService>(system));
server_manager->RegisterNamedService(
"appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, window_system));
server_manager->RegisterNamedService(
"appletOE", std::make_shared<IApplicationProxyService>(system, window_system));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -9,6 +9,7 @@ namespace Service::AM {
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
constexpr Result ResultNoMessages{ErrorModule::AM, 3};
constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22};
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};

View File

@ -48,11 +48,6 @@ enum class SystemButtonType {
CaptureButtonLongPressing,
};
enum class SysPlatformRegion : s32 {
Global = 1,
Terra = 2,
};
struct AppletProcessLaunchReason {
u8 flag;
INSERT_PADDING_BYTES(3);
@ -66,12 +61,6 @@ enum class ScreenshotPermission : u32 {
Disable = 2,
};
struct FocusHandlingMode {
bool notify;
bool background;
bool suspend;
};
enum class IdleTimeDetectionExtension : u32 {
Disabled = 0,
Extended = 1,
@ -244,7 +233,6 @@ struct ApplicationPlayStatistics {
static_assert(sizeof(ApplicationPlayStatistics) == 0x18,
"ApplicationPlayStatistics has incorrect size.");
using AppletResourceUserId = u64;
using ProgramId = u64;
struct Applet;

View File

@ -1,27 +1,71 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
namespace Service::AM {
Applet::Applet(Core::System& system, std::unique_ptr<Process> process_)
: context(system, "Applet"), message_queue(system), process(std::move(process_)),
hid_registration(system, *process), gpu_error_detected_event(context),
friend_invitation_storage_channel_event(context), notification_storage_channel_event(context),
health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context),
pop_from_general_channel_event(context), library_applet_launchable_event(context),
accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) {
Applet::Applet(Core::System& system, std::unique_ptr<Process> process_, bool is_application)
: context(system, "Applet"), lifecycle_manager(system, context, is_application),
process(std::move(process_)), hid_registration(system, *process),
gpu_error_detected_event(context), friend_invitation_storage_channel_event(context),
notification_storage_channel_event(context), health_warning_disappeared_system_event(context),
acquired_sleep_lock_event(context), pop_from_general_channel_event(context),
library_applet_launchable_event(context), accumulated_suspended_tick_changed_event(context),
sleep_lock_event(context), state_changed_event(context) {
aruid = process->GetProcessId();
aruid.pid = process->GetProcessId();
program_id = process->GetProgramId();
}
Applet::~Applet() = default;
void Applet::UpdateSuspensionStateLocked(bool force_message) {
// Remove any forced resumption.
lifecycle_manager.RemoveForceResumeIfPossible();
// Check if we're runnable.
const bool curr_activity_runnable = lifecycle_manager.IsRunnable();
const bool prev_activity_runnable = is_activity_runnable;
const bool was_changed = curr_activity_runnable != prev_activity_runnable;
if (was_changed) {
if (curr_activity_runnable) {
process->Suspend(false);
} else {
process->Suspend(true);
lifecycle_manager.RequestResumeNotification();
}
is_activity_runnable = curr_activity_runnable;
}
if (lifecycle_manager.GetForcedSuspend()) {
// TODO: why is this allowed?
return;
}
// Signal if the focus state was changed or the process state was changed.
if (lifecycle_manager.UpdateRequestedFocusState() || was_changed || force_message) {
lifecycle_manager.SignalSystemEventIfNeeded();
}
}
void Applet::SetInteractibleLocked(bool interactible) {
if (is_interactible == interactible) {
return;
}
is_interactible = interactible;
hid_registration.EnableAppletToGetInput(interactible && !lifecycle_manager.GetExitRequested());
}
void Applet::OnProcessTerminatedLocked() {
is_completed = true;
state_changed_event.Signal();
}
} // namespace Service::AM

View File

@ -3,25 +3,28 @@
#pragma once
#include <deque>
#include <mutex>
#include "common/math_util.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/os/process.h"
#include "core/hle/service/service.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/am/display_layer_manager.h"
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/am/lifecycle_manager.h"
#include "core/hle/service/am/process_holder.h"
namespace Service::AM {
struct Applet {
explicit Applet(Core::System& system, std::unique_ptr<Process> process_);
explicit Applet(Core::System& system, std::unique_ptr<Process> process_, bool is_application);
~Applet();
// Lock
@ -30,11 +33,13 @@ struct Applet {
// Event creation helper
KernelHelpers::ServiceContext context;
// Applet message queue
AppletMessageQueue message_queue;
// Lifecycle manager
LifecycleManager lifecycle_manager;
// Process
std::unique_ptr<Process> process;
std::optional<ProcessHolder> process_holder;
bool is_process_running{};
// Creation state
AppletId applet_id{};
@ -75,11 +80,9 @@ struct Applet {
bool game_play_recording_supported{};
GamePlayRecordingState game_play_recording_state{GamePlayRecordingState::Disabled};
bool jit_service_launched{};
bool is_running{};
bool application_crash_report_enabled{};
// Common state
FocusState focus_state{};
bool sleep_lock_enabled{};
bool vr_mode_enabled{};
bool lcd_backlight_off_enabled{};
@ -93,15 +96,12 @@ struct Applet {
// Caller applet
std::weak_ptr<Applet> caller_applet{};
std::shared_ptr<AppletDataBroker> caller_applet_broker{};
std::list<std::shared_ptr<Applet>> child_applets{};
bool is_completed{};
// Self state
bool exit_locked{};
s32 fatal_section_count{};
bool operation_mode_changed_notification_enabled{true};
bool performance_mode_changed_notification_enabled{true};
FocusHandlingMode focus_handling_mode{};
bool restart_message_enabled{};
bool out_of_focus_suspension_enabled{true};
Capture::AlbumImageOrientation album_image_orientation{};
bool handles_request_to_display{};
ScreenshotPermission screenshot_permission{};
@ -110,6 +110,9 @@ struct Applet {
u64 suspended_ticks{};
bool album_image_taken_notification_enabled{};
bool record_volume_muted{};
bool is_activity_runnable{};
bool is_interactible{true};
bool window_visible{true};
// Events
Event gpu_error_detected_event;
@ -121,9 +124,15 @@ struct Applet {
Event library_applet_launchable_event;
Event accumulated_suspended_tick_changed_event;
Event sleep_lock_event;
Event state_changed_event;
// Frontend state
std::shared_ptr<Frontend::FrontendApplet> frontend{};
// Process state management
void UpdateSuspensionStateLocked(bool force_message);
void SetInteractibleLocked(bool interactible);
void OnProcessTerminatedLocked();
};
} // namespace Service::AM

View File

@ -44,24 +44,8 @@ Kernel::KReadableEvent* AppletStorageChannel::GetEvent() {
AppletDataBroker::AppletDataBroker(Core::System& system_)
: system(system_), context(system_, "AppletDataBroker"), in_data(context),
interactive_in_data(context), out_data(context), interactive_out_data(context),
state_changed_event(context), is_completed(false) {}
interactive_in_data(context), out_data(context), interactive_out_data(context) {}
AppletDataBroker::~AppletDataBroker() = default;
void AppletDataBroker::SignalCompletion() {
{
std::scoped_lock lk{lock};
if (is_completed) {
return;
}
is_completed = true;
state_changed_event.Signal();
}
system.GetAppletManager().FocusStateChanged();
}
} // namespace Service::AM

View File

@ -53,16 +53,6 @@ public:
return interactive_out_data;
}
Event& GetStateChangedEvent() {
return state_changed_event;
}
bool IsCompleted() const {
return is_completed;
}
void SignalCompletion();
private:
Core::System& system;
KernelHelpers::ServiceContext context;
@ -71,10 +61,6 @@ private:
AppletStorageChannel interactive_in_data;
AppletStorageChannel out_data;
AppletStorageChannel interactive_out_data;
Event state_changed_event;
std::mutex lock;
bool is_completed;
};
} // namespace Service::AM

View File

@ -13,6 +13,7 @@
#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/am/window_system.h"
#include "hid_core/hid_types.h"
namespace Service::AM {
@ -225,49 +226,46 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan
} // namespace
AppletManager::AppletManager(Core::System& system) : m_system(system) {}
AppletManager::~AppletManager() {
this->Reset();
}
void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) {
std::scoped_lock lk{m_lock};
m_applets.emplace(applet->aruid, std::move(applet));
}
void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) {
std::shared_ptr<Applet> applet;
bool should_stop = false;
{
std::scoped_lock lk{m_lock};
const auto it = m_applets.find(aruid);
if (it == m_applets.end()) {
return;
}
applet = it->second;
m_applets.erase(it);
should_stop = m_applets.empty();
}
// Terminate process.
applet->process->Terminate();
// If there were no applets left, stop emulation.
if (should_stop) {
m_system.Exit();
}
}
AppletManager::~AppletManager() = default;
void AppletManager::CreateAndInsertByFrontendAppletParameters(
AppletResourceUserId aruid, const FrontendAppletParameters& params) {
// TODO: this should be run inside AM so that the events will have a parent process
// TODO: have am create the guest process
auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system));
std::unique_ptr<Process> process, const FrontendAppletParameters& params) {
{
std::scoped_lock lk{m_lock};
m_pending_process = std::move(process);
m_pending_parameters = params;
}
m_cv.notify_all();
}
void AppletManager::RequestExit() {
std::scoped_lock lk{m_lock};
if (m_window_system) {
m_window_system->OnExitRequested();
}
}
void AppletManager::OperationModeChanged() {
std::scoped_lock lk{m_lock};
if (m_window_system) {
m_window_system->OnOperationModeChanged();
}
}
void AppletManager::SetWindowSystem(WindowSystem* window_system) {
std::unique_lock lk{m_lock};
m_window_system = window_system;
if (!m_window_system) {
return;
}
m_cv.wait(lk, [&] { return m_pending_process != nullptr; });
const auto& params = m_pending_parameters;
auto applet = std::make_shared<Applet>(m_system, std::move(m_pending_process),
params.applet_id == AppletId::Application);
applet->aruid = aruid;
applet->program_id = params.program_id;
applet->applet_id = params.applet_id;
applet->type = params.applet_type;
@ -322,59 +320,19 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters(
}
// Applet was started by frontend, so it is foreground.
applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessage::FocusStateChanged);
applet->focus_state = FocusState::InFocus;
applet->lifecycle_manager.SetFocusState(FocusState::InFocus);
this->InsertApplet(std::move(applet));
}
std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const {
std::scoped_lock lk{m_lock};
if (const auto it = m_applets.find(aruid); it != m_applets.end()) {
return it->second;
if (applet->applet_id == AppletId::QLaunch) {
applet->lifecycle_manager.SetFocusHandlingMode(false);
applet->lifecycle_manager.SetOutOfFocusSuspendingEnabled(false);
m_window_system->TrackApplet(applet, false);
m_window_system->RequestHomeMenuToGetForeground();
} else {
m_window_system->TrackApplet(applet, true);
m_window_system->RequestApplicationToGetForeground();
}
return {};
}
void AppletManager::Reset() {
std::scoped_lock lk{m_lock};
m_applets.clear();
}
void AppletManager::RequestExit() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
applet->message_queue.RequestExit();
}
}
void AppletManager::RequestResume() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
applet->message_queue.RequestResume();
}
}
void AppletManager::OperationModeChanged() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
applet->message_queue.OperationModeChanged();
}
}
void AppletManager::FocusStateChanged() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
applet->message_queue.FocusStateChanged();
}
applet->process->Run();
}
} // namespace Service::AM

View File

@ -3,17 +3,23 @@
#pragma once
#include <map>
#include <condition_variable>
#include <mutex>
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/am_types.h"
namespace Core {
class System;
}
namespace Service {
class Process;
}
namespace Service::AM {
class WindowSystem;
enum class LaunchType {
FrontendInitiated,
ApplicationInitiated,
@ -33,27 +39,24 @@ public:
explicit AppletManager(Core::System& system);
~AppletManager();
void InsertApplet(std::shared_ptr<Applet> applet);
void TerminateAndRemoveApplet(AppletResourceUserId aruid);
void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid,
void CreateAndInsertByFrontendAppletParameters(std::unique_ptr<Process> process,
const FrontendAppletParameters& params);
std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const;
void Reset();
void RequestExit();
void RequestResume();
void OperationModeChanged();
void FocusStateChanged();
public:
void SetWindowSystem(WindowSystem* window_system);
private:
Core::System& m_system;
mutable std::mutex m_lock{};
std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{};
std::mutex m_lock;
std::condition_variable m_cv;
// AudioController state goes here
WindowSystem* m_window_system{};
FrontendAppletParameters m_pending_parameters{};
std::unique_ptr<Process> m_pending_process{};
};
} // namespace Service::AM

View File

@ -1,73 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
AppletMessageQueue::AppletMessageQueue(Core::System& system)
: service_context{system, "AppletMessageQueue"} {
on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
}
AppletMessageQueue::~AppletMessageQueue() {
service_context.CloseEvent(on_new_message);
service_context.CloseEvent(on_operation_mode_changed);
}
Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
return on_new_message->GetReadableEvent();
}
Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
return on_operation_mode_changed->GetReadableEvent();
}
void AppletMessageQueue::PushMessage(AppletMessage msg) {
{
std::scoped_lock lk{lock};
messages.push(msg);
}
on_new_message->Signal();
}
AppletMessage AppletMessageQueue::PopMessage() {
std::scoped_lock lk{lock};
if (messages.empty()) {
on_new_message->Clear();
return AppletMessage::None;
}
auto msg = messages.front();
messages.pop();
if (messages.empty()) {
on_new_message->Clear();
}
return msg;
}
std::size_t AppletMessageQueue::GetMessageCount() const {
std::scoped_lock lk{lock};
return messages.size();
}
void AppletMessageQueue::RequestExit() {
PushMessage(AppletMessage::Exit);
}
void AppletMessageQueue::RequestResume() {
PushMessage(AppletMessage::Resume);
}
void AppletMessageQueue::FocusStateChanged() {
PushMessage(AppletMessage::FocusStateChanged);
}
void AppletMessageQueue::OperationModeChanged() {
PushMessage(AppletMessage::OperationModeChanged);
PushMessage(AppletMessage::PerformanceModeChanged);
on_operation_mode_changed->Signal();
}
} // namespace Service::AM

View File

@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <queue>
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Kernel {
class KReadableEvent;
} // namespace Kernel
namespace Service::AM {
class AppletMessageQueue {
public:
explicit AppletMessageQueue(Core::System& system);
~AppletMessageQueue();
Kernel::KReadableEvent& GetMessageReceiveEvent();
Kernel::KReadableEvent& GetOperationModeChangedEvent();
void PushMessage(AppletMessage msg);
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
void RequestExit();
void RequestResume();
void FocusStateChanged();
void OperationModeChanged();
private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* on_new_message;
Kernel::KEvent* on_operation_mode_changed;
mutable std::mutex lock;
std::queue<AppletMessage> messages;
};
} // namespace Service::AM

View File

@ -0,0 +1,89 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/am/button_poller.h"
#include "core/hle/service/am/window_system.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
namespace Service::AM {
namespace {
ButtonPressDuration ClassifyPressDuration(std::chrono::steady_clock::time_point start) {
using namespace std::chrono_literals;
const auto dur = std::chrono::steady_clock::now() - start;
// TODO: determine actual thresholds
// TODO: these are likely different for each button
if (dur < 500ms) {
return ButtonPressDuration::ShortPressing;
} else if (dur < 1000ms) {
return ButtonPressDuration::MiddlePressing;
} else {
return ButtonPressDuration::LongPressing;
}
}
} // namespace
ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system)
: m_window_system(window_system) {
// TODO: am reads this from the home button state in hid, which is controller-agnostic.
Core::HID::ControllerUpdateCallback engine_callback{
.on_change =
[this](Core::HID::ControllerTriggerType type) {
if (type == Core::HID::ControllerTriggerType::Button) {
this->OnButtonStateChanged();
}
},
.is_npad_service = true,
};
m_handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
m_handheld_key = m_handheld->SetCallback(engine_callback);
m_player1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
m_player1_key = m_player1->SetCallback(engine_callback);
}
ButtonPoller::~ButtonPoller() {
m_handheld->DeleteCallback(m_handheld_key);
m_player1->DeleteCallback(m_player1_key);
}
void ButtonPoller::OnButtonStateChanged() {
const bool home_button =
m_handheld->GetHomeButtons().home.Value() || m_player1->GetHomeButtons().home.Value();
const bool capture_button = m_handheld->GetCaptureButtons().capture.Value() ||
m_player1->GetCaptureButtons().capture.Value();
// Buttons pressed which were not previously pressed
if (home_button && !m_home_button_press_start) {
m_home_button_press_start = std::chrono::steady_clock::now();
}
if (capture_button && !m_capture_button_press_start) {
m_capture_button_press_start = std::chrono::steady_clock::now();
}
// if (power_button && !m_power_button_press_start) {
// m_power_button_press_start = std::chrono::steady_clock::now();
// }
// Buttons released which were previously held
if (!home_button && m_home_button_press_start) {
m_window_system.OnHomeButtonPressed(ClassifyPressDuration(*m_home_button_press_start));
m_home_button_press_start = std::nullopt;
}
if (!capture_button && m_capture_button_press_start) {
// TODO
m_capture_button_press_start = std::nullopt;
}
// if (!power_button && m_power_button_press_start) {
// // TODO
// m_power_button_press_start = std::nullopt;
// }
}
} // namespace Service::AM

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <chrono>
#include <optional>
#include "hid_core/frontend/emulated_controller.h"
namespace Core {
namespace HID {
class EmulatedController;
}
class System;
} // namespace Core
namespace Service::AM {
class WindowSystem;
class ButtonPoller {
public:
explicit ButtonPoller(Core::System& system, WindowSystem& window_system);
~ButtonPoller();
private:
void OnButtonStateChanged();
private:
WindowSystem& m_window_system;
Core::HID::EmulatedController* m_handheld{};
int m_handheld_key{};
Core::HID::EmulatedController* m_player1{};
int m_player1_key{};
std::optional<std::chrono::steady_clock::time_point> m_home_button_press_start{};
std::optional<std::chrono::steady_clock::time_point> m_capture_button_press_start{};
std::optional<std::chrono::steady_clock::time_point> m_power_button_press_start{};
};
} // namespace Service::AM

View File

@ -0,0 +1,162 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/event_observer.h"
#include "core/hle/service/am/window_system.h"
namespace Service::AM {
enum class UserDataTag : u32 {
WakeupEvent,
AppletProcess,
};
EventObserver::EventObserver(Core::System& system, WindowSystem& window_system)
: m_system(system), m_context(system, "am:EventObserver"), m_window_system(window_system),
m_wakeup_event(m_context), m_wakeup_holder(m_wakeup_event.GetHandle()) {
m_window_system.SetEventObserver(this);
m_wakeup_holder.SetUserData(static_cast<uintptr_t>(UserDataTag::WakeupEvent));
m_wakeup_holder.LinkToMultiWait(std::addressof(m_multi_wait));
m_thread = std::thread([&] { this->ThreadFunc(); });
}
EventObserver::~EventObserver() {
// Signal thread and wait for processing to finish.
m_stop_source.request_stop();
m_wakeup_event.Signal();
m_thread.join();
// Free remaining owned sessions.
auto it = m_process_holder_list.begin();
while (it != m_process_holder_list.end()) {
// Get the holder.
auto* const holder = std::addressof(*it);
// Remove from the list.
it = m_process_holder_list.erase(it);
// Free the holder.
delete holder;
}
}
void EventObserver::TrackAppletProcess(Applet& applet) {
// Don't observe dummy processes.
if (!applet.process->IsInitialized()) {
return;
}
// Allocate new holder.
auto* holder = new ProcessHolder(applet, *applet.process);
holder->SetUserData(static_cast<uintptr_t>(UserDataTag::AppletProcess));
// Insert into list.
{
std::scoped_lock lk{m_lock};
m_process_holder_list.push_back(*holder);
holder->LinkToMultiWait(std::addressof(m_deferred_wait_list));
}
// Signal wakeup.
m_wakeup_event.Signal();
}
void EventObserver::RequestUpdate() {
m_wakeup_event.Signal();
}
void EventObserver::LinkDeferred() {
std::scoped_lock lk{m_lock};
m_multi_wait.MoveAll(std::addressof(m_deferred_wait_list));
}
MultiWaitHolder* EventObserver::WaitSignaled() {
while (true) {
this->LinkDeferred();
// If we're done, return before we start waiting.
if (m_stop_source.stop_requested()) {
return nullptr;
}
auto* selected = m_multi_wait.WaitAny(m_system.Kernel());
if (selected != std::addressof(m_wakeup_holder)) {
// Unlink the process.
selected->UnlinkFromMultiWait();
}
return selected;
}
}
void EventObserver::Process(MultiWaitHolder* holder) {
switch (static_cast<UserDataTag>(holder->GetUserData())) {
case UserDataTag::WakeupEvent:
this->OnWakeupEvent(holder);
break;
case UserDataTag::AppletProcess:
this->OnProcessEvent(static_cast<ProcessHolder*>(holder));
break;
default:
UNREACHABLE();
}
}
void EventObserver::OnWakeupEvent(MultiWaitHolder* holder) {
m_wakeup_event.Clear();
// Perform recalculation.
m_window_system.Update();
}
void EventObserver::OnProcessEvent(ProcessHolder* holder) {
// Check process state.
auto& applet = holder->GetApplet();
auto& process = holder->GetProcess();
{
std::scoped_lock lk{m_lock, applet.lock};
if (process.IsTerminated()) {
// Destroy the holder.
this->DestroyAppletProcessHolderLocked(holder);
} else {
// Reset signaled state.
process.ResetSignal();
// Relink wakeup event.
holder->LinkToMultiWait(std::addressof(m_deferred_wait_list));
}
// Set running.
applet.is_process_running = process.IsRunning();
}
// Perform recalculation.
m_window_system.Update();
}
void EventObserver::DestroyAppletProcessHolderLocked(ProcessHolder* holder) {
// Remove from owned list.
m_process_holder_list.erase(m_process_holder_list.iterator_to(*holder));
// Destroy and free.
delete holder;
}
void EventObserver::ThreadFunc() {
Common::SetCurrentThreadName("am:EventObserver");
while (true) {
auto* signaled_holder = this->WaitSignaled();
if (!signaled_holder) {
break;
}
this->Process(signaled_holder);
}
}
} // namespace Service::AM

View File

@ -0,0 +1,74 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/polyfill_thread.h"
#include "common/thread.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/os/multi_wait.h"
namespace Core {
class System;
}
namespace Service::AM {
struct Applet;
class ProcessHolder;
class WindowSystem;
class EventObserver {
public:
explicit EventObserver(Core::System& system, WindowSystem& window_system);
~EventObserver();
void TrackAppletProcess(Applet& applet);
void RequestUpdate();
private:
void LinkDeferred();
MultiWaitHolder* WaitSignaled();
void Process(MultiWaitHolder* holder);
bool WaitAndProcessImpl();
void LoopProcess();
private:
void OnWakeupEvent(MultiWaitHolder* holder);
void OnProcessEvent(ProcessHolder* holder);
private:
void DestroyAppletProcessHolderLocked(ProcessHolder* holder);
private:
void ThreadFunc();
private:
// System reference and context.
Core::System& m_system;
KernelHelpers::ServiceContext m_context;
// Window manager.
WindowSystem& m_window_system;
// Guest event handle to wake up the event loop processor.
Event m_wakeup_event;
MultiWaitHolder m_wakeup_holder;
// Mutex to protect remaining members.
std::mutex m_lock{};
// List of owned process holders.
Common::IntrusiveListBaseTraits<ProcessHolder>::ListType m_process_holder_list;
// Multi-wait objects for new tasks.
MultiWait m_multi_wait;
MultiWait m_deferred_wait_list;
// Processing thread.
std::thread m_thread{};
std::stop_source m_stop_source{};
};
} // namespace Service::AM

View File

@ -69,7 +69,11 @@ void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
}
void FrontendApplet::Exit() {
applet.lock()->caller_applet_broker->SignalCompletion();
auto applet_ = applet.lock();
std::scoped_lock lk{applet_->lock};
applet_->is_completed = true;
applet_->state_changed_event.Signal();
}
FrontendAppletSet::FrontendAppletSet() = default;

View File

@ -3,24 +3,28 @@
#include "core/core.h"
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/hid/hid_server.h"
#include "core/hle/service/os/process.h"
#include "core/hle/service/sm/sm.h"
#include "hid_core/resource_manager.h"
namespace Service::AM {
HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) {
m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid");
m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid", true);
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
true);
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
true);
}
}
HidRegistration::~HidRegistration() {
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
false);
m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId(
m_process.GetProcessId());
}
@ -28,6 +32,8 @@ HidRegistration::~HidRegistration() {
void HidRegistration::EnableAppletToGetInput(bool enable) {
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
enable);
m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
}
}

View File

@ -13,9 +13,11 @@ namespace Service::HID {
class IHidServer;
}
namespace Service::AM {
namespace Service {
class Process;
}
namespace Service::AM {
class HidRegistration {
public:

View File

@ -0,0 +1,379 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "core/hle/service/am/lifecycle_manager.h"
namespace Service::AM {
LifecycleManager::LifecycleManager(Core::System& system, KernelHelpers::ServiceContext& context,
bool is_application)
: m_system_event(context), m_operation_mode_changed_system_event(context),
m_is_application(is_application) {}
LifecycleManager::~LifecycleManager() = default;
Event& LifecycleManager::GetSystemEvent() {
return m_system_event;
}
Event& LifecycleManager::GetOperationModeChangedSystemEvent() {
return m_operation_mode_changed_system_event;
}
void LifecycleManager::PushUnorderedMessage(AppletMessage message) {
m_unordered_messages.push_back(message);
this->SignalSystemEventIfNeeded();
}
AppletMessage LifecycleManager::PopMessageInOrderOfPriority() {
if (m_has_resume) {
m_has_resume = false;
return AppletMessage::Resume;
}
if (m_has_acknowledged_exit != m_has_requested_exit) {
m_has_acknowledged_exit = m_has_requested_exit;
return AppletMessage::Exit;
}
if (m_focus_state_changed_notification_enabled) {
if (!m_is_application) {
if (m_requested_focus_state != m_acknowledged_focus_state) {
m_acknowledged_focus_state = m_requested_focus_state;
switch (m_requested_focus_state) {
case FocusState::InFocus:
return AppletMessage::ChangeIntoForeground;
case FocusState::NotInFocus:
return AppletMessage::ChangeIntoBackground;
default:
ASSERT(false);
}
}
} else if (m_has_focus_state_changed) {
m_has_focus_state_changed = false;
return AppletMessage::FocusStateChanged;
}
}
if (m_has_requested_request_to_prepare_sleep != m_has_acknowledged_request_to_prepare_sleep) {
m_has_acknowledged_request_to_prepare_sleep = true;
return AppletMessage::RequestToPrepareSleep;
}
if (m_requested_request_to_display_state != m_acknowledged_request_to_display_state) {
m_acknowledged_request_to_display_state = m_requested_request_to_display_state;
return AppletMessage::RequestToDisplay;
}
if (m_has_operation_mode_changed) {
m_has_operation_mode_changed = false;
return AppletMessage::OperationModeChanged;
}
if (m_has_performance_mode_changed) {
m_has_performance_mode_changed = false;
return AppletMessage::PerformanceModeChanged;
}
if (m_has_sd_card_removed) {
m_has_sd_card_removed = false;
return AppletMessage::SdCardRemoved;
}
if (m_has_sleep_required_by_high_temperature) {
m_has_sleep_required_by_high_temperature = false;
return AppletMessage::SleepRequiredByHighTemperature;
}
if (m_has_sleep_required_by_low_battery) {
m_has_sleep_required_by_low_battery = false;
return AppletMessage::SleepRequiredByLowBattery;
}
if (m_has_auto_power_down) {
m_has_auto_power_down = false;
return AppletMessage::AutoPowerDown;
}
if (m_has_album_screen_shot_taken) {
m_has_album_screen_shot_taken = false;
return AppletMessage::AlbumScreenShotTaken;
}
if (m_has_album_recording_saved) {
m_has_album_recording_saved = false;
return AppletMessage::AlbumRecordingSaved;
}
if (!m_unordered_messages.empty()) {
const auto message = m_unordered_messages.front();
m_unordered_messages.pop_front();
return message;
}
return AppletMessage::None;
}
bool LifecycleManager::ShouldSignalSystemEvent() {
if (m_focus_state_changed_notification_enabled) {
if (!m_is_application) {
if (m_requested_focus_state != m_acknowledged_focus_state) {
return true;
}
} else if (m_has_focus_state_changed) {
return true;
}
}
return !m_unordered_messages.empty() || m_has_resume ||
(m_has_requested_exit != m_has_acknowledged_exit) ||
(m_has_requested_request_to_prepare_sleep !=
m_has_acknowledged_request_to_prepare_sleep) ||
m_has_operation_mode_changed || m_has_performance_mode_changed ||
m_has_sd_card_removed || m_has_sleep_required_by_high_temperature ||
m_has_sleep_required_by_low_battery || m_has_auto_power_down ||
(m_requested_request_to_display_state != m_acknowledged_request_to_display_state) ||
m_has_album_screen_shot_taken || m_has_album_recording_saved;
}
void LifecycleManager::OnOperationAndPerformanceModeChanged() {
if (m_operation_mode_changed_notification_enabled) {
m_has_operation_mode_changed = true;
}
if (m_performance_mode_changed_notification_enabled) {
m_has_performance_mode_changed = true;
}
m_operation_mode_changed_system_event.Signal();
this->SignalSystemEventIfNeeded();
}
void LifecycleManager::SignalSystemEventIfNeeded() {
// Check our cached value for the system event.
const bool applet_message_available = m_applet_message_available;
// If it's not current, we need to do an update, either clearing or signaling.
if (applet_message_available != this->ShouldSignalSystemEvent()) {
if (!applet_message_available) {
m_system_event.Signal();
m_applet_message_available = true;
} else {
m_system_event.Clear();
m_applet_message_available = false;
}
}
}
bool LifecycleManager::PopMessage(AppletMessage* out_message) {
const auto message = this->PopMessageInOrderOfPriority();
this->SignalSystemEventIfNeeded();
*out_message = message;
return message != AppletMessage::None;
}
void LifecycleManager::SetFocusHandlingMode(bool suspend) {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
case FocusHandlingMode::SuspendHomeSleep:
if (!suspend) {
// Disallow suspension.
m_focus_handling_mode = FocusHandlingMode::NoSuspend;
}
break;
case FocusHandlingMode::NoSuspend:
if (suspend) {
// Allow suspension temporally.
m_focus_handling_mode = FocusHandlingMode::SuspendHomeSleep;
}
break;
}
}
void LifecycleManager::SetOutOfFocusSuspendingEnabled(bool enabled) {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
if (!enabled) {
// Allow suspension temporally.
m_focus_handling_mode = FocusHandlingMode::SuspendHomeSleep;
}
break;
case FocusHandlingMode::SuspendHomeSleep:
case FocusHandlingMode::NoSuspend:
if (enabled) {
// Allow suspension.
m_focus_handling_mode = FocusHandlingMode::AlwaysSuspend;
}
break;
}
}
void LifecycleManager::RemoveForceResumeIfPossible() {
// If resume is not forced, we have nothing to do.
if (m_suspend_mode != SuspendMode::ForceResume) {
return;
}
// Check activity state.
// If we are already resumed, we can remove the forced state.
switch (m_activity_state) {
case ActivityState::ForegroundVisible:
case ActivityState::ForegroundObscured:
m_suspend_mode = SuspendMode::NoOverride;
return;
default:
break;
}
// Check focus handling mode.
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
case FocusHandlingMode::SuspendHomeSleep:
// If the applet allows suspension, we can remove the forced state.
m_suspend_mode = SuspendMode::NoOverride;
break;
case FocusHandlingMode::NoSuspend:
// If the applet is not an application, we can remove the forced state.
// Only applications can be forced to resume.
if (!m_is_application) {
m_suspend_mode = SuspendMode::NoOverride;
}
}
}
bool LifecycleManager::IsRunnable() const {
// If suspend is forced, return that.
if (m_forced_suspend) {
return false;
}
// Check suspend mode override.
switch (m_suspend_mode) {
case SuspendMode::NoOverride:
// Continue processing.
break;
case SuspendMode::ForceResume:
// The applet is runnable during forced resumption when its exit is requested.
return m_has_requested_exit;
case SuspendMode::ForceSuspend:
// The applet is never runnable during forced suspension.
return false;
}
// Always run if exit is requested.
if (m_has_requested_exit) {
return true;
}
if (m_activity_state == ActivityState::ForegroundVisible) {
// The applet is runnable now.
return true;
}
if (m_activity_state == ActivityState::ForegroundObscured) {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
// The applet is not runnable while running the applet.
return false;
case FocusHandlingMode::SuspendHomeSleep:
// The applet is runnable while running the applet.
return true;
case FocusHandlingMode::NoSuspend:
// The applet is always runnable.
return true;
}
}
// The activity is a suspended one.
// The applet should be suspended unless it has disabled suspension.
return m_focus_handling_mode == FocusHandlingMode::NoSuspend;
}
FocusState LifecycleManager::GetFocusStateWhileForegroundObscured() const {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
// The applet never learns it has lost focus.
return FocusState::InFocus;
case FocusHandlingMode::SuspendHomeSleep:
// The applet learns it has lost focus when launching a child applet.
return FocusState::NotInFocus;
case FocusHandlingMode::NoSuspend:
// The applet always learns it has lost focus.
return FocusState::NotInFocus;
default:
UNREACHABLE();
}
}
FocusState LifecycleManager::GetFocusStateWhileBackground(bool is_obscured) const {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
// The applet never learns it has lost focus.
return FocusState::InFocus;
case FocusHandlingMode::SuspendHomeSleep:
// The applet learns it has lost focus when launching a child applet.
return is_obscured ? FocusState::NotInFocus : FocusState::InFocus;
case FocusHandlingMode::NoSuspend:
// The applet always learns it has lost focus.
return m_is_application ? FocusState::Background : FocusState::NotInFocus;
default:
UNREACHABLE();
}
}
bool LifecycleManager::UpdateRequestedFocusState() {
FocusState new_state{};
if (m_suspend_mode == SuspendMode::NoOverride) {
// With no forced suspend or resume, we take the focus state designated
// by the combination of the activity flag and the focus handling mode.
switch (m_activity_state) {
case ActivityState::ForegroundVisible:
new_state = FocusState::InFocus;
break;
case ActivityState::ForegroundObscured:
new_state = this->GetFocusStateWhileForegroundObscured();
break;
case ActivityState::BackgroundVisible:
new_state = this->GetFocusStateWhileBackground(false);
break;
case ActivityState::BackgroundObscured:
new_state = this->GetFocusStateWhileBackground(true);
break;
default:
UNREACHABLE();
}
} else {
// With forced suspend or resume, the applet is guaranteed to be background.
new_state = this->GetFocusStateWhileBackground(false);
}
if (new_state != m_requested_focus_state) {
// Mark the focus state as ready for update.
m_requested_focus_state = new_state;
// We changed the focus state.
return true;
}
// We didn't change the focus state.
return false;
}
} // namespace Service::AM

View File

@ -0,0 +1,183 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <list>
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/os/event.h"
namespace Core {
class System;
}
namespace Service::AM {
enum class ActivityState : u32 {
ForegroundVisible = 0,
ForegroundObscured = 1,
BackgroundVisible = 2,
BackgroundObscured = 3,
};
enum class FocusHandlingMode : u32 {
AlwaysSuspend = 0,
SuspendHomeSleep = 1,
NoSuspend = 2,
};
enum class SuspendMode : u32 {
NoOverride = 0,
ForceResume = 1,
ForceSuspend = 2,
};
class LifecycleManager {
public:
explicit LifecycleManager(Core::System& system, KernelHelpers::ServiceContext& context,
bool is_application);
~LifecycleManager();
public:
Event& GetSystemEvent();
Event& GetOperationModeChangedSystemEvent();
public:
bool IsApplication() {
return m_is_application;
}
bool GetForcedSuspend() {
return m_forced_suspend;
}
bool GetExitRequested() {
return m_has_requested_exit;
}
ActivityState GetActivityState() {
return m_activity_state;
}
FocusState GetAndClearFocusState() {
m_acknowledged_focus_state = m_requested_focus_state;
return m_acknowledged_focus_state;
}
void SetFocusState(FocusState state) {
if (m_requested_focus_state != state) {
m_has_focus_state_changed = true;
}
m_requested_focus_state = state;
this->SignalSystemEventIfNeeded();
}
void RequestExit() {
m_has_requested_exit = true;
this->SignalSystemEventIfNeeded();
}
void RequestResumeNotification() {
// NOTE: this appears to be a bug in am.
// If an applet makes a concurrent request to receive resume notifications
// while it is being suspended, the first resume notification will be lost.
// This is not the case with other notification types.
if (m_resume_notification_enabled) {
m_has_resume = true;
}
}
void OnOperationAndPerformanceModeChanged();
public:
void SetFocusStateChangedNotificationEnabled(bool enabled) {
m_focus_state_changed_notification_enabled = enabled;
this->SignalSystemEventIfNeeded();
}
void SetOperationModeChangedNotificationEnabled(bool enabled) {
m_operation_mode_changed_notification_enabled = enabled;
this->SignalSystemEventIfNeeded();
}
void SetPerformanceModeChangedNotificationEnabled(bool enabled) {
m_performance_mode_changed_notification_enabled = enabled;
this->SignalSystemEventIfNeeded();
}
void SetResumeNotificationEnabled(bool enabled) {
m_resume_notification_enabled = enabled;
}
void SetActivityState(ActivityState state) {
m_activity_state = state;
}
void SetSuspendMode(SuspendMode mode) {
m_suspend_mode = mode;
}
void SetForcedSuspend(bool enabled) {
m_forced_suspend = enabled;
}
public:
void SetFocusHandlingMode(bool suspend);
void SetOutOfFocusSuspendingEnabled(bool enabled);
void RemoveForceResumeIfPossible();
bool IsRunnable() const;
bool UpdateRequestedFocusState();
void SignalSystemEventIfNeeded();
public:
void PushUnorderedMessage(AppletMessage message);
bool PopMessage(AppletMessage* out_message);
private:
FocusState GetFocusStateWhileForegroundObscured() const;
FocusState GetFocusStateWhileBackground(bool is_obscured) const;
private:
AppletMessage PopMessageInOrderOfPriority();
bool ShouldSignalSystemEvent();
private:
Event m_system_event;
Event m_operation_mode_changed_system_event;
std::list<AppletMessage> m_unordered_messages{};
bool m_is_application{};
bool m_focus_state_changed_notification_enabled{true};
bool m_operation_mode_changed_notification_enabled{true};
bool m_performance_mode_changed_notification_enabled{true};
bool m_resume_notification_enabled{};
bool m_requested_request_to_display_state{};
bool m_acknowledged_request_to_display_state{};
bool m_has_resume{};
bool m_has_focus_state_changed{true};
bool m_has_album_recording_saved{};
bool m_has_album_screen_shot_taken{};
bool m_has_auto_power_down{};
bool m_has_sleep_required_by_low_battery{};
bool m_has_sleep_required_by_high_temperature{};
bool m_has_sd_card_removed{};
bool m_has_performance_mode_changed{};
bool m_has_operation_mode_changed{};
bool m_has_requested_request_to_prepare_sleep{};
bool m_has_acknowledged_request_to_prepare_sleep{};
bool m_has_requested_exit{};
bool m_has_acknowledged_exit{};
bool m_applet_message_available{};
bool m_forced_suspend{};
FocusHandlingMode m_focus_handling_mode{FocusHandlingMode::SuspendHomeSleep};
ActivityState m_activity_state{ActivityState::ForegroundVisible};
SuspendMode m_suspend_mode{SuspendMode::NoOverride};
FocusState m_requested_focus_state{};
FocusState m_acknowledged_focus_state{};
};
} // namespace Service::AM

View File

@ -0,0 +1,130 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/os/process.h"
#include "core/loader/loader.h"
namespace Service::AM {
namespace {
FileSys::StorageId GetStorageIdForFrontendSlot(
std::optional<FileSys::ContentProviderUnionSlot> slot) {
if (!slot.has_value()) {
return FileSys::StorageId::None;
}
switch (*slot) {
case FileSys::ContentProviderUnionSlot::UserNAND:
return FileSys::StorageId::NandUser;
case FileSys::ContentProviderUnionSlot::SysNAND:
return FileSys::StorageId::NandSystem;
case FileSys::ContentProviderUnionSlot::SDMC:
return FileSys::StorageId::SdCard;
case FileSys::ContentProviderUnionSlot::FrontendManual:
return FileSys::StorageId::Host;
default:
return FileSys::StorageId::None;
}
}
std::unique_ptr<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index) {
// Get the appropriate loader to parse this NCA.
out_loader = Loader::GetLoader(system, file, program_id, program_index);
// Ensure we have a loader which can parse the NCA.
if (!out_loader) {
return nullptr;
}
// Try to load the process.
auto process = std::make_unique<Process>(system);
if (process->Initialize(*out_loader, out_load_result)) {
return process;
}
return nullptr;
}
} // Anonymous namespace
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
u8 minimum_key_generation, u8 maximum_key_generation) {
// Attempt to load program NCA.
FileSys::VirtualFile nca_raw{};
// Get the program NCA from storage.
auto& storage = system.GetContentProviderUnion();
nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
// Ensure we retrieved a program NCA.
if (!nca_raw) {
return nullptr;
}
// Ensure we have a suitable version.
if (minimum_key_generation > 0) {
FileSys::NCA nca(nca_raw);
if (nca.GetStatus() == Loader::ResultStatus::Success &&
(nca.GetKeyGeneration() < minimum_key_generation ||
nca.GetKeyGeneration() > maximum_key_generation)) {
LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
nca.GetKeyGeneration());
return nullptr;
}
}
std::unique_ptr<Loader::AppLoader> loader;
Loader::ResultStatus status;
return CreateProcessImpl(loader, status, system, nca_raw, program_id, 0);
}
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index) {
auto process =
CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index);
if (!process) {
return nullptr;
}
FileSys::NACP nacp;
if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
}
auto& storage = system.GetContentProviderUnion();
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process->GetProgramId();
FileSys::PatchManager pm{launch.title_id, system.GetFileSystemController(), storage};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(
storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(
FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
}
} // namespace Service::AM

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h"
namespace Core {
class System;
}
namespace Loader {
class AppLoader;
enum class ResultStatus : u16;
} // namespace Loader
namespace Service {
class Process;
}
namespace Service::AM {
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
u8 minimum_key_generation, u8 maximum_key_generation);
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index);
} // namespace Service::AM

View File

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/am/process_holder.h"
#include "core/hle/service/os/process.h"
namespace Service::AM {
ProcessHolder::ProcessHolder(Applet& applet, Process& process)
: MultiWaitHolder(process.GetHandle()), m_applet(applet), m_process(process) {}
ProcessHolder::~ProcessHolder() = default;
} // namespace Service::AM

View File

@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/os/multi_wait_holder.h"
namespace Service {
class Process;
}
namespace Service::AM {
struct Applet;
class ProcessHolder : public MultiWaitHolder, public Common::IntrusiveListBaseNode<ProcessHolder> {
public:
explicit ProcessHolder(Applet& applet, Process& process);
~ProcessHolder();
Applet& GetApplet() const {
return m_applet;
}
Process& GetProcess() const {
return m_process;
}
private:
Applet& m_applet;
Process& m_process;
};
} // namespace Service::AM

View File

@ -6,12 +6,14 @@
#include "core/hle/service/am/service/all_system_applet_proxies_service.h"
#include "core/hle/service/am/service/library_applet_proxy.h"
#include "core/hle/service/am/service/system_applet_proxy.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_)
: ServiceFramework{system_, "appletAE"} {
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
WindowSystem& window_system)
: ServiceFramework{system_, "appletAE"}, m_window_system{window_system} {
// clang-format off
static const FunctionInfo functions[] = {
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
@ -36,8 +38,8 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
*out_system_applet_proxy =
std::make_shared<ISystemAppletProxy>(system, applet, process_handle.Get());
*out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
system, applet, process_handle.Get(), m_window_system);
R_SUCCEED();
} else {
UNIMPLEMENTED();
@ -52,8 +54,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
*out_library_applet_proxy =
std::make_shared<ILibraryAppletProxy>(system, applet, process_handle.Get());
*out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
system, applet, process_handle.Get(), m_window_system);
R_SUCCEED();
} else {
UNIMPLEMENTED();
@ -73,7 +75,7 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld(
std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId(
ProcessId process_id) {
return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid);
return m_window_system.GetByAppletResourceUserId(process_id.pid);
}
} // namespace Service::AM

View File

@ -14,11 +14,12 @@ struct Applet;
struct AppletAttribute;
class ILibraryAppletProxy;
class ISystemAppletProxy;
class WindowSystem;
class IAllSystemAppletProxiesService final
: public ServiceFramework<IAllSystemAppletProxiesService> {
public:
explicit IAllSystemAppletProxiesService(Core::System& system_);
explicit IAllSystemAppletProxiesService(Core::System& system_, WindowSystem& window_system);
~IAllSystemAppletProxiesService() override;
private:
@ -35,6 +36,8 @@ private:
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
WindowSystem& m_window_system;
};
} // namespace AM

View File

@ -19,7 +19,7 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
{21, nullptr, "TryPopFromAppletBoundChannel"},
{40, nullptr, "GetDisplayLogicalResolution"},
{42, nullptr, "SetDisplayMagnification"},
{50, nullptr, "SetHomeButtonDoubleClickEnabled"},
{50, D<&IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled>, "SetHomeButtonDoubleClickEnabled"},
{51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"},
{52, nullptr, "IsHomeButtonShortPressedBlocked"},
{60, nullptr, "IsVrModeCurtainRequired"},
@ -40,6 +40,13 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
IAppletCommonFunctions::~IAppletCommonFunctions() = default;
Result IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled(
bool home_button_double_click_enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called, home_button_double_click_enabled={}",
home_button_double_click_enabled);
R_SUCCEED();
}
Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled(
Out<bool> out_home_button_double_click_enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called");

View File

@ -16,6 +16,7 @@ public:
~IAppletCommonFunctions() override;
private:
Result SetHomeButtonDoubleClickEnabled(bool home_button_double_click_enabled);
Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
Result SetCpuBoostRequestPriority(s32 priority);
Result GetCurrentApplicationId(Out<u64> out_application_id);

View File

@ -9,12 +9,16 @@
#include "core/hle/service/am/service/application_accessor.h"
#include "core/hle/service/am/service/library_applet_accessor.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/glue/glue_manager.h"
namespace Service::AM {
IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IApplicationAccessor"}, m_applet(std::move(applet)) {
IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system)
: ServiceFramework{system_, "IApplicationAccessor"}, m_window_system(window_system),
m_applet(std::move(applet)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
@ -59,7 +63,15 @@ Result IApplicationAccessor::Start() {
Result IApplicationAccessor::RequestExit() {
LOG_INFO(Service_AM, "called");
m_applet->message_queue.RequestExit();
std::scoped_lock lk{m_applet->lock};
if (m_applet->exit_locked) {
m_applet->lifecycle_manager.RequestExit();
m_applet->UpdateSuspensionStateLocked(true);
} else {
m_applet->process->Terminate();
}
R_SUCCEED();
}
@ -71,13 +83,14 @@ Result IApplicationAccessor::Terminate() {
Result IApplicationAccessor::GetResult() {
LOG_INFO(Service_AM, "called");
R_SUCCEED();
std::scoped_lock lk{m_applet->lock};
R_RETURN(m_applet->terminate_result);
}
Result IApplicationAccessor::GetAppletStateChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_AM, "called");
*out_event = m_applet->caller_applet_broker->GetStateChangedEvent().GetHandle();
*out_event = m_applet->state_changed_event.GetHandle();
R_SUCCEED();
}
@ -96,8 +109,15 @@ Result IApplicationAccessor::PushLaunchParameter(LaunchParameterKind kind,
Result IApplicationAccessor::GetApplicationControlProperty(
OutBuffer<BufferAttr_HipcMapAlias> out_control_property) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_THROW(ResultUnknown);
LOG_INFO(Service_AM, "called");
std::vector<u8> nacp;
R_TRY(system.GetARPManager().GetControlProperty(&nacp, m_applet->program_id));
std::memcpy(out_control_property.data(), nacp.data(),
std::min(out_control_property.size(), nacp.size()));
R_SUCCEED();
}
Result IApplicationAccessor::SetUsers(bool enable,
@ -114,8 +134,9 @@ Result IApplicationAccessor::GetCurrentLibraryApplet(
}
Result IApplicationAccessor::RequestForApplicationToGetForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_THROW(ResultUnknown);
LOG_INFO(Service_AM, "called");
m_window_system.RequestApplicationToGetForeground();
R_SUCCEED();
}
Result IApplicationAccessor::CheckRightsEnvironmentAvailable(Out<bool> out_is_available) {

View File

@ -13,10 +13,12 @@ namespace Service::AM {
struct Applet;
class ILibraryAppletAccessor;
class IStorage;
class WindowSystem;
class IApplicationAccessor final : public ServiceFramework<IApplicationAccessor> {
public:
explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet);
explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system);
~IApplicationAccessor() override;
private:
@ -34,6 +36,7 @@ private:
Result GetNsRightsEnvironmentHandle(Out<u64> out_handle);
Result ReportApplicationExitTimeout();
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -1,17 +1,57 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/am/service/application_accessor.h"
#include "core/hle/service/am/service/application_creator.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/loader/loader.h"
namespace Service::AM {
IApplicationCreator::IApplicationCreator(Core::System& system_)
: ServiceFramework{system_, "IApplicationCreator"} {
namespace {
Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_application_accessor,
Core::System& system, WindowSystem& window_system, u64 program_id) {
FileSys::VirtualFile nca_raw{};
// Get the program NCA from storage.
auto& storage = system.GetContentProviderUnion();
nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
// Ensure we retrieved a program NCA.
R_UNLESS(nca_raw != nullptr, ResultUnknown);
std::vector<u8> control;
std::unique_ptr<Loader::AppLoader> loader;
Loader::ResultStatus result;
auto process =
CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
R_UNLESS(process != nullptr, ResultUnknown);
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
applet->program_id = program_id;
applet->applet_id = AppletId::Application;
applet->type = AppletType::Application;
applet->library_applet_mode = LibraryAppletMode::AllForeground;
window_system.TrackApplet(applet, true);
*out_application_accessor =
std::make_shared<IApplicationAccessor>(system, applet, window_system);
R_SUCCEED();
}
} // namespace
IApplicationCreator::IApplicationCreator(Core::System& system_, WindowSystem& window_system)
: ServiceFramework{system_, "IApplicationCreator"}, m_window_system{window_system} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"},
@ -28,8 +68,9 @@ IApplicationCreator::~IApplicationCreator() = default;
Result IApplicationCreator::CreateApplication(
Out<SharedPointer<IApplicationAccessor>> out_application_accessor, u64 application_id) {
LOG_ERROR(Service_NS, "called, application_id={:x}", application_id);
R_THROW(ResultUnknown);
LOG_INFO(Service_NS, "called, application_id={:016X}", application_id);
R_RETURN(
CreateGuestApplication(out_application_accessor, system, m_window_system, application_id));
}
} // namespace Service::AM

View File

@ -10,14 +10,17 @@ namespace Service::AM {
class IApplicationAccessor;
struct Applet;
class WindowSystem;
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
public:
explicit IApplicationCreator(Core::System& system_);
explicit IApplicationCreator(Core::System& system_, WindowSystem& window_system);
~IApplicationCreator() override;
private:
Result CreateApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id);
WindowSystem& m_window_system;
};
} // namespace Service::AM

View File

@ -123,13 +123,13 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
FileSys::SaveDataAttribute attribute{};
attribute.title_id = m_applet->program_id;
attribute.program_id = m_applet->program_id;
attribute.user_id = user_id.AsU128();
attribute.type = FileSys::SaveDataType::SaveData;
attribute.type = FileSys::SaveDataType::Account;
FileSys::VirtualDir save_data{};
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
&save_data, FileSys::SaveDataSpaceId::User, attribute));
*out_size = 0;
R_SUCCEED();
@ -181,7 +181,8 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
}
Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({}-{})", terminate_result.GetInnerValue(),
LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({:04}-{:04})",
terminate_result.GetInnerValue(),
static_cast<u32>(terminate_result.GetModule()) + 2000,
terminate_result.GetDescription());

View File

@ -17,9 +17,9 @@
namespace Service::AM {
IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process)
: ServiceFramework{system_, "IApplicationProxy"}, m_process{process}, m_applet{
std::move(applet)} {
Kernel::KProcess* process, WindowSystem& window_system)
: ServiceFramework{system_, "IApplicationProxy"},
m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@ -70,7 +70,7 @@ Result IApplicationProxy::GetDebugFunctions(
Result IApplicationProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet);
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
R_SUCCEED();
}
@ -91,7 +91,8 @@ Result IApplicationProxy::GetCommonStateGetter(
Result IApplicationProxy::GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
LOG_DEBUG(Service_AM, "called");
*out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet);
*out_library_applet_creator =
std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
R_SUCCEED();
}

View File

@ -18,11 +18,12 @@ class ILibraryAppletCreator;
class IProcessWindingController;
class ISelfController;
class IWindowController;
class WindowSystem;
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process);
Kernel::KProcess* process, WindowSystem& window_system);
~IApplicationProxy();
private:
@ -40,6 +41,7 @@ private:
Out<SharedPointer<IApplicationFunctions>> out_application_functions);
private:
WindowSystem& m_window_system;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -6,12 +6,14 @@
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/service/application_proxy.h"
#include "core/hle/service/am/service/application_proxy_service.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IApplicationProxyService::IApplicationProxyService(Core::System& system_)
: ServiceFramework{system_, "appletOE"} {
IApplicationProxyService::IApplicationProxyService(Core::System& system_,
WindowSystem& window_system)
: ServiceFramework{system_, "appletOE"}, m_window_system{window_system} {
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
};
@ -26,8 +28,8 @@ Result IApplicationProxyService::OpenApplicationProxy(
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid)) {
*out_application_proxy =
std::make_shared<IApplicationProxy>(system, applet, process_handle.Get());
*out_application_proxy = std::make_shared<IApplicationProxy>(
system, applet, process_handle.Get(), m_window_system);
R_SUCCEED();
} else {
UNIMPLEMENTED();
@ -36,7 +38,7 @@ Result IApplicationProxyService::OpenApplicationProxy(
}
std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) {
return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid);
return m_window_system.GetByAppletResourceUserId(process_id.pid);
}
} // namespace Service::AM

View File

@ -12,10 +12,11 @@ namespace AM {
struct Applet;
class IApplicationProxy;
class WindowSystem;
class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
public:
explicit IApplicationProxyService(Core::System& system_);
explicit IApplicationProxyService(Core::System& system_, WindowSystem& window_system);
~IApplicationProxyService() override;
private:
@ -24,6 +25,8 @@ private:
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
WindowSystem& m_window_system;
};
} // namespace AM

View File

@ -80,15 +80,14 @@ ICommonStateGetter::~ICommonStateGetter() = default;
Result ICommonStateGetter::GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = &m_applet->message_queue.GetMessageReceiveEvent();
*out_event = m_applet->lifecycle_manager.GetSystemEvent().GetHandle();
R_SUCCEED();
}
Result ICommonStateGetter::ReceiveMessage(Out<AppletMessage> out_applet_message) {
LOG_DEBUG(Service_AM, "called");
*out_applet_message = m_applet->message_queue.PopMessage();
if (*out_applet_message == AppletMessage::None) {
if (!m_applet->lifecycle_manager.PopMessage(out_applet_message)) {
LOG_ERROR(Service_AM, "Tried to pop message but none was available!");
R_THROW(AM::ResultNoMessages);
}
@ -100,7 +99,7 @@ Result ICommonStateGetter::GetCurrentFocusState(Out<FocusState> out_focus_state)
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{m_applet->lock};
*out_focus_state = m_applet->focus_state;
*out_focus_state = m_applet->lifecycle_manager.GetAndClearFocusState();
R_SUCCEED();
}
@ -137,7 +136,7 @@ Result ICommonStateGetter::GetWriterLockAccessorEx(
Result ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = &m_applet->message_queue.GetOperationModeChangedEvent();
*out_event = m_applet->lifecycle_manager.GetOperationModeChangedSystemEvent().GetHandle();
R_SUCCEED();
}
@ -260,9 +259,9 @@ Result ICommonStateGetter::GetAppletLaunchedHistory(
}
Result ICommonStateGetter::GetSettingsPlatformRegion(
Out<SysPlatformRegion> out_settings_platform_region) {
Out<Set::PlatformRegion> out_settings_platform_region) {
LOG_INFO(Service_AM, "called");
*out_settings_platform_region = SysPlatformRegion::Global;
*out_settings_platform_region = Set::PlatformRegion::Global;
R_SUCCEED();
}

View File

@ -8,6 +8,7 @@
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/settings_types.h"
namespace Kernel {
class KReadableEvent;
@ -50,7 +51,7 @@ private:
Result GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info);
Result GetAppletLaunchedHistory(Out<s32> out_count,
OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids);
Result GetSettingsPlatformRegion(Out<SysPlatformRegion> out_settings_platform_region);
Result GetSettingsPlatformRegion(Out<Set::PlatformRegion> out_settings_platform_region);
Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
void SetCpuBoostMode(HLERequestContext& ctx);

View File

@ -4,13 +4,16 @@
#include "core/hle/result.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/service/home_menu_functions.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IHomeMenuFunctions"}, m_applet{std::move(applet)},
m_context{system, "IHomeMenuFunctions"}, m_pop_from_general_channel_event{m_context} {
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system)
: ServiceFramework{system_, "IHomeMenuFunctions"}, m_window_system{window_system},
m_applet{std::move(applet)}, m_context{system, "IHomeMenuFunctions"},
m_pop_from_general_channel_event{m_context} {
// clang-format off
static const FunctionInfo functions[] = {
{10, D<&IHomeMenuFunctions::RequestToGetForeground>, "RequestToGetForeground"},
@ -37,17 +40,20 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Ap
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
Result IHomeMenuFunctions::RequestToGetForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_INFO(Service_AM, "called");
m_window_system.RequestHomeMenuToGetForeground();
R_SUCCEED();
}
Result IHomeMenuFunctions::LockForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_INFO(Service_AM, "called");
m_window_system.RequestLockHomeMenuIntoForeground();
R_SUCCEED();
}
Result IHomeMenuFunctions::UnlockForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_INFO(Service_AM, "called");
m_window_system.RequestUnlockHomeMenuIntoForeground();
R_SUCCEED();
}

View File

@ -11,10 +11,12 @@
namespace Service::AM {
struct Applet;
class WindowSystem;
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
public:
explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet);
explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system);
~IHomeMenuFunctions() override;
private:
@ -26,6 +28,7 @@ private:
Result IsForceTerminateApplicationDisabledForDebug(
Out<bool> out_is_force_terminate_application_disabled_for_debug);
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;
KernelHelpers::ServiceContext m_context;
Event m_pop_from_general_channel_event;

View File

@ -47,20 +47,21 @@ ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
Result ILibraryAppletAccessor::GetAppletStateChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = m_broker->GetStateChangedEvent().GetHandle();
*out_event = m_applet->state_changed_event.GetHandle();
R_SUCCEED();
}
Result ILibraryAppletAccessor::IsCompleted(Out<bool> out_is_completed) {
LOG_DEBUG(Service_AM, "called");
*out_is_completed = m_broker->IsCompleted();
std::scoped_lock lk{m_applet->lock};
*out_is_completed = m_applet->is_completed;
R_SUCCEED();
}
Result ILibraryAppletAccessor::GetResult(Out<Result> out_result) {
Result ILibraryAppletAccessor::GetResult() {
LOG_DEBUG(Service_AM, "called");
*out_result = m_applet->terminate_result;
R_SUCCEED();
std::scoped_lock lk{m_applet->lock};
R_RETURN(m_applet->terminate_result);
}
Result ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero() {
@ -77,7 +78,10 @@ Result ILibraryAppletAccessor::Start() {
Result ILibraryAppletAccessor::RequestExit() {
LOG_DEBUG(Service_AM, "called");
m_applet->message_queue.RequestExit();
{
std::scoped_lock lk{m_applet->lock};
m_applet->lifecycle_manager.RequestExit();
}
FrontendRequestExit();
R_SUCCEED();
}

View File

@ -21,7 +21,7 @@ public:
private:
Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result IsCompleted(Out<bool> out_is_completed);
Result GetResult(Out<Result> out_result);
Result GetResult();
Result PresetLibraryAppletGpuTimeSliceZero();
Result Start();
Result RequestExit();

View File

@ -7,9 +7,11 @@
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/am/service/library_applet_accessor.h"
#include "core/hle/service/am/service/library_applet_creator.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/sm/sm.h"
@ -93,6 +95,7 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
}
std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
WindowSystem& window_system,
std::shared_ptr<Applet> caller_applet,
AppletId applet_id,
LibraryAppletMode mode) {
@ -110,53 +113,38 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
Firmware1700 = 17,
};
auto process = std::make_unique<Process>(system);
if (!process->Initialize(program_id, Firmware1400, Firmware1700)) {
auto process = CreateProcess(system, program_id, Firmware1400, Firmware1700);
if (!process) {
// Couldn't initialize the guest process
return {};
}
const auto applet = std::make_shared<Applet>(system, std::move(process));
const auto applet = std::make_shared<Applet>(system, std::move(process), false);
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
applet->library_applet_mode = mode;
// Set focus state
switch (mode) {
case LibraryAppletMode::AllForeground:
case LibraryAppletMode::NoUi:
case LibraryAppletMode::PartialForeground:
case LibraryAppletMode::PartialForegroundIndirectDisplay:
applet->hid_registration.EnableAppletToGetInput(true);
applet->focus_state = FocusState::InFocus;
applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
break;
case LibraryAppletMode::AllForegroundInitiallyHidden:
applet->hid_registration.EnableAppletToGetInput(false);
applet->focus_state = FocusState::NotInFocus;
applet->display_layer_manager.SetWindowVisibility(false);
applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
break;
}
applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden;
auto broker = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = broker;
caller_applet->child_applets.push_back(applet);
system.GetAppletManager().InsertApplet(applet);
window_system.TrackApplet(applet, false);
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
}
std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
WindowSystem& window_system,
std::shared_ptr<Applet> caller_applet,
AppletId applet_id,
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
auto process = std::make_unique<Process>(system);
auto applet = std::make_shared<Applet>(system, std::move(process));
auto applet = std::make_shared<Applet>(system, std::move(process), false);
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
@ -166,14 +154,19 @@ std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& syste
applet->caller_applet = caller_applet;
applet->caller_applet_broker = storage;
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
caller_applet->child_applets.push_back(applet);
window_system.TrackApplet(applet, false);
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
}
} // namespace
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "ILibraryAppletCreator"}, m_applet{std::move(applet)} {
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system)
: ServiceFramework{system_, "ILibraryAppletCreator"},
m_window_system{window_system}, m_applet{std::move(applet)} {
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"},
@ -195,10 +188,12 @@ Result ILibraryAppletCreator::CreateLibraryApplet(
std::shared_ptr<ILibraryAppletAccessor> library_applet;
if (ShouldCreateGuestApplet(applet_id)) {
library_applet = CreateGuestApplet(system, m_applet, applet_id, library_applet_mode);
library_applet =
CreateGuestApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
}
if (!library_applet) {
library_applet = CreateFrontendApplet(system, m_applet, applet_id, library_applet_mode);
library_applet =
CreateFrontendApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
}
if (!library_applet) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);

View File

@ -12,10 +12,12 @@ namespace Service::AM {
struct Applet;
class ILibraryAppletAccessor;
class IStorage;
class WindowSystem;
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet);
explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system);
~ILibraryAppletCreator() override;
private:
@ -29,6 +31,7 @@ private:
Result CreateHandleStorage(Out<SharedPointer<IStorage>> out_storage, s64 size,
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;
};

Some files were not shown because too many files have changed in this diff Show More