compositor: check repaint_msec with a helper

Validate repaint_msec so it's not longer than a refresh interval.

Negative repaint windows will cause problems for frame scheduling in the
future, so remove them.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
This commit is contained in:
Derek Foreman 2025-11-06 12:28:34 -06:00
parent e286cf6e15
commit ed77aca2d8
3 changed files with 49 additions and 5 deletions

View file

@ -1213,7 +1213,7 @@ weston_compositor_init_config(struct weston_compositor *ec,
s = weston_config_get_section(config, "core", NULL, NULL); s = weston_config_get_section(config, "core", NULL, NULL);
weston_config_section_get_int(s, "repaint-window", &repaint_msec, weston_config_section_get_int(s, "repaint-window", &repaint_msec,
ec->repaint_msec); ec->repaint_msec);
if (repaint_msec < -10 || repaint_msec > 1000) { if (repaint_msec < 1 || repaint_msec > 1000) {
weston_log("Invalid repaint_window value in config: %d\n", weston_log("Invalid repaint_window value in config: %d\n",
repaint_msec); repaint_msec);
} else { } else {

View file

@ -3860,6 +3860,49 @@ out:
return false; return false;
} }
static int
weston_output_repaint_msec(const struct weston_output *output)
{
int refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
int refresh_msec = refresh_nsec / 1000000;
int repaint_msec;
repaint_msec = output->compositor->repaint_msec;
/* repaint_msec is, roughly speaking, the amount of time the compositor
* reserves before presentation to complete a repaint.
*
* If we reserve more time than a full refresh of the display, we'll
* always end up trying to schedule our next update in the past, which
* leads to every repaint immediately following the previous
* presentation.
*
* Beginning the repaint immediately after presentation leads to all
* client requests being processed after the repaint deadline for
* the current presentation 100% of the time, forcing an extra frame
* of latency.
*
* To avoid this forced latency, always ensure that repaint_msec is
* at least 1ms shorter than the refresh duration.
*/
if (repaint_msec > refresh_msec)
repaint_msec = refresh_msec - 1;
/* If we don't reserve enough time to repaint, we could miss the
* intended presentation time entirely.
*
* Negative values would ensure the next repaint is always after
* the next possible presentation time, forcing us to miss
* opportunities to present new content.
*
* Make sure we leave at least 1ms of time to repaint.
*/
if (repaint_msec < 1)
repaint_msec = 1;
return repaint_msec;
}
/** Calculate when we should start a repaint to hit a presentation time /** Calculate when we should start a repaint to hit a presentation time
* *
* \param output The output * \param output The output
@ -3895,7 +3938,7 @@ weston_output_repaint_from_present(const struct weston_output *output,
return late ? *now : *present_time; return late ? *now : *present_time;
timespec_add_msec(&repaint_time, present_time, timespec_add_msec(&repaint_time, present_time,
-output->compositor->repaint_msec); -weston_output_repaint_msec(output));
return repaint_time; return repaint_time;
} }
@ -4273,7 +4316,7 @@ weston_output_finish_frame(struct weston_output *output,
*/ */
while (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && while (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID &&
output->vrr_mode != WESTON_VRR_MODE_GAME && output->vrr_mode != WESTON_VRR_MODE_GAME &&
timespec_sub_to_msec(&output->next_present, &now) < compositor->repaint_msec) timespec_sub_to_msec(&output->next_present, &now) < weston_output_repaint_msec(output))
timespec_add_nsec(&output->next_present, timespec_add_nsec(&output->next_present,
&output->next_present, &output->next_present,
refresh_nsec); refresh_nsec);

View file

@ -150,8 +150,9 @@ window is longer than the output refresh period, the repaint will be done
immediately when the previous repaint finishes, not processing client requests immediately when the previous repaint finishes, not processing client requests
in between. If the repaint window is too short, the compositor may miss the in between. If the repaint window is too short, the compositor may miss the
target vertical blank, increasing output latency. The default value is 7 target vertical blank, increasing output latency. The default value is 7
milliseconds. The allowed range is from -10 to 1000 milliseconds. Using a milliseconds. The allowed range is from 1 to 1000 milliseconds, but the
negative value will force the compositor to always miss the target vblank. compositor will reduce large values to 1 millisecond less than the current
refresh rate.
.TP 7 .TP 7
.BI "idle-time="seconds .BI "idle-time="seconds
sets Weston's idle timeout in seconds. This idle timeout is the time sets Weston's idle timeout in seconds. This idle timeout is the time