From: Michel Dänzer <[email protected]> At least with older kernels, the flip may never complete otherwise, which can result in us hanging in drmmode_set_mode_major.
Fixes: https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-ati/+bug/1577170 (Ported from radeon commits 9090309e057dc703d1a5bffd88e6cae14108cfc3, e520ce0ec0adf91ddce5c932d4b3f9477fd49304, a36fdaff40d5b4795a1400c348a80eee94892212 and 4bd2d01552f18153afa03a8947b22eebf3d67c6b) Signed-off-by: Michel Dänzer <[email protected]> --- src/amdgpu_kms.c | 6 ++--- src/amdgpu_present.c | 4 +-- src/amdgpu_video.c | 2 +- src/drmmode_display.c | 73 +++++++++++++++++++++++++++++++++++++++++---------- src/drmmode_display.h | 3 +++ 5 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c index d557313..1bce781 100644 --- a/src/amdgpu_kms.c +++ b/src/amdgpu_kms.c @@ -366,7 +366,7 @@ amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) BoxRec extents; if (!xf86_crtc->enabled || - drmmode_crtc->dpms_mode != DPMSModeOn || + drmmode_crtc->pending_dpms_mode != DPMSModeOn || !drmmode_crtc->scanout[scanout_id].pixmap) return FALSE; @@ -485,7 +485,7 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc) if (!xf86_crtc->enabled || drmmode_crtc->scanout_update_pending || !drmmode_crtc->scanout[0].pixmap || - drmmode_crtc->dpms_mode != DPMSModeOn) + drmmode_crtc->pending_dpms_mode != DPMSModeOn) return; pDamage = drmmode_crtc->scanout[0].damage; @@ -537,7 +537,7 @@ amdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data) drmmode_crtc_private_ptr drmmode_crtc = event_data; drmmode_crtc->scanout_update_pending = FALSE; - drmmode_crtc->flip_pending = FALSE; + drmmode_clear_pending_flip(crtc); } static void diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c index 192c410..e36778c 100644 --- a/src/amdgpu_present.c +++ b/src/amdgpu_present.c @@ -235,7 +235,7 @@ amdgpu_present_check_unflip(ScrnInfoPtr scrn) drmmode_crtc->scanout[0].bo) return FALSE; - if (drmmode_crtc->dpms_mode == DPMSModeOn) + if (drmmode_crtc->pending_dpms_mode == DPMSModeOn) num_crtcs_on++; } @@ -376,7 +376,7 @@ modeset: if (!crtc->enabled) continue; - if (drmmode_crtc->dpms_mode == DPMSModeOn) + if (drmmode_crtc->pending_dpms_mode == DPMSModeOn) crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y); else diff --git a/src/amdgpu_video.c b/src/amdgpu_video.c index 8f9a2b9..3f441e7 100644 --- a/src/amdgpu_video.c +++ b/src/amdgpu_video.c @@ -67,7 +67,7 @@ static int amdgpu_box_area(BoxPtr box) Bool amdgpu_crtc_is_enabled(xf86CrtcPtr crtc) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - return drmmode_crtc->dpms_mode == DPMSModeOn; + return drmmode_crtc->pending_dpms_mode == DPMSModeOn; } xf86CrtcPtr diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 3063fac..491599f 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -249,9 +249,15 @@ drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) CARD64 ust; int ret; + drmmode_crtc->pending_dpms_mode = mode; + if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { drmVBlank vbl; + /* Wait for any pending flip to finish */ + if (drmmode_crtc->flip_pending) + return; + /* * On->Off transition: record the last vblank time, * sequence number and frame period. @@ -309,10 +315,14 @@ drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); /* Disable unused CRTCs and enable/disable active CRTCs */ - if (!crtc->enabled || mode != DPMSModeOn) + if (!crtc->enabled || mode != DPMSModeOn) { + /* Wait for any pending flip to finish */ + if (drmmode_crtc->flip_pending) + return; + drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0, NULL, 0, NULL); - else if (drmmode_crtc->dpms_mode != DPMSModeOn) + } else if (drmmode_crtc->dpms_mode != DPMSModeOn) crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y); } @@ -1171,6 +1181,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]); drmmode_crtc->drmmode = drmmode; drmmode_crtc->dpms_mode = DPMSModeOff; + drmmode_crtc->pending_dpms_mode = DPMSModeOff; crtc->driver_private = drmmode_crtc; drmmode_crtc_hw_id(crtc); @@ -1298,9 +1309,16 @@ static void drmmode_output_dpms(xf86OutputPtr output, int mode) if (!koutput) return; - if (mode != DPMSModeOn && crtc) + if (mode != DPMSModeOn && crtc) { + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_do_crtc_dpms(crtc, mode); + /* Wait for any pending flip to finish */ + if (drmmode_crtc->flip_pending) + return; + } + drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, drmmode_output->dpms_enum_id, mode); @@ -2002,26 +2020,50 @@ static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { drmmode_xf86crtc_resize }; +void +drmmode_clear_pending_flip(xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + drmmode_crtc->flip_pending = FALSE; + + if (!crtc->enabled || + (drmmode_crtc->pending_dpms_mode != DPMSModeOn && + drmmode_crtc->dpms_mode != drmmode_crtc->pending_dpms_mode)) { + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + int o; + + for (o = 0; o < xf86_config->num_output; o++) { + xf86OutputPtr output = xf86_config->output[o]; + + if (output->crtc != crtc) + continue; + + drmmode_output_dpms(output, drmmode_crtc->pending_dpms_mode); + } + + drmmode_crtc_dpms(crtc, drmmode_crtc->pending_dpms_mode); + } +} + static void drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) { - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_flipdata_ptr flipdata = event_data; if (--flipdata->flip_count == 0) { - if (flipdata->fe_crtc) - crtc = flipdata->fe_crtc; - flipdata->abort(crtc, flipdata->event_data); + if (!flipdata->fe_crtc) + flipdata->fe_crtc = crtc; + flipdata->abort(flipdata->fe_crtc, flipdata->event_data); free(flipdata); } - drmmode_crtc->flip_pending = FALSE; + drmmode_clear_pending_flip(crtc); } static void drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) { - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); drmmode_flipdata_ptr flipdata = event_data; @@ -2033,11 +2075,14 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even } if (--flipdata->flip_count == 0) { - /* Deliver cached msc, ust from reference crtc to flip event handler */ + /* Deliver MSC & UST from reference/current CRTC to flip event + * handler + */ if (flipdata->fe_crtc) - crtc = flipdata->fe_crtc; - flipdata->handler(crtc, flipdata->fe_frame, flipdata->fe_usec, - flipdata->event_data); + flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, + flipdata->fe_usec, flipdata->event_data); + else + flipdata->handler(crtc, frame, usec, flipdata->event_data); /* Release framebuffer */ drmModeRmFB(pAMDGPUEnt->fd, flipdata->old_fb_id); @@ -2045,7 +2090,7 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even free(flipdata); } - drmmode_crtc->flip_pending = FALSE; + drmmode_clear_pending_flip(crtc); } #if HAVE_NOTIFY_FD diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 2e62a8c..14fbcfc 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -88,6 +88,8 @@ typedef struct { unsigned scanout_id; Bool scanout_update_pending; int dpms_mode; + /* For when a flip is pending when DPMS off requested */ + int pending_dpms_mode; CARD64 dpms_last_ust; uint32_t dpms_last_seq; int dpms_last_fps; @@ -147,6 +149,7 @@ extern void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode); extern int drmmode_get_crtc_id(xf86CrtcPtr crtc); extern int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe); +extern void drmmode_clear_pending_flip(xf86CrtcPtr crtc); Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, PixmapPtr new_front, uint64_t id, void *data, int ref_crtc_hw_id, amdgpu_drm_handler_proc handler, -- 2.9.3 _______________________________________________ amd-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/amd-gfx
