From 1eed7efd09ce9c7cb85cf799711fadd89ecf5a88 Mon Sep 17 00:00:00 2001 From: Maufeat Date: Wed, 17 Dec 2025 06:26:02 +0100 Subject: [PATCH] [core, display, overlay] Add LayerIsOverlay to separate overlay on composer, stub RequestListSummaryOverlayNotification, sync emu settings when setting language (#3123) This should fix the issue with, for example, ToTK running at 60 FPS when overlay applet is running. This also should always run the overlay as actual overlay and not in the back. Stubs RequestListSummaryOverlayNotifications in friends Syncs Language of the Emulator, when setting language, this is used in Starter Applet Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3123 Reviewed-by: CamilleLaVey Reviewed-by: Caio Oliveira Co-authored-by: Maufeat Co-committed-by: Maufeat --- .../hle/service/am/display_layer_manager.cpp | 12 ++-- .../service/am/service/overlay_functions.cpp | 32 +++++++++- .../service/am/service/overlay_functions.h | 1 + src/core/hle/service/am/window_system.cpp | 4 +- src/core/hle/service/friend/friend.cpp | 12 +++- .../ns/application_manager_interface.cpp | 51 ++++++++++++++- .../ns/application_manager_interface.h | 4 ++ src/core/hle/service/ns/ns_types.h | 5 ++ src/core/hle/service/nvnflinger/display.h | 3 +- .../service/nvnflinger/hardware_composer.cpp | 63 ++++++++++++++----- .../service/nvnflinger/hardware_composer.h | 4 ++ .../service/nvnflinger/surface_flinger.cpp | 10 +++ .../hle/service/nvnflinger/surface_flinger.h | 1 + .../service/set/system_settings_server.cpp | 26 ++++++++ src/core/hle/service/vi/conductor.cpp | 3 + src/core/hle/service/vi/container.cpp | 10 +++ src/core/hle/service/vi/container.h | 1 + .../hle/service/vi/shared_buffer_manager.cpp | 55 +++------------- 18 files changed, 222 insertions(+), 75 deletions(-) diff --git a/src/core/hle/service/am/display_layer_manager.cpp b/src/core/hle/service/am/display_layer_manager.cpp index a93ca5bc67..6789629310 100644 --- a/src/core/hle/service/am/display_layer_manager.cpp +++ b/src/core/hle/service/am/display_layer_manager.cpp @@ -36,10 +36,6 @@ void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* pro m_buffer_sharing_enabled = false; m_blending_enabled = mode == LibraryAppletMode::PartialForeground || mode == LibraryAppletMode::PartialForegroundIndirectDisplay; - - if (m_applet_id != AppletId::Application) { - (void)this->IsSystemBufferSharingEnabled(); - } } void DisplayLayerManager::Finalize() { @@ -80,11 +76,10 @@ Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) { if (m_applet_id != AppletId::Application) { (void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id); if (m_applet_id == AppletId::OverlayDisplay) { - static constexpr s32 kOverlayBackgroundZ = -1; - (void)m_manager_display_service->SetLayerZIndex(kOverlayBackgroundZ, *out_layer_id); + (void)m_manager_display_service->SetLayerZIndex(-1, *out_layer_id); + (void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true); } else { - static constexpr s32 kOverlayZ = 3; - (void)m_manager_display_service->SetLayerZIndex(kOverlayZ, *out_layer_id); + (void)m_manager_display_service->SetLayerZIndex(1, *out_layer_id); } } @@ -131,6 +126,7 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() { s32 initial_z = 1; if (m_applet_id == AppletId::OverlayDisplay) { initial_z = -1; + (void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true); } m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id); R_SUCCEED(); diff --git a/src/core/hle/service/am/service/overlay_functions.cpp b/src/core/hle/service/am/service/overlay_functions.cpp index 8af037734a..41f2e5c008 100644 --- a/src/core/hle/service/am/service/overlay_functions.cpp +++ b/src/core/hle/service/am/service/overlay_functions.cpp @@ -24,7 +24,7 @@ namespace Service::AM { {20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"}, {21, nullptr, "SetHandlingTouchScreenInputEnabled"}, {30, nullptr, "SetHealthWarningShowingState"}, - {31, nullptr, "IsHealthWarningRequired"}, + {31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"}, {40, nullptr, "GetApplicationNintendoLogo"}, {41, nullptr, "GetApplicationStartupMovie"}, {50, nullptr, "SetGpuTimeSliceBoostForApplication"}, @@ -69,12 +69,33 @@ namespace Service::AM { Result IOverlayFunctions::GetApplicationIdForLogo(Out out_application_id) { LOG_DEBUG(Service_AM, "called"); - // Prefer explicit application_id if available, else fall back to program_id + std::shared_ptr target_applet; + + auto* window_system = system.GetAppletManager().GetWindowSystem(); + if (window_system) { + target_applet = window_system->GetMainApplet(); + if (target_applet) { + std::scoped_lock lk{target_applet->lock}; + LOG_DEBUG(Service_AM, "applet_id={}, program_id={:016X}, type={}", + static_cast(target_applet->applet_id), target_applet->program_id, + static_cast(target_applet->type)); + + u64 id = target_applet->screen_shot_identity.application_id; + if (id == 0) { + id = target_applet->program_id; + } + LOG_DEBUG(Service_AM, "application_id={:016X}", id); + *out_application_id = id; + R_SUCCEED(); + } + } + std::scoped_lock lk{m_applet->lock}; u64 id = m_applet->screen_shot_identity.application_id; if (id == 0) { id = m_applet->program_id; } + LOG_DEBUG(Service_AM, "application_id={:016X} (fallback)", id); *out_application_id = id; R_SUCCEED(); } @@ -86,6 +107,13 @@ namespace Service::AM { R_SUCCEED(); } + Result IOverlayFunctions::IsHealthWarningRequired(Out is_required) { + LOG_DEBUG(Service_AM, "called"); + std::scoped_lock lk{m_applet->lock}; + *is_required = false; + R_SUCCEED(); + } + Result IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled(bool enabled) { LOG_DEBUG(Service_AM, "called, enabled={}", enabled); std::scoped_lock lk{m_applet->lock}; diff --git a/src/core/hle/service/am/service/overlay_functions.h b/src/core/hle/service/am/service/overlay_functions.h index 26c5cc0c88..870f5eae9c 100644 --- a/src/core/hle/service/am/service/overlay_functions.h +++ b/src/core/hle/service/am/service/overlay_functions.h @@ -18,6 +18,7 @@ namespace Service::AM { Result EndToWatchShortHomeButtonMessage(); Result GetApplicationIdForLogo(Out out_application_id); Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled); + Result IsHealthWarningRequired(Out is_required); Result SetHandlingHomeButtonShortPressedEnabled(bool enabled); Result Unknown70(); diff --git a/src/core/hle/service/am/window_system.cpp b/src/core/hle/service/am/window_system.cpp index c78a955f68..77ca5a76f5 100644 --- a/src/core/hle/service/am/window_system.cpp +++ b/src/core/hle/service/am/window_system.cpp @@ -186,8 +186,6 @@ void WindowSystem::OnSystemButtonPress(SystemButtonType type) { if (m_overlay_display) { std::scoped_lock lk_overlay{m_overlay_display->lock}; m_overlay_display->overlay_in_foreground = !m_overlay_display->overlay_in_foreground; - // Tie window visibility to foreground state so hidden when not active - m_overlay_display->window_visible = m_overlay_display->overlay_in_foreground; LOG_INFO(Service_AM, "Overlay long-press toggle: overlay_in_foreground={} window_visible={}", m_overlay_display->overlay_in_foreground, m_overlay_display->window_visible); } SendButtonAppletMessageLocked(AppletMessage::DetectLongPressingHomeButton); @@ -393,7 +391,7 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b s32 z_index = 0; const bool now_foreground = inherited_foreground; if (applet->applet_id == AppletId::OverlayDisplay) { - z_index = applet->overlay_in_foreground ? 100000 : -100000; + z_index = applet->overlay_in_foreground ? 100000 : -1; } else if (now_foreground && !is_obscured) { z_index = 2; } else if (now_foreground) { diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 84c73e9d6f..f65e70a969 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -67,7 +70,7 @@ public: {20701, &IFriendService::GetPlayHistoryStatistics, "GetPlayHistoryStatistics"}, {20800, &IFriendService::LoadUserSetting, "LoadUserSetting"}, {20801, nullptr, "SyncUserSetting"}, - {20900, nullptr, "RequestListSummaryOverlayNotification"}, + {20900, &IFriendService::RequestListSummaryOverlayNotification, "RequestListSummaryOverlayNotification"}, {21000, nullptr, "GetExternalApplicationCatalog"}, {22000, nullptr, "GetReceivedFriendInvitationList"}, {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"}, @@ -317,6 +320,13 @@ private: rb.Push(ResultSuccess); } + void RequestListSummaryOverlayNotification(HLERequestContext& ctx) { + LOG_INFO(Service_Friend, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + void GetReceivedFriendInvitationCountCache(HLERequestContext& ctx) { LOG_DEBUG(Service_Friend, "(STUBBED) called, check in out"); diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp index 6f05116853..7c4843a80a 100644 --- a/src/core/hle/service/ns/application_manager_interface.cpp +++ b/src/core/hle/service/ns/application_manager_interface.cpp @@ -10,6 +10,8 @@ #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/application_manager_interface.h" + +#include "core/file_sys/content_archive.h" #include "core/hle/service/ns/content_management_interface.h" #include "core/hle/service/ns/read_only_application_control_data_interface.h" #include "core/file_sys/patch_manager.h" @@ -54,7 +56,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_ {37, nullptr, "ListRequiredVersion"}, {38, D<&IApplicationManagerInterface::CheckApplicationLaunchVersion>, "CheckApplicationLaunchVersion"}, {39, nullptr, "CheckApplicationLaunchRights"}, - {40, nullptr, "GetApplicationLogoData"}, + {40, D<&IApplicationManagerInterface::GetApplicationLogoData>, "GetApplicationLogoData"}, {41, nullptr, "CalculateApplicationDownloadRequiredSize"}, {42, nullptr, "CleanupSdCard"}, {43, D<&IApplicationManagerInterface::CheckSdCardMountStatus>, "CheckSdCardMountStatus"}, @@ -331,6 +333,53 @@ Result IApplicationManagerInterface::UnregisterNetworkServiceAccountWithUserSave LOG_DEBUG(Service_NS, "called, user_id={}", user_id.FormattedString()); R_SUCCEED(); } + +Result IApplicationManagerInterface::GetApplicationLogoData( + Out out_size, OutBuffer out_buffer, u64 application_id, + InBuffer logo_path_buffer) { + const std::string path_view{reinterpret_cast(logo_path_buffer.data()), + logo_path_buffer.size()}; + + // Find null terminator and trim the path + auto null_pos = path_view.find('\0'); + std::string path = (null_pos != std::string::npos) ? path_view.substr(0, null_pos) : path_view; + + LOG_DEBUG(Service_NS, "called, application_id={:016X}, logo_path={}", application_id, path); + + auto& content_provider = system.GetContentProviderUnion(); + + auto program = content_provider.GetEntry(application_id, FileSys::ContentRecordType::Program); + if (!program) { + LOG_WARNING(Service_NS, "Application program not found for id={:016X}", application_id); + R_RETURN(ResultUnknown); + } + + const auto logo_dir = program->GetLogoPartition(); + if (!logo_dir) { + LOG_WARNING(Service_NS, "Logo partition not found for id={:016X}", application_id); + R_RETURN(ResultUnknown); + } + + const auto file = logo_dir->GetFile(path); + if (!file) { + LOG_WARNING(Service_NS, "Logo path not found: {} for id={:016X}", path, + application_id); + R_RETURN(ResultUnknown); + } + + const auto data = file->ReadAllBytes(); + if (data.size() > out_buffer.size()) { + LOG_WARNING(Service_NS, "Logo buffer too small: have={}, need={}", out_buffer.size(), + data.size()); + R_RETURN(ResultUnknown); + } + + std::memcpy(out_buffer.data(), data.data(), data.size()); + *out_size = static_cast(data.size()); + + R_SUCCEED(); +} + Result IApplicationManagerInterface::GetApplicationControlData( OutBuffer out_buffer, Out out_actual_size, ApplicationControlSource application_control_source, u64 application_id) { diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h index 915581172e..e7bab6dca1 100644 --- a/src/core/hle/service/ns/application_manager_interface.h +++ b/src/core/hle/service/ns/application_manager_interface.h @@ -60,6 +60,10 @@ public: u64 application_id); Result CheckApplicationLaunchVersion(u64 application_id); Result GetApplicationTerminateResult(Out out_result, u64 application_id); + Result GetApplicationLogoData(Out out_size, + OutBuffer out_buffer, + u64 application_id, + InBuffer logo_path_buffer); Result Unknown4022(OutCopyHandle out_event); Result Unknown4023(Out out_result); Result Unknown4053(); diff --git a/src/core/hle/service/ns/ns_types.h b/src/core/hle/service/ns/ns_types.h index 8e7e4fa0dc..247f7063af 100644 --- a/src/core/hle/service/ns/ns_types.h +++ b/src/core/hle/service/ns/ns_types.h @@ -179,4 +179,9 @@ struct ApplicationDisplayData { }; static_assert(sizeof(ApplicationDisplayData) == 0x300, "ApplicationDisplayData has incorrect size."); +struct LogoPath { + std::array path; +}; +static_assert(std::is_trivially_copyable_v, "LogoPath must be trivially copyable."); + } // namespace Service::NS diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h index 1264465079..ada302a79e 100644 --- a/src/core/hle/service/nvnflinger/display.h +++ b/src/core/hle/service/nvnflinger/display.h @@ -15,7 +15,7 @@ struct Layer { explicit Layer(std::shared_ptr buffer_item_consumer_, s32 consumer_id_) : buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_), - blending(LayerBlending::None), visible(true), z_index(0) {} + blending(LayerBlending::None), visible(true), z_index(0), is_overlay(false) {} ~Layer() { buffer_item_consumer->Abandon(); } @@ -25,6 +25,7 @@ struct Layer { LayerBlending blending; bool visible; s32 z_index; + bool is_overlay; }; struct LayerStack { diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp index 4f8f5da69a..cfd999497b 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.cpp +++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp @@ -78,8 +78,25 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, for (auto& layer : display.stack.layers) { auto consumer_id = layer->consumer_id; + bool should_try_acquire = true; + if (!layer->is_overlay) { + auto fb_it = m_framebuffers.find(consumer_id); + if (fb_it != m_framebuffers.end() && fb_it->second.is_acquired) { + const u64 frames_since_last_acquire = m_frame_number - fb_it->second.last_acquire_frame; + const s32 expected_interval = NormalizeSwapInterval(nullptr, fb_it->second.item.swap_interval); + + if (frames_since_last_acquire < static_cast(expected_interval)) { + should_try_acquire = false; + } + } + } + // Try to fetch the framebuffer (either new or stale). - const auto result = this->CacheFramebufferLocked(*layer, consumer_id); + const auto result = should_try_acquire + ? this->CacheFramebufferLocked(*layer, consumer_id) + : (m_framebuffers.find(consumer_id) != m_framebuffers.end() && m_framebuffers[consumer_id].is_acquired + ? CacheStatus::CachedBufferReused + : CacheStatus::NoBufferAvailable); // If we failed, skip this layer. if (result == CacheStatus::NoBufferAvailable) { @@ -111,6 +128,12 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, }); } + // Overlay layers run at their own framerate independently of the game. + // Skip them when calculating the swap interval for the main game. + if (layer->is_overlay) { + continue; + } + // We need to compose again either before this frame is supposed to // be released, or exactly on the vsync period it should be released. const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval); @@ -138,33 +161,44 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, // Batch framebuffer releases, instead of one-into-one. std::vector> to_release; for (auto& [layer_id, framebuffer] : m_framebuffers) { - if (framebuffer.release_frame_number > m_frame_number || !framebuffer.is_acquired) + if (!framebuffer.is_acquired) + continue; + + auto layer = display.stack.FindLayer(layer_id); + if (!layer) continue; - if (auto layer = display.stack.FindLayer(layer_id); layer) + + // Overlay layers always release after every compose + // Non-overlay layers release based on their swap interval + if (layer->is_overlay || framebuffer.release_frame_number <= m_frame_number) { to_release.emplace_back(layer.get(), &framebuffer); + } } for (auto& [layer, framebuffer] : to_release) { layer->buffer_item_consumer->ReleaseBuffer(framebuffer->item, android::Fence::NoFence()); framebuffer->is_acquired = false; } - // Advance by at least one frame. - const u32 frame_advance = swap_interval.value_or(1); - m_frame_number += frame_advance; + // Advance by 1 frame (60 FPS compositing) + m_frame_number += 1; - // Release any necessary framebuffers. + // Release any necessary framebuffers (non-overlay layers only, as overlays are already released above). for (auto& [layer_id, framebuffer] : m_framebuffers) { - if (framebuffer.release_frame_number > m_frame_number) { - // Not yet ready to release this framebuffer. + if (!framebuffer.is_acquired) { + // Already released. continue; } - if (!framebuffer.is_acquired) { - // Already released. + if (framebuffer.release_frame_number > m_frame_number) { continue; } if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) { + // Skip overlay layers as they were already released above + if (layer->is_overlay) { + continue; + } + // TODO: support release fence // This is needed to prevent screen tearing layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); @@ -172,7 +206,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, } } - return frame_advance; + return 1; } void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) { @@ -200,8 +234,9 @@ bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& fr } // We succeeded, so set the new release frame info. - framebuffer.release_frame_number = - NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval); + const s32 swap_interval = layer.is_overlay ? 1 : NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval); + framebuffer.release_frame_number = m_frame_number + swap_interval; + framebuffer.last_acquire_frame = m_frame_number; framebuffer.is_acquired = true; return true; diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h index c5b8304681..e9b7194612 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.h +++ b/src/core/hle/service/nvnflinger/hardware_composer.h @@ -1,3 +1,6 @@ +// 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-3.0-or-later @@ -34,6 +37,7 @@ private: struct Framebuffer { android::BufferItem item{}; ReleaseFrameNumber release_frame_number{}; + u64 last_acquire_frame{0}; bool is_acquired{false}; }; diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp index 8362b65e58..fbf70592bd 100644 --- a/src/core/hle/service/nvnflinger/surface_flinger.cpp +++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp @@ -1,3 +1,6 @@ +// 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 @@ -101,6 +104,13 @@ void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blen } } +void SurfaceFlinger::SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay) { + if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) { + layer->is_overlay = is_overlay; + LOG_DEBUG(Service_VI, "Layer {} marked as overlay: {}", consumer_binder_id, is_overlay); + } +} + Display* SurfaceFlinger::FindDisplay(u64 display_id) { for (auto& display : m_displays) { if (display.id == display_id) { diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h index d771909a82..05b4206c34 100644 --- a/src/core/hle/service/nvnflinger/surface_flinger.h +++ b/src/core/hle/service/nvnflinger/surface_flinger.h @@ -47,6 +47,7 @@ public: void SetLayerVisibility(s32 consumer_binder_id, bool visible); void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending); + void SetLayerIsOverlay(s32 consumer_binder_id, bool is_overlay); std::shared_ptr FindLayer(s32 consumer_binder_id); diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp index 115eaf331a..f87dd847ba 100644 --- a/src/core/hle/service/set/system_settings_server.cpp +++ b/src/core/hle/service/set/system_settings_server.cpp @@ -36,6 +36,29 @@ struct SettingsHeader { u32 version; u32 reserved; }; + +void SyncGlobalLanguageFromCode(LanguageCode language_code) { + const auto it = std::find_if(available_language_codes.begin(), available_language_codes.end(), + [language_code](LanguageCode code) { return code == language_code; }); + if (it == available_language_codes.end()) { + return; + } + + const std::size_t index = static_cast(std::distance(available_language_codes.begin(), it)); + if (index >= static_cast(Settings::values.language_index.GetValue())) { + Settings::values.language_index.SetValue(static_cast(index)); + } +} + +void SyncGlobalRegionFromCode(SystemRegionCode region_code) { + const auto region_index = static_cast(region_code); + if (region_index > static_cast(Settings::Region::Taiwan)) { + return; + } + + Settings::values.region_index.SetValue(static_cast(region_index)); +} + } // Anonymous namespace Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, @@ -457,6 +480,7 @@ Result ISystemSettingsServer::SetLanguageCode(LanguageCode language_code) { LOG_INFO(Service_SET, "called, language_code={}", language_code); m_system_settings.language_code = language_code; + SyncGlobalLanguageFromCode(language_code); SetSaveNeeded(); R_SUCCEED(); } @@ -889,6 +913,7 @@ Result ISystemSettingsServer::SetRegionCode(SystemRegionCode region_code) { LOG_INFO(Service_SET, "called, region_code={}", region_code); m_system_settings.region_code = region_code; + SyncGlobalRegionFromCode(region_code); SetSaveNeeded(); R_SUCCEED(); } @@ -1224,6 +1249,7 @@ Result ISystemSettingsServer::SetKeyboardLayout(KeyboardLayout keyboard_layout) LOG_INFO(Service_SET, "called, keyboard_layout={}", keyboard_layout); m_system_settings.keyboard_layout = keyboard_layout; + SetSaveNeeded(); R_SUCCEED(); } diff --git a/src/core/hle/service/vi/conductor.cpp b/src/core/hle/service/vi/conductor.cpp index c8ce4fca04..a271041be6 100644 --- a/src/core/hle/service/vi/conductor.cpp +++ b/src/core/hle/service/vi/conductor.cpp @@ -1,3 +1,6 @@ +// 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 diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp index e7d3b4757b..e7255c2b0a 100644 --- a/src/core/hle/service/vi/container.cpp +++ b/src/core/hle/service/vi/container.cpp @@ -166,6 +166,16 @@ Result Container::GetLayerZIndex(u64 layer_id, s32* out_z_index) { R_RETURN(VI::ResultNotFound); } +Result Container::SetLayerIsOverlay(u64 layer_id, bool is_overlay) { + std::scoped_lock lk{m_lock}; + + auto* const layer = m_layers.GetLayerById(layer_id); + R_UNLESS(layer != nullptr, VI::ResultNotFound); + + m_surface_flinger->SetLayerIsOverlay(layer->GetConsumerBinderId(), is_overlay); + R_SUCCEED(); +} + void Container::LinkVsyncEvent(u64 display_id, Event* event) { std::scoped_lock lk{m_lock}; m_conductor->LinkVsyncEvent(display_id, event); diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h index 544a47889a..5d111e71ab 100644 --- a/src/core/hle/service/vi/container.h +++ b/src/core/hle/service/vi/container.h @@ -67,6 +67,7 @@ public: Result SetLayerBlending(u64 layer_id, bool enabled); Result SetLayerZIndex(u64 layer_id, s32 z_index); Result GetLayerZIndex(u64 layer_id, s32* out_z_index); + Result SetLayerIsOverlay(u64 layer_id, bool is_overlay); void LinkVsyncEvent(u64 display_id, Event* event); void UnlinkVsyncEvent(u64 display_id, Event* event); diff --git a/src/core/hle/service/vi/shared_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp index e1808f74ca..1568344830 100644 --- a/src/core/hle/service/vi/shared_buffer_manager.cpp +++ b/src/core/hle/service/vi/shared_buffer_manager.cpp @@ -46,8 +46,8 @@ Result AllocateSharedBufferMemory(std::unique_ptr* out_page_ u32* start = system.DeviceMemory().GetPointer(block.GetAddress()); u32* end = system.DeviceMemory().GetPointer(block.GetAddress() + block.GetSize()); - for (; start < end; ++start) { - *start = 0x00000000; // ARGB/RGBA with alpha=0 + for (; start < end; start++) { + *start = 0xFF0000FF; } } @@ -257,7 +257,6 @@ Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* // 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 producer; @@ -374,11 +373,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence, android::Status::NoError, VI::ResultOperationFailed); - // Ensure the layer is visible when content is presented. - // Re-assert overlay priority in case clients reset it. - (void)m_container.SetLayerZIndex(layer_id, 100000); - (void)m_container.SetLayerVisibility(layer_id, true); - // We succeeded. R_SUCCEED(); } @@ -415,51 +409,22 @@ 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* const block_start = m_system.DeviceMemory().GetPointer(block.GetAddress()); - u8* ptr = block_start; - u8* const block_end = m_system.DeviceMemory().GetPointer(block.GetAddress() + block.GetSize()); + u8* start = m_system.DeviceMemory().GetPointer(block.GetAddress()); + u8* end = m_system.DeviceMemory().GetPointer(block.GetAddress() + block.GetSize()); - for (; ptr < block_end; ++ptr) { + for (; start < end; start++) { + *start = 0; if (e >= 0 && e < static_cast(capture_buffer.size())) { - *ptr = capture_buffer[static_cast(e)]; - } else { - *ptr = 0; + *start = capture_buffer[e]; } - ++e; + e++; } - m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(block_start, scratch, [&](DAddr addr) { - m_system.GPU().InvalidateRegion(addr, block_end - block_start); + m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) { + m_system.GPU().InvalidateRegion(addr, end - start); }); } - // After writing, present a frame on each active shared layer so it becomes visible. - for (auto& [aruid, session] : m_sessions) { - std::shared_ptr 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 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(SharedBufferWidth), static_cast(SharedBufferHeight)}; - qin.fence = android::Fence::NoFence(); - qin.transform = static_cast(0); - qin.swap_interval = 1; - (void)producer->QueueBuffer(slot, qin, &qout); - } - *out_was_written = true; *out_layer_index = 1; R_SUCCEED();