modesetting: unflip before any setcrtc() calls

Make sure we're not scanning out any fbs with fancy modifiers when
we try to light up new displays. This is already the case in cases
where the screen gets resized, but in cases where that doesn't happen
it might be possible for the modeset(s) to fail due to watermark/etc.
constraints imposed by the fancy modifiers. We can avoid that by
making sure everything gets unflipped before the modeset.

v2: make poll timeout infinite
    s/in_modeset/pending_modeset/
    deal with tearfree fallout (goto no_flip)

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
This commit is contained in:
Ville Syrjälä 2020-10-22 15:45:13 +03:00 committed by Matt Turner
parent 0c1a93d319
commit 899c87af1f
8 changed files with 69 additions and 0 deletions

View File

@ -206,6 +206,8 @@ void ms_drm_abort(ScrnInfoPtr scrn,
void *match_data); void *match_data);
void ms_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq); void ms_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq);
Bool ms_drm_queue_is_empty(void);
Bool xf86_crtc_on(xf86CrtcPtr crtc); Bool xf86_crtc_on(xf86CrtcPtr crtc);
xf86CrtcPtr ms_dri2_crtc_covering_drawable(DrawablePtr pDraw); xf86CrtcPtr ms_dri2_crtc_covering_drawable(DrawablePtr pDraw);
@ -255,6 +257,7 @@ Bool ms_do_tearfree_flip(ScreenPtr screen, xf86CrtcPtr crtc);
#endif #endif
int ms_flush_drm_events(ScreenPtr screen); int ms_flush_drm_events(ScreenPtr screen);
void ms_drain_drm_events(ScreenPtr screen);
Bool ms_window_has_variable_refresh(modesettingPtr ms, WindowPtr win); Bool ms_window_has_variable_refresh(modesettingPtr ms, WindowPtr win);
void ms_present_set_screen_vrr(ScrnInfoPtr scrn, Bool vrr_enabled); void ms_present_set_screen_vrr(ScrnInfoPtr scrn, Bool vrr_enabled);
Bool ms_tearfree_is_active_on_crtc(xf86CrtcPtr crtc); Bool ms_tearfree_is_active_on_crtc(xf86CrtcPtr crtc);

View File

@ -1662,6 +1662,26 @@ drmmode_create_tearfree_shadow(xf86CrtcPtr crtc)
return TRUE; return TRUE;
} }
static void drmmmode_prepare_modeset(ScrnInfoPtr scrn)
{
ScreenPtr pScreen = scrn->pScreen;
modesettingPtr ms = modesettingPTR(scrn);
if (ms->drmmode.pending_modeset)
return;
/*
* Force present to unflip everything before we might
* try lighting up new displays. This makes sure fancy
* modifiers can't cause the modeset to fail.
*/
ms->drmmode.pending_modeset = TRUE;
present_check_flips(pScreen->root);
ms->drmmode.pending_modeset = FALSE;
ms_drain_drm_events(pScreen);
}
static Bool static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, int x, int y) Rotation rotation, int x, int y)
@ -1677,6 +1697,9 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Bool can_test; Bool can_test;
int i; int i;
if (mode)
drmmmode_prepare_modeset(crtc->scrn);
saved_mode = crtc->mode; saved_mode = crtc->mode;
saved_x = crtc->x; saved_x = crtc->x;
saved_y = crtc->y; saved_y = crtc->y;
@ -3906,6 +3929,8 @@ drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw,
Bool success = TRUE; Bool success = TRUE;
int c; int c;
drmmmode_prepare_modeset(pScrn);
for (c = 0; c < config->num_crtc; c++) { for (c = 0; c < config->num_crtc; c++) {
xf86CrtcPtr crtc = config->crtc[c]; xf86CrtcPtr crtc = config->crtc[c];
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;

View File

@ -139,6 +139,8 @@ typedef struct {
uint32_t vrr_prop_id; uint32_t vrr_prop_id;
Bool use_ctm; Bool use_ctm;
Bool pending_modeset;
} drmmode_rec, *drmmode_ptr; } drmmode_rec, *drmmode_ptr;
typedef struct { typedef struct {

View File

@ -69,6 +69,13 @@ ms_flush_drm_events(ScreenPtr screen)
return ms_flush_drm_events_timeout(screen, 0); return ms_flush_drm_events_timeout(screen, 0);
} }
void
ms_drain_drm_events(ScreenPtr screen)
{
while (!ms_drm_queue_is_empty())
ms_flush_drm_events_timeout(screen, -1);
}
#ifdef GLAMOR_HAS_GBM #ifdef GLAMOR_HAS_GBM
/* /*

View File

@ -327,6 +327,9 @@ ms_present_check_flip(RRCrtcPtr crtc,
if (ms->drmmode.sprites_visible > 0) if (ms->drmmode.sprites_visible > 0)
goto no_flip; goto no_flip;
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))
goto no_flip; goto no_flip;

View File

@ -642,6 +642,12 @@ ms_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec,
FALSE, (uint32_t) (uintptr_t) user_ptr); FALSE, (uint32_t) (uintptr_t) user_ptr);
} }
Bool
ms_drm_queue_is_empty(void)
{
return xorg_list_is_empty(&ms_drm_queue);
}
Bool Bool
ms_vblank_screen_init(ScreenPtr screen) ms_vblank_screen_init(ScreenPtr screen)
{ {

View File

@ -157,6 +157,9 @@ present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc);
extern _X_EXPORT Bool extern _X_EXPORT Bool
present_screen_init(ScreenPtr screen, present_screen_info_ptr info); present_screen_init(ScreenPtr screen, present_screen_info_ptr info);
extern _X_EXPORT void
present_check_flips(WindowPtr window);
typedef void (*present_complete_notify_proc)(WindowPtr window, typedef void (*present_complete_notify_proc)(WindowPtr window,
CARD8 kind, CARD8 kind,
CARD8 mode, CARD8 mode,

View File

@ -191,6 +191,26 @@ present_screen_priv_init(ScreenPtr screen)
return screen_priv; return screen_priv;
} }
static int
check_flip_visit(WindowPtr window, void *data)
{
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
if (!screen_priv)
return WT_DONTWALKCHILDREN;
screen_priv->check_flip_window(window);
return WT_WALKCHILDREN;
}
void
present_check_flips(WindowPtr window)
{
TraverseTree(window, check_flip_visit, NULL);
}
/* /*
* Initialize a screen for use with present in default screen flip mode (scmd) * Initialize a screen for use with present in default screen flip mode (scmd)
*/ */