mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-12-19 20:11:00 +01:00
am: add new datatypes for per-applet state
This commit is contained in:
parent
7de6b41030
commit
a7e9d7842d
19 changed files with 1496 additions and 1 deletions
|
@ -393,8 +393,13 @@ add_library(core STATIC
|
|||
hle/service/am/am.cpp
|
||||
hle/service/am/am.h
|
||||
hle/service/am/am_results.h
|
||||
hle/service/am/am_types.h
|
||||
hle/service/am/applet.cpp
|
||||
hle/service/am/applet.h
|
||||
hle/service/am/applet_ae.cpp
|
||||
hle/service/am/applet_ae.h
|
||||
hle/service/am/applet_manager.cpp
|
||||
hle/service/am/applet_manager.h
|
||||
hle/service/am/applet_oe.cpp
|
||||
hle/service/am/applet_oe.h
|
||||
hle/service/am/applets/applet_cabinet.cpp
|
||||
|
@ -438,6 +443,8 @@ add_library(core STATIC
|
|||
hle/service/am/display_controller.h
|
||||
hle/service/am/global_state_controller.cpp
|
||||
hle/service/am/global_state_controller.h
|
||||
hle/service/am/hid_registration.cpp
|
||||
hle/service/am/hid_registration.h
|
||||
hle/service/am/home_menu_functions.cpp
|
||||
hle/service/am/home_menu_functions.h
|
||||
hle/service/am/idle.cpp
|
||||
|
@ -450,16 +457,24 @@ add_library(core STATIC
|
|||
hle/service/am/library_applet_proxy.h
|
||||
hle/service/am/library_applet_self_accessor.cpp
|
||||
hle/service/am/library_applet_self_accessor.h
|
||||
hle/service/am/library_applet_storage.cpp
|
||||
hle/service/am/library_applet_storage.h
|
||||
hle/service/am/lock_accessor.cpp
|
||||
hle/service/am/lock_accessor.h
|
||||
hle/service/am/managed_layer_holder.cpp
|
||||
hle/service/am/managed_layer_holder.h
|
||||
hle/service/am/omm.cpp
|
||||
hle/service/am/omm.h
|
||||
hle/service/am/process_winding_controller.cpp
|
||||
hle/service/am/process_winding_controller.h
|
||||
hle/service/am/process.cpp
|
||||
hle/service/am/process.h
|
||||
hle/service/am/self_controller.cpp
|
||||
hle/service/am/self_controller.h
|
||||
hle/service/am/system_applet_proxy.cpp
|
||||
hle/service/am/system_applet_proxy.h
|
||||
hle/service/am/system_buffer_manager.cpp
|
||||
hle/service/am/system_buffer_manager.h
|
||||
hle/service/am/spsm.cpp
|
||||
hle/service/am/spsm.h
|
||||
hle/service/am/storage_accessor.cpp
|
||||
|
@ -531,6 +546,8 @@ add_library(core STATIC
|
|||
hle/service/es/es.h
|
||||
hle/service/eupld/eupld.cpp
|
||||
hle/service/eupld/eupld.h
|
||||
hle/service/event.cpp
|
||||
hle/service/event.h
|
||||
hle/service/fatal/fatal.cpp
|
||||
hle/service/fatal/fatal.h
|
||||
hle/service/fatal/fatal_p.cpp
|
||||
|
|
171
src/core/hle/service/am/am_types.h
Normal file
171
src/core/hle/service/am/am_types.h
Normal file
|
@ -0,0 +1,171 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace Frontend {
|
||||
class FrontendApplet;
|
||||
}
|
||||
|
||||
enum class AppletType {
|
||||
Application,
|
||||
LibraryApplet,
|
||||
SystemApplet,
|
||||
};
|
||||
|
||||
enum class GameplayRecordingState : u32 {
|
||||
Disabled,
|
||||
Enabled,
|
||||
};
|
||||
|
||||
// This is nn::oe::FocusState
|
||||
enum class FocusState : u8 {
|
||||
InFocus = 1,
|
||||
NotInFocus = 2,
|
||||
Background = 3,
|
||||
};
|
||||
|
||||
// This is nn::oe::OperationMode
|
||||
enum class OperationMode : u8 {
|
||||
Handheld = 0,
|
||||
Docked = 1,
|
||||
};
|
||||
|
||||
// This is nn::am::service::SystemButtonType
|
||||
enum class SystemButtonType {
|
||||
None,
|
||||
HomeButtonShortPressing,
|
||||
HomeButtonLongPressing,
|
||||
PowerButtonShortPressing,
|
||||
PowerButtonLongPressing,
|
||||
ShutdownSystem,
|
||||
CaptureButtonShortPressing,
|
||||
CaptureButtonLongPressing,
|
||||
};
|
||||
|
||||
enum class SysPlatformRegion : s32 {
|
||||
Global = 1,
|
||||
Terra = 2,
|
||||
};
|
||||
|
||||
struct AppletProcessLaunchReason {
|
||||
u8 flag;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(AppletProcessLaunchReason) == 0x4,
|
||||
"AppletProcessLaunchReason is an invalid size");
|
||||
|
||||
enum class ScreenshotPermission : u32 {
|
||||
Inherit = 0,
|
||||
Enable = 1,
|
||||
Disable = 2,
|
||||
};
|
||||
|
||||
struct FocusHandlingMode {
|
||||
bool unknown0;
|
||||
bool unknown1;
|
||||
bool unknown2;
|
||||
bool unknown3;
|
||||
};
|
||||
|
||||
enum class IdleTimeDetectionExtension : u32 {
|
||||
Disabled = 0,
|
||||
Extended = 1,
|
||||
ExtendedUnsafe = 2,
|
||||
};
|
||||
|
||||
enum class AppletId : u32 {
|
||||
None = 0x00,
|
||||
Application = 0x01,
|
||||
OverlayDisplay = 0x02,
|
||||
QLaunch = 0x03,
|
||||
Starter = 0x04,
|
||||
Auth = 0x0A,
|
||||
Cabinet = 0x0B,
|
||||
Controller = 0x0C,
|
||||
DataErase = 0x0D,
|
||||
Error = 0x0E,
|
||||
NetConnect = 0x0F,
|
||||
ProfileSelect = 0x10,
|
||||
SoftwareKeyboard = 0x11,
|
||||
MiiEdit = 0x12,
|
||||
Web = 0x13,
|
||||
Shop = 0x14,
|
||||
PhotoViewer = 0x15,
|
||||
Settings = 0x16,
|
||||
OfflineWeb = 0x17,
|
||||
LoginShare = 0x18,
|
||||
WebAuth = 0x19,
|
||||
MyPage = 0x1A,
|
||||
};
|
||||
|
||||
enum class AppletProgramId : u64 {
|
||||
QLaunch = 0x0100000000001000ull,
|
||||
Auth = 0x0100000000001001ull,
|
||||
Cabinet = 0x0100000000001002ull,
|
||||
Controller = 0x0100000000001003ull,
|
||||
DataErase = 0x0100000000001004ull,
|
||||
Error = 0x0100000000001005ull,
|
||||
NetConnect = 0x0100000000001006ull,
|
||||
ProfileSelect = 0x0100000000001007ull,
|
||||
SoftwareKeyboard = 0x0100000000001008ull,
|
||||
MiiEdit = 0x0100000000001009ull,
|
||||
Web = 0x010000000000100Aull,
|
||||
Shop = 0x010000000000100Bull,
|
||||
OverlayDisplay = 0x010000000000100Cull,
|
||||
PhotoViewer = 0x010000000000100Dull,
|
||||
Settings = 0x010000000000100Eull,
|
||||
OfflineWeb = 0x010000000000100Full,
|
||||
LoginShare = 0x0100000000001010ull,
|
||||
WebAuth = 0x0100000000001011ull,
|
||||
Starter = 0x0100000000001012ull,
|
||||
MyPage = 0x0100000000001013ull,
|
||||
MaxProgramId = 0x0100000000001FFFull,
|
||||
};
|
||||
|
||||
enum class LibraryAppletMode : u32 {
|
||||
AllForeground = 0,
|
||||
Background = 1,
|
||||
NoUI = 2,
|
||||
BackgroundIndirectDisplay = 3,
|
||||
AllForegroundInitiallyHidden = 4,
|
||||
};
|
||||
|
||||
enum class CommonArgumentVersion : u32 {
|
||||
Version0,
|
||||
Version1,
|
||||
Version2,
|
||||
Version3,
|
||||
};
|
||||
|
||||
enum class CommonArgumentSize : u32 {
|
||||
Version3 = 0x20,
|
||||
};
|
||||
|
||||
enum class ThemeColor : u32 {
|
||||
BasicWhite = 0,
|
||||
BasicBlack = 3,
|
||||
};
|
||||
|
||||
struct CommonArguments {
|
||||
CommonArgumentVersion arguments_version;
|
||||
CommonArgumentSize size;
|
||||
u32 library_version;
|
||||
ThemeColor theme_color;
|
||||
bool play_startup_sound;
|
||||
u64 system_tick;
|
||||
};
|
||||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
||||
|
||||
using AppletResourceUserId = u64;
|
||||
using ProgramId = u64;
|
||||
|
||||
struct Applet;
|
||||
struct AppletStorageHolder;
|
||||
|
||||
} // namespace Service::AM
|
63
src/core/hle/service/am/applet.cpp
Normal file
63
src/core/hle/service/am/applet.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context)
|
||||
: m_event(context) {}
|
||||
AppletStorageChannel::~AppletStorageChannel() = default;
|
||||
|
||||
void AppletStorageChannel::PushData(std::shared_ptr<IStorage> storage) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
m_data.emplace_back(std::move(storage));
|
||||
m_event.Signal();
|
||||
}
|
||||
|
||||
Result AppletStorageChannel::PopData(std::shared_ptr<IStorage>* out_storage) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
SCOPE_EXIT({
|
||||
if (m_data.empty()) {
|
||||
m_event.Clear();
|
||||
}
|
||||
});
|
||||
|
||||
R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
|
||||
|
||||
*out_storage = std::move(m_data.front());
|
||||
m_data.pop_front();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent* AppletStorageChannel::GetEvent() {
|
||||
return m_event.GetHandle();
|
||||
}
|
||||
|
||||
AppletStorageHolder::AppletStorageHolder(Core::System& system)
|
||||
: context(system, "AppletStorageHolder"), in_data(context), interactive_in_data(context),
|
||||
out_data(context), interactive_out_data(context), state_changed_event(context) {}
|
||||
|
||||
AppletStorageHolder::~AppletStorageHolder() = default;
|
||||
|
||||
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) {
|
||||
|
||||
aruid = process->GetProcessId();
|
||||
program_id = process->GetProgramId();
|
||||
}
|
||||
|
||||
Applet::~Applet() = default;
|
||||
|
||||
} // namespace Service::AM
|
164
src/core/hle/service/am/applet.h
Normal file
164
src/core/hle/service/am/applet.h
Normal file
|
@ -0,0 +1,164 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#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/event.h"
|
||||
#include "core/hle/service/kernel_helpers.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/hid_registration.h"
|
||||
#include "core/hle/service/am/managed_layer_holder.h"
|
||||
#include "core/hle/service/am/process.h"
|
||||
#include "core/hle/service/am/storage.h"
|
||||
#include "core/hle/service/am/system_buffer_manager.h"
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class FbShareBufferManager;
|
||||
class Nvnflinger;
|
||||
} // namespace Service::Nvnflinger
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class AppletStorageChannel {
|
||||
public:
|
||||
explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx);
|
||||
~AppletStorageChannel();
|
||||
|
||||
void PushData(std::shared_ptr<IStorage> storage);
|
||||
Result PopData(std::shared_ptr<IStorage>* out_storage);
|
||||
Kernel::KReadableEvent* GetEvent();
|
||||
|
||||
private:
|
||||
std::mutex m_lock{};
|
||||
std::deque<std::shared_ptr<IStorage>> m_data{};
|
||||
Event m_event;
|
||||
};
|
||||
|
||||
struct AppletStorageHolder {
|
||||
explicit AppletStorageHolder(Core::System& system);
|
||||
~AppletStorageHolder();
|
||||
|
||||
KernelHelpers::ServiceContext context;
|
||||
|
||||
AppletStorageChannel in_data;
|
||||
AppletStorageChannel interactive_in_data;
|
||||
AppletStorageChannel out_data;
|
||||
AppletStorageChannel interactive_out_data;
|
||||
Event state_changed_event;
|
||||
};
|
||||
|
||||
struct Applet {
|
||||
explicit Applet(Core::System& system, std::unique_ptr<Process> process_);
|
||||
~Applet();
|
||||
|
||||
// Lock
|
||||
std::mutex lock{};
|
||||
|
||||
// Event creation helper
|
||||
KernelHelpers::ServiceContext context;
|
||||
|
||||
// Applet message queue
|
||||
AppletMessageQueue message_queue;
|
||||
|
||||
// Process
|
||||
std::unique_ptr<Process> process;
|
||||
|
||||
// Creation state
|
||||
AppletId applet_id{};
|
||||
AppletResourceUserId aruid{};
|
||||
AppletProcessLaunchReason launch_reason{};
|
||||
AppletType type{};
|
||||
ProgramId program_id{};
|
||||
LibraryAppletMode library_applet_mode{};
|
||||
s32 previous_program_index{-1};
|
||||
ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable};
|
||||
|
||||
// hid state
|
||||
HidRegistration hid_registration;
|
||||
|
||||
// vi state
|
||||
SystemBufferManager system_buffer_manager{};
|
||||
ManagedLayerHolder managed_layer_holder{};
|
||||
|
||||
// Applet common functions
|
||||
Result terminate_result{};
|
||||
s32 display_logical_width{};
|
||||
s32 display_logical_height{};
|
||||
Common::Rectangle<f32> display_magnification{0, 0, 1, 1};
|
||||
bool home_button_double_click_enabled{};
|
||||
bool home_button_short_pressed_blocked{};
|
||||
bool home_button_long_pressed_blocked{};
|
||||
bool vr_mode_curtain_required{};
|
||||
bool sleep_required_by_high_temperature{};
|
||||
bool sleep_required_by_low_battery{};
|
||||
s32 cpu_boost_request_priority{-1};
|
||||
bool handling_capture_button_short_pressed_message_enabled_for_applet{};
|
||||
bool handling_capture_button_long_pressed_message_enabled_for_applet{};
|
||||
u32 application_core_usage_mode{};
|
||||
|
||||
// Application functions
|
||||
bool gameplay_recording_supported{};
|
||||
GameplayRecordingState gameplay_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{};
|
||||
APM::CpuBoostMode boost_mode{};
|
||||
bool request_exit_to_library_applet_at_execute_next_program_enabled{};
|
||||
|
||||
// Channels
|
||||
std::deque<std::vector<u8>> user_channel_launch_parameter{};
|
||||
std::deque<std::vector<u8>> preselected_user_launch_parameter{};
|
||||
|
||||
// Caller applet
|
||||
std::weak_ptr<Applet> caller_applet{};
|
||||
std::shared_ptr<AppletStorageHolder> caller_applet_storage{};
|
||||
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{};
|
||||
IdleTimeDetectionExtension idle_time_detection_extension{};
|
||||
bool auto_sleep_disabled{};
|
||||
u64 suspended_ticks{};
|
||||
bool album_image_taken_notification_enabled{};
|
||||
bool record_volume_muted{};
|
||||
|
||||
// Events
|
||||
Event gpu_error_detected_event;
|
||||
Event friend_invitation_storage_channel_event;
|
||||
Event notification_storage_channel_event;
|
||||
Event health_warning_disappeared_system_event;
|
||||
Event acquired_sleep_lock_event;
|
||||
Event pop_from_general_channel_event;
|
||||
Event library_applet_launchable_event;
|
||||
Event accumulated_suspended_tick_changed_event;
|
||||
Event sleep_lock_event;
|
||||
|
||||
// Frontend state
|
||||
std::shared_ptr<Frontend::FrontendApplet> frontend{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
352
src/core/hle/service/am/applet_manager.cpp
Normal file
352
src/core/hle/service/am/applet_manager.cpp
Normal file
|
@ -0,0 +1,352 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||
#include "core/hle/service/am/applets/applet_controller.h"
|
||||
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA;
|
||||
|
||||
struct LaunchParameterAccountPreselectedUser {
|
||||
u32 magic;
|
||||
u32 is_account_selected;
|
||||
Common::UUID current_user;
|
||||
INSERT_PADDING_BYTES(0x70);
|
||||
};
|
||||
static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
|
||||
|
||||
AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system,
|
||||
std::shared_ptr<Applet>& applet) {
|
||||
applet->caller_applet_storage = std::make_shared<AppletStorageHolder>(system);
|
||||
return applet->caller_applet_storage->in_data;
|
||||
}
|
||||
|
||||
void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) {
|
||||
const CommonArguments arguments{
|
||||
.arguments_version = CommonArgumentVersion::Version3,
|
||||
.size = CommonArgumentSize::Version3,
|
||||
.library_version = 1,
|
||||
.theme_color = ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> settings_data{2};
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data)));
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(settings_data)));
|
||||
}
|
||||
|
||||
void PushInShowController(Core::System& system, AppletStorageChannel& channel) {
|
||||
const CommonArguments common_args = {
|
||||
.arguments_version = CommonArgumentVersion::Version3,
|
||||
.size = CommonArgumentSize::Version3,
|
||||
.library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8),
|
||||
.theme_color = ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
Applets::ControllerSupportArgNew user_args = {
|
||||
.header = {.player_count_min = 1,
|
||||
.player_count_max = 4,
|
||||
.enable_take_over_connection = true,
|
||||
.enable_left_justify = false,
|
||||
.enable_permit_joy_dual = true,
|
||||
.enable_single_mode = false,
|
||||
.enable_identification_color = false},
|
||||
.identification_colors = {},
|
||||
.enable_explain_text = false,
|
||||
.explain_text = {},
|
||||
};
|
||||
|
||||
Applets::ControllerSupportArgPrivate private_args = {
|
||||
.arg_private_size = sizeof(Applets::ControllerSupportArgPrivate),
|
||||
.arg_size = sizeof(Applets::ControllerSupportArgNew),
|
||||
.is_home_menu = true,
|
||||
.flag_1 = true,
|
||||
.mode = Applets::ControllerSupportMode::ShowControllerSupport,
|
||||
.caller = Applets::ControllerSupportCaller::
|
||||
Application, // switchbrew: Always zero except with
|
||||
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
|
||||
// which sets this to the input param
|
||||
.style_set = Core::HID::NpadStyleSet::None,
|
||||
.joy_hold_type = 0,
|
||||
};
|
||||
std::vector<u8> common_args_data(sizeof(common_args));
|
||||
std::vector<u8> private_args_data(sizeof(private_args));
|
||||
std::vector<u8> user_args_data(sizeof(user_args));
|
||||
|
||||
std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
|
||||
std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
|
||||
std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
|
||||
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(common_args_data)));
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(private_args_data)));
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(user_args_data)));
|
||||
}
|
||||
|
||||
void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) {
|
||||
const CommonArguments arguments{
|
||||
.arguments_version = CommonArgumentVersion::Version3,
|
||||
.size = CommonArgumentSize::Version3,
|
||||
.library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1),
|
||||
.theme_color = ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
const Applets::StartParamForAmiiboSettings amiibo_settings{
|
||||
.param_1 = 0,
|
||||
.applet_mode = system.GetAppletManager().GetCabinetMode(),
|
||||
.flags = Applets::CabinetFlags::None,
|
||||
.amiibo_settings_1 = 0,
|
||||
.device_handle = 0,
|
||||
.tag_info{},
|
||||
.register_info{},
|
||||
.amiibo_settings_3{},
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> settings_data(sizeof(amiibo_settings));
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data)));
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(settings_data)));
|
||||
}
|
||||
|
||||
void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) {
|
||||
struct MiiEditV3 {
|
||||
Applets::MiiEditAppletInputCommon common;
|
||||
Applets::MiiEditAppletInputV3 input;
|
||||
};
|
||||
static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size.");
|
||||
|
||||
MiiEditV3 mii_arguments{
|
||||
.common =
|
||||
{
|
||||
.version = Applets::MiiEditAppletVersion::Version3,
|
||||
.applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit,
|
||||
},
|
||||
.input{},
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(mii_arguments));
|
||||
std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments));
|
||||
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data)));
|
||||
}
|
||||
|
||||
void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) {
|
||||
const CommonArguments arguments{
|
||||
.arguments_version = CommonArgumentVersion::Version3,
|
||||
.size = CommonArgumentSize::Version3,
|
||||
.library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301),
|
||||
.theme_color = ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
std::vector<char16_t> initial_string(0);
|
||||
|
||||
const Applets::SwkbdConfigCommon swkbd_config{
|
||||
.type = Applets::SwkbdType::Qwerty,
|
||||
.ok_text{},
|
||||
.left_optional_symbol_key{},
|
||||
.right_optional_symbol_key{},
|
||||
.use_prediction = false,
|
||||
.key_disable_flags{},
|
||||
.initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start,
|
||||
.header_text{},
|
||||
.sub_text{},
|
||||
.guide_text{},
|
||||
.max_text_length = 500,
|
||||
.min_text_length = 0,
|
||||
.password_mode = Applets::SwkbdPasswordMode::Disabled,
|
||||
.text_draw_type = Applets::SwkbdTextDrawType::Box,
|
||||
.enable_return_button = true,
|
||||
.use_utf8 = false,
|
||||
.use_blur_background = true,
|
||||
.initial_string_offset{},
|
||||
.initial_string_length = static_cast<u32>(initial_string.size()),
|
||||
.user_dictionary_offset{},
|
||||
.user_dictionary_entries{},
|
||||
.use_text_check = false,
|
||||
};
|
||||
|
||||
Applets::SwkbdConfigNew swkbd_config_new{};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new));
|
||||
std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t));
|
||||
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config));
|
||||
std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new,
|
||||
sizeof(Applets::SwkbdConfigNew));
|
||||
std::memcpy(work_buffer.data(), initial_string.data(),
|
||||
swkbd_config.initial_string_length * sizeof(char16_t));
|
||||
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data)));
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(swkbd_data)));
|
||||
channel.PushData(std::make_shared<IStorage>(system, std::move(work_buffer)));
|
||||
}
|
||||
|
||||
} // 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;
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// Terminate process.
|
||||
applet->process->Terminate();
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
applet->aruid = aruid;
|
||||
applet->program_id = params.program_id;
|
||||
applet->applet_id = params.applet_id;
|
||||
applet->type = params.applet_type;
|
||||
applet->previous_program_index = params.previous_program_index;
|
||||
|
||||
// Push UserChannel data from previous application
|
||||
if (params.launch_type == LaunchType::ApplicationInitiated) {
|
||||
applet->user_channel_launch_parameter.swap(m_system.GetUserChannel());
|
||||
}
|
||||
|
||||
// TODO: Read whether we need a preselected user from NACP?
|
||||
// TODO: This can be done quite easily from loader
|
||||
{
|
||||
LaunchParameterAccountPreselectedUser lp{};
|
||||
|
||||
lp.magic = LaunchParameterAccountPreselectedUserMagic;
|
||||
lp.is_account_selected = 1;
|
||||
|
||||
Account::ProfileManager profile_manager{};
|
||||
const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
|
||||
ASSERT(uuid.has_value() && uuid->IsValid());
|
||||
lp.current_user = *uuid;
|
||||
|
||||
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
|
||||
std::memcpy(buffer.data(), &lp, buffer.size());
|
||||
|
||||
applet->preselected_user_launch_parameter.push_back(std::move(buffer));
|
||||
}
|
||||
|
||||
// Starting from frontend, some applets require input data.
|
||||
switch (applet->applet_id) {
|
||||
case AppletId::Cabinet:
|
||||
PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
case AppletId::MiiEdit:
|
||||
PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
case AppletId::PhotoViewer:
|
||||
PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
case AppletId::SoftwareKeyboard:
|
||||
PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
case AppletId::Controller:
|
||||
PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Applet was started by frontend, so it is foreground.
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
||||
applet->focus_state = 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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
59
src/core/hle/service/am/applet_manager.h
Normal file
59
src/core/hle/service/am/applet_manager.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
#include "core/hle/service/am/applet.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
enum class LaunchType {
|
||||
FrontendInitiated,
|
||||
ApplicationInitiated,
|
||||
};
|
||||
|
||||
struct FrontendAppletParameters {
|
||||
ProgramId program_id{};
|
||||
AppletId applet_id{};
|
||||
AppletType applet_type{};
|
||||
LaunchType launch_type{};
|
||||
s32 program_index{};
|
||||
s32 previous_program_index{-1};
|
||||
};
|
||||
|
||||
class AppletManager {
|
||||
public:
|
||||
explicit AppletManager(Core::System& system);
|
||||
~AppletManager();
|
||||
|
||||
void InsertApplet(std::shared_ptr<Applet> applet);
|
||||
void TerminateAndRemoveApplet(AppletResourceUserId aruid);
|
||||
|
||||
void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid,
|
||||
const FrontendAppletParameters& params);
|
||||
std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const;
|
||||
|
||||
void Reset();
|
||||
|
||||
void RequestExit();
|
||||
void RequestResume();
|
||||
void OperationModeChanged();
|
||||
void FocusStateChanged();
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
mutable std::mutex m_lock{};
|
||||
std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{};
|
||||
|
||||
// AudioController state goes here
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
29
src/core/hle/service/am/hid_registration.cpp
Normal file
29
src/core/hle/service/am/hid_registration.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#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/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");
|
||||
|
||||
if (m_process.IsInitialized()) {
|
||||
m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
HidRegistration::~HidRegistration() {
|
||||
if (m_process.IsInitialized()) {
|
||||
m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId(
|
||||
m_process.GetProcessId());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
30
src/core/hle/service/am/hid_registration.h
Normal file
30
src/core/hle/service/am/hid_registration.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class IHidServer;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class Process;
|
||||
|
||||
class HidRegistration {
|
||||
public:
|
||||
explicit HidRegistration(Core::System& system, Process& process);
|
||||
~HidRegistration();
|
||||
|
||||
private:
|
||||
Process& m_process;
|
||||
std::shared_ptr<Service::HID::IHidServer> m_hid_server;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
140
src/core/hle/service/am/library_applet_storage.cpp
Normal file
140
src/core/hle/service/am/library_applet_storage.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/library_applet_storage.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
|
||||
Result ValidateOffset(s64 offset, size_t size, size_t data_size) {
|
||||
R_UNLESS(offset >= 0, AM::ResultInvalidOffset);
|
||||
|
||||
const size_t begin = offset;
|
||||
const size_t end = begin + size;
|
||||
|
||||
R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
class BufferLibraryAppletStorage final : public LibraryAppletStorage {
|
||||
public:
|
||||
explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {}
|
||||
~BufferLibraryAppletStorage() = default;
|
||||
|
||||
Result Read(s64 offset, void* buffer, size_t size) override {
|
||||
R_TRY(ValidateOffset(offset, size, m_data.size()));
|
||||
|
||||
std::memcpy(buffer, m_data.data() + offset, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result Write(s64 offset, const void* buffer, size_t size) override {
|
||||
R_TRY(ValidateOffset(offset, size, m_data.size()));
|
||||
|
||||
std::memcpy(m_data.data() + offset, buffer, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
s64 GetSize() override {
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
Kernel::KTransferMemory* GetHandle() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<u8> m_data;
|
||||
};
|
||||
|
||||
class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage {
|
||||
public:
|
||||
explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem, bool is_writable,
|
||||
s64 size)
|
||||
: m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) {
|
||||
m_trmem->Open();
|
||||
}
|
||||
|
||||
~TransferMemoryLibraryAppletStorage() {
|
||||
m_trmem->Close();
|
||||
m_trmem = nullptr;
|
||||
}
|
||||
|
||||
Result Read(s64 offset, void* buffer, size_t size) override {
|
||||
R_TRY(ValidateOffset(offset, size, m_size));
|
||||
|
||||
m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result Write(s64 offset, const void* buffer, size_t size) override {
|
||||
R_UNLESS(m_is_writable, ResultUnknown);
|
||||
R_TRY(ValidateOffset(offset, size, m_size));
|
||||
|
||||
m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
s64 GetSize() override {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
Kernel::KTransferMemory* GetHandle() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
Core::Memory::Memory& m_memory;
|
||||
Kernel::KTransferMemory* m_trmem;
|
||||
bool m_is_writable;
|
||||
s64 m_size;
|
||||
};
|
||||
|
||||
class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage {
|
||||
public:
|
||||
explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem, s64 size)
|
||||
: TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {}
|
||||
~HandleLibraryAppletStorage() = default;
|
||||
|
||||
Kernel::KTransferMemory* GetHandle() override {
|
||||
return m_trmem;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
LibraryAppletStorage::~LibraryAppletStorage() = default;
|
||||
|
||||
std::vector<u8> LibraryAppletStorage::GetData() {
|
||||
std::vector<u8> data(this->GetSize());
|
||||
this->Read(0, data.data(), data.size());
|
||||
return data;
|
||||
}
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) {
|
||||
return std::make_shared<BufferLibraryAppletStorage>(std::move(data));
|
||||
}
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem,
|
||||
bool is_writable, s64 size) {
|
||||
return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size);
|
||||
}
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem,
|
||||
s64 size) {
|
||||
return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
36
src/core/hle/service/am/library_applet_storage.h
Normal file
36
src/core/hle/service/am/library_applet_storage.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KTransferMemory;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class LibraryAppletStorage {
|
||||
public:
|
||||
virtual ~LibraryAppletStorage();
|
||||
virtual Result Read(s64 offset, void* buffer, size_t size) = 0;
|
||||
virtual Result Write(s64 offset, const void* buffer, size_t size) = 0;
|
||||
virtual s64 GetSize() = 0;
|
||||
virtual Kernel::KTransferMemory* GetHandle() = 0;
|
||||
|
||||
std::vector<u8> GetData();
|
||||
};
|
||||
|
||||
std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data);
|
||||
std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem,
|
||||
bool is_writable, s64 size);
|
||||
std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
|
||||
Kernel::KTransferMemory* trmem, s64 size);
|
||||
|
||||
} // namespace Service::AM
|
59
src/core/hle/service/am/managed_layer_holder.cpp
Normal file
59
src/core/hle/service/am/managed_layer_holder.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/managed_layer_holder.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ManagedLayerHolder::ManagedLayerHolder() = default;
|
||||
ManagedLayerHolder::~ManagedLayerHolder() {
|
||||
if (!m_nvnflinger) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& layer : m_managed_display_layers) {
|
||||
m_nvnflinger->DestroyLayer(layer);
|
||||
}
|
||||
|
||||
for (const auto& layer : m_managed_display_recording_layers) {
|
||||
m_nvnflinger->DestroyLayer(layer);
|
||||
}
|
||||
|
||||
m_nvnflinger = nullptr;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
|
||||
m_nvnflinger = nvnflinger;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
const auto display_id = m_nvnflinger->OpenDisplay("Default");
|
||||
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
|
||||
|
||||
m_managed_display_layers.emplace(*layer_id);
|
||||
|
||||
*out_layer = *layer_id;
|
||||
}
|
||||
|
||||
void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
|
||||
u64* out_recording_layer) {
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
|
||||
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
|
||||
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
|
||||
// side effects.
|
||||
// TODO: Support multiple layers
|
||||
const auto display_id = m_nvnflinger->OpenDisplay("Default");
|
||||
const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
|
||||
|
||||
m_managed_display_layers.emplace(*layer_id);
|
||||
|
||||
*out_layer = *layer_id;
|
||||
*out_recording_layer = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
32
src/core/hle/service/am/managed_layer_holder.h
Normal file
32
src/core/hle/service/am/managed_layer_holder.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class Nvnflinger;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class ManagedLayerHolder {
|
||||
public:
|
||||
ManagedLayerHolder();
|
||||
~ManagedLayerHolder();
|
||||
|
||||
void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
|
||||
void CreateManagedDisplayLayer(u64* out_layer);
|
||||
void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
|
||||
|
||||
private:
|
||||
Nvnflinger::Nvnflinger* m_nvnflinger{};
|
||||
std::set<u64> m_managed_display_layers{};
|
||||
std::set<u64> m_managed_display_recording_layers{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
138
src/core/hle/service/am/process.cpp
Normal file
138
src/core/hle/service/am/process.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/am/process.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
Process::Process(Core::System& system)
|
||||
: m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
|
||||
m_program_id(), m_process_started() {}
|
||||
|
||||
Process::~Process() {
|
||||
this->Finalize();
|
||||
}
|
||||
|
||||
bool Process::Initialize(u64 program_id) {
|
||||
// First, ensure we are not holding another process.
|
||||
this->Finalize();
|
||||
|
||||
// Get the filesystem controller.
|
||||
auto& fsc = m_system.GetFileSystemController();
|
||||
|
||||
// Attempt to load program NCA.
|
||||
const FileSys::RegisteredCache* bis_system{};
|
||||
FileSys::VirtualFile nca{};
|
||||
|
||||
// Get the program NCA from built-in storage.
|
||||
bis_system = fsc.GetSystemNANDContents();
|
||||
if (bis_system) {
|
||||
nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
|
||||
}
|
||||
|
||||
// Ensure we retrieved a program NCA.
|
||||
if (!nca) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the appropriate loader to parse this NCA.
|
||||
auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0);
|
||||
|
||||
// Ensure we have a loader which can parse the NCA.
|
||||
if (!app_loader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the process.
|
||||
auto* const process = Kernel::KProcess::Create(m_system.Kernel());
|
||||
Kernel::KProcess::Register(m_system.Kernel(), process);
|
||||
|
||||
// On exit, ensure we free the additional reference to the process.
|
||||
SCOPE_EXIT({ process->Close(); });
|
||||
|
||||
// Insert process modules into memory.
|
||||
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
|
||||
|
||||
// Ensure loading was successful.
|
||||
if (load_result != Loader::ResultStatus::Success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: remove this, kernel already tracks this
|
||||
m_system.Kernel().AppendNewProcess(process);
|
||||
|
||||
// Note the load parameters from NPDM.
|
||||
m_main_thread_priority = load_parameters->main_thread_priority;
|
||||
m_main_thread_stack_size = load_parameters->main_thread_stack_size;
|
||||
|
||||
// This process has not started yet.
|
||||
m_process_started = false;
|
||||
|
||||
// Take ownership of the process object.
|
||||
m_process = process;
|
||||
m_process->Open();
|
||||
|
||||
// We succeeded.
|
||||
return true;
|
||||
}
|
||||
|
||||
void Process::Finalize() {
|
||||
// Terminate, if we are currently holding a process.
|
||||
this->Terminate();
|
||||
|
||||
// Close the process.
|
||||
if (m_process) {
|
||||
m_process->Close();
|
||||
|
||||
// TODO: remove this, kernel already tracks this
|
||||
m_system.Kernel().RemoveProcess(m_process);
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
m_process = nullptr;
|
||||
m_main_thread_priority = 0;
|
||||
m_main_thread_stack_size = 0;
|
||||
m_program_id = 0;
|
||||
m_process_started = false;
|
||||
}
|
||||
|
||||
bool Process::Run() {
|
||||
// If we already started the process, don't start again.
|
||||
if (m_process_started) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start.
|
||||
if (m_process) {
|
||||
m_process->Run(m_main_thread_priority, m_main_thread_stack_size);
|
||||
}
|
||||
|
||||
// Mark as started.
|
||||
m_process_started = true;
|
||||
|
||||
// We succeeded.
|
||||
return true;
|
||||
}
|
||||
|
||||
void Process::Terminate() {
|
||||
if (m_process) {
|
||||
m_process->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
u64 Process::GetProcessId() const {
|
||||
if (m_process) {
|
||||
return m_process->GetProcessId();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
50
src/core/hle/service/am/process.h
Normal file
50
src/core/hle/service/am/process.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KProcess;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class Process {
|
||||
public:
|
||||
explicit Process(Core::System& system);
|
||||
~Process();
|
||||
|
||||
bool Initialize(u64 program_id);
|
||||
void Finalize();
|
||||
|
||||
bool Run();
|
||||
void Terminate();
|
||||
|
||||
bool IsInitialized() const {
|
||||
return m_process != nullptr;
|
||||
}
|
||||
u64 GetProcessId() const;
|
||||
u64 GetProgramId() const {
|
||||
return m_program_id;
|
||||
}
|
||||
Kernel::KProcess* GetProcess() const {
|
||||
return m_process;
|
||||
}
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
Kernel::KProcess* m_process{};
|
||||
s32 m_main_thread_priority{};
|
||||
u64 m_main_thread_stack_size{};
|
||||
u64 m_program_id{};
|
||||
bool m_process_started{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
49
src/core/hle/service/am/system_buffer_manager.cpp
Normal file
49
src/core/hle/service/am/system_buffer_manager.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/system_buffer_manager.h"
|
||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
SystemBufferManager::SystemBufferManager() = default;
|
||||
|
||||
SystemBufferManager::~SystemBufferManager() {
|
||||
if (!m_nvnflinger) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up shared layers.
|
||||
if (m_buffer_sharing_enabled) {
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
|
||||
AppletId applet_id) {
|
||||
if (m_nvnflinger) {
|
||||
return m_buffer_sharing_enabled;
|
||||
}
|
||||
|
||||
m_process = process;
|
||||
m_nvnflinger = nvnflinger;
|
||||
m_buffer_sharing_enabled = false;
|
||||
m_system_shared_buffer_id = 0;
|
||||
m_system_shared_layer_id = 0;
|
||||
|
||||
if (applet_id <= AppletId::Application) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
|
||||
const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
|
||||
&m_system_shared_buffer_id, &m_system_shared_layer_id, display_id);
|
||||
|
||||
if (res.IsSuccess()) {
|
||||
m_buffer_sharing_enabled = true;
|
||||
}
|
||||
|
||||
return m_buffer_sharing_enabled;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
44
src/core/hle/service/am/system_buffer_manager.h
Normal file
44
src/core/hle/service/am/system_buffer_manager.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KProcess;
|
||||
}
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class Nvnflinger;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class SystemBufferManager {
|
||||
public:
|
||||
SystemBufferManager();
|
||||
~SystemBufferManager();
|
||||
|
||||
bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id);
|
||||
|
||||
void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
|
||||
u64* out_system_shared_layer_id) {
|
||||
*out_system_shared_buffer_id = m_system_shared_buffer_id;
|
||||
*out_system_shared_layer_id = m_system_shared_layer_id;
|
||||
}
|
||||
|
||||
private:
|
||||
Kernel::KProcess* m_process{};
|
||||
Nvnflinger::Nvnflinger* m_nvnflinger{};
|
||||
bool m_buffer_sharing_enabled{};
|
||||
u64 m_system_shared_buffer_id{};
|
||||
u64 m_system_shared_layer_id{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
31
src/core/hle/service/event.cpp
Normal file
31
src/core/hle/service/event.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
Event::Event(KernelHelpers::ServiceContext& ctx) {
|
||||
m_event = ctx.CreateEvent("Event");
|
||||
}
|
||||
|
||||
Event::~Event() {
|
||||
m_event->GetReadableEvent().Close();
|
||||
m_event->Close();
|
||||
}
|
||||
|
||||
void Event::Signal() {
|
||||
m_event->Signal();
|
||||
}
|
||||
|
||||
void Event::Clear() {
|
||||
m_event->Clear();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent* Event::GetHandle() {
|
||||
return &m_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
} // namespace Service
|
31
src/core/hle/service/event.h
Normal file
31
src/core/hle/service/event.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace KernelHelpers {
|
||||
class ServiceContext;
|
||||
}
|
||||
|
||||
class Event {
|
||||
public:
|
||||
explicit Event(KernelHelpers::ServiceContext& ctx);
|
||||
~Event();
|
||||
|
||||
void Signal();
|
||||
void Clear();
|
||||
|
||||
Kernel::KReadableEvent* GetHandle();
|
||||
|
||||
private:
|
||||
Kernel::KEvent* m_event;
|
||||
};
|
||||
|
||||
} // namespace Service
|
|
@ -128,7 +128,7 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D
|
|||
|
||||
// Ensure we maintain a clean state on failure.
|
||||
ON_RESULT_FAILURE {
|
||||
ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd)));
|
||||
R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd));
|
||||
};
|
||||
|
||||
// Assign the allocated memory to the handle.
|
||||
|
|
Loading…
Reference in a new issue