drm: Don't forget about modesetting + modesetting robustness

Makes it so that we don't forget about any required modesets we need to
undertake, and makes modesetting robust by trying again when compositing
(in case the error was not mode but plane related), and falling back to
the previous mode if that fails.

If we have no mode to fall back to then we abort, same if we fail our
mode fallback commit.

Co-authored-by: Simon Ser <contact@emersion.fr>
This commit is contained in:
Joshua Ashton 2021-12-20 18:53:57 +00:00 committed by Simon Ser
parent bbfbf0dd8d
commit 95eba7e549
3 changed files with 36 additions and 9 deletions

View file

@ -1226,6 +1226,15 @@ int drm_prepare( struct drm_t *drm, const struct Composite_t *pComposite, const
drm->fbids_in_req.clear();
if ( needs_modeset )
drm->needs_modeset = true;
}
return ret;
}
void drm_rollback( struct drm_t *drm )
{
drm->pending = drm->current;
for ( size_t i = 0; i < drm->crtcs.size(); i++ )
@ -1234,9 +1243,6 @@ int drm_prepare( struct drm_t *drm, const struct Composite_t *pComposite, const
}
}
return ret;
}
bool drm_poll_state( struct drm_t *drm )
{
bool out_of_date = drm->out_of_date.exchange(false);

View file

@ -142,6 +142,7 @@ bool init_drm(struct drm_t *drm, int width, int height, int refresh);
void finish_drm(struct drm_t *drm);
int drm_commit(struct drm_t *drm, struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline );
int drm_prepare( struct drm_t *drm, const struct Composite_t *pComposite, const struct VulkanPipeline_t *pPipeline );
void drm_rollback( struct drm_t *drm );
bool drm_poll_state(struct drm_t *drm);
uint32_t drm_fbid_from_dmabuf( struct drm_t *drm, struct wlr_buffer *buf, struct wlr_dmabuf_attributes *dma_buf );
void drm_lock_fbid( struct drm_t *drm, uint32_t fbid );

View file

@ -1643,10 +1643,30 @@ paint_all(Display *dpy, MouseCursor *cursor)
if ( ret != 0 )
{
xwm_log.errorf( "Failed to prepare 1-layer flip: %s", strerror( -ret ) );
if ( g_DRM.current.mode_id == 0 )
{
xwm_log.errorf("We failed our modeset and have no mode to fall back to! (Initial modeset failed?): %s", strerror(-ret));
abort();
}
xwm_log.errorf("Failed to prepare 1-layer flip (%s), trying again with previous mode if modeset needed", strerror( -ret ));
drm_rollback( &g_DRM );
// Try once again to in case we need to fall back to another mode.
ret = drm_prepare( &g_DRM, &composite, &pipeline );
// Happens when we're VT-switched away
if ( ret == -EACCES )
return;
if ( ret != 0 )
{
xwm_log.errorf("Failed to prepare 1-layer flip entirely: %s", strerror( -ret ));
// We should always handle a 1-layer flip
abort();
}
}
drm_commit( &g_DRM, &composite, &pipeline );
}