X-Servers before 1.12.0 don't have the DRI2SwapLimit()
API. On these, default to a swaplimit of 1 - double-buffering.

This patch implements support for swap limit of 2,
triple-buffering, on old x-servers via Francisco Jerez
previous hack:

Return DRI2SwapComplete() before the swap has completed,
so clients don't get blocked on the pending swap. This
allows for a "triple-buffering look-alike" behaviour, but
breaks the swap scheduling and timestamping defined
in the OML_sync_control spec, so applications which
rely on conformant behaviour will break with a swap
limit of 2 on pre 1.12.0 x-servers.

Signed-off-by: Mario Kleiner <mario.klei...@tuebingen.mpg.de>
---
 man/nouveau.man    |    6 +++++-
 src/nouveau_dri2.c |   32 +++++++++++++++++++++++++++++---
 src/nv_driver.c    |   11 ++++++-----
 3 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/man/nouveau.man b/man/nouveau.man
index 59f6c1a..7c72907 100644
--- a/man/nouveau.man
+++ b/man/nouveau.man
@@ -101,7 +101,11 @@ a drawable before a client is blocked.
 A value of 1 corresponds to double-buffering. A value of 2 corresponds
 to triple-buffering. Higher values may allow higher framerate, but also
 increase lag for interactive applications, e.g., games. Nouveau currently
-supports a maximum value of 2 on XOrg 1.12+ and a maximum of 1 on older 
servers.
+reliably supports a maximum value of 2 on XOrg 1.12+. A maximum setting of 2
+on older x-servers is allowed, but it will break conformance with the
+OpenML OML_sync_control specification and will cause failure of software
+that relies on correct presentation timing behaviour as defined in that
+specification.
 .br
 Default: 2 for XOrg 1.12+, 1 for older servers.
 .SH "SEE ALSO"
diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index fdc5148..f0c7fec 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -255,6 +255,18 @@ nouveau_dri2_swap_limit_validate(DrawablePtr draw, int 
swap_limit)
 }
 #endif
 
+/* Shall we intentionally violate the OML_sync_control spec to
+ * get some sort of triple-buffering behaviour on a pre 1.12.0
+ * x-server?
+ */
+static Bool violate_oml(DrawablePtr draw)
+{
+       ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
+       NVPtr pNv = NVPTR(scrn);
+
+       return (DRI2INFOREC_VERSION < 6) && (pNv->swap_limit > 1);
+}
+
 static void
 nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
                         unsigned int tv_sec, unsigned int tv_usec,
@@ -319,7 +331,9 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int 
frame,
 
                if (DRI2CanFlip(draw)) {
                        type = DRI2_FLIP_COMPLETE;
-                       ret = drmmode_page_flip(draw, src_pix, s, 
ref_crtc_hw_id);
+                       ret = drmmode_page_flip(draw, src_pix,
+                                               violate_oml(draw) ? NULL : s,
+                                               ref_crtc_hw_id);
                        if (!ret)
                                goto out;
                }
@@ -330,7 +344,7 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int 
frame,
                DamageRegionProcessPending(draw);
 
                /* If it is a page flip, finish it in the flip event handler. */
-               if (type == DRI2_FLIP_COMPLETE)
+               if ((type == DRI2_FLIP_COMPLETE) && !violate_oml(draw))
                        return;
        } else {
                type = DRI2_BLIT_COMPLETE;
@@ -344,7 +358,7 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int 
frame,
                REGION_TRANSLATE(0, &reg, -draw->x, -draw->y);
                nouveau_dri2_copy_region(draw, &reg, s->dst, s->src);
 
-               if (can_sync_to_vblank(draw)) {
+               if (can_sync_to_vblank(draw) && !violate_oml(draw)) {
                        /* Request a vblank event one vblank from now, the most
                         * likely (optimistic?) time a direct framebuffer blit
                         * will complete or a desktop compositor will update its
@@ -361,6 +375,14 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int 
frame,
                }
        }
 
+       /* Special triple-buffering hack for old pre 1.12.0 x-servers used? */
+       if (violate_oml(draw)) {
+               /* Signal to client that swap completion timestamps and counts
+                * are invalid - they violate the specification.
+                */
+               frame = tv_sec = tv_usec = 0;
+       }
+
        /*
         * Tell the X server buffers are already swapped even if they're
         * not, to prevent it from blocking the client on the next
@@ -371,6 +393,10 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int 
frame,
         *       It is still needed as a fallback for some copy swaps as
         *       we lack a method to detect true swap completion for
         *       DRI2_BLIT_COMPLETE.
+        *
+        *       It is also used if triple-buffering is requested on
+        *       old x-servers which don't support the DRI2SwapLimit()
+        *       function.
         */
        DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec,
                         type, s->func, s->data);
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 5def531..7512464 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -863,11 +863,12 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
                reason = "";
                from = X_CONFIG;
 
-               if (DRI2INFOREC_VERSION < 6) {
-                       /* No swap limit api in server. Stick to server default 
of 1. */
-                       pNv->swap_limit = 1;
-                       from = X_DEFAULT;
-                       reason = ": This X-Server only supports a swap limit of 
1.";
+               if ((DRI2INFOREC_VERSION < 6) && (pNv->swap_limit > 1)) {
+                       /* No swap limit api in server. A value > 1 requires use
+                        * of problematic hacks.
+                        */
+                       from = X_WARNING;
+                       reason = ": Caution: Use of this swap limit > 1 
violates OML_sync_control spec on this X-Server!\n";
                }
        } else {
                /* Driver default: Double buffering on old servers, 
triple-buffering
-- 
1.7.5.4

_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to