diff options
| author | 2024-01-23 10:19:55 -0500 | |
|---|---|---|
| committer | 2024-01-31 11:27:21 -0500 | |
| commit | 2c421a7046c5ff1fdb8319f097a89a331907baf6 (patch) | |
| tree | b33e0baabf3aa23fd6c800c9e5786466548b9fb1 | |
| parent | nvnflinger/gpu: implement layer stack composition (diff) | |
| download | yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.gz yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.xz yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.zip | |
hardware_composer: implement speed limit extensions
| -rw-r--r-- | src/core/hle/service/nvnflinger/buffer_item.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/hardware_composer.cpp | 53 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/hardware_composer.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/nvnflinger.cpp | 12 | ||||
| -rw-r--r-- | 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: | |||
| 40 | bool is_droppable{}; | 40 | bool is_droppable{}; |
| 41 | bool acquire_called{}; | 41 | bool acquire_called{}; |
| 42 | bool transform_to_display_inverse{}; | 42 | bool transform_to_display_inverse{}; |
| 43 | u32 swap_interval{}; | 43 | s32 swap_interval{}; |
| 44 | }; | 44 | }; |
| 45 | 45 | ||
| 46 | } // namespace Service::android | 46 | } // 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 @@ | |||
| 16 | 16 | ||
| 17 | namespace Service::Nvnflinger { | 17 | namespace Service::Nvnflinger { |
| 18 | 18 | ||
| 19 | namespace { | ||
| 20 | |||
| 21 | s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) { | ||
| 22 | if (swap_interval <= 0) { | ||
| 23 | // As an extension, treat nonpositive swap interval as speed multiplier. | ||
| 24 | if (out_speed_scale) { | ||
| 25 | *out_speed_scale = 2.f * static_cast<f32>(1 - swap_interval); | ||
| 26 | } | ||
| 27 | |||
| 28 | swap_interval = 1; | ||
| 29 | } | ||
| 30 | |||
| 31 | if (swap_interval >= 5) { | ||
| 32 | // As an extension, treat high swap interval as precise speed control. | ||
| 33 | if (out_speed_scale) { | ||
| 34 | *out_speed_scale = static_cast<f32>(swap_interval) / 100.f; | ||
| 35 | } | ||
| 36 | |||
| 37 | swap_interval = 1; | ||
| 38 | } | ||
| 39 | |||
| 40 | return swap_interval; | ||
| 41 | } | ||
| 42 | |||
| 43 | } // namespace | ||
| 44 | |||
| 19 | HardwareComposer::HardwareComposer() = default; | 45 | HardwareComposer::HardwareComposer() = default; |
| 20 | HardwareComposer::~HardwareComposer() = default; | 46 | HardwareComposer::~HardwareComposer() = default; |
| 21 | 47 | ||
| 22 | u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp, | 48 | u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, |
| 23 | u32 frame_advance) { | 49 | Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) { |
| 24 | boost::container::small_vector<HwcLayer, 2> composition_stack; | 50 | boost::container::small_vector<HwcLayer, 2> composition_stack; |
| 25 | 51 | ||
| 26 | m_frame_number += frame_advance; | 52 | m_frame_number += frame_advance; |
| @@ -45,8 +71,11 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis | |||
| 45 | } | 71 | } |
| 46 | } | 72 | } |
| 47 | 73 | ||
| 74 | // Set default speed limit to 100%. | ||
| 75 | *out_speed_scale = 1.0f; | ||
| 76 | |||
| 48 | // Determine the number of vsync periods to wait before composing again. | 77 | // Determine the number of vsync periods to wait before composing again. |
| 49 | std::optional<u32> swap_interval{}; | 78 | std::optional<s32> swap_interval{}; |
| 50 | bool has_acquired_buffer{}; | 79 | bool has_acquired_buffer{}; |
| 51 | 80 | ||
| 52 | // Acquire all necessary framebuffers. | 81 | // Acquire all necessary framebuffers. |
| @@ -87,14 +116,15 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis | |||
| 87 | 116 | ||
| 88 | // We need to compose again either before this frame is supposed to | 117 | // We need to compose again either before this frame is supposed to |
| 89 | // be released, or exactly on the vsync period it should be released. | 118 | // be released, or exactly on the vsync period it should be released. |
| 90 | // | 119 | const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval); |
| 120 | |||
| 91 | // TODO: handle cases where swap intervals are relatively prime. So far, | 121 | // TODO: handle cases where swap intervals are relatively prime. So far, |
| 92 | // only swap intervals of 0, 1 and 2 have been observed, but if 3 were | 122 | // only swap intervals of 0, 1 and 2 have been observed, but if 3 were |
| 93 | // to be introduced, this would cause an issue. | 123 | // to be introduced, this would cause an issue. |
| 94 | if (swap_interval) { | 124 | if (swap_interval) { |
| 95 | swap_interval = std::min(*swap_interval, item.swap_interval); | 125 | swap_interval = std::min(*swap_interval, item_swap_interval); |
| 96 | } else { | 126 | } else { |
| 97 | swap_interval = item.swap_interval; | 127 | swap_interval = item_swap_interval; |
| 98 | } | 128 | } |
| 99 | } | 129 | } |
| 100 | 130 | ||
| @@ -111,13 +141,8 @@ u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdis | |||
| 111 | // Render MicroProfile. | 141 | // Render MicroProfile. |
| 112 | MicroProfileFlip(); | 142 | MicroProfileFlip(); |
| 113 | 143 | ||
| 114 | // If we advanced, then advance by at least 1 frame. | 144 | // Advance by at least one frame. |
| 115 | if (swap_interval) { | 145 | return swap_interval.value_or(1); |
| 116 | return std::max(*swap_interval, 1U); | ||
| 117 | } | ||
| 118 | |||
| 119 | // Otherwise, advance by exactly one frame. | ||
| 120 | return 1U; | ||
| 121 | } | 146 | } |
| 122 | 147 | ||
| 123 | void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { | 148 | void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { |
| @@ -146,7 +171,7 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer | |||
| 146 | 171 | ||
| 147 | // We succeeded, so set the new release frame info. | 172 | // We succeeded, so set the new release frame info. |
| 148 | framebuffer.release_frame_number = | 173 | framebuffer.release_frame_number = |
| 149 | m_frame_number + std::max(1U, framebuffer.item.swap_interval); | 174 | NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval); |
| 150 | framebuffer.is_acquired = true; | 175 | framebuffer.is_acquired = true; |
| 151 | 176 | ||
| 152 | return true; | 177 | 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: | |||
| 26 | explicit HardwareComposer(); | 26 | explicit HardwareComposer(); |
| 27 | ~HardwareComposer(); | 27 | ~HardwareComposer(); |
| 28 | 28 | ||
| 29 | u32 ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp, | 29 | u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, |
| 30 | u32 frame_advance); | 30 | Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance); |
| 31 | void RemoveLayerLocked(VI::Display& display, LayerId layer_id); | 31 | void RemoveLayerLocked(VI::Display& display, LayerId layer_id); |
| 32 | 32 | ||
| 33 | private: | 33 | 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() { | |||
| 291 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); | 291 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); |
| 292 | ASSERT(nvdisp); | 292 | ASSERT(nvdisp); |
| 293 | 293 | ||
| 294 | swap_interval = display.GetComposer().ComposeLocked(display, *nvdisp, swap_interval); | 294 | swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp, |
| 295 | swap_interval); | ||
| 295 | } | 296 | } |
| 296 | } | 297 | } |
| 297 | 298 | ||
| @@ -308,15 +309,16 @@ s64 Nvnflinger::GetNextTicks() const { | |||
| 308 | speed_scale = 0.01f; | 309 | speed_scale = 0.01f; |
| 309 | } | 310 | } |
| 310 | } | 311 | } |
| 312 | |||
| 313 | // Adjust by speed limit determined during composition. | ||
| 314 | speed_scale /= compose_speed_scale; | ||
| 315 | |||
| 311 | if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { | 316 | if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { |
| 312 | // Run at intended presentation rate during video playback. | 317 | // Run at intended presentation rate during video playback. |
| 313 | speed_scale = 1.f; | 318 | speed_scale = 1.f; |
| 314 | } | 319 | } |
| 315 | 320 | ||
| 316 | // As an extension, treat nonpositive swap interval as framerate multiplier. | 321 | const f32 effective_fps = 60.f / static_cast<f32>(swap_interval); |
| 317 | const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval) | ||
| 318 | : 60.f / static_cast<f32>(swap_interval); | ||
| 319 | |||
| 320 | return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); | 322 | return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); |
| 321 | } | 323 | } |
| 322 | 324 | ||
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: | |||
| 144 | u32 next_buffer_queue_id = 1; | 144 | u32 next_buffer_queue_id = 1; |
| 145 | 145 | ||
| 146 | s32 swap_interval = 1; | 146 | s32 swap_interval = 1; |
| 147 | f32 compose_speed_scale = 1.0f; | ||
| 147 | 148 | ||
| 148 | bool is_abandoned = false; | 149 | bool is_abandoned = false; |
| 149 | 150 | ||