All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH xf86-video-ati 1/2] Pass pixmap instead of handle to radeon_do_pageflip
@ 2017-05-02  7:40 Michel Dänzer
       [not found] ` <20170502074034.17211-1-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Michel Dänzer @ 2017-05-02  7:40 UTC (permalink / raw)
  To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW

From: Michel Dänzer <michel.daenzer@amd.com>

This brings us in line with amdgpu and prepares for the following
change, no functional change intended.

Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
---
 src/drmmode_display.c |  8 ++++++--
 src/drmmode_display.h |  2 +-
 src/radeon_dri2.c     |  5 +----
 src/radeon_present.c  | 15 ++-------------
 4 files changed, 10 insertions(+), 20 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 84e7ef967..a92cf785f 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -2900,7 +2900,7 @@ 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 pixmap, 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,
@@ -2918,6 +2918,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 	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 handle;
 
 	if (info->allowColorTiling) {
 		if (info->ChipFamily >= CHIP_FAMILY_R600)
@@ -2939,13 +2940,16 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
              goto error;
         }
 
+	if (!radeon_get_pixmap_handle(pixmap, &handle))
+		goto error;
+
 	/*
 	 * 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,
-			 new_front_handle, &drmmode->fb_id))
+			 handle, &drmmode->fb_id))
 		goto error;
 
 	/*
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index bd3f5f987..efca331cb 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 pixmap, 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 c108ceab2..cc72bd52d 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 af55e462f..90632d0ec 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;
-- 
2.11.0

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS framebuffer lifetimes
       [not found] ` <20170502074034.17211-1-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
@ 2017-05-02  7:40   ` Michel Dänzer
       [not found]     ` <20170502074034.17211-2-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
  2017-05-10  9:05   ` [PATCH xf86-video-ati 1/2] Pass pixmap instead of handle to radeon_do_pageflip Michel Dänzer
  1 sibling, 1 reply; 6+ messages in thread
From: Michel Dänzer @ 2017-05-02  7:40 UTC (permalink / raw)
  To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW

From: Michel Dänzer <michel.daenzer@amd.com>

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).

Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
---
 src/drmmode_display.c  | 150 ++++++++++++++++++++-----------------------------
 src/drmmode_display.h  |  41 ++++++++++++--
 src/radeon.h           |  73 ++++++++++++++++++++++++
 src/radeon_bo_helper.h |   3 -
 src/radeon_exa.c       |   2 +
 src/radeon_kms.c       |  64 ++++++++++++++++++---
 src/radeon_present.c   |   8 ---
 7 files changed, 228 insertions(+), 113 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index a92cf785f..b9baeecae 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);
@@ -830,7 +827,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
@@ -878,15 +875,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) &&
@@ -896,22 +892,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 */
@@ -921,13 +919,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);
@@ -972,7 +972,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,
@@ -2107,13 +2109,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;
@@ -2213,8 +2211,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;
@@ -2296,8 +2292,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);
 
@@ -2311,7 +2305,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;
 }
@@ -2325,7 +2318,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 &&
@@ -2369,7 +2362,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? */
@@ -2389,12 +2382,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);
 }
 
@@ -2651,6 +2643,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;
 		}
@@ -2911,14 +2905,12 @@ 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;
-	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 handle;
+	struct drmmode_fb *fb;
 
 	if (info->allowColorTiling) {
 		if (info->ChipFamily >= CHIP_FAMILY_R600)
@@ -2927,12 +2919,6 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 			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;
-	}
-
         flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
         if (!flipdata) {
              xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -2940,17 +2926,11 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
              goto error;
         }
 
-	if (!radeon_get_pixmap_handle(pixmap, &handle))
-		goto error;
-
-	/*
-	 * 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,
-			 handle, &drmmode->fb_id))
+	fb = radeon_pixmap_get_fb(pixmap);
+	if (!fb) {
+		ErrorF("Failed to get FB for flip\n");
 		goto error;
+	}
 
 	/*
 	 * Queue flips on all enabled CRTCs
@@ -2994,7 +2974,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)
@@ -3002,13 +2982,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;
 	}
 
@@ -3020,12 +3000,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 efca331cb..7b592dbd0 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,33 @@ 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__);
+		}
+		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 2cb188e1f..febe580b6 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 f1aed5516..771342502 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 1e457a8bb..d8dd7fdce 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 b3427c462..2b410eb3d 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 90632d0ec..635d10861 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;
-- 
2.11.0

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* RE: [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS framebuffer lifetimes
       [not found]     ` <20170502074034.17211-2-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
@ 2017-05-02 14:08       ` Deucher, Alexander
  0 siblings, 0 replies; 6+ messages in thread
From: Deucher, Alexander @ 2017-05-02 14:08 UTC (permalink / raw)
  To: 'Michel Dänzer', amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW

> -----Original Message-----
> From: amd-gfx [mailto:amd-gfx-bounces@lists.freedesktop.org] On Behalf
> Of Michel Dänzer
> Sent: Tuesday, May 02, 2017 3:41 AM
> To: amd-gfx@lists.freedesktop.org
> Subject: [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS
> framebuffer lifetimes
> 
> From: Michel Dänzer <michel.daenzer@amd.com>
> 
> 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).
> 
> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>

Series is:
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>


> ---
>  src/drmmode_display.c  | 150 ++++++++++++++++++++------------------------
> -----
>  src/drmmode_display.h  |  41 ++++++++++++--
>  src/radeon.h           |  73 ++++++++++++++++++++++++
>  src/radeon_bo_helper.h |   3 -
>  src/radeon_exa.c       |   2 +
>  src/radeon_kms.c       |  64 ++++++++++++++++++---
>  src/radeon_present.c   |   8 ---
>  7 files changed, 228 insertions(+), 113 deletions(-)
> 
> diff --git a/src/drmmode_display.c b/src/drmmode_display.c
> index a92cf785f..b9baeecae 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);
> @@ -830,7 +827,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
> @@ -878,15 +875,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) &&
> @@ -896,22 +892,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 */
> @@ -921,13 +919,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);
> @@ -972,7 +972,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,
> @@ -2107,13 +2109,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;
> @@ -2213,8 +2211,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;
> @@ -2296,8 +2292,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);
> 
> @@ -2311,7 +2305,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;
>  }
> @@ -2325,7 +2318,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 &&
> @@ -2369,7 +2362,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? */
> @@ -2389,12 +2382,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);
>  }
> 
> @@ -2651,6 +2643,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;
>  		}
> @@ -2911,14 +2905,12 @@ 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;
> -	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 handle;
> +	struct drmmode_fb *fb;
> 
>  	if (info->allowColorTiling) {
>  		if (info->ChipFamily >= CHIP_FAMILY_R600)
> @@ -2927,12 +2919,6 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn,
> ClientPtr client,
>  			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;
> -	}
> -
>          flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
>          if (!flipdata) {
>               xf86DrvMsg(scrn->scrnIndex, X_WARNING,
> @@ -2940,17 +2926,11 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn,
> ClientPtr client,
>               goto error;
>          }
> 
> -	if (!radeon_get_pixmap_handle(pixmap, &handle))
> -		goto error;
> -
> -	/*
> -	 * 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,
> -			 handle, &drmmode->fb_id))
> +	fb = radeon_pixmap_get_fb(pixmap);
> +	if (!fb) {
> +		ErrorF("Failed to get FB for flip\n");
>  		goto error;
> +	}
> 
>  	/*
>  	 * Queue flips on all enabled CRTCs
> @@ -2994,7 +2974,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)
> @@ -3002,13 +2982,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;
>  	}
> 
> @@ -3020,12 +3000,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 efca331cb..7b592dbd0 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,33 @@ 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__);
> +		}
> +		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 2cb188e1f..febe580b6 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 f1aed5516..771342502 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 1e457a8bb..d8dd7fdce 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 b3427c462..2b410eb3d 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 90632d0ec..635d10861 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;
> --
> 2.11.0
> 
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH xf86-video-ati 1/2] Pass pixmap instead of handle to radeon_do_pageflip
       [not found] ` <20170502074034.17211-1-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
  2017-05-02  7:40   ` [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS framebuffer lifetimes Michel Dänzer
@ 2017-05-10  9:05   ` Michel Dänzer
       [not found]     ` <20170510090559.4649-1-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
  1 sibling, 1 reply; 6+ messages in thread
From: Michel Dänzer @ 2017-05-10  9:05 UTC (permalink / raw)
  To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW

From: Michel Dänzer <michel.daenzer@amd.com>

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@amd.com> # v1
Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
---
 src/drmmode_display.c | 26 +++++++++-----------------
 src/drmmode_display.h |  2 +-
 src/radeon_dri2.c     |  5 +----
 src/radeon_present.c  | 15 ++-------------
 4 files changed, 13 insertions(+), 35 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 0b823754b..a101ac233 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 bd3f5f987..35d64179d 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 c108ceab2..cc72bd52d 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 af55e462f..90632d0ec 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;
-- 
2.11.0

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS framebuffer lifetimes
       [not found]     ` <20170510090559.4649-1-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
@ 2017-05-10  9:05       ` Michel Dänzer
       [not found]         ` <20170510090559.4649-2-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Michel Dänzer @ 2017-05-10  9:05 UTC (permalink / raw)
  To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW

From: Michel Dänzer <michel.daenzer@amd.com>

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@amd.com> # v1
Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
---
 src/drmmode_display.c  | 147 +++++++++++++++++++++----------------------------
 src/drmmode_display.h  |  39 +++++++++++--
 src/radeon.h           |  73 ++++++++++++++++++++++++
 src/radeon_bo_helper.h |   3 -
 src/radeon_exa.c       |   2 +
 src/radeon_kms.c       |  64 ++++++++++++++++++---
 src/radeon_present.c   |   8 ---
 7 files changed, 226 insertions(+), 110 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index a101ac233..ec3072621 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 35d64179d..14d1cb034 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 2cb188e1f..febe580b6 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 f1aed5516..771342502 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 1e457a8bb..d8dd7fdce 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 b3427c462..2b410eb3d 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 90632d0ec..635d10861 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;
-- 
2.11.0

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* RE: [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS framebuffer lifetimes
       [not found]         ` <20170510090559.4649-2-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
@ 2017-05-10 16:06           ` Deucher, Alexander
  0 siblings, 0 replies; 6+ messages in thread
From: Deucher, Alexander @ 2017-05-10 16:06 UTC (permalink / raw)
  To: 'Michel Dänzer', amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW

> -----Original Message-----
> From: amd-gfx [mailto:amd-gfx-bounces@lists.freedesktop.org] On Behalf
> Of Michel Dänzer
> Sent: Wednesday, May 10, 2017 5:06 AM
> To: amd-gfx@lists.freedesktop.org
> Subject: [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS
> framebuffer lifetimes
> 
> From: Michel Dänzer <michel.daenzer@amd.com>
> 
> 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@amd.com> # v1
> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>

Series is:
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>

> ---
>  src/drmmode_display.c  | 147 +++++++++++++++++++++-----------------------
> -----
>  src/drmmode_display.h  |  39 +++++++++++--
>  src/radeon.h           |  73 ++++++++++++++++++++++++
>  src/radeon_bo_helper.h |   3 -
>  src/radeon_exa.c       |   2 +
>  src/radeon_kms.c       |  64 ++++++++++++++++++---
>  src/radeon_present.c   |   8 ---
>  7 files changed, 226 insertions(+), 110 deletions(-)
> 
> diff --git a/src/drmmode_display.c b/src/drmmode_display.c
> index a101ac233..ec3072621 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 35d64179d..14d1cb034 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 2cb188e1f..febe580b6 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 f1aed5516..771342502 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 1e457a8bb..d8dd7fdce 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 b3427c462..2b410eb3d 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 90632d0ec..635d10861 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;
> --
> 2.11.0
> 
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-05-10 16:06 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-02  7:40 [PATCH xf86-video-ati 1/2] Pass pixmap instead of handle to radeon_do_pageflip Michel Dänzer
     [not found] ` <20170502074034.17211-1-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
2017-05-02  7:40   ` [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS framebuffer lifetimes Michel Dänzer
     [not found]     ` <20170502074034.17211-2-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
2017-05-02 14:08       ` Deucher, Alexander
2017-05-10  9:05   ` [PATCH xf86-video-ati 1/2] Pass pixmap instead of handle to radeon_do_pageflip Michel Dänzer
     [not found]     ` <20170510090559.4649-1-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
2017-05-10  9:05       ` [PATCH xf86-video-ati 2/2] Use reference counting for tracking KMS framebuffer lifetimes Michel Dänzer
     [not found]         ` <20170510090559.4649-2-michel-otUistvHUpPR7s880joybQ@public.gmane.org>
2017-05-10 16:06           ` Deucher, Alexander

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.