summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiam <byteslice@airmail.cc>2024-01-23 16:19:55 +0100
committerLiam <byteslice@airmail.cc>2024-01-31 17:27:21 +0100
commit2c421a7046c5ff1fdb8319f097a89a331907baf6 (patch)
treeb33e0baabf3aa23fd6c800c9e5786466548b9fb1
parentnvnflinger/gpu: implement layer stack composition (diff)
downloadyuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar
yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.gz
yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.bz2
yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.lz
yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.xz
yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.tar.zst
yuzu-2c421a7046c5ff1fdb8319f097a89a331907baf6.zip
-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:
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<f32>(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<f32>(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<HwcLayer, 2> 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<u32> swap_interval{};
+ std::optional<s32> 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<Nvidia::Devices::nvdisp_disp0>(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<f32>(1 - swap_interval)
- : 60.f / static_cast<f32>(swap_interval);
-
+ const f32 effective_fps = 60.f / static_cast<f32>(swap_interval);
return static_cast<s64>(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;