[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 <camillelavey99@gmail.com>
Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Co-committed-by: Maufeat <sahyno1996@gmail.com>
This commit is contained in:
Maufeat 2025-12-17 06:26:02 +01:00 committed by crueter
parent 50f8d4130d
commit 1eed7efd09
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
18 changed files with 223 additions and 76 deletions

View file

@ -15,7 +15,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), 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 {

View file

@ -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<u64>(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<std::pair<Layer*, Framebuffer*>> 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;
if (auto layer = display.stack.FindLayer(layer_id); layer)
auto layer = display.stack.FindLayer(layer_id);
if (!layer)
continue;
// 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.
continue;
}
if (!framebuffer.is_acquired) {
// Already released.
continue;
}
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;

View file

@ -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};
};

View file

@ -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) {

View file

@ -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<Layer> FindLayer(s32 consumer_binder_id);