summaryrefslogtreecommitdiff
path: root/hw/xfree86/drivers/modesetting
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner.de@gmail.com>2021-08-30 05:42:04 +0200
committerPovilas Kanapickas <povilas@radix.lt>2021-09-09 09:53:21 +0000
commit68f01c0f02ece4f6efe9ce18be81244246a1e114 (patch)
tree5ce0f8f1e8f5f499e349ae4a99eaf0381c0493bd /hw/xfree86/drivers/modesetting
parent1fd5dec11bbb85e87f70a39f1c1b59af95a7feaf (diff)
modesetting: Add option for non-vsynced flips for "secondary" outputs.
Whenever an unredirected fullscreen window uses pageflipping for a DRI3/Present PresentPixmap() operation and the X-Screen has more than one active output, multiple crtc's need to execute pageflips. Only after the last flip has completed can the PresentPixmap operation as a whole complete. If a sync_flip is requested for the present, then the current implementation will synchronize each pageflip to the vblank of its associated crtc. This provides tear-free image presentation across all outputs, but introduces a different artifact, if not all outputs run at the same refresh rate with perfect synchrony: The slowest output throttles the presentation rate, and present completion is delayed to flip completion of the "latest" output to complete. This means degraded performance, e.g., a dual-display setup with a 144 Hz monitor and a 60 Hz monitor will always be throttled to at most 60 fps. It also means non-constant present rate if refresh cycles drift against each other, creating complex "beat patterns", tremors, stutters and periodic slowdowns - quite irritating! Such a scenario will be especially annoying if one uses multiple outputs in "mirror mode" aka "clone mode". One output will usually be the "production output" with the highest quality and fastest display attached, whereas a secondary mirror output just has a cheaper display for monitoring attached. Users care about perfect and perfectly timed tear-free presentation on the "production output", but cares less about quality on the secondary "mirror output". They are willing to trade quality on secondary outputs away in exchange for better presentation timing on the "production output". One example use case for such production + monitoring displays are neuroscience / medical science applications where one high quality display device is used to present visual animations to test subjects or patients in a fMRI scanner room (production display), whereas an operator monitors the same visual animations from a control room on a lower quality display. Presentation timing needs to be perfect, and animations high-speed and tear-free for the production display, whereas quality and timing don't matter for the monitoring display. This commit gives users the option to choose such a trade-off as opt-in: It adds a new boolean option "AsyncFlipSecondaries" to the device section of xorg.conf. If this option is specified as true, then DRI3 pageflip behaviour changes as follows: 1. The "reference crtc" for a windows PresentPixmap operation does a vblank synced flip, or a DRM_MODE_PAGE_FLIP_ASYNC non-synchronized flip, as requested by the caller, just as in the past. Typically flips will be requested to be vblank synchronized for tear-free presentation. The "reference crtc" is the one chosen by the caller to drive presentation timing (as specified by PresentPixmap()'s "target_msc", "divisor", "remainder" parameters and implemented by vblank events) and to deliver Present completion timestamps (msc and ust) extracted from its pageflip completion event. 2. All other crtc's, which also page-flip in a multi-display configuration, will try to flip with DRM_MODE_PAGE_FLIP_ASYNC, ie. immediately and not synchronized to vblank. This allows the PresentPixmap operation to complete with little delay compared to a single-display present, especially if the different crtc's run at different video refresh rates or their refresh cycles are not perfectly synchronized, but drift against each other. The downside is potential tearing artifacts on all outputs apart from the one of the "reference crtc". Successfully tested on a AMD gpu with single-display, dual-display and triple-display setups, and with single-X-Screen as well as dual-X-Screen "ZaphodHeads" configurations. Please consider merging this commit for the upcoming server 1.21 branch. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Diffstat (limited to 'hw/xfree86/drivers/modesetting')
-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);
}