hardware_composer: implement speed limit extensions
This commit is contained in:
parent
a595e9e8a7
commit
2c421a7046
|
@ -40,7 +40,7 @@ public:
|
||||||
bool is_droppable{};
|
bool is_droppable{};
|
||||||
bool acquire_called{};
|
bool acquire_called{};
|
||||||
bool transform_to_display_inverse{};
|
bool transform_to_display_inverse{};
|
||||||
u32 swap_interval{};
|
s32 swap_interval{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::android
|
} // namespace Service::android
|
||||||
|
|
|
@ -16,11 +16,37 @@
|
||||||
|
|
||||||
namespace Service::Nvnflinger {
|
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;
|
||||||
HardwareComposer::~HardwareComposer() = default;
|
HardwareComposer::~HardwareComposer() = default;
|
||||||
|
|
||||||
u32 HardwareComposer::ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp,
|
u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
|
||||||
u32 frame_advance) {
|
Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) {
|
||||||
boost::container::small_vector<HwcLayer, 2> composition_stack;
|
boost::container::small_vector<HwcLayer, 2> composition_stack;
|
||||||
|
|
||||||
m_frame_number += frame_advance;
|
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.
|
// 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{};
|
bool has_acquired_buffer{};
|
||||||
|
|
||||||
// Acquire all necessary framebuffers.
|
// 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
|
// We need to compose again either before this frame is supposed to
|
||||||
// be released, or exactly on the vsync period it should be released.
|
// 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,
|
// 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
|
||||||
// to be introduced, this would cause an issue.
|
// to be introduced, this would cause an issue.
|
||||||
if (swap_interval) {
|
if (swap_interval) {
|
||||||
swap_interval = std::min(*swap_interval, item.swap_interval);
|
swap_interval = std::min(*swap_interval, item_swap_interval);
|
||||||
} else {
|
} 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.
|
// Render MicroProfile.
|
||||||
MicroProfileFlip();
|
MicroProfileFlip();
|
||||||
|
|
||||||
// If we advanced, then advance by at least 1 frame.
|
// Advance by at least one frame.
|
||||||
if (swap_interval) {
|
return swap_interval.value_or(1);
|
||||||
return std::max(*swap_interval, 1U);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, advance by exactly one frame.
|
|
||||||
return 1U;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {
|
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.
|
// We succeeded, so set the new release frame info.
|
||||||
framebuffer.release_frame_number =
|
framebuffer.release_frame_number =
|
||||||
m_frame_number + std::max(1U, framebuffer.item.swap_interval);
|
NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval);
|
||||||
framebuffer.is_acquired = true;
|
framebuffer.is_acquired = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -26,8 +26,8 @@ public:
|
||||||
explicit HardwareComposer();
|
explicit HardwareComposer();
|
||||||
~HardwareComposer();
|
~HardwareComposer();
|
||||||
|
|
||||||
u32 ComposeLocked(VI::Display& display, Nvidia::Devices::nvdisp_disp0& nvdisp,
|
u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
|
||||||
u32 frame_advance);
|
Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance);
|
||||||
void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
|
void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -291,7 +291,8 @@ void Nvnflinger::Compose() {
|
||||||
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
|
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
|
||||||
ASSERT(nvdisp);
|
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;
|
speed_scale = 0.01f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust by speed limit determined during composition.
|
||||||
|
speed_scale /= compose_speed_scale;
|
||||||
|
|
||||||
if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
|
if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
|
||||||
// Run at intended presentation rate during video playback.
|
// Run at intended presentation rate during video playback.
|
||||||
speed_scale = 1.f;
|
speed_scale = 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// As an extension, treat nonpositive swap interval as framerate multiplier.
|
const f32 effective_fps = 60.f / static_cast<f32>(swap_interval);
|
||||||
const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
|
|
||||||
: 60.f / static_cast<f32>(swap_interval);
|
|
||||||
|
|
||||||
return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
|
return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,7 @@ private:
|
||||||
u32 next_buffer_queue_id = 1;
|
u32 next_buffer_queue_id = 1;
|
||||||
|
|
||||||
s32 swap_interval = 1;
|
s32 swap_interval = 1;
|
||||||
|
f32 compose_speed_scale = 1.0f;
|
||||||
|
|
||||||
bool is_abandoned = false;
|
bool is_abandoned = false;
|
||||||
|
|
||||||
|
|
Reference in New Issue