c/multi: Be slightly smarter about late frames

This commit is contained in:
Jakob Bornecrantz 2022-03-29 19:01:29 +01:00
parent cf413a445f
commit e7713bf1e4
3 changed files with 67 additions and 32 deletions

View file

@ -177,15 +177,31 @@ wait_for_scheduled_free(struct multi_compositor *mc)
os_mutex_lock(&mc->slot_lock);
struct multi_compositor volatile *v_mc = mc;
// Block here if the scheduled slot is not clear.
while (mc->scheduled.active) {
while (v_mc->scheduled.active) {
// This frame is for the next frame, drop the old one no matter what.
if (time_is_within_half_ms(mc->progress.display_time_ns, mc->slot_next_frame_display)) {
U_LOG_W("Dropping old missed frame in favour for completed new frame");
break;
}
// Replace the scheduled frame if it's in the past.
uint64_t now_ns = os_monotonic_get_ns();
if (mc->scheduled.display_time_ns < now_ns) {
if (v_mc->scheduled.display_time_ns < now_ns) {
break;
}
U_LOG_D("next: %f (%" PRIu64 ")\nprogress: %f (%" PRIu64 ")\nscheduled: %f (%" PRIu64 ")\n",
time_ns_to_ms_f((int64_t)v_mc->slot_next_frame_display - now_ns), //
v_mc->slot_next_frame_display, //
time_ns_to_ms_f((int64_t)v_mc->progress.display_time_ns - now_ns), //
v_mc->progress.display_time_ns, //
time_ns_to_ms_f((int64_t)v_mc->scheduled.display_time_ns - now_ns), //
v_mc->scheduled.display_time_ns); //
os_mutex_unlock(&mc->slot_lock);
os_nanosleep(U_TIME_1MS_IN_NS);

View file

@ -153,6 +153,11 @@ struct multi_compositor
//! Lock for all of the slots.
struct os_mutex slot_lock;
/*!
* The next which the next frames to be picked up will be displayed.
*/
uint64_t slot_next_frame_display;
/*!
* Currently being transferred or waited on.
* Not protected by the slot lock as it is only touched by the client thread.

View file

@ -1,4 +1,4 @@
// Copyright 2019-2021, Collabora, Ltd.
// Copyright 2019-2022, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@ -282,10 +282,31 @@ transfer_layers_locked(struct multi_system_compositor *msc, uint64_t display_tim
}
static void
broadcast_timings(struct multi_system_compositor *msc,
uint64_t predicted_display_time_ns,
uint64_t predicted_display_period_ns,
uint64_t diff_ns)
broadcast_timings_to_clients(struct multi_system_compositor *msc, uint64_t predicted_display_time_ns)
{
COMP_TRACE_MARKER();
os_mutex_lock(&msc->list_and_timing_lock);
for (size_t i = 0; i < ARRAY_SIZE(msc->clients); i++) {
struct multi_compositor *mc = msc->clients[i];
if (mc == NULL) {
continue;
}
os_mutex_lock(&mc->slot_lock);
mc->slot_next_frame_display = predicted_display_time_ns;
os_mutex_unlock(&mc->slot_lock);
}
os_mutex_unlock(&msc->list_and_timing_lock);
}
static void
broadcast_timings_to_pacers(struct multi_system_compositor *msc,
uint64_t predicted_display_time_ns,
uint64_t predicted_display_period_ns,
uint64_t diff_ns)
{
COMP_TRACE_MARKER();
@ -302,6 +323,10 @@ broadcast_timings(struct multi_system_compositor *msc,
predicted_display_time_ns, //
predicted_display_period_ns, //
diff_ns); //
os_mutex_lock(&mc->slot_lock);
mc->slot_next_frame_display = predicted_display_time_ns;
os_mutex_unlock(&mc->slot_lock);
}
msc->last_timings.predicted_display_time_ns = predicted_display_time_ns;
@ -312,26 +337,10 @@ broadcast_timings(struct multi_system_compositor *msc,
}
static void
wait_frame(struct xrt_compositor *xc,
int64_t *out_frame_id,
uint64_t *out_wake_time_ns,
uint64_t *out_predicted_gpu_time_ns,
uint64_t *out_predicted_display_time_ns,
uint64_t *out_predicted_display_period_ns)
wait_frame(struct xrt_compositor *xc, int64_t frame_id, uint64_t wake_up_time_ns)
{
COMP_TRACE_MARKER();
int64_t frame_id = -1;
uint64_t wake_up_time_ns = 0;
xrt_comp_predict_frame( //
xc, //
&frame_id, //
&wake_up_time_ns, //
out_predicted_gpu_time_ns, //
out_predicted_display_time_ns, //
out_predicted_display_period_ns); //
uint64_t now_ns = os_monotonic_get_ns();
if (now_ns < wake_up_time_ns) {
os_nanosleep(wake_up_time_ns - now_ns);
@ -340,9 +349,6 @@ wait_frame(struct xrt_compositor *xc,
now_ns = os_monotonic_get_ns();
xrt_comp_mark_frame(xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, now_ns);
*out_frame_id = frame_id;
*out_wake_time_ns = wake_up_time_ns;
}
static int
@ -361,24 +367,32 @@ multi_main_loop(struct multi_system_compositor *msc)
while (os_thread_helper_is_running_locked(&msc->oth)) {
os_thread_helper_unlock(&msc->oth);
int64_t frame_id;
uint64_t wake_time_ns = 0;
int64_t frame_id = -1;
uint64_t wake_up_time_ns = 0;
uint64_t predicted_gpu_time_ns = 0;
uint64_t predicted_display_time_ns = 0;
uint64_t predicted_display_period_ns = 0;
wait_frame( //
// Get the information for the next frame.
xrt_comp_predict_frame( //
xc, //
&frame_id, //
&wake_time_ns, //
&wake_up_time_ns, //
&predicted_gpu_time_ns, //
&predicted_display_time_ns, //
&predicted_display_period_ns); //
// Do this as soon as we have the new display time.
broadcast_timings_to_clients(msc, predicted_display_time_ns);
// Now we can wait.
wait_frame(xc, frame_id, wake_up_time_ns);
uint64_t now_ns = os_monotonic_get_ns();
uint64_t diff_ns = predicted_display_time_ns - now_ns;
broadcast_timings(msc, predicted_display_time_ns, predicted_display_period_ns, diff_ns);
// Now we know the diff, broadcast to pacers.
broadcast_timings_to_pacers(msc, predicted_display_time_ns, predicted_display_period_ns, diff_ns);
xrt_comp_begin_frame(xc, frame_id);
xrt_comp_layer_begin(xc, frame_id, 0, 0);