From dcf8371a81124eca13d362d9854d47a93f3d7713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Jun 2025 22:37:08 +0200 Subject: [PATCH 1/6] present: Walk all children when setting window pixmaps 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: notbabaisyou --- present/present.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/present/present.c b/present/present.c index aa265aabf..6386a90a8 100644 --- a/present/present.c +++ b/present/present.c @@ -120,9 +120,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 9c0b9cf21d6a392a5a07b444a8a1a30a7c40c55e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Jun 2025 22:38:41 +0200 Subject: [PATCH 2/6] present: Don't ping-pong between sync and async flips 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: notbabaisyou --- present/present_vblank.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/present/present_vblank.c b/present/present_vblank.c index 72a8b2e3e..7b83bc630 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,14 @@ 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 8f912fa4aa7c016fddf44e4db7583407dd79e51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Jun 2025 22:40:23 +0200 Subject: [PATCH 3/6] modesetting: Don't try to use modifiers when allocating the root pixmap 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: notbabaisyou --- .../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 f28c3596b..29b02867e 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -1114,10 +1114,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) { @@ -1135,22 +1131,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 787286c946152743f8b6b76b953462251627a39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Jun 2025 22:41:10 +0200 Subject: [PATCH 4/6] modesetting: Enable universal planes client cap 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: notbabaisyou --- 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 29b02867e..2cb3098ad 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2400,6 +2400,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 c5a23ada0e8183de28806be131b9151290ea89d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Jun 2025 22:48:35 +0200 Subject: [PATCH 5/6] modesetting: Parse the IN_FORMATS_ASYNC blob The kernel has gained another format/modifier blob to indicate which formats/modifiers support async flips since Linux 6.16. Parse it. Signed-off-by: notbabaisyou --- .../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 2cb3098ad..360760cce 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -114,8 +114,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; @@ -135,7 +145,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; @@ -166,7 +176,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); @@ -186,7 +196,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; @@ -241,7 +251,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 @@ -2295,7 +2306,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; @@ -2341,9 +2352,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); @@ -2359,7 +2370,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[] = { @@ -2382,6 +2393,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", }, @@ -2456,6 +2468,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); @@ -2467,6 +2481,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 { @@ -2481,9 +2497,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 421d70016..56dea8754 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -294,7 +294,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 c2eae141302f946bf6bbb919fcaf137396c997d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Jun 2025 22:52:59 +0200 Subject: [PATCH 6/6] modesetting: Use IN_FORMATS_ASYNC for async flips 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: notbabaisyou --- hw/xfree86/drivers/modesetting/driver.c | 50 +++++++++++++++++++ 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, 82 insertions(+), 3 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 43783c4b1..dfbe5bb94 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -913,6 +913,51 @@ msSetWindowVRRMode(WindowPtr window, WindowVRRMode mode) 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; +} + static void FreeScreen(ScrnInfoPtr pScrn) { @@ -1711,6 +1756,11 @@ modsetCreateScreenResources(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 62b0db0cc..8b465e6e1 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, @@ -261,3 +266,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 360760cce..8ebdd4a1f 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -243,6 +243,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) { @@ -251,8 +252,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 56dea8754..80ac5c9d3 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -294,7 +294,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; @@ -321,6 +321,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 (ms->drmmode.sprites_visible > 0) goto no_flip; @@ -328,8 +329,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;