1
0
Fork 0
mirror of https://github.com/yshui/picom.git synced 2025-04-14 17:53:25 -04:00

vblank: alternative invalid present event recovery

I found sometimes, when we receive an invalid PresentCompleteNotify,
keep requesting new present notifys using `last_msc + 1` doesn't really
help us recover. Instead X just keeps sending us bad
PresentCompleteNotifys, and we stuck in a loop. (This is more likely to
happen during screen resolution change. Also this did not seem to be
possible previously, when we were still handling resolution changes
inside the X critical section.)

This commit tries to test out a different approach. The hypothesis is,
maybe doing something to the screen (e.g. render and present a new frame)
helps change the internal state of the X server, thus kicks us out of the
loop. So whenever we get an invalid notify, we fake a vblank event so
rendering can happen. And we keeps doing this until we are (hopefully)
fine.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-06-27 17:18:29 +01:00
parent 1c57ba85b7
commit 532784149e
No known key found for this signature in database
GPG key ID: D3A4405BE6CC17F4

View file

@ -401,6 +401,10 @@ static void handle_present_complete_notify(struct present_vblank_scheduler *self
assert(self->base.vblank_event_requested);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
auto now_us = (unsigned long)(now.tv_sec * 1000000L + now.tv_nsec / 1000);
// X sometimes sends duplicate/bogus MSC events, when screen has just been turned
// off. Don't use the msc value in these events. We treat this as not receiving a
// vblank event at all, and try to get a new one.
@ -409,18 +413,15 @@ static void handle_present_complete_notify(struct present_vblank_scheduler *self
// https://gitlab.freedesktop.org/xorg/xserver/-/issues/1418
bool event_is_invalid = cne->msc <= self->last_msc || cne->ust == 0;
if (event_is_invalid) {
log_debug("Invalid PresentCompleteNotify event, %" PRIu64 " %" PRIu64,
log_debug("Invalid PresentCompleteNotify event, %" PRIu64 " %" PRIu64
". Trying to recover, reporting a fake vblank.",
cne->msc, cne->ust);
x_request_vblank_event(self->base.c, cne->window, self->last_msc + 1);
return;
self->last_ust = now_us;
self->last_msc += 1;
} else {
self->last_ust = cne->ust;
self->last_msc = cne->msc;
}
self->last_ust = cne->ust;
self->last_msc = cne->msc;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
auto now_us = (unsigned long)(now.tv_sec * 1000000L + now.tv_nsec / 1000);
double delay_sec = 0.0;
if (now_us < cne->ust) {
log_trace("The end of this vblank is %" PRIu64 " us into the "