Currently user-space can only request page-flip events for all CRTCs included in an atomic commit. This is cumbersome with multi-CRTC commits: when moving a plane from a different CRTC, or when disabling a plane, user-space has no way to opt-out of the page-flip events.
Additionally, page-flip events are invalid for already-disable planes, so user-space needs to add special cases [1]. Libraries cannot add planes to the commit without risking causing unexpected page-flip events for the compositor [2]. Figuring out what CRTCs get implicitly included in a commit is non-trivial [3]. Introduce a new PAGE_FLIP_EVENT CRTC property so that user-space can select explicitly which CRTCs will get page-flip events. The property is very similar to IN_FENCE_FD/OUT_FENCE_PTR: it always reads as zero, and 1 can be written to request an event. A user-space implementation is available at [4]. [1]: https://github.com/ValveSoftware/gamescope/blob/67fcb3aebae0ae1eb2d1cff60f29e6d9fe1d128f/src/Backends/DRMBackend.cpp#L2897 [2]: https://gitlab.freedesktop.org/emersion/libliftoff/-/merge_requests/85 [3]: https://lore.kernel.org/dri-devel/[email protected]/ [4]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5387 Signed-off-by: Simon Ser <[email protected]> Cc: Daniel Stone <[email protected]> Cc: Michel Dänzer <[email protected]> Cc: Pekka Paalanen <[email protected]> Cc: Christian König <[email protected]> Cc: Simona Vetter <[email protected]> --- drivers/gpu/drm/drm_atomic_uapi.c | 17 +++++++++++++++-- drivers/gpu/drm/drm_crtc.c | 7 +++++++ drivers/gpu/drm/drm_mode_config.c | 6 ++++++ include/drm/drm_crtc.h | 6 ++++++ include/drm/drm_mode_config.h | 4 ++++ 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 6441b55cc274..21f2b0df4f63 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -466,6 +466,14 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, return -EFAULT; set_out_fence_for_crtc(state->state, crtc, fence_ptr); + } else if (property == config->prop_page_flip_event) { + if (val != 1) { + drm_dbg_atomic(crtc->dev, + "[CRTC:%d:%s] PAGE_FLIP_EVENT can only be set to 1", + crtc->base.id, crtc->name); + return -EINVAL; + } + state->page_flip_event_requested = val; } else if (property == crtc->scaling_filter_property) { state->scaling_filter = val; } else if (property == crtc->sharpness_strength_property) { @@ -507,6 +515,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val = state->background_color; else if (property == config->prop_out_fence_ptr) *val = 0; + else if (property == config->prop_page_flip_event) + *val = 0; else if (property == crtc->scaling_filter_property) *val = state->scaling_filter; else if (property == crtc->sharpness_strength_property) @@ -1385,6 +1395,7 @@ static int prepare_signaling(struct drm_device *dev, struct drm_connector *conn; struct drm_connector_state *conn_state; int i, c = 0, ret; + bool page_flip_event_requested; if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) return 0; @@ -1392,9 +1403,11 @@ static int prepare_signaling(struct drm_device *dev, for_each_new_crtc_in_state(state, crtc, crtc_state, i) { s32 __user *fence_ptr; + page_flip_event_requested = arg->flags & DRM_MODE_PAGE_FLIP_EVENT || + crtc_state->page_flip_event_requested; fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc); - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) { + if (page_flip_event_requested || fence_ptr) { struct drm_pending_vblank_event *e; e = create_vblank_event(crtc, arg->user_data); @@ -1404,7 +1417,7 @@ static int prepare_signaling(struct drm_device *dev, crtc_state->event = e; } - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + if (page_flip_event_requested) { struct drm_pending_vblank_event *e = crtc_state->event; if (!file_priv) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 63ead8ba6756..5ad6681bd47c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -248,6 +248,11 @@ struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc) * The sharpness effect takes place post blending on the final composed output. * If the feature is disabled, the content remains same without any sharpening effect * and when this feature is applied, it enhances the clarity of the content. + * PAGE_FLIP_EVENT: + * Atomic property for requesting a page-flip event on this CRTC. + * + * The value of this property is an integer value which always reads as + * zero and can be written with 1 to request the event. */ __printf(6, 0) @@ -322,6 +327,8 @@ static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc * config->prop_out_fence_ptr, 0); drm_object_attach_property(&crtc->base, config->prop_vrr_enabled, 0); + drm_object_attach_property(&crtc->base, + config->prop_page_flip_event, 0); } return 0; diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index f432f485a914..688937d2e1ec 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -496,6 +496,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.prop_out_fence_ptr = prop; + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "PAGE_FLIP_EVENT", 0, 1); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_page_flip_event = prop; + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, "CRTC_ID", DRM_MODE_OBJECT_CRTC); if (!prop) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 152349f973e3..b0f9130d263a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -311,6 +311,12 @@ struct drm_crtc_state { */ bool vrr_enabled; + /** + * @page_flip_event_requested: indicates whether a page-flip event has + * been requested on this CRTC. + */ + bool page_flip_event_requested; + /** * @self_refresh_active: * diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index d8f5b7e9673e..13f39677c32f 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -670,6 +670,10 @@ struct drm_mode_config { * value of type s32, and then cast that pointer to u64. */ struct drm_property *prop_out_fence_ptr; + /** + * @page_flip_event_property: property to request page-flip events. + */ + struct drm_property *prop_page_flip_event; /** * @prop_crtc_id: Default atomic plane property to specify the * &drm_crtc. -- 2.54.0
