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();