diff --git a/debian/patches/0005-present-disarm-wait-fence-before-re-execution.patch b/debian/patches/0005-present-disarm-wait-fence-before-re-execution.patch new file mode 100644 index 000000000..6d109c069 --- /dev/null +++ b/debian/patches/0005-present-disarm-wait-fence-before-re-execution.patch @@ -0,0 +1,33 @@ +From: KiralyCraft +Subject: present: disarm the wait-fence callback before re-execution + +A fence notification is one-shot, but re_execute() can leave the Present +request alive while it waits for its target MSC. Clear the callback before +re-entering the execution path. If that path must wait again, it installs +a new callback itself. + +This is required when the Sync trigger walker restarts after a callback: +otherwise a still-live request can be called repeatedly in the same scan. +It also prevents a later trigger of a reused fence from executing the old +request again. + +The same callback-lifetime correction is used by Termux:X11: +https://github.com/KiralyCraft/termux-x11/commit/fc534e514d7ad4851d0aca3357495816260e4549 +--- + present/present_execute.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/present/present_execute.c b/present/present_execute.c +--- a/present/present_execute.c ++++ b/present/present_execute.c +@@ -38,6 +38,10 @@ present_wait_fence_triggered(void *param) + ScreenPtr screen = vblank->screen; + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + ++ /* Re-execution may keep this request alive until its target MSC. ++ * Disarm this notification; a new wait will install a new callback. */ ++ present_fence_set_callback(vblank->wait_fence, NULL, NULL); ++ + screen_priv->re_execute(vblank); + } + diff --git a/debian/patches/0006-miext-sync-restart-trigger-scan-after-callback.patch b/debian/patches/0006-miext-sync-restart-trigger-scan-after-callback.patch new file mode 100644 index 000000000..daad604a5 --- /dev/null +++ b/debian/patches/0006-miext-sync-restart-trigger-scan-after-callback.patch @@ -0,0 +1,49 @@ +From: Olivier Fourdan +Subject: miext/sync: restart the trigger scan after a callback +Origin: upstream, https://gitlab.freedesktop.org/xorg/xserver/-/commit/f19ab94ba9c891d801231654267556dc7f32b5e0 + +Backport upstream's trigger-list lifetime correction. A callback can remove +other entries as well as its own entry, so saving the next pointer before +calling it is not sufficient. Restart from the current list head instead. + +Apply after the Present one-shot callback correction, so a request that +survives re-execution cannot keep firing in the restart scan. + +Signed-off-by: Olivier Fourdan +Acked-by: Peter Hutterer +--- + miext/sync/misync.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/miext/sync/misync.c b/miext/sync/misync.c +--- a/miext/sync/misync.c ++++ b/miext/sync/misync.c +@@ -131,16 +131,22 @@ miSyncDestroyFence(SyncFence * pFence) + void + miSyncTriggerFence(SyncFence * pFence) + { +- SyncTriggerList *ptl, *pNext; ++ SyncTriggerList *ptl; ++ Bool triggered; + + pFence->funcs.SetTriggered(pFence); + + /* run through triggers to see if any fired */ +- for (ptl = pFence->sync.pTriglist; ptl; ptl = pNext) { +- pNext = ptl->next; +- if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, 0)) +- (*ptl->pTrigger->TriggerFired) (ptl->pTrigger); +- } ++ do { ++ triggered = FALSE; ++ for (ptl = pFence->sync.pTriglist; ptl; ptl = ptl->next) { ++ if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, 0)) { ++ (*ptl->pTrigger->TriggerFired) (ptl->pTrigger); ++ triggered = TRUE; ++ break; ++ } ++ } ++ } while (triggered); + } + + SyncScreenFuncsPtr diff --git a/debian/patches/0007-xwayland-present-do-not-rewait-after-copy.patch b/debian/patches/0007-xwayland-present-do-not-rewait-after-copy.patch new file mode 100644 index 000000000..410f6598b --- /dev/null +++ b/debian/patches/0007-xwayland-present-do-not-rewait-after-copy.patch @@ -0,0 +1,37 @@ +From: KiralyCraft +Subject: xwayland: do not reacquire a copied Present pixmap + +After a COPY Present, Idle permits the client to reuse the source pixmap +and reset its wait fence for a later frame. The old request may still be +queued for its delayed Complete notification. Re-executing that request +must not wait for the source again, because that now belongs to a different +presentation. + +Waiting a second time can overwrite blocking_event with the old copied +request. That request subsequently completes without draining blocked_queue, +leaving newer requests blocked indefinitely. + +Only perform acquisition before the copy. The first wait, asynchronous +render fences, and delayed completion scheduling are unchanged. +--- + hw/xwayland/xwayland-present.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c +--- a/hw/xwayland/xwayland-present.c ++++ b/hw/xwayland/xwayland-present.c +@@ -1048,8 +1048,12 @@ xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) + } + + retry: +- if (present_execute_wait(vblank, crtc_msc) || +- xwl_present_wait_acquire_fence_avail(xwl_screen, vblank)) { ++ /* The source pixmap is already idle after a copy. Its wait fence may ++ * have been reset for a later Present, so do not acquire it again just ++ * to send this request's delayed completion notification. */ ++ if (!event->copy_executed && ++ (present_execute_wait(vblank, crtc_msc) || ++ xwl_present_wait_acquire_fence_avail(xwl_screen, vblank))) { + if (!notify_only) + /* block execution of subsequent requests until this request is ready */ + xwl_present_window->blocking_event = event->vblank.event_id; diff --git a/debian/patches/series b/debian/patches/series index 0232983ed..a078be54c 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -2,3 +2,6 @@ 0002-xwayland-glamor-add-KGSL-surfaceless-backend-path.patch 0003-xwayland-dri3-support-KGSL-surfaceless-client-render.patch 0004-xwayland-scope-KGSL-frame-callback-recovery-per-window.patch +0005-present-disarm-wait-fence-before-re-execution.patch +0006-miext-sync-restart-trigger-scan-after-callback.patch +0007-xwayland-present-do-not-rewait-after-copy.patch