present: Prevent double vblank enqueue on error when TearFree is used

It's possible for present_execute_copy to enqueue a vblank even when
TearFree is used, specifically when the present_queue_vblank in
present_scmd_pixmap fails and the subsequent vblank enqueue in
present_execute_copy somehow doesn't. This could happen if the DRM event
queue is exhausted when present_queue_vblank is called, but is no longer
exhausted by the time present_execute_copy is reached.

This exceedingly unlikely chain of events can lead to a vblank getting
enqueued a second time by the TearFree machinery in present_execute, which
is not good.

Although this scenario is very unlikely, prevent it by first checking that
the vblank wasn't enqueued by present_execute_copy before attempting to
enqueue it for TearFree.

Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
Acked-by: Martin Roukala <martin.roukala@mupuf.org>
This commit is contained in:
Sultan Alsawaf 2023-01-22 22:16:58 -08:00
parent 53b02054f3
commit d4bd39f1a5

View File

@ -554,7 +554,6 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
WindowPtr window = vblank->window; WindowPtr window = vblank->window;
ScreenPtr screen = window->drawable.pScreen; ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen); present_screen_priv_ptr screen_priv = present_screen_priv(screen);
uint64_t completion_msc;
if (vblank && vblank->crtc) { if (vblank && vblank->crtc) {
screen_priv=present_screen_priv(vblank->crtc->pScreen); screen_priv=present_screen_priv(vblank->crtc->pScreen);
} }
@ -652,23 +651,26 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
* If TearFree is already flipping then the presentation will be visible * If TearFree is already flipping then the presentation will be visible
* at the *next* next vblank. * at the *next* next vblank.
*/ */
completion_msc = crtc_msc + 1; if (!vblank->queued) {
switch (vblank->reason) { uint64_t completion_msc = crtc_msc + 1;
case PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING:
if (vblank->exec_msc < crtc_msc) switch (vblank->reason) {
completion_msc++; case PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING:
case PRESENT_FLIP_REASON_DRIVER_TEARFREE: if (vblank->exec_msc < crtc_msc)
if (Success == screen_priv->queue_vblank(screen, completion_msc++;
window, case PRESENT_FLIP_REASON_DRIVER_TEARFREE:
vblank->crtc, if (Success == screen_priv->queue_vblank(screen,
vblank->event_id, window,
completion_msc)) { vblank->crtc,
/* Ensure present_execute_post() runs at the next MSC */ vblank->event_id,
vblank->exec_msc = vblank->target_msc; completion_msc)) {
vblank->queued = TRUE; /* Ensure present_execute_post() runs at the next MSC */
vblank->exec_msc = vblank->target_msc;
vblank->queued = TRUE;
}
default:
break;
} }
default:
break;
} }
if (vblank->queued) { if (vblank->queued) {