Permalink
Browse files

dri2: Add support for DRI2SwapLimit() API.

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.kleiner@tuebingen.mpg.de>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
  • Loading branch information...
1 parent 820916e commit 6fdf60b7288d49f889c80705aabc1db3bc327ba3 @kleinerm kleinerm committed with Feb 15, 2012
Showing with 77 additions and 2 deletions.
  1. +11 −0 man/nouveau.man
  2. +27 −2 src/nouveau_dri2.c
  3. +2 −0 src/nv_const.h
  4. +34 −0 src/nv_driver.c
  5. +3 −0 src/nv_type.h
View
@@ -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
View
@@ -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);
}
View
@@ -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 }
};
View
@@ -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)
View
@@ -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;

0 comments on commit 6fdf60b

Please sign in to comment.