diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 11c273e2..08909c1b 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -110,23 +110,24 @@ error: } static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, - struct wlr_drm_connector *conn, drmModeModeInfo *mode) { + struct wlr_drm_connector *conn) { struct wlr_drm_crtc *crtc = conn->crtc; - if (mode != NULL) { + bool modeset = crtc->pending & WLR_DRM_CRTC_MODE; + if (modeset) { if (crtc->mode_id != 0) { drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); } - if (drmModeCreatePropertyBlob(drm->fd, mode, sizeof(*mode), - &crtc->mode_id)) { - wlr_log_errno(WLR_ERROR, "Unable to create property blob"); + if (drmModeCreatePropertyBlob(drm->fd, &crtc->mode, + sizeof(drmModeModeInfo), &crtc->mode_id)) { + wlr_log_errno(WLR_ERROR, "Unable to create mode property blob"); return false; } } uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT; - if (mode != NULL) { + if (modeset) { flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; } else { flags |= DRM_MODE_ATOMIC_NONBLOCK; @@ -135,7 +136,7 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, struct atomic atom; atomic_begin(crtc, &atom); atomic_add(&atom, conn->id, conn->props.crtc_id, crtc->id); - if (mode != NULL && conn->props.link_status != 0) { + if (modeset && conn->props.link_status != 0) { atomic_add(&atom, conn->id, conn->props.link_status, DRM_MODE_LINK_STATUS_GOOD); } @@ -151,12 +152,13 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, } } - if (!atomic_end(drm->fd, mode ? DRM_MODE_ATOMIC_ALLOW_MODESET : 0, &atom)) { + if (!atomic_end(drm->fd, modeset ? DRM_MODE_ATOMIC_ALLOW_MODESET : 0, + &atom)) { drmModeAtomicSetCursor(atom.req, 0); return false; } - if (!atomic_commit(drm->fd, &atom, conn, flags, mode)) { + if (!atomic_commit(drm->fd, &atom, conn, flags, modeset)) { return false; } diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 578b966f..c91843cc 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -334,11 +334,10 @@ static bool drm_connector_attach_render(struct wlr_output *output, return drm_surface_make_current(&conn->crtc->primary->surf, buffer_age); } -static bool drm_crtc_page_flip(struct wlr_drm_connector *conn, - struct wlr_drm_mode *mode) { - struct wlr_drm_backend *drm = get_drm_backend_from_backend(conn->output.backend); +static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) { + struct wlr_drm_backend *drm = + get_drm_backend_from_backend(conn->output.backend); struct wlr_drm_crtc *crtc = conn->crtc; - drmModeModeInfo *drm_mode = mode ? &mode->drm_mode : NULL; if (conn->pageflip_pending) { wlr_log(WLR_ERROR, "Failed to page-flip output '%s': " @@ -346,7 +345,11 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn, return false; } - if (!drm->iface->crtc_pageflip(drm, conn, drm_mode)) { + bool ok = drm->iface->crtc_pageflip(drm, conn); + + crtc->pending = 0; + + if (!ok) { return false; } @@ -454,7 +457,7 @@ static bool drm_connector_commit_buffer(struct wlr_output *output) { break; } - if (!drm_crtc_page_flip(conn, NULL)) { + if (!drm_crtc_page_flip(conn)) { drm_fb_clear(&plane->pending_fb); return false; } @@ -661,8 +664,7 @@ struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) { return &plane->current_fb; } -static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn, - struct wlr_drm_mode *mode) { +static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn) { struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { wlr_log(WLR_ERROR, "Page-flip failed on connector '%s': no CRTC", @@ -679,10 +681,12 @@ static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn, } } - return drm_crtc_page_flip(conn, mode); + return drm_crtc_page_flip(conn); } static void drm_connector_start_renderer(struct wlr_drm_connector *conn) { + struct wlr_drm_crtc *crtc = conn->crtc; + if (conn->state != WLR_DRM_CONN_CONNECTED) { return; } @@ -690,7 +694,10 @@ static void drm_connector_start_renderer(struct wlr_drm_connector *conn) { wlr_log(WLR_DEBUG, "Starting renderer on output '%s'", conn->output.name); struct wlr_drm_mode *mode = (struct wlr_drm_mode *)conn->output.current_mode; - if (!drm_connector_pageflip_renderer(conn, mode)) { + memcpy(&crtc->mode, &mode->drm_mode, sizeof(drmModeModeInfo)); + crtc->pending |= WLR_DRM_CRTC_MODE; + + if (!drm_connector_pageflip_renderer(conn)) { wl_event_source_timer_update(conn->retry_pageflip, 1000000.0f / conn->output.current_mode->refresh); } @@ -717,6 +724,9 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, } struct wlr_drm_plane *plane = crtc->primary; + crtc->pending |= WLR_DRM_CRTC_MODE; + memcpy(&crtc->mode, &mode->drm_mode, sizeof(drmModeModeInfo)); + int width = mode->wlr_mode.width; int height = mode->wlr_mode.height; uint32_t format = drm->renderer.gbm_format; @@ -730,7 +740,7 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, } if (!drm_plane_init_surface(plane, drm, width, height, format, 0, modifiers) || - !drm_connector_pageflip_renderer(conn, mode)) { + !drm_connector_pageflip_renderer(conn)) { if (!modifiers) { wlr_log(WLR_ERROR, "Failed to initialize renderer " "on connector '%s': initial page-flip failed", @@ -748,7 +758,7 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, 0, modifiers)) { return false; } - if (!drm_connector_pageflip_renderer(conn, mode)) { + if (!drm_connector_pageflip_renderer(conn)) { wlr_log(WLR_ERROR, "Failed to initialize renderer " "on connector '%s': initial page-flip failed", conn->output.name); diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index da9b636f..ba16493f 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -7,7 +7,7 @@ #include "backend/drm/util.h" static bool legacy_crtc_pageflip(struct wlr_drm_backend *drm, - struct wlr_drm_connector *conn, drmModeModeInfo *mode) { + struct wlr_drm_connector *conn) { struct wlr_drm_crtc *crtc = conn->crtc; struct wlr_drm_plane *cursor = crtc->cursor; @@ -22,9 +22,9 @@ static bool legacy_crtc_pageflip(struct wlr_drm_backend *drm, return false; } - if (mode) { + if (crtc->pending & WLR_DRM_CRTC_MODE) { if (drmModeSetCrtc(drm->fd, crtc->id, fb_id, 0, 0, - &conn->id, 1, mode)) { + &conn->id, 1, &crtc->mode)) { wlr_log_errno(WLR_ERROR, "%s: Failed to set CRTC", conn->output.name); return false; } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 11f6732a..e8fc452a 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -42,8 +42,15 @@ struct wlr_drm_plane { union wlr_drm_plane_props props; }; +enum wlr_drm_crtc_field { + WLR_DRM_CRTC_MODE = 1 << 0, +}; + struct wlr_drm_crtc { uint32_t id; + uint32_t pending; // bitfield of enum wlr_drm_crtc_field + + drmModeModeInfo mode; // Atomic modesetting only uint32_t mode_id; diff --git a/include/backend/drm/iface.h b/include/backend/drm/iface.h index acaf4730..6e074249 100644 --- a/include/backend/drm/iface.h +++ b/include/backend/drm/iface.h @@ -16,9 +16,9 @@ struct wlr_drm_interface { // Enable or disable DPMS for connector bool (*conn_enable)(struct wlr_drm_backend *drm, struct wlr_drm_connector *conn, bool enable); - // Pageflip on crtc. If mode is non-NULL perform a full modeset using it. + // Pageflip on crtc. bool (*crtc_pageflip)(struct wlr_drm_backend *drm, - struct wlr_drm_connector *conn, drmModeModeInfo *mode); + struct wlr_drm_connector *conn); // Enable the cursor buffer on crtc. Set bo to NULL to disable bool (*crtc_set_cursor)(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, struct gbm_bo *bo);