Merge ~jeff250/ubuntu/+source/xorg-server:tearfree into ubuntu/+source/xorg-server:ubuntu/devel

Proposed by Jeffrey Knockel
Status: Work in progress
Proposed branch: ~jeff250/ubuntu/+source/xorg-server:tearfree
Merge into: ubuntu/+source/xorg-server:ubuntu/devel
Diff against target: 2058 lines (+2030/-0)
4 files modified
debian/changelog (+9/-0)
debian/patches/series (+4/-0)
debian/patches/tearfree-modesetting.patch (+1385/-0)
debian/patches/tearfree-present-fixes.patch (+632/-0)
Reviewer Review Type Date Requested Status
Timo Aaltonen Pending
Ubuntu Sponsors Pending
git-ubuntu import Pending
Review via email: mp+457781@code.launchpad.net

Description of the change

While the Xorg server can eliminate tearing in many cases, in others, such as in the absence of a compositor or in the presence of xrandr rotation or scaling, tearing may still be present (see, e.g., [1,2,3]). To address these cases, this merge request contains Sultan Alsawaf's patches from [4] (specifically, from [5]) and from [6] to implement "TearFree" mode in the modesetting driver. "TearFree" mode is considered mature and robust by upstream and has since been enabled by default in the modesetting driver [7], and the feature is similar to the "TearFree" modes already implemented in other DDX drivers. However, while this merge request implements "TearFree" mode for the modesetting driver, this merge request does not yet include upstream's patches to enable the mode by default. Instead, enabling "TearFree" in the modesetting driver will still require something such as the following added to xorg.conf:

Section "Device"
    Identifier "Graphics Adapter"
    Driver "modesetting"
    Option "TearFree" "true"
EndSection

[1] https://bugs.launchpad.net/xorg-server/+bug/1754284
[2] https://bugs.launchpad.net/xorg-server/+bug/1846398
[3] https://bugs.launchpad.net/xorg-server/+bug/1853094
[4] https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1006
[5] https://github.com/kerneltoast/xserver/tree/new-tearfree-21.1.5
[6] https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1042
[7] https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1224

To post a comment you must log in.
Revision history for this message
Simon Chopin (schopin) wrote :

Hi! Thanks for the patches and helping improve Ubuntu.

As a random Core Dev I don't feel particularly comfortable sponsoring these changes without the opinion of someone at least a bit knowledgeable about xorg, so I pinged someone that's presumably a better fit on IRC so that they can have a look at it. Meanwhile I still do have a couple of comments about the metadata aspects to help future-proofing the contribution.

Cheers!

Revision history for this message
Jeffrey Knockel (jeff250) wrote :

> Hi! Thanks for the patches and helping improve Ubuntu.
>
> As a random Core Dev I don't feel particularly comfortable sponsoring these
> changes without the opinion of someone at least a bit knowledgeable about
> xorg, so I pinged someone that's presumably a better fit on IRC so that they
> can have a look at it. Meanwhile I still do have a couple of comments about
> the metadata aspects to help future-proofing the contribution.
>
> Cheers!

Thanks for your feedback. I have addressed your comments in the latest force-push. Hopefully it follows guidelines now. :) I also look forward to hearing what the other developer has to say.

Revision history for this message
Paride Legovini (paride) wrote :

Like Simon before me, I don't feel fully comfortable in merging this big diff as I have no experience working with the xorg packages.

I pointed out a couple of minor issues with the DEP-3 headers of the patches you added, should you need a reference for the syntax of those headers see [1]. Also ideally please split the diff in separate commits (one per added patch, plus one for the d/changelog changes).

Once you find or file an Ubuntu bug describing what you're going to fix here, please reference it in the new d/changelog entry using the `LP: #nnnnnn` syntax. This way Launchpad will auto-update the bug after the package gets uploaded.

A couple of extra questions:

1. In case you are familiar with Xorg's release schedule, when do you think these patches will be part of a new release?

2. Is there a Debian bug about the issue?

I'll try to get the attention of somebody more knowledgeable with Xorg.

[1] https://dep-team.pages.debian.net/deps/dep3/

Revision history for this message
Jeffrey Knockel (jeff250) wrote :

> Like Simon before me, I don't feel fully comfortable in merging this big diff
> as I have no experience working with the xorg packages.
>
> I pointed out a couple of minor issues with the DEP-3 headers of the patches
> you added, should you need a reference for the syntax of those headers see
> [1]. Also ideally please split the diff in separate commits (one per added
> patch, plus one for the d/changelog changes).

Thanks, I will address these issues.

> Once you find or file an Ubuntu bug describing what you're going to fix here,
> please reference it in the new d/changelog entry using the `LP: #nnnnnn`
> syntax. This way Launchpad will auto-update the bug after the package gets
> uploaded.

There are a number of filed bugs (e.g., [1,2]) addressed by this diff, but my proposed diff won't fix the issue for users by default -- a user must still opt-in to running the modesetting driver in tearfree mode by modifying their xorg.conf file. Is it appropriate to list these bugs and have them automatically closed if the fix is opt-in? (Note that upstream has already accepted a patch [3] to enable tearfree mode by default, i.e., to make it opt-out, but I decided to omit this patch due to its recency and my assumption that it would be easier to get tearfree mode accepted into Ubuntu as opt-in vs. opt-out; however, I can include this patch and make it opt-out if this would be more desirable.)

[1] https://bugs.launchpad.net/xorg-server/+bug/1846398
[2] https://bugs.launchpad.net/xorg-server/+bug/1853094
[3] https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1224

> A couple of extra questions:
>
> 1. In case you are familiar with Xorg's release schedule, when do you think
> these patches will be part of a new release?

I have no special familiarity with Xorg's release schedule, but my understanding as an outsider is that there is no longer any official "maintainer" of the Xorg X server. This makes me pessimistic that there will be anything but security fixes in future releases for the foreseeable future.

> 2. Is there a Debian bug about the issue?

I did a search and found that [4,5] are likely related, especially [5] as the user reports the issue only occurring after switching from the intel DDX driver to the modesetting one.

[4] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=839239
[5] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1003806

In general though it doesn't seem as though the debian bugtrackers have the same depth of reporting of the addressed issue as Ubuntu's.

> I'll try to get the attention of somebody more knowledgeable with Xorg.

Thanks, I understand that this is a tricky diff. :)

16282b7... by Jeffrey Knockel <email address hidden>

Enable "TearFree" option for modesetting driver

c8f4878... by Jeffrey Knockel <email address hidden>

Fix inaccurate Present timing for TearFree

9c5de4b... by Timo Aaltonen

2:21.1.11-1ubuntu1 (patches unapplied)

Imported using git-ubuntu import.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

I went ahead and added a slot for Timo to review this :)

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

The upstream patch[1] has this hunk:

hw/xfree86/common/xf86Module.h:
-#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(25, 3)
+#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(25, 4)

Your debdiff is not touching that. Precaution, or something else?

But, this is over my head, I don't know if patching xorg like this debdiff has other implications. I would be much more comfortable if these were in a new release.

I'll note that 21.1.11 was tagged on Jan 16th, 2024, so quite recently, and 21.1.10 a month before, so releases are happening.

1. https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1006/diffs

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Oh, and you should rebase this on top of what is in noble at the moment, which is 2:21.1.11-1ubuntu1

609edb0... by Jeffrey Knockel <email address hidden>

Update debian/changelog with TearFree fixes

Revision history for this message
Jeffrey Knockel (jeff250) wrote :

> I went ahead and added a slot for Timo to review this :)

Thanks!

> The upstream patch[1] has this hunk:
>
> hw/xfree86/common/xf86Module.h:
> -#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(25, 3)
> +#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(25, 4)
>
> Your debdiff is not touching that. Precaution, or something else?
>
> But, this is over my head, I don't know if patching xorg like this debdiff has
> other implications.

This change is tricky because the current ABI_VIDEODRV_VERSION of our version (21.1.11) is 25.2, so I don't know if it makes sense to bump it to 25.4, if we don't include the changes from 25.2 to 25.3.

The original author of the upstream merge request did not include this change in his port [1] of the changes to 21.1.x, which my debdiff is based on. However, he may have been faced with the same dilemma.

[1] https://github.com/kerneltoast/xserver/tree/new-tearfree-21.1.5

> I would be much more comfortable if these were in a new release.
>
> I'll note that 21.1.11 was tagged on Jan 16th, 2024, so quite recently, and
> 21.1.10 a month before, so releases are happening.

Yes I would feel more comfortable if these were in a new release as well. :) One of my motivations for submitting this merge request was because the last major release of Xorg's X server (21.1.0) was in 2021. My understanding of their recent releases is that they contain security fixes, minor bug fixes, and only small additions (e.g., PresentWindowDestroyed events).

> Oh, and you should rebase this on top of what is in noble at the moment, which
> is 2:21.1.11-1ubuntu1

Done!

Revision history for this message
Timo Aaltonen (tjaalton) wrote :

Hi, I pinged upstream about having a new release now that many of the long-standing MR's have been merged, and it might happen. And I'd much rather have this via an upstream release than as another distro patch..

Maybe I'll push a git snapshot to Debian experimental to see what breaks.

Revision history for this message
Robie Basak (racb) wrote :

Hi,

This is still in the sponsorship queue, but like the others I'm reluctant to add an extensive distro patch without the maintenance question being answered. I wouldn't add it without an ack from the desktop team. But it sounds like there might be movement upstream, so I guess there's no action to take for this in Ubuntu at the moment.

To clear up the queue, I'm going to set the MP to Work In Progress as it's not ready to merge as-is. If the status changes and the desktop team have indicated that they're willing to maintain the patch, or you need help in some other way, please change the status back to Needs review and it should reappear in the queue.

Thanks!

Revision history for this message
Jeffrey Knockel (jeff250) wrote :

> Hi, I pinged upstream about having a new release now that many of the long-standing MR's have been merged, and it might happen.

That would be great!

> Maybe I'll push a git snapshot to Debian experimental to see what breaks.

That would be amazing, and I would love to test it.

Unmerged commits

609edb0... by Jeffrey Knockel <email address hidden>

Update debian/changelog with TearFree fixes

c8f4878... by Jeffrey Knockel <email address hidden>

Fix inaccurate Present timing for TearFree

16282b7... by Jeffrey Knockel <email address hidden>

Enable "TearFree" option for modesetting driver

9c5de4b... by Timo Aaltonen

2:21.1.11-1ubuntu1 (patches unapplied)

Imported using git-ubuntu import.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index d7d892a..c0a26cf 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,12 @@
6+xorg-server (2:21.1.11-1ubuntu2) noble; urgency=medium
7+
8+ * Backport opt-in TearFree mode in the modesetting driver
9+ - tearfree-modesetting.patch: Enable "TearFree" modesetting driver option.
10+ - tearfree-present-fixes.patch: Fix inaccurate PresentCompleteNotify timing
11+ for TearFree.
12+
13+ -- Jeffrey Knockel <jeff@jeffreyknockel.com> Fri, 19 Jan 2024 13:31:31 -0500
14+
15 xorg-server (2:21.1.11-1ubuntu1) noble; urgency=medium
16
17 * Merge from Debian.
18diff --git a/debian/patches/series b/debian/patches/series
19index 6482af0..55f72fe 100644
20--- a/debian/patches/series
21+++ b/debian/patches/series
22@@ -26,3 +26,7 @@ fix-default-permissions.patch
23 reset-transforms-in-closescreen.diff
24 re-calculate-the-clock-and-refresh-rate.diff
25 0001-dix-Force-update-LEDs-after-device-state-update-in-E.patch
26+
27+# tearfree fixes
28+tearfree-modesetting.patch
29+tearfree-present-fixes.patch
30diff --git a/debian/patches/tearfree-modesetting.patch b/debian/patches/tearfree-modesetting.patch
31new file mode 100644
32index 0000000..99e8dd3
33--- /dev/null
34+++ b/debian/patches/tearfree-modesetting.patch
35@@ -0,0 +1,1385 @@
36+Description: Enable "TearFree" option for modesetting driver
37+Origin: upstream, https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1006
38+Bug: https://gitlab.freedesktop.org/xorg/xserver/-/issues/244
39+Bug-Ubuntu: https://bugs.launchpad.net/xorg-server/+bug/1754284
40+Bug-Ubuntu: https://bugs.launchpad.net/xorg-server/+bug/1846398
41+Bug-Ubuntu: https://bugs.launchpad.net/xorg-server/+bug/1853094
42+Index: xorg-server-21.1.6/dix/pixmap.c
43+===================================================================
44+--- xorg-server-21.1.6.orig/dix/pixmap.c 2022-12-19 05:53:03.000000000 -0500
45++++ xorg-server-21.1.6/dix/pixmap.c 2023-01-09 10:11:45.537724859 -0500
46+@@ -262,12 +262,11 @@
47+ return TRUE;
48+ }
49+
50+-static void
51+-PixmapDirtyCopyArea(PixmapPtr dst,
52+- PixmapDirtyUpdatePtr dirty,
53++void
54++PixmapDirtyCopyArea(PixmapPtr dst, DrawablePtr src,
55++ int x, int y, int dst_x, int dst_y,
56+ RegionPtr dirty_region)
57+ {
58+- DrawablePtr src = dirty->src;
59+ ScreenPtr pScreen = src->pScreen;
60+ int n;
61+ BoxPtr b;
62+@@ -294,9 +293,8 @@
63+ h = dst_box.y2 - dst_box.y1;
64+
65+ pGC->ops->CopyArea(src, &dst->drawable, pGC,
66+- dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h,
67+- dirty->dst_x + dst_box.x1,
68+- dirty->dst_y + dst_box.y1);
69++ x + dst_box.x1, y + dst_box.y1, w, h,
70++ dst_x + dst_box.x1, dst_y + dst_box.y1);
71+ b++;
72+ }
73+ FreeScratchGC(pGC);
74+@@ -408,7 +406,8 @@
75+ RegionTranslate(&pixregion, -dirty->x, -dirty->y);
76+
77+ if (!pScreen->root || dirty->rotation == RR_Rotate_0)
78+- PixmapDirtyCopyArea(dst, dirty, &pixregion);
79++ PixmapDirtyCopyArea(dst, dirty->src, dirty->x, dirty->y,
80++ dirty->dst_x, dirty->dst_y, &pixregion);
81+ else
82+ PixmapDirtyCompositeRotate(dst, dirty, &pixregion);
83+ pScreen->SourceValidate = SourceValidate;
84+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/driver.c
85+===================================================================
86+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/driver.c 2022-12-19 05:53:03.000000000 -0500
87++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/driver.c 2023-01-09 10:11:45.537724859 -0500
88+@@ -145,6 +145,7 @@
89+ {OPTION_VARIABLE_REFRESH, "VariableRefresh", OPTV_BOOLEAN, {0}, FALSE},
90+ {OPTION_USE_GAMMA_LUT, "UseGammaLUT", OPTV_BOOLEAN, {0}, FALSE},
91+ {OPTION_ASYNC_FLIP_SECONDARIES, "AsyncFlipSecondaries", OPTV_BOOLEAN, {0}, FALSE},
92++ {OPTION_TEARFREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE},
93+ {-1, NULL, OPTV_NONE, {0}, FALSE}
94+ };
95+
96+@@ -516,14 +517,15 @@
97+ }
98+
99+ static int
100+-dispatch_dirty_region(ScrnInfoPtr scrn,
101+- PixmapPtr pixmap, DamagePtr damage, int fb_id)
102++dispatch_damages(ScrnInfoPtr scrn, RegionPtr dirty, DamagePtr damage, int fb_id)
103+ {
104+ modesettingPtr ms = modesettingPTR(scrn);
105+- RegionPtr dirty = DamageRegion(damage);
106+ unsigned num_cliprects = REGION_NUM_RECTS(dirty);
107+ int ret = 0;
108+
109++ if (!ms->dirty_enabled)
110++ return 0;
111++
112+ if (num_cliprects) {
113+ drmModeClip *clip = xallocarray(num_cliprects, sizeof(drmModeClip));
114+ BoxPtr rect = REGION_RECTS(dirty);
115+@@ -551,12 +553,98 @@
116+ }
117+ }
118+
119++ if (ret == -EINVAL || ret == -ENOSYS) {
120++ xf86DrvMsg(scrn->scrnIndex, X_INFO,
121++ "Disabling kernel dirty updates, not required.\n");
122++ ms->dirty_enabled = FALSE;
123++ }
124++
125+ free(clip);
126+- DamageEmpty(damage);
127++ if (damage)
128++ DamageEmpty(damage);
129+ }
130+ return ret;
131+ }
132+
133++static int
134++dispatch_dirty_region(ScrnInfoPtr scrn,
135++ PixmapPtr pixmap, DamagePtr damage, int fb_id)
136++{
137++ return dispatch_damages(scrn, DamageRegion(damage), damage, fb_id);
138++}
139++
140++static void
141++ms_tearfree_update_damages(ScreenPtr pScreen)
142++{
143++ ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
144++ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
145++ modesettingPtr ms = modesettingPTR(scrn);
146++ RegionPtr dirty = DamageRegion(ms->damage);
147++ int c, i;
148++
149++ if (RegionNil(dirty))
150++ return;
151++
152++ for (c = 0; c < xf86_config->num_crtc; c++) {
153++ xf86CrtcPtr crtc = xf86_config->crtc[c];
154++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
155++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
156++ RegionRec region;
157++
158++ /* Compute how much of the damage intersects with this CRTC */
159++ RegionInit(&region, &crtc->bounds, 0);
160++ RegionIntersect(&region, &region, dirty);
161++
162++ if (trf->buf[0].px) {
163++ for (i = 0; i < ARRAY_SIZE(trf->buf); i++)
164++ RegionUnion(&trf->buf[i].dmg, &trf->buf[i].dmg, &region);
165++ } else {
166++ /* Just notify the kernel of the damages if TearFree isn't used */
167++ dispatch_damages(scrn, &region, NULL, ms->drmmode.fb_id);
168++ }
169++ }
170++ DamageEmpty(ms->damage);
171++}
172++
173++static void
174++ms_tearfree_do_flips(ScreenPtr pScreen)
175++{
176++#ifdef GLAMOR_HAS_GBM
177++ ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
178++ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
179++ modesettingPtr ms = modesettingPTR(scrn);
180++ int c;
181++
182++ if (!ms->drmmode.tearfree_enable)
183++ return;
184++
185++ for (c = 0; c < xf86_config->num_crtc; c++) {
186++ xf86CrtcPtr crtc = xf86_config->crtc[c];
187++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
188++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
189++
190++ /* Skip disabled CRTCs and those which aren't using TearFree */
191++ if (!trf->buf[0].px || !crtc->scrn->vtSema || !xf86_crtc_on(crtc))
192++ continue;
193++
194++ /* Skip if the last flip is still pending, a DRI client is flipping, or
195++ * there isn't any damage on the front buffer.
196++ */
197++ if (trf->flip_seq || ms->drmmode.dri2_flipping ||
198++ ms->drmmode.present_flipping ||
199++ RegionNil(&trf->buf[trf->back_idx ^ 1].dmg))
200++ continue;
201++
202++ /* Flip. If it fails, notify the kernel of the front buffer damages */
203++ if (ms_do_tearfree_flip(pScreen, crtc)) {
204++ dispatch_damages(scrn, &trf->buf[trf->back_idx ^ 1].dmg,
205++ NULL, trf->buf[trf->back_idx ^ 1].fb_id);
206++ RegionEmpty(&trf->buf[trf->back_idx ^ 1].dmg);
207++ }
208++ }
209++#endif
210++}
211++
212+ static void
213+ dispatch_dirty(ScreenPtr pScreen)
214+ {
215+@@ -568,12 +656,9 @@
216+
217+ ret = dispatch_dirty_region(scrn, pixmap, ms->damage, fb_id);
218+ if (ret == -EINVAL || ret == -ENOSYS) {
219+- ms->dirty_enabled = FALSE;
220+ DamageUnregister(ms->damage);
221+ DamageDestroy(ms->damage);
222+ ms->damage = NULL;
223+- xf86DrvMsg(scrn->scrnIndex, X_INFO,
224+- "Disabling kernel dirty updates, not required.\n");
225+ return;
226+ }
227+ }
228+@@ -703,10 +788,13 @@
229+ pScreen->BlockHandler = msBlockHandler;
230+ if (pScreen->isGPU && !ms->drmmode.reverse_prime_offload_mode)
231+ dispatch_secondary_dirty(pScreen);
232++ else if (ms->drmmode.tearfree_enable)
233++ ms_tearfree_update_damages(pScreen);
234+ else if (ms->dirty_enabled)
235+ dispatch_dirty(pScreen);
236+
237+ ms_dirty_update(pScreen, timeout);
238++ ms_tearfree_do_flips(pScreen);
239+ }
240+
241+ static void
242+@@ -1242,6 +1330,27 @@
243+ ms->atomic_modeset = FALSE;
244+ }
245+
246++ /* TearFree requires glamor and, if PageFlip is enabled, universal planes */
247++ if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_TEARFREE, FALSE)) {
248++ if (pScrn->is_gpu) {
249++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
250++ "TearFree cannot synchronize PRIME; use 'PRIME Synchronization' instead\n");
251++ } else if (ms->drmmode.glamor) {
252++ /* Atomic modesetting implicitly enables universal planes */
253++ if (!ms->drmmode.pageflip || ms->atomic_modeset ||
254++ !drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
255++ ms->drmmode.tearfree_enable = TRUE;
256++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TearFree: enabled\n");
257++ } else {
258++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
259++ "TearFree requires either universal planes, or setting 'Option \"PageFlip\" \"off\"'\n");
260++ }
261++ } else {
262++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
263++ "TearFree requires Glamor acceleration\n");
264++ }
265++ }
266++
267+ ms->kms_has_modifiers = FALSE;
268+ ret = drmGetCap(ms->fd, DRM_CAP_ADDFB2_MODIFIERS, &value);
269+ if (ret == 0 && value != 0)
270+@@ -1589,13 +1698,13 @@
271+
272+ err = drmModeDirtyFB(ms->fd, ms->drmmode.fb_id, NULL, 0);
273+
274+- if (err != -EINVAL && err != -ENOSYS) {
275++ if ((err != -EINVAL && err != -ENOSYS) || ms->drmmode.tearfree_enable) {
276+ ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
277+ pScreen, rootPixmap);
278+
279+ if (ms->damage) {
280+ DamageRegister(&rootPixmap->drawable, ms->damage);
281+- ms->dirty_enabled = TRUE;
282++ ms->dirty_enabled = err != -EINVAL && err != -ENOSYS;
283+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
284+ }
285+ else {
286+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/driver.h
287+===================================================================
288+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/driver.h 2022-12-19 05:53:03.000000000 -0500
289++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/driver.h 2023-01-09 10:11:45.541724797 -0500
290+@@ -61,6 +61,7 @@
291+ OPTION_VARIABLE_REFRESH,
292+ OPTION_USE_GAMMA_LUT,
293+ OPTION_ASYNC_FLIP_SECONDARIES,
294++ OPTION_TEARFREE,
295+ } modesettingOpts;
296+
297+ typedef struct
298+@@ -86,10 +87,13 @@
299+ struct xorg_list list;
300+ xf86CrtcPtr crtc;
301+ uint32_t seq;
302++ uint64_t msc;
303+ void *data;
304+ ScrnInfoPtr scrn;
305+ ms_drm_handler_proc handler;
306+ ms_drm_abort_proc abort;
307++ Bool kernel_queued;
308++ Bool aborted;
309+ };
310+
311+ typedef struct _modesettingRec {
312+@@ -238,6 +242,8 @@
313+ ms_pageflip_abort_proc pageflip_abort,
314+ const char *log_prefix);
315+
316++Bool ms_do_tearfree_flip(ScreenPtr screen, xf86CrtcPtr crtc);
317++
318+ #endif
319+
320+ int ms_flush_drm_events(ScreenPtr screen);
321+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/drmmode_display.c
322+===================================================================
323+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/drmmode_display.c 2023-01-09 10:11:15.278283797 -0500
324++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/drmmode_display.c 2023-01-09 10:11:45.541724797 -0500
325+@@ -632,6 +632,7 @@
326+ {
327+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
328+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
329++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
330+ int ret;
331+
332+ *fb_id = 0;
333+@@ -646,6 +647,10 @@
334+ *x = drmmode_crtc->prime_pixmap_x;
335+ *y = 0;
336+ }
337++ else if (trf->buf[trf->back_idx ^ 1].px) {
338++ *fb_id = trf->buf[trf->back_idx ^ 1].fb_id;
339++ *x = *y = 0;
340++ }
341+ else if (drmmode_crtc->rotate_fb_id) {
342+ *fb_id = drmmode_crtc->rotate_fb_id;
343+ *x = *y = 0;
344+@@ -922,6 +927,10 @@
345+ drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode);
346+ ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
347+ fb_id, x, y, output_ids, output_count, &kmode);
348++ if (!ret && !ms->atomic_modeset) {
349++ drmmode_crtc->src_x = x;
350++ drmmode_crtc->src_y = y;
351++ }
352+
353+ drmmode_set_ctm(crtc, ctm);
354+
355+@@ -930,7 +939,8 @@
356+ }
357+
358+ int
359+-drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
360++drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, int x, int y,
361++ uint32_t flags, void *data)
362+ {
363+ modesettingPtr ms = modesettingPTR(crtc->scrn);
364+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
365+@@ -942,7 +952,7 @@
366+ if (!req)
367+ return 1;
368+
369+- ret = plane_add_props(req, crtc, fb_id, crtc->x, crtc->y);
370++ ret = plane_add_props(req, crtc, fb_id, x, y);
371+ flags |= DRM_MODE_ATOMIC_NONBLOCK;
372+ if (ret == 0)
373+ ret = drmModeAtomicCommit(ms->fd, req, flags, data);
374+@@ -950,6 +960,26 @@
375+ return ret;
376+ }
377+
378++ /* The frame buffer source coordinates may change when switching between the
379++ * primary frame buffer and a per-CRTC frame buffer. Set the correct source
380++ * coordinates if they differ for this flip.
381++ */
382++ if (drmmode_crtc->src_x != x || drmmode_crtc->src_y != y) {
383++ ret = drmModeSetPlane(ms->fd, drmmode_crtc->plane_id,
384++ drmmode_crtc->mode_crtc->crtc_id, fb_id, 0,
385++ 0, 0, crtc->mode.HDisplay, crtc->mode.VDisplay,
386++ x << 16, y << 16, crtc->mode.HDisplay << 16,
387++ crtc->mode.VDisplay << 16);
388++ if (ret) {
389++ xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
390++ "error changing fb src coordinates for flip: %d\n", ret);
391++ return ret;
392++ }
393++
394++ drmmode_crtc->src_x = x;
395++ drmmode_crtc->src_y = y;
396++ }
397++
398+ return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
399+ fb_id, flags, data);
400+ }
401+@@ -1548,6 +1578,90 @@
402+ #endif
403+ }
404+
405++void
406++drmmode_copy_damage(xf86CrtcPtr crtc, PixmapPtr dst, RegionPtr dmg, Bool empty)
407++{
408++#ifdef GLAMOR_HAS_GBM
409++ ScreenPtr pScreen = xf86ScrnToScreen(crtc->scrn);
410++ DrawableRec *src;
411++
412++ /* Copy the screen's pixmap into the destination pixmap */
413++ if (crtc->rotatedPixmap) {
414++ src = &crtc->rotatedPixmap->drawable;
415++ xf86RotateCrtcRedisplay(crtc, dst, src, dmg, FALSE);
416++ } else {
417++ src = &pScreen->GetScreenPixmap(pScreen)->drawable;
418++ PixmapDirtyCopyArea(dst, src, 0, 0, -crtc->x, -crtc->y, dmg);
419++ }
420++
421++ /* Reset the damages if requested */
422++ if (empty)
423++ RegionEmpty(dmg);
424++
425++ /* Wait until the GC operations finish */
426++ modesettingPTR(crtc->scrn)->glamor.finish(pScreen);
427++#endif
428++}
429++
430++static void
431++drmmode_shadow_fb_destroy(xf86CrtcPtr crtc, PixmapPtr pixmap,
432++ void *data, drmmode_bo *bo, uint32_t *fb_id);
433++static void
434++drmmode_destroy_tearfree_shadow(xf86CrtcPtr crtc)
435++{
436++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
437++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
438++ int i;
439++
440++ if (trf->flip_seq)
441++ ms_drm_abort_seq(crtc->scrn, trf->flip_seq);
442++
443++ for (i = 0; i < ARRAY_SIZE(trf->buf); i++) {
444++ if (trf->buf[i].px) {
445++ drmmode_shadow_fb_destroy(crtc, trf->buf[i].px, (void *)(long)1,
446++ &trf->buf[i].bo, &trf->buf[i].fb_id);
447++ trf->buf[i].px = NULL;
448++ RegionUninit(&trf->buf[i].dmg);
449++ }
450++ }
451++}
452++
453++static PixmapPtr
454++drmmode_shadow_fb_create(xf86CrtcPtr crtc, void *data, int width, int height,
455++ drmmode_bo *bo, uint32_t *fb_id);
456++static Bool
457++drmmode_create_tearfree_shadow(xf86CrtcPtr crtc)
458++{
459++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
460++ drmmode_ptr drmmode = drmmode_crtc->drmmode;
461++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
462++ uint32_t w = crtc->mode.HDisplay, h = crtc->mode.VDisplay;
463++ int i;
464++
465++ if (!drmmode->tearfree_enable)
466++ return TRUE;
467++
468++ /* Destroy the old mode's buffers and make new ones */
469++ drmmode_destroy_tearfree_shadow(crtc);
470++ for (i = 0; i < ARRAY_SIZE(trf->buf); i++) {
471++ trf->buf[i].px = drmmode_shadow_fb_create(crtc, NULL, w, h,
472++ &trf->buf[i].bo,
473++ &trf->buf[i].fb_id);
474++ if (!trf->buf[i].px) {
475++ drmmode_destroy_tearfree_shadow(crtc);
476++ xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
477++ "shadow creation failed for TearFree buf%d\n", i);
478++ return FALSE;
479++ }
480++ RegionInit(&trf->buf[i].dmg, &crtc->bounds, 0);
481++ }
482++
483++ /* Initialize the front buffer with the current scanout */
484++ drmmode_copy_damage(crtc, trf->buf[trf->back_idx ^ 1].px,
485++ &trf->buf[trf->back_idx ^ 1].dmg, TRUE);
486++ return TRUE;
487++}
488++
489+ static Bool
490+ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
491+ Rotation rotation, int x, int y)
492+@@ -1581,6 +1695,10 @@
493+ crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
494+ crtc->gamma_blue, crtc->gamma_size);
495+
496++ ret = drmmode_create_tearfree_shadow(crtc);
497++ if (!ret)
498++ goto done;
499++
500+ can_test = drmmode_crtc_can_test_mode(crtc);
501+ if (drmmode_crtc_set_mode(crtc, can_test)) {
502+ xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
503+@@ -1626,6 +1744,7 @@
504+ crtc->y = saved_y;
505+ crtc->rotation = saved_rotation;
506+ crtc->mode = saved_mode;
507++ drmmode_create_tearfree_shadow(crtc);
508+ } else
509+ crtc->active = TRUE;
510+
511+@@ -1931,33 +2050,42 @@
512+ }
513+
514+ static void *
515+-drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
516++drmmode_shadow_fb_allocate(xf86CrtcPtr crtc, int width, int height,
517++ drmmode_bo *bo, uint32_t *fb_id)
518+ {
519+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
520+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
521+ int ret;
522+
523+- if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
524+- width, height, drmmode->kbpp)) {
525++ if (!drmmode_create_bo(drmmode, bo, width, height, drmmode->kbpp)) {
526+ xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
527+ "Couldn't allocate shadow memory for rotated CRTC\n");
528+ return NULL;
529+ }
530+
531+- ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
532+- &drmmode_crtc->rotate_fb_id);
533++ ret = drmmode_bo_import(drmmode, bo, fb_id);
534+
535+ if (ret) {
536+ ErrorF("failed to add rotate fb\n");
537+- drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
538++ drmmode_bo_destroy(drmmode, bo);
539+ return NULL;
540+ }
541+
542+ #ifdef GLAMOR_HAS_GBM
543+ if (drmmode->gbm)
544+- return drmmode_crtc->rotate_bo.gbm;
545++ return bo->gbm;
546+ #endif
547+- return drmmode_crtc->rotate_bo.dumb;
548++ return bo->dumb;
549++}
550++
551++static void *
552++drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
553++{
554++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
555++
556++ return drmmode_shadow_fb_allocate(crtc, width, height,
557++ &drmmode_crtc->rotate_bo,
558++ &drmmode_crtc->rotate_fb_id);
559+ }
560+
561+ static PixmapPtr
562+@@ -1983,71 +2111,92 @@
563+ drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
564+
565+ static PixmapPtr
566+-drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
567++drmmode_shadow_fb_create(xf86CrtcPtr crtc, void *data, int width, int height,
568++ drmmode_bo *bo, uint32_t *fb_id)
569+ {
570+ ScrnInfoPtr scrn = crtc->scrn;
571+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
572+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
573+- uint32_t rotate_pitch;
574+- PixmapPtr rotate_pixmap;
575++ uint32_t pitch;
576++ PixmapPtr pixmap;
577+ void *pPixData = NULL;
578+
579+ if (!data) {
580+- data = drmmode_shadow_allocate(crtc, width, height);
581++ data = drmmode_shadow_fb_allocate(crtc, width, height, bo, fb_id);
582+ if (!data) {
583+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
584+- "Couldn't allocate shadow pixmap for rotated CRTC\n");
585++ "Couldn't allocate shadow pixmap for CRTC\n");
586+ return NULL;
587+ }
588+ }
589+
590+- if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
591++ if (!drmmode_bo_has_bo(bo)) {
592+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
593+- "Couldn't allocate shadow pixmap for rotated CRTC\n");
594++ "Couldn't allocate shadow pixmap for CRTC\n");
595+ return NULL;
596+ }
597+
598+- pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
599+- rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo);
600++ pPixData = drmmode_bo_map(drmmode, bo);
601++ pitch = drmmode_bo_get_pitch(bo);
602+
603+- rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
604+- width, height,
605+- scrn->depth,
606+- drmmode->kbpp,
607+- rotate_pitch,
608+- pPixData);
609++ pixmap = drmmode_create_pixmap_header(scrn->pScreen,
610++ width, height,
611++ scrn->depth,
612++ drmmode->kbpp,
613++ pitch,
614++ pPixData);
615+
616+- if (rotate_pixmap == NULL) {
617++ if (pixmap == NULL) {
618+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
619+- "Couldn't allocate shadow pixmap for rotated CRTC\n");
620++ "Couldn't allocate shadow pixmap for CRTC\n");
621+ return NULL;
622+ }
623+
624+- drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
625++ drmmode_set_pixmap_bo(drmmode, pixmap, bo);
626++
627++ return pixmap;
628++}
629++
630++static PixmapPtr
631++drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
632++{
633++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
634+
635+- return rotate_pixmap;
636++ return drmmode_shadow_fb_create(crtc, data, width, height,
637++ &drmmode_crtc->rotate_bo,
638++ &drmmode_crtc->rotate_fb_id);
639+ }
640+
641+ static void
642+-drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
643++drmmode_shadow_fb_destroy(xf86CrtcPtr crtc, PixmapPtr pixmap,
644++ void *data, drmmode_bo *bo, uint32_t *fb_id)
645+ {
646+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
647+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
648+
649+- if (rotate_pixmap) {
650+- rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
651++ if (pixmap) {
652++ pixmap->drawable.pScreen->DestroyPixmap(pixmap);
653+ }
654+
655+ if (data) {
656+- drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
657+- drmmode_crtc->rotate_fb_id = 0;
658++ drmModeRmFB(drmmode->fd, *fb_id);
659++ *fb_id = 0;
660+
661+- drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
662+- memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
663++ drmmode_bo_destroy(drmmode, bo);
664++ memset(bo, 0, sizeof(*bo));
665+ }
666+ }
667+
668+ static void
669++drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr pixmap, void *data)
670++{
671++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
672++
673++ drmmode_shadow_fb_destroy(crtc, pixmap, data, &drmmode_crtc->rotate_bo,
674++ &drmmode_crtc->rotate_fb_id);
675++}
676++
677++static void
678+ drmmode_crtc_destroy(xf86CrtcPtr crtc)
679+ {
680+ drmmode_mode_ptr iterator, next;
681+@@ -2380,6 +2529,7 @@
682+ drmmode_crtc->drmmode = drmmode;
683+ drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
684+ xorg_list_init(&drmmode_crtc->mode_list);
685++ drmmode_crtc->next_msc = UINT64_MAX;
686+
687+ props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
688+ DRM_MODE_OBJECT_CRTC);
689+@@ -4253,6 +4403,7 @@
690+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
691+
692+ dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
693++ drmmode_destroy_tearfree_shadow(crtc);
694+ }
695+ }
696+
697+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/drmmode_display.h
698+===================================================================
699+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/drmmode_display.h 2022-12-19 05:53:03.000000000 -0500
700++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/drmmode_display.h 2023-01-09 10:11:45.541724797 -0500
701+@@ -135,6 +135,7 @@
702+ Bool async_flip_secondaries;
703+ Bool dri2_enable;
704+ Bool present_enable;
705++ Bool tearfree_enable;
706+
707+ uint32_t vrr_prop_id;
708+ Bool use_ctm;
709+@@ -167,6 +168,19 @@
710+ } drmmode_format_rec, *drmmode_format_ptr;
711+
712+ typedef struct {
713++ drmmode_bo bo;
714++ uint32_t fb_id;
715++ PixmapPtr px;
716++ RegionRec dmg;
717++} drmmode_shadow_fb_rec, *drmmode_shadow_fb_ptr;
718++
719++typedef struct {
720++ drmmode_shadow_fb_rec buf[2];
721++ uint32_t back_idx;
722++ uint32_t flip_seq;
723++} drmmode_tearfree_rec, *drmmode_tearfree_ptr;
724++
725++typedef struct {
726+ drmmode_ptr drmmode;
727+ drmModeCrtcPtr mode_crtc;
728+ uint32_t vblank_pipe;
729+@@ -184,11 +198,14 @@
730+
731+ drmmode_bo rotate_bo;
732+ unsigned rotate_fb_id;
733++ drmmode_tearfree_rec tearfree;
734+
735+ PixmapPtr prime_pixmap;
736+ PixmapPtr prime_pixmap_back;
737+ unsigned prime_pixmap_x;
738+
739++ int src_x, src_y;
740++
741+ /**
742+ * @{ MSC (vblank count) handling for the PRESENT extension.
743+ *
744+@@ -200,6 +217,8 @@
745+ uint64_t msc_high;
746+ /** @} */
747+
748++ uint64_t next_msc;
749++
750+ Bool need_modeset;
751+ struct xorg_list mode_list;
752+
753+@@ -308,8 +327,11 @@
754+ int *depth, int *bpp);
755+
756+ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
757++void drmmode_copy_damage(xf86CrtcPtr crtc, PixmapPtr dst, RegionPtr damage,
758++ Bool empty);
759+
760+-int drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data);
761++int drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, int x, int y,
762++ uint32_t flags, void *data);
763+
764+ void drmmode_set_dpms(ScrnInfoPtr scrn, int PowerManagementMode, int flags);
765+ void drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled);
766+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/modesetting.man
767+===================================================================
768+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/modesetting.man 2022-12-19 05:53:03.000000000 -0500
769++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/modesetting.man 2023-01-09 10:11:45.541724797 -0500
770+@@ -109,6 +109,17 @@
771+ entries, if supported by the kernel. By default, GAMMA_LUT will be used for
772+ kms drivers which are known to be safe for use of GAMMA_LUT.
773+ .TP
774++.BI "Option \*qTearFree\*q \*q" boolean \*q
775++Enable tearing prevention using the hardware page flipping mechanism.
776++It allocates two extra scanout buffers for each CRTC and utilizes damage
777++tracking to minimize buffer copying and skip unnecessary flips when the
778++screen's contents have not changed. It works on transformed screens too, such
779++as rotated and scaled CRTCs. When PageFlip is enabled, fullscreen DRI
780++applications will still have the discretion to not use tearing prevention.
781++.br
782++The default is
783++.B off.
784++.TP
785+ .SH "SEE ALSO"
786+ @xservername@(@appmansuffix@), @xconfigfile@(@filemansuffix@), Xserver(@appmansuffix@),
787+ X(@miscmansuffix@)
788+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/pageflip.c
789+===================================================================
790+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/pageflip.c 2022-12-19 05:53:03.000000000 -0500
791++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/pageflip.c 2023-01-09 10:11:45.541724797 -0500
792+@@ -35,8 +35,8 @@
793+ * Returns a negative value on error, 0 if there was nothing to process,
794+ * or 1 if we handled any events.
795+ */
796+-int
797+-ms_flush_drm_events(ScreenPtr screen)
798++static int
799++ms_flush_drm_events_timeout(ScreenPtr screen, int timeout)
800+ {
801+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
802+ modesettingPtr ms = modesettingPTR(scrn);
803+@@ -45,7 +45,7 @@
804+ int r;
805+
806+ do {
807+- r = xserver_poll(&p, 1, 0);
808++ r = xserver_poll(&p, 1, timeout);
809+ } while (r == -1 && (errno == EINTR || errno == EAGAIN));
810+
811+ /* If there was an error, r will be < 0. Return that. If there was
812+@@ -63,6 +63,12 @@
813+ return 1;
814+ }
815+
816++int
817++ms_flush_drm_events(ScreenPtr screen)
818++{
819++ return ms_flush_drm_events_timeout(screen, 0);
820++}
821++
822+ #ifdef GLAMOR_HAS_GBM
823+
824+ /*
825+@@ -160,11 +166,32 @@
826+ }
827+
828+ static Bool
829+-do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
830+- uint32_t flags, uint32_t seq)
831++do_queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc, uint32_t flags,
832++ uint32_t seq, uint32_t fb_id, int x, int y)
833+ {
834+- return drmmode_crtc_flip(crtc, ms->drmmode.fb_id, flags,
835+- (void *) (uintptr_t) seq);
836++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
837++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
838++
839++ while (drmmode_crtc_flip(crtc, fb_id, x, y, flags, (void *)(long)seq)) {
840++ /* We may have failed because the event queue was full. Flush it
841++ * and retry. If there was nothing to flush, then we failed for
842++ * some other reason and should just return an error.
843++ */
844++ if (ms_flush_drm_events(screen) <= 0) {
845++ /* The failure could be caused by a pending TearFree flip, in which
846++ * case we should wait until there's a new event and try again.
847++ */
848++ if (!trf->flip_seq || ms_flush_drm_events_timeout(screen, -1) < 0) {
849++ ms_drm_abort_seq(crtc->scrn, seq);
850++ return TRUE;
851++ }
852++ }
853++
854++ /* We flushed some events, so try again. */
855++ xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING, "flip queue retry\n");
856++ }
857++
858++ return FALSE;
859+ }
860+
861+ enum queue_flip_status {
862+@@ -205,20 +232,9 @@
863+ /* take a reference on flipdata for use in flip */
864+ flipdata->flip_count++;
865+
866+- while (do_queue_flip_on_crtc(ms, crtc, flags, seq)) {
867+- /* We may have failed because the event queue was full. Flush it
868+- * and retry. If there was nothing to flush, then we failed for
869+- * some other reason and should just return an error.
870+- */
871+- if (ms_flush_drm_events(screen) <= 0) {
872+- /* Aborting will also decrement flip_count and free(flip). */
873+- ms_drm_abort_seq(scrn, seq);
874+- return QUEUE_FLIP_DRM_FLUSH_FAILED;
875+- }
876+-
877+- /* We flushed some events, so try again. */
878+- xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue retry\n");
879+- }
880++ if (do_queue_flip_on_crtc(screen, crtc, flags, seq, ms->drmmode.fb_id,
881++ crtc->x, crtc->y))
882++ return QUEUE_FLIP_DRM_FLUSH_FAILED;
883+
884+ /* The page flip succeeded. */
885+ return QUEUE_FLIP_SUCCESS;
886+@@ -465,4 +481,50 @@
887+ #endif /* GLAMOR_HAS_GBM */
888+ }
889+
890++static void
891++ms_tearfree_flip_abort(void *data)
892++{
893++ drmmode_tearfree_ptr trf = data;
894++
895++ trf->flip_seq = 0;
896++}
897++
898++static void
899++ms_tearfree_flip_handler(uint64_t msc, uint64_t usec, void *data)
900++{
901++ drmmode_tearfree_ptr trf = data;
902++
903++ /* Swap the buffers and complete the flip */
904++ trf->back_idx ^= 1;
905++ trf->flip_seq = 0;
906++}
907++
908++Bool
909++ms_do_tearfree_flip(ScreenPtr screen, xf86CrtcPtr crtc)
910++{
911++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
912++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
913++ uint32_t idx = trf->back_idx, seq;
914++
915++ seq = ms_drm_queue_alloc(crtc, trf, ms_tearfree_flip_handler,
916++ ms_tearfree_flip_abort);
917++ if (!seq)
918++ goto no_flip;
919++
920++ /* Copy the damage to the back buffer and then flip it at the vblank */
921++ drmmode_copy_damage(crtc, trf->buf[idx].px, &trf->buf[idx].dmg, TRUE);
922++ if (do_queue_flip_on_crtc(screen, crtc, DRM_MODE_PAGE_FLIP_EVENT,
923++ seq, trf->buf[idx].fb_id, 0, 0))
924++ goto no_flip;
925++
926++ trf->flip_seq = seq;
927++ return FALSE;
928++
929++no_flip:
930++ xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
931++ "TearFree flip failed, rendering frame without TearFree\n");
932++ drmmode_copy_damage(crtc, trf->buf[idx ^ 1].px,
933++ &trf->buf[idx ^ 1].dmg, FALSE);
934++ return TRUE;
935++}
936+ #endif
937+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/present.c
938+===================================================================
939+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/present.c 2022-12-19 05:53:03.000000000 -0500
940++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/present.c 2023-01-09 10:11:45.541724797 -0500
941+@@ -318,14 +318,32 @@
942+ modesettingPtr ms = modesettingPTR(scrn);
943+
944+ if (ms->drmmode.sprites_visible > 0)
945+- return FALSE;
946++ goto no_flip;
947+
948+ if(!ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason))
949+- return FALSE;
950++ goto no_flip;
951+
952+ ms->flip_window = window;
953+
954+ return TRUE;
955++
956++no_flip:
957++ /* Export some info about TearFree if Present can't flip anyway */
958++ if (reason && ms->drmmode.tearfree_enable) {
959++ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
960++ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
961++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
962++
963++ if (trf->buf[0].px) {
964++ if (trf->flip_seq)
965++ /* The driver has a TearFree flip pending */
966++ *reason = PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING;
967++ else
968++ /* The driver uses TearFree flips and there's no flip pending */
969++ *reason = PRESENT_FLIP_REASON_DRIVER_TEARFREE;
970++ }
971++ }
972++ return FALSE;
973+ }
974+
975+ /*
976+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/vblank.c
977+===================================================================
978+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/vblank.c 2022-12-19 05:53:03.000000000 -0500
979++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/vblank.c 2023-01-09 10:11:45.541724797 -0500
980+@@ -260,6 +260,51 @@
981+ }
982+ }
983+
984++static void
985++ms_drm_set_seq_msc(uint32_t seq, uint64_t msc)
986++{
987++ struct ms_drm_queue *q;
988++
989++ xorg_list_for_each_entry(q, &ms_drm_queue, list) {
990++ if (q->seq == seq) {
991++ q->msc = msc;
992++ break;
993++ }
994++ }
995++}
996++
997++static void
998++ms_drm_set_seq_queued(uint32_t seq, uint64_t msc)
999++{
1000++ drmmode_crtc_private_ptr drmmode_crtc;
1001++ struct ms_drm_queue *q;
1002++
1003++ xorg_list_for_each_entry(q, &ms_drm_queue, list) {
1004++ if (q->seq == seq) {
1005++ drmmode_crtc = q->crtc->driver_private;
1006++ if (msc < drmmode_crtc->next_msc)
1007++ drmmode_crtc->next_msc = msc;
1008++ q->msc = msc;
1009++ q->kernel_queued = TRUE;
1010++ break;
1011++ }
1012++ }
1013++}
1014++
1015++static Bool
1016++ms_queue_coalesce(xf86CrtcPtr crtc, uint32_t seq, uint64_t msc)
1017++{
1018++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1019++
1020++ /* If the next MSC is too late, then this event can't be coalesced */
1021++ if (msc < drmmode_crtc->next_msc)
1022++ return FALSE;
1023++
1024++ /* Set the target MSC on this sequence number */
1025++ ms_drm_set_seq_msc(seq, msc);
1026++ return TRUE;
1027++}
1028++
1029+ Bool
1030+ ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,
1031+ uint64_t msc, uint64_t *msc_queued, uint32_t seq)
1032+@@ -271,6 +316,10 @@
1033+ drmVBlank vbl;
1034+ int ret;
1035+
1036++ /* Try coalescing this event into another to avoid event queue exhaustion */
1037++ if (flags == MS_QUEUE_ABSOLUTE && ms_queue_coalesce(crtc, seq, msc))
1038++ return TRUE;
1039++
1040+ for (;;) {
1041+ /* Queue an event at the specified sequence */
1042+ if (ms->has_queue_sequence || !ms->tried_queue_sequence) {
1043+@@ -287,8 +336,10 @@
1044+ ret = drmCrtcQueueSequence(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
1045+ drm_flags, msc, &kernel_queued, seq);
1046+ if (ret == 0) {
1047++ msc = ms_kernel_msc_to_crtc_msc(crtc, kernel_queued, TRUE);
1048++ ms_drm_set_seq_queued(seq, msc);
1049+ if (msc_queued)
1050+- *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, kernel_queued, TRUE);
1051++ *msc_queued = msc;
1052+ ms->has_queue_sequence = TRUE;
1053+ return TRUE;
1054+ }
1055+@@ -310,8 +361,10 @@
1056+ vbl.request.signal = seq;
1057+ ret = drmWaitVBlank(ms->fd, &vbl);
1058+ if (ret == 0) {
1059++ msc = ms_kernel_msc_to_crtc_msc(crtc, vbl.reply.sequence, FALSE);
1060++ ms_drm_set_seq_queued(seq, msc);
1061+ if (msc_queued)
1062+- *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, vbl.reply.sequence, FALSE);
1063++ *msc_queued = msc;
1064+ return TRUE;
1065+ }
1066+ check:
1067+@@ -418,13 +471,15 @@
1068+ if (!ms_drm_seq)
1069+ ++ms_drm_seq;
1070+ q->seq = ms_drm_seq++;
1071++ q->msc = UINT64_MAX;
1072+ q->scrn = scrn;
1073+ q->crtc = crtc;
1074+ q->data = data;
1075+ q->handler = handler;
1076+ q->abort = abort;
1077+
1078+- xorg_list_add(&q->list, &ms_drm_queue);
1079++ /* Keep the list formatted in ascending order of sequence number */
1080++ xorg_list_append(&q->list, &ms_drm_queue);
1081+
1082+ return q->seq;
1083+ }
1084+@@ -437,9 +492,18 @@
1085+ static void
1086+ ms_drm_abort_one(struct ms_drm_queue *q)
1087+ {
1088++ if (q->aborted)
1089++ return;
1090++
1091++ /* Don't remove vblank events if they were queued in the kernel */
1092++ if (q->kernel_queued) {
1093++ q->abort(q->data);
1094++ q->aborted = TRUE;
1095++ } else {
1096+ xorg_list_del(&q->list);
1097+ q->abort(q->data);
1098+ free(q);
1099++ }
1100+ }
1101+
1102+ /**
1103+@@ -500,18 +564,61 @@
1104+ {
1105+ struct ms_drm_queue *q, *tmp;
1106+ uint32_t seq = (uint32_t) user_data;
1107++ xf86CrtcPtr crtc = NULL;
1108++ drmmode_crtc_private_ptr drmmode_crtc;
1109++ uint64_t msc, next_msc = UINT64_MAX;
1110+
1111+- xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
1112++ /* Handle the seq for this event first in order to get the CRTC */
1113++ xorg_list_for_each_entry(q, &ms_drm_queue, list) {
1114+ if (q->seq == seq) {
1115+- uint64_t msc;
1116+-
1117+- msc = ms_kernel_msc_to_crtc_msc(q->crtc, frame, is64bit);
1118++ crtc = q->crtc;
1119++ msc = ms_kernel_msc_to_crtc_msc(crtc, frame, is64bit);
1120+ xorg_list_del(&q->list);
1121+- q->handler(msc, ns / 1000, q->data);
1122++ if (!q->aborted)
1123++ q->handler(msc, ns / 1000, q->data);
1124+ free(q);
1125+ break;
1126+ }
1127+ }
1128++
1129++ if (!crtc)
1130++ return;
1131++
1132++ /* Now run all of the vblank events for this CRTC with an expired MSC */
1133++ xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
1134++ if (q->crtc == crtc && q->msc <= msc) {
1135++ xorg_list_del(&q->list);
1136++ if (!q->aborted)
1137++ q->handler(msc, ns / 1000, q->data);
1138++ free(q);
1139++ }
1140++ }
1141++
1142++ /* Find this CRTC's next queued MSC and next non-queued MSC to be handled */
1143++ msc = UINT64_MAX;
1144++ xorg_list_for_each_entry(q, &ms_drm_queue, list) {
1145++ if (q->crtc == crtc) {
1146++ if (q->kernel_queued) {
1147++ if (q->msc < next_msc)
1148++ next_msc = q->msc;
1149++ } else if (q->msc < msc) {
1150++ msc = q->msc;
1151++ seq = q->seq;
1152++ }
1153++ }
1154++ }
1155++
1156++ /* Queue an event if the next queued MSC isn't soon enough */
1157++ drmmode_crtc = crtc->driver_private;
1158++ drmmode_crtc->next_msc = next_msc;
1159++ if (msc < next_msc && !ms_queue_vblank(crtc, MS_QUEUE_ABSOLUTE, msc, NULL, seq)) {
1160++ xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
1161++ "failed to queue next vblank event, aborting lost events\n");
1162++ xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
1163++ if (q->crtc == crtc && q->msc < next_msc)
1164++ ms_drm_abort_one(q);
1165++ }
1166++ }
1167+ }
1168+
1169+ static void
1170+Index: xorg-server-21.1.6/hw/xfree86/modes/xf86Crtc.h
1171+===================================================================
1172+--- xorg-server-21.1.6.orig/hw/xfree86/modes/xf86Crtc.h 2022-12-19 05:53:03.000000000 -0500
1173++++ xorg-server-21.1.6/hw/xfree86/modes/xf86Crtc.h 2023-01-09 10:11:45.541724797 -0500
1174+@@ -912,6 +912,11 @@
1175+ extern _X_EXPORT Bool
1176+ xf86CrtcRotate(xf86CrtcPtr crtc);
1177+
1178++extern _X_EXPORT void
1179++ xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, PixmapPtr dst_pixmap,
1180++ DrawableRec *src_drawable, RegionPtr region,
1181++ Bool transform_src);
1182++
1183+ /*
1184+ * Clean up any rotation data, used when a crtc is turned off
1185+ * as well as when rotation is disabled.
1186+Index: xorg-server-21.1.6/hw/xfree86/modes/xf86Rotate.c
1187+===================================================================
1188+--- xorg-server-21.1.6.orig/hw/xfree86/modes/xf86Rotate.c 2022-12-19 05:53:03.000000000 -0500
1189++++ xorg-server-21.1.6/hw/xfree86/modes/xf86Rotate.c 2023-01-09 10:11:45.541724797 -0500
1190+@@ -39,13 +39,13 @@
1191+ #include "X11/extensions/dpmsconst.h"
1192+ #include "X11/Xatom.h"
1193+
1194+-static void
1195+-xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, RegionPtr region)
1196++void
1197++xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, PixmapPtr dst_pixmap,
1198++ DrawableRec *src_drawable, RegionPtr region,
1199++ Bool transform_src)
1200+ {
1201+ ScrnInfoPtr scrn = crtc->scrn;
1202+ ScreenPtr screen = scrn->pScreen;
1203+- WindowPtr root = screen->root;
1204+- PixmapPtr dst_pixmap = crtc->rotatedPixmap;
1205+ PictFormatPtr format = PictureWindowFormat(screen->root);
1206+ int error;
1207+ PicturePtr src, dst;
1208+@@ -57,7 +57,7 @@
1209+ return;
1210+
1211+ src = CreatePicture(None,
1212+- &root->drawable,
1213++ src_drawable,
1214+ format,
1215+ CPSubwindowMode,
1216+ &include_inferiors, serverClient, &error);
1217+@@ -70,9 +70,11 @@
1218+ if (!dst)
1219+ return;
1220+
1221+- error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
1222+- if (error)
1223+- return;
1224++ if (transform_src) {
1225++ error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
1226++ if (error)
1227++ return;
1228++ }
1229+ if (crtc->transform_in_use && crtc->filter)
1230+ SetPicturePictFilter(src, crtc->filter, crtc->params, crtc->nparams);
1231+
1232+@@ -205,7 +207,9 @@
1233+
1234+ /* update damaged region */
1235+ if (RegionNotEmpty(&crtc_damage))
1236+- xf86RotateCrtcRedisplay(crtc, &crtc_damage);
1237++ xf86RotateCrtcRedisplay(crtc, crtc->rotatedPixmap,
1238++ &pScreen->root->drawable,
1239++ &crtc_damage, TRUE);
1240+
1241+ RegionUninit(&crtc_damage);
1242+ }
1243+Index: xorg-server-21.1.6/include/pixmap.h
1244+===================================================================
1245+--- xorg-server-21.1.6.orig/include/pixmap.h 2022-12-19 05:53:03.000000000 -0500
1246++++ xorg-server-21.1.6/include/pixmap.h 2023-01-09 10:11:45.541724797 -0500
1247+@@ -134,4 +134,9 @@
1248+ extern _X_EXPORT Bool
1249+ PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty);
1250+
1251++extern _X_EXPORT void
1252++PixmapDirtyCopyArea(PixmapPtr dst, DrawablePtr src,
1253++ int x, int y, int dst_x, int dst_y,
1254++ RegionPtr dirty_region);
1255++
1256+ #endif /* PIXMAP_H */
1257+Index: xorg-server-21.1.6/present/present.h
1258+===================================================================
1259+--- xorg-server-21.1.6.orig/present/present.h 2022-12-19 05:53:03.000000000 -0500
1260++++ xorg-server-21.1.6/present/present.h 2023-01-09 10:11:45.541724797 -0500
1261+@@ -29,7 +29,9 @@
1262+
1263+ typedef enum {
1264+ PRESENT_FLIP_REASON_UNKNOWN,
1265+- PRESENT_FLIP_REASON_BUFFER_FORMAT
1266++ PRESENT_FLIP_REASON_BUFFER_FORMAT,
1267++ PRESENT_FLIP_REASON_DRIVER_TEARFREE,
1268++ PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING
1269+ } PresentFlipReason;
1270+
1271+ typedef struct present_vblank present_vblank_rec, *present_vblank_ptr;
1272+Index: xorg-server-21.1.6/present/present_scmd.c
1273+===================================================================
1274+--- xorg-server-21.1.6.orig/present/present_scmd.c 2023-01-09 10:11:15.134286918 -0500
1275++++ xorg-server-21.1.6/present/present_scmd.c 2023-01-09 10:11:45.541724797 -0500
1276+@@ -71,6 +71,7 @@
1277+ PixmapPtr window_pixmap;
1278+ WindowPtr root = screen->root;
1279+ present_screen_priv_ptr screen_priv = present_screen_priv(screen);
1280++ PresentFlipReason tmp_reason = PRESENT_FLIP_REASON_UNKNOWN;
1281+
1282+ if (crtc) {
1283+ screen_priv = present_screen_priv(crtc->pScreen);
1284+@@ -91,6 +92,27 @@
1285+ if (!screen_priv->info->flip)
1286+ return FALSE;
1287+
1288++ /* Ask the driver for permission. Do this now to see if there's TearFree. */
1289++ if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
1290++ if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, &tmp_reason)) {
1291++ DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
1292++ /* It's fine to return now unless the page flip failure reason is
1293++ * PRESENT_FLIP_REASON_BUFFER_FORMAT; we must only output that
1294++ * reason if all the other checks pass.
1295++ */
1296++ if (!reason || tmp_reason != PRESENT_FLIP_REASON_BUFFER_FORMAT) {
1297++ if (reason)
1298++ *reason = tmp_reason;
1299++ return FALSE;
1300++ }
1301++ }
1302++ } else if (screen_priv->info->check_flip) {
1303++ if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
1304++ DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
1305++ return FALSE;
1306++ }
1307++ }
1308++
1309+ /* Make sure the window hasn't been redirected with Composite */
1310+ window_pixmap = screen->GetWindowPixmap(window);
1311+ if (window_pixmap != screen->GetScreenPixmap(screen) &&
1312+@@ -123,17 +145,10 @@
1313+ return FALSE;
1314+ }
1315+
1316+- /* Ask the driver for permission */
1317+- if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
1318+- if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
1319+- DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
1320+- return FALSE;
1321+- }
1322+- } else if (screen_priv->info->check_flip) {
1323+- if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
1324+- DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
1325+- return FALSE;
1326+- }
1327++ if (tmp_reason == PRESENT_FLIP_REASON_BUFFER_FORMAT) {
1328++ if (reason)
1329++ *reason = tmp_reason;
1330++ return FALSE;
1331+ }
1332+
1333+ return TRUE;
1334+@@ -462,7 +477,9 @@
1335+ xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
1336+ if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) {
1337+ vblank->flip = FALSE;
1338+- vblank->reason = reason;
1339++ /* Don't spuriously flag this as a TearFree presentation */
1340++ if (reason < PRESENT_FLIP_REASON_DRIVER_TEARFREE)
1341++ vblank->reason = reason;
1342+ if (vblank->sync_flip)
1343+ vblank->exec_msc = vblank->target_msc;
1344+ }
1345+@@ -543,6 +560,7 @@
1346+ WindowPtr window = vblank->window;
1347+ ScreenPtr screen = window->drawable.pScreen;
1348+ present_screen_priv_ptr screen_priv = present_screen_priv(screen);
1349++ uint64_t completion_msc;
1350+ if (vblank && vblank->crtc) {
1351+ screen_priv=present_screen_priv(vblank->crtc->pScreen);
1352+ }
1353+@@ -566,7 +584,9 @@
1354+ xorg_list_del(&vblank->window_list);
1355+ vblank->queued = FALSE;
1356+
1357+- if (vblank->pixmap && vblank->window) {
1358++ if (vblank->pixmap && vblank->window &&
1359++ (vblank->reason < PRESENT_FLIP_REASON_DRIVER_TEARFREE ||
1360++ vblank->exec_msc != vblank->target_msc)) {
1361+
1362+ if (vblank->flip) {
1363+
1364+@@ -633,6 +653,30 @@
1365+
1366+ present_execute_copy(vblank, crtc_msc);
1367+
1368++ /* The presentation will be visible at the next vblank with TearFree, so
1369++ * the PresentComplete notification needs to be sent at the next vblank.
1370++ * If TearFree is already flipping then the presentation will be visible
1371++ * at the *next* next vblank.
1372++ */
1373++ completion_msc = crtc_msc + 1;
1374++ switch (vblank->reason) {
1375++ case PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING:
1376++ if (vblank->exec_msc < crtc_msc)
1377++ completion_msc++;
1378++ case PRESENT_FLIP_REASON_DRIVER_TEARFREE:
1379++ if (Success == screen_priv->queue_vblank(screen,
1380++ window,
1381++ vblank->crtc,
1382++ vblank->event_id,
1383++ completion_msc)) {
1384++ /* Ensure present_execute_post() runs at the next MSC */
1385++ vblank->exec_msc = vblank->target_msc;
1386++ vblank->queued = TRUE;
1387++ }
1388++ default:
1389++ break;
1390++ }
1391++
1392+ if (vblank->queued) {
1393+ xorg_list_add(&vblank->event_queue, &present_exec_queue);
1394+ xorg_list_append(&vblank->window_list,
1395+@@ -745,6 +789,11 @@
1396+ if (vblank->crtc != target_crtc || vblank->target_msc != target_msc)
1397+ continue;
1398+
1399++ /* Too late to abort now if TearFree execution already happened */
1400++ if (vblank->reason >= PRESENT_FLIP_REASON_DRIVER_TEARFREE &&
1401++ vblank->exec_msc == vblank->target_msc)
1402++ continue;
1403++
1404+ present_vblank_scrap(vblank);
1405+ if (vblank->flip_ready)
1406+ present_re_execute(vblank);
1407+@@ -773,7 +822,12 @@
1408+
1409+ vblank->event_id = ++present_scmd_event_id;
1410+
1411+- if (vblank->flip && vblank->sync_flip)
1412++ /* The soonest presentation is crtc_msc+2 if TearFree is already flipping */
1413++ if (vblank->reason == PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING &&
1414++ !msc_is_after(vblank->exec_msc, crtc_msc + 1))
1415++ vblank->exec_msc -= 2;
1416++ else if (vblank->reason >= PRESENT_FLIP_REASON_DRIVER_TEARFREE ||
1417++ (vblank->flip && vblank->sync_flip))
1418+ vblank->exec_msc--;
1419+
1420+ xorg_list_append(&vblank->event_queue, &present_exec_queue);
1421diff --git a/debian/patches/tearfree-present-fixes.patch b/debian/patches/tearfree-present-fixes.patch
1422new file mode 100644
1423index 0000000..ac3bb67
1424--- /dev/null
1425+++ b/debian/patches/tearfree-present-fixes.patch
1426@@ -0,0 +1,632 @@
1427+Description: Fix inaccurate PresentCompleteNotify timing for TearFree
1428+ Note that this patch can be considered a continuation of
1429+ tearfree-modesetting.patch and finishing its implementation. Similar changes
1430+ were initially part of the original upstream merge request but were split off
1431+ to make it more wieldy.
1432+Origin: upstream, https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1042
1433+
1434+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/dri2.c
1435+===================================================================
1436+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/dri2.c
1437++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/dri2.c
1438+@@ -483,7 +483,6 @@ ms_dri2_schedule_flip(ms_dri2_frame_even
1439+ modesettingPtr ms = modesettingPTR(scrn);
1440+ ms_dri2_buffer_private_ptr back_priv = info->back->driverPrivate;
1441+ struct ms_dri2_vblank_event *event;
1442+- drmmode_crtc_private_ptr drmmode_crtc = info->crtc->driver_private;
1443+
1444+ event = calloc(1, sizeof(struct ms_dri2_vblank_event));
1445+ if (!event)
1446+@@ -495,7 +494,7 @@ ms_dri2_schedule_flip(ms_dri2_frame_even
1447+ event->event_data = info->event_data;
1448+
1449+ if (ms_do_pageflip(screen, back_priv->pixmap, event,
1450+- drmmode_crtc->vblank_pipe, FALSE,
1451++ info->crtc, FALSE,
1452+ ms_dri2_flip_handler,
1453+ ms_dri2_flip_abort,
1454+ "DRI2-flip")) {
1455+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/driver.c
1456+===================================================================
1457+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/driver.c
1458++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/driver.c
1459+@@ -623,9 +623,11 @@ ms_tearfree_do_flips(ScreenPtr pScreen)
1460+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1461+ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1462+
1463+- /* Skip disabled CRTCs and those which aren't using TearFree */
1464+- if (!trf->buf[0].px || !crtc->scrn->vtSema || !xf86_crtc_on(crtc))
1465++ if (!ms_tearfree_is_active_on_crtc(crtc)) {
1466++ /* Notify any lingering DRI clients waiting for a flip to finish */
1467++ ms_tearfree_dri_abort_all(crtc);
1468+ continue;
1469++ }
1470+
1471+ /* Skip if the last flip is still pending, a DRI client is flipping, or
1472+ * there isn't any damage on the front buffer.
1473+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/driver.h
1474+===================================================================
1475+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/driver.h
1476++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/driver.h
1477+@@ -236,12 +236,20 @@ typedef void (*ms_pageflip_abort_proc)(m
1478+ Bool ms_do_pageflip(ScreenPtr screen,
1479+ PixmapPtr new_front,
1480+ void *event,
1481+- int ref_crtc_vblank_pipe,
1482++ xf86CrtcPtr ref_crtc,
1483+ Bool async,
1484+ ms_pageflip_handler_proc pageflip_handler,
1485+ ms_pageflip_abort_proc pageflip_abort,
1486+ const char *log_prefix);
1487+
1488++Bool
1489++ms_tearfree_dri_abort(xf86CrtcPtr crtc,
1490++ Bool (*match)(void *data, void *match_data),
1491++ void *match_data);
1492++
1493++void
1494++ms_tearfree_dri_abort_all(xf86CrtcPtr crtc);
1495++
1496+ Bool ms_do_tearfree_flip(ScreenPtr screen, xf86CrtcPtr crtc);
1497+
1498+ #endif
1499+@@ -249,3 +257,4 @@ Bool ms_do_tearfree_flip(ScreenPtr scree
1500+ int ms_flush_drm_events(ScreenPtr screen);
1501+ Bool ms_window_has_variable_refresh(modesettingPtr ms, WindowPtr win);
1502+ void ms_present_set_screen_vrr(ScrnInfoPtr scrn, Bool vrr_enabled);
1503++Bool ms_tearfree_is_active_on_crtc(xf86CrtcPtr crtc);
1504+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/drmmode_display.c
1505+===================================================================
1506+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/drmmode_display.c
1507++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/drmmode_display.c
1508+@@ -2529,6 +2529,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drm
1509+ drmmode_crtc->drmmode = drmmode;
1510+ drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
1511+ xorg_list_init(&drmmode_crtc->mode_list);
1512++ xorg_list_init(&drmmode_crtc->tearfree.dri_flip_list);
1513+ drmmode_crtc->next_msc = UINT64_MAX;
1514+
1515+ props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
1516+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/drmmode_display.h
1517+===================================================================
1518+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/drmmode_display.h
1519++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/drmmode_display.h
1520+@@ -176,6 +176,7 @@ typedef struct {
1521+
1522+ typedef struct {
1523+ drmmode_shadow_fb_rec buf[2];
1524++ struct xorg_list dri_flip_list;
1525+ uint32_t back_idx;
1526+ uint32_t flip_seq;
1527+ } drmmode_tearfree_rec, *drmmode_tearfree_ptr;
1528+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/pageflip.c
1529+===================================================================
1530+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/pageflip.c
1531++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/pageflip.c
1532+@@ -99,6 +99,8 @@ struct ms_crtc_pageflip {
1533+ Bool on_reference_crtc;
1534+ /* reference to the ms_flipdata */
1535+ struct ms_flipdata *flipdata;
1536++ struct xorg_list node;
1537++ uint32_t tearfree_seq;
1538+ };
1539+
1540+ /**
1541+@@ -142,7 +144,8 @@ ms_pageflip_handler(uint64_t msc, uint64
1542+ flipdata->fe_usec,
1543+ flipdata->event);
1544+
1545+- drmModeRmFB(ms->fd, flipdata->old_fb_id);
1546++ if (flipdata->old_fb_id)
1547++ drmModeRmFB(ms->fd, flipdata->old_fb_id);
1548+ }
1549+ ms_pageflip_free(flip);
1550+ }
1551+@@ -204,11 +207,10 @@ enum queue_flip_status {
1552+ static int
1553+ queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
1554+ struct ms_flipdata *flipdata,
1555+- int ref_crtc_vblank_pipe, uint32_t flags)
1556++ xf86CrtcPtr ref_crtc, uint32_t flags)
1557+ {
1558+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1559+ modesettingPtr ms = modesettingPTR(scrn);
1560+- drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1561+ struct ms_crtc_pageflip *flip;
1562+ uint32_t seq;
1563+
1564+@@ -220,7 +222,7 @@ queue_flip_on_crtc(ScreenPtr screen, xf8
1565+ /* Only the reference crtc will finally deliver its page flip
1566+ * completion event. All other crtc's events will be discarded.
1567+ */
1568+- flip->on_reference_crtc = (drmmode_crtc->vblank_pipe == ref_crtc_vblank_pipe);
1569++ flip->on_reference_crtc = crtc == ref_crtc;
1570+ flip->flipdata = flipdata;
1571+
1572+ seq = ms_drm_queue_alloc(crtc, flip, ms_pageflip_handler, ms_pageflip_abort);
1573+@@ -310,20 +312,75 @@ ms_print_pageflip_error(int screen_index
1574+ }
1575+ }
1576+
1577++static Bool
1578++ms_tearfree_dri_flip(modesettingPtr ms, xf86CrtcPtr crtc, void *event,
1579++ ms_pageflip_handler_proc pageflip_handler,
1580++ ms_pageflip_abort_proc pageflip_abort)
1581++{
1582++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1583++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1584++ struct ms_crtc_pageflip *flip;
1585++ struct ms_flipdata *flipdata;
1586++ RegionRec region;
1587++ RegionPtr dirty;
1588++
1589++ if (!ms_tearfree_is_active_on_crtc(crtc))
1590++ return FALSE;
1591++
1592++ /* Check for damage on the primary scanout to know if TearFree will flip */
1593++ dirty = DamageRegion(ms->damage);
1594++ if (RegionNil(dirty))
1595++ return FALSE;
1596++
1597++ /* Compute how much of the current damage intersects with this CRTC */
1598++ RegionInit(&region, &crtc->bounds, 0);
1599++ RegionIntersect(&region, &region, dirty);
1600++
1601++ /* No damage on this CRTC means no TearFree flip. This means the DRI client
1602++ * didn't change this CRTC's contents at all with its presentation, possibly
1603++ * because its window is fully occluded by another window on this CRTC.
1604++ */
1605++ if (RegionNil(&region))
1606++ return FALSE;
1607++
1608++ flip = calloc(1, sizeof(*flip));
1609++ if (!flip)
1610++ return FALSE;
1611++
1612++ flipdata = calloc(1, sizeof(*flipdata));
1613++ if (!flipdata) {
1614++ free(flip);
1615++ return FALSE;
1616++ }
1617++
1618++ /* Only track the DRI client's fake flip on the reference CRTC, which aligns
1619++ * with the behavior of Present when a client copies its pixmap rather than
1620++ * directly flipping it onto the display.
1621++ */
1622++ flip->on_reference_crtc = TRUE;
1623++ flip->flipdata = flipdata;
1624++ flip->tearfree_seq = trf->flip_seq;
1625++ flipdata->screen = xf86ScrnToScreen(crtc->scrn);
1626++ flipdata->event = event;
1627++ flipdata->flip_count = 1;
1628++ flipdata->event_handler = pageflip_handler;
1629++ flipdata->abort_handler = pageflip_abort;
1630++
1631++ /* Keep the list in FIFO order so that clients are notified in order */
1632++ xorg_list_append(&flip->node, &trf->dri_flip_list);
1633++ return TRUE;
1634++}
1635+
1636+ Bool
1637+ ms_do_pageflip(ScreenPtr screen,
1638+ PixmapPtr new_front,
1639+ void *event,
1640+- int ref_crtc_vblank_pipe,
1641++ xf86CrtcPtr ref_crtc,
1642+ Bool async,
1643+ ms_pageflip_handler_proc pageflip_handler,
1644+ ms_pageflip_abort_proc pageflip_abort,
1645+ const char *log_prefix)
1646+ {
1647+-#ifndef GLAMOR_HAS_GBM
1648+- return FALSE;
1649+-#else
1650+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1651+ modesettingPtr ms = modesettingPTR(scrn);
1652+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1653+@@ -331,6 +388,22 @@ ms_do_pageflip(ScreenPtr screen,
1654+ uint32_t flags;
1655+ int i;
1656+ struct ms_flipdata *flipdata;
1657++
1658++ /* A NULL pixmap indicates this DRI client's pixmap is to be flipped through
1659++ * TearFree instead. The pixmap is already copied to the primary scanout at
1660++ * this point, so all that's left is to wire up this fake flip to TearFree
1661++ * so that TearFree can send a notification to the DRI client when the
1662++ * pixmap actually appears on the display. This is the only way to let DRI
1663++ * clients accurately know when their pixmaps appear on the display when
1664++ * TearFree is enabled.
1665++ */
1666++ if (!new_front) {
1667++ if (!ms_tearfree_dri_flip(ms, ref_crtc, event, pageflip_handler,
1668++ pageflip_abort))
1669++ goto error_free_event;
1670++ return TRUE;
1671++ }
1672++
1673+ ms->glamor.block_handler(screen);
1674+
1675+ new_front_bo.gbm = ms->glamor.gbm_bo_from_pixmap(screen, new_front);
1676+@@ -340,7 +413,7 @@ ms_do_pageflip(ScreenPtr screen,
1677+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1678+ "%s: Failed to get GBM BO for flip to new front.\n",
1679+ log_prefix);
1680+- return FALSE;
1681++ goto error_free_event;
1682+ }
1683+
1684+ flipdata = calloc(1, sizeof(struct ms_flipdata));
1685+@@ -348,7 +421,7 @@ ms_do_pageflip(ScreenPtr screen,
1686+ drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
1687+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1688+ "%s: Failed to allocate flipdata.\n", log_prefix);
1689+- return FALSE;
1690++ goto error_free_event;
1691+ }
1692+
1693+ flipdata->event = event;
1694+@@ -396,7 +469,6 @@ ms_do_pageflip(ScreenPtr screen,
1695+ for (i = 0; i < config->num_crtc; i++) {
1696+ enum queue_flip_status flip_status;
1697+ xf86CrtcPtr crtc = config->crtc[i];
1698+- drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1699+
1700+ if (!xf86_crtc_on(crtc))
1701+ continue;
1702+@@ -417,13 +489,11 @@ ms_do_pageflip(ScreenPtr screen,
1703+ * outputs in a "clone-mode" or "mirror-mode" configuration.
1704+ */
1705+ if (ms->drmmode.can_async_flip && ms->drmmode.async_flip_secondaries &&
1706+- (drmmode_crtc->vblank_pipe != ref_crtc_vblank_pipe) &&
1707+- (ref_crtc_vblank_pipe >= 0))
1708++ ref_crtc && crtc != ref_crtc)
1709+ flags |= DRM_MODE_PAGE_FLIP_ASYNC;
1710+
1711+ flip_status = queue_flip_on_crtc(screen, crtc, flipdata,
1712+- ref_crtc_vblank_pipe,
1713+- flags);
1714++ ref_crtc, flags);
1715+
1716+ switch (flip_status) {
1717+ case QUEUE_FLIP_ALLOC_FAILED:
1718+@@ -472,31 +542,106 @@ error_out:
1719+ drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
1720+ /* if only the local reference - free the structure,
1721+ * else drop the local reference and return */
1722+- if (flipdata->flip_count == 1)
1723++ if (flipdata->flip_count == 1) {
1724+ free(flipdata);
1725+- else
1726++ } else {
1727+ flipdata->flip_count--;
1728++ return FALSE;
1729++ }
1730+
1731++error_free_event:
1732++ /* Free the event since the caller has no way to know it's safe to free */
1733++ free(event);
1734+ return FALSE;
1735+-#endif /* GLAMOR_HAS_GBM */
1736++}
1737++
1738++Bool
1739++ms_tearfree_dri_abort(xf86CrtcPtr crtc,
1740++ Bool (*match)(void *data, void *match_data),
1741++ void *match_data)
1742++{
1743++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1744++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1745++ struct ms_crtc_pageflip *flip;
1746++
1747++ /* The window is getting destroyed; abort without notifying the client */
1748++ xorg_list_for_each_entry(flip, &trf->dri_flip_list, node) {
1749++ if (match(flip->flipdata->event, match_data)) {
1750++ xorg_list_del(&flip->node);
1751++ ms_pageflip_abort(flip);
1752++ return TRUE;
1753++ }
1754++ }
1755++
1756++ return FALSE;
1757++}
1758++
1759++void
1760++ms_tearfree_dri_abort_all(xf86CrtcPtr crtc)
1761++{
1762++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1763++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1764++ struct ms_crtc_pageflip *flip, *tmp;
1765++ uint64_t usec = 0, msc = 0;
1766++
1767++ /* Nothing to abort if there aren't any DRI clients waiting for a flip */
1768++ if (xorg_list_is_empty(&trf->dri_flip_list))
1769++ return;
1770++
1771++ /* Even though we're aborting, these clients' pixmaps were actually blitted,
1772++ * so technically the presentation isn't aborted. That's why the normal
1773++ * handler is called instead of the abort handler, along with the current
1774++ * time and MSC for this CRTC.
1775++ */
1776++ ms_get_crtc_ust_msc(crtc, &usec, &msc);
1777++ xorg_list_for_each_entry_safe(flip, tmp, &trf->dri_flip_list, node)
1778++ ms_pageflip_handler(msc, usec, flip);
1779++ xorg_list_init(&trf->dri_flip_list);
1780++}
1781++
1782++static void
1783++ms_tearfree_dri_notify(drmmode_tearfree_ptr trf, uint64_t msc, uint64_t usec)
1784++{
1785++ struct ms_crtc_pageflip *flip, *tmp;
1786++
1787++ xorg_list_for_each_entry_safe(flip, tmp, &trf->dri_flip_list, node) {
1788++ /* If a TearFree flip was already pending at the time this DRI client's
1789++ * pixmap was copied, then the pixmap isn't contained in this TearFree
1790++ * flip, but will be part of the next TearFree flip instead.
1791++ */
1792++ if (flip->tearfree_seq) {
1793++ flip->tearfree_seq = 0;
1794++ } else {
1795++ xorg_list_del(&flip->node);
1796++ ms_pageflip_handler(msc, usec, flip);
1797++ }
1798++ }
1799+ }
1800+
1801+ static void
1802+ ms_tearfree_flip_abort(void *data)
1803+ {
1804+- drmmode_tearfree_ptr trf = data;
1805++ xf86CrtcPtr crtc = data;
1806++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1807++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1808+
1809+ trf->flip_seq = 0;
1810++ ms_tearfree_dri_abort_all(crtc);
1811+ }
1812+
1813+ static void
1814+ ms_tearfree_flip_handler(uint64_t msc, uint64_t usec, void *data)
1815+ {
1816+- drmmode_tearfree_ptr trf = data;
1817++ xf86CrtcPtr crtc = data;
1818++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1819++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1820+
1821+ /* Swap the buffers and complete the flip */
1822+ trf->back_idx ^= 1;
1823+ trf->flip_seq = 0;
1824++
1825++ /* Notify DRI clients that their pixmaps are now visible on the display */
1826++ ms_tearfree_dri_notify(trf, msc, usec);
1827+ }
1828+
1829+ Bool
1830+@@ -506,10 +651,16 @@ ms_do_tearfree_flip(ScreenPtr screen, xf
1831+ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1832+ uint32_t idx = trf->back_idx, seq;
1833+
1834+- seq = ms_drm_queue_alloc(crtc, trf, ms_tearfree_flip_handler,
1835++ seq = ms_drm_queue_alloc(crtc, crtc, ms_tearfree_flip_handler,
1836+ ms_tearfree_flip_abort);
1837+- if (!seq)
1838++ if (!seq) {
1839++ /* Need to notify the DRI clients if a sequence wasn't allocated. Once a
1840++ * sequence is allocated, explicitly performing this cleanup isn't
1841++ * necessary since it's already done as part of aborting the sequence.
1842++ */
1843++ ms_tearfree_dri_abort_all(crtc);
1844+ goto no_flip;
1845++ }
1846+
1847+ /* Copy the damage to the back buffer and then flip it at the vblank */
1848+ drmmode_copy_damage(crtc, trf->buf[idx].px, &trf->buf[idx].dmg, TRUE);
1849+@@ -528,3 +679,13 @@ no_flip:
1850+ return TRUE;
1851+ }
1852+ #endif
1853++
1854++Bool
1855++ms_tearfree_is_active_on_crtc(xf86CrtcPtr crtc)
1856++{
1857++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1858++ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1859++
1860++ /* If TearFree is enabled, XServer owns the VT, and the CRTC is active */
1861++ return trf->buf[0].px && crtc->scrn->vtSema && xf86_crtc_on(crtc);
1862++}
1863+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/present.c
1864+===================================================================
1865+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/present.c
1866++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/present.c
1867+@@ -165,6 +165,13 @@ ms_present_abort_vblank(RRCrtcPtr crtc,
1868+ {
1869+ ScreenPtr screen = crtc->pScreen;
1870+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1871++#ifdef GLAMOR_HAS_GBM
1872++ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
1873++
1874++ /* Check if this is a fake flip routed through TearFree and abort it */
1875++ if (ms_tearfree_dri_abort(xf86_crtc, ms_present_event_match, &event_id))
1876++ return;
1877++#endif
1878+
1879+ ms_drm_abort(scrn, ms_present_event_match, &event_id);
1880+ }
1881+@@ -329,12 +336,12 @@ ms_present_check_flip(RRCrtcPtr crtc,
1882+
1883+ no_flip:
1884+ /* Export some info about TearFree if Present can't flip anyway */
1885+- if (reason && ms->drmmode.tearfree_enable) {
1886++ if (reason) {
1887+ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
1888+ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
1889+ drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
1890+
1891+- if (trf->buf[0].px) {
1892++ if (ms_tearfree_is_active_on_crtc(xf86_crtc)) {
1893+ if (trf->flip_seq)
1894+ /* The driver has a TearFree flip pending */
1895+ *reason = PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING;
1896+@@ -361,11 +368,12 @@ ms_present_flip(RRCrtcPtr crtc,
1897+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1898+ modesettingPtr ms = modesettingPTR(scrn);
1899+ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
1900+- drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
1901+ Bool ret;
1902+ struct ms_present_vblank_event *event;
1903+
1904+- if (!ms_present_check_flip(crtc, ms->flip_window, pixmap, sync_flip, NULL))
1905++ /* A NULL pixmap means this is a fake flip to be routed through TearFree */
1906++ if (pixmap &&
1907++ !ms_present_check_flip(crtc, ms->flip_window, pixmap, sync_flip, NULL))
1908+ return FALSE;
1909+
1910+ event = calloc(1, sizeof(struct ms_present_vblank_event));
1911+@@ -378,6 +386,12 @@ ms_present_flip(RRCrtcPtr crtc,
1912+ event->event_id = event_id;
1913+ event->unflip = FALSE;
1914+
1915++ /* Register the fake flip (indicated by a NULL pixmap) with TearFree */
1916++ if (!pixmap)
1917++ return ms_do_pageflip(screen, NULL, event, xf86_crtc, FALSE,
1918++ ms_present_flip_handler, ms_present_flip_abort,
1919++ "Present-TearFree-flip");
1920++
1921+ /* A window can only flip if it covers the entire X screen.
1922+ * Only one window can flip at a time.
1923+ *
1924+@@ -389,7 +403,7 @@ ms_present_flip(RRCrtcPtr crtc,
1925+ ms_present_set_screen_vrr(scrn, TRUE);
1926+ }
1927+
1928+- ret = ms_do_pageflip(screen, pixmap, event, drmmode_crtc->vblank_pipe, !sync_flip,
1929++ ret = ms_do_pageflip(screen, pixmap, event, xf86_crtc, !sync_flip,
1930+ ms_present_flip_handler, ms_present_flip_abort,
1931+ "Present-flip");
1932+ if (ret)
1933+@@ -421,7 +435,7 @@ ms_present_unflip(ScreenPtr screen, uint
1934+ event->unflip = TRUE;
1935+
1936+ if (ms_present_check_unflip(NULL, screen->root, pixmap, TRUE, NULL) &&
1937+- ms_do_pageflip(screen, pixmap, event, -1, FALSE,
1938++ ms_do_pageflip(screen, pixmap, event, NULL, FALSE,
1939+ ms_present_flip_handler, ms_present_flip_abort,
1940+ "Present-unflip")) {
1941+ return;
1942+Index: xorg-server-21.1.6/hw/xfree86/drivers/modesetting/vblank.c
1943+===================================================================
1944+--- xorg-server-21.1.6.orig/hw/xfree86/drivers/modesetting/vblank.c
1945++++ xorg-server-21.1.6/hw/xfree86/drivers/modesetting/vblank.c
1946+@@ -573,10 +573,15 @@ ms_drm_sequence_handler(int fd, uint64_t
1947+ if (q->seq == seq) {
1948+ crtc = q->crtc;
1949+ msc = ms_kernel_msc_to_crtc_msc(crtc, frame, is64bit);
1950+- xorg_list_del(&q->list);
1951+- if (!q->aborted)
1952+- q->handler(msc, ns / 1000, q->data);
1953+- free(q);
1954++
1955++ /* Write the current MSC to this event to ensure its handler runs in
1956++ * the loop below. This is done because we don't want to run the
1957++ * handler right now, since we need to ensure all events are handled
1958++ * in FIFO order with respect to one another. Otherwise, if this
1959++ * event were handled first just because it was queued to the
1960++ * kernel, it could run before older events expiring at this MSC.
1961++ */
1962++ q->msc = msc;
1963+ break;
1964+ }
1965+ }
1966+Index: xorg-server-21.1.6/present/present.h
1967+===================================================================
1968+--- xorg-server-21.1.6.orig/present/present.h
1969++++ xorg-server-21.1.6/present/present.h
1970+@@ -30,6 +30,12 @@
1971+ typedef enum {
1972+ PRESENT_FLIP_REASON_UNKNOWN,
1973+ PRESENT_FLIP_REASON_BUFFER_FORMAT,
1974++
1975++ /* Don't add new flip reasons after the TearFree ones, since it's expected
1976++ * that the TearFree reasons are the highest ones in order to allow doing
1977++ * `reason >= PRESENT_FLIP_REASON_DRIVER_TEARFREE` to check if a reason is
1978++ * PRESENT_FLIP_REASON_DRIVER_TEARFREE{_FLIPPING}.
1979++ */
1980+ PRESENT_FLIP_REASON_DRIVER_TEARFREE,
1981+ PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING
1982+ } PresentFlipReason;
1983+Index: xorg-server-21.1.6/present/present_scmd.c
1984+===================================================================
1985+--- xorg-server-21.1.6.orig/present/present_scmd.c
1986++++ xorg-server-21.1.6/present/present_scmd.c
1987+@@ -560,7 +560,6 @@ present_execute(present_vblank_ptr vblan
1988+ WindowPtr window = vblank->window;
1989+ ScreenPtr screen = window->drawable.pScreen;
1990+ present_screen_priv_ptr screen_priv = present_screen_priv(screen);
1991+- uint64_t completion_msc;
1992+ if (vblank && vblank->crtc) {
1993+ screen_priv=present_screen_priv(vblank->crtc->pScreen);
1994+ }
1995+@@ -653,28 +652,49 @@ present_execute(present_vblank_ptr vblan
1996+
1997+ present_execute_copy(vblank, crtc_msc);
1998+
1999+- /* The presentation will be visible at the next vblank with TearFree, so
2000+- * the PresentComplete notification needs to be sent at the next vblank.
2001+- * If TearFree is already flipping then the presentation will be visible
2002+- * at the *next* next vblank.
2003++ /* With TearFree, there's no way to tell exactly when the presentation
2004++ * will be visible except by waiting for a notification from the kernel
2005++ * driver indicating that the page flip is complete. This is because the
2006++ * CRTC's MSC can change while the target MSC is calculated and even
2007++ * while the page flip IOCTL is sent to the kernel due to scheduling
2008++ * delays and/or unfortunate timing. Even worse, a page flip isn't
2009++ * actually guaranteed to be finished after one vblank; it may be
2010++ * several MSCs until a flip actually finishes depending on delays and
2011++ * load in hardware.
2012++ *
2013++ * So, to get a notification from the driver with TearFree active, the
2014++ * driver expects a present_flip() call with a NULL pixmap to indicate
2015++ * that this is a fake flip for a pixmap that's already been copied to
2016++ * the primary scanout, which will then be flipped by TearFree. TearFree
2017++ * will then send a notification once the flip containing this pixmap is
2018++ * complete.
2019++ *
2020++ * If the fake flip attempt fails, then fall back to just enqueuing a
2021++ * vblank event targeting the next MSC.
2022+ */
2023+- completion_msc = crtc_msc + 1;
2024+- switch (vblank->reason) {
2025+- case PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING:
2026+- if (vblank->exec_msc < crtc_msc)
2027+- completion_msc++;
2028+- case PRESENT_FLIP_REASON_DRIVER_TEARFREE:
2029+- if (Success == screen_priv->queue_vblank(screen,
2030++ if (!vblank->queued &&
2031++ vblank->reason >= PRESENT_FLIP_REASON_DRIVER_TEARFREE) {
2032++ uint64_t completion_msc = crtc_msc + 1;
2033++
2034++ /* If TearFree is already flipping then the presentation will be
2035++ * visible at the *next* next vblank. This calculation only matters
2036++ * for the vblank event fallback.
2037++ */
2038++ if (vblank->reason == PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING &&
2039++ vblank->exec_msc < crtc_msc)
2040++ completion_msc++;
2041++
2042++ /* Try the fake flip first and then fall back to a vblank event */
2043++ if (present_flip(vblank->crtc, vblank->event_id, 0, NULL, TRUE) ||
2044++ Success == screen_priv->queue_vblank(screen,
2045+ window,
2046+ vblank->crtc,
2047+ vblank->event_id,
2048+ completion_msc)) {
2049+- /* Ensure present_execute_post() runs at the next MSC */
2050++ /* Ensure present_execute_post() runs at the next execution */
2051+ vblank->exec_msc = vblank->target_msc;
2052+ vblank->queued = TRUE;
2053+ }
2054+- default:
2055+- break;
2056+ }
2057+
2058+ if (vblank->queued) {

Subscribers

People subscribed via source and target branches