mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-02-03 12:28:07 +00:00
a/util: Have all timestamps be injected into pacing.
No more calling os_monotonic_get_ns() inside the pacing helpers. Much better testability.
This commit is contained in:
parent
40caa24d4b
commit
a2e1eb7e75
src/xrt
auxiliary/util
compositor
|
@ -62,6 +62,8 @@ struct u_pacing_compositor
|
||||||
* Predict the next frame.
|
* Predict the next frame.
|
||||||
*
|
*
|
||||||
* @param[in] upc The compositor pacing helper.
|
* @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_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_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.
|
* @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.
|
* @see @ref frame-pacing.
|
||||||
*/
|
*/
|
||||||
void (*predict)(struct u_pacing_compositor *upc,
|
void (*predict)(struct u_pacing_compositor *upc,
|
||||||
|
uint64_t now_ns,
|
||||||
int64_t *out_frame_id,
|
int64_t *out_frame_id,
|
||||||
uint64_t *out_wake_up_time_ns,
|
uint64_t *out_wake_up_time_ns,
|
||||||
uint64_t *out_desired_present_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.
|
* 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
|
* @param[in] present_margin_ns How "early" present happened compared to when it needed to happen in
|
||||||
* order to hit @p earliestPresentTime.
|
* 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.
|
* @see @ref frame-pacing.
|
||||||
*/
|
*/
|
||||||
|
@ -126,7 +131,8 @@ struct u_pacing_compositor
|
||||||
uint64_t desired_present_time_ns,
|
uint64_t desired_present_time_ns,
|
||||||
uint64_t actual_present_time_ns,
|
uint64_t actual_present_time_ns,
|
||||||
uint64_t earliest_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.
|
* Destroy this u_pacing_compositor.
|
||||||
|
@ -144,6 +150,7 @@ struct u_pacing_compositor
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
u_pc_predict(struct u_pacing_compositor *upc,
|
u_pc_predict(struct u_pacing_compositor *upc,
|
||||||
|
uint64_t now_ns,
|
||||||
int64_t *out_frame_id,
|
int64_t *out_frame_id,
|
||||||
uint64_t *out_wake_up_time_ns,
|
uint64_t *out_wake_up_time_ns,
|
||||||
uint64_t *out_desired_present_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)
|
uint64_t *out_min_display_period_ns)
|
||||||
{
|
{
|
||||||
upc->predict(upc, //
|
upc->predict(upc, //
|
||||||
|
now_ns, //
|
||||||
out_frame_id, //
|
out_frame_id, //
|
||||||
out_wake_up_time_ns, //
|
out_wake_up_time_ns, //
|
||||||
out_desired_present_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 desired_present_time_ns,
|
||||||
uint64_t actual_present_time_ns,
|
uint64_t actual_present_time_ns,
|
||||||
uint64_t earliest_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,
|
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`.
|
* should wait till `out_wake_up_time`.
|
||||||
*
|
*
|
||||||
* @param upa Render timing helper.
|
* @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_frame_id Frame ID of this predicted frame.
|
||||||
* @param[out] out_wake_up_time When the client should be woken up.
|
* @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_time Predicted display time.
|
||||||
* @param[out] out_predicted_display_period Predicted display period.
|
* @param[out] out_predicted_display_period Predicted display period.
|
||||||
*/
|
*/
|
||||||
void (*predict)(struct u_pacing_app *upa,
|
void (*predict)(struct u_pacing_app *upa,
|
||||||
|
uint64_t now_ns,
|
||||||
int64_t *out_frame_id,
|
int64_t *out_frame_id,
|
||||||
uint64_t *out_wake_up_time,
|
uint64_t *out_wake_up_time,
|
||||||
uint64_t *out_predicted_display_time,
|
uint64_t *out_predicted_display_time,
|
||||||
|
@ -272,8 +284,9 @@ struct u_pacing_app
|
||||||
*
|
*
|
||||||
* @param upa Render timing helper.
|
* @param upa Render timing helper.
|
||||||
* @param[in] frame_id The frame ID to mark as discarded.
|
* @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
|
* 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 upa Render timing helper.
|
||||||
* @param[in] frame_id The frame ID to mark as delivered.
|
* @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.
|
* Add a new sample point from the main render loop.
|
||||||
|
@ -323,12 +337,14 @@ struct u_pacing_app
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
u_pa_predict(struct u_pacing_app *upa,
|
u_pa_predict(struct u_pacing_app *upa,
|
||||||
|
uint64_t now_ns,
|
||||||
int64_t *out_frame_id,
|
int64_t *out_frame_id,
|
||||||
uint64_t *out_wake_up_time,
|
uint64_t *out_wake_up_time,
|
||||||
uint64_t *out_predicted_display_time,
|
uint64_t *out_predicted_display_time,
|
||||||
uint64_t *out_predicted_display_period)
|
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
|
* @ingroup aux_pacing
|
||||||
*/
|
*/
|
||||||
static inline void
|
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
|
* @ingroup aux_pacing
|
||||||
*/
|
*/
|
||||||
static inline void
|
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.
|
* 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
|
* @ingroup aux_pacing
|
||||||
* @see u_pacing_compositor
|
* @see u_pacing_compositor
|
||||||
*/
|
*/
|
||||||
xrt_result_t
|
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.
|
* Creates a new application pacing helper.
|
||||||
|
|
|
@ -188,11 +188,8 @@ calc_period(const struct pacing_app *pa)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t
|
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
|
// Total app and compositor time to produce a frame
|
||||||
uint64_t app_and_compositor_time_ns = total_app_and_compositor_time_ns(pa);
|
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
|
static void
|
||||||
pa_predict(struct u_pacing_app *upa,
|
pa_predict(struct u_pacing_app *upa,
|
||||||
|
uint64_t now_ns,
|
||||||
int64_t *out_frame_id,
|
int64_t *out_frame_id,
|
||||||
uint64_t *out_wake_up_time,
|
uint64_t *out_wake_up_time,
|
||||||
uint64_t *out_predicted_display_time,
|
uint64_t *out_predicted_display_time,
|
||||||
|
@ -235,7 +233,7 @@ pa_predict(struct u_pacing_app *upa,
|
||||||
DEBUG_PRINT_FRAME_ID();
|
DEBUG_PRINT_FRAME_ID();
|
||||||
|
|
||||||
uint64_t period_ns = calc_period(pa);
|
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.
|
// When should the client wake up.
|
||||||
uint64_t wake_up_time_ns = predict_ns - total_app_and_compositor_time_ns(pa);
|
uint64_t wake_up_time_ns = predict_ns - total_app_and_compositor_time_ns(pa);
|
||||||
// When the client should deliver the frame to us.
|
// 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].frame_id = frame_id;
|
||||||
pa->frames[index].predicted_delivery_time_ns = delivery_time_ns;
|
pa->frames[index].predicted_delivery_time_ns = delivery_time_ns;
|
||||||
pa->frames[index].predicted_display_period_ns = period_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
|
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:
|
case U_TIMING_POINT_BEGIN:
|
||||||
assert(pa->frames[index].state == U_RT_WAIT_LEFT);
|
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;
|
pa->frames[index].state = U_RT_BEGUN;
|
||||||
break;
|
break;
|
||||||
case U_TIMING_POINT_SUBMIT:
|
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
|
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);
|
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].frame_id == frame_id);
|
||||||
assert(pa->frames[index].state == U_RT_WAIT_LEFT || pa->frames[index].state == U_RT_BEGUN);
|
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].state = U_PA_READY;
|
||||||
pa->frames[index].frame_id = -1;
|
pa->frames[index].frame_id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
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->frame_id == frame_id);
|
||||||
assert(f->state == U_RT_BEGUN);
|
assert(f->state == U_RT_BEGUN);
|
||||||
|
|
||||||
uint64_t now_ns = os_monotonic_get_ns();
|
|
||||||
|
|
||||||
// Update all data.
|
// Update all data.
|
||||||
f->when.delivered_ns = now_ns;
|
f->when.delivered_ns = when_ns;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process data.
|
* 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;
|
bool late = false;
|
||||||
if (diff_ns < 0) {
|
if (diff_ns < 0) {
|
||||||
diff_ns = -diff_ns;
|
diff_ns = -diff_ns;
|
||||||
|
|
|
@ -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.
|
* frame::desired_present_time_ns (with a crude estimate) and frame::when_predict_ns.
|
||||||
*/
|
*/
|
||||||
static struct frame *
|
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);
|
struct frame *f = create_frame(dt, STATE_PREDICTED);
|
||||||
uint64_t now_ns = os_monotonic_get_ns();
|
|
||||||
|
|
||||||
// Wild shot in the dark.
|
// 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->when_predict_ns = now_ns;
|
||||||
f->desired_present_time_ns = the_time_ns;
|
f->desired_present_time_ns = the_time_ns;
|
||||||
|
|
||||||
|
@ -277,9 +276,8 @@ do_clean_slate_frame(struct display_timing *dt)
|
||||||
* prediction in it.
|
* prediction in it.
|
||||||
*/
|
*/
|
||||||
static struct frame *
|
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.
|
// 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 from_time_ns = now_ns + calc_total_app_time(dt);
|
||||||
uint64_t desired_present_time_ns = last_present_time_ns + dt->frame_period_ns;
|
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 *
|
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;
|
struct frame *f = NULL;
|
||||||
// Last earliest display time, can be zero.
|
// Last earliest display time, can be zero.
|
||||||
struct frame *last_predicted = get_latest_frame_with_state_at_least(dt, STATE_PREDICTED);
|
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);
|
struct frame *last_completed = get_latest_frame_with_state_at_least(dt, STATE_INFO);
|
||||||
if (last_predicted == NULL && last_completed == NULL) {
|
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) {
|
} else if (last_completed == last_predicted) {
|
||||||
// Very high propability that we missed a frame.
|
// 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) {
|
} else if (last_completed != NULL) {
|
||||||
assert(last_predicted != NULL);
|
assert(last_predicted != NULL);
|
||||||
assert(last_predicted->frame_id > last_completed->frame_id);
|
assert(last_predicted->frame_id > last_completed->frame_id);
|
||||||
|
@ -342,11 +340,11 @@ predict_next_frame(struct display_timing *dt)
|
||||||
diff_id = 1;
|
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 {
|
} else {
|
||||||
assert(last_predicted != NULL);
|
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);
|
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
|
static void
|
||||||
dt_predict(struct u_pacing_compositor *upc,
|
dt_predict(struct u_pacing_compositor *upc,
|
||||||
|
uint64_t now_ns,
|
||||||
int64_t *out_frame_id,
|
int64_t *out_frame_id,
|
||||||
uint64_t *out_wake_up_time_ns,
|
uint64_t *out_wake_up_time_ns,
|
||||||
uint64_t *out_desired_present_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 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 wake_up_time_ns = f->wake_up_time_ns;
|
||||||
uint64_t desired_present_time_ns = f->desired_present_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 desired_present_time_ns,
|
||||||
uint64_t actual_present_time_ns,
|
uint64_t actual_present_time_ns,
|
||||||
uint64_t earliest_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);
|
struct display_timing *dt = display_timing(upc);
|
||||||
(void)dt;
|
(void)dt;
|
||||||
|
@ -481,7 +481,7 @@ dt_info(struct u_pacing_compositor *upc,
|
||||||
assert(f->state == STATE_SUBMITTED);
|
assert(f->state == STATE_SUBMITTED);
|
||||||
assert(f->desired_present_time_ns == desired_present_time_ns);
|
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->actual_present_time_ns = actual_present_time_ns;
|
||||||
f->earliest_present_time_ns = earliest_present_time_ns;
|
f->earliest_present_time_ns = earliest_present_time_ns;
|
||||||
f->present_margin_ns = present_margin_ns;
|
f->present_margin_ns = present_margin_ns;
|
||||||
|
|
|
@ -69,10 +69,9 @@ fake_timing(struct u_pacing_compositor *upc)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t
|
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 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;
|
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) {
|
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
|
static void
|
||||||
pc_predict(struct u_pacing_compositor *upc,
|
pc_predict(struct u_pacing_compositor *upc,
|
||||||
|
uint64_t now_ns,
|
||||||
int64_t *out_frame_id,
|
int64_t *out_frame_id,
|
||||||
uint64_t *out_wake_up_time_ns,
|
uint64_t *out_wake_up_time_ns,
|
||||||
uint64_t *out_desired_present_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);
|
struct fake_timing *ft = fake_timing(upc);
|
||||||
|
|
||||||
int64_t frame_id = ft->frame_id_generator++;
|
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 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 wake_up_time_ns = desired_present_time_ns - ft->app_time_ns;
|
||||||
uint64_t present_slop_ns = U_TIME_HALF_MS_IN_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 desired_present_time_ns,
|
||||||
uint64_t actual_present_time_ns,
|
uint64_t actual_present_time_ns,
|
||||||
uint64_t earliest_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
|
* The compositor might call this function because it selected the
|
||||||
|
@ -166,7 +167,7 @@ pc_destroy(struct u_pacing_compositor *upc)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
xrt_result_t
|
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);
|
struct fake_timing *ft = U_TYPED_CALLOC(struct fake_timing);
|
||||||
ft->base.predict = pc_predict;
|
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);
|
ft->app_time_ns = get_percent_of_time(estimated_frame_period_ns, 20);
|
||||||
|
|
||||||
// Make the next display time be in the future.
|
// 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.
|
// Return value.
|
||||||
*out_uft = &ft->base;
|
*out_uft = &ft->base;
|
||||||
|
|
|
@ -123,13 +123,14 @@ comp_target_swapchain_create_images(struct comp_target *ct,
|
||||||
VkBool32 supported;
|
VkBool32 supported;
|
||||||
VkResult ret;
|
VkResult ret;
|
||||||
|
|
||||||
|
uint64_t now_ns = os_monotonic_get_ns();
|
||||||
// Some platforms really don't like the display_timing code.
|
// 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;
|
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) {
|
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_create(ct->c->settings.nominal_frame_interval_ns,
|
||||||
&U_PC_DISPLAY_TIMING_CONFIG_DEFAULT, &cts->upc);
|
&U_PC_DISPLAY_TIMING_CONFIG_DEFAULT, &cts->upc);
|
||||||
} else if (cts->upc == NULL) {
|
} 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.
|
// 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_time_ns = 0;
|
||||||
uint64_t predicted_display_period_ns = 0;
|
uint64_t predicted_display_period_ns = 0;
|
||||||
uint64_t min_display_period_ns = 0;
|
uint64_t min_display_period_ns = 0;
|
||||||
|
uint64_t now_ns = os_monotonic_get_ns();
|
||||||
|
|
||||||
u_pc_predict(cts->upc, //
|
u_pc_predict(cts->upc, //
|
||||||
|
now_ns, //
|
||||||
&frame_id, //
|
&frame_id, //
|
||||||
&wake_up_time_ns, //
|
&wake_up_time_ns, //
|
||||||
&desired_present_time_ns, //
|
&desired_present_time_ns, //
|
||||||
|
@ -670,14 +673,15 @@ comp_target_swapchain_update_timings(struct comp_target *ct)
|
||||||
cts->swapchain.handle, //
|
cts->swapchain.handle, //
|
||||||
&count, //
|
&count, //
|
||||||
timings); //
|
timings); //
|
||||||
|
uint64_t now_ns = os_monotonic_get_ns();
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
u_pc_info(cts->upc, //
|
u_pc_info(cts->upc, //
|
||||||
timings[i].presentID, //
|
timings[i].presentID, //
|
||||||
timings[i].desiredPresentTime, //
|
timings[i].desiredPresentTime, //
|
||||||
timings[i].actualPresentTime, //
|
timings[i].actualPresentTime, //
|
||||||
timings[i].earliestPresentTime, //
|
timings[i].earliestPresentTime, //
|
||||||
timings[i].presentMargin); //
|
timings[i].presentMargin, //
|
||||||
|
now_ns); //
|
||||||
}
|
}
|
||||||
free(timings);
|
free(timings);
|
||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
|
|
|
@ -194,11 +194,12 @@ multi_compositor_predict_frame(struct xrt_compositor *xc,
|
||||||
COMP_TRACE_MARKER();
|
COMP_TRACE_MARKER();
|
||||||
|
|
||||||
struct multi_compositor *mc = multi_compositor(xc);
|
struct multi_compositor *mc = multi_compositor(xc);
|
||||||
|
uint64_t now_ns = os_monotonic_get_ns();
|
||||||
os_mutex_lock(&mc->msc->list_and_timing_lock);
|
os_mutex_lock(&mc->msc->list_and_timing_lock);
|
||||||
|
|
||||||
u_pa_predict( //
|
u_pa_predict( //
|
||||||
mc->upa, //
|
mc->upa, //
|
||||||
|
now_ns, //
|
||||||
out_frame_id, //
|
out_frame_id, //
|
||||||
out_wake_time_ns, //
|
out_wake_time_ns, //
|
||||||
out_predicted_display_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();
|
COMP_TRACE_MARKER();
|
||||||
|
|
||||||
struct multi_compositor *mc = multi_compositor(xc);
|
struct multi_compositor *mc = multi_compositor(xc);
|
||||||
|
uint64_t now_ns = os_monotonic_get_ns();
|
||||||
|
|
||||||
os_mutex_lock(&mc->msc->list_and_timing_lock);
|
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);
|
os_mutex_unlock(&mc->msc->list_and_timing_lock);
|
||||||
|
|
||||||
return XRT_SUCCESS;
|
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);
|
wait_for_scheduled_free(mc);
|
||||||
|
uint64_t now_ns = os_monotonic_get_ns();
|
||||||
|
|
||||||
os_mutex_lock(&mc->msc->list_and_timing_lock);
|
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);
|
os_mutex_unlock(&mc->msc->list_and_timing_lock);
|
||||||
|
|
||||||
return XRT_SUCCESS;
|
return XRT_SUCCESS;
|
||||||
|
|
Loading…
Reference in a new issue