Fix VT switching with ShadowFB

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: c16ff42f92 ("Make all active CRTCs scan out an all-black
                      framebuffer in LeaveVT")
(Ported from radeon commit 34da04daec82077571558ac3fe1ec0c1203a01ad)
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Michel Dänzer
2017-10-19 16:20:03 +02:00
parent 2f72be038d
commit 55396cc45c

View File

@@ -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,85 +1990,92 @@ 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 (!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;
if (!drmmode_crtc->fb)
continue;
/* 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;
w = max(w, crtc->mode.HDisplay);
h = max(h, crtc->mode.VDisplay);
}
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);
/* 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);
}
pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen), None, pAMDGPUEnt);
} else {
memset(info->front_buffer->cpu_ptr, 0, pScrn->virtualX *
info->pixel_bytes * pScrn->virtualY);
}
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;
FindClientResourcesByType(clients[i], RT_PIXMAP, pixmap_unref_fb,
pAMDGPUEnt);
}
pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen), None, pAMDGPUEnt);
TimerSet(NULL, 0, 1000, cleanup_black_fb, pScreen);
xf86_hide_cursors(pScrn);