mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2024-12-29 11:06:18 +00:00
u/pacing: Keep track of frame times in fake pacer
This commit is contained in:
parent
479973e68f
commit
f1c8843b7d
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2020-2023, Collabora, Ltd.
|
// Copyright 2020-2024, Collabora, Ltd.
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
/*!
|
/*!
|
||||||
* @file
|
* @file
|
||||||
|
@ -31,6 +31,59 @@
|
||||||
|
|
||||||
DEBUG_GET_ONCE_FLOAT_OPTION(present_to_display_offset_ms, "U_PACING_COMP_PRESENT_TO_DISPLAY_OFFSET_MS", 4.0f)
|
DEBUG_GET_ONCE_FLOAT_OPTION(present_to_display_offset_ms, "U_PACING_COMP_PRESENT_TO_DISPLAY_OFFSET_MS", 4.0f)
|
||||||
DEBUG_GET_ONCE_FLOAT_OPTION(min_comp_time_ms, "U_PACING_COMP_MIN_TIME_MS", 3.0f)
|
DEBUG_GET_ONCE_FLOAT_OPTION(min_comp_time_ms, "U_PACING_COMP_MIN_TIME_MS", 3.0f)
|
||||||
|
DEBUG_GET_ONCE_BOOL_OPTION(live_stats, "U_PACING_LIVE_STATS", false)
|
||||||
|
|
||||||
|
// We keep track of this number of frames.
|
||||||
|
#define FRAME_COUNT 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal helper for keeping track of frame data.
|
||||||
|
*/
|
||||||
|
struct frame
|
||||||
|
{
|
||||||
|
//! An arbitrary id that identifies this frame. Set in `pc_predict`.
|
||||||
|
int64_t frame_id;
|
||||||
|
|
||||||
|
//! When should the compositor wake up. Set in `pc_predict`.
|
||||||
|
uint64_t predicted_wake_up_time_ns;
|
||||||
|
|
||||||
|
//! When should the compositor present the frame.
|
||||||
|
uint64_t predicted_present_time_ns;
|
||||||
|
|
||||||
|
//! When should the frame be displayed.
|
||||||
|
uint64_t predicted_display_time_ns;
|
||||||
|
|
||||||
|
//! The period that the pacer used for this frame.
|
||||||
|
uint64_t predicted_display_period_ns;
|
||||||
|
|
||||||
|
//! When this frame was last used for a prediction. Set in `pc_predict`.
|
||||||
|
uint64_t when_predict_ns;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* When the compositor woke up after its equivalent of wait_frame.
|
||||||
|
* Set in `pc_mark_point` with `U_TIMING_POINT_WAKE_UP`.
|
||||||
|
*/
|
||||||
|
uint64_t when_woke_ns;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* When the compositor began rendering a frame. Set in `pc_mark_point`
|
||||||
|
* with `U_TIMING_POINT_BEGIN`.
|
||||||
|
*/
|
||||||
|
uint64_t when_began_ns;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* When the compositor began submitting the work to the GPU, after
|
||||||
|
* it completed building the command buffers. Set in `pc_mark_point`
|
||||||
|
* with `U_TIMING_POINT_SUBMIT_BEGIN`.
|
||||||
|
*/
|
||||||
|
uint64_t when_submit_began_ns;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* When the compositor completed submitting the work to the GPU. Set in
|
||||||
|
* `pc_mark_point` with `U_TIMING_POINT_SUBMIT_END`.
|
||||||
|
*/
|
||||||
|
uint64_t when_submit_end_ns;
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* A very simple pacer that tries it best to pace a compositor. Used when the
|
* A very simple pacer that tries it best to pace a compositor. Used when the
|
||||||
|
@ -63,6 +116,9 @@ struct fake_timing
|
||||||
|
|
||||||
//! This won't run out, trust me.
|
//! This won't run out, trust me.
|
||||||
int64_t frame_id_generator;
|
int64_t frame_id_generator;
|
||||||
|
|
||||||
|
//! Frames we keep track off.
|
||||||
|
struct frame frames[FRAME_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,6 +134,34 @@ fake_timing(struct u_pacing_compositor *upc)
|
||||||
return (struct fake_timing *)upc;
|
return (struct fake_timing *)upc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct frame *
|
||||||
|
get_frame_or_null(struct fake_timing *ft, int64_t frame_id)
|
||||||
|
{
|
||||||
|
uint64_t index = (uint64_t)frame_id % FRAME_COUNT;
|
||||||
|
struct frame *f = &ft->frames[index];
|
||||||
|
|
||||||
|
if (f->frame_id == frame_id) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
// Just drop it, doesn't happen during normal operation.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct frame *
|
||||||
|
get_new_frame(struct fake_timing *ft)
|
||||||
|
{
|
||||||
|
int64_t frame_id = ft->frame_id_generator++;
|
||||||
|
|
||||||
|
uint64_t index = (uint64_t)frame_id % FRAME_COUNT;
|
||||||
|
struct frame *f = &ft->frames[index];
|
||||||
|
|
||||||
|
// We don't care if it has been fully finished.
|
||||||
|
U_ZERO(f);
|
||||||
|
f->frame_id = frame_id;
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t
|
static uint64_t
|
||||||
predict_next_frame_present_time(struct fake_timing *ft, uint64_t now_ns)
|
predict_next_frame_present_time(struct fake_timing *ft, uint64_t now_ns)
|
||||||
{
|
{
|
||||||
|
@ -126,7 +210,9 @@ 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++;
|
struct frame *f = get_new_frame(ft);
|
||||||
|
|
||||||
|
int64_t frame_id = f->frame_id;
|
||||||
uint64_t desired_present_time_ns = predict_next_frame_present_time(ft, now_ns);
|
uint64_t desired_present_time_ns = predict_next_frame_present_time(ft, now_ns);
|
||||||
uint64_t predicted_display_time_ns = calc_display_time(ft, desired_present_time_ns);
|
uint64_t predicted_display_time_ns = calc_display_time(ft, desired_present_time_ns);
|
||||||
|
|
||||||
|
@ -135,6 +221,12 @@ pc_predict(struct u_pacing_compositor *upc,
|
||||||
uint64_t predicted_display_period_ns = ft->frame_period_ns;
|
uint64_t predicted_display_period_ns = ft->frame_period_ns;
|
||||||
uint64_t min_display_period_ns = ft->frame_period_ns;
|
uint64_t min_display_period_ns = ft->frame_period_ns;
|
||||||
|
|
||||||
|
// Set the frame info.
|
||||||
|
f->predicted_wake_up_time_ns = wake_up_time_ns;
|
||||||
|
f->predicted_present_time_ns = desired_present_time_ns;
|
||||||
|
f->predicted_display_time_ns = predicted_display_time_ns;
|
||||||
|
f->predicted_display_period_ns = predicted_display_period_ns;
|
||||||
|
|
||||||
*out_frame_id = frame_id;
|
*out_frame_id = frame_id;
|
||||||
*out_wake_up_time_ns = wake_up_time_ns;
|
*out_wake_up_time_ns = wake_up_time_ns;
|
||||||
*out_desired_present_time_ns = desired_present_time_ns;
|
*out_desired_present_time_ns = desired_present_time_ns;
|
||||||
|
@ -162,12 +254,20 @@ pc_predict(struct u_pacing_compositor *upc,
|
||||||
static void
|
static void
|
||||||
pc_mark_point(struct u_pacing_compositor *upc, enum u_timing_point point, int64_t frame_id, uint64_t when_ns)
|
pc_mark_point(struct u_pacing_compositor *upc, enum u_timing_point point, int64_t frame_id, uint64_t when_ns)
|
||||||
{
|
{
|
||||||
|
struct fake_timing *ft = fake_timing(upc);
|
||||||
|
struct frame *f = get_frame_or_null(ft, frame_id);
|
||||||
|
|
||||||
|
// Just drop info if no frame found.
|
||||||
|
if (f == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// To help validate calling code.
|
// To help validate calling code.
|
||||||
switch (point) {
|
switch (point) {
|
||||||
case U_TIMING_POINT_WAKE_UP: break;
|
case U_TIMING_POINT_WAKE_UP: f->when_woke_ns = when_ns; break;
|
||||||
case U_TIMING_POINT_BEGIN: break;
|
case U_TIMING_POINT_BEGIN: f->when_began_ns = when_ns; break;
|
||||||
case U_TIMING_POINT_SUBMIT_BEGIN: break;
|
case U_TIMING_POINT_SUBMIT_BEGIN: f->when_submit_began_ns = when_ns; break;
|
||||||
case U_TIMING_POINT_SUBMIT_END: break;
|
case U_TIMING_POINT_SUBMIT_END: f->when_submit_end_ns = when_ns; break;
|
||||||
default: assert(false);
|
default: assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue