diff --git a/src/xrt/auxiliary/util/u_pacing.h b/src/xrt/auxiliary/util/u_pacing.h index 26c2b9a59..0501f6ac0 100644 --- a/src/xrt/auxiliary/util/u_pacing.h +++ b/src/xrt/auxiliary/util/u_pacing.h @@ -62,6 +62,8 @@ struct u_pacing_compositor * Predict the next frame. * * @param[in] upc The compositor pacing helper. + * @param[in] now_ns The current timestamp in nanoseconds, nominally from @ref + * os_monotonic_get_ns * @param[out] out_frame_id Id used to refer to this frame again. * @param[out] out_wake_up_time_ns When should the compositor wake up. * @param[out] out_desired_present_time_ns The GPU should start scanning out at this time. @@ -73,6 +75,7 @@ struct u_pacing_compositor * @see @ref frame-pacing. */ void (*predict)(struct u_pacing_compositor *upc, + uint64_t now_ns, int64_t *out_frame_id, uint64_t *out_wake_up_time_ns, uint64_t *out_desired_present_time_ns, @@ -118,6 +121,8 @@ struct u_pacing_compositor * actual_present_time_ns if a @p desired_present_time_ns was passed. * @param[in] present_margin_ns How "early" present happened compared to when it needed to happen in * order to hit @p earliestPresentTime. + * @param[in] when_ns The time when we got the info, nominally from @ref + * os_monotonic_get_ns * * @see @ref frame-pacing. */ @@ -126,7 +131,8 @@ struct u_pacing_compositor uint64_t desired_present_time_ns, uint64_t actual_present_time_ns, uint64_t earliest_present_time_ns, - uint64_t present_margin_ns); + uint64_t present_margin_ns, + uint64_t when_ns); /*! * Destroy this u_pacing_compositor. @@ -144,6 +150,7 @@ struct u_pacing_compositor */ static inline void u_pc_predict(struct u_pacing_compositor *upc, + uint64_t now_ns, int64_t *out_frame_id, uint64_t *out_wake_up_time_ns, uint64_t *out_desired_present_time_ns, @@ -153,6 +160,7 @@ u_pc_predict(struct u_pacing_compositor *upc, uint64_t *out_min_display_period_ns) { upc->predict(upc, // + now_ns, // out_frame_id, // out_wake_up_time_ns, // out_desired_present_time_ns, // @@ -190,10 +198,11 @@ u_pc_info(struct u_pacing_compositor *upc, uint64_t desired_present_time_ns, uint64_t actual_present_time_ns, uint64_t earliest_present_time_ns, - uint64_t present_margin_ns) + uint64_t present_margin_ns, + uint64_t when_ns) { upc->info(upc, frame_id, desired_present_time_ns, actual_present_time_ns, earliest_present_time_ns, - present_margin_ns); + present_margin_ns, when_ns); } /*! @@ -244,12 +253,15 @@ struct u_pacing_app * should wait till `out_wake_up_time`. * * @param upa Render timing helper. + * @param[in] now_ns The current timestamp in nanoseconds, nominally from @ref + * os_monotonic_get_ns * @param[out] out_frame_id Frame ID of this predicted frame. * @param[out] out_wake_up_time When the client should be woken up. * @param[out] out_predicted_display_time Predicted display time. * @param[out] out_predicted_display_period Predicted display period. */ void (*predict)(struct u_pacing_app *upa, + uint64_t now_ns, int64_t *out_frame_id, uint64_t *out_wake_up_time, uint64_t *out_predicted_display_time, @@ -272,8 +284,9 @@ struct u_pacing_app * * @param upa Render timing helper. * @param[in] frame_id The frame ID to mark as discarded. + * @param[in] when_ns The time when it was discarded, nominally from @ref os_monotonic_get_ns */ - void (*mark_discarded)(struct u_pacing_app *upa, int64_t frame_id); + void (*mark_discarded)(struct u_pacing_app *upa, int64_t frame_id, uint64_t when_ns); /*! * A frame has been delivered from the client, see `xrEndFrame`. The GPU might @@ -281,8 +294,9 @@ struct u_pacing_app * * @param upa Render timing helper. * @param[in] frame_id The frame ID to mark as delivered. + * @param[in] when_ns The time when it was delivered, nominally from @ref os_monotonic_get_ns */ - void (*mark_delivered)(struct u_pacing_app *upa, int64_t frame_id); + void (*mark_delivered)(struct u_pacing_app *upa, int64_t frame_id, uint64_t when_ns); /*! * Add a new sample point from the main render loop. @@ -323,12 +337,14 @@ struct u_pacing_app */ static inline void u_pa_predict(struct u_pacing_app *upa, + uint64_t now_ns, int64_t *out_frame_id, uint64_t *out_wake_up_time, uint64_t *out_predicted_display_time, uint64_t *out_predicted_display_period) { - upa->predict(upa, out_frame_id, out_wake_up_time, out_predicted_display_time, out_predicted_display_period); + upa->predict(upa, now_ns, out_frame_id, out_wake_up_time, out_predicted_display_time, + out_predicted_display_period); } /*! @@ -354,9 +370,9 @@ u_pa_mark_point(struct u_pacing_app *upa, int64_t frame_id, enum u_timing_point * @ingroup aux_pacing */ static inline void -u_pa_mark_discarded(struct u_pacing_app *upa, int64_t frame_id) +u_pa_mark_discarded(struct u_pacing_app *upa, int64_t frame_id, uint64_t when_ns) { - upa->mark_discarded(upa, frame_id); + upa->mark_discarded(upa, frame_id, when_ns); } /*! @@ -368,9 +384,9 @@ u_pa_mark_discarded(struct u_pacing_app *upa, int64_t frame_id) * @ingroup aux_pacing */ static inline void -u_pa_mark_delivered(struct u_pacing_app *upa, int64_t frame_id) +u_pa_mark_delivered(struct u_pacing_app *upa, int64_t frame_id, uint64_t when_ns) { - upa->mark_delivered(upa, frame_id); + upa->mark_delivered(upa, frame_id, when_ns); } /*! @@ -477,11 +493,15 @@ u_pc_display_timing_create(uint64_t estimated_frame_period_ns, * * When you cannot get display timing information, use this. * + * @param[in] estimated_frame_period_ns The estimated duration/period of a frame in nanoseconds. + * @param[in] now_ns The current timestamp in nanoseconds, nominally from @ref os_monotonic_get_ns + * @param[out] out_upc The pointer to populate with the created compositor pacing helper + * * @ingroup aux_pacing * @see u_pacing_compositor */ xrt_result_t -u_pc_fake_create(uint64_t estimated_frame_period_ns, struct u_pacing_compositor **out_upc); +u_pc_fake_create(uint64_t estimated_frame_period_ns, uint64_t now_ns, struct u_pacing_compositor **out_upc); /*! * Creates a new application pacing helper. diff --git a/src/xrt/auxiliary/util/u_pacing_app.c b/src/xrt/auxiliary/util/u_pacing_app.c index 8063420e5..9e83d354b 100644 --- a/src/xrt/auxiliary/util/u_pacing_app.c +++ b/src/xrt/auxiliary/util/u_pacing_app.c @@ -188,11 +188,8 @@ calc_period(const struct pacing_app *pa) } static uint64_t -predict_display_time(const struct pacing_app *pa, uint64_t period_ns) +predict_display_time(const struct pacing_app *pa, uint64_t now_ns, uint64_t period_ns) { - // Now - uint64_t now_ns = os_monotonic_get_ns(); - // Total app and compositor time to produce a frame uint64_t app_and_compositor_time_ns = total_app_and_compositor_time_ns(pa); @@ -222,6 +219,7 @@ predict_display_time(const struct pacing_app *pa, uint64_t period_ns) static void pa_predict(struct u_pacing_app *upa, + uint64_t now_ns, int64_t *out_frame_id, uint64_t *out_wake_up_time, uint64_t *out_predicted_display_time, @@ -235,7 +233,7 @@ pa_predict(struct u_pacing_app *upa, DEBUG_PRINT_FRAME_ID(); uint64_t period_ns = calc_period(pa); - uint64_t predict_ns = predict_display_time(pa, period_ns); + uint64_t predict_ns = predict_display_time(pa, now_ns, period_ns); // When should the client wake up. uint64_t wake_up_time_ns = predict_ns - total_app_and_compositor_time_ns(pa); // When the client should deliver the frame to us. @@ -255,7 +253,7 @@ pa_predict(struct u_pacing_app *upa, pa->frames[index].frame_id = frame_id; pa->frames[index].predicted_delivery_time_ns = delivery_time_ns; pa->frames[index].predicted_display_period_ns = period_ns; - pa->frames[index].when.predicted_ns = os_monotonic_get_ns(); + pa->frames[index].when.predicted_ns = now_ns; } static void @@ -278,7 +276,7 @@ pa_mark_point(struct u_pacing_app *upa, int64_t frame_id, enum u_timing_point po case U_TIMING_POINT_BEGIN: assert(pa->frames[index].state == U_RT_WAIT_LEFT); - pa->frames[index].when.begin_ns = os_monotonic_get_ns(); + pa->frames[index].when.begin_ns = when_ns; pa->frames[index].state = U_RT_BEGUN; break; case U_TIMING_POINT_SUBMIT: @@ -287,7 +285,7 @@ pa_mark_point(struct u_pacing_app *upa, int64_t frame_id, enum u_timing_point po } static void -pa_mark_discarded(struct u_pacing_app *upa, int64_t frame_id) +pa_mark_discarded(struct u_pacing_app *upa, int64_t frame_id, uint64_t when_ns) { struct pacing_app *pa = pacing_app(upa); @@ -297,13 +295,13 @@ pa_mark_discarded(struct u_pacing_app *upa, int64_t frame_id) assert(pa->frames[index].frame_id == frame_id); assert(pa->frames[index].state == U_RT_WAIT_LEFT || pa->frames[index].state == U_RT_BEGUN); - pa->frames[index].when.delivered_ns = os_monotonic_get_ns(); + pa->frames[index].when.delivered_ns = when_ns; pa->frames[index].state = U_PA_READY; pa->frames[index].frame_id = -1; } static void -pa_mark_delivered(struct u_pacing_app *upa, int64_t frame_id) +pa_mark_delivered(struct u_pacing_app *upa, int64_t frame_id, uint64_t when_ns) { struct pacing_app *pa = pacing_app(upa); @@ -314,17 +312,15 @@ pa_mark_delivered(struct u_pacing_app *upa, int64_t frame_id) assert(f->frame_id == frame_id); assert(f->state == U_RT_BEGUN); - uint64_t now_ns = os_monotonic_get_ns(); - // Update all data. - f->when.delivered_ns = now_ns; + f->when.delivered_ns = when_ns; /* * Process data. */ - int64_t diff_ns = f->predicted_delivery_time_ns - now_ns; + int64_t diff_ns = f->predicted_delivery_time_ns - when_ns; bool late = false; if (diff_ns < 0) { diff_ns = -diff_ns; diff --git a/src/xrt/auxiliary/util/u_pacing_compositor.c b/src/xrt/auxiliary/util/u_pacing_compositor.c index 4b308afeb..03bee8b9d 100644 --- a/src/xrt/auxiliary/util/u_pacing_compositor.c +++ b/src/xrt/auxiliary/util/u_pacing_compositor.c @@ -259,13 +259,12 @@ get_latest_frame_with_state_at_least(struct display_timing *dt, enum frame_state * frame::desired_present_time_ns (with a crude estimate) and frame::when_predict_ns. */ static struct frame * -do_clean_slate_frame(struct display_timing *dt) +do_clean_slate_frame(struct display_timing *dt, uint64_t now_ns) { struct frame *f = create_frame(dt, STATE_PREDICTED); - uint64_t now_ns = os_monotonic_get_ns(); // Wild shot in the dark. - uint64_t the_time_ns = os_monotonic_get_ns() + dt->frame_period_ns * 10; + uint64_t the_time_ns = now_ns + dt->frame_period_ns * 10; f->when_predict_ns = now_ns; f->desired_present_time_ns = the_time_ns; @@ -277,9 +276,8 @@ do_clean_slate_frame(struct display_timing *dt) * prediction in it. */ static struct frame * -walk_forward_through_frames(struct display_timing *dt, uint64_t last_present_time_ns) +walk_forward_through_frames(struct display_timing *dt, uint64_t last_present_time_ns, uint64_t now_ns) { - uint64_t now_ns = os_monotonic_get_ns(); // This is the earliest possible time we could present, assuming rendering still must take place. uint64_t from_time_ns = now_ns + calc_total_app_time(dt); uint64_t desired_present_time_ns = last_present_time_ns + dt->frame_period_ns; @@ -306,17 +304,17 @@ walk_forward_through_frames(struct display_timing *dt, uint64_t last_present_tim } static struct frame * -predict_next_frame(struct display_timing *dt) +predict_next_frame(struct display_timing *dt, uint64_t now_ns) { struct frame *f = NULL; // Last earliest display time, can be zero. struct frame *last_predicted = get_latest_frame_with_state_at_least(dt, STATE_PREDICTED); struct frame *last_completed = get_latest_frame_with_state_at_least(dt, STATE_INFO); if (last_predicted == NULL && last_completed == NULL) { - f = do_clean_slate_frame(dt); + f = do_clean_slate_frame(dt, now_ns); } else if (last_completed == last_predicted) { // Very high propability that we missed a frame. - f = walk_forward_through_frames(dt, last_completed->earliest_present_time_ns); + f = walk_forward_through_frames(dt, last_completed->earliest_present_time_ns, now_ns); } else if (last_completed != NULL) { assert(last_predicted != NULL); assert(last_predicted->frame_id > last_completed->frame_id); @@ -342,11 +340,11 @@ predict_next_frame(struct display_timing *dt) diff_id = 1; } - f = walk_forward_through_frames(dt, adjusted_last_present_time_ns); + f = walk_forward_through_frames(dt, adjusted_last_present_time_ns, now_ns); } else { assert(last_predicted != NULL); - f = walk_forward_through_frames(dt, last_predicted->predicted_display_time_ns); + f = walk_forward_through_frames(dt, last_predicted->predicted_display_time_ns, now_ns); } f->predicted_display_time_ns = calc_display_time_from_present_time(dt, f->desired_present_time_ns); @@ -404,6 +402,7 @@ adjust_app_time(struct display_timing *dt, struct frame *f) static void dt_predict(struct u_pacing_compositor *upc, + uint64_t now_ns, int64_t *out_frame_id, uint64_t *out_wake_up_time_ns, uint64_t *out_desired_present_time_ns, @@ -414,7 +413,7 @@ dt_predict(struct u_pacing_compositor *upc, { struct display_timing *dt = display_timing(upc); - struct frame *f = predict_next_frame(dt); + struct frame *f = predict_next_frame(dt, now_ns); uint64_t wake_up_time_ns = f->wake_up_time_ns; uint64_t desired_present_time_ns = f->desired_present_time_ns; @@ -464,7 +463,8 @@ dt_info(struct u_pacing_compositor *upc, uint64_t desired_present_time_ns, uint64_t actual_present_time_ns, uint64_t earliest_present_time_ns, - uint64_t present_margin_ns) + uint64_t present_margin_ns, + uint64_t when_ns) { struct display_timing *dt = display_timing(upc); (void)dt; @@ -481,7 +481,7 @@ dt_info(struct u_pacing_compositor *upc, assert(f->state == STATE_SUBMITTED); assert(f->desired_present_time_ns == desired_present_time_ns); - f->when_infoed_ns = os_monotonic_get_ns(); + f->when_infoed_ns = when_ns; f->actual_present_time_ns = actual_present_time_ns; f->earliest_present_time_ns = earliest_present_time_ns; f->present_margin_ns = present_margin_ns; diff --git a/src/xrt/auxiliary/util/u_pacing_compositor_fake.c b/src/xrt/auxiliary/util/u_pacing_compositor_fake.c index d192834aa..aca64064c 100644 --- a/src/xrt/auxiliary/util/u_pacing_compositor_fake.c +++ b/src/xrt/auxiliary/util/u_pacing_compositor_fake.c @@ -69,10 +69,9 @@ fake_timing(struct u_pacing_compositor *upc) } static uint64_t -predict_next_frame(struct fake_timing *ft) +predict_next_frame(struct fake_timing *ft, uint64_t now_ns) { uint64_t time_needed_ns = ft->present_offset_ns + ft->app_time_ns; - uint64_t now_ns = os_monotonic_get_ns(); uint64_t predicted_display_time_ns = ft->last_display_time_ns + ft->frame_period_ns; while (now_ns + time_needed_ns > predicted_display_time_ns) { @@ -98,6 +97,7 @@ get_percent_of_time(uint64_t time_ns, uint32_t fraction_percent) static void pc_predict(struct u_pacing_compositor *upc, + uint64_t now_ns, int64_t *out_frame_id, uint64_t *out_wake_up_time_ns, uint64_t *out_desired_present_time_ns, @@ -109,7 +109,7 @@ pc_predict(struct u_pacing_compositor *upc, struct fake_timing *ft = fake_timing(upc); int64_t frame_id = ft->frame_id_generator++; - uint64_t predicted_display_time_ns = predict_next_frame(ft); + uint64_t predicted_display_time_ns = predict_next_frame(ft, now_ns); uint64_t desired_present_time_ns = predicted_display_time_ns - ft->present_offset_ns; uint64_t wake_up_time_ns = desired_present_time_ns - ft->app_time_ns; uint64_t present_slop_ns = U_TIME_HALF_MS_IN_NS; @@ -143,7 +143,8 @@ pc_info(struct u_pacing_compositor *upc, uint64_t desired_present_time_ns, uint64_t actual_present_time_ns, uint64_t earliest_present_time_ns, - uint64_t present_margin_ns) + uint64_t present_margin_ns, + uint64_t when_ns) { /* * The compositor might call this function because it selected the @@ -166,7 +167,7 @@ pc_destroy(struct u_pacing_compositor *upc) */ xrt_result_t -u_pc_fake_create(uint64_t estimated_frame_period_ns, struct u_pacing_compositor **out_uft) +u_pc_fake_create(uint64_t estimated_frame_period_ns, uint64_t now_ns, struct u_pacing_compositor **out_uft) { struct fake_timing *ft = U_TYPED_CALLOC(struct fake_timing); ft->base.predict = pc_predict; @@ -185,7 +186,7 @@ u_pc_fake_create(uint64_t estimated_frame_period_ns, struct u_pacing_compositor ft->app_time_ns = get_percent_of_time(estimated_frame_period_ns, 20); // Make the next display time be in the future. - ft->last_display_time_ns = os_monotonic_get_ns() + U_TIME_1MS_IN_NS * 50.0; + ft->last_display_time_ns = now_ns + U_TIME_1MS_IN_NS * 50.0; // Return value. *out_uft = &ft->base; diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index 23e0d0703..8d2bec1ea 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -123,13 +123,14 @@ comp_target_swapchain_create_images(struct comp_target *ct, VkBool32 supported; VkResult ret; + uint64_t now_ns = os_monotonic_get_ns(); // Some platforms really don't like the display_timing code. bool use_display_timing_if_available = cts->timing_usage == COMP_TARGET_USE_DISPLAY_IF_AVAILABLE; if (cts->upc == NULL && use_display_timing_if_available && vk->has_GOOGLE_display_timing) { u_pc_display_timing_create(ct->c->settings.nominal_frame_interval_ns, &U_PC_DISPLAY_TIMING_CONFIG_DEFAULT, &cts->upc); } else if (cts->upc == NULL) { - u_pc_fake_create(ct->c->settings.nominal_frame_interval_ns, &cts->upc); + u_pc_fake_create(ct->c->settings.nominal_frame_interval_ns, now_ns, &cts->upc); } // Free old image views. @@ -598,8 +599,10 @@ comp_target_swapchain_calc_frame_pacing(struct comp_target *ct, uint64_t predicted_display_time_ns = 0; uint64_t predicted_display_period_ns = 0; uint64_t min_display_period_ns = 0; + uint64_t now_ns = os_monotonic_get_ns(); u_pc_predict(cts->upc, // + now_ns, // &frame_id, // &wake_up_time_ns, // &desired_present_time_ns, // @@ -670,14 +673,15 @@ comp_target_swapchain_update_timings(struct comp_target *ct) cts->swapchain.handle, // &count, // timings); // - + uint64_t now_ns = os_monotonic_get_ns(); for (uint32_t i = 0; i < count; i++) { u_pc_info(cts->upc, // timings[i].presentID, // timings[i].desiredPresentTime, // timings[i].actualPresentTime, // timings[i].earliestPresentTime, // - timings[i].presentMargin); // + timings[i].presentMargin, // + now_ns); // } free(timings); return VK_SUCCESS; diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c index 7f8a5c191..dd21f4b20 100644 --- a/src/xrt/compositor/multi/comp_multi_compositor.c +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -194,11 +194,12 @@ multi_compositor_predict_frame(struct xrt_compositor *xc, COMP_TRACE_MARKER(); struct multi_compositor *mc = multi_compositor(xc); - + uint64_t now_ns = os_monotonic_get_ns(); os_mutex_lock(&mc->msc->list_and_timing_lock); u_pa_predict( // mc->upa, // + now_ns, // out_frame_id, // out_wake_time_ns, // out_predicted_display_time_ns, // @@ -290,9 +291,10 @@ multi_compositor_discard_frame(struct xrt_compositor *xc, int64_t frame_id) COMP_TRACE_MARKER(); struct multi_compositor *mc = multi_compositor(xc); + uint64_t now_ns = os_monotonic_get_ns(); os_mutex_lock(&mc->msc->list_and_timing_lock); - u_pa_mark_discarded(mc->upa, frame_id); + u_pa_mark_discarded(mc->upa, frame_id, now_ns); os_mutex_unlock(&mc->msc->list_and_timing_lock); return XRT_SUCCESS; @@ -507,9 +509,10 @@ multi_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_g } wait_for_scheduled_free(mc); + uint64_t now_ns = os_monotonic_get_ns(); os_mutex_lock(&mc->msc->list_and_timing_lock); - u_pa_mark_delivered(mc->upa, frame_id); + u_pa_mark_delivered(mc->upa, frame_id, now_ns); os_mutex_unlock(&mc->msc->list_and_timing_lock); return XRT_SUCCESS;