mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-02-03 12:28:07 +00:00
u/tr: Refactor rendering timing code
This commit is contained in:
parent
d745396396
commit
5dbcca65c5
src/xrt
auxiliary/util
compositor/multi
|
@ -42,25 +42,57 @@ min_period(const struct u_rt_helper *urth)
|
|||
}
|
||||
|
||||
static uint64_t
|
||||
last_displayed(const struct u_rt_helper *urth)
|
||||
last_sample_displayed(const struct u_rt_helper *urth)
|
||||
{
|
||||
return urth->last_input.predicted_display_time_ns;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
get_last_input_plus_period_at_least_greater_then(struct u_rt_helper *urth, uint64_t then_ns)
|
||||
last_return_predicted_display(const struct u_rt_helper *urth)
|
||||
{
|
||||
uint64_t val = last_displayed(urth);
|
||||
return urth->last_returned_ns;
|
||||
}
|
||||
|
||||
if (min_period(urth) == 0) {
|
||||
return then_ns;
|
||||
static uint64_t
|
||||
total_app_time_ns(const struct u_rt_helper *urth)
|
||||
{
|
||||
return urth->app.cpu_time_ns + urth->app.draw_time_ns;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
total_app_and_compositor_time_ns(const struct u_rt_helper *urth)
|
||||
{
|
||||
return total_app_time_ns(urth) + urth->app.margin_ns + urth->last_input.extra_ns;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
predict_display_time(struct u_rt_helper *urth)
|
||||
{
|
||||
// Now
|
||||
uint64_t now_ns = os_monotonic_get_ns();
|
||||
|
||||
// Error checking.
|
||||
uint64_t period_ns = min_period(urth);
|
||||
if (period_ns == 0) {
|
||||
assert(false && "Have not yet received and samples from timing driver.");
|
||||
return now_ns;
|
||||
}
|
||||
|
||||
while (val <= then_ns) {
|
||||
val += min_period(urth);
|
||||
assert(val != 0);
|
||||
// Total app and compositor time to produce a frame
|
||||
uint64_t app_and_compositor_time_ns = total_app_and_compositor_time_ns(urth);
|
||||
|
||||
// Start from the last time that the driver displayed something.
|
||||
uint64_t val = last_sample_displayed(urth);
|
||||
|
||||
// Return a time after the last returned display time.
|
||||
while (val < last_return_predicted_display(urth)) {
|
||||
val += period_ns;
|
||||
}
|
||||
|
||||
// Have to have enough time to perform app work.
|
||||
while ((val - app_and_compositor_time_ns) <= now_ns) {
|
||||
val += period_ns;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -79,6 +111,10 @@ u_rt_helper_client_clear(struct u_rt_helper *urth)
|
|||
urth->frames[i].state = U_RT_READY;
|
||||
urth->frames[i].frame_id = -1;
|
||||
}
|
||||
|
||||
urth->app.cpu_time_ns = U_TIME_1MS_IN_NS * 2;
|
||||
urth->app.draw_time_ns = U_TIME_1MS_IN_NS * 2;
|
||||
urth->app.margin_ns = U_TIME_1MS_IN_NS / 2;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -91,31 +127,22 @@ u_rt_helper_init(struct u_rt_helper *urth)
|
|||
void
|
||||
u_rt_helper_predict(struct u_rt_helper *urth,
|
||||
int64_t *out_frame_id,
|
||||
uint64_t *predicted_display_time,
|
||||
uint64_t *wake_up_time,
|
||||
uint64_t *predicted_display_period,
|
||||
uint64_t *min_display_period)
|
||||
uint64_t *out_wake_up_time,
|
||||
uint64_t *out_predicted_display_time,
|
||||
uint64_t *out_predicted_display_period)
|
||||
{
|
||||
int64_t frame_id = ++urth->frame_counter;
|
||||
*out_frame_id = frame_id;
|
||||
|
||||
DEBUG_PRINT_FRAME_ID();
|
||||
|
||||
uint64_t at_least_ns = os_monotonic_get_ns();
|
||||
|
||||
// Don't return a time before the last returned type.
|
||||
if (at_least_ns < urth->last_returned_ns) {
|
||||
at_least_ns = urth->last_returned_ns;
|
||||
}
|
||||
|
||||
uint64_t predict_ns = get_last_input_plus_period_at_least_greater_then(urth, at_least_ns);
|
||||
uint64_t predict_ns = predict_display_time(urth);
|
||||
|
||||
urth->last_returned_ns = predict_ns;
|
||||
|
||||
*wake_up_time = predict_ns - min_period(urth);
|
||||
*predicted_display_time = predict_ns;
|
||||
*predicted_display_period = min_period(urth);
|
||||
*min_display_period = min_period(urth);
|
||||
*out_wake_up_time = predict_ns - total_app_and_compositor_time_ns(urth);
|
||||
*out_predicted_display_time = predict_ns;
|
||||
*out_predicted_display_period = min_period(urth);
|
||||
|
||||
size_t index = GET_INDEX_FROM_ID(urth, frame_id);
|
||||
assert(urth->frames[index].frame_id == -1);
|
||||
|
@ -134,29 +161,29 @@ u_rt_helper_predict(struct u_rt_helper *urth,
|
|||
}
|
||||
|
||||
void
|
||||
u_rt_helper_mark_wait_woke(struct u_rt_helper *urth, int64_t frame_id)
|
||||
u_rt_helper_mark(struct u_rt_helper *urth, int64_t frame_id, enum u_timing_point point, uint64_t when_ns)
|
||||
{
|
||||
DEBUG_PRINT_FRAME_ID();
|
||||
|
||||
size_t index = GET_INDEX_FROM_ID(urth, frame_id);
|
||||
assert(urth->frames[index].frame_id == frame_id);
|
||||
assert(urth->frames[index].state == U_RT_PREDICTED);
|
||||
|
||||
urth->frames[index].when.wait_woke_ns = os_monotonic_get_ns();
|
||||
urth->frames[index].state = U_RT_WAIT_LEFT;
|
||||
}
|
||||
switch (point) {
|
||||
case U_TIMING_POINT_WAKE_UP:
|
||||
assert(urth->frames[index].state == U_RT_PREDICTED);
|
||||
|
||||
void
|
||||
u_rt_helper_mark_begin(struct u_rt_helper *urth, int64_t frame_id)
|
||||
{
|
||||
DEBUG_PRINT_FRAME_ID();
|
||||
urth->frames[index].when.wait_woke_ns = when_ns;
|
||||
urth->frames[index].state = U_RT_WAIT_LEFT;
|
||||
break;
|
||||
case U_TIMING_POINT_BEGIN:
|
||||
assert(urth->frames[index].state == U_RT_WAIT_LEFT);
|
||||
|
||||
size_t index = GET_INDEX_FROM_ID(urth, frame_id);
|
||||
assert(urth->frames[index].frame_id == frame_id);
|
||||
assert(urth->frames[index].state == U_RT_WAIT_LEFT);
|
||||
|
||||
urth->frames[index].when.begin_ns = os_monotonic_get_ns();
|
||||
urth->frames[index].state = U_RT_BEGUN;
|
||||
urth->frames[index].when.begin_ns = os_monotonic_get_ns();
|
||||
urth->frames[index].state = U_RT_BEGUN;
|
||||
break;
|
||||
case U_TIMING_POINT_SUBMIT:
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "xrt/xrt_compiler.h"
|
||||
#include "os/os_time.h"
|
||||
#include "util/u_timing.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -57,6 +59,16 @@ struct u_rt_helper
|
|||
|
||||
int64_t frame_counter;
|
||||
|
||||
struct
|
||||
{
|
||||
//! App time between wait returning and begin being called.
|
||||
uint64_t cpu_time_ns;
|
||||
//! Time between begin and frame rendering completeing.
|
||||
uint64_t draw_time_ns;
|
||||
//! Exrta time between end of draw time and when the compositor wakes up.
|
||||
uint64_t margin_ns;
|
||||
} app; //!< App statistics.
|
||||
|
||||
struct
|
||||
{
|
||||
//! The last display time that the thing driving this helper got.
|
||||
|
@ -83,33 +95,32 @@ void
|
|||
u_rt_helper_client_clear(struct u_rt_helper *urth);
|
||||
|
||||
/*!
|
||||
* Predict when the client's next rendered frame will be presented, also when
|
||||
* the client should be woken up from sleeping, its display period and the
|
||||
* minimum display period that the client might have.
|
||||
* Predict when the client's next: rendered frame will be display; when the
|
||||
* client should be woken up from sleeping; and its display period.
|
||||
*
|
||||
* This is called from `xrWaitFrame`, but it does not do any waiting, the caller
|
||||
* should wait till `out_wake_up_time`.
|
||||
*
|
||||
* @param urth Render timing helper.
|
||||
* @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
|
||||
u_rt_helper_predict(struct u_rt_helper *urth,
|
||||
int64_t *out_frame_id,
|
||||
uint64_t *out_predicted_display_time,
|
||||
uint64_t *out_wake_up_time,
|
||||
uint64_t *out_predicted_display_period,
|
||||
uint64_t *out_min_display_period);
|
||||
uint64_t *out_predicted_display_time,
|
||||
uint64_t *out_predicted_display_period);
|
||||
|
||||
/*!
|
||||
* Log when the client woke up after sleeping for the time returned in
|
||||
* @ref u_rt_helper_predict. This happens inside of `xrWaitFrame`.
|
||||
* Mark a point on the frame's lifetime.
|
||||
*
|
||||
* @see @ref frame-timing.
|
||||
*/
|
||||
void
|
||||
u_rt_helper_mark_wait_woke(struct u_rt_helper *urth, int64_t frame_id);
|
||||
|
||||
/*!
|
||||
* The client has started rendering work, see `xrBeginFrame`.
|
||||
*/
|
||||
void
|
||||
u_rt_helper_mark_begin(struct u_rt_helper *urth, int64_t frame_id);
|
||||
u_rt_helper_mark(struct u_rt_helper *urth, int64_t frame_id, enum u_timing_point point, uint64_t when_ns);
|
||||
|
||||
/*!
|
||||
* When a frame has been discarded.
|
||||
|
|
|
@ -197,15 +197,12 @@ multi_compositor_predict_frame(struct xrt_compositor *xc,
|
|||
|
||||
os_mutex_lock(&mc->msc->list_and_timing_lock);
|
||||
|
||||
uint64_t min_display_period = 0;
|
||||
|
||||
u_rt_helper_predict( //
|
||||
&mc->urth, //
|
||||
out_frame_id, //
|
||||
out_predicted_display_time_ns, //
|
||||
out_wake_time_ns, //
|
||||
out_predicted_display_period_ns, //
|
||||
&min_display_period); //
|
||||
u_rt_helper_predict( //
|
||||
&mc->urth, //
|
||||
out_frame_id, //
|
||||
out_wake_time_ns, //
|
||||
out_predicted_display_time_ns, //
|
||||
out_predicted_display_period_ns); //
|
||||
|
||||
os_mutex_unlock(&mc->msc->list_and_timing_lock);
|
||||
|
||||
|
@ -225,7 +222,8 @@ multi_compositor_mark_frame(struct xrt_compositor *xc,
|
|||
switch (point) {
|
||||
case XRT_COMPOSITOR_FRAME_POINT_WOKE:
|
||||
os_mutex_lock(&mc->msc->list_and_timing_lock);
|
||||
u_rt_helper_mark_wait_woke(&mc->urth, frame_id);
|
||||
uint64_t now_ns = os_monotonic_get_ns();
|
||||
u_rt_helper_mark(&mc->urth, frame_id, U_TIMING_POINT_WAKE_UP, now_ns);
|
||||
os_mutex_unlock(&mc->msc->list_and_timing_lock);
|
||||
break;
|
||||
default: assert(false);
|
||||
|
@ -256,7 +254,8 @@ multi_compositor_begin_frame(struct xrt_compositor *xc, int64_t frame_id)
|
|||
struct multi_compositor *mc = multi_compositor(xc);
|
||||
|
||||
os_mutex_lock(&mc->msc->list_and_timing_lock);
|
||||
u_rt_helper_mark_begin(&mc->urth, frame_id);
|
||||
uint64_t now_ns = os_monotonic_get_ns();
|
||||
u_rt_helper_mark(&mc->urth, frame_id, U_TIMING_POINT_BEGIN, now_ns);
|
||||
os_mutex_unlock(&mc->msc->list_and_timing_lock);
|
||||
|
||||
return XRT_SUCCESS;
|
||||
|
|
|
@ -285,6 +285,40 @@ broadcast_timings(struct multi_system_compositor *msc,
|
|||
os_mutex_unlock(&msc->list_and_timing_lock);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
multi_main_loop(struct multi_system_compositor *msc)
|
||||
{
|
||||
|
@ -302,10 +336,18 @@ multi_main_loop(struct multi_system_compositor *msc)
|
|||
os_thread_helper_unlock(&msc->oth);
|
||||
|
||||
int64_t frame_id;
|
||||
uint64_t predicted_display_time_ns;
|
||||
uint64_t predicted_display_period_ns;
|
||||
uint64_t wake_time_ns = 0;
|
||||
uint64_t predicted_gpu_time_ns = 0;
|
||||
uint64_t predicted_display_time_ns = 0;
|
||||
uint64_t predicted_display_period_ns = 0;
|
||||
|
||||
xrt_comp_wait_frame(xc, &frame_id, &predicted_display_time_ns, &predicted_display_period_ns);
|
||||
wait_frame( //
|
||||
xc, //
|
||||
&frame_id, //
|
||||
&wake_time_ns, //
|
||||
&predicted_gpu_time_ns, //
|
||||
&predicted_display_time_ns, //
|
||||
&predicted_display_period_ns); //
|
||||
|
||||
uint64_t now_ns = os_monotonic_get_ns();
|
||||
uint64_t diff_ns = predicted_display_time_ns - now_ns;
|
||||
|
|
Loading…
Reference in a new issue