From c17d704a5baa0c902994f035d3da39d77d31fef3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 30 May 2014 21:21:00 +0100 Subject: [PATCH] sna: Enable kernel support for asynchronous flips If a flip fails, attempt to restore the previous working configuration (using a modeset) then disable further flipping. Signed-off-by: Chris Wilson --- src/sna/sna.h | 2 + src/sna/sna_display.c | 99 +++++++++++++++++++++++++++++++++++++------ src/sna/sna_dri2.c | 2 +- src/sna/sna_driver.c | 23 +--------- 4 files changed, 89 insertions(+), 37 deletions(-) diff --git a/src/sna/sna.h b/src/sna/sna.h index 7a1b6932..d40ccf42 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -243,6 +243,8 @@ struct sna { #define SNA_PERFORMANCE 0x100 #define SNA_POWERSAVE 0x200 #define SNA_REMOVE_OUTPUTS 0x400 +#define SNA_HAS_FLIP 0x10000 +#define SNA_HAS_ASYNC_FLIP 0x20000 #define SNA_REDISCOVER 0x40000000 #define SNA_REPROBE 0x80000000 diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 2a887176..6803409e 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -88,6 +88,8 @@ union compat_mode_get_connector{ #define DEFAULT_DPI 96 #endif +#define DRM_MODE_PAGE_FLIP_ASYNC 0x02 + #if 0 #define __DBG DBG #else @@ -4096,6 +4098,9 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo, int count = 0; int i; + if ((sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) == 0) + return 0; + /* * Queue flips on all enabled CRTCs * Note that if/when we get per-CRTC buffers, we'll have to update this. @@ -4118,32 +4123,42 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo, arg.crtc_id = crtc->id; arg.fb_id = get_fb(sna, bo, width, height); - if (arg.fb_id == 0) - goto disable; + if (arg.fb_id == 0) { + assert(count == 0); + return 0; + } /* Only the reference crtc will finally deliver its page flip * completion event. All other crtc's events will be discarded. */ - arg.user_data = (uintptr_t)data; - arg.user_data |= crtc->pipe == pipe; - arg.flags = DRM_MODE_PAGE_FLIP_EVENT; + if (data) { + arg.user_data = (uintptr_t)data; + arg.user_data |= crtc->pipe == pipe; + arg.flags = DRM_MODE_PAGE_FLIP_EVENT; + } else { + arg.user_data = 0; + arg.flags = DRM_MODE_PAGE_FLIP_ASYNC; + } arg.reserved = 0; DBG(("%s: crtc %d id=%d, pipe=%d, [ref? %d] --> fb %d\n", __FUNCTION__, i, crtc->id, crtc->pipe, crtc->pipe == pipe, arg.fb_id)); if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) { - DBG(("%s: flip [fb=%d] on crtc %d id=%d failed - %d\n", + DBG(("%s: flip [fb=%d] on crtc %d id=%d pipe=%d failed - %d\n", __FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno)); -disable: - if (count == 0) - return 0; - xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, - "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n", - __FUNCTION__, crtc->id, crtc->pipe); - sna_crtc_disable(config->crtc[i]); - continue; + "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n", + crtc->id, crtc->pipe, data ? "synchronous": "asynchronous"); + if (count && !xf86SetDesiredModes(sna->scrn)) { + xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, + "failed to restore display configuration\n"); + for (; i < sna->mode.num_real_crtc; i++) + sna_crtc_disable(config->crtc[i]); + } + + sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP); + return 0; } if (crtc->bo != bo) { @@ -4522,6 +4537,58 @@ sanitize_outputs(struct sna *sna) config->output[i]->crtc = NULL; } +static bool has_flip(struct sna *sna) +{ + drm_i915_getparam_t gp; + int v; + + if (sna->flags & SNA_NO_FLIP) + return false; + + v = 0; + + VG_CLEAR(gp); + gp.param = I915_PARAM_HAS_PAGEFLIPPING; + gp.value = &v; + + if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GETPARAM, &gp)) + return false; + + VG(VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v))); + return v > 0; +} + +static bool has_flip__async(struct sna *sna) +{ +#define LOCAL_IOCTL_GET_CAP DRM_IOWR(0x0c, struct local_get_cap) +#define DRM_CAP_ASYNC_PAGE_FLIP 0x7 + struct local_get_cap { + uint64_t name; + uint64_t value; + } cap = { DRM_CAP_ASYNC_PAGE_FLIP }; + + if (sna->flags & SNA_NO_FLIP) + return false; + + if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_GET_CAP, &cap) == 0) + return cap.value > 0; + + return false; +} + +static void +probe_capabilities(struct sna *sna) +{ + sna->flags &= ~(SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP); + if (has_flip(sna)) + sna->flags |= SNA_HAS_FLIP; + if (has_flip__async(sna)) + sna->flags |= SNA_HAS_ASYNC_FLIP; + DBG(("%s: page flips? %s, async? %s\n", __FUNCTION__, + sna->flags & SNA_HAS_FLIP ? "enabled" : "disabled", + sna->flags & SNA_HAS_ASYNC_FLIP ? "enabled" : "disabled")); +} + static void sna_crtc_config_notify(ScreenPtr screen) { @@ -4529,6 +4596,8 @@ sna_crtc_config_notify(ScreenPtr screen) DBG(("%s\n", __FUNCTION__)); + probe_capabilities(sna); + sna_dri2_reset_scanout(sna); sna_mode_update(sna); @@ -4552,6 +4621,8 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna) return true; } + probe_capabilities(sna); + if (!xf86GetOptValInteger(sna->Options, OPTION_VIRTUAL, &num_fake)) num_fake = 1; diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c index f6d2fea0..4bfa8e14 100644 --- a/src/sna/sna_dri2.c +++ b/src/sna/sna_dri2.c @@ -1330,7 +1330,7 @@ can_flip(struct sna * sna, return false; } - if (sna->flags & SNA_NO_FLIP) { + if ((sna->flags & (SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP)) == 0) { DBG(("%s: no, pageflips disabled\n", __FUNCTION__)); return false; } diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index f609254c..9d079cb8 100644 --- a/src/sna/sna_driver.c +++ b/src/sna/sna_driver.c @@ -294,27 +294,6 @@ static bool has_vsync(struct sna *sna) return true; } -static bool has_pageflipping(struct sna *sna) -{ - drm_i915_getparam_t gp; - int v; - - if (sna->flags & SNA_IS_HOSTED) - return false; - - v = 0; - - VG_CLEAR(gp); - gp.param = I915_PARAM_HAS_PAGEFLIPPING; - gp.value = &v; - - if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GETPARAM, &gp)) - return false; - - VG(VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v))); - return v > 0; -} - static void sna_setup_capabilities(ScrnInfoPtr scrn, int fd) { #if HAS_PIXMAP_SHARING && defined(DRM_CAP_PRIME) @@ -576,7 +555,7 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags) sna->flags |= SNA_NO_VSYNC; DBG(("%s: vsync? %s\n", __FUNCTION__, sna->flags & SNA_NO_VSYNC ? "disabled" : "enabled")); - if (!has_pageflipping(sna) || + if (sna->flags & SNA_IS_HOSTED || !xf86ReturnOptValBool(sna->Options, OPTION_PAGEFLIP, TRUE)) sna->flags |= SNA_NO_FLIP; DBG(("%s: page flips? %s\n", __FUNCTION__, sna->flags & SNA_NO_FLIP ? "disabled" : "enabled"));