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

Michel Dänzer daenzer at kemper.freedesktop.org
Thu May 11 09:56:17 UTC 2017


 src/drmmode_display.c  |  244 ++++++++++++++++++++++++++-----------------------
 src/drmmode_display.h  |   44 +++++++-
 src/radeon.h           |   73 ++++++++++++++
 src/radeon_bo_helper.h |    3 
 src/radeon_dri2.c      |    5 -
 src/radeon_exa.c       |    2 
 src/radeon_kms.c       |   71 +++++++++++---
 src/radeon_present.c   |   23 ----
 8 files changed, 305 insertions(+), 160 deletions(-)

New commits:
commit 7dc68e26755466f9056f8c72195ab8690660693d
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Tue May 2 11:47:58 2017 +0900

    Simplify tracking of PRIME scanout pixmap
    
    Remember the shared pixmap passed to drmmode_set_scanout_pixmap for each
    CRTC, and just compare against that.
    
    Fixes leaving stale entries in ScreenRec::pixmap_dirty_list under some
    circumstances, which would usually result in use-after-free and a crash
    down the line.
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index ec307262..e2899cf5 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -732,9 +732,7 @@ drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
 
 		xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list,
 					 ent) {
-			if (dirty->src == crtc->randr_crtc->scanout_pixmap &&
-			    dirty->slave_dst ==
-			    drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap) {
+			if (dirty->src == drmmode_crtc->prime_scanout_pixmap) {
 				dirty->slave_dst =
 					drmmode_crtc->scanout[scanout_id].pixmap;
 				break;
@@ -887,7 +885,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
 
 #ifdef RADEON_PIXMAP_SHARING
-		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
+		if (drmmode_crtc->prime_scanout_pixmap) {
 			drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id,
 							  &fb, &x, &y);
 		} else
@@ -1278,14 +1276,15 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
 	PixmapDirtyUpdatePtr dirty;
 
 	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
-		if (dirty->slave_dst != drmmode_crtc->scanout[scanout_id].pixmap)
-			continue;
-
-		PixmapStopDirtyTracking(dirty->src, dirty->slave_dst);
-		drmmode_crtc_scanout_free(drmmode_crtc);
-		break;
+		if (dirty->src == drmmode_crtc->prime_scanout_pixmap) {
+			PixmapStopDirtyTracking(dirty->src, dirty->slave_dst);
+			break;
+		}
 	}
 
+	drmmode_crtc_scanout_free(drmmode_crtc);
+	drmmode_crtc->prime_scanout_pixmap = NULL;
+
 	if (!ppix)
 		return TRUE;
 
@@ -1302,6 +1301,8 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
 		return FALSE;
 	}
 
+	drmmode_crtc->prime_scanout_pixmap = ppix;
+
 #ifdef HAS_DIRTYTRACKING_ROTATION
 	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
 				 0, 0, 0, 0, RR_Rotate_0);
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 14d1cb03..df2c4b7b 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -92,6 +92,9 @@ typedef struct {
     unsigned scanout_id;
     Bool scanout_update_pending;
     Bool tear_free;
+
+    PixmapPtr prime_scanout_pixmap;
+
     int dpms_mode;
     /* For when a flip is pending when DPMS off requested */
     int pending_dpms_mode;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 2b410eb3..c4bdfcfa 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -657,8 +657,7 @@ radeon_prime_dirty_to_crtc(PixmapDirtyUpdatePtr dirty)
 	xf86CrtcPtr xf86_crtc = xf86_config->crtc[c];
 	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 
-	if (drmmode_crtc->scanout[0].pixmap == dirty->slave_dst ||
-	    drmmode_crtc->scanout[1].pixmap == dirty->slave_dst)
+	if (drmmode_crtc->prime_scanout_pixmap == dirty->src)
 	    return xf86_crtc;
     }
 
@@ -671,13 +670,11 @@ radeon_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id)
     ScrnInfoPtr scrn = crtc->scrn;
     ScreenPtr screen = scrn->pScreen;
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-    PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap;
     PixmapDirtyUpdatePtr dirty;
     Bool ret = FALSE;
 
     xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
-	if (dirty->src == scanoutpix && dirty->slave_dst ==
-	    drmmode_crtc->scanout[scanout_id ^ drmmode_crtc->tear_free].pixmap) {
+	if (dirty->src == drmmode_crtc->prime_scanout_pixmap) {
 	    RegionPtr region;
 
 	    if (master_has_sync_shared_pixmap(scrn, dirty))
commit 55e513b978b2afc52b7cafc5bfcb0d1dc78d75f6
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Sat Apr 29 17:05:58 2017 +0900

    Use reference counting for tracking KMS framebuffer lifetimes
    
    References are held by the pixmaps corresponding to the FBs (so
    the same KMS FB can be reused as long as the pixmap exists) and by the
    CRTCs scanning out from them (so a KMS FB is only destroyed once it's
    not being scanned out anymore, preventing intermittent black screens and
    worse issues due to a CRTC turning off when it should be on).
    
    v2:
    * Only increase reference count in drmmode_fb_reference if it was sane
      before
    * Make drmmode_fb_reference's indentation match the rest of
      drmmode_display.h
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index a101ac23..ec307262 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -375,6 +375,7 @@ drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
 
 		drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
 			       0, 0, 0, NULL, 0, NULL);
+		drmmode_fb_reference(drmmode->fd, &drmmode_crtc->fb, NULL);
 	} else if (drmmode_crtc->dpms_mode != DPMSModeOn)
 		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
 					    crtc->x, crtc->y);
@@ -447,8 +448,9 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 {
 	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
 	RADEONInfoPtr info = RADEONPTR(pScrn);
-	PixmapPtr src, dst;
 	ScreenPtr pScreen = pScrn->pScreen;
+	PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen);
+	struct drmmode_fb *fb = radeon_pixmap_get_fb(dst);
 	int fbcon_id = 0;
 	Bool force;
 	GCPtr gc;
@@ -464,7 +466,7 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 	if (!fbcon_id)
 		return;
 
-	if (fbcon_id == drmmode->fb_id) {
+	if (fbcon_id == fb->handle) {
 		/* in some rare case there might be no fbcon and we might already
 		 * be the one with the current fb to avoid a false deadlck in
 		 * kernel ttm code just do nothing as anyway there is nothing
@@ -477,8 +479,6 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 	if (!src)
 		return;
 
-	dst = pScreen->GetScreenPixmap(pScreen);
-
 	gc = GetScratchGC(pScrn->depth, pScreen);
 	ValidateGC(&dst->drawable, gc);
 
@@ -505,8 +505,6 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
 	}
 
 	if (scanout->bo) {
-		drmModeRmFB(drmmode->fd, scanout->fb_id);
-		scanout->fb_id = 0;
 		radeon_bo_unmap(scanout->bo);
 		radeon_bo_unref(scanout->bo);
 		scanout->bo = NULL;
@@ -571,15 +569,9 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
 	scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth,
 					     tiling, pScrn->bitsPerPixel,
 					     &pitch, &surface, &tiling);
-	if (scanout->bo == NULL)
-		goto error;
-
-	if (drmModeAddFB(drmmode->fd, width, height, pScrn->depth,
-			   pScrn->bitsPerPixel, pitch,
-			   scanout->bo->handle,
-			   &scanout->fb_id) != 0) {
-		ErrorF("failed to add scanout fb\n");
-		goto error;
+	if (!scanout->bo) {
+		ErrorF("failed to create CRTC scanout BO\n");
+		return NULL;
 	}
 
 	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
@@ -587,13 +579,17 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
 						 pScrn->depth,
 						 pScrn->bitsPerPixel,
 						 pitch, scanout->bo, NULL);
-	if (scanout->pixmap) {
+	if (!scanout->pixmap) {
+		ErrorF("failed to create CRTC scanout pixmap\n");
+		goto error;
+	}
+
+	if (radeon_pixmap_get_fb(scanout->pixmap)) {
 		scanout->width = width;
 		scanout->height = height;
 	} else {
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			   "Couldn't allocate scanout pixmap for CRTC\n");
-error:
+		ErrorF("failed to create CRTC scanout FB\n");
+error:		
 		drmmode_crtc_scanout_destroy(drmmode, scanout);
 	}
 
@@ -706,8 +702,8 @@ drmmode_handle_transform(xf86CrtcPtr crtc)
 
 static void
 drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
-				  unsigned scanout_id, int *fb_id, int *x,
-				  int *y)
+				  unsigned scanout_id, struct drmmode_fb **fb,
+				  int *x, int *y)
 {
 	ScrnInfoPtr scrn = crtc->scrn;
 	ScreenPtr screen = scrn->pScreen;
@@ -759,7 +755,7 @@ drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
 		}
 	}
 
-	*fb_id = drmmode_crtc->scanout[scanout_id].fb_id;
+	*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
 	*x = *y = 0;
 	drmmode_crtc->scanout_id = scanout_id;
 }
@@ -768,7 +764,8 @@ drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
 
 static void
 drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
-			    unsigned scanout_id, int *fb_id, int *x, int *y)
+			    unsigned scanout_id, struct drmmode_fb **fb, int *x,
+			    int *y)
 {
 	ScrnInfoPtr scrn = crtc->scrn;
 	ScreenPtr screen = scrn->pScreen;
@@ -804,7 +801,7 @@ drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
 		box->x2 = max(box->x2, scrn->virtualX);
 		box->y2 = max(box->y2, scrn->virtualY);
 
-		*fb_id = drmmode_crtc->scanout[scanout_id].fb_id;
+		*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
 		*x = *y = 0;
 
 		radeon_scanout_do_update(crtc, scanout_id);
@@ -841,7 +838,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 	int output_count = 0;
 	Bool ret = FALSE;
 	int i;
-	int fb_id;
+	struct drmmode_fb *fb = NULL;
 	drmModeModeInfo kmode;
 
 	/* The root window contents may be undefined before the WindowExposures
@@ -889,15 +886,14 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 
 		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
 
-		fb_id = drmmode->fb_id;
 #ifdef RADEON_PIXMAP_SHARING
 		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
 			drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id,
-							  &fb_id, &x, &y);
+							  &fb, &x, &y);
 		} else
 #endif
-		if (drmmode_crtc->rotate.fb_id) {
-			fb_id = drmmode_crtc->rotate.fb_id;
+		if (drmmode_crtc->rotate.pixmap) {
+			fb = radeon_pixmap_get_fb(drmmode_crtc->rotate.pixmap);
 			x = y = 0;
 
 		} else if (!radeon_is_gpu_screen(pScreen) &&
@@ -907,22 +903,24 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 #endif
 			    info->shadow_primary)) {
 			drmmode_crtc_scanout_update(crtc, mode, scanout_id,
-						    &fb_id, &x, &y);
+						    &fb, &x, &y);
 		}
 
-		if (fb_id == 0) {
-			if (drmModeAddFB(drmmode->fd,
-					 pScrn->virtualX,
-					 pScrn->virtualY,
-					 pScrn->depth, pScrn->bitsPerPixel,
-					 pScrn->displayWidth * info->pixel_bytes,
-					 info->front_bo->handle,
-					 &drmmode->fb_id) < 0) {
-				ErrorF("failed to add fb\n");
-				goto done;
-			}
-
-			fb_id = drmmode->fb_id;
+		if (!fb)
+			fb = radeon_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root));
+		if (!fb) {
+			fb = radeon_fb_create(drmmode->fd, pScrn->virtualX,
+					      pScrn->virtualY, pScrn->depth,
+					      pScrn->bitsPerPixel,
+					      pScrn->displayWidth * info->pixel_bytes,
+					      info->front_bo->handle);
+			/* Prevent refcnt of ad-hoc FBs from reaching 2 */
+			drmmode_fb_reference(drmmode->fd, &drmmode_crtc->fb, NULL);
+			drmmode_crtc->fb = fb;
+		}
+		if (!fb) {
+			ErrorF("failed to add FB for modeset\n");
+			goto done;
 		}
 
 		/* Wait for any pending flip to finish */
@@ -932,13 +930,15 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 
 		if (drmModeSetCrtc(drmmode->fd,
 				   drmmode_crtc->mode_crtc->crtc_id,
-				   fb_id, x, y, output_ids,
+				   fb->handle, x, y, output_ids,
 				   output_count, &kmode) != 0) {
 			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
 				   "failed to set mode: %s\n", strerror(errno));
 			goto done;
-		} else
+		} else {
 			ret = TRUE;
+			drmmode_fb_reference(drmmode->fd, &drmmode_crtc->fb, fb);
+		}
 
 		if (pScreen)
 			xf86CrtcSetScreenSubpixelOrder(pScreen);
@@ -983,7 +983,9 @@ done:
 	} else {
 		crtc->active = TRUE;
 
-		if (fb_id != drmmode_crtc->scanout[scanout_id].fb_id)
+		if (drmmode_crtc->scanout[scanout_id].pixmap &&
+		    fb != radeon_pixmap_get_fb(drmmode_crtc->
+					       scanout[scanout_id].pixmap))
 			drmmode_crtc_scanout_free(drmmode_crtc);
 		else if (!drmmode_crtc->tear_free) {
 			drmmode_crtc_scanout_destroy(drmmode,
@@ -2157,13 +2159,9 @@ static Bool
 drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 {
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
-	drmmode_crtc_private_ptr
-		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
-	drmmode_ptr drmmode = drmmode_crtc->drmmode;
 	RADEONInfoPtr info = RADEONPTR(scrn);
 	struct radeon_bo *old_front = NULL;
 	ScreenPtr   screen = xf86ScrnToScreen(scrn);
-	uint32_t    old_fb_id;
 	int	    i, pitch, old_width, old_height, old_pitch;
 	int aligned_height;
 	uint32_t screen_size;
@@ -2263,8 +2261,6 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 	old_width = scrn->virtualX;
 	old_height = scrn->virtualY;
 	old_pitch = scrn->displayWidth;
-	old_fb_id = drmmode->fb_id;
-	drmmode->fb_id = 0;
 	old_front = info->front_bo;
 
 	scrn->virtualX = width;
@@ -2346,8 +2342,6 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 				       crtc->rotation, crtc->x, crtc->y);
 	}
 
-	if (old_fb_id)
-		drmModeRmFB(drmmode->fd, old_fb_id);
 	if (old_front)
 		radeon_bo_unref(old_front);
 
@@ -2361,7 +2355,6 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 	scrn->virtualX = old_width;
 	scrn->virtualY = old_height;
 	scrn->displayWidth = old_pitch;
-	drmmode->fb_id = old_fb_id;
 
 	return FALSE;
 }
@@ -2375,7 +2368,7 @@ drmmode_clear_pending_flip(xf86CrtcPtr crtc)
 {
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
-	drmmode_crtc->flip_pending = FALSE;
+	drmmode_crtc->flip_pending = NULL;
 
 	if (!crtc->enabled ||
 	    (drmmode_crtc->pending_dpms_mode != DPMSModeOn &&
@@ -2419,7 +2412,7 @@ drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
 static void
 drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
 {
-	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	drmmode_flipdata_ptr flipdata = event_data;
 
 	/* Is this the event whose info shall be delivered to higher level? */
@@ -2439,12 +2432,11 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even
 		else
 			flipdata->handler(crtc, frame, usec, flipdata->event_data);
 
-		/* Release framebuffer */
-		drmModeRmFB(info->drmmode.fd, flipdata->old_fb_id);
-
 		free(flipdata);
 	}
 
+	drmmode_fb_reference(drmmode_crtc->drmmode->fd, &drmmode_crtc->fb,
+			     drmmode_crtc->flip_pending);
 	drmmode_clear_pending_flip(crtc);
 }
 
@@ -2701,6 +2693,8 @@ Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
 				drmModeSetCrtc(drmmode->fd,
 					       drmmode_crtc->mode_crtc->crtc_id,
 					       0, 0, 0, NULL, 0, NULL);
+				drmmode_fb_reference(drmmode->fd,
+						     &drmmode_crtc->fb, NULL);
 			}
 			continue;
 		}
@@ -2960,18 +2954,11 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	xf86CrtcPtr crtc = NULL;
 	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
-	drmmode_ptr drmmode = drmmode_crtc->drmmode;
 	int i;
 	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
 	drmmode_flipdata_ptr flipdata;
 	uintptr_t drm_queue_seq = 0;
-	uint32_t new_front_handle;
-
-	if (!radeon_get_pixmap_handle(new_front, &new_front_handle)) {
-		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-			   "flip queue: failed to get new front handle\n");
-		return FALSE;
-	}
+	struct drmmode_fb *fb;
 
         flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
         if (!flipdata) {
@@ -2980,15 +2967,11 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
              goto error;
         }
 
-	/*
-	 * Create a new handle for the back buffer
-	 */
-	flipdata->old_fb_id = drmmode->fb_id;
-	if (drmModeAddFB(drmmode->fd, new_front->drawable.width,
-			 new_front->drawable.height, scrn->depth,
-			 scrn->bitsPerPixel, new_front->devKind,
-			 new_front_handle, &drmmode->fb_id))
+	fb = radeon_pixmap_get_fb(new_front);
+	if (!fb) {
+		ErrorF("Failed to get FB for flip\n");
 		goto error;
+	}
 
 	/*
 	 * Queue flips on all enabled CRTCs
@@ -3032,7 +3015,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 		if (drmmode_crtc->hw_id == ref_crtc_hw_id) {
 			if (drmmode_page_flip_target_absolute(pRADEONEnt,
 							      drmmode_crtc,
-							      drmmode->fb_id,
+							      fb->handle,
 							      flip_flags,
 							      drm_queue_seq,
 							      target_msc) != 0)
@@ -3040,13 +3023,13 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 		} else {
 			if (drmmode_page_flip_target_relative(pRADEONEnt,
 							      drmmode_crtc,
-							      drmmode->fb_id,
+							      fb->handle,
 							      flip_flags,
 							      drm_queue_seq, 0) != 0)
 				goto flip_error;
 		}
 
-		drmmode_crtc->flip_pending = TRUE;
+		drmmode_crtc->flip_pending = fb;
 		drm_queue_seq = 0;
 	}
 
@@ -3058,12 +3041,6 @@ flip_error:
 		   strerror(errno));
 
 error:
-	if (flipdata && flipdata->flip_count <= 1 &&
-	    drmmode->fb_id != flipdata->old_fb_id) {
-		drmModeRmFB(drmmode->fd, drmmode->fb_id);
-		drmmode->fb_id = flipdata->old_fb_id;
-	}
-
 	if (drm_queue_seq)
 		radeon_drm_abort_entry(drm_queue_seq);
 	else if (crtc)
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 35d64179..14d1cb03 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -41,7 +41,6 @@
 
 typedef struct {
   int fd;
-  unsigned fb_id;
   drmModeFBPtr mode_fb;
   int cpp;
   struct radeon_bo_manager *bufmgr;
@@ -60,7 +59,6 @@ typedef struct {
 } drmmode_rec, *drmmode_ptr;
 
 typedef struct {
-  unsigned old_fb_id;
   int flip_count;
   void *event_data;
   unsigned int fe_frame;
@@ -70,10 +68,14 @@ typedef struct {
   radeon_drm_abort_proc abort;
 } drmmode_flipdata_rec, *drmmode_flipdata_ptr;
 
+struct drmmode_fb {
+	int refcnt;
+	uint32_t handle;
+};
+
 struct drmmode_scanout {
     struct radeon_bo *bo;
     PixmapPtr pixmap;
-    unsigned fb_id;
     int width, height;
 };
 
@@ -102,8 +104,10 @@ typedef struct {
      * modeset)
      */
     Bool need_modeset;
-    /* A flip is pending for this CRTC */
-    Bool flip_pending;
+    /* A flip to this FB is pending for this CRTC */
+    struct drmmode_fb *flip_pending;
+    /* The FB currently being scanned out by this CRTC, if any */
+    struct drmmode_fb *fb;
 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
 
 typedef struct {
@@ -135,6 +139,31 @@ enum drmmode_flip_sync {
 };
 
 
+static inline void
+drmmode_fb_reference(int drm_fd, struct drmmode_fb **old, struct drmmode_fb *new)
+{
+    if (new) {
+	if (new->refcnt <= 0)
+	    ErrorF("New FB's refcnt was %d in %s\n", new->refcnt, __func__);
+	else
+	    new->refcnt++;
+    }
+
+    if (*old) {
+	if ((*old)->refcnt <= 0) {
+	    ErrorF("Old FB's refcnt was %d in %s\n", (*old)->refcnt, __func__);
+	} else {
+	    if (--(*old)->refcnt == 0) {
+		drmModeRmFB(drm_fd, (*old)->handle);
+		free(*old);
+	    }
+	}
+    }
+
+    *old = new;
+}
+
+
 extern int drmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt,
 					     drmmode_crtc_private_ptr drmmode_crtc,
 					     int fb_id, uint32_t flags,
diff --git a/src/radeon.h b/src/radeon.h
index 2cb188e1..febe580b 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -288,6 +288,7 @@ struct radeon_pixmap {
 	uint_fast32_t gpu_write;
 
 	struct radeon_bo *bo;
+	struct drmmode_fb *fb;
 
 	uint32_t tiling_flags;
 
@@ -313,6 +314,7 @@ static inline void radeon_set_pixmap_private(PixmapPtr pixmap, struct radeon_pix
 
 struct radeon_exa_pixmap_priv {
     struct radeon_bo *bo;
+    struct drmmode_fb *fb;
     uint32_t tiling_flags;
     struct radeon_surface surface;
     Bool bo_mapped;
@@ -609,6 +611,9 @@ extern void  RADEONCopySwap(uint8_t *dst, uint8_t *src, unsigned int size, int s
 extern void RADEONInit3DEngine(ScrnInfoPtr pScrn);
 extern int radeon_cs_space_remaining(ScrnInfoPtr pScrn);
 
+/* radeon_bo_helper.c */
+extern Bool radeon_get_pixmap_handle(PixmapPtr pixmap, uint32_t *handle);
+
 /* radeon_commonfuncs.c */
 extern void RADEONWaitForVLine(ScrnInfoPtr pScrn, PixmapPtr pPix,
 			       xf86CrtcPtr crtc, int start, int stop);
@@ -706,6 +711,8 @@ static inline Bool radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo)
 		radeon_bo_unref(priv->bo);
 	    }
 
+	    drmmode_fb_reference(info->drmmode.fd, &priv->fb, NULL);
+
 	    if (!bo) {
 		free(priv);
 		priv = NULL;
@@ -790,6 +797,72 @@ static inline Bool radeon_get_pixmap_shared(PixmapPtr pPix)
     return FALSE;
 }
 
+static inline struct drmmode_fb*
+radeon_fb_create(int drm_fd, uint32_t width, uint32_t height, uint8_t depth,
+		 uint8_t bpp, uint32_t pitch, uint32_t handle)
+{
+    struct drmmode_fb *fb  = malloc(sizeof(*fb));
+
+    if (!fb)
+	return NULL;
+
+    fb->refcnt = 1;
+    if (drmModeAddFB(drm_fd, width, height, depth, bpp, pitch, handle,
+		     &fb->handle) == 0)
+	return fb;
+
+    free(fb);
+    return NULL;
+}
+
+static inline struct drmmode_fb*
+radeon_pixmap_create_fb(int drm_fd, PixmapPtr pix)
+{
+    uint32_t handle;
+
+    if (!radeon_get_pixmap_handle(pix, &handle))
+	return NULL;
+
+    return radeon_fb_create(drm_fd, pix->drawable.width, pix->drawable.height,
+			    pix->drawable.depth, pix->drawable.bitsPerPixel,
+			    pix->devKind, handle);
+}
+
+static inline struct drmmode_fb*
+radeon_pixmap_get_fb(PixmapPtr pix)
+{
+    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pix->drawable.pScreen));
+
+#ifdef USE_GLAMOR
+    if (info->use_glamor) {
+	struct radeon_pixmap *priv = radeon_get_pixmap_private(pix);
+
+	if (!priv)
+	    return NULL;
+
+	if (!priv->fb)
+	    priv->fb = radeon_pixmap_create_fb(info->drmmode.fd, pix);
+
+	return priv->fb;
+    } else
+#endif
+    if (info->accelOn)
+    {
+	struct radeon_exa_pixmap_priv *driver_priv =
+	    exaGetPixmapDriverPrivate(pix);
+
+	if (!driver_priv)
+	    return NULL;
+
+	if (!driver_priv->fb)
+	    driver_priv->fb = radeon_pixmap_create_fb(info->drmmode.fd, pix);
+
+	return driver_priv->fb;
+    }
+
+    return NULL;
+}
+
 #define CP_PACKET0(reg, n)						\
 	(RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
 #define CP_PACKET1(reg0, reg1)						\
diff --git a/src/radeon_bo_helper.h b/src/radeon_bo_helper.h
index f1aed551..77134250 100644
--- a/src/radeon_bo_helper.h
+++ b/src/radeon_bo_helper.h
@@ -28,9 +28,6 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth,
 		       int usage_hint, int bitsPerPixel, int *new_pitch,
 		       struct radeon_surface *new_surface, uint32_t *new_tiling);
 
-extern Bool
-radeon_get_pixmap_handle(PixmapPtr pixmap, uint32_t *handle);
-
 extern uint32_t
 radeon_get_pixmap_tiling_flags(PixmapPtr pPix);
 
diff --git a/src/radeon_exa.c b/src/radeon_exa.c
index 1e457a8b..d8dd7fdc 100644
--- a/src/radeon_exa.c
+++ b/src/radeon_exa.c
@@ -300,6 +300,7 @@ void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
 
 void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv)
 {
+    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pScreen));
     struct radeon_exa_pixmap_priv *driver_priv = driverPriv;
 
     if (!driverPriv)
@@ -307,6 +308,7 @@ void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv)
 
     if (driver_priv->bo)
 	radeon_bo_unref(driver_priv->bo);
+    drmmode_fb_reference(info->drmmode.fd, &driver_priv->fb, NULL);
     free(driverPriv);
 }
 
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index b3427c46..2b410eb3 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -772,6 +772,17 @@ radeon_prime_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
 }
 
 static void
+radeon_prime_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
+				  void *event_data)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = event_data;
+
+    drmmode_fb_reference(drmmode_crtc->drmmode->fd, &drmmode_crtc->fb,
+			 drmmode_crtc->flip_pending);
+    radeon_prime_scanout_flip_abort(crtc, event_data);
+}
+
+static void
 radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
 {
     ScreenPtr screen = ent->slave_dst->drawable.pScreen;
@@ -798,7 +809,8 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
     drm_queue_seq = radeon_drm_queue_alloc(crtc,
 					   RADEON_DRM_QUEUE_CLIENT_DEFAULT,
 					   RADEON_DRM_QUEUE_ID_DEFAULT,
-					   drmmode_crtc, NULL,
+					   drmmode_crtc,
+					   radeon_prime_scanout_flip_handler,
 					   radeon_prime_scanout_flip_abort);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -806,8 +818,17 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
 	return;
     }
 
+    drmmode_crtc->flip_pending =
+	radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
+    if (!drmmode_crtc->flip_pending) {
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		   "Failed to get FB for PRIME flip.\n");
+	radeon_drm_abort_entry(drm_queue_seq);
+	return;
+    }
+
     if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc,
-					  drmmode_crtc->scanout[scanout_id].fb_id,
+					  drmmode_crtc->flip_pending->handle,
 					  0, drm_queue_seq, 0) != 0) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n",
 		   __func__, strerror(errno));
@@ -817,7 +838,6 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
 
     drmmode_crtc->scanout_id = scanout_id;
     drmmode_crtc->scanout_update_pending = TRUE;
-    drmmode_crtc->flip_pending = TRUE;
 }
 
 static void
@@ -1053,10 +1073,14 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
 static void
 radeon_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
 {
-    drmmode_crtc_private_ptr drmmode_crtc = event_data;
+    radeon_prime_scanout_flip_abort(crtc, event_data);
+}
 
-    drmmode_crtc->scanout_update_pending = FALSE;
-    drmmode_clear_pending_flip(crtc);
+static void
+radeon_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
+			    void *event_data)
+{
+    radeon_prime_scanout_flip_handler(crtc, msc, usec, event_data);
 }
 
 static void
@@ -1080,7 +1104,8 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info,
     drm_queue_seq = radeon_drm_queue_alloc(xf86_crtc,
 					   RADEON_DRM_QUEUE_CLIENT_DEFAULT,
 					   RADEON_DRM_QUEUE_ID_DEFAULT,
-					   drmmode_crtc, NULL,
+					   drmmode_crtc,
+					   radeon_scanout_flip_handler,
 					   radeon_scanout_flip_abort);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -1088,8 +1113,17 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info,
 	return;
     }
 
+    drmmode_crtc->flip_pending =
+	radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
+    if (!drmmode_crtc->flip_pending) {
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		   "Failed to get FB for scanout flip.\n");
+	radeon_drm_abort_entry(drm_queue_seq);
+	return;
+    }
+
     if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc,
-					  drmmode_crtc->scanout[scanout_id].fb_id,
+					  drmmode_crtc->flip_pending->handle,
 					  0, drm_queue_seq, 0) != 0) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n",
 		   __func__, strerror(errno));
@@ -1099,7 +1133,6 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info,
 
     drmmode_crtc->scanout_id = scanout_id;
     drmmode_crtc->scanout_update_pending = TRUE;
-    drmmode_crtc->flip_pending = TRUE;
 }
 
 static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
@@ -1114,6 +1147,19 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
     (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
     pScreen->BlockHandler = RADEONBlockHandler_KMS;
 
+    if (!pScrn->vtSema) {
+	radeon_cs_flush_indirect(pScrn);
+
+	for (c = 0; c < xf86_config->num_crtc; c++) {
+	    drmmode_crtc_private_ptr drmmode_crtc =
+		xf86_config->crtc[c]->driver_private;
+
+	    drmmode_fb_reference(info->drmmode.fd, &drmmode_crtc->fb, NULL);
+	}
+
+	return;
+    }
+
     if (!radeon_is_gpu_screen(pScreen))
     {
 	for (c = 0; c < xf86_config->num_crtc; c++) {
diff --git a/src/radeon_present.c b/src/radeon_present.c
index 90632d0e..635d1086 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -373,7 +373,6 @@ radeon_present_unflip(ScreenPtr screen, uint64_t event_id)
     enum drmmode_flip_sync flip_sync =
 	(radeon_present_screen_info.capabilities & PresentCapabilityAsync) ?
 	FLIP_ASYNC : FLIP_VSYNC;
-    int old_fb_id;
     int i;
 
     radeon_cs_flush_indirect(scrn);
@@ -396,12 +395,6 @@ radeon_present_unflip(ScreenPtr screen, uint64_t event_id)
 	return;
 
 modeset:
-    /* info->drmmode.fb_id still points to the FB for the last flipped BO.
-     * Clear it, drmmode_set_mode_major will re-create it
-     */
-    old_fb_id = info->drmmode.fb_id;
-    info->drmmode.fb_id = 0;
-
     radeon_bo_wait(info->front_bo);
     for (i = 0; i < config->num_crtc; i++) {
 	xf86CrtcPtr crtc = config->crtc[i];
@@ -417,7 +410,6 @@ modeset:
 	    drmmode_crtc->need_modeset = TRUE;
     }
 
-    drmModeRmFB(info->drmmode.fd, old_fb_id);
     present_event_notify(event_id, 0, 0);
 
     info->drmmode.present_flipping = FALSE;
commit 944391b0052466b71bf9919b56139dc197a7e072
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Feb 8 18:14:30 2017 +0900

    Pass pixmap instead of handle to radeon_do_pageflip
    
    This brings us in line with amdgpu and prepares for the following
    change, no functional change intended.
    
    (Ported from amdgpu commit e463b849f3e9d7b69e64a65619a22e00e78d297b)
    
    v2:
    * Be more consistent with the amdgpu code, which should make porting
      the following change to amdgpu easier
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 0b823754..a101ac23 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -2950,36 +2950,27 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
 }
 
 Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
-			uint32_t new_front_handle, uint64_t id, void *data,
+			PixmapPtr new_front, uint64_t id, void *data,
 			int ref_crtc_hw_id, radeon_drm_handler_proc handler,
 			radeon_drm_abort_proc abort,
 			enum drmmode_flip_sync flip_sync,
 			uint32_t target_msc)
 {
 	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
-	RADEONInfoPtr info = RADEONPTR(scrn);
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	xf86CrtcPtr crtc = NULL;
 	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
-	unsigned int pitch;
 	int i;
-	uint32_t tiling_flags = 0;
 	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
 	drmmode_flipdata_ptr flipdata;
 	uintptr_t drm_queue_seq = 0;
+	uint32_t new_front_handle;
 
-	if (info->allowColorTiling) {
-		if (info->ChipFamily >= CHIP_FAMILY_R600)
-			tiling_flags |= RADEON_TILING_MICRO;
-		else
-			tiling_flags |= RADEON_TILING_MACRO;
-	}
-
-	pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->pixel_bytes, tiling_flags)) *
-		info->pixel_bytes;
-	if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
-		pitch = info->front_surface.level[0].pitch_bytes;
+	if (!radeon_get_pixmap_handle(new_front, &new_front_handle)) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "flip queue: failed to get new front handle\n");
+		return FALSE;
 	}
 
         flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
@@ -2993,8 +2984,9 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 	 * Create a new handle for the back buffer
 	 */
 	flipdata->old_fb_id = drmmode->fb_id;
-	if (drmModeAddFB(drmmode->fd, scrn->virtualX, scrn->virtualY,
-			 scrn->depth, scrn->bitsPerPixel, pitch,
+	if (drmModeAddFB(drmmode->fd, new_front->drawable.width,
+			 new_front->drawable.height, scrn->depth,
+			 scrn->bitsPerPixel, new_front->devKind,
 			 new_front_handle, &drmmode->fb_id))
 		goto error;
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index bd3f5f98..35d64179 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -168,7 +168,7 @@ extern int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
 extern void drmmode_clear_pending_flip(xf86CrtcPtr crtc);
 
 Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
-			uint32_t new_front_handle, uint64_t id, void *data,
+			PixmapPtr new_front, uint64_t id, void *data,
 			int ref_crtc_hw_id, radeon_drm_handler_proc handler,
 			radeon_drm_abort_proc abort,
 			enum drmmode_flip_sync flip_sync,
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index c108ceab..cc72bd52 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -652,7 +652,6 @@ radeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client,
     ScrnInfoPtr scrn = crtc->scrn;
     RADEONInfoPtr info = RADEONPTR(scrn);
     struct dri2_buffer_priv *back_priv;
-    struct radeon_bo *bo;
     DRI2FrameEventPtr flip_info;
     int ref_crtc_hw_id = drmmode_get_crtc_id(crtc);
 
@@ -673,9 +672,7 @@ radeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client,
 
     /* Page flip the full screen buffer */
     back_priv = back->driverPrivate;
-    bo = radeon_get_pixmap_bo(back_priv->pixmap);
-
-    if (radeon_do_pageflip(scrn, client, bo->handle,
+    if (radeon_do_pageflip(scrn, client, back_priv->pixmap,
 			   RADEON_DRM_QUEUE_ID_DEFAULT, flip_info,
 			   ref_crtc_hw_id,
 			   radeon_dri2_flip_event_handler,
diff --git a/src/radeon_present.c b/src/radeon_present.c
index af55e462..90632d0e 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -332,15 +332,11 @@ radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
     struct radeon_present_vblank_event *event;
     xf86CrtcPtr xf86_crtc = crtc->devPrivate;
     int crtc_id = xf86_crtc ? drmmode_get_crtc_id(xf86_crtc) : -1;
-    uint32_t handle;
     Bool ret;
 
     if (!radeon_present_check_flip(crtc, screen->root, pixmap, sync_flip))
 	return FALSE;
 
-    if (!radeon_get_pixmap_handle(pixmap, &handle))
-	return FALSE;
-
     event = calloc(1, sizeof(struct radeon_present_vblank_event));
     if (!event)
 	return FALSE;
@@ -349,7 +345,7 @@ radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
 
     radeon_cs_flush_indirect(scrn);
 
-    ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle,
+    ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, pixmap,
 			     event_id, event, crtc_id,
 			     radeon_present_flip_event,
 			     radeon_present_flip_abort,
@@ -377,7 +373,6 @@ radeon_present_unflip(ScreenPtr screen, uint64_t event_id)
     enum drmmode_flip_sync flip_sync =
 	(radeon_present_screen_info.capabilities & PresentCapabilityAsync) ?
 	FLIP_ASYNC : FLIP_VSYNC;
-    uint32_t handle;
     int old_fb_id;
     int i;
 
@@ -386,12 +381,6 @@ radeon_present_unflip(ScreenPtr screen, uint64_t event_id)
     if (!radeon_present_check_unflip(scrn))
 	goto modeset;
 
-    if (!radeon_get_pixmap_handle(pixmap, &handle)) {
-	ErrorF("%s: radeon_get_pixmap_handle failed, display might freeze\n",
-	       __func__);
-	goto modeset;
-    }
-
     event = calloc(1, sizeof(struct radeon_present_vblank_event));
     if (!event) {
 	ErrorF("%s: calloc failed, display might freeze\n", __func__);
@@ -401,7 +390,7 @@ radeon_present_unflip(ScreenPtr screen, uint64_t event_id)
     event->event_id = event_id;
     event->unflip = TRUE;
 
-    if (radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle,
+    if (radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, pixmap,
 			   event_id, event, -1, radeon_present_flip_event,
 			   radeon_present_flip_abort, flip_sync, 0))
 	return;
commit f32c45194ac6f82cbe42d255ed72f857018778e0
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Tue May 9 11:18:00 2017 +0900

    Apply gamma correction to HW cursor
    
    The display hardware CLUT we're currently using for gamma correction
    doesn't affect the HW cursor, so we have to apply it manually when
    uploading the HW cursor data.
    
    This currently only works in depth 24/32.
    
    (Ported from amdgpu commit 82fa615f38137add75f9cd4bb49c48dd88de916f)
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 84e7ef96..0b823754 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -812,6 +812,17 @@ drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
 	}
 }
 
+static void
+drmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
+			  uint16_t *blue, int size)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+	drmModeCrtcSetGamma(drmmode_crtc->drmmode->fd,
+			    drmmode_crtc->mode_crtc->crtc_id, size, red, green,
+			    blue);
+}
+
 static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		     Rotation rotation, int x, int y)
@@ -873,8 +884,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		if (drmmode_crtc->tear_free)
 			scanout_id = drmmode_crtc->scanout_id;
 
-		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
-				       crtc->gamma_blue, crtc->gamma_size);
+		drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, crtc->gamma_green,
+					  crtc->gamma_blue, crtc->gamma_size);
 
 		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
 
@@ -1043,6 +1054,31 @@ drmmode_cursor_src_offset(Rotation rotation, int width, int height,
 
 #endif
 
+static uint32_t
+drmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb)
+{
+	uint32_t alpha = argb >> 24;
+	uint32_t rgb[3];
+	int i;
+
+	if (!alpha)
+		return 0;
+
+	if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
+		return argb;
+
+	/* Un-premultiply alpha */
+	for (i = 0; i < 3; i++)
+		rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha;
+
+	/* Apply gamma correction and pre-multiply alpha */
+	rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff;
+	rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff;
+	rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff;
+
+	return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
+}
+
 static void
 drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
 {
@@ -1068,7 +1104,8 @@ drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
 								      dstx, dsty);
 
 				ptr[dsty * info->cursor_w + dstx] =
-					cpu_to_le32(image[srcoffset]);
+					cpu_to_le32(drmmode_cursor_gamma(crtc,
+									 image[srcoffset]));
 			}
 		}
 	} else
@@ -1078,7 +1115,7 @@ drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
 		int i;
 
 		for (i = 0; i < cursor_size; i++)
-			ptr[i] = cpu_to_le32(image[i]);
+			ptr[i] = cpu_to_le32(drmmode_cursor_gamma(crtc, image[i]));
 	}
 }
 
@@ -1209,11 +1246,24 @@ static void
 drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
                       uint16_t *blue, int size)
 {
-	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	ScrnInfoPtr scrn = crtc->scrn;
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+	RADEONInfoPtr info = RADEONPTR(scrn);
+	int i;
 
-	drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
-			    size, red, green, blue);
+	drmmode_crtc_gamma_do_set(crtc, red, green, blue, size);
+
+	/* Compute index of this CRTC into xf86_config->crtc */
+	for (i = 0; xf86_config->crtc[i] != crtc; i++) {}
+
+	if (info->hwcursor_disabled & (1 << i))
+		return;
+
+#ifdef HAVE_XF86_CURSOR_RESET_CURSOR
+	xf86CursorResetCursor(scrn->pScreen);
+#else
+	xf86_reload_cursors(scrn->pScreen);
+#endif
 }
 
 #ifdef RADEON_PIXMAP_SHARING


More information about the xorg-commit mailing list