summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/xfree86/drivers/modesetting/driver.c7
-rw-r--r--hw/xfree86/drivers/modesetting/driver.h1
-rw-r--r--hw/xfree86/drivers/modesetting/drmmode_display.h2
-rw-r--r--hw/xfree86/drivers/modesetting/modesetting.man15
-rw-r--r--hw/xfree86/drivers/modesetting/pageflip.c25
-rw-r--r--hw/xfree86/drivers/modesetting/present.c4
6 files changed, 49 insertions, 5 deletions
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);
}