diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 264c6fe33..6ddd6c810 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -919,6 +919,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) @@ -1827,6 +1871,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 d103acbe9..b2d3f24b4 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -240,6 +240,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) { @@ -248,8 +249,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;