Browse Source

init test

pull/2953/head
unknown 1 year ago
parent
commit
8df7b91778
  1. 4
      src/core/CMakeLists.txt
  2. 1
      src/core/hle/service/am/am_types.h
  3. 2
      src/core/hle/service/am/applet.cpp
  4. 1
      src/core/hle/service/am/applet.h
  5. 14
      src/core/hle/service/am/applet_manager.cpp
  6. 27
      src/core/hle/service/am/display_layer_manager.cpp
  7. 19
      src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
  8. 4
      src/core/hle/service/am/service/all_system_applet_proxies_service.h
  9. 10
      src/core/hle/service/am/service/applet_common_functions.cpp
  10. 1
      src/core/hle/service/am/service/applet_common_functions.h
  11. 4
      src/core/hle/service/am/service/application_creator.cpp
  12. 37
      src/core/hle/service/am/service/common_state_getter.cpp
  13. 2
      src/core/hle/service/am/service/common_state_getter.h
  14. 122
      src/core/hle/service/am/service/overlay_applet_proxy.cpp
  15. 55
      src/core/hle/service/am/service/overlay_applet_proxy.h
  16. 82
      src/core/hle/service/am/service/overlay_functions.cpp
  17. 33
      src/core/hle/service/am/service/overlay_functions.h
  18. 42
      src/core/hle/service/am/service/system_applet_proxy.cpp
  19. 6
      src/core/hle/service/am/service/system_applet_proxy.h
  20. 25
      src/core/hle/service/am/window_system.cpp
  21. 1
      src/core/hle/service/am/window_system.h
  22. 8
      src/core/hle/service/caps/caps_a.cpp
  23. 2
      src/core/hle/service/caps/caps_a.h
  24. 33
      src/core/hle/service/npns/npns.cpp
  25. 3
      src/core/hle/service/nvnflinger/display.h
  26. 8
      src/core/hle/service/nvnflinger/hardware_composer.cpp
  27. 5
      src/core/hle/service/nvnflinger/surface_flinger.h
  28. 9
      src/core/hle/service/psc/ovln/ovln_types.h
  29. 105
      src/core/hle/service/psc/ovln/receiver.cpp
  30. 31
      src/core/hle/service/psc/ovln/receiver.h
  31. 2
      src/core/hle/service/psc/ovln/receiver_service.cpp
  32. 33
      src/core/hle/service/vi/container.cpp
  33. 2
      src/core/hle/service/vi/container.h
  34. 4
      src/core/hle/service/vi/manager_display_service.cpp
  35. 3
      src/core/hle/service/vi/manager_display_service.h
  36. 61
      src/core/hle/service/vi/shared_buffer_manager.cpp
  37. 18
      src/core/hle/service/vi/system_display_service.cpp
  38. 3
      src/core/hle/service/vi/system_display_service.h

4
src/core/CMakeLists.txt

@ -487,6 +487,10 @@ add_library(core STATIC
hle/service/am/service/library_applet_self_accessor.h
hle/service/am/service/lock_accessor.cpp
hle/service/am/service/lock_accessor.h
hle/service/am/service/overlay_functions.cpp
hle/service/am/service/overlay_functions.h
hle/service/am/service/overlay_applet_proxy.cpp
hle/service/am/service/overlay_applet_proxy.h
hle/service/am/service/process_winding_controller.cpp
hle/service/am/service/process_winding_controller.h
hle/service/am/service/self_controller.cpp

1
src/core/hle/service/am/am_types.h

@ -15,6 +15,7 @@ class FrontendApplet;
enum class AppletType {
Application,
LibraryApplet,
OverlayApplet,
SystemApplet,
};

2
src/core/hle/service/am/applet.cpp

@ -12,7 +12,7 @@ namespace Service::AM {
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),
process(std::move(process_)), hid_registration(system, *process), overlay_event(context),
gpu_error_detected_event(context), friend_invitation_storage_channel_event(context),
notification_storage_channel_event(context), health_warning_disappeared_system_event(context),
unknown_event(context), acquired_sleep_lock_event(context), pop_from_general_channel_event(context),

1
src/core/hle/service/am/applet.h

@ -124,6 +124,7 @@ struct Applet {
bool window_visible{true};
// Events
Event overlay_event;
Event gpu_error_detected_event;
Event friend_invitation_storage_channel_event;
Event notification_storage_channel_event;

14
src/core/hle/service/am/applet_manager.cpp

@ -15,6 +15,7 @@
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/am/window_system.h"
#include "hid_core/hid_types.h"
#include "core/hle/service/am/process_creation.h"
namespace Service::AM {
@ -262,6 +263,19 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
m_cv.wait(lk, [&] { return m_pending_process != nullptr; });
// Launch overlay applet before tracking the application, if available.
if (auto overlay_process = CreateProcess(m_system, static_cast<u64>(AppletProgramId::OverlayDisplay), 0, 0)) {
auto overlay_applet = std::make_shared<Applet>(m_system, std::move(overlay_process), false);
overlay_applet->program_id = static_cast<u64>(AppletProgramId::OverlayDisplay);
overlay_applet->applet_id = AppletId::OverlayDisplay;
overlay_applet->type = AppletType::OverlayApplet;
// Use PartialForeground so blending is enabled and overlay can be composed on top
overlay_applet->library_applet_mode = LibraryAppletMode::PartialForeground;
m_window_system->TrackApplet(overlay_applet, true);
overlay_applet->process->Run();
LOG_INFO(Service_AM, "Overlay applet launched before application");
}
const auto& params = m_pending_parameters;
auto applet = std::make_shared<Applet>(m_system, std::move(m_pending_process),
params.applet_id == AppletId::Application);

27
src/core/hle/service/am/display_layer_manager.cpp

@ -33,6 +33,11 @@ void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* pro
m_buffer_sharing_enabled = false;
m_blending_enabled = mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay;
// For non-application applets, proactively enable shared buffer session so the layer exists
if (m_applet_id != AppletId::Application) {
(void)this->IsSystemBufferSharingEnabled();
}
}
void DisplayLayerManager::Finalize() {
@ -99,13 +104,29 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
// Create the shared layer.
u64 display_id;
R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"}));
R_TRY(m_manager_display_service->CreateSharedLayerSession(m_process, &m_system_shared_buffer_id,
&m_system_shared_layer_id, display_id,
m_blending_enabled));
R_TRY(m_manager_display_service->CreateSharedLayerSession(
m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id,
m_blending_enabled));
LOG_DEBUG(Service_VI,
"DLM: SharedBuffer enabled buffer_id={} layer_id={} blending={} display={}",
m_system_shared_buffer_id, m_system_shared_layer_id, m_blending_enabled, display_id);
// We succeeded, so set up remaining state.
m_buffer_sharing_enabled = true;
// Ensure the overlay layer is visible and above the application layer when applicable
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
if (m_applet_id != AppletId::Application) {
static constexpr s32 kOverlayZ = 100000;
m_manager_display_service->SetLayerZIndex(kOverlayZ, m_system_shared_layer_id);
m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
LOG_INFO(Service_VI,
"DLM: Overlay session ready buffer_id={} layer_id={} z={} visible={} blending={}",
m_system_shared_buffer_id, m_system_shared_layer_id, kOverlayZ, m_visible,
m_blending_enabled);
}
R_SUCCEED();
}

19
src/core/hle/service/am/service/all_system_applet_proxies_service.cpp

@ -7,6 +7,7 @@
#include "core/hle/service/am/service/application_proxy.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/service/overlay_applet_proxy.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
@ -21,7 +22,7 @@ IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& sys
{110, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxyEx"},
{200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"},
{201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"},
{300, nullptr, "OpenOverlayAppletProxy"},
{300, D<&IAllSystemAppletProxiesService::OpenOverlayAppletProxy>, "OpenOverlayAppletProxy"},
{350, D<&IAllSystemAppletProxiesService::OpenSystemApplicationProxy>, "OpenSystemApplicationProxy"},
{400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
{410, nullptr, "GetSystemAppletControllerForDebug"},
@ -67,6 +68,22 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
}
}
Result IAllSystemAppletProxiesService::OpenOverlayAppletProxy(
Out<SharedPointer<IOverlayAppletProxy>> out_overlay_applet_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute) {
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
*out_overlay_applet_proxy = std::make_shared<IOverlayAppletProxy>(
system, applet, process_handle.Get(), m_window_system);
R_SUCCEED();
} else {
UNIMPLEMENTED();
R_THROW(ResultUnknown);
}
}
Result IAllSystemAppletProxiesService::OpenSystemApplicationProxy(
Out<SharedPointer<IApplicationProxy>> out_system_application_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle,

4
src/core/hle/service/am/service/all_system_applet_proxies_service.h

@ -5,6 +5,7 @@
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/am/service/overlay_applet_proxy.h"
namespace Service {
@ -31,6 +32,9 @@ private:
ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
Result OpenOverlayAppletProxy(Out<SharedPointer<IOverlayAppletProxy>> out_overlay_applet_proxy,
ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
Result OpenLibraryAppletProxyOld(
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle);

10
src/core/hle/service/am/service/applet_common_functions.cpp

@ -18,7 +18,7 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
{20, nullptr, "PushToAppletBoundChannel"},
{21, nullptr, "TryPopFromAppletBoundChannel"},
{40, nullptr, "GetDisplayLogicalResolution"},
{42, nullptr, "SetDisplayMagnification"},
{42, D<&IAppletCommonFunctions::SetDisplayMagnification>, "SetDisplayMagnification"},
{50, D<&IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled>, "SetHomeButtonDoubleClickEnabled"},
{51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"},
{52, nullptr, "IsHomeButtonShortPressedBlocked"},
@ -58,6 +58,14 @@ Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled(
R_SUCCEED();
}
Result IAppletCommonFunctions::SetDisplayMagnification(f32 x, f32 y, f32 width, f32 height) {
LOG_WARNING(Service_AM, "(STUBBED) called, x={}, y={}, width={}, height={}", x, y, width,
height);
std::scoped_lock lk{applet->lock};
applet->display_magnification = Common::Rectangle<f32>{x, y, x + width, y + height};
R_SUCCEED();
}
Result IAppletCommonFunctions::SetCpuBoostRequestPriority(s32 priority) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};

1
src/core/hle/service/am/service/applet_common_functions.h

@ -18,6 +18,7 @@ public:
private:
Result SetHomeButtonDoubleClickEnabled(bool home_button_double_click_enabled);
Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
Result SetDisplayMagnification(f32 x, f32 y, f32 width, f32 height);
Result SetCpuBoostRequestPriority(s32 priority);
Result GetCurrentApplicationId(Out<u64> out_application_id);
Result Unknown350(Out<u16> out_unknown);

4
src/core/hle/service/am/service/application_creator.cpp

@ -31,6 +31,10 @@ Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_applicati
std::vector<u8> control;
std::unique_ptr<Loader::AppLoader> loader;
Loader::ResultStatus result;
// Launch overlay first if available.
// TryLaunchOverlayApplet(system, window_system);
auto process =
CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
R_UNLESS(process != nullptr, ResultUnknown);

37
src/core/hle/service/am/service/common_state_getter.cpp

@ -6,6 +6,7 @@
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/common_state_getter.h"
#include "core/hle/service/am/service/lock_accessor.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/apm/apm_interface.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/pm/pm.h"
@ -34,7 +35,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
{12, nullptr, "ReleaseSleepLockTransiently"},
{13, D<&ICommonStateGetter::GetAcquiredSleepLockEvent>, "GetAcquiredSleepLockEvent"},
{14, nullptr, "GetWakeupCount"},
{20, nullptr, "PushToGeneralChannel"},
{20, D<&ICommonStateGetter::PushToGeneralChannel>, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, D<&ICommonStateGetter::GetReaderLockAccessorEx>, "GetReaderLockAccessorEx"},
{32, D<&ICommonStateGetter::GetWriterLockAccessorEx>, "GetWriterLockAccessorEx"},
@ -245,7 +246,28 @@ Result ICommonStateGetter::GetBuiltInDisplayType(Out<s32> out_display_type) {
}
Result ICommonStateGetter::PerformSystemButtonPressingIfInFocus(SystemButtonType type) {
LOG_WARNING(Service_AM, "(STUBBED) called, type={}", type);
LOG_DEBUG(Service_AM, "called, type={}", type);
std::scoped_lock lk{m_applet->lock};
switch (type) {
case SystemButtonType::HomeButtonShortPressing:
if (!m_applet->home_button_short_pressed_blocked) {
m_applet->lifecycle_manager.PushUnorderedMessage(
AppletMessage::DetectShortPressingHomeButton);
}
break;
case SystemButtonType::HomeButtonLongPressing:
if (!m_applet->home_button_long_pressed_blocked) {
m_applet->lifecycle_manager.PushUnorderedMessage(
AppletMessage::DetectLongPressingHomeButton);
}
break;
default:
// Other buttons ignored for now
break;
}
R_SUCCEED();
}
@ -287,4 +309,15 @@ Result ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnab
R_SUCCEED();
}
Result ICommonStateGetter::PushToGeneralChannel(SharedPointer<IStorage> storage) {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{m_applet->lock};
// Push to a general-purpose channel and notify listeners via event
m_applet->user_channel_launch_parameter.push_back(storage->GetData());
m_applet->pop_from_general_channel_event.Signal();
R_SUCCEED();
}
} // namespace Service::AM

2
src/core/hle/service/am/service/common_state_getter.h

@ -18,6 +18,7 @@ namespace Service::AM {
struct Applet;
class ILockAccessor;
class IStorage; // forward declaration for storage handle type
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
@ -55,6 +56,7 @@ private:
OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids);
Result GetSettingsPlatformRegion(Out<Set::PlatformRegion> out_settings_platform_region);
Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
Result PushToGeneralChannel(SharedPointer<IStorage> storage); // cmd 20
void SetCpuBoostMode(HLERequestContext& ctx);

122
src/core/hle/service/am/service/overlay_applet_proxy.cpp

@ -0,0 +1,122 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/am/service/common_state_getter.h"
#include "core/hle/service/am/service/display_controller.h"
#include "core/hle/service/am/service/global_state_controller.h"
#include "core/hle/service/am/service/audio_controller.h"
#include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/am/service/overlay_applet_proxy.h"
#include "core/hle/service/am/service/library_applet_creator.h"
#include "core/hle/service/am/service/process_winding_controller.h"
#include "core/hle/service/am/service/self_controller.h"
#include "core/hle/service/am/service/window_controller.h"
#include "core/hle/service/am/service/debug_functions.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IOverlayAppletProxy::IOverlayAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, WindowSystem& window_system)
: ServiceFramework{system_, "IOverlayAppletProxy"},
m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IOverlayAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
{1, D<&IOverlayAppletProxy::GetSelfController>, "GetSelfController"},
{2, D<&IOverlayAppletProxy::GetWindowController>, "GetWindowController"},
{3, D<&IOverlayAppletProxy::GetAudioController>, "GetAudioController"},
{4, D<&IOverlayAppletProxy::GetDisplayController>, "GetDisplayController"},
{10, D<&IOverlayAppletProxy::GetProcessWindingController>, "GetProcessWindingController"},
{11, D<&IOverlayAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
{20, D<&IOverlayAppletProxy::GetOverlayFunctions>, "GetOverlayFunctions"},
{21, D<&IOverlayAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"},
{23, D<&IOverlayAppletProxy::GetGlobalStateController>, "GetGlobalStateController"},
{1000, D<&IOverlayAppletProxy::GetDebugFunctions>, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
IOverlayAppletProxy::~IOverlayAppletProxy() = default;
Result IOverlayAppletProxy::GetCommonStateGetter(
Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
LOG_DEBUG(Service_AM, "called");
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
LOG_DEBUG(Service_AM, "called");
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetAudioController(
Out<SharedPointer<IAudioController>> out_audio_controller) {
LOG_DEBUG(Service_AM, "called");
*out_audio_controller = std::make_shared<IAudioController>(system);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetDisplayController(
Out<SharedPointer<IDisplayController>> out_display_controller) {
LOG_DEBUG(Service_AM, "called");
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
LOG_DEBUG(Service_AM, "called");
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
LOG_DEBUG(Service_AM, "called");
*out_library_applet_creator =
std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetOverlayFunctions(
Out<SharedPointer<IOverlayFunctions>> out_overlay_functions) {
LOG_DEBUG(Service_AM, "called");
*out_overlay_functions = std::make_shared<IOverlayFunctions>(system, m_applet);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetAppletCommonFunctions(
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions) {
LOG_DEBUG(Service_AM, "called");
*out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller) {
LOG_DEBUG(Service_AM, "called");
*out_global_state_controller = std::make_shared<IGlobalStateController>(system);
R_SUCCEED();
}
Result IOverlayAppletProxy::GetDebugFunctions(
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
LOG_DEBUG(Service_AM, "called");
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
R_SUCCEED();
}
} // namespace Service::AM

55
src/core/hle/service/am/service/overlay_applet_proxy.h

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/am/service/overlay_functions.h"
namespace Service::AM {
struct Applet;
class IAppletCommonFunctions;
class IAudioController;
class ICommonStateGetter;
class IDebugFunctions;
class IDisplayController;
class IHomeMenuFunctions;
class IGlobalStateController;
class ILibraryAppletCreator;
class ILibraryAppletSelfAccessor;
class IProcessWindingController;
class ISelfController;
class IWindowController;
class WindowSystem;
class IOverlayAppletProxy final : public ServiceFramework<IOverlayAppletProxy> {
public:
explicit IOverlayAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, WindowSystem& window_system);
~IOverlayAppletProxy();
private:
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
Result GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
Result GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
Result GetOverlayFunctions(Out<SharedPointer<IOverlayFunctions>> out_overlay_functions);
Result GetAppletCommonFunctions(
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions);
Result GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
WindowSystem& m_window_system;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

82
src/core/hle/service/am/service/overlay_functions.cpp

@ -0,0 +1,82 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/overlay_functions.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IOverlayFunctions::IOverlayFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IOverlayFunctions"}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IOverlayFunctions::BeginToWatchShortHomeButtonMessage>, "BeginToWatchShortHomeButtonMessage"},
{1, D<&IOverlayFunctions::EndToWatchShortHomeButtonMessage>, "EndToWatchShortHomeButtonMessage"},
{2, D<&IOverlayFunctions::GetApplicationIdForLogo>, "GetApplicationIdForLogo"},
{3, nullptr, "SetGpuTimeSliceBoost"},
{4, D<&IOverlayFunctions::SetAutoSleepTimeAndDimmingTimeEnabled>, "SetAutoSleepTimeAndDimmingTimeEnabled"},
{5, nullptr, "TerminateApplicationAndSetReason"},
{6, nullptr, "SetScreenShotPermissionGlobally"},
{10, nullptr, "StartShutdownSequenceForOverlay"},
{11, nullptr, "StartRebootSequenceForOverlay"},
{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
{21, nullptr, "SetHandlingTouchScreenInputEnabled"},
{30, nullptr, "SetHealthWarningShowingState"},
{31, nullptr, "IsHealthWarningRequired"},
{40, nullptr, "GetApplicationNintendoLogo"},
{41, nullptr, "GetApplicationStartupMovie"},
{50, nullptr, "SetGpuTimeSliceBoostForApplication"},
{60, nullptr, "Unknown60"},
{90, nullptr, "SetRequiresGpuResourceUse"},
{101, nullptr, "BeginToObserveHidInputForDevelop"},
};
// clang-format on
RegisterHandlers(functions);
}
IOverlayFunctions::~IOverlayFunctions() = default;
Result IOverlayFunctions::BeginToWatchShortHomeButtonMessage() {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{m_applet->lock};
m_applet->home_button_short_pressed_blocked = false;
R_SUCCEED();
}
Result IOverlayFunctions::EndToWatchShortHomeButtonMessage() {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{m_applet->lock};
m_applet->home_button_short_pressed_blocked = true;
R_SUCCEED();
}
Result IOverlayFunctions::GetApplicationIdForLogo(Out<u64> out_application_id) {
LOG_DEBUG(Service_AM, "called");
// Prefer explicit application_id if available, else fall back to program_id
std::scoped_lock lk{m_applet->lock};
u64 id = m_applet->screen_shot_identity.application_id;
if (id == 0) {
id = m_applet->program_id;
}
*out_application_id = id;
R_SUCCEED();
}
Result IOverlayFunctions::SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};
m_applet->auto_sleep_disabled = !enabled;
R_SUCCEED();
}
Result IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled(bool enabled) {
LOG_DEBUG(Service_AM, "called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};
m_applet->home_button_short_pressed_blocked = !enabled;
R_SUCCEED();
}
} // namespace Service::AM

33
src/core/hle/service/am/service/overlay_functions.h

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IOverlayFunctions final : public ServiceFramework<IOverlayFunctions> {
public:
explicit IOverlayFunctions(Core::System& system_, std::shared_ptr<Applet> applet);
~IOverlayFunctions() override;
private:
// 0
Result BeginToWatchShortHomeButtonMessage();
// 1
Result EndToWatchShortHomeButtonMessage();
// 2
Result GetApplicationIdForLogo(Out<u64> out_application_id);
// 4
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
// 20
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
private:
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

42
src/core/hle/service/am/service/system_applet_proxy.cpp

@ -44,52 +44,52 @@ ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Ap
ISystemAppletProxy::~ISystemAppletProxy() = default;
Result ISystemAppletProxy::GetAudioController(
Out<SharedPointer<IAudioController>> out_audio_controller) {
Result ISystemAppletProxy::GetCommonStateGetter(
Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
LOG_DEBUG(Service_AM, "called");
*out_audio_controller = std::make_shared<IAudioController>(system);
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetDisplayController(
Out<SharedPointer<IDisplayController>> out_display_controller) {
Result ISystemAppletProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
LOG_DEBUG(Service_AM, "called");
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
R_SUCCEED();
}
Result ISystemAppletProxy::GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
Result ISystemAppletProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
R_SUCCEED();
}
Result ISystemAppletProxy::GetDebugFunctions(
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
Result ISystemAppletProxy::GetAudioController(
Out<SharedPointer<IAudioController>> out_audio_controller) {
LOG_DEBUG(Service_AM, "called");
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
*out_audio_controller = std::make_shared<IAudioController>(system);
R_SUCCEED();
}
Result ISystemAppletProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
Result ISystemAppletProxy::GetDisplayController(
Out<SharedPointer<IDisplayController>> out_display_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
Result ISystemAppletProxy::GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
LOG_DEBUG(Service_AM, "called");
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetCommonStateGetter(
Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
Result ISystemAppletProxy::GetDebugFunctions(
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
LOG_DEBUG(Service_AM, "called");
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
R_SUCCEED();
}

6
src/core/hle/service/am/service/system_applet_proxy.h

@ -30,14 +30,14 @@ public:
~ISystemAppletProxy();
private:
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
Result GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
Result GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
Result GetApplicationCreator(Out<SharedPointer<IApplicationCreator>> out_application_creator);

25
src/core/hle/service/am/window_system.cpp

@ -35,6 +35,7 @@ void WindowSystem::Update() {
// Recursively update each applet root.
this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu);
this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application);
this->UpdateAppletStateLocked(m_overlay_display, true); // overlay is always updated
}
void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_application) {
@ -43,6 +44,9 @@ void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_applicati
if (applet->applet_id == AppletId::QLaunch) {
ASSERT(m_home_menu == nullptr);
m_home_menu = applet.get();
} else if (applet->applet_id == AppletId::OverlayDisplay) {
// Track overlay display applet
m_overlay_display = applet.get();
} else if (is_application) {
ASSERT(m_application == nullptr);
m_application = applet.get();
@ -139,6 +143,19 @@ void WindowSystem::OnExitRequested() {
void WindowSystem::OnHomeButtonPressed(ButtonPressDuration type) {
std::scoped_lock lk{m_lock};
// Prefer sending to overlay display if present.
if (m_overlay_display) {
std::scoped_lock lk3{m_overlay_display->lock};
if (type == ButtonPressDuration::ShortPressing) {
m_overlay_display->lifecycle_manager.PushUnorderedMessage(
AppletMessage::DetectShortPressingHomeButton);
} else if (type == ButtonPressDuration::LongPressing) {
m_overlay_display->lifecycle_manager.PushUnorderedMessage(
AppletMessage::DetectLongPressingHomeButton);
}
return;
}
// If we don't have a home menu, nothing to do.
if (!m_home_menu) {
return;
@ -151,6 +168,9 @@ void WindowSystem::OnHomeButtonPressed(ButtonPressDuration type) {
if (type == ButtonPressDuration::ShortPressing) {
m_home_menu->lifecycle_manager.PushUnorderedMessage(
AppletMessage::DetectShortPressingHomeButton);
} else if (type == ButtonPressDuration::LongPressing) {
m_home_menu->lifecycle_manager.PushUnorderedMessage(
AppletMessage::DetectLongPressingHomeButton);
}
}
@ -208,6 +228,11 @@ void WindowSystem::PruneTerminatedAppletsLocked() {
}
}
// If this was the overlay display, clear the pointer.
if (applet.get() == m_overlay_display) {
m_overlay_display = nullptr;
}
// Finalize applet.
applet->OnProcessTerminatedLocked();

1
src/core/hle/service/am/window_system.h

@ -75,6 +75,7 @@ private:
// Foreground roots.
Applet* m_home_menu{};
Applet* m_application{};
Applet* m_overlay_display{}; // overlay display applet (DevOverlay)
// Applet map by aruid.
std::map<u64, std::shared_ptr<Applet>> m_applets{};

8
src/core/hle/service/caps/caps_a.cpp

@ -53,6 +53,7 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
{8021, nullptr, "GetAlbumEntryFromApplicationAlbumEntryAruid"},
{10011, nullptr, "SetInternalErrorConversionEnabled"},
{50000, nullptr, "LoadMakerNoteInfoForDebug"},
{50011, C<&IAlbumAccessorService::GetAlbumAccessResultForDebug>, "GetAlbumAccessResultForDebug"},
{60002, nullptr, "OpenAccessorSession"},
};
// clang-format on
@ -197,4 +198,11 @@ Result IAlbumAccessorService::TranslateResult(Result in_result) {
return in_result;
}
Result IAlbumAccessorService::GetAlbumAccessResultForDebug(Out<Result> out_result) {
LOG_WARNING(Service_Capture, "(STUBBED) called");
*out_result = ResultSuccess;
R_SUCCEED();
}
} // namespace Service::Capture

2
src/core/hle/service/caps/caps_a.h

@ -52,6 +52,8 @@ private:
Result TranslateResult(Result in_result);
Result GetAlbumAccessResultForDebug(Out<Result> out_result);
std::shared_ptr<AlbumManager> manager = nullptr;
};

33
src/core/hle/service/npns/npns.cpp

@ -150,16 +150,17 @@ private:
class INpnsUser final : public ServiceFramework<INpnsUser> {
public:
explicit INpnsUser(Core::System& system_) : ServiceFramework{system_, "npns:u"} {
explicit INpnsUser(Core::System& system_)
: ServiceFramework{system_, "npns:u"}, service_context{system, "npns:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "ListenAll"},
{2, nullptr, "ListenTo"},
{3, nullptr, "Receive"},
{4, nullptr, "ReceiveRaw"},
{5, nullptr, "GetReceiveEvent"},
{5, C<&INpnsUser::GetReceiveEvent>, "GetReceiveEvent"},
{7, nullptr, "GetStateChangeEvent"},
{8, nullptr, "ListenToByName"}, // 18.0.0+
{8, C<&INpnsUser::ListenToByName>, "ListenToByName"}, // 18.0.0+
{21, nullptr, "CreateToken"},
{23, nullptr, "DestroyToken"},
{25, nullptr, "QueryIsTokenValid"},
@ -178,7 +179,33 @@ public:
// clang-format on
RegisterHandlers(functions);
get_receive_event = service_context.CreateEvent("npns:u:GetReceiveEvent");
}
~INpnsUser() override {
service_context.CloseEvent(get_receive_event);
}
private:
Result ListenToByName(InBuffer<BufferAttr_HipcMapAlias> name_buffer) {
const std::string name(reinterpret_cast<const char*>(name_buffer.data()), name_buffer.size());
LOG_DEBUG(Service_NPNS, "called, name={}", name);
// Store the name for future use if needed
// For now, just acknowledge the registration
R_SUCCEED();
}
Result GetReceiveEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_NPNS, "called");
*out_event = &get_receive_event->GetReadableEvent();
R_SUCCEED();
}
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* get_receive_event;
};
void LoopProcess(Core::System& system) {

3
src/core/hle/service/nvnflinger/display.h

@ -12,7 +12,7 @@ struct Layer {
explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_,
s32 consumer_id_)
: buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_),
blending(LayerBlending::None), visible(true) {}
blending(LayerBlending::None), visible(true), z_index(0) {}
~Layer() {
buffer_item_consumer->Abandon();
}
@ -21,6 +21,7 @@ struct Layer {
s32 consumer_id;
LayerBlending blending;
bool visible;
s32 z_index;
};
struct LayerStack {

8
src/core/hle/service/nvnflinger/hardware_composer.cpp

@ -95,7 +95,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
const auto& item = buffer.item;
const auto& igbp_buffer = *item.graphic_buffer;
// TODO: get proper Z-index from layer
// Proper Z-index from the layer metadata
if (layer->visible) {
composition_stack.emplace_back(HwcLayer{
.buffer_handle = igbp_buffer.BufferId(),
@ -104,7 +104,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
.width = igbp_buffer.Width(),
.height = igbp_buffer.Height(),
.stride = igbp_buffer.Stride(),
.z_index = 0,
.z_index = layer->z_index,
.blending = layer->blending,
.transform = static_cast<android::BufferTransformFlags>(item.transform),
.crop_rect = item.crop,
@ -128,9 +128,9 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
// If any new buffers were acquired, we can present.
if (has_acquired_buffer && !composition_stack.empty()) {
// Sort by Z-index.
// Sort back-to-front: lower z first, higher z last so top-most draws last (on top).
std::stable_sort(composition_stack.begin(), composition_stack.end(),
[&](auto& l, auto& r) { return l.z_index < r.z_index; });
[&](const HwcLayer& l, const HwcLayer& r) { return l.z_index > r.z_index; });
// Composite.
nvdisp.Composite(composition_stack);

5
src/core/hle/service/nvnflinger/surface_flinger.h

@ -45,9 +45,10 @@ public:
void SetLayerVisibility(s32 consumer_binder_id, bool visible);
void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending);
std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id); // expose for Container
private:
Display* FindDisplay(u64 display_id);
std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
public:
// TODO: these don't belong here
@ -66,4 +67,4 @@ private:
HardwareComposer m_composer;
};
} // namespace Service::Nvnflinger
} // namespace Service::Nvnflinger

9
src/core/hle/service/psc/ovln/ovln_types.h

@ -18,4 +18,13 @@ union MessageFlags {
};
static_assert(sizeof(MessageFlags) == 0x8, "MessageFlags has incorrect size");
struct SourceName {
char name[0x16];
const char* GetString() const {
return name;
}
};
;
} // namespace Service::PSC

105
src/core/hle/service/psc/ovln/receiver.cpp

@ -2,23 +2,114 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/psc/ovln/receiver.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::PSC {
IReceiver::IReceiver(Core::System& system_) : ServiceFramework{system_, "IReceiver"} {
IReceiver::IReceiver(Core::System& system_)
: ServiceFramework{system_, "IReceiver"}, service_context{system_, "IReceiver"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "AddSource"},
{1, nullptr, "RemoveSource"},
{2, nullptr, "GetReceiveEventHandle"},
{3, nullptr, "Receive"},
{4, nullptr, "ReceiveWithTick"},
{0, D<&IReceiver::AddSource>, "AddSource"},
{1, D<&IReceiver::RemoveSource>, "RemoveSource"},
{2, D<&IReceiver::GetReceiveEventHandle>, "GetReceiveEventHandle"},
{3, D<&IReceiver::Receive>, "Receive"},
{4, D<&IReceiver::ReceiveWithTick>, "ReceiveWithTick"},
};
// clang-format on
RegisterHandlers(functions);
receive_event = service_context.CreateEvent("IReceiver::ReceiveEvent");
}
IReceiver::~IReceiver() {
service_context.CloseEvent(receive_event);
}
Result IReceiver::AddSource(SourceName source_name) {
const std::string name = source_name.GetString();
LOG_INFO(Service_PSC, "called: source_name={}", name);
// Add source if it doesn't already exist
if (message_sources.find(name) == message_sources.end()) {
message_sources[name] = {};
}
R_SUCCEED();
}
Result IReceiver::RemoveSource(SourceName source_name) {
const std::string name = source_name.GetString();
LOG_INFO(Service_PSC, "called: source_name={}", name);
// Remove source if it exists
message_sources.erase(name);
R_SUCCEED();
}
IReceiver::~IReceiver() = default;
Result IReceiver::GetReceiveEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_PSC, "called");
*out_event = &receive_event->GetReadableEvent();
R_SUCCEED();
}
Result IReceiver::Receive(Out<OverlayNotification> out_notification, Out<MessageFlags> out_flags) {
u64 tick;
return ReceiveWithTick(out_notification, out_flags, Out<u64>(&tick));
}
Result IReceiver::ReceiveWithTick(Out<OverlayNotification> out_notification,
Out<MessageFlags> out_flags, Out<u64> out_tick) {
LOG_DEBUG(Service_PSC, "called");
// Find the message with the lowest ID across all sources
const std::string* target_source = nullptr;
size_t target_index = 0;
for (const auto& [source_name, messages] : message_sources) {
if (!messages.empty()) {
if (target_source == nullptr) {
target_source = &source_name;
target_index = 0;
}
// Note: In the real implementation, we would track message IDs
// For now, just use FIFO order
}
}
if (target_source != nullptr) {
auto& messages = message_sources[*target_source];
*out_notification = messages[target_index].first;
*out_flags = messages[target_index].second;
*out_tick = 0; // TODO: Implement tick tracking
// Remove the message
messages.erase(messages.begin() + target_index);
// Clear event if no more messages
bool has_messages = false;
for (const auto& [_, msgs] : message_sources) {
if (!msgs.empty()) {
has_messages = true;
break;
}
}
if (!has_messages) {
receive_event->Clear();
}
R_SUCCEED();
}
// No messages available
*out_notification = {};
*out_flags = {};
*out_tick = 0;
LOG_WARNING(Service_PSC, "No messages available");
R_THROW(ResultUnknown); // TODO: Use proper OvlnResult::NoMessages when available
}
} // namespace Service::PSC

31
src/core/hle/service/psc/ovln/receiver.h

@ -1,9 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <map>
#include <memory>
#include <string>
#include "core/hle/result.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
#include "core/hle/service/psc/ovln/ovln_types.h"
namespace Kernel {
class KReadableEvent;
}
namespace Service::PSC {
@ -11,6 +25,23 @@ class IReceiver final : public ServiceFramework<IReceiver> {
public:
explicit IReceiver(Core::System& system_);
~IReceiver() override;
IReceiver(const IReceiver&) = delete;
IReceiver& operator=(const IReceiver&) = delete;
private:
Result AddSource(SourceName source_name);
Result RemoveSource(SourceName source_name);
Result GetReceiveEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result Receive(Out<OverlayNotification> out_notification, Out<MessageFlags> out_flags);
Result ReceiveWithTick(Out<OverlayNotification> out_notification, Out<MessageFlags> out_flags,
Out<u64> out_tick);
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* receive_event;
// Message sources map (source name -> message queue)
std::map<std::string, std::vector<std::pair<OverlayNotification, MessageFlags>>> message_sources;
};
} // namespace Service::PSC

2
src/core/hle/service/psc/ovln/receiver_service.cpp

@ -21,7 +21,7 @@ IReceiverService::~IReceiverService() = default;
Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
LOG_DEBUG(Service_PSC, "called");
*out_receiver = std::make_shared<IReceiver>(system);
*out_receiver = std::shared_ptr<IReceiver>(new IReceiver(system));
R_SUCCEED();
}

33
src/core/hle/service/vi/container.cpp

@ -131,6 +131,39 @@ Result Container::SetLayerBlending(u64 layer_id, bool enabled) {
R_SUCCEED();
}
Result Container::SetLayerZIndex(u64 layer_id, s32 z_index) {
std::scoped_lock lk{m_lock};
auto* const layer = m_layers.GetLayerById(layer_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
// Forward to nvnflinger layer via surface flinger (store on the layer struct)
if (auto layer_ref = m_surface_flinger->FindLayer(layer->GetConsumerBinderId())) {
LOG_INFO(Service_VI, "Container: SetLayerZIndex layer_id={} z={} (cid={})", layer_id,
z_index, layer->GetConsumerBinderId());
layer_ref->z_index = z_index;
} else {
LOG_INFO(Service_VI, "Container: SetLayerZIndex failed to find layer for layer_id={} (cid={})",
layer_id, layer->GetConsumerBinderId());
}
R_SUCCEED();
}
Result Container::GetLayerZIndex(u64 layer_id, s32* out_z_index) {
std::scoped_lock lk{m_lock};
auto* const layer = m_layers.GetLayerById(layer_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
if (auto layer_ref = m_surface_flinger->FindLayer(layer->GetConsumerBinderId())) {
*out_z_index = layer_ref->z_index;
R_SUCCEED();
}
R_RETURN(VI::ResultNotFound);
}
void Container::LinkVsyncEvent(u64 display_id, Event* event) {
std::scoped_lock lk{m_lock};
m_conductor->LinkVsyncEvent(display_id, event);

2
src/core/hle/service/vi/container.h

@ -62,6 +62,8 @@ public:
Result SetLayerVisibility(u64 layer_id, bool visible);
Result SetLayerBlending(u64 layer_id, bool enabled);
Result SetLayerZIndex(u64 layer_id, s32 z_index);
Result GetLayerZIndex(u64 layer_id, s32* out_z_index);
void LinkVsyncEvent(u64 display_id, Event* event);
void UnlinkVsyncEvent(u64 display_id, Event* event);

4
src/core/hle/service/vi/manager_display_service.cpp

@ -116,6 +116,10 @@ Result IManagerDisplayService::SetLayerBlending(bool enabled, u64 layer_id) {
R_RETURN(m_container->SetLayerBlending(layer_id, enabled));
}
Result IManagerDisplayService::SetLayerZIndex(s32 z_index, u64 layer_id) {
R_RETURN(m_container->SetLayerZIndex(layer_id, z_index));
}
Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id,
AppletResourceUserId aruid) {
LOG_DEBUG(Service_VI, "called. flags={}, display={}, aruid={}", flags, display_id, aruid.pid);

3
src/core/hle/service/vi/manager_display_service.h

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
@ -22,6 +24,7 @@ public:
void DestroySharedLayerSession(Kernel::KProcess* owner_process);
Result SetLayerBlending(bool enabled, u64 layer_id);
Result SetLayerZIndex(s32 z_index, u64 layer_id);
public:
Result CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id,

61
src/core/hle/service/vi/shared_buffer_manager.cpp

@ -38,13 +38,13 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_
Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
Kernel::KMemoryManager::Direction::FromBack)));
// Fill the output data with red.
// Initialize to fully transparent black to avoid covering content before first present.
for (auto& block : *pg) {
u32* start = system.DeviceMemory().GetPointer<u32>(block.GetAddress());
u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
for (; start < end; start++) {
*start = 0xFF0000FF;
for (; start < end; ++start) {
*start = 0x00000000; // ARGB/RGBA with alpha=0
}
}
@ -252,8 +252,9 @@ Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64*
R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id),
std::addressof(session.layer_id), display_id));
// Configure blending.
// Configure blending and z-index
R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
R_ASSERT(m_container.SetLayerZIndex(session.layer_id, 100000));
// Get the producer and set preallocated buffers.
std::shared_ptr<android::BufferQueueProducer> producer;
@ -261,6 +262,8 @@ Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64*
MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle);
MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle);
// Do not queue a frame here. The layer will be made visible on first Present.
// Assign outputs.
*out_buffer_id = m_buffer_id;
*out_layer_handle = session.layer_id;
@ -370,6 +373,9 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
android::Status::NoError,
VI::ResultOperationFailed);
// Ensure the layer is visible when content is presented.
(void)m_container.SetLayerVisibility(layer_id, true);
// We succeeded.
R_SUCCEED();
}
@ -399,6 +405,7 @@ Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadabl
R_SUCCEED();
}
// Keep the present-on-write path to make overlay visible when data arrives.
Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
Common::ScratchBuffer<u32> scratch;
@ -406,23 +413,51 @@ Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32*
// TODO: this could be optimized
s64 e = -1280 * 768 * 4;
for (auto& block : *m_buffer_page_group) {
u8* start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
u8* end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
for (; start < end; start++) {
*start = 0;
u8* const block_start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
u8* ptr = block_start;
u8* const block_end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
for (; ptr < block_end; ++ptr) {
if (e >= 0 && e < static_cast<s64>(capture_buffer.size())) {
*start = capture_buffer[e];
*ptr = capture_buffer[static_cast<size_t>(e)];
} else {
*ptr = 0;
}
e++;
++e;
}
m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) {
m_system.GPU().InvalidateRegion(addr, end - start);
m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(block_start, scratch, [&](DAddr addr) {
m_system.GPU().InvalidateRegion(addr, block_end - block_start);
});
}
// After writing, present a frame on each active shared layer so it becomes visible.
for (auto& [aruid, session] : m_sessions) {
std::shared_ptr<android::BufferQueueProducer> producer;
if (R_FAILED(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id))) {
continue;
}
s32 slot = -1;
android::Fence fence = android::Fence::NoFence();
if (producer->DequeueBuffer(&slot, &fence, SharedBufferAsync != 0, SharedBufferWidth,
SharedBufferHeight, SharedBufferBlockLinearFormat, 0) !=
android::Status::NoError) {
continue;
}
std::shared_ptr<android::GraphicBuffer> gb;
if (producer->RequestBuffer(slot, &gb) != android::Status::NoError) {
producer->CancelBuffer(slot, android::Fence::NoFence());
continue;
}
android::QueueBufferInput qin{};
android::QueueBufferOutput qout{};
qin.crop = {0, 0, static_cast<s32>(SharedBufferWidth), static_cast<s32>(SharedBufferHeight)};
qin.fence = android::Fence::NoFence();
qin.transform = static_cast<android::NativeWindowTransform>(0);
qin.swap_interval = 1;
(void)producer->QueueBuffer(slot, qin, &qout);
}
*out_was_written = true;
*out_layer_index = 1;
R_SUCCEED();

18
src/core/hle/service/vi/system_display_service.cpp

@ -20,7 +20,7 @@ ISystemDisplayService::ISystemDisplayService(Core::System& system_,
{1204, nullptr, "SetDisplayMagnification"},
{2201, nullptr, "SetLayerPosition"},
{2203, nullptr, "SetLayerSize"},
{2204, nullptr, "GetLayerZ"},
{2204, C<&ISystemDisplayService::GetLayerZ>, "GetLayerZ"},
{2205, C<&ISystemDisplayService::SetLayerZ>, "SetLayerZ"},
{2207, C<&ISystemDisplayService::SetLayerVisibility>, "SetLayerVisibility"},
{2209, nullptr, "SetLayerAlpha"},
@ -68,16 +68,26 @@ ISystemDisplayService::ISystemDisplayService(Core::System& system_,
ISystemDisplayService::~ISystemDisplayService() = default;
Result ISystemDisplayService::SetLayerZ(u32 z_value, u64 layer_id) {
LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}, z_value={}", layer_id, z_value);
Result ISystemDisplayService::GetLayerZ(Out<u64> out_z_value, u64 layer_id) {
LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
s32 z{};
const auto res = m_container->GetLayerZIndex(layer_id, &z);
R_TRY(res);
*out_z_value = static_cast<u64>(z);
R_SUCCEED();
}
Result ISystemDisplayService::SetLayerZ(u64 layer_id, u64 z_value) {
LOG_DEBUG(Service_VI, "called. layer_id={}, z_value={}", layer_id, z_value);
// Forward to container using internal API when available
R_RETURN(m_container->SetLayerZIndex(layer_id, static_cast<s32>(z_value)));
}
// This function currently does nothing but return a success error code in
// the vi library itself, so do the same thing, but log out the passed in values.
Result ISystemDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
LOG_DEBUG(Service_VI, "called, layer_id={}, visible={}", layer_id, visible);
R_SUCCEED();
R_RETURN(m_container->SetLayerVisibility(layer_id, visible));
}
Result ISystemDisplayService::ListDisplayModes(

3
src/core/hle/service/vi/system_display_service.h

@ -18,7 +18,8 @@ public:
~ISystemDisplayService() override;
private:
Result SetLayerZ(u32 z_value, u64 layer_id);
Result GetLayerZ(Out<u64> out_z_value, u64 layer_id);
Result SetLayerZ(u64 layer_id, u64 z_value);
Result SetLayerVisibility(bool visible, u64 layer_id);
Result ListDisplayModes(Out<u64> out_count, u64 display_id,
OutArray<DisplayMode, BufferAttr_HipcMapAlias> out_display_modes);

Loading…
Cancel
Save