[PATCH xf86-video-amdgpu 1/2] Fix VT switching with ShadowFB

Michel Dänzer michel at daenzer.net
Thu Oct 19 16:03:28 UTC 2017


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

We were trying to call acceleration specific functions from LeaveVT.
Instead, memset the scanout buffer to all 0 in LeaveVT and allocate a
new one in EnterVT.

Bugzilla: https://bugs.freedesktop.org/102948
Fixes: c16ff42f927d ("Make all active CRTCs scan out an all-black
                      framebuffer in LeaveVT")
(Ported from radeon commit 34da04daec82077571558ac3fe1ec0c1203a01ad)

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/amdgpu_kms.c | 154 +++++++++++++++++++++++++++++++++----------------------
 1 file changed, 94 insertions(+), 60 deletions(-)

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 6fe43264c..e3d7d71cf 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -1941,6 +1941,33 @@ Bool AMDGPUEnterVT_KMS(ScrnInfoPtr pScrn)
 
 	amdgpu_set_drm_master(pScrn);
 
+	if (info->shadow_fb) {
+		int pitch;
+		struct amdgpu_buffer *front_buffer =
+			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
+					       pScrn->virtualY, pScrn->depth,
+					       AMDGPU_CREATE_PIXMAP_LINEAR,
+					       pScrn->bitsPerPixel,
+					       &pitch);
+
+		if (front_buffer) {
+			if (amdgpu_bo_map(pScrn, front_buffer) == 0) {
+				memset(front_buffer->cpu_ptr, 0, pitch * pScrn->virtualY);
+				amdgpu_bo_unref(&info->front_buffer);
+				info->front_buffer = front_buffer;
+			} else {
+				amdgpu_bo_unref(&front_buffer);
+				front_buffer = NULL;
+			}
+		}
+
+		if (!front_buffer) {
+			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+				   "Failed to allocate new scanout BO after VT switch, "
+				   "other DRM masters may see screen contents\n");
+		}
+	}
+
 	pScrn->vtSema = TRUE;
 
 	if (!drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE))
@@ -1963,84 +1990,91 @@ pixmap_unref_fb(void *value, XID id, void *cdata)
 void AMDGPULeaveVT_KMS(ScrnInfoPtr pScrn)
 {
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
-	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(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, AMDGPU_LOGLEVEL_DEBUG,
 		       "AMDGPULeaveVT_KMS\n");
 
-	/* 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);
-	}
+	if (!info->shadow_fb) {
+		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
+		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;
+
+		/* 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;
 
-	/* 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 =
-				amdgpu_pixmap_get_fb(black_scanout.pixmap);
+			w = max(w, crtc->mode.HDisplay);
+			h = max(h, crtc->mode.VDisplay);
+		}
 
-			amdgpu_pixmap_clear(black_scanout.pixmap);
-			amdgpu_glamor_finish(pScrn);
+		/* 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 =
+					amdgpu_pixmap_get_fb(black_scanout.pixmap);
 
-			for (i = 0; i < xf86_config->num_crtc; i++) {
-				crtc = xf86_config->crtc[i];
-				drmmode_crtc = crtc->driver_private;
+				amdgpu_pixmap_clear(black_scanout.pixmap);
+				amdgpu_glamor_finish(pScrn);
 
-				if (drmmode_crtc->fb) {
-					if (black_fb) {
-						drmmode_set_mode(crtc, black_fb, &crtc->mode, 0, 0);
-					} else {
-						drmModeSetCrtc(pAMDGPUEnt->fd,
-							       drmmode_crtc->mode_crtc->crtc_id, 0, 0,
-							       0, NULL, 0, NULL);
-						drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb,
-								     NULL);
-					}
+				for (i = 0; i < xf86_config->num_crtc; i++) {
+					crtc = xf86_config->crtc[i];
+					drmmode_crtc = crtc->driver_private;
 
-					if (pScrn->is_gpu) {
-						if (drmmode_crtc->scanout[0].pixmap)
-							pixmap_unref_fb(drmmode_crtc->scanout[0].pixmap,
-									None, pAMDGPUEnt);
-						if (drmmode_crtc->scanout[1].pixmap)
-							pixmap_unref_fb(drmmode_crtc->scanout[1].pixmap,
-									None, pAMDGPUEnt);
-					} else {
-						drmmode_crtc_scanout_free(drmmode_crtc);
+					if (drmmode_crtc->fb) {
+						if (black_fb) {
+							drmmode_set_mode(crtc, black_fb, &crtc->mode, 0, 0);
+						} else {
+							drmModeSetCrtc(pAMDGPUEnt->fd,
+								       drmmode_crtc->mode_crtc->crtc_id, 0,
+								       0, 0, NULL, 0, NULL);
+							drmmode_fb_reference(pAMDGPUEnt->fd,
+									     &drmmode_crtc->fb, NULL);
+						}
+
+						if (pScrn->is_gpu) {
+							if (drmmode_crtc->scanout[0].pixmap)
+								pixmap_unref_fb(drmmode_crtc->scanout[0].pixmap,
+										None, pAMDGPUEnt);
+							if (drmmode_crtc->scanout[1].pixmap)
+								pixmap_unref_fb(drmmode_crtc->scanout[1].pixmap,
+										None, pAMDGPUEnt);
+						} else {
+							drmmode_crtc_scanout_free(drmmode_crtc);
+						}
 					}
 				}
 			}
 		}
-	}
 
-	xf86RotateFreeShadow(pScrn);
-	drmmode_crtc_scanout_destroy(&info->drmmode, &black_scanout);
+		xf86RotateFreeShadow(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;
+		/* 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,
+						  pAMDGPUEnt);
+		}
 
-		FindClientResourcesByType(clients[i], RT_PIXMAP, pixmap_unref_fb,
-					  pAMDGPUEnt);
+		pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen), None, pAMDGPUEnt);
+	} else {
+		memset(info->front_buffer->cpu_ptr, 0, pScrn->virtualX *
+		       info->pixel_bytes * pScrn->virtualY);
 	}
-	pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen), None, pAMDGPUEnt);
 
 	TimerSet(NULL, 0, 1000, cleanup_black_fb, pScreen);
 
-- 
2.14.2



More information about the amd-gfx mailing list