[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

xserver-xorg-video-nouveau: Changes to 'upstream-unstable'



 man/nouveau.man            |   15 +
 src/drmmode_display.c      |  107 ++++++++++++-
 src/hwdefs/nv_object.xml.h |  248 +++++++++++++++---------------
 src/nouveau_dri2.c         |  274 +++++++++++++++++++++++++++++++--
 src/nouveau_exa.c          |  334 +++++++++++------------------------------
 src/nouveau_local.h        |   96 +++++++++++
 src/nouveau_xv.c           |  121 +++++----------
 src/nv04_exa.c             |  116 +++++++++-----
 src/nv04_xv_blit.c         |   22 +-
 src/nv10_exa.c             |  183 ++++++++++------------
 src/nv30_exa.c             |  126 +++++++--------
 src/nv30_shaders.c         |   25 +--
 src/nv30_xv_tex.c          |   35 +---
 src/nv40_exa.c             |  110 ++++++-------
 src/nv40_xv_tex.c          |   25 +--
 src/nv50_accel.c           |  124 +++++++--------
 src/nv50_accel.h           |   12 -
 src/nv50_exa.c             |  182 ++++++++++++++++------
 src/nv50_xv.c              |   51 ++----
 src/nv_accel_common.c      |  176 ++++++++++-----------
 src/nv_const.h             |    2 
 src/nv_driver.c            |   43 +++++
 src/nv_include.h           |    3 
 src/nv_proto.h             |   20 ++
 src/nv_type.h              |    4 
 src/nvc0_accel.c           |  196 ++++++++++++------------
 src/nvc0_accel.h           |   17 --
 src/nvc0_exa.c             |  363 +++++++++++++++++----------------------------
 src/nvc0_xv.c              |  104 ++----------
 29 files changed, 1706 insertions(+), 1428 deletions(-)

New commits:
commit ab7291d368ddc66ad21c5ad5caa0faeee42ccaf1
Author: Ben Skeggs <bskeggs@redhat.com>
Date:   Wed Mar 21 14:56:55 2012 +1000

    xv: don't try to init textured video without 3d engine object
    
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/nouveau_xv.c b/src/nouveau_xv.c
index ad203a0..54ae3be 100644
--- a/src/nouveau_xv.c
+++ b/src/nouveau_xv.c
@@ -2022,6 +2022,28 @@ NV50SetupTexturedVideo (ScreenPtr pScreen)
 	return adapt;
 }
 
+void
+NVSetupTexturedVideo (ScreenPtr pScreen, XF86VideoAdaptorPtr *textureAdaptor)
+{
+	ScrnInfoPtr          pScrn = xf86Screens[pScreen->myNum];
+	NVPtr                pNv = NVPTR(pScrn);
+
+	if (!pNv->Nv3D)
+		return;
+
+	if (pNv->Architecture == NV_ARCH_30) {
+		textureAdaptor[0] = NV30SetupTexturedVideo(pScreen, FALSE);
+		textureAdaptor[1] = NV30SetupTexturedVideo(pScreen, TRUE);
+	} else
+	if (pNv->Architecture == NV_ARCH_40) {
+		textureAdaptor[0] = NV40SetupTexturedVideo(pScreen, FALSE);
+		textureAdaptor[1] = NV40SetupTexturedVideo(pScreen, TRUE);
+	} else
+	if (pNv->Architecture >= NV_ARCH_50) {
+		textureAdaptor[0] = NV50SetupTexturedVideo(pScreen);
+	}
+}
+
 /**
  * NVInitVideo
  * tries to initialize the various supported adapters
@@ -2056,17 +2078,7 @@ NVInitVideo(ScreenPtr pScreen)
 			blitAdaptor    = NVSetupBlitVideo(pScreen);
 		}
 
-		if (pNv->Architecture == NV_ARCH_30) {
-			textureAdaptor[0] = NV30SetupTexturedVideo(pScreen, FALSE);
-			textureAdaptor[1] = NV30SetupTexturedVideo(pScreen, TRUE);
-		} else
-		if (pNv->Architecture == NV_ARCH_40) {
-			textureAdaptor[0] = NV40SetupTexturedVideo(pScreen, FALSE);
-			textureAdaptor[1] = NV40SetupTexturedVideo(pScreen, TRUE);
-		} else
-		if (pNv->Architecture >= NV_ARCH_50) {
-			textureAdaptor[0] = NV50SetupTexturedVideo(pScreen);
-		}
+		NVSetupTexturedVideo(pScreen, textureAdaptor);
 	}
 
 	num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);

commit fe7e0425a4a43b2a7d4743a0a90a86724c3b6775
Author: Ben Skeggs <bskeggs@redhat.com>
Date:   Mon Mar 12 11:59:29 2012 +1000

    recognise kepler
    
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/nv_driver.c b/src/nv_driver.c
index 667a0a7..56865e2 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -265,6 +265,7 @@ NVPciProbe(DriverPtr drv, int entity_num, struct pci_device *pci_dev,
 	case 0xa0:
 	case 0xc0:
 	case 0xd0:
+	case 0xe0:
 		break;
 	default:
 		xf86DrvMsg(-1, X_ERROR, "Unknown chipset: NV%02x\n", chipset);
@@ -694,6 +695,9 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
 	case 0xd0:
 		pNv->Architecture = NV_ARCH_C0;
 		break;
+	case 0xe0:
+		pNv->Architecture = NV_ARCH_E0;
+		break;
 	default:
 		return FALSE;
 	}
diff --git a/src/nv_type.h b/src/nv_type.h
index 73328fc..c8f27ac 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -25,6 +25,7 @@
 #define NV_ARCH_40  0x40
 #define NV_ARCH_50  0x50
 #define NV_ARCH_C0  0xc0
+#define NV_ARCH_E0  0xe0
 
 /* NV50 */
 typedef struct _NVRec *NVPtr;

commit f5d1cd2cb6808838ae1a188cef888eaa9582c76d
Author: Ben Skeggs <bskeggs@redhat.com>
Date:   Tue Mar 6 08:16:51 2012 +1000

    remove use of xf86PciInfo.h, deprecated now apparently
    
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/nv_driver.c b/src/nv_driver.c
index 7512464..667a0a7 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -65,8 +65,8 @@ static Bool	NVUnmapMem(ScrnInfoPtr pScrn);
 	  0x00030000, 0x00ffffff, 0 }
 
 static const struct pci_id_match nouveau_device_match[] = {
-	NOUVEAU_PCI_DEVICE(PCI_VENDOR_NVIDIA, PCI_MATCH_ANY),
-	NOUVEAU_PCI_DEVICE(PCI_VENDOR_NVIDIA_SGS, PCI_MATCH_ANY),
+	NOUVEAU_PCI_DEVICE(0x12d2, PCI_MATCH_ANY),
+	NOUVEAU_PCI_DEVICE(0x10de, PCI_MATCH_ANY),
 	{ 0, 0, 0 },
 };
 
diff --git a/src/nv_include.h b/src/nv_include.h
index 496eefe..407b7c9 100644
--- a/src/nv_include.h
+++ b/src/nv_include.h
@@ -17,9 +17,6 @@
 #define PPC_MMIO_IS_BE
 #include "compiler.h"
 
-/* Drivers for PCI hardware need this */
-#include "xf86PciInfo.h"
-
 /* Drivers that need to access the PCI config space directly need this */
 #include "xf86Pci.h"
 

commit 248de8cdbd6d0bc062633b49896fa4791148cd3b
Author: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Date:   Thu Feb 16 00:45:24 2012 +0100

    dri2: Fix corner case crash for swaplimit > 1
    
    If a swaplimit > 1 is set on a server which
    supports the swaplimit api (XOrg 1.12.0+),
    the following can happen:
    
    1. Client calls glXSwapBuffersMscOML() with a
       swap target > 1 vblank in the future, or a
       client calls glXSwapbuffers() while the swap
       interval is set to > 1 (unusual but possible).
    
    2. nouveau_dri2_finish_swap() is therefore called
       only at the target vblank, instead of immediately.
    
    3. Because of the deferred execution of
       nouveu_dri2_finish_swap(), the OpenGL client
       can call x-servers DRI2GetBuffersWithFormat()
       before nouveau_dri2_finish_swap() executes and
       it deletes pixmaps that would be needed by
       nouveau_dri2_finish_swap() --> Segfault --> Crash.
    
    Prevent this: When a swap is scheduled into the
    future, we temporarily reduce the swaplimit to 1
    until nouveau_dri2_finish_swap() is done, then
    restore it to its original value. This throttles
    the client inside the server in DRI2ThrottleClient()
    before it can call the evil DRI2GetbuffersWithFormat().
    
    The client will still be released one video refresh
    interval before swap completion, so there is still
    some potential win.
    
    This doesn't affect the common case of swapping at
    the next vblank, where this throttling is not needed
    or done.
    
    Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index f0c7fec..7878a5a 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -445,6 +445,26 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 		if (*target_msc == 0)
 			*target_msc = 1;
 
+#if DRI2INFOREC_VERSION >= 6
+		/* Is this a swap in the future, ie. the vblank event will
+		 * not be immediately dispatched, but only at a future vblank?
+		 * If so, we need to temporarily lower the swaplimit to 1, so
+		 * that DRI2GetBuffersWithFormat() requests from the client get
+		 * deferred in the x-server until the vblank event has been
+		 * dispatched to us and nouveau_dri2_finish_swap() is done. If
+		 * we wouldn't do this, DRI2GetBuffersWithFormat() would operate
+		 * on wrong (pre-swap) buffers, and cause a segfault later on in
+		 * nouveau_dri2_finish_swap(). Our vblank event handler restores
+		 * the old swaplimit immediately after nouveau_dri2_finish_swap()
+		 * is done, so we still get 1 video refresh cycle worth of
+		 * triple-buffering. For a swap at next vblank, dispatch of the
+		 * vblank event happens immediately, so there isn't any need
+		 * for this lowered swaplimit.
+		 */
+		if (current_msc < *target_msc - 1)
+			DRI2SwapLimit(draw, 1);
+#endif
+
 		/* Request a vblank event one frame before the target */
 		ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE |
 					  DRM_VBLANK_EVENT,
@@ -557,6 +577,12 @@ nouveau_dri2_vblank_handler(int fd, unsigned int frame,
 	switch (s->action) {
 	case SWAP:
 		nouveau_dri2_finish_swap(draw, frame, tv_sec, tv_usec, s);
+#if DRI2INFOREC_VERSION >= 6
+		/* Restore real swap limit on drawable, now that it is safe. */
+		ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
+		DRI2SwapLimit(draw, NVPTR(scrn)->swap_limit);
+#endif
+
 		break;
 
 	case WAIT:

commit 247465ec5e21ce7151ef1e6a3e7644bc74d48a5b
Author: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Date:   Thu Feb 16 00:45:23 2012 +0100

    dri2: Reimplement hack for triple-buffering on old X-Servers.
    
    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.kleiner@tuebingen.mpg.de>
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

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

commit a1902ffaab1f6807fdaac0fce49f784e7208d1a5
Author: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Date:   Thu Feb 16 00:45:22 2012 +0100

    dri2: Allow vblank controlled swaps for redirected windows. Part II
    
    This part implements proper throttling for clients. For
    vblank synchronized blits, it defers DRI2SwapComplete()
    until 1 vblank after the framebuffer blit is submitted to
    the gpu.
    
    Rationale:
    
    For unredirected windows, this is the earliest time the
    "blit swap" can complete, as blits are submitted one vblank
    before the target vblank and synchronized with vblank in the
    gpu. This makes swap completion timestamps at least reasonable.
    
    For redirected windows, the compositor will probably pick
    up the "blit swapped" frontbuffer pixmap of the window quickly,
    but defer its own recomposition to the next vblank, at least
    if sync to vblank for the compositor is on.
    
    Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 6a0800c..fdc5148 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -135,6 +135,7 @@ nouveau_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
 struct nouveau_dri2_vblank_state {
 	enum {
 		SWAP,
+		BLIT,
 		WAIT
 	} action;
 
@@ -342,6 +343,22 @@ 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)) {
+			/* 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
+			 * screen. This defers DRI2SwapComplete() to the earliest
+			 * likely time of real swap completion.
+			 */
+			s->action = BLIT;
+			ret = nouveau_wait_vblank(draw, DRM_VBLANK_EVENT |
+						  DRM_VBLANK_RELATIVE, 1,
+						  NULL, NULL, s);
+			/* Done, if success. Otherwise use fallback below. */
+			if (!ret)
+				return;
+		}
 	}
 
 	/*
@@ -351,8 +368,9 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
 	 *
 	 * 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.
+	 *       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.
 	 */
 	DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec,
 			 type, s->func, s->data);
@@ -505,8 +523,10 @@ nouveau_dri2_vblank_handler(int fd, unsigned int frame,
 
 	ret = dixLookupDrawable(&draw, s->draw, serverClient,
 				M_ANY, DixWriteAccess);
-	if (ret)
+	if (ret) {
+		free(s);
 		return;
+	}
 
 	switch (s->action) {
 	case SWAP:
@@ -517,6 +537,12 @@ nouveau_dri2_vblank_handler(int fd, unsigned int frame,
 		DRI2WaitMSCComplete(s->client, draw, frame, tv_sec, tv_usec);
 		free(s);
 		break;
+
+	case BLIT:
+		DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec,
+				 DRI2_BLIT_COMPLETE, s->func, s->data);
+		free(s);
+		break;
 	}
 }
 

commit c8572d329014afc0c79b5765468dcdfb65be0868
Author: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Date:   Thu Feb 16 00:45:21 2012 +0100

    dri2: Allow vblank controlled swaps for redirected windows. Part I
    
    Make sure that swaps for redirected windows under a
    compositor are still scheduled via vblank events, to
    avoid effects like 2900 fps swaps under a compositor.
    
    See discussion with Francisco Jerez at:
    
    http://lists.freedesktop.org/archives/nouveau/2011-September/009278.html
    http://lists.freedesktop.org/archives/nouveau/2011-September/009292.html
    
    This is part I of the agreed upon band-aid, in a separate patch.
    
    It allows to use vblank related functions on redirected
    windows and thereby fixes functions from sgi_sync_control
    and oml_sync_control extension, e.g., glXWaitForMscOML(),
    glXGetSyncValuesOML(), glXWaitVideoSyncSGI, ...
    
    Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 719b3bb..6a0800c 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -204,10 +204,8 @@ can_sync_to_vblank(DrawablePtr draw)
 {
 	ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
 	NVPtr pNv = NVPTR(scrn);
-	PixmapPtr pix = NVGetDrawablePixmap(draw);
 
 	return pNv->glx_vblank &&
-		nouveau_exa_pixmap_is_onscreen(pix) &&
 		nv_window_belongs_to_crtc(scrn, draw->x, draw->y,
 					  draw->width, draw->height);
 }

commit 919643888045b102f3e10dfdeb6210ab14b6ecab
Author: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Date:   Thu Feb 16 00:45:20 2012 +0100

    dri2: Fixes to swap scheduling.
    
    Fix some small off-by-one errors and a mismatch
    between 32 bit kernel interfaces for vblank count
    and 64 bit dri2 interfaces for target_msc et al.
    
    Return corrected target_msc to swap scheduling in
    x-server.
    
    A revised version of the patch discussed here:
    http://lists.freedesktop.org/archives/nouveau/2011-September/009143.html
    
    Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 8608678..719b3bb 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -387,11 +387,22 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 		if (ret)
 			goto fail;
 
+		/* Truncate to match kernel interfaces; means occasional overflow
+		 * misses, but that's generally not a big deal.
+		 */
+		*target_msc &= 0xffffffff;
+		divisor &= 0xffffffff;
+		remainder &= 0xffffffff;
+
 		/* Calculate a swap target if we don't have one */
 		if (current_msc >= *target_msc && divisor)
 			*target_msc = current_msc + divisor
 				- (current_msc - remainder) % divisor;
 
+		/* Avoid underflow of unsigned value below */
+		if (*target_msc == 0)
+			*target_msc = 1;
+
 		/* Request a vblank event one frame before the target */
 		ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE |
 					  DRM_VBLANK_EVENT,
@@ -399,7 +410,8 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 					  &expect_msc, NULL, s);
 		if (ret)
 			goto fail;
-		s->frame = (unsigned int) expect_msc & 0xffffffff;
+		s->frame = 1 + ((unsigned int) expect_msc & 0xffffffff);
+		*target_msc = 1 + expect_msc;
 	} else {
 		/* We can't/don't want to sync to vblank, just swap. */
 		nouveau_dri2_finish_swap(draw, 0, 0, 0, s);
@@ -420,6 +432,13 @@ nouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr draw,
 	CARD64 current_msc;
 	int ret;
 
+	/* Truncate to match kernel interfaces; means occasional overflow
+	 * misses, but that's generally not a big deal.
+	 */
+	target_msc &= 0xffffffff;
+	divisor &= 0xffffffff;
+	remainder &= 0xffffffff;
+
 	if (!can_sync_to_vblank(draw)) {
 		DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
 		return TRUE;
@@ -439,7 +458,7 @@ nouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr draw,
 		goto fail;
 
 	/* Calculate a wait target if we don't have one */
-	if (current_msc > target_msc && divisor)
+	if (current_msc >= target_msc && divisor)
 		target_msc = current_msc + divisor
 			- (current_msc - remainder) % divisor;
 

commit 5ede4538366a352aa9726560f8d42e85df4aec82
Author: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Date:   Thu Feb 16 00:45:19 2012 +0100

    dri2: Update front buffer pixmap and name before exchanging buffers
    
    Buffer exchange assumes that the front buffer pixmap and name
    information is accurate. That may not be the case eg. if the window
    has been (un)redirected since the buffer was created.
    
    This is a translation to nouveau of a fix that was originally developed
    by Ville Syrjala <syrjala@sci.fi> for the ati/radeon ddx to fix the
    same bug there.
    
    See thread at:
    
    http://lists.x.org/archives/xorg-devel/2011-May/021908.html
    
    Fixes FDO bug #35452.
    
    Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 2908e56..8608678 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -149,6 +149,35 @@ struct nouveau_dri2_vblank_state {
 };
 
 static Bool
+update_front(DrawablePtr draw, DRI2BufferPtr front)
+{
+	int r;
+	PixmapPtr pixmap;
+	struct nouveau_dri2_buffer *nvbuf = nouveau_dri2_buffer(front);
+
+	if (draw->type == DRAWABLE_PIXMAP)
+		pixmap = (PixmapPtr)draw;
+	else
+		pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw);
+
+	pixmap->refcnt++;
+
+	exaMoveInPixmap(pixmap);
+	r = nouveau_bo_handle_get(nouveau_pixmap_bo(pixmap), &front->name);
+	if (r) {
+		(*draw->pScreen->DestroyPixmap)(pixmap);
+		return FALSE;
+	}
+
+	(*draw->pScreen->DestroyPixmap)(nvbuf->ppix);
+	front->pitch = pixmap->devKind;
+	front->cpp = pixmap->drawable.bitsPerPixel / 8;
+	nvbuf->ppix = pixmap;
+
+	return TRUE;
+}
+
+static Bool
 can_exchange(DrawablePtr draw, PixmapPtr dst_pix, PixmapPtr src_pix)
 {
 	ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
@@ -234,13 +263,14 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
 {
 	ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
 	NVPtr pNv = NVPTR(scrn);
-	PixmapPtr dst_pix = nouveau_dri2_buffer(s->dst)->ppix;
+	PixmapPtr dst_pix;
 	PixmapPtr src_pix = nouveau_dri2_buffer(s->src)->ppix;
-	struct nouveau_bo *dst_bo = nouveau_pixmap_bo(dst_pix);
+	struct nouveau_bo *dst_bo;
 	struct nouveau_bo *src_bo = nouveau_pixmap_bo(src_pix);
 	struct nouveau_channel *chan = pNv->chan;
 	RegionRec reg;
 	int type, ret;
+	Bool front_updated;
 
 	REGION_INIT(0, &reg, (&(BoxRec){ 0, 0, draw->width, draw->height }), 0);
 	REGION_TRANSLATE(0, &reg, draw->x, draw->y);
@@ -257,6 +287,15 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
 	if (ref_crtc_hw_id & 1)
 		ref_crtc_hw_id = 1;
 
+	/* Update frontbuffer pixmap and name: Could have changed due to
+	 * window (un)redirection as part of compositing.
+	 */
+	front_updated = update_front(draw, s->dst);
+
+	/* Assign frontbuffer pixmap, after update in update_front() */
+	dst_pix = nouveau_dri2_buffer(s->dst)->ppix;
+	dst_bo = nouveau_pixmap_bo(dst_pix);
+
 	/* Throttle on the previous frame before swapping */
 	nouveau_bo_map(dst_bo, NOUVEAU_BO_RD);
 	nouveau_bo_unmap(dst_bo);
@@ -275,7 +314,7 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
 		FIRE_RING(chan);
 	}
 
-	if (can_exchange(draw, dst_pix, src_pix)) {
+	if (front_updated && can_exchange(draw, dst_pix, src_pix)) {
 		type = DRI2_EXCHANGE_COMPLETE;
 		DamageRegionAppend(draw, &reg);
 

commit 6fdf60b7288d49f889c80705aabc1db3bc327ba3
Author: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Date:   Thu Feb 16 00:45:18 2012 +0100

    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>

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;

commit 820916e722db2997a53128f2f370d14a02d4401c
Author: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Date:   Thu Feb 16 00:45:17 2012 +0100

    dri2: Implement handling of pageflip completion events.
    
    Requests pageflip completion events from the kernel.
    Implements pageflip completion handler to finalize
    and timestamp swaps.
    
    Completion handler includes a consistency check, and
    disambiguation if multiple crtc's are involved in a
    pageflip (e.g., clone mode, extendend desktop). Only
    the timestamp of the crtc whose vblank event initially
    triggered the swap is used, but handler waits for flip
    completion on all involved crtc's before completing the
    swap and releasing the old framebuffer.
    
    This code is almost identical to the code used in the
    ati/radeon ddx and intel ddx.
    
    Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
    Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 75ef6dd..9e15c29 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -83,6 +83,21 @@ typedef struct {
     drmmode_prop_ptr props;
 } drmmode_output_private_rec, *drmmode_output_private_ptr;
 
+typedef struct {
+    drmmode_ptr drmmode;
+    unsigned old_fb_id;
+    int flip_count;
+    void *event_data;
+    unsigned int fe_frame;
+    unsigned int fe_tv_sec;
+    unsigned int fe_tv_usec;
+} drmmode_flipdata_rec, *drmmode_flipdata_ptr;
+
+typedef struct {
+    drmmode_flipdata_ptr flipdata;
+    Bool dispatch_me;
+} drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr;
+
 static void drmmode_output_dpms(xf86OutputPtr output, int mode);
 
 static drmmode_ptr
@@ -1245,13 +1260,17 @@ drmmode_cursor_init(ScreenPtr pScreen)
 }
 
 Bool
-drmmode_page_flip(DrawablePtr draw, PixmapPtr back, void *priv)
+drmmode_page_flip(DrawablePtr draw, PixmapPtr back, void *priv,
+		  unsigned int ref_crtc_hw_id)
 {
 	ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
 	drmmode_ptr mode = crtc->drmmode;
 	int ret, i, old_fb_id;
+	int emitted = 0;
+	drmmode_flipdata_ptr flipdata;
+	drmmode_flipevtcarrier_ptr flipcarrier;
 
 	old_fb_id = mode->fb_id;
 	ret = drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
@@ -1264,24 +1283,64 @@ drmmode_page_flip(DrawablePtr draw, PixmapPtr back, void *priv)
 		return FALSE;
 	}
 
+	flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
+	if (!flipdata) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		"flip queue: data alloc failed.\n");
+		goto error_undo;
+	}
+


Reply to: