Uses the new DRI2SwapLimit() API of X-Server 1.12+
to allow to change the maximum number of pending
swaps on a drawable before the OpenGL client is
throttled by the server.

The new optional xorg.conf parameter "SwapLimit"
allows to select a new swap limit >= 1. The default
swap limit is 2 for triple-buffering on XOrg 1.12+,
1 for double-buffering on older servers, as we can't
change the swap limit there.

Signed-off-by: Mario Kleiner <mario.klei...@tuebingen.mpg.de>
---
 man/nouveau.man    |   11 +++++++++++
 src/nouveau_dri2.c |   29 +++++++++++++++++++++++++++--
 src/nv_const.h     |    2 ++
 src/nv_driver.c    |   34 ++++++++++++++++++++++++++++++++++
 src/nv_type.h      |    3 +++
 5 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/man/nouveau.man b/man/nouveau.man
index dd9d938..59f6c1a 100644
--- a/man/nouveau.man
+++ b/man/nouveau.man
@@ -93,6 +93,17 @@ will assign xrandr outputs LVDS and VGA-0 to this instance 
of the driver.
 .TP
 .BI "Option \*qPageFlip\*q \*q" boolean \*q
 Enable DRI2 page flipping. Default: on.
+.TP
+.BI "Option \*qSwapLimit\*q \*q" integer \*q
+Set maximum allowed number of pending OpenGL double-buffer swaps for
+a drawable before a client is blocked.
+.br
+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.
+.br
+Default: 2 for XOrg 1.12+, 1 for older servers.
 .SH "SEE ALSO"
 __xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), 
Xserver(__appmansuffix__), X(__miscmansuffix__)
 .SH AUTHORS
diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index acef08a..2908e56 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -42,6 +42,11 @@ nouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int 
attachment,
                } else {
                        WindowPtr pwin = (WindowPtr)pDraw;
                        ppix = pScreen->GetWindowPixmap(pwin);
+
+#if DRI2INFOREC_VERSION >= 6
+                       /* Set initial swap limit on drawable. */
+                       DRI2SwapLimit(pDraw, pNv->swap_limit);
+#endif
                }
 
                ppix->refcnt++;
@@ -208,6 +213,20 @@ nouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc,
        return 0;
 }
 
+#if DRI2INFOREC_VERSION >= 6
+static Bool
+nouveau_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit)
+{
+       ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
+       NVPtr pNv = NVPTR(scrn);
+
+       if ((swap_limit < 1 ) || (swap_limit > pNv->max_swap_limit))
+               return FALSE;
+
+       return TRUE;
+}
+#endif
+
 static void
 nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
                         unsigned int tv_sec, unsigned int tv_usec,
@@ -293,8 +312,10 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int 
frame,
         * not, to prevent it from blocking the client on the next
         * GetBuffers request (and let the client do triple-buffering).
         *
-        * XXX - The DRI2SwapLimit() API will allow us to move this to
-        *       the flip handler with no FPS hit.
+        * XXX - The DRI2SwapLimit() API allowed us to move this to
+        *       the flip handler with no FPS hit for page flipped swaps.
+        *       It is still needed for copy swaps as we lack a method
+        *       to detect true swap completion for DRI2_BLIT_COMPLETE.
         */
        DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec,
                         type, s->func, s->data);
@@ -534,6 +555,10 @@ nouveau_dri2_init(ScreenPtr pScreen)
        dri2.ScheduleWaitMSC = nouveau_dri2_schedule_wait;
        dri2.GetMSC = nouveau_dri2_get_msc;
 
+#if DRI2INFOREC_VERSION >= 6
+       dri2.SwapLimitValidate = nouveau_dri2_swap_limit_validate;
+#endif
+
        return DRI2ScreenInit(pScreen, &dri2);
 }
 
diff --git a/src/nv_const.h b/src/nv_const.h
index a27a951..5c232d4 100644
--- a/src/nv_const.h
+++ b/src/nv_const.h
@@ -15,6 +15,7 @@ typedef enum {
     OPTION_GLX_VBLANK,
     OPTION_ZAPHOD_HEADS,
     OPTION_PAGE_FLIP,
+    OPTION_SWAP_LIMIT,
 } NVOpts;
 
 
@@ -28,6 +29,7 @@ static const OptionInfoRec NVOptions[] = {
     { OPTION_GLX_VBLANK,       "GLXVBlank",    OPTV_BOOLEAN,   {0}, FALSE },
     { OPTION_ZAPHOD_HEADS,     "ZaphodHeads",  OPTV_STRING,    {0}, FALSE },
     { OPTION_PAGE_FLIP,                "PageFlip",     OPTV_BOOLEAN,   {0}, 
FALSE },
+    { OPTION_SWAP_LIMIT,       "SwapLimit",    OPTV_INTEGER,   {0}, FALSE },
     { -1,                       NULL,           OPTV_NONE,      {0}, FALSE }
 };
 
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 87ef2c4..5def531 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -31,6 +31,9 @@
 #include "xf86drm.h"
 #include "xf86drmMode.h"
 #include "nouveau_drm.h"
+#ifdef DRI2
+#include "dri2.h"
+#endif
 
 /*
  * Forward definitions for the functions that make up the driver.
@@ -847,6 +850,37 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
                (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << 
pScrn->offset.blue);
        }
 
+       /* Limit to max 2 pending swaps - we can't handle more than 
triple-buffering: */
+       pNv->max_swap_limit = 2;
+
+       if(xf86GetOptValInteger(pNv->Options, OPTION_SWAP_LIMIT, 
&(pNv->swap_limit))) {
+               if (pNv->swap_limit < 1)
+                       pNv->swap_limit = 1;
+
+               if (pNv->swap_limit > pNv->max_swap_limit)
+                       pNv->swap_limit = pNv->max_swap_limit;
+
+               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.";
+               }
+       } else {
+               /* Driver default: Double buffering on old servers, 
triple-buffering
+                * on Xorg 1.12+.
+                */
+               pNv->swap_limit = (DRI2INFOREC_VERSION < 6) ? 1 : 2;
+               reason = "";
+               from = X_DEFAULT;
+       }
+
+       xf86DrvMsg(pScrn->scrnIndex, from, "Swap limit set to %d [Max allowed 
%d]%s\n",
+                  pNv->swap_limit, pNv->max_swap_limit, reason);
+
        ret = drmmode_pre_init(pScrn, nouveau_device(pNv->dev)->fd,
                               pScrn->bitsPerPixel >> 3);
        if (ret == FALSE)
diff --git a/src/nv_type.h b/src/nv_type.h
index 4204556..73328fc 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -53,6 +53,9 @@ typedef struct _NVRec {
     Bool               tiled_scanout;
     Bool               glx_vblank;
     Bool               has_pageflip;
+    int                swap_limit;
+    int                max_swap_limit;
+
     ScreenBlockHandlerProcPtr BlockHandler;
     CreateScreenResourcesProcPtr CreateScreenResources;
     CloseScreenProcPtr  CloseScreen;
-- 
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