mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-01 12:46:12 +00:00
u/rt: Tidy and documment render timing code
This commit is contained in:
parent
3856ae4540
commit
797fa5459c
|
@ -30,17 +30,29 @@
|
|||
} while (false)
|
||||
#endif
|
||||
|
||||
static uint64_t
|
||||
min_period(const struct u_rt_helper *urth)
|
||||
{
|
||||
return urth->last_input.predicted_display_period_ns;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
last_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)
|
||||
{
|
||||
uint64_t val = urth->last_input;
|
||||
uint64_t val = last_displayed(urth);
|
||||
|
||||
if (urth->period == 0) {
|
||||
if (min_period(urth) == 0) {
|
||||
return then_ns;
|
||||
}
|
||||
|
||||
while (val <= then_ns) {
|
||||
val += urth->period;
|
||||
val += min_period(urth);
|
||||
assert(val != 0);
|
||||
}
|
||||
|
||||
|
@ -87,18 +99,18 @@ u_rt_helper_predict(struct u_rt_helper *urth,
|
|||
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) {
|
||||
at_least_ns = urth->last_returned;
|
||||
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);
|
||||
|
||||
urth->last_returned = predict_ns;
|
||||
urth->last_returned_ns = predict_ns;
|
||||
|
||||
*wake_up_time = predict_ns - urth->period;
|
||||
*wake_up_time = predict_ns - min_period(urth);
|
||||
*predicted_display_time = predict_ns;
|
||||
*predicted_display_period = urth->period;
|
||||
*min_display_period = urth->period;
|
||||
*predicted_display_period = min_period(urth);
|
||||
*min_display_period = min_period(urth);
|
||||
|
||||
size_t index = (uint64_t)frame_id % ARRAY_SIZE(urth->frames);
|
||||
assert(urth->frames[index].frame_id == -1);
|
||||
|
@ -174,13 +186,12 @@ u_rt_helper_mark_delivered(struct u_rt_helper *urth, int64_t frame_id)
|
|||
}
|
||||
|
||||
void
|
||||
u_rt_helper_new_sample(struct u_rt_helper *urth, uint64_t predict, uint64_t extra, uint64_t min_period)
|
||||
u_rt_helper_new_sample(struct u_rt_helper *urth,
|
||||
uint64_t predicted_display_time_ns,
|
||||
uint64_t predicted_display_period_ns,
|
||||
uint64_t extra_ns)
|
||||
{
|
||||
urth->last_input = predict;
|
||||
urth->extra = extra;
|
||||
urth->period = min_period;
|
||||
|
||||
if (urth->last_returned == 0) {
|
||||
return;
|
||||
}
|
||||
urth->last_input.predicted_display_time_ns = predicted_display_time_ns;
|
||||
urth->last_input.predicted_display_period_ns = predicted_display_period_ns;
|
||||
urth->last_input.extra_ns = extra_ns;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,11 @@ struct u_rt_frame
|
|||
enum u_rt_state state;
|
||||
};
|
||||
|
||||
/*!
|
||||
* This render timing helper is designed to schedule the rendering time of
|
||||
* clients that submit frames to a compositor, which runs its own render loop
|
||||
* that picks latest completed frames for that client.
|
||||
*/
|
||||
struct u_rt_helper
|
||||
{
|
||||
struct u_rt_frame frames[2];
|
||||
|
@ -43,10 +48,17 @@ struct u_rt_helper
|
|||
|
||||
int64_t frame_counter;
|
||||
|
||||
uint64_t extra;
|
||||
uint64_t period;
|
||||
uint64_t last_input;
|
||||
uint64_t last_returned;
|
||||
struct
|
||||
{
|
||||
//! The last display time that the thing driving this helper got.
|
||||
uint64_t predicted_display_time_ns;
|
||||
//! The last display period the hardware is running at.
|
||||
uint64_t predicted_display_period_ns;
|
||||
//! The extra time needed by the thing driving this helper.
|
||||
uint64_t extra_ns;
|
||||
} last_input;
|
||||
|
||||
uint64_t last_returned_ns;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -55,10 +67,20 @@ u_rt_helper_init(struct u_rt_helper *urth);
|
|||
/*!
|
||||
* This function gets the client part of the render timing helper ready to be
|
||||
* used. If you use init you will also clear all of the timing information.
|
||||
*
|
||||
* Call this when resetting a client.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This is called from `xrWaitFrame`, but it does not do any waiting, the caller
|
||||
* should wait till `out_wake_up_time`.
|
||||
*/
|
||||
void
|
||||
u_rt_helper_predict(struct u_rt_helper *urth,
|
||||
int64_t *out_frame_id,
|
||||
|
@ -67,20 +89,55 @@ u_rt_helper_predict(struct u_rt_helper *urth,
|
|||
uint64_t *out_predicted_display_period,
|
||||
uint64_t *out_min_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`.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
* When a frame has been discared.
|
||||
*/
|
||||
void
|
||||
u_rt_helper_mark_discarded(struct u_rt_helper *urth, int64_t frame_id);
|
||||
|
||||
/*!
|
||||
* A frame has been delivered from the client, see `xrEndFrame`. The GPU might
|
||||
* still be rendering the work.
|
||||
*/
|
||||
void
|
||||
u_rt_helper_mark_delivered(struct u_rt_helper *urth, int64_t frame_id);
|
||||
|
||||
/*!
|
||||
* Add a new sample point from the main render loop.
|
||||
*
|
||||
* This is called in the main renderer loop that tightly submits frames to the
|
||||
* real compositor for displaying. This is only used to inform the render helper
|
||||
* when the frame will be shown, not any timing information about the client.
|
||||
*
|
||||
* When this is called doesn't matter that much, as the render timing will need
|
||||
* to be able to predict one or more frames into the future anyways. But
|
||||
* preferably as soon as the main loop wakes up from wait frame.
|
||||
*
|
||||
* @param urth Self pointer
|
||||
* @param predicted_display_time_ns Predicted display time for this sample.
|
||||
* @param predicted_display_period_ns Predicted display period for this sample.
|
||||
* @param extra_ns Time between display and when this sample
|
||||
* was created, that is when the main loop
|
||||
* was woken up by the main compositor.
|
||||
*/
|
||||
void
|
||||
u_rt_helper_new_sample(struct u_rt_helper *urth, uint64_t predict, uint64_t extra, uint64_t min_period);
|
||||
u_rt_helper_new_sample(struct u_rt_helper *urth,
|
||||
uint64_t predicted_display_time_ns,
|
||||
uint64_t predicted_display_period_ns,
|
||||
uint64_t extra_ns);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -1014,20 +1014,24 @@ main_loop(struct ipc_server *s)
|
|||
|
||||
while (s->running) {
|
||||
int64_t frame_id;
|
||||
uint64_t predicted_display_time;
|
||||
uint64_t predicted_display_period;
|
||||
uint64_t predicted_display_time_ns;
|
||||
uint64_t predicted_display_period_ns;
|
||||
|
||||
xrt_comp_wait_frame(xc, &frame_id, &predicted_display_time, &predicted_display_period);
|
||||
xrt_comp_wait_frame(xc, &frame_id, &predicted_display_time_ns, &predicted_display_period_ns);
|
||||
|
||||
uint64_t now = os_monotonic_get_ns();
|
||||
uint64_t diff = predicted_display_time - now;
|
||||
uint64_t now_ns = os_monotonic_get_ns();
|
||||
uint64_t diff_ns = predicted_display_time_ns - now_ns;
|
||||
|
||||
os_mutex_lock(&s->global_state_lock);
|
||||
|
||||
// Broadcast the new timing information to the helpers.
|
||||
for (size_t i = 0; i < ARRAY_SIZE(s->threads); i++) {
|
||||
u_rt_helper_new_sample((struct u_rt_helper *)&s->threads[i].ics.urth, predicted_display_time,
|
||||
diff, predicted_display_period);
|
||||
struct u_rt_helper *urth = (struct u_rt_helper *)&s->threads[i].ics.urth;
|
||||
u_rt_helper_new_sample( //
|
||||
urth, //
|
||||
predicted_display_time_ns, //
|
||||
predicted_display_period_ns, //
|
||||
diff_ns); //
|
||||
}
|
||||
|
||||
os_mutex_unlock(&s->global_state_lock);
|
||||
|
|
Loading…
Reference in a new issue