From f9b1229edc7dd5340d42bb9a4a0cf719a406d97e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sun, 2 Mar 2025 23:41:10 +0200 Subject: [PATCH 1/6] present: Walk all children when setting window pixmaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently skip setting the window pixmap on any window not using its parent's pixmap. That does not work correctly in the presence of reparenting. Consider the following scenario: 1. window A is created as child of B 2. present starts flipping and sets the whole window tree to use pixmap X 3. window C is created (uses the screen pixmap by default) 4. window A is reparented to C 5. present stops flipping and attempts to set the whole window tree back to the screen pixmap, except the walk terminates at window C since it's using an unexpected pixmap, and window A is left with the stale pixmap X 6. pixmap X is destroyed 7. the X server segfaults on a rendering operation on window A due the stale pixmap I managed to hit this with mpv (doing present flips) and crack-attack (keeps alternating between a menu window and an actual game window): 1. start both applications 2. start a game in crack-attack 3. fullscreen mpv 4. end the game in crack attack 5. unfullscreen mpv 6. the crack-attack menu window has appeared, but might be corrupted and doing stuff on it segfaults the X server I suppose the other option might be to make new windows automatically inherit their parent's pixmap instead of using the screen pixmap. But I've not looked into how that would affect eg. composite. Signed-off-by: Ville Syrjälä --- present/present.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/present/present.c b/present/present.c index 336816e27..4c1870373 100644 --- a/present/present.c +++ b/present/present.c @@ -118,9 +118,14 @@ present_set_tree_pixmap_visit(WindowPtr window, void *data) struct pixmap_visit *visit = data; ScreenPtr screen = window->drawable.pScreen; - if ((*screen->GetWindowPixmap)(window) != visit->old) - return WT_DONTWALKCHILDREN; - (*screen->SetWindowPixmap)(window, visit->new); + if ((*screen->GetWindowPixmap)(window) == visit->old) + (*screen->SetWindowPixmap)(window, visit->new); + + /* + * Walk the entire tree in case windows using the + * the old pixmap have been reparented to newly + * created windows using the screen pixmap instead. + */ return WT_WALKCHILDREN; } From 68283a77c6f0d7f59e50fae2e90d4fa03027d864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 21 Feb 2025 21:08:07 +0200 Subject: [PATCH 2/6] present: Don't ping-pong between sync and async flips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many Intel GPUs can't switch between sync and async flips willy nilly. Sometimes that change itself will take one extra frame. This means that constant ping-pong between sync and async flips is only going to cause problems. Stay in async flip mode as long as the client is requesting it. The present protocol spec does say: "If 'options' contains PresentOptionAsync, and the 'target-msc' is less than or equal to the current msc for 'window', then the operation will be performed as soon as possible, not necessarily waiting for the next vertical blank interval." So there is an expectation that a future target-msc will still be respected even when PresentOptionAsync is specified. Staying in async flip mode won't actually change that given that present_scmd_pixmap() takes the flip mode into account when calculating exec_msc. So visually the flip should still happen on the correct target_msc regardles of whether we executed it as sync or async. Signed-off-by: Ville Syrjälä --- present/present_vblank.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/present/present_vblank.c b/present/present_vblank.c index 72a8b2e3e..13110f750 100644 --- a/present/present_vblank.c +++ b/present/present_vblank.c @@ -40,6 +40,20 @@ present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_ } } +static Bool +present_want_async_flip(uint32_t options, uint32_t capabilities) +{ + if (options & PresentOptionAsync && + capabilities & PresentCapabilityAsync) + return TRUE; + + if (options & PresentOptionAsyncMayTear && + capabilities & PresentCapabilityAsyncMayTear) + return TRUE; + + return FALSE; +} + /* The memory vblank points to must be 0-initialized before calling this function. * * If this function returns FALSE, present_vblank_destroy must be called to clean @@ -118,15 +132,13 @@ present_vblank_init(present_vblank_ptr vblank, if (pixmap != NULL && !(options & PresentOptionCopy) && screen_priv->check_flip) { - if (msc_is_after(target_msc, crtc_msc) && - screen_priv->check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason)) - { - vblank->flip = TRUE; - vblank->sync_flip = TRUE; - } else if ((capabilities & PresentAllAsyncCapabilities) && - screen_priv->check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason)) + Bool sync_flip = !present_want_async_flip(options, capabilities); + + if (screen_priv->check_flip (target_crtc, window, pixmap, + sync_flip, valid, x_off, y_off, &reason)) { vblank->flip = TRUE; + vblank->sync_flip = sync_flip; } } vblank->reason = reason; From 48727822ee5245d9bae35af28b4016016cbdfd61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 19 Feb 2025 23:25:54 +0200 Subject: [PATCH 3/6] modesetting: Don't try to use modifiers when allocating the root pixmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want the root pixmap to use conservative tiling modifiers in order to make sure modeset/etc can never fail due to hardware watermark restictions/etc. Currenlty this is all dead code anyway because we aren't actually parsing the IN_FORMATS blob (missing universal plane client cap). But we want to start parsing that, so let's first make sure we don't get any behavioural changes from doing so. Signed-off-by: Ville Syrjälä --- .../drivers/modesetting/drmmode_display.c | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index bd895fe96..e253711a2 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -1115,10 +1115,6 @@ drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, #ifdef GLAMOR_HAS_GBM if (drmmode->glamor) { -#ifdef GBM_BO_WITH_MODIFIERS - uint32_t num_modifiers; - uint64_t *modifiers = NULL; -#endif uint32_t format; switch (drmmode->scrn->depth) { @@ -1136,22 +1132,6 @@ drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, break; } -#ifdef GBM_BO_WITH_MODIFIERS - num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers, - FALSE, TRUE); - if (num_modifiers > 0 && - !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) { - bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height, - format, modifiers, - num_modifiers); - free(modifiers); - if (bo->gbm) { - bo->used_modifiers = TRUE; - return TRUE; - } - } -#endif - bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format, GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); bo->used_modifiers = FALSE; From a75ea2d71ba2686256fc65f0640162472e972a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 19 Feb 2025 23:28:16 +0200 Subject: [PATCH 4/6] modesetting: Enable universal planes client cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable the universal planes client cap so that we actually get access to the primary plane's IN_FORMATS blob. We will now start to parse the blob. Signed-off-by: Ville Syrjälä --- hw/xfree86/drivers/modesetting/drmmode_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index e253711a2..2157a3020 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2406,6 +2406,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) return; } + drmSetClientCap(drmmode->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); kplane_res = drmModeGetPlaneResources(drmmode->fd); if (!kplane_res) { xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR, From eb6b71a81cbd8a5307e1595bae43c3d978285fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 21 Feb 2025 22:01:53 +0200 Subject: [PATCH 5/6] modesetting: Parse the IN_FORMATS_ASYNC blob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kernel has gained another format/modifier blob to indicate which formats/modifiers support async flips. Parse it. Signed-off-by: Ville Syrjälä --- .../drivers/modesetting/drmmode_display.c | 47 ++++++++++++++----- .../drivers/modesetting/drmmode_display.h | 4 +- hw/xfree86/drivers/modesetting/present.c | 2 +- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 2157a3020..696873e8b 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -113,8 +113,18 @@ get_opaque_format(uint32_t format) } } +static drmmode_format_ptr get_format(drmmode_crtc_private_ptr drmmode_crtc, + Bool async_flip, int i) +{ + if (async_flip && drmmode_crtc->formats_async) + return &drmmode_crtc->formats_async[i]; + else + return &drmmode_crtc->formats[i]; +} + Bool -drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier) +drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, + uint64_t modifier, Bool async_flip) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); int c, i, j; @@ -134,7 +144,7 @@ drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier continue; for (i = 0; i < drmmode_crtc->num_formats; i++) { - drmmode_format_ptr iter = &drmmode_crtc->formats[i]; + drmmode_format_ptr iter = get_format(drmmode_crtc, async_flip, i); if (iter->format != format) continue; @@ -165,7 +175,7 @@ drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier #ifdef GBM_BO_WITH_MODIFIERS static uint32_t get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers, - Bool enabled_crtc_only, Bool exclude_multiplane) + Bool enabled_crtc_only, Bool exclude_multiplane, Bool async_flip) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); modesettingPtr ms = modesettingPTR(scrn); @@ -185,7 +195,7 @@ get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers, continue; for (i = 0; i < drmmode_crtc->num_formats; i++) { - drmmode_format_ptr iter = &drmmode_crtc->formats[i]; + drmmode_format_ptr iter = get_format(drmmode_crtc, async_flip, i); if (iter->format != format) continue; @@ -240,7 +250,8 @@ get_drawable_modifiers(DrawablePtr draw, uint32_t format, return TRUE; } - *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE); + *num_modifiers = get_modifiers_set(scrn, format, modifiers, + TRUE, FALSE, FALSE); return TRUE; } #endif @@ -2301,7 +2312,7 @@ is_plane_assigned(ScrnInfoPtr scrn, int plane_id) */ static Bool populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane, - uint32_t blob_id) + drmmode_format_rec *formats, uint32_t blob_id) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; @@ -2347,9 +2358,9 @@ populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane, modifiers[num_modifiers - 1] = mod->modifier; } - drmmode_crtc->formats[i].format = blob_formats[i]; - drmmode_crtc->formats[i].modifiers = modifiers; - drmmode_crtc->formats[i].num_modifiers = num_modifiers; + formats[i].format = blob_formats[i]; + formats[i].modifiers = modifiers; + formats[i].num_modifiers = num_modifiers; } drmModeFreePropertyBlob(blob); @@ -2365,7 +2376,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) drmModePlaneRes *kplane_res; drmModePlane *kplane, *best_kplane = NULL; drmModeObjectProperties *props; - uint32_t i, type, blob_id; + uint32_t i, type, blob_id, async_blob_id; int current_crtc, best_plane = 0; static drmmode_prop_enum_info_rec plane_type_enums[] = { @@ -2388,6 +2399,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", }, [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", }, [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", }, + [DRMMODE_PLANE_IN_FORMATS_ASYNC] = { .name = "IN_FORMATS_ASYNC", }, [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", }, [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", }, [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", }, @@ -2462,6 +2474,8 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) best_kplane = kplane; blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS], props, 0); + async_blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS_ASYNC], + props, 0); drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props, DRMMODE_PLANE__COUNT, 1); drmModeFreeObjectProperties(props); @@ -2473,6 +2487,8 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) best_kplane = kplane; blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS], props, 0); + async_blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS_ASYNC], + props, 0); drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props, DRMMODE_PLANE__COUNT, 1); } else { @@ -2487,9 +2503,18 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) drmmode_crtc->num_formats = best_kplane->count_formats; drmmode_crtc->formats = calloc(best_kplane->count_formats, sizeof(drmmode_format_rec)); - if (!populate_format_modifiers(crtc, best_kplane, blob_id)) { + if (!populate_format_modifiers(crtc, best_kplane, + drmmode_crtc->formats, blob_id)) { for (i = 0; i < best_kplane->count_formats; i++) drmmode_crtc->formats[i].format = best_kplane->formats[i]; + } else { + drmmode_crtc->formats_async = calloc(best_kplane->count_formats, + sizeof(drmmode_format_rec)); + if (!populate_format_modifiers(crtc, best_kplane, + drmmode_crtc->formats_async, async_blob_id)) { + free(drmmode_crtc->formats_async); + drmmode_crtc->formats_async = NULL; + } } drmModeFreePlane(best_kplane); } diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index a82ae2609..df36b8ff6 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -42,6 +42,7 @@ enum drmmode_plane_property { DRMMODE_PLANE_TYPE = 0, DRMMODE_PLANE_FB_ID, DRMMODE_PLANE_IN_FORMATS, + DRMMODE_PLANE_IN_FORMATS_ASYNC, DRMMODE_PLANE_CRTC_ID, DRMMODE_PLANE_SRC_X, DRMMODE_PLANE_SRC_Y, @@ -198,6 +199,7 @@ typedef struct { drmmode_mode_ptr current_mode; uint32_t num_formats; drmmode_format_rec *formats; + drmmode_format_rec *formats_async; drmmode_bo rotate_bo; unsigned rotate_fb_id; @@ -293,7 +295,7 @@ typedef struct _msSpritePriv { extern miPointerSpriteFuncRec drmmode_sprite_funcs; Bool drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, - uint64_t modifier); + uint64_t modifier, Bool async_flip); int drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo, uint32_t *fb_id); int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo); diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index 85e101976..a72a6c0fd 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -296,7 +296,7 @@ ms_present_check_unflip(RRCrtcPtr crtc, modifier = gbm_bo_get_modifier(gbm); gbm_bo_destroy(gbm); - if (!drmmode_is_format_supported(scrn, format, modifier)) { + if (!drmmode_is_format_supported(scrn, format, modifier, FALSE)) { if (reason) *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT; return FALSE; From de139cb687cea3521e550cfea214e5e404ca8320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 19 Feb 2025 20:11:14 +0200 Subject: [PATCH 6/6] modesetting: Use IN_FORMATS_ASYNC for async flips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the IN_FORMATS_ASYNC blob (as opposed to the normal IN_FORMATS blob) to determine which formats/modifiers are supported. This will allow the client to allocate buffers which can actually be async flipped. In order to guarantee that the most optimal modifier is always used we also need to force a modifier renegotiation when swicthing between sync and async flips. Otherwise eg. sync flips might end up using a less optimal sync+async modifier instead of a more optimal sync-only modifier. Signed-off-by: Ville Syrjälä --- hw/xfree86/drivers/modesetting/driver.c | 49 +++++++++++++++++++ hw/xfree86/drivers/modesetting/driver.h | 9 ++++ .../drivers/modesetting/drmmode_display.c | 6 ++- .../drivers/modesetting/drmmode_display.h | 1 + hw/xfree86/drivers/modesetting/present.c | 19 ++++++- 5 files changed, 81 insertions(+), 3 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 9b839243e..d89588cfb 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -927,6 +927,50 @@ ms_vrr_property_update(WindowPtr window, Bool variable_refresh) ms_present_set_screen_vrr(scrn, variable_refresh); } +Bool +ms_window_has_async_flip(WindowPtr win) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(win->drawable.pScreen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_async_flip_priv *priv = dixLookupPrivate(&win->devPrivates, + &ms->drmmode.asyncFlipPrivateKeyRec); + + return priv->async_flip; +} + +void +ms_window_update_async_flip(WindowPtr win, Bool async_flip) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(win->drawable.pScreen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_async_flip_priv *priv = dixLookupPrivate(&win->devPrivates, + &ms->drmmode.asyncFlipPrivateKeyRec); + + priv->async_flip = async_flip; +} + +Bool +ms_window_has_async_flip_modifiers(WindowPtr win) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(win->drawable.pScreen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_async_flip_priv *priv = dixLookupPrivate(&win->devPrivates, + &ms->drmmode.asyncFlipPrivateKeyRec); + + return priv->async_flip_modifiers; +} + +void +ms_window_update_async_flip_modifiers(WindowPtr win, Bool async_flip) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(win->drawable.pScreen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_async_flip_priv *priv = dixLookupPrivate(&win->devPrivates, + &ms->drmmode.asyncFlipPrivateKeyRec); + + priv->async_flip_modifiers = async_flip; +} + /* Wrapper for xserver/dix/property.c:ProcChangeProperty */ static int ms_change_property(ClientPtr client) @@ -1832,6 +1876,11 @@ CreateScreenResources(ScreenPtr pScreen) sizeof(struct ms_vrr_priv))) return FALSE; + if (!dixRegisterPrivateKey(&ms->drmmode.asyncFlipPrivateKeyRec, + PRIVATE_WINDOW, + sizeof(struct ms_async_flip_priv))) + return FALSE; + return ret; } diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 74630cac4..e291bfa90 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -49,6 +49,11 @@ struct ms_vrr_priv { Bool variable_refresh; }; +struct ms_async_flip_priv { + Bool async_flip; + Bool async_flip_modifiers; +}; + typedef enum { OPTION_SW_CURSOR, OPTION_DEVICE_PATH, @@ -262,3 +267,7 @@ void ms_drain_drm_events(ScreenPtr screen); Bool ms_window_has_variable_refresh(modesettingPtr ms, WindowPtr win); void ms_present_set_screen_vrr(ScrnInfoPtr scrn, Bool vrr_enabled); Bool ms_tearfree_is_active_on_crtc(xf86CrtcPtr crtc); +Bool ms_window_has_async_flip(WindowPtr win); +void ms_window_update_async_flip(WindowPtr win, Bool async_flip); +Bool ms_window_has_async_flip_modifiers(WindowPtr win); +void ms_window_update_async_flip_modifiers(WindowPtr win, Bool async_flip); diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 696873e8b..a3cd326b2 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -242,6 +242,7 @@ get_drawable_modifiers(DrawablePtr draw, uint32_t format, { ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); modesettingPtr ms = modesettingPTR(scrn); + Bool async_flip; if (!present_can_window_flip((WindowPtr) draw) || !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) { @@ -250,8 +251,11 @@ get_drawable_modifiers(DrawablePtr draw, uint32_t format, return TRUE; } + async_flip = ms_window_has_async_flip((WindowPtr)draw); + ms_window_update_async_flip_modifiers((WindowPtr)draw, async_flip); + *num_modifiers = get_modifiers_set(scrn, format, modifiers, - TRUE, FALSE, FALSE); + TRUE, FALSE, async_flip); return TRUE; } #endif diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index df36b8ff6..5e7ba9df1 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -119,6 +119,7 @@ typedef struct { DevPrivateKeyRec pixmapPrivateKeyRec; DevScreenPrivateKeyRec spritePrivateKeyRec; DevPrivateKeyRec vrrPrivateKeyRec; + DevPrivateKeyRec asyncFlipPrivateKeyRec; /* Number of SW cursors currently visible on this screen */ int sprites_visible; diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index a72a6c0fd..e6815e80e 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -296,7 +296,7 @@ ms_present_check_unflip(RRCrtcPtr crtc, modifier = gbm_bo_get_modifier(gbm); gbm_bo_destroy(gbm); - if (!drmmode_is_format_supported(scrn, format, modifier, FALSE)) { + if (!drmmode_is_format_supported(scrn, format, modifier, !sync_flip)) { if (reason) *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT; return FALSE; @@ -323,6 +323,7 @@ ms_present_check_flip(RRCrtcPtr crtc, ScreenPtr screen = window->drawable.pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); modesettingPtr ms = modesettingPTR(scrn); + Bool async_flip = !sync_flip; if (reason) *reason = PRESENT_FLIP_REASON_UNKNOWN; @@ -333,8 +334,22 @@ ms_present_check_flip(RRCrtcPtr crtc, if (ms->drmmode.pending_modeset) goto no_flip; - if(!ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason)) + if (!ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason)) { + if (reason && *reason == PRESENT_FLIP_REASON_BUFFER_FORMAT) + ms_window_update_async_flip(window, async_flip); goto no_flip; + } + + ms_window_update_async_flip(window, async_flip); + + /* + * Force a format renegotiation when switching between sync and async, + * otherwise we may end up with a working but suboptimal modifier. + */ + if (reason && async_flip != ms_window_has_async_flip_modifiers(window)) { + *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT; + goto no_flip; + } ms->flip_window = window;