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


Reply via email to