diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c index 2d0e59f7b..5678ca919 100644 --- a/src/xrt/compositor/multi/comp_multi_compositor.c +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -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); diff --git a/src/xrt/compositor/multi/comp_multi_private.h b/src/xrt/compositor/multi/comp_multi_private.h index a67522bf5..2a07cb47d 100644 --- a/src/xrt/compositor/multi/comp_multi_private.h +++ b/src/xrt/compositor/multi/comp_multi_private.h @@ -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. diff --git a/src/xrt/compositor/multi/comp_multi_system.c b/src/xrt/compositor/multi/comp_multi_system.c index 4bf63ff64..2625f1ead 100644 --- a/src/xrt/compositor/multi/comp_multi_system.c +++ b/src/xrt/compositor/multi/comp_multi_system.c @@ -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);