From 2c421a7046c5ff1fdb8319f097a89a331907baf6 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 23 Jan 2024 10:19:55 -0500 Subject: hardware_composer: implement speed limit extensions --- src/core/hle/service/nvnflinger/buffer_item.h | 2 +- .../hle/service/nvnflinger/hardware_composer.cpp | 53 ++++++++++++++++------ .../hle/service/nvnflinger/hardware_composer.h | 4 +- src/core/hle/service/nvnflinger/nvnflinger.cpp | 12 +++-- src/core/hle/service/nvnflinger/nvnflinger.h | 1 + 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/core/hle/service/nvnflinger/buffer_item.h b/src/core/hle/service/nvnflinger/buffer_item.h index f9f262628..7fd808f54 100644 --- a/src/core/hle/service/nvnflinger/buffer_item.h +++ b/src/core/hle/service/nvnflinger/buffer_item.h @@ -40,7 +40,7 @@ public: bool is_droppable{}; bool acquire_called{}; bool transform_to_display_inverse{}; - u32 swap_interval{}; + s32 swap_interval{}; }; } // namespace Service::android diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp index 54889bb4f..c720dd1f8 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.cpp +++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp @@ -16,11 +16,37 @@ namespace Service::Nvnflinger { +namespace { + +s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) { + if (swap_interval <= 0) { + // As an extension, treat nonpositive swap interval as speed multiplier. + if (out_speed_scale) { + *out_speed_scale = 2.f * static_cast(1 - swap_interval); + } + + swap_interval = 1; + } + + if (swap_interval >= 5) { + // As an extension, treat high swap interval as precise speed control. + if (out_speed_scale) { + *out_speed_scale = static_cast(swap_interval) / 100.f; + } + + swap_interval = 1; + } + + return swap_interval; +} + +} // namespace + HardwareComposer::HardwareComposer() = default; HardwareComposer::~HardwareComposer() = default; -u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp, - u32 frame_advance) { +u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, + Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) { boost::container::small_vector composition_stack; m_frame_number += frame_advance; @@ -45,8 +71,11 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis } } + // Set default speed limit to 100%. + *out_speed_scale = 1.0f; + // Determine the number of vsync periods to wait before composing again. - std::optional swap_interval{}; + std::optional swap_interval{}; bool has_acquired_buffer{}; // Acquire all necessary framebuffers. @@ -87,14 +116,15 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis // 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); + // 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 // to be introduced, this would cause an issue. if (swap_interval) { - swap_interval = std::min(*swap_interval, item.swap_interval); + swap_interval = std::min(*swap_interval, item_swap_interval); } else { - swap_interval = item.swap_interval; + swap_interval = item_swap_interval; } } @@ -111,13 +141,8 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis // Render MicroProfile. MicroProfileFlip(); - // If we advanced, then advance by at least 1 frame. - if (swap_interval) { - return std::max(*swap_interval, 1U); - } - - // Otherwise, advance by exactly one frame. - return 1U; + // Advance by at least one frame. + return swap_interval.value_or(1); } void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { @@ -146,7 +171,7 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer // We succeeded, so set the new release frame info. framebuffer.release_frame_number = - m_frame_number + std::max(1U, framebuffer.item.swap_interval); + NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval); 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 611afc169..ddab94ac9 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.h +++ b/src/core/hle/service/nvnflinger/hardware_composer.h @@ -26,8 +26,8 @@ public: explicit HardwareComposer(); ~HardwareComposer(); - u32 ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp, - u32 frame_advance); + u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, + Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance); void RemoveLayerLocked(VI::Display& display, LayerId layer_id); private: diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index e775a2ca8..a4e848882 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -291,7 +291,8 @@ void Nvnflinger::Compose() { auto nvdisp = nvdrv->GetDevice(disp_fd); ASSERT(nvdisp); - swap_interval = display.GetComposer().ComposeLocked(display, *nvdisp, swap_interval); + swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp, + swap_interval); } } @@ -308,15 +309,16 @@ s64 Nvnflinger::GetNextTicks() const { speed_scale = 0.01f; } } + + // Adjust by speed limit determined during composition. + speed_scale /= compose_speed_scale; + if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { // Run at intended presentation rate during video playback. speed_scale = 1.f; } - // As an extension, treat nonpositive swap interval as framerate multiplier. - const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast(1 - swap_interval) - : 60.f / static_cast(swap_interval); - + const f32 effective_fps = 60.f / static_cast(swap_interval); return static_cast(speed_scale * (1000000000.f / effective_fps)); } diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 73ff36620..c984d55a0 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -144,6 +144,7 @@ private: u32 next_buffer_queue_id = 1; s32 swap_interval = 1; + f32 compose_speed_scale = 1.0f; bool is_abandoned = false; -- cgit v1.2.3