<div dir="ltr">Hi<div><br></div><div>This doesn't seem to apply cleanly to master or 1.19.6, am I missing something?</div><div><br></div><div>Cheers</div><div><br></div><div>Mike</div></div><br><div class="gmail_quote"><div dir="ltr">On Sun, 6 May 2018 at 06:35 Mario Kleiner <<a href="mailto:mario.kleiner.de@gmail.com">mario.kleiner.de@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">The old 32-Bit wraparound handling didn't actually work,<br>
due to some integer casting bug, and the mapping was ill<br>
equipped to deal with input from the new true 64-bit<br>
GetCrtcSequence/QueueCrtcSequence api's introduced in Linux<br>
4.15.<br>
<br>
For 32-Bit truncated input from pageflip events and old vblank<br>
events and old drmWaitVblank ioctl, implement new wraparound<br>
handling, which also allows to deal with wraparound in the other<br>
direction, e.g., if a 32-Bit truncated sequence value is passed<br>
in, whose true 64-Bit in-kernel hw value is within 2^30 counts<br>
of the previous processed value, but whose 32-bit truncated<br>
sequence value happens to lie just above or below a 2^32<br>
boundary, iow. one of the two values 'sequence' vs. 'msc_prev'<br>
lies above a 2^32 border, the other one below it.<br>
<br>
The method is directly translated from Mesa's proven implementation<br>
of the INTEL_swap_events extension, where a true underlying<br>
64-Bit wide swapbuffers count (SBC) needs to get reconstructed<br>
from a 32-Bit LSB truncated SBC transported over the X11 protocol<br>
wire. Same conditions apply, ie. successive true 64-Bit SBC<br>
values are close to each other, but don't always get received<br>
in strictly monotonically increasing order. See Mesa commit<br>
cc5ddd584d17abd422ae4d8e83805969485740d9 ("glx: Handle<br>
out-of-sequence swap completion events correctly. (v2)") for<br>
explanation.<br>
<br>
Additionally add a separate path for true 64-bit msc input<br>
originating from Linux 4.15+ drmCrtcGetSequence/QueueSequence<br>
ioctl's and corresponding 64-bit vblank events. True 64-bit<br>
msc's don't need remapping and must be passed through.<br>
<br>
As a reliability bonus, they are also used here to update the<br>
tracking values msc_prev and ms_high with perfect 64-Bit ground<br>
truth as baseline for mapping msc from pageflip completion events,<br>
because pageflip events are always 32-bit wide, even when the new<br>
kernel api's are used. Because each pageflip(-event) is always<br>
preceeded close in time (and vblank count) by a drmCrtcQueueSequence<br>
queued event or drmCrtcGetSequence query as part of DRI2 or DRI3+Present<br>
swap scheduling, we can be certain that each pageflip event will get<br>
its truncated 32-bit msc remapped reliably to the true 64-bit msc of<br>
flip completion whenever the sequence api is available, ie. on Linux<br>
4.15 or later.<br>
<br>
Note: In principle at least the 32-bit mapping path could also<br>
be backported to earlier server branches, as this seems to be<br>
broken for at least server 1.16 to 1.19.<br>
<br>
Signed-off-by: Mario Kleiner <<a href="mailto:mario.kleiner.de@gmail.com" target="_blank">mario.kleiner.de@gmail.com</a>><br>
Cc: Adam Jackson <<a href="mailto:ajax@redhat.com" target="_blank">ajax@redhat.com</a>><br>
Cc: Keith Packard <<a href="mailto:keithp@keithp.com" target="_blank">keithp@keithp.com</a>><br>
Cc: Michel Dänzer <<a href="mailto:michel.daenzer@amd.com" target="_blank">michel.daenzer@amd.com</a>><br>
---<br>
hw/xfree86/drivers/modesetting/driver.h | 2 +-<br>
hw/xfree86/drivers/modesetting/vblank.c | 66 ++++++++++++++++++++++++++-------<br>
2 files changed, 54 insertions(+), 14 deletions(-)<br>
<br>
diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h<br>
index 3a81d4d..55f3400 100644<br>
--- a/hw/xfree86/drivers/modesetting/driver.h<br>
+++ b/hw/xfree86/drivers/modesetting/driver.h<br>
@@ -149,7 +149,7 @@ xf86CrtcPtr ms_dri2_crtc_covering_drawable(DrawablePtr pDraw);<br>
<br>
int ms_get_crtc_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc);<br>
<br>
-uint64_t ms_kernel_msc_to_crtc_msc(xf86CrtcPtr crtc, uint64_t sequence);<br>
+uint64_t ms_kernel_msc_to_crtc_msc(xf86CrtcPtr crtc, uint64_t sequence, Bool is64bit);<br>
<br>
<br>
Bool ms_dri2_screen_init(ScreenPtr screen);<br>
diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c<br>
index d1a6fc1..561229f 100644<br>
--- a/hw/xfree86/drivers/modesetting/vblank.c<br>
+++ b/hw/xfree86/drivers/modesetting/vblank.c<br>
@@ -239,7 +239,7 @@ ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,<br>
drm_flags, msc, &kernel_queued, seq);<br>
if (ret == 0) {<br>
if (msc_queued)<br>
- *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, kernel_queued);<br>
+ *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, kernel_queued, TRUE);<br>
ms->has_queue_sequence = TRUE;<br>
return TRUE;<br>
}<br>
@@ -262,7 +262,7 @@ ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,<br>
ret = drmWaitVBlank(ms->fd, &vbl);<br>
if (ret == 0) {<br>
if (msc_queued)<br>
- *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, vbl.reply.sequence);<br>
+ *msc_queued = ms_kernel_msc_to_crtc_msc(crtc, vbl.reply.sequence, FALSE);<br>
return TRUE;<br>
}<br>
check:<br>
@@ -275,28 +275,59 @@ ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,<br>
}<br>
<br>
/**<br>
- * Convert a 32-bit kernel MSC sequence number to a 64-bit local sequence<br>
- * number, adding in the high 32 bits, and dealing with 64-bit wrapping.<br>
+ * Convert a 32-bit or 64-bit kernel MSC sequence number to a 64-bit local<br>
+ * sequence number, adding in the high 32 bits, and dealing with 32-bit<br>
+ * wrapping if needed.<br>
*/<br>
uint64_t<br>
-ms_kernel_msc_to_crtc_msc(xf86CrtcPtr crtc, uint64_t sequence)<br>
+ms_kernel_msc_to_crtc_msc(xf86CrtcPtr crtc, uint64_t sequence, Bool is64bit)<br>
{<br>
drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;<br>
<br>
- if ((int32_t) (sequence - drmmode_crtc->msc_prev) < -0x40000000)<br>
- drmmode_crtc->msc_high += 0x100000000L;<br>
+ if (!is64bit) {<br>
+ /* sequence is provided as a 32 bit value from one of the 32 bit apis,<br>
+ * e.g., drmWaitVBlank(), classic vblank events, or pageflip events.<br>
+ *<br>
+ * Track and handle 32-Bit wrapping, somewhat robust against occasional<br>
+ * out-of-order not always monotonically increasing sequence values.<br>
+ */<br>
+ if ((int64_t) sequence < ((int64_t) drmmode_crtc->msc_prev - 0x40000000))<br>
+ drmmode_crtc->msc_high += 0x100000000L;<br>
+<br>
+ if ((int64_t) sequence > ((int64_t) drmmode_crtc->msc_prev + 0x40000000))<br>
+ drmmode_crtc->msc_high -= 0x100000000L;<br>
+<br>
+ drmmode_crtc->msc_prev = sequence;<br>
+<br>
+ return drmmode_crtc->msc_high + sequence;<br>
+ }<br>
+<br>
+ /* True 64-Bit sequence from Linux 4.15+ 64-Bit drmCrtcGetSequence /<br>
+ * drmCrtcQueueSequence apis and events. Pass through sequence unmodified,<br>
+ * but update the 32-bit tracking variables with reliable ground truth.<br>
+ *<br>
+ * With 64-Bit api in use, the only !is64bit input is from pageflip events,<br>
+ * and any pageflip event is usually preceeded by some is64bit input from<br>
+ * swap scheduling, so this should provide reliable mapping for pageflip<br>
+ * events based on true 64-bit input as baseline as well.<br>
+ */<br>
drmmode_crtc->msc_prev = sequence;<br>
- return drmmode_crtc->msc_high + sequence;<br>
+ drmmode_crtc->msc_high = sequence & 0xffffffff00000000;<br>
+<br>
+ return sequence;<br>
}<br>
<br>
int<br>
ms_get_crtc_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)<br>
{<br>
+ ScreenPtr screen = crtc->randr_crtc->pScreen;<br>
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);<br>
+ modesettingPtr ms = modesettingPTR(scrn);<br>
uint64_t kernel_msc;<br>
<br>
if (!ms_get_kernel_ust_msc(crtc, &kernel_msc, ust))<br>
return BadMatch;<br>
- *msc = ms_kernel_msc_to_crtc_msc(crtc, kernel_msc);<br>
+ *msc = ms_kernel_msc_to_crtc_msc(crtc, kernel_msc, ms->has_queue_sequence);<br>
<br>
return Success;<br>
}<br>
@@ -416,7 +447,7 @@ ms_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data),<br>
* drm event queue and calls the handler for it.<br>
*/<br>
static void<br>
-ms_drm_sequence_handler(int fd, uint64_t frame, uint64_t ns, uint64_t user_data)<br>
+ms_drm_sequence_handler(int fd, uint64_t frame, uint64_t ns, Bool is64bit, uint64_t user_data)<br>
{<br>
struct ms_drm_queue *q, *tmp;<br>
uint32_t seq = (uint32_t) user_data;<br>
@@ -425,7 +456,7 @@ ms_drm_sequence_handler(int fd, uint64_t frame, uint64_t ns, uint64_t user_data)<br>
if (q->seq == seq) {<br>
uint64_t msc;<br>
<br>
- msc = ms_kernel_msc_to_crtc_msc(q->crtc, frame);<br>
+ msc = ms_kernel_msc_to_crtc_msc(q->crtc, frame, is64bit);<br>
xorg_list_del(&q->list);<br>
q->handler(msc, ns / 1000, q->data);<br>
free(q);<br>
@@ -435,10 +466,19 @@ ms_drm_sequence_handler(int fd, uint64_t frame, uint64_t ns, uint64_t user_data)<br>
}<br>
<br>
static void<br>
+ms_drm_sequence_handler_64bit(int fd, uint64_t frame, uint64_t ns, uint64_t user_data)<br>
+{<br>
+ /* frame is true 64 bit wrapped into 64 bit */<br>
+ ms_drm_sequence_handler(fd, frame, ns, TRUE, user_data);<br>
+}<br>
+<br>
+static void<br>
ms_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec,<br>
void *user_ptr)<br>
{<br>
- ms_drm_sequence_handler(fd, frame, ((uint64_t) sec * 1000000 + usec) * 1000, (uint32_t) (uintptr_t) user_ptr);<br>
+ /* frame is 32 bit wrapped into 64 bit */<br>
+ ms_drm_sequence_handler(fd, frame, ((uint64_t) sec * 1000000 + usec) * 1000,<br>
+ FALSE, (uint32_t) (uintptr_t) user_ptr);<br>
}<br>
<br>
Bool<br>
@@ -452,7 +492,7 @@ ms_vblank_screen_init(ScreenPtr screen)<br>
ms->event_context.version = 4;<br>
ms->event_context.vblank_handler = ms_drm_handler;<br>
ms->event_context.page_flip_handler = ms_drm_handler;<br>
- ms->event_context.sequence_handler = ms_drm_sequence_handler;<br>
+ ms->event_context.sequence_handler = ms_drm_sequence_handler_64bit;<br>
<br>
/* We need to re-register the DRM fd for the synchronisation<br>
* feedback on every server generation, so perform the<br>
-- <br>
2.7.4<br>
<br>
_______________________________________________<br>
<a href="mailto:xorg-devel@lists.x.org" target="_blank">xorg-devel@lists.x.org</a>: X.Org development<br>
Archives: <a href="http://lists.x.org/archives/xorg-devel" rel="noreferrer" target="_blank">http://lists.x.org/archives/xorg-devel</a><br>
Info: <a href="https://lists.x.org/mailman/listinfo/xorg-devel" rel="noreferrer" target="_blank">https://lists.x.org/mailman/listinfo/xorg-devel</a></blockquote></div>