xf86-video-ati: Branch 'master' - 7 commits

Alex Deucher agd5f at kemper.freedesktop.org
Mon Jan 10 15:18:21 PST 2011


 man/radeon.man        |   17 ++-
 src/drmmode_display.c |  134 +++++++++++++++++++++++-
 src/drmmode_display.h |   12 ++
 src/evergreen_exa.c   |   21 ++-
 src/r600_exa.c        |   21 ++-
 src/radeon.h          |    8 +
 src/radeon_dri2.c     |  278 ++++++++++++++++++++++++++++++++++++++++++--------
 src/radeon_dri2.h     |    2 
 src/radeon_exa.c      |   11 +
 src/radeon_kms.c      |   23 +++-
 10 files changed, 461 insertions(+), 66 deletions(-)

New commits:
commit e5d0a400d08da2358fac9c2ad12042f125525736
Merge: 0e432df... e27e9b4...
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Mon Jan 10 18:16:49 2011 -0500

    Merge branch 'kms-pflip' of git+ssh://git.freedesktop.org/git/xorg/driver/xf86-video-ati

commit e27e9b4e50ad42885ad2e25be897cdf29aa59712
Author: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
Date:   Sun Dec 19 03:56:17 2010 +0100

    ddx/ati: Bugfix for pageflip consistency check.
    
    target_msc wasn't passed from vblank event handler
    to pageflip routine, due to a missing initalization.
    Now fixed.
    
    Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>

diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index 8b12872..e8e16ff 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -595,7 +595,7 @@ static Bool
 radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
 			  DrawablePtr draw, DRI2BufferPtr front,
 			  DRI2BufferPtr back, DRI2SwapEventPtr func,
-			  void *data)
+			  void *data, unsigned int target_msc)
 {
     struct dri2_buffer_priv *back_priv;
     struct radeon_exa_pixmap_priv *exa_priv;
@@ -613,6 +613,8 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
     flip_info->type = DRI2_SWAP;
     flip_info->event_complete = func;
     flip_info->event_data = data;
+    flip_info->frame = target_msc;
+
     xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
 		   "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info);
 
@@ -717,7 +719,8 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
 				      event->front,
 				      event->back,
 				      event->event_complete,
-				      event->event_data)) {
+				      event->event_data,
+				      event->frame)) {
 	    radeon_dri2_exchange_buffers(drawable, event->front, event->back);
 	    break;
 	}
commit 69639ef377a9d6701cdef902f8a1c5e0b58cf833
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Thu Dec 2 02:12:24 2010 -0500

    radeon/kms: pageflipping man page updates

diff --git a/man/radeon.man b/man/radeon.man
index 103b465..499b1e5 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -259,7 +259,22 @@ to use VRAM for non-essential pixmaps.  This option allows us to override the
 heuristic.  The default is
 .B on
 with > 32MB VRAM, off with < 32MB.
-
+.TP
+.BI "Option \*qSwapbuffersWait\*q \*q" boolean \*q
+This option controls the behavior of glXSwapBuffers and glXCopySubBufferMESA
+calls by GL applications.  If enabled, the calls will avoid tearing by making
+sure the display scanline is outside of the area to be copied before the copy
+occurs.  If disabled, no scanline synchronization is performed, meaning tearing
+will likely occur.  Note that when enabled, this option can adversely affect
+the framerate of applications that render frames at less than refresh rate.
+.IP
+The default value is
+.B on.
+.TP
+.BI "Option \*qEnablePageFlip\*q \*q" boolean \*q
+Enable DRI2 page flipping.  The default is
+.B on.
+Pageflipping is supported on all radeon hardware.
 .PP
 The following driver
 .B Options
@@ -364,17 +379,6 @@ Color tiling will be automatically disabled in interlaced or doublescan screen m
 .br
 The default value is
 .B on.
-.TP
-.BI "Option \*qSwapbuffersWait\*q \*q" boolean \*q
-This option controls the behavior of glXSwapBuffers and glXCopySubBufferMESA
-calls by GL applications.  If enabled, the calls will avoid tearing by making
-sure the display scanline is outside of the area to be copied before the copy
-occurs.  If disabled, no scanline synchronization is performed, meaning tearing
-will likely occur.  Note that when enabled, this option can adversely affect
-the framerate of applications that render frames at less than refresh rate.
-.IP
-The default value is
-.B on.
 .TP 
 .BI "Option \*qIgnoreEDID\*q \*q" boolean \*q
 Do not use EDID data for mode validation.  DDC is still used
commit f48af8a6cfa1ac665f07b8f9712e94b77bc4f5e9
Author: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
Date:   Tue Nov 23 04:41:53 2010 +0100

    ddx/ati: Fix reporting of pageflip completion events on multi-head.
    
    When a drawable is page-flipped on multiple crtc's (fullscreen
    drawable on mirror-mode or multi-head x-screen), only one pageflip
    event is finally delivered, after the last participating crtc signals
    flip completion, this to avoid visual corruption.
    
    Old code returned vblank count and timestamps of flip completion
    of this last crtc, instead of the values of the "master crtc", the
    one that was used for initially scheduling/triggering the pagflip
    via vblank events. (master = radeon_dri2_drawable_crtc(drawable))
    
    This patch makes sure that the pageflip completion values of the
    "master" crtc are returned, otherwise client applications will
    get confused by the random (msc, ust) values returned by whichever
    crtc was the last to complete its flip. Without this, the returned
    values change randomly and jump forward and backward in time and
    count.
    
    The patch also implements a consistency check on returned vblank
    count values of pageflip completion. Impossible values are detected,
    a x-warning is logged and returned (msc,ust) values are marked invalid,
    so clients could perform error handling. Such a warning would indicate
    bugs in the pageflip completion routine of future kms drivers or the
    ddx to aid driver debugging.
    
    Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 1310da7..9248cb0 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1284,18 +1284,32 @@ static void
 drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
 		     unsigned int tv_usec, void *event_data)
 {
-	drmmode_ptr drmmode = event_data;
+	drmmode_flipevtcarrier_ptr flipcarrier = event_data;
+	drmmode_ptr drmmode = flipcarrier->drmmode;
+
+	/* Is this the event whose info shall be delivered to higher level? */
+	if (flipcarrier->dispatch_me) {
+		/* Yes: Cache msc, ust for later delivery. */
+		drmmode->fe_frame = frame;
+		drmmode->fe_tv_sec = tv_sec;
+		drmmode->fe_tv_usec = tv_usec;
+	}
+	free(flipcarrier);
 
+	/* Last crtc completed flip? */
 	drmmode->flip_count--;
 	if (drmmode->flip_count > 0)
 		return;
 
+	/* Release framebuffer */
 	drmModeRmFB(drmmode->fd, drmmode->old_fb_id);
 
 	if (drmmode->event_data == NULL)
 		return;
 
-	radeon_dri2_flip_event_handler(frame, tv_sec, tv_usec, drmmode->event_data);
+	/* Deliver cached msc, ust from reference crtc to flip event handler */
+	radeon_dri2_flip_event_handler(drmmode->fe_frame, drmmode->fe_tv_sec,
+				       drmmode->fe_tv_usec, drmmode->event_data);
 }
 
 
@@ -1584,7 +1598,7 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
 #endif
 }
 
-Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data)
+Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id)
 {
 	RADEONInfoPtr info = RADEONPTR(scrn);
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -1594,6 +1608,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
 	int i, old_fb_id;
 	uint32_t tiling_flags = 0;
 	int height;
+	drmmode_flipevtcarrier_ptr flipcarrier;
 
 	if (info->allowColorTiling) {
 		if (info->ChipFamily >= CHIP_FAMILY_R600)
@@ -1623,6 +1638,10 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
 	 * Also, flips queued on disabled or incorrectly configured displays
 	 * may never complete; this is a configuration error.
 	 */
+	drmmode->fe_frame = 0;
+	drmmode->fe_tv_sec = 0;
+	drmmode->fe_tv_usec = 0;
+
 	for (i = 0; i < config->num_crtc; i++) {
 		if (!config->crtc[i]->enabled)
 			continue;
@@ -1630,10 +1649,25 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
 		drmmode->event_data = data;
 		drmmode->flip_count++;
 		drmmode_crtc = config->crtc[i]->driver_private;
+
+		flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec));
+		if (!flipcarrier) {
+			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+				   "flip queue: carrier alloc failed.\n");
+			goto error_undo;
+		}
+
+		/* Only the reference crtc will finally deliver its page flip
+		 * completion event. All other crtc's events will be discarded.
+		 */
+		flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id);
+		flipcarrier->drmmode = drmmode;
+
 		if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
-				    drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, drmmode)) {
+				    drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) {
 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 				   "flip queue failed: %s\n", strerror(errno));
+			free(flipcarrier);
 			goto error_undo;
 		}
 	}
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index c3d3561..548907b 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -52,9 +52,17 @@ typedef struct {
   drmEventContext event_context;
   int flip_count;
   void *event_data;
+  unsigned int fe_frame;
+  unsigned int fe_tv_sec;
+  unsigned int fe_tv_usec;
 } drmmode_rec, *drmmode_ptr;
 
 typedef struct {
+  drmmode_ptr drmmode;
+  Bool dispatch_me;
+} drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr;
+
+typedef struct {
     drmmode_ptr drmmode;
     drmModeCrtcPtr mode_crtc;
     int hw_id;
@@ -101,7 +109,7 @@ extern int drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling);
 extern int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
 extern int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
 
-Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data);
+Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id);
 
 #endif
 
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index c28017c..8b12872 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -571,6 +571,26 @@ radeon_dri2_unref_buffer(BufferPtr buffer)
     }
 }
 
+static int radeon_dri2_drawable_crtc(DrawablePtr pDraw)
+{
+    ScreenPtr pScreen = pDraw->pScreen;
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    xf86CrtcPtr crtc;
+    int crtc_id = -1;
+
+    crtc = radeon_pick_best_crtc(pScrn,
+				 pDraw->x,
+				 pDraw->x + pDraw->width,
+				 pDraw->y,
+				 pDraw->y + pDraw->height);
+
+    /* Make sure the CRTC is valid and this is the real front buffer */
+    if (crtc != NULL && !crtc->rotatedData) {
+        crtc_id = drmmode_get_crtc_id(crtc);
+    }
+    return crtc_id;
+}
+
 static Bool
 radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
 			  DrawablePtr draw, DRI2BufferPtr front,
@@ -581,6 +601,9 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
     struct radeon_exa_pixmap_priv *exa_priv;
     DRI2FrameEventPtr flip_info;
 
+    /* Main crtc for this drawable shall finally deliver pageflip event. */
+    int ref_crtc_hw_id = radeon_dri2_drawable_crtc(draw);
+
     flip_info = calloc(1, sizeof(DRI2FrameEventRec));
     if (!flip_info)
 	return FALSE;
@@ -596,7 +619,8 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
     /* Page flip the full screen buffer */
     back_priv = back->driverPrivate;
     exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap);
-    return radeon_do_pageflip(scrn, exa_priv->bo, flip_info);
+
+    return radeon_do_pageflip(scrn, exa_priv->bo, flip_info, ref_crtc_hw_id);
 }
 
 static Bool
@@ -735,26 +759,6 @@ cleanup:
     free(event);
 }
 
-static int radeon_dri2_drawable_crtc(DrawablePtr pDraw)
-{
-    ScreenPtr pScreen = pDraw->pScreen;
-    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
-    xf86CrtcPtr crtc;
-    int crtc_id = -1;
-
-    crtc = radeon_pick_best_crtc(pScrn,
-				 pDraw->x,
-				 pDraw->x + pDraw->width,
-				 pDraw->y,
-				 pDraw->y + pDraw->height);
-
-    /* Make sure the CRTC is valid and this is the real front buffer */
-    if (crtc != NULL && !crtc->rotatedData) {
-        crtc_id = drmmode_get_crtc_id(crtc);
-    }
-    return crtc_id;
-}
-
 /*
  * Get current frame count and frame count timestamp, based on drawable's
  * crtc.
@@ -952,6 +956,18 @@ void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
     /* We assume our flips arrive in order, so we don't check the frame */
     switch (flip->type) {
     case DRI2_SWAP:
+	/* Check for too small vblank count of pageflip completion, taking wraparound
+	 * into account. This usually means some defective kms pageflip completion,
+	 * causing wrong (msc, ust) return values and possible visual corruption.
+	 */
+	if ((frame < flip->frame) && (flip->frame - frame < 5)) {
+	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		       "%s: Pageflip completion event has impossible msc %d < target_msc %d\n",
+		        __func__, frame, flip->frame);
+	    /* All-Zero values signal failure of (msc, ust) timestamping to client. */
+	    frame = tv_sec = tv_usec = 0;
+	}
+
 	DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
 			 DRI2_FLIP_COMPLETE, flip->event_complete,
 			 flip->event_data);
commit 122536ee0aeb1eef1a9d80d5e464dcb423dc2837
Author: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
Date:   Mon Nov 22 04:11:07 2010 +0100

    ddx/ati: Add option "SwapbuffersWait" to control vsync of DRI2 swaps.
    
    A new optional kms driver option "SwapbuffersWait" is defined
    for xorg.conf, which defaults to "on". If "on", DRI2 bufferswaps
    will be synchronized to vsync, otherwise not.
    
    This currently only affects copy-swaps, not pageflipped swaps.
    It also requires a swap_interval setting of zero by the OpenGL
    client.
    
    Ideally, we'd provide a way for dri2 to pass the current swap
    interval to the ddx so we could change this dynamically.
    
    Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>

diff --git a/man/radeon.man b/man/radeon.man
index ede41b9..103b465 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -364,6 +364,17 @@ Color tiling will be automatically disabled in interlaced or doublescan screen m
 .br
 The default value is
 .B on.
+.TP
+.BI "Option \*qSwapbuffersWait\*q \*q" boolean \*q
+This option controls the behavior of glXSwapBuffers and glXCopySubBufferMESA
+calls by GL applications.  If enabled, the calls will avoid tearing by making
+sure the display scanline is outside of the area to be copied before the copy
+occurs.  If disabled, no scanline synchronization is performed, meaning tearing
+will likely occur.  Note that when enabled, this option can adversely affect
+the framerate of applications that render frames at less than refresh rate.
+.IP
+The default value is
+.B on.
 .TP 
 .BI "Option \*qIgnoreEDID\*q \*q" boolean \*q
 Do not use EDID data for mode validation.  DDC is still used
diff --git a/src/radeon.h b/src/radeon.h
index 0f7d012..42b7485 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -224,7 +224,8 @@ typedef enum {
     OPTION_FORCE_LOW_POWER,
     OPTION_DYNAMIC_PM,
     OPTION_NEW_PLL,
-    OPTION_ZAPHOD_HEADS
+    OPTION_ZAPHOD_HEADS,
+    OPTION_SWAPBUFFERS_WAIT
 } RADEONOpts;
 
 
@@ -1076,6 +1077,9 @@ typedef struct {
     int               bicubic_offset;
     /* kms pageflipping */
     Bool allowPageFlip;
+
+    /* Perform vsync'ed SwapBuffers? */
+    Bool swapBuffersWait;
 } RADEONInfoRec, *RADEONInfoPtr;
 
 #define RADEONWaitForFifo(pScrn, entries)				\
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index 69f8a48..c28017c 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -443,7 +443,9 @@ radeon_dri2_copy_region(DrawablePtr drawable,
     }
 
     vsync = info->accel_state->vsync;
-    info->accel_state->vsync = TRUE;
+
+    /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */ 
+    info->accel_state->vsync = info->swapBuffersWait;
 
     (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc,
                          0, 0, drawable->width, drawable->height, 0, 0);
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 38467c0..59f8281 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -71,6 +71,7 @@ const OptionInfoRec RADEONOptions_KMS[] = {
     { OPTION_EXA_PIXMAPS,    "EXAPixmaps",	 OPTV_BOOLEAN,   {0}, FALSE },
     { OPTION_ZAPHOD_HEADS,   "ZaphodHeads",      OPTV_STRING,  {0}, FALSE },
     { OPTION_PAGE_FLIP,      "EnablePageFlip",   OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_SWAPBUFFERS_WAIT,"SwapbuffersWait", OPTV_BOOLEAN, {0}, FALSE },
     { -1,                    NULL,               OPTV_NONE,    {0}, FALSE }
 };
 
@@ -628,6 +629,11 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
 		   "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis");
     }
 
+    info->swapBuffersWait = xf86ReturnOptValBool(info->Options,
+						 OPTION_SWAPBUFFERS_WAIT, TRUE);
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	       "SwapBuffers wait for vsync: %sabled\n", info->swapBuffersWait ? "en" : "dis");
+
     if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n");
 	goto fail;
commit 0de680730294bd623f6b3e189faa7b88a09d3a2a
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Wed Nov 17 17:39:39 2010 -0500

    radeon/kms: add pageflip support
    
    requires radeon drm 2.8.0 or higher
    
    Signed-off-by: Alex Deucher <alexdeucher at gmail.com>
    Signed-off-by: Jerome Glisse <jglisse at redhat.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 3301231..1310da7 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -29,6 +29,7 @@
 #include "config.h"
 #endif
 
+#include <errno.h>
 #ifdef XF86DRM_MODE
 #include <sys/ioctl.h>
 #include "micmap.h"
@@ -1280,6 +1281,25 @@ drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
 }
 
 static void
+drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
+		     unsigned int tv_usec, void *event_data)
+{
+	drmmode_ptr drmmode = event_data;
+
+	drmmode->flip_count--;
+	if (drmmode->flip_count > 0)
+		return;
+
+	drmModeRmFB(drmmode->fd, drmmode->old_fb_id);
+
+	if (drmmode->event_data == NULL)
+		return;
+
+	radeon_dri2_flip_event_handler(frame, tv_sec, tv_usec, drmmode->event_data);
+}
+
+
+static void
 drm_wakeup_handler(pointer data, int err, pointer p)
 {
 	drmmode_ptr drmmode = data;
@@ -1322,8 +1342,9 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
 	drmmode->flip_count = 0;
 	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
 	drmmode->event_context.vblank_handler = drmmode_vblank_handler;
-	drmmode->event_context.page_flip_handler = NULL;
+	drmmode->event_context.page_flip_handler = drmmode_flip_handler;
 	if (!pRADEONEnt->fd_wakeup_registered && info->dri->pKernelDRMVersion->version_minor >= 4) {
+		drmmode->flip_count = 0;
 		AddGeneralSocket(drmmode->fd);
 		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
 				drm_wakeup_handler, drmmode);
@@ -1563,4 +1584,71 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
 #endif
 }
 
+Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data)
+{
+	RADEONInfoPtr info = RADEONPTR(scrn);
+	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	unsigned int pitch = scrn->displayWidth * info->CurrentLayout.pixel_bytes;
+	int i, old_fb_id;
+	uint32_t tiling_flags = 0;
+	int height;
+
+	if (info->allowColorTiling) {
+		if (info->ChipFamily >= CHIP_FAMILY_R600)
+			tiling_flags |= RADEON_TILING_MICRO;
+		else
+			tiling_flags |= RADEON_TILING_MACRO;
+	}
+
+	pitch = RADEON_ALIGN(pitch, drmmode_get_pitch_align(scrn, info->CurrentLayout.pixel_bytes, tiling_flags));
+	height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags));
+
+	/*
+	 * Create a new handle for the back buffer
+	 */
+	old_fb_id = drmmode->fb_id;
+	if (drmModeAddFB(drmmode->fd, scrn->virtualX, height,
+			 scrn->depth, scrn->bitsPerPixel, pitch,
+			 new_front->handle, &drmmode->fb_id))
+		goto error_out;
+
+	/*
+	 * Queue flips on all enabled CRTCs
+	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
+	 * Right now it assumes a single shared fb across all CRTCs, with the
+	 * kernel fixing up the offset of each CRTC as necessary.
+	 *
+	 * Also, flips queued on disabled or incorrectly configured displays
+	 * may never complete; this is a configuration error.
+	 */
+	for (i = 0; i < config->num_crtc; i++) {
+		if (!config->crtc[i]->enabled)
+			continue;
+
+		drmmode->event_data = data;
+		drmmode->flip_count++;
+		drmmode_crtc = config->crtc[i]->driver_private;
+		if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+				    drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, drmmode)) {
+			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+				   "flip queue failed: %s\n", strerror(errno));
+			goto error_undo;
+		}
+	}
+
+	drmmode->old_fb_id = old_fb_id;
+	return TRUE;
+
+error_undo:
+	drmModeRmFB(drmmode->fd, drmmode->fb_id);
+	drmmode->fb_id = old_fb_id;
+
+error_out:
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
+		   strerror(errno));
+	return FALSE;
+}
+
 #endif
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index e6bfd50..c3d3561 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -39,6 +39,7 @@
 typedef struct {
   int fd;
   unsigned fb_id;
+  unsigned old_fb_id;
   drmModeResPtr mode_res;
   drmModeFBPtr mode_fb;
   int cpp;
@@ -50,6 +51,7 @@ typedef struct {
 #endif
   drmEventContext event_context;
   int flip_count;
+  void *event_data;
 } drmmode_rec, *drmmode_ptr;
 
 typedef struct {
@@ -99,6 +101,8 @@ extern int drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling);
 extern int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
 extern int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
 
+Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data);
+
 #endif
 
 #endif
diff --git a/src/radeon.h b/src/radeon.h
index 84d3563..0f7d012 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -1074,6 +1074,8 @@ typedef struct {
     struct radeon_bo *bicubic_bo;
     void             *bicubic_memory;
     int               bicubic_offset;
+    /* kms pageflipping */
+    Bool allowPageFlip;
 } RADEONInfoRec, *RADEONInfoPtr;
 
 #define RADEONWaitForFifo(pScrn, entries)				\
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index f2ea0bb..69f8a48 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -82,6 +82,10 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
     struct radeon_exa_pixmap_priv *driver_priv;
     int i, r, need_enlarge = 0;
     int flags = 0;
+    unsigned front_width;
+
+    pixmap = screen->GetScreenPixmap(screen);
+    front_width = pixmap->drawable.width;
 
     buffers = calloc(count, sizeof *buffers);
     if (buffers == NULL) {
@@ -162,12 +166,18 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
 						  drawable->depth,
 						  flags);
 
-	    } else
+	    } else {
+		unsigned aligned_width = drawable->width;
+
+		if (aligned_width == front_width)
+		    aligned_width = pScrn->virtualX;
+
 		pixmap = (*pScreen->CreatePixmap)(pScreen,
-						  drawable->width,
+						  aligned_width,
 						  drawable->height,
 						  drawable->depth,
 						  flags);
+	    }
         }
 
         if (attachments[i] == DRI2BufferDepth) {
@@ -206,6 +216,10 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
     struct radeon_exa_pixmap_priv *driver_priv;
     int r, need_enlarge = 0;
     int flags;
+    unsigned front_width;
+
+    pixmap = pScreen->GetScreenPixmap(pScreen);
+    front_width = pixmap->drawable.width;
 
     buffers = calloc(1, sizeof *buffers);
     if (buffers == NULL) {
@@ -287,12 +301,18 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
 					      (format != 0)?format:drawable->depth,
 					      flags);
 
-	} else
+	} else {
+	    unsigned aligned_width = drawable->width;
+
+	    if (aligned_width == front_width)
+		aligned_width = pScrn->virtualX;
+
 	    pixmap = (*pScreen->CreatePixmap)(pScreen,
-					      drawable->width,
+					      aligned_width,
 					      drawable->height,
 					      (format != 0)?format:drawable->depth,
 					      flags);
+	}
     }
 
     if (attachment == DRI2BufferDepth) {
@@ -549,12 +569,98 @@ radeon_dri2_unref_buffer(BufferPtr buffer)
     }
 }
 
+static Bool
+radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
+			  DrawablePtr draw, DRI2BufferPtr front,
+			  DRI2BufferPtr back, DRI2SwapEventPtr func,
+			  void *data)
+{
+    struct dri2_buffer_priv *back_priv;
+    struct radeon_exa_pixmap_priv *exa_priv;
+    DRI2FrameEventPtr flip_info;
+
+    flip_info = calloc(1, sizeof(DRI2FrameEventRec));
+    if (!flip_info)
+	return FALSE;
+
+    flip_info->drawable_id = draw->id;
+    flip_info->client = client;
+    flip_info->type = DRI2_SWAP;
+    flip_info->event_complete = func;
+    flip_info->event_data = data;
+    xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info);
+
+    /* Page flip the full screen buffer */
+    back_priv = back->driverPrivate;
+    exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap);
+    return radeon_do_pageflip(scrn, exa_priv->bo, flip_info);
+}
+
+static Bool
+can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
+{
+    struct dri2_buffer_priv *front_priv = front->driverPrivate;
+    struct dri2_buffer_priv *back_priv = back->driverPrivate;
+    PixmapPtr front_pixmap = front_priv->pixmap;
+    PixmapPtr back_pixmap = back_priv->pixmap;
+
+    if (front_pixmap->drawable.width != back_pixmap->drawable.width)
+	return FALSE;
+
+    if (front_pixmap->drawable.height != back_pixmap->drawable.height)
+	return FALSE;
+
+    if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
+	return FALSE;
+
+    if (front_pixmap->devKind != back_pixmap->devKind)
+	return FALSE;
+
+    return TRUE;
+}
+
+static void
+radeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
+{
+    struct dri2_buffer_priv *front_priv = front->driverPrivate;
+    struct dri2_buffer_priv *back_priv = back->driverPrivate;
+    struct radeon_exa_pixmap_priv *front_radeon, *back_radeon;
+    ScreenPtr screen;
+    RADEONInfoPtr info;
+    struct radeon_bo *bo;
+    int tmp;
+
+    /* Swap BO names so DRI works */
+    tmp = front->name;
+    front->name = back->name;
+    back->name = tmp;
+
+    /* Swap pixmap bos */
+    front_radeon = exaGetPixmapDriverPrivate(front_priv->pixmap);
+    back_radeon = exaGetPixmapDriverPrivate(back_priv->pixmap);
+    bo = back_radeon->bo;
+    back_radeon->bo = front_radeon->bo;
+    front_radeon->bo = bo;
+
+    /* Do we need to update the Screen? */
+    screen = draw->pScreen;
+    info = RADEONPTR(xf86Screens[screen->myNum]);
+    if (front_radeon->bo == info->front_bo) {
+	radeon_bo_unref(info->front_bo);
+	info->front_bo = back_radeon->bo;
+	radeon_bo_ref(info->front_bo);
+	front_radeon = exaGetPixmapDriverPrivate(screen->GetScreenPixmap(screen));
+        front_radeon->bo = bo;
+    }
+}
+
 void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
                                      unsigned int tv_usec, void *event_data)
 {
     DRI2FrameEventPtr event = event_data;
+    RADEONInfoPtr info;
     DrawablePtr drawable;
-    ClientPtr client;
     ScreenPtr screen;
     ScrnInfoPtr scrn;
     int status;
@@ -563,7 +669,7 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
     RegionRec region;
 
     if (!event->valid)
-        goto cleanup;
+	goto cleanup;
 
     status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
                                M_ANY, DixWriteAccess);
@@ -572,25 +678,45 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
 
     screen = drawable->pScreen;
     scrn = xf86Screens[screen->myNum];
-    client = event->client;
+    info = RADEONPTR(scrn);
 
     switch (event->type) {
     case DRI2_FLIP:
+	if (info->allowPageFlip &&
+	    DRI2CanFlip(drawable) &&
+	    can_exchange(event->front, event->back) &&
+	    radeon_dri2_schedule_flip(scrn,
+				      event->client,
+				      drawable,
+				      event->front,
+				      event->back,
+				      event->event_complete,
+				      event->event_data)) {
+	    radeon_dri2_exchange_buffers(drawable, event->front, event->back);
+	    break;
+	}
+	/* else fall through to exchange/blit */
     case DRI2_SWAP:
-        box.x1 = 0;
-        box.y1 = 0;
-        box.x2 = drawable->width;
-        box.y2 = drawable->height;
-        REGION_INIT(pScreen, &region, &box, 0);
-        radeon_dri2_copy_region(drawable, &region, event->front, event->back);
-        swap_type = DRI2_BLIT_COMPLETE;
-
-        DRI2SwapComplete(client, drawable, frame, tv_sec, tv_usec,
+	if (DRI2CanExchange(drawable) &&
+	    can_exchange(event->front, event->back)) {
+	    radeon_dri2_exchange_buffers(drawable, event->front, event->back);
+	    swap_type = DRI2_EXCHANGE_COMPLETE;
+	} else {
+	    box.x1 = 0;
+	    box.y1 = 0;
+	    box.x2 = drawable->width;
+	    box.y2 = drawable->height;
+	    REGION_INIT(pScreen, &region, &box, 0);
+	    radeon_dri2_copy_region(drawable, &region, event->front, event->back);
+	    swap_type = DRI2_BLIT_COMPLETE;
+	}
+
+        DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec,
                 swap_type, event->event_complete, event->event_data);
 
         break;
     case DRI2_WAITMSC:
-        DRI2WaitMSCComplete(client, drawable, frame, tv_sec, tv_usec);
+        DRI2WaitMSCComplete(event->client, drawable, frame, tv_sec, tv_usec);
         break;
     default:
         /* Unknown type */
@@ -638,7 +764,7 @@ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
     RADEONInfoPtr info = RADEONPTR(scrn);
     drmVBlank vbl;
     int ret;
-    int crtc= radeon_dri2_drawable_crtc(draw);
+    int crtc = radeon_dri2_drawable_crtc(draw);
 
     /* Drawable not displayed, make up a value */
     if (crtc == -1) {
@@ -796,6 +922,47 @@ out_complete:
     return TRUE;
 }
 
+void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
+				    unsigned int tv_usec, void *event_data)
+{
+    DRI2FrameEventPtr flip = event_data;
+    DrawablePtr drawable;
+    ScreenPtr screen;
+    ScrnInfoPtr scrn;
+    int status;
+    PixmapPtr pixmap;
+
+    status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient,
+			       M_ANY, DixWriteAccess);
+    if (status != Success) {
+	free(flip);
+	return;
+    }
+
+    screen = drawable->pScreen;
+    scrn = xf86Screens[screen->myNum];
+
+    pixmap = screen->GetScreenPixmap(screen);
+    xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n",
+		   __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4);
+
+    /* We assume our flips arrive in order, so we don't check the frame */
+    switch (flip->type) {
+    case DRI2_SWAP:
+	DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
+			 DRI2_FLIP_COMPLETE, flip->event_complete,
+			 flip->event_data);
+	break;
+    default:
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__);
+	/* Unknown type */
+	break;
+    }
+
+    free(flip);
+}
+
 /*
  * ScheduleSwap is responsible for requesting a DRM vblank event for the
  * appropriate frame.
@@ -883,6 +1050,15 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
     }
 
     current_msc = vbl.reply.sequence;
+
+    /* Flips need to be submitted one frame before */
+    if (info->allowPageFlip &&
+	DRI2CanFlip(draw) &&
+	can_exchange(front, back)) {
+	swap_type = DRI2_FLIP;
+	flip = 1;
+    }
+
     swap_info->type = swap_type;
 
     /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
@@ -899,9 +1075,6 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
      */
     if (divisor == 0 || current_msc < *target_msc) {
         vbl.request.type =  DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
-        if (crtc > 0)
-            vbl.request.type |= DRM_VBLANK_SECONDARY;
-
         /* If non-pageflipping, but blitting/exchanging, we need to use
          * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
          * on.
diff --git a/src/radeon_dri2.h b/src/radeon_dri2.h
index 688530f..7995286 100644
--- a/src/radeon_dri2.h
+++ b/src/radeon_dri2.h
@@ -44,5 +44,7 @@ xf86CrtcPtr radeon_covering_crtc(ScrnInfoPtr pScrn, BoxPtr box,
                                  xf86CrtcPtr desired, BoxPtr crtc_box_ret);
 void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
                                      unsigned int tv_usec, void *event_data);
+void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
+				    unsigned int tv_usec, void *event_data);
 
 #endif
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 122ac29..38467c0 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -70,6 +70,7 @@ const OptionInfoRec RADEONOptions_KMS[] = {
     { OPTION_EXA_VSYNC,      "EXAVSync",         OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_EXA_PIXMAPS,    "EXAPixmaps",	 OPTV_BOOLEAN,   {0}, FALSE },
     { OPTION_ZAPHOD_HEADS,   "ZaphodHeads",      OPTV_STRING,  {0}, FALSE },
+    { OPTION_PAGE_FLIP,      "EnablePageFlip",   OPTV_BOOLEAN, {0}, FALSE },
     { -1,                    NULL,               OPTV_NONE,    {0}, FALSE }
 };
 
@@ -620,6 +621,13 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 	 "KMS Color Tiling: %sabled\n", info->allowColorTiling ? "en" : "dis");
 
+    if (info->dri->pKernelDRMVersion->version_minor >= 8) {
+	info->allowPageFlip = xf86ReturnOptValBool(info->Options,
+						   OPTION_PAGE_FLIP, TRUE);
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		   "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis");
+    }
+
     if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n");
 	goto fail;
commit fccdca8db34010f566bd068c74cdef0f4a8cb7f5
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Wed Nov 17 17:37:25 2010 -0500

    radeon/kms: allow tiled front buffer on 6xx/7xx
    
    Use UTS/DFS to tile/untile as appropriate for sw access.
    Also enables pageflipping with tiling enabled.

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 0a6e338..3301231 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -266,9 +266,10 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 	uint32_t tiling_flags = 0;
 	int height;
 
-	/* no tiled scanout on r6xx+ yet */
 	if (info->allowColorTiling) {
-		if (info->ChipFamily < CHIP_FAMILY_R600)
+		if (info->ChipFamily >= CHIP_FAMILY_R600)
+			tiling_flags |= RADEON_TILING_MICRO;
+		else
 			tiling_flags |= RADEON_TILING_MACRO;
 	}
 
@@ -1167,9 +1168,10 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 	if (front_bo)
 		radeon_bo_wait(front_bo);
 
-	/* no tiled scanout on r6xx+ yet */
 	if (info->allowColorTiling) {
-		if (info->ChipFamily < CHIP_FAMILY_R600)
+		if (info->ChipFamily >= CHIP_FAMILY_R600)
+			tiling_flags |= RADEON_TILING_MICRO;
+		else
 			tiling_flags |= RADEON_TILING_MACRO;
 	}
 
diff --git a/src/evergreen_exa.c b/src/evergreen_exa.c
index 89afaff..7e62773 100644
--- a/src/evergreen_exa.c
+++ b/src/evergreen_exa.c
@@ -1647,22 +1647,29 @@ EVERGREENDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w,
     Bool flush = FALSE;
     Bool r;
     struct r600_accel_object src_obj, dst_obj;
+    uint32_t tiling_flags = 0, pitch = 0;
 
     if (bpp < 8)
 	return FALSE;
 
     driver_priv = exaGetPixmapDriverPrivate(pSrc);
 
+    ret = radeon_bo_get_tiling(driver_priv->bo, &tiling_flags, &pitch);
+    if (ret)
+	ErrorF("radeon_bo_get_tiling failed\n");
+
     /* If we know the BO won't end up in VRAM anyway, don't bother with a scratch */
     copy_src = driver_priv->bo;
     copy_pitch = pSrc->devKind;
-    if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
-	src_domain = radeon_bo_get_src_domain(driver_priv->bo);
-	if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
-	    (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
-	    src_domain = 0;
-	else /* A write may be scheduled */
-	    flush = TRUE;
+    if (!(tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
+	if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
+	    src_domain = radeon_bo_get_src_domain(driver_priv->bo);
+	    if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
+		(RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
+		src_domain = 0;
+	    else /* A write may be scheduled */
+		flush = TRUE;
+	}
     }
 
     if (!src_domain)
diff --git a/src/r600_exa.c b/src/r600_exa.c
index f6cde1d..9b3144b 100644
--- a/src/r600_exa.c
+++ b/src/r600_exa.c
@@ -1895,22 +1895,29 @@ R600DownloadFromScreenCS(PixmapPtr pSrc, int x, int y, int w,
     Bool flush = FALSE;
     Bool r;
     struct r600_accel_object src_obj, dst_obj;
+    uint32_t tiling_flags = 0, pitch = 0;
 
     if (bpp < 8)
 	return FALSE;
 
     driver_priv = exaGetPixmapDriverPrivate(pSrc);
 
+    ret = radeon_bo_get_tiling(driver_priv->bo, &tiling_flags, &pitch);
+    if (ret)
+	ErrorF("radeon_bo_get_tiling failed\n");
+
     /* If we know the BO won't end up in VRAM anyway, don't bother with a scratch */
     copy_src = driver_priv->bo;
     copy_pitch = pSrc->devKind;
-    if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
-	src_domain = radeon_bo_get_src_domain(driver_priv->bo);
-	if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
-	    (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
-	    src_domain = 0;
-	else /* A write may be scheduled */
-	    flush = TRUE;
+    if (!(tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
+	if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
+	    src_domain = radeon_bo_get_src_domain(driver_priv->bo);
+	    if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
+		(RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
+		src_domain = 0;
+	    else /* A write may be scheduled */
+		flush = TRUE;
+	}
     }
 
     if (!src_domain)
diff --git a/src/radeon_exa.c b/src/radeon_exa.c
index 503d569..1c512d4 100644
--- a/src/radeon_exa.c
+++ b/src/radeon_exa.c
@@ -306,6 +306,17 @@ Bool RADEONPrepareAccess_CS(PixmapPtr pPix, int index)
     if (!driver_priv)
       return FALSE;
 
+    if (info->ChipFamily >= CHIP_FAMILY_R600) {
+	uint32_t tiling_flags = 0, pitch = 0;
+
+	ret = radeon_bo_get_tiling(driver_priv->bo, &tiling_flags, &pitch);
+	if (ret)
+	    return FALSE;
+	/* untile in DFS/UTS */
+	if (tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))
+	    return FALSE;
+    }
+
     /* if we have more refs than just the BO then flush */
     if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
 	flush = TRUE;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index f4c54b3..122ac29 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -678,7 +678,9 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
 
     /* no tiled scanout on r6xx+ yet */
     if (info->allowColorTiling) {
-	if (info->ChipFamily < CHIP_FAMILY_R600)
+	if (info->ChipFamily >= CHIP_FAMILY_R600)
+	    tiling |= RADEON_TILING_MICRO;
+	else
 	    tiling |= RADEON_TILING_MACRO;
     }
     cpp = pScrn->bitsPerPixel / 8;
@@ -1115,9 +1117,10 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
 	    return FALSE;
     }
 
-    /* no tiled scanout on r6xx+ yet */
     if (info->allowColorTiling) {
-	if (info->ChipFamily < CHIP_FAMILY_R600)
+	if (info->ChipFamily >= CHIP_FAMILY_R600)
+	    tiling_flags |= RADEON_TILING_MICRO;
+	else
 	    tiling_flags |= RADEON_TILING_MACRO;
     }
     pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, cpp, tiling_flags)) * cpp;


More information about the xorg-commit mailing list