diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index fde65e0e5..535f49d1d 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -144,6 +144,7 @@ static const OptionInfoRec Options[] = { {OPTION_ATOMIC, "Atomic", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_VARIABLE_REFRESH, "VariableRefresh", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_USE_GAMMA_LUT, "UseGammaLUT", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_ASYNC_FLIP_SECONDARIES, "AsyncFlipSecondaries", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; @@ -1200,6 +1201,12 @@ PreInit(ScrnInfoPtr pScrn, int flags) &ms->vrr_support) ? X_CONFIG : X_DEFAULT; xf86DrvMsg(pScrn->scrnIndex, from, "VariableRefresh: %sabled\n", ms->vrr_support ? "en" : "dis"); + + ms->drmmode.async_flip_secondaries = FALSE; + from = xf86GetOptValBool(ms->drmmode.Options, OPTION_ASYNC_FLIP_SECONDARIES, + &ms->drmmode.async_flip_secondaries) ? X_CONFIG : X_DEFAULT; + xf86DrvMsg(pScrn->scrnIndex, from, "AsyncFlipSecondaries: %sabled\n", + ms->drmmode.async_flip_secondaries ? "en" : "dis"); } } diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 6217a0e64..71aa8730e 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -60,6 +60,7 @@ typedef enum { OPTION_ATOMIC, OPTION_VARIABLE_REFRESH, OPTION_USE_GAMMA_LUT, + OPTION_ASYNC_FLIP_SECONDARIES, } modesettingOpts; typedef struct diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index dbb413c12..29f9b8f7d 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -131,6 +131,8 @@ typedef struct { Bool present_flipping; Bool flip_bo_import_failed; + Bool can_async_flip; + Bool async_flip_secondaries; Bool dri2_enable; Bool present_enable; diff --git a/hw/xfree86/drivers/modesetting/modesetting.man b/hw/xfree86/drivers/modesetting/modesetting.man index bc294da7c..0145344d2 100644 --- a/hw/xfree86/drivers/modesetting/modesetting.man +++ b/hw/xfree86/drivers/modesetting/modesetting.man @@ -71,6 +71,21 @@ One of \*qglamor\*q or \*qnone\*q. Default: glamor. Enable DRI3 page flipping. The default is .B on. .TP +.BI "Option \*qAsyncFlipSecondaries\*q \*q" boolean \*q +Use async flips for secondary video outputs on multi-display setups. If a screen +has multiple displays attached and DRI3 page flipping is used, then only one of +the displays will have its page flip synchronized to vblank for tear-free +presentation. This is the display that is used for presentation timing and +timestamping, usually the one covering the biggest pixel area of the screen. +All other displays ("Secondaries") will not synchronize their flips. This may +cause some tearing on these displays, but it prevents a permanent or periodic +slowdown or irritating judder of animations if not all video outputs are running +synchronized with each other and with the same refresh rate. There is no perfect +solution apart from perfectly synchronized outputs, but this option may give +preferrable results if the displays in a multi-display setup mirror or clone +each other. The default is +.B off. +.TP .BI "Option \*qZaphodHeads\*q \*q" string \*q Specify the RandR output(s) to use with zaphod mode for a particular driver instance. If you use this option you must use this option for all instances diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c index d943a4dd4..23ee95f9a 100644 --- a/hw/xfree86/drivers/modesetting/pageflip.c +++ b/hw/xfree86/drivers/modesetting/pageflip.c @@ -368,10 +368,6 @@ ms_do_pageflip(ScreenPtr screen, ms->drmmode.flip_bo_import_failed = FALSE; } - flags = DRM_MODE_PAGE_FLIP_EVENT; - if (async) - flags |= DRM_MODE_PAGE_FLIP_ASYNC; - /* Queue flips on all enabled CRTCs. * * Note that if/when we get per-CRTC buffers, we'll have to update this. @@ -384,10 +380,31 @@ ms_do_pageflip(ScreenPtr screen, for (i = 0; i < config->num_crtc; i++) { enum queue_flip_status flip_status; xf86CrtcPtr crtc = config->crtc[i]; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; if (!xf86_crtc_on(crtc)) continue; + flags = DRM_MODE_PAGE_FLIP_EVENT; + if (ms->drmmode.can_async_flip && async) + flags |= DRM_MODE_PAGE_FLIP_ASYNC; + + /* + * If this is not the reference crtc used for flip timing and flip event + * delivery and timestamping, ie. not the one whose presentation timing + * we do really care about, and async flips are possible, and requested + * by an xorg.conf option, then we flip this "secondary" crtc without + * sync to vblank. This may cause tearing on such "secondary" outputs, + * but it will prevent throttling of multi-display flips to the refresh + * cycle of any of the secondary crtcs, avoiding periodic slowdowns and + * judder caused by unsynchronized outputs. This is especially useful for + * outputs in a "clone-mode" or "mirror-mode" configuration. + */ + if (ms->drmmode.can_async_flip && ms->drmmode.async_flip_secondaries && + (drmmode_crtc->vblank_pipe != ref_crtc_vblank_pipe) && + (ref_crtc_vblank_pipe >= 0)) + flags |= DRM_MODE_PAGE_FLIP_ASYNC; + flip_status = queue_flip_on_crtc(screen, crtc, flipdata, ref_crtc_vblank_pipe, flags); diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index b90a1b8ac..c3266d871 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -464,8 +464,10 @@ ms_present_screen_init(ScreenPtr screen) int ret; ret = drmGetCap(ms->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); - if (ret == 0 && value == 1) + if (ret == 0 && value == 1) { ms_present_screen_info.capabilities |= PresentCapabilityAsync; + ms->drmmode.can_async_flip = TRUE; + } return present_screen_init(screen, &ms_present_screen_info); }