summaryrefslogtreecommitdiff
path: root/src/core/hle/service/nvnflinger
diff options
context:
space:
mode:
authorGravatar Liam2024-01-23 10:19:55 -0500
committerGravatar Liam2024-01-31 11:27:21 -0500
commit2c421a7046c5ff1fdb8319f097a89a331907baf6 (patch)
treeb33e0baabf3aa23fd6c800c9e5786466548b9fb1 /src/core/hle/service/nvnflinger
parentnvnflinger/gpu: implement layer stack composition (diff)
downloadyuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.gz
yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.xz
yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.zip
hardware_composer: implement speed limit extensions
Diffstat (limited to 'src/core/hle/service/nvnflinger')
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item.h2
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.cpp53
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.h4
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp12
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h1
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
17namespace Service::Nvnflinger { 17namespace Service::Nvnflinger {
18 18
19namespace {
20
21s32 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
19HardwareComposer::HardwareComposer() = default; 45HardwareComposer::HardwareComposer() = default;
20HardwareComposer::~HardwareComposer() = default; 46HardwareComposer::~HardwareComposer() = default;
21 47
22u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp, 48u32 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
123void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { 148void 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
33private: 33private:
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