From f1c8843b7dd7e1962a683f41f12b7f479245dd76 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 3 Jan 2024 17:35:41 +0000 Subject: [PATCH] u/pacing: Keep track of frame times in fake pacer --- .../auxiliary/util/u_pacing_compositor_fake.c | 112 +++++++++++++++++- 1 file changed, 106 insertions(+), 6 deletions(-) diff --git a/src/xrt/auxiliary/util/u_pacing_compositor_fake.c b/src/xrt/auxiliary/util/u_pacing_compositor_fake.c index 795959acd..3fdf07ff6 100644 --- a/src/xrt/auxiliary/util/u_pacing_compositor_fake.c +++ b/src/xrt/auxiliary/util/u_pacing_compositor_fake.c @@ -1,4 +1,4 @@ -// Copyright 2020-2023, Collabora, Ltd. +// Copyright 2020-2024, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @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(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 @@ -63,6 +116,9 @@ struct fake_timing //! This won't run out, trust me. 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; } +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 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); - 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 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 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_wake_up_time_ns = wake_up_time_ns; *out_desired_present_time_ns = desired_present_time_ns; @@ -162,12 +254,20 @@ pc_predict(struct u_pacing_compositor *upc, static void 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. switch (point) { - case U_TIMING_POINT_WAKE_UP: break; - case U_TIMING_POINT_BEGIN: break; - case U_TIMING_POINT_SUBMIT_BEGIN: break; - case U_TIMING_POINT_SUBMIT_END: break; + case U_TIMING_POINT_WAKE_UP: f->when_woke_ns = when_ns; break; + case U_TIMING_POINT_BEGIN: f->when_began_ns = when_ns; break; + case U_TIMING_POINT_SUBMIT_BEGIN: f->when_submit_began_ns = when_ns; break; + case U_TIMING_POINT_SUBMIT_END: f->when_submit_end_ns = when_ns; break; default: assert(false); } }