[nvmflinger] fixed 30fps cap for games with swap_interval=2, and prefer newest queued frames to reduce input latency

This commit is contained in:
xbzk 2026-03-14 20:18:02 -03:00
parent 98a93561de
commit f856c2dfa0
2 changed files with 18 additions and 27 deletions

View file

@ -45,6 +45,17 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
auto front(core->queue.begin()); auto front(core->queue.begin());
// prefer newest queued frame for lower input latency (if no present deadline is requested).
if (expected_present.count() == 0 && core->queue.size() > 1) {
while (core->queue.size() > 1) {
const auto stale = core->queue.begin();
if (core->StillTracking(*stale)) slots[stale->slot].buffer_state = BufferState::Free;
core->queue.erase(stale);
}
core->SignalDequeueCondition();
front = core->queue.begin();
}
// If expected_present is specified, we may not want to return a buffer yet. // If expected_present is specified, we may not want to return a buffer yet.
if (expected_present.count() != 0) { if (expected_present.count() != 0) {
constexpr auto MAX_REASONABLE_NSEC = 1000000000LL; // 1 second constexpr auto MAX_REASONABLE_NSEC = 1000000000LL; // 1 second

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@ -77,26 +77,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
// Acquire all necessary framebuffers. // Acquire all necessary framebuffers.
for (auto& layer : display.stack.layers) { for (auto& layer : display.stack.layers) {
auto consumer_id = layer->consumer_id; auto consumer_id = layer->consumer_id;
const auto result = this->CacheFramebufferLocked(*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 = 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 we failed, skip this layer.
if (result == CacheStatus::NoBufferAvailable) { if (result == CacheStatus::NoBufferAvailable) {
@ -134,9 +115,9 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
continue; continue;
} }
// We need to compose again either before this frame is supposed to // hard-throttle non-overlay presentation cadence on 1..4 removed!!
// be released, or exactly on the vsync period it should be released. NormalizeSwapInterval(out_speed_scale, item.swap_interval);
const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval); const s32 item_swap_interval = 1;
// TODO: handle cases where swap intervals are relatively prime. So far, // TODO: handle cases where swap intervals are relatively prime. So far,
// only swap intervals of 0, 1 and 2 have been observed, but if 3 were // only swap intervals of 0, 1 and 2 have been observed, but if 3 were
@ -233,9 +214,8 @@ bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& fr
return false; return false;
} }
// We succeeded, so set the new release frame info. // Keep 60Hz consumer cadence and let producer queue timing decide effective FPS.
const s32 swap_interval = layer.is_overlay ? 1 : NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval); framebuffer.release_frame_number = m_frame_number + 1;
framebuffer.release_frame_number = m_frame_number + swap_interval;
framebuffer.last_acquire_frame = m_frame_number; framebuffer.last_acquire_frame = m_frame_number;
framebuffer.is_acquired = true; framebuffer.is_acquired = true;