[PATCH xf86-video-ati 5/6] Make all active CRTCs scan out an all-black framebuffer in LeaveVT

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

 



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

And destroy all other FBs. This is so that other DRM masters can only
get access to this all-black FB, not to any other FB we created, while
we're switched away and not DRM master.

Fixes: 55e513b978b2 ("Use reference counting for tracking KMS
                      framebuffer lifetimes")
Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/drmmode_display.c |  4 +--
 src/drmmode_display.h |  4 +++
 src/radeon_kms.c      | 98 +++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 98 insertions(+), 8 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 791d59986..ba170ee64 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -536,7 +536,7 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
 	}
 }
 
-static void
+void
 drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc)
 {
 	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
@@ -558,7 +558,7 @@ drmmode_scanout_free(ScrnInfoPtr scrn)
 		drmmode_crtc_scanout_free(xf86_config->crtc[c]->driver_private);
 }
 
-static PixmapPtr
+PixmapPtr
 drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
 			    int width, int height)
 {
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 00b5e8119..ace059dcc 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -216,6 +216,10 @@ extern Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn);
 extern void drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
 					 struct drmmode_scanout *scanout);
 extern void drmmode_scanout_free(ScrnInfoPtr scrn);
+void drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc);
+PixmapPtr drmmode_crtc_scanout_create(xf86CrtcPtr crtc,
+				      struct drmmode_scanout *scanout,
+				      int width, int height);
 
 extern void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode);
 extern void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode);
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index ca2d36d04..5410c4208 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -32,6 +32,7 @@
 #include <sys/ioctl.h>
 /* Driver data structures */
 #include "radeon.h"
+#include "radeon_bo_helper.h"
 #include "radeon_drm_queue.h"
 #include "radeon_glamor.h"
 #include "radeon_reg.h"
@@ -1158,9 +1159,10 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
     (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
     pScreen->BlockHandler = RADEONBlockHandler_KMS;
 
-    if (!pScrn->vtSema) {
-	radeon_cs_flush_indirect(pScrn);
-
+    if (!xf86ScreenToScrn(radeon_master_screen(pScreen))->vtSema) {
+	/* Unreference the all-black FB created by RADEONLeaveVT_KMS. After
+	 * this, there should be no FB left created by this driver.
+	 */
 	for (c = 0; c < xf86_config->num_crtc; c++) {
 	    drmmode_crtc_private_ptr drmmode_crtc =
 		xf86_config->crtc[c]->driver_private;
@@ -2472,21 +2474,105 @@ Bool RADEONEnterVT_KMS(VT_FUNC_ARGS_DECL)
 }
 
 
+static void
+pixmap_unref_fb(void *value, XID id, void *cdata)
+{
+    PixmapPtr pixmap = value;
+    RADEONEntPtr pRADEONEnt = cdata;
+    struct drmmode_fb **fb_ptr = radeon_pixmap_get_fb_ptr(pixmap);
+
+    if (fb_ptr)
+	drmmode_fb_reference(pRADEONEnt->fd, fb_ptr, NULL);
+}
+
 void RADEONLeaveVT_KMS(VT_FUNC_ARGS_DECL)
 {
     SCRN_INFO_PTR(arg);
     RADEONInfoPtr  info  = RADEONPTR(pScrn);
+    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+    ScreenPtr pScreen = pScrn->pScreen;
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    struct drmmode_scanout black_scanout = { .pixmap = NULL, .bo = NULL };
+    xf86CrtcPtr crtc;
+    drmmode_crtc_private_ptr drmmode_crtc;
+    unsigned w = 0, h = 0;
+    int i;
 
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
 		   "RADEONLeaveVT_KMS\n");
 
-    radeon_drop_drm_master(pScrn);
+    /* Compute maximum scanout dimensions of active CRTCs */
+    for (i = 0; i < xf86_config->num_crtc; i++) {
+	crtc = xf86_config->crtc[i];
+	drmmode_crtc = crtc->driver_private;
+
+	if (!drmmode_crtc->fb)
+	    continue;
+
+	w = max(w, crtc->mode.HDisplay);
+	h = max(h, crtc->mode.VDisplay);
+    }
+
+    /* Make all active CRTCs scan out from an all-black framebuffer */
+    if (w > 0 && h > 0) {
+	if (drmmode_crtc_scanout_create(crtc, &black_scanout, w, h)) {
+	    struct drmmode_fb *black_fb =
+		radeon_pixmap_get_fb(black_scanout.pixmap);
+
+	    radeon_pixmap_clear(black_scanout.pixmap);
+	    radeon_cs_flush_indirect(pScrn);
+	    radeon_bo_wait(black_scanout.bo);
+
+	    for (i = 0; i < xf86_config->num_crtc; i++) {
+		crtc = xf86_config->crtc[i];
+		drmmode_crtc = crtc->driver_private;
+
+		if (drmmode_crtc->fb) {
+		    if (black_fb) {
+			drmmode_set_mode(crtc, black_fb, &crtc->mode, 0, 0);
+		    } else {
+			drmModeSetCrtc(pRADEONEnt->fd,
+				       drmmode_crtc->mode_crtc->crtc_id, 0, 0,
+				       0, NULL, 0, NULL);
+			drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb,
+					     NULL);
+		    }
+
+		    if (pScrn->is_gpu) {
+			if (drmmode_crtc->scanout[0].pixmap)
+			    pixmap_unref_fb(drmmode_crtc->scanout[0].pixmap,
+					    None, pRADEONEnt);
+			if (drmmode_crtc->scanout[1].pixmap)
+			    pixmap_unref_fb(drmmode_crtc->scanout[1].pixmap,
+					    None, pRADEONEnt);
+		    } else {
+			drmmode_crtc_scanout_free(drmmode_crtc);
+		    }
+		}
+	    }
+	}
+    }
 
     xf86RotateFreeShadow(pScrn);
-    if (!pScrn->is_gpu)
-	drmmode_scanout_free(pScrn);
+    drmmode_crtc_scanout_destroy(&info->drmmode, &black_scanout);
+
+    /* Unreference FBs of all pixmaps. After this, the only FB remaining
+     * should be the all-black one being scanned out by active CRTCs
+     */
+    for (i = 0; i < currentMaxClients; i++) {
+	if (i > 0 &&
+	    (!clients[i] || clients[i]->clientState != ClientStateRunning))
+            continue;
+
+	FindClientResourcesByType(clients[i], RT_PIXMAP, pixmap_unref_fb,
+				  pRADEONEnt);
+    }
+    pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen), None, pRADEONEnt);
 
     xf86_hide_cursors (pScrn);
+
+    radeon_drop_drm_master(pScrn);
+
     info->accel_state->XInited3D = FALSE;
     info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
 
-- 
2.14.1



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux