From 008d213cb4b4ee0d400fe776ba2764b2b8dd277e Mon Sep 17 00:00:00 2001
From: Mario Kleiner <mario.kleiner.de@gmail.com>
Date: Thu, 1 Dec 2016 07:42:03 +0100
Subject: [PATCH xserver 2/2] modesetting: Add custom low-lag optimizations for
 Psychtoolbox.

We want to get rid of the 1 frame extra-lag induced by NVidia's
design, so Psychtoolbox can wait for true flip completion UDP
packets, instead of the "flip scheduled" UDP packets, and thereby
provide more robust Flip completion timestamping, without the 1
frame penalty that would cut maximu achievable display update
rate (fps) down to half the video refresh rate.

For this we use the following trick:

We modify the msSharedPixmapNotifyDamage() callback, which is
called by the NVidia proprietary driver as soon as a OpenGL
bufferswap has been triggered and the new rendered frame copied
to the NVidia drivers GPU internal linear staging framebuffer.
The callback no longer calls drmmode_SharedPixmapPresentOnVBlank()
as in the original design to schedule a PresentSharedPixmap and
kms-pageflip at the next vblank, inducing the 1 frame delay, as
the pageflip can then only execute 1 vblank after that vblank.
Instead we call drmmode_SharedPixmapPresent() immediately without
waiting for next vblank.

This removes the extra lag. However, the trick only works
on a single display setup, ie. with exactly 1 active crtc
on the X-Screen. On multi-display it causes stability issues,
freezes, hangs etc. Therefore we only enable this optimization
if the X-Screen has exactly one active crtc. Otherwise we fall
back to the old extra-lag code which is stable. This is not a
real loss to PTB, as the whole hack only works with reasonably
reliable timing on a single-display per X-Screen configuration.
We can't deal with the timestamping of multi-display kms-flip
completion in any sane way.

Availability of this extra low-lag mode is signalled to PTB
by exposure of a new X-Atom "PrimeTimingHack2", so PTB can
adapt its swap scheduling and feedback to the user accordingly.

This patch tested against the NVidia 375.20 release driver with
X-Server 1.19.0 final on a Lenovo Z50 Optimus laptop with
Intel HD 4400 + GeForce 840M. Datapixx confirms correct
timestamping.

Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
---
 hw/xfree86/drivers/modesetting/driver.c          | 17 +++++++++++++++--
 hw/xfree86/drivers/modesetting/drmmode_display.c |  9 +++++++--
 hw/xfree86/drivers/modesetting/drmmode_display.h |  1 +
 3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index 3da69a3..542fa47 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -1462,6 +1462,7 @@ msSharedPixmapNotifyDamage(PixmapPtr ppix)
 {
     Bool ret = FALSE;
     int c;
+    int num_enabled = 0;
 
     ScreenPtr screen = ppix->drawable.pScreen;
     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
@@ -1476,6 +1477,11 @@ msSharedPixmapNotifyDamage(PixmapPtr ppix)
 
     for (c = 0; c < xf86_config->num_crtc; c++) {
         xf86CrtcPtr crtc = xf86_config->crtc[c];
+        num_enabled += crtc->enabled ? 1 : 0;
+    }
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr crtc = xf86_config->crtc[c];
         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
         if (!drmmode_crtc)
@@ -1483,8 +1489,15 @@ msSharedPixmapNotifyDamage(PixmapPtr ppix)
         if (!(drmmode_crtc->prime_pixmap && drmmode_crtc->prime_pixmap_back))
             continue;
 
-        // Received damage on master screen pixmap, schedule present on vblank
-        ret |= drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, &ms->drmmode);
+        /* Immediate present only works reliably for single active crtc. */
+        if (num_enabled > 1) {
+            // Received damage on master screen pixmap, schedule present at next vblank:
+            ret |= drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, &ms->drmmode);
+        }
+        else {
+            // Received damage on master screen pixmap, schedule present asap:
+            ret |= drmmode_SharedPixmapPresent(ppix, crtc, &ms->drmmode);
+        }
     }
 
     return ret;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index d0cf665..f2c4f4f 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -216,6 +216,7 @@ static void
 drmmode_InitSharedPixmapFeedback(drmmode_ptr drmmode)
 {
     static Atom PrimeTimingHack1 = None;
+    static Atom PrimeTimingHack2 = None;
     int scrnIndex = drmmode->scrn->scrnIndex % 256;
     struct sockaddr_in addr = { 0 };
 
@@ -244,7 +245,7 @@ drmmode_InitSharedPixmapFeedback(drmmode_ptr drmmode)
             fcntl(fd_primestatus[scrnIndex], F_SETFL, O_NONBLOCK);
 
             xf86DrvMsg(drmmode->scrn->scrnIndex, X_INFO,
-                        "Bound Unix UDP socket for Prime feedback on localhost:%i\n", 10000 + scrnIndex);
+                        "NoLag: Bound Unix UDP socket for Prime feedback on localhost:%i\n", 10000 + scrnIndex);
         }
     }
 
@@ -253,6 +254,10 @@ drmmode_InitSharedPixmapFeedback(drmmode_ptr drmmode)
      */
     if (PrimeTimingHack1 == None)
         PrimeTimingHack1 = MakeAtom("PrimeTimingHack1", strlen("PrimeTimingHack1"), TRUE);
+
+    /* Additionally signal via Atom that this is a driver with low/no lag modifications: */
+    if (PrimeTimingHack2 == None)
+        PrimeTimingHack2 = MakeAtom("PrimeTimingHack2", strlen("PrimeTimingHack2"), TRUE);
 }
 
 static void
@@ -293,7 +298,7 @@ drmmode_SendSharedPixmapFeedback(Bool flipcomplete)
                    "Send for Prime feedback: flipcompletion=%d : msc=%lu : ust=%lu\n", buf.flags, buf.frame, buf.usec);
 }
 
-static Bool
+Bool
 drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc,
                             drmmode_ptr drmmode)
 {
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 50976b8..26f1578 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -178,6 +178,7 @@ Bool drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
                                         PixmapPtr front, PixmapPtr back);
 Bool drmmode_SharedPixmapPresentOnVBlank(PixmapPtr frontTarget, xf86CrtcPtr crtc,
                                          drmmode_ptr drmmode);
+Bool drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc, drmmode_ptr drmmode);
 Bool drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
                               drmmode_ptr drmmode);
 void drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode);
-- 
2.7.4

