xf86-video-amdgpu: Branch 'master'

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Feb 14 19:21:14 UTC 2022


 man/amdgpu.man        |   15 +++++++++++++++
 src/amdgpu_drv.h      |    3 +++
 src/amdgpu_kms.c      |    8 ++++++++
 src/amdgpu_present.c  |    7 ++++++-
 src/drmmode_display.c |   12 +++++++++++-
 5 files changed, 43 insertions(+), 2 deletions(-)

New commits:
commit 65c127366a22c03d2ffcdcdf91eec28cac733e83
Author: Mario Kleiner <mario.kleiner.de at gmail.com>
Date:   Tue Jan 25 03:44:47 2022 +0100

    Add option for non-vsynced flips for "secondary" outputs.
    
    This is a straightforward port of a patch with the same name
    "modesetting: Add option for non-vsynced flips for "secondary"
    outputs." from X-Server master / X-Server 21.1. See server MR 742.
    The description below is therefore identical to that X-Server commit:
    
    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 and dual-display
    setups, and with single-X-Screen as well as dual-X-Screen "ZaphodHeads"
    configurations.
    
    Signed-off-by: Mario Kleiner <mario.kleiner.de at gmail.com>

diff --git a/man/amdgpu.man b/man/amdgpu.man
index 36193e0..65ac77c 100644
--- a/man/amdgpu.man
+++ b/man/amdgpu.man
@@ -90,6 +90,21 @@ when an suitable application is flipping via the Present extension.
 The default is
 .B off.
 .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 \*qAccelMethod\*q \*q" string \*q
 Setting this option to
 .B none
diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index e2e162e..200f0ba 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -165,6 +165,7 @@ typedef enum {
 	OPTION_TEAR_FREE,
 	OPTION_DELETE_DP12,
 	OPTION_VARIABLE_REFRESH,
+	OPTION_ASYNC_FLIP_SECONDARIES,
 } AMDGPUOpts;
 
 static inline ScreenPtr
@@ -306,6 +307,8 @@ typedef struct {
 	/* kms pageflipping */
 	WindowPtr flip_window;
 	Bool allowPageFlip;
+	Bool can_async_flip;
+	Bool async_flip_secondaries;
 
 	/* cursor size */
 	int cursor_w;
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 8997759..6d65c81 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -87,6 +87,7 @@ const OptionInfoRec AMDGPUOptions_KMS[] = {
 	{OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE},
 	{OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE},
 	{OPTION_VARIABLE_REFRESH, "VariableRefresh", OPTV_BOOLEAN, {0}, FALSE },
+	{OPTION_ASYNC_FLIP_SECONDARIES, "AsyncFlipSecondaries", OPTV_BOOLEAN, {0}, FALSE},
 	{-1, NULL, OPTV_NONE, {0}, FALSE}
 };
 
@@ -1637,6 +1638,13 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
 
 			xf86DrvMsg(pScrn->scrnIndex, from, "VariableRefresh: %sabled\n",
 				   info->vrr_support ? "en" : "dis");
+
+			info->async_flip_secondaries = FALSE;
+			from = xf86GetOptValBool(info->Options, OPTION_ASYNC_FLIP_SECONDARIES,
+						 &info->async_flip_secondaries) ? X_CONFIG : X_DEFAULT;
+
+			xf86DrvMsg(pScrn->scrnIndex, from, "AsyncFlipSecondaries: %sabled\n",
+				   info->async_flip_secondaries ? "en" : "dis");
 		}
 	}
 
diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index cc3d113..f768dd2 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -496,8 +496,13 @@ amdgpu_present_has_async_flip(ScreenPtr screen)
 Bool
 amdgpu_present_screen_init(ScreenPtr screen)
 {
-	if (amdgpu_present_has_async_flip(screen))
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+
+	if (amdgpu_present_has_async_flip(screen)) {
 		amdgpu_present_screen_info.capabilities |= PresentCapabilityAsync;
+		info->can_async_flip = TRUE;
+	}
 
 	if (!present_screen_init(screen, &amdgpu_present_screen_info)) {
 		xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_WARNING,
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index b6cdde7..5b73fce 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -3970,17 +3970,27 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 			uint32_t target_msc)
 {
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	xf86CrtcPtr crtc = NULL;
 	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
 	int crtc_id;
 	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
+	uint32_t sec_flip_flags = flip_flags;
 	drmmode_flipdata_ptr flipdata;
 	Bool handle_deferred = FALSE;
 	uintptr_t drm_queue_seq = 0;
 	struct drmmode_fb *fb;
 	int i = 0;
 
+	/*
+	 * Flip secondary non-ref_crtc crtc's async if possible and requested
+	 * by xorg.conf option "AsyncFlipSecondaries". Otherwise follow the lead
+	 * of flip_sync.
+	 */
+	if (info->can_async_flip && info->async_flip_secondaries)
+		sec_flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC;
+
 	flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs *
 			  sizeof(flipdata->fb[0]));
 	if (!flipdata) {
@@ -4081,7 +4091,7 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 			if (drmmode_page_flip_target_relative(pAMDGPUEnt,
 							      drmmode_crtc,
 							      flipdata->fb[crtc_id]->handle,
-							      flip_flags,
+							      sec_flip_flags,
 							      drm_queue_seq, 0) != 0)
 				goto flip_error;
 		}


More information about the xorg-commit mailing list