From 95eba7e549dce9bc80b5e1b21835e552d51a0359 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Mon, 20 Dec 2021 18:53:57 +0000 Subject: [PATCH] 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 --- src/drm.cpp | 18 ++++++++++++------ src/drm.hpp | 1 + src/steamcompmgr.cpp | 26 +++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/drm.cpp b/src/drm.cpp index c4fde20..54e12eb 100644 --- a/src/drm.cpp +++ b/src/drm.cpp @@ -1226,17 +1226,23 @@ int drm_prepare( struct drm_t *drm, const struct Composite_t *pComposite, const drm->fbids_in_req.clear(); - drm->pending = drm->current; - - for ( size_t i = 0; i < drm->crtcs.size(); i++ ) - { - drm->crtcs[i].pending = drm->crtcs[i].current; - } + 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++ ) + { + drm->crtcs[i].pending = drm->crtcs[i].current; + } +} + bool drm_poll_state( struct drm_t *drm ) { bool out_of_date = drm->out_of_date.exchange(false); diff --git a/src/drm.hpp b/src/drm.hpp index 8462945..59eaa14 100644 --- a/src/drm.hpp +++ b/src/drm.hpp @@ -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 ); diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index f128501..28704df 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -1643,9 +1643,29 @@ paint_all(Display *dpy, MouseCursor *cursor) if ( ret != 0 ) { - xwm_log.errorf( "Failed to prepare 1-layer flip: %s", strerror( -ret ) ); - // We should always handle a 1-layer flip - abort(); + 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 );