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;