mbox series

[v3,0/6] Add support for atomic async page-flips

Message ID 20220929184307.258331-1-contact@emersion.fr (mailing list archive)
Headers show
Series Add support for atomic async page-flips | expand

Message

Simon Ser Sept. 29, 2022, 6:43 p.m. UTC
This series adds support for DRM_MODE_PAGE_FLIP_ASYNC for atomic
commits, aka. "immediate flip" (which might result in tearing).
The feature was only available via the legacy uAPI, however for
gaming use-cases it may be desirable to enable it via the atomic
uAPI too.

- Patchwork: https://patchwork.freedesktop.org/series/107683/
- User-space patch: https://github.com/Plagman/gamescope/pull/595
- IGT patch: https://patchwork.freedesktop.org/series/107681/

Main changes in v2: add docs, fail atomic commit if async flip isn't
possible.

Changes in v3: add a note in the documentation about Intel hardware,
add R-b tags.

Tested on an AMD Picasso iGPU (Simon) and an AMD Vangogh GPU (André).

Simon Ser (6):
  drm: document DRM_MODE_PAGE_FLIP_ASYNC
  amd/display: only accept async flips for fast updates
  drm: introduce drm_mode_config.atomic_async_page_flip_not_supported
  drm: allow DRM_MODE_PAGE_FLIP_ASYNC for atomic commits
  drm: introduce DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP
  amd/display: indicate support for atomic async page-flips on DC

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  8 ++++++
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    | 10 +++++++
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c  |  1 +
 drivers/gpu/drm/drm_atomic_uapi.c             | 28 +++++++++++++++++--
 drivers/gpu/drm/drm_ioctl.c                   |  5 ++++
 drivers/gpu/drm/i915/display/intel_display.c  |  1 +
 drivers/gpu/drm/nouveau/nouveau_display.c     |  1 +
 drivers/gpu/drm/vc4/vc4_kms.c                 |  1 +
 include/drm/drm_mode_config.h                 | 11 ++++++++
 include/uapi/drm/drm.h                        | 10 ++++++-
 include/uapi/drm/drm_mode.h                   | 16 +++++++++++
 11 files changed, 88 insertions(+), 4 deletions(-)

Comments

Harry Wentland Sept. 30, 2022, 1:42 p.m. UTC | #1
On 9/29/22 14:43, Simon Ser wrote:
> This series adds support for DRM_MODE_PAGE_FLIP_ASYNC for atomic
> commits, aka. "immediate flip" (which might result in tearing).
> The feature was only available via the legacy uAPI, however for
> gaming use-cases it may be desirable to enable it via the atomic
> uAPI too.
> 
> - Patchwork: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.freedesktop.org%2Fseries%2F107683%2F&data=05%7C01%7CHarry.Wentland%40amd.com%7Cac97e739abd04e7d3f9c08daa24a7de9%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C638000738084626501%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=J3DbO0agtOXfEt0XNA%2FKvmSLmJrFPW048T214BSl4dA%3D&reserved=0
> - User-space patch: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FPlagman%2Fgamescope%2Fpull%2F595&data=05%7C01%7CHarry.Wentland%40amd.com%7Cac97e739abd04e7d3f9c08daa24a7de9%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C638000738084626501%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=6vJftf%2Bl5h4vR3ANZKWw9AhghZpPhAcHdXR5EI8Xwrs%3D&reserved=0
> - IGT patch: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.freedesktop.org%2Fseries%2F107681%2F&data=05%7C01%7CHarry.Wentland%40amd.com%7Cac97e739abd04e7d3f9c08daa24a7de9%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C638000738084626501%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=hOJssKhjj39wIHkrd%2FEI8csLvpZDoENbakqqkN%2F22O8%3D&reserved=0
> 
> Main changes in v2: add docs, fail atomic commit if async flip isn't
> possible.
> 
> Changes in v3: add a note in the documentation about Intel hardware,
> add R-b tags.
> 
> Tested on an AMD Picasso iGPU (Simon) and an AMD Vangogh GPU (André).
> 
> Simon Ser (6):
>   drm: document DRM_MODE_PAGE_FLIP_ASYNC
>   amd/display: only accept async flips for fast updates
>   drm: introduce drm_mode_config.atomic_async_page_flip_not_supported
>   drm: allow DRM_MODE_PAGE_FLIP_ASYNC for atomic commits
>   drm: introduce DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP
>   amd/display: indicate support for atomic async page-flips on DC
> 

Finally had a chance to go through this. Series looks good
and is
Reviewed-by: Harry Wentland <harry.wentland@amd.com>

Harry

>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  8 ++++++
>  .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    | 10 +++++++
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c  |  1 +
>  drivers/gpu/drm/drm_atomic_uapi.c             | 28 +++++++++++++++++--
>  drivers/gpu/drm/drm_ioctl.c                   |  5 ++++
>  drivers/gpu/drm/i915/display/intel_display.c  |  1 +
>  drivers/gpu/drm/nouveau/nouveau_display.c     |  1 +
>  drivers/gpu/drm/vc4/vc4_kms.c                 |  1 +
>  include/drm/drm_mode_config.h                 | 11 ++++++++
>  include/uapi/drm/drm.h                        | 10 ++++++-
>  include/uapi/drm/drm_mode.h                   | 16 +++++++++++
>  11 files changed, 88 insertions(+), 4 deletions(-)
>
Ville Syrjälä Sept. 30, 2022, 1:52 p.m. UTC | #2
On Thu, Sep 29, 2022 at 06:43:15PM +0000, Simon Ser wrote:
> This series adds support for DRM_MODE_PAGE_FLIP_ASYNC for atomic
> commits, aka. "immediate flip" (which might result in tearing).
> The feature was only available via the legacy uAPI, however for
> gaming use-cases it may be desirable to enable it via the atomic
> uAPI too.
> 
> - Patchwork: https://patchwork.freedesktop.org/series/107683/
> - User-space patch: https://github.com/Plagman/gamescope/pull/595
> - IGT patch: https://patchwork.freedesktop.org/series/107681/

So no tests that actually verify that the kernel properly rejects
stuff stuff like modesets, gamma LUT updates, plane movement,
etc.?

> 
> Main changes in v2: add docs, fail atomic commit if async flip isn't
> possible.
> 
> Changes in v3: add a note in the documentation about Intel hardware,
> add R-b tags.
> 
> Tested on an AMD Picasso iGPU (Simon) and an AMD Vangogh GPU (André).
> 
> Simon Ser (6):
>   drm: document DRM_MODE_PAGE_FLIP_ASYNC
>   amd/display: only accept async flips for fast updates
>   drm: introduce drm_mode_config.atomic_async_page_flip_not_supported
>   drm: allow DRM_MODE_PAGE_FLIP_ASYNC for atomic commits
>   drm: introduce DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP
>   amd/display: indicate support for atomic async page-flips on DC
> 
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  8 ++++++
>  .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    | 10 +++++++
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c  |  1 +
>  drivers/gpu/drm/drm_atomic_uapi.c             | 28 +++++++++++++++++--
>  drivers/gpu/drm/drm_ioctl.c                   |  5 ++++
>  drivers/gpu/drm/i915/display/intel_display.c  |  1 +
>  drivers/gpu/drm/nouveau/nouveau_display.c     |  1 +
>  drivers/gpu/drm/vc4/vc4_kms.c                 |  1 +
>  include/drm/drm_mode_config.h                 | 11 ++++++++
>  include/uapi/drm/drm.h                        | 10 ++++++-
>  include/uapi/drm/drm_mode.h                   | 16 +++++++++++
>  11 files changed, 88 insertions(+), 4 deletions(-)
> 
> -- 
> 2.37.3
>
Ville Syrjälä Sept. 30, 2022, 2:19 p.m. UTC | #3
On Fri, Sep 30, 2022 at 04:52:56PM +0300, Ville Syrjälä wrote:
> On Thu, Sep 29, 2022 at 06:43:15PM +0000, Simon Ser wrote:
> > This series adds support for DRM_MODE_PAGE_FLIP_ASYNC for atomic
> > commits, aka. "immediate flip" (which might result in tearing).
> > The feature was only available via the legacy uAPI, however for
> > gaming use-cases it may be desirable to enable it via the atomic
> > uAPI too.
> > 
> > - Patchwork: https://patchwork.freedesktop.org/series/107683/
> > - User-space patch: https://github.com/Plagman/gamescope/pull/595
> > - IGT patch: https://patchwork.freedesktop.org/series/107681/
> 
> So no tests that actually verify that the kernel properly rejects
> stuff stuff like modesets, gamma LUT updates, plane movement,
> etc.?

Pondering this a bit more, it just occurred to me the current driver
level checks might easily lead to confusing behaviour. Eg. is
the ioctl going to succeed if you ask for an async change of some
random property while the crtc disabled, but fails if you ask for
the same async property change when the crtc is active?

So another reason why rejecting most properties already at
the uapi level might be a good idea.
Ville Syrjälä Sept. 30, 2022, 3:09 p.m. UTC | #4
On Fri, Sep 30, 2022 at 05:19:07PM +0300, Ville Syrjälä wrote:
> On Fri, Sep 30, 2022 at 04:52:56PM +0300, Ville Syrjälä wrote:
> > On Thu, Sep 29, 2022 at 06:43:15PM +0000, Simon Ser wrote:
> > > This series adds support for DRM_MODE_PAGE_FLIP_ASYNC for atomic
> > > commits, aka. "immediate flip" (which might result in tearing).
> > > The feature was only available via the legacy uAPI, however for
> > > gaming use-cases it may be desirable to enable it via the atomic
> > > uAPI too.
> > > 
> > > - Patchwork: https://patchwork.freedesktop.org/series/107683/
> > > - User-space patch: https://github.com/Plagman/gamescope/pull/595
> > > - IGT patch: https://patchwork.freedesktop.org/series/107681/
> > 
> > So no tests that actually verify that the kernel properly rejects
> > stuff stuff like modesets, gamma LUT updates, plane movement,
> > etc.?
> 
> Pondering this a bit more, it just occurred to me the current driver
> level checks might easily lead to confusing behaviour. Eg. is
> the ioctl going to succeed if you ask for an async change of some
> random property while the crtc disabled, but fails if you ask for
> the same async property change when the crtc is active?
> 
> So another reason why rejecting most properties already at
> the uapi level might be a good idea.

And just to be clear this is pretty much what I suggest:

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 79730fa1dd8e..471a2c703847 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -1392,6 +1392,13 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
 				goto out;
 			}
 
+			if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC &&
+			    prop != dev->mode_config.prop_fb_id) {
+				drm_mode_object_put(obj);
+				ret = -EINVAL;
+				goto out;
+			}
+
 			if (copy_from_user(&prop_value,
 					   prop_values_ptr + copied_props,
 					   sizeof(prop_value))) {


That would actively discourage people from even attempting the
"just dump all the state into the ioctl" approach with async flips
since even the props whose value isn't even changing would be rejected.
Pekka Paalanen Sept. 30, 2022, 3:37 p.m. UTC | #5
On Fri, 30 Sep 2022 18:09:55 +0300
Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:

> That would actively discourage people from even attempting the
> "just dump all the state into the ioctl" approach with async flips
> since even the props whose value isn't even changing would be rejected.

About that.

To me it looks like just a classic case of broken communication.

The kernel developers assume that of course userspace will minimize the
state set to only those properties that change, because...?

Userspace developers think that of course the kernel will optimize the
state set into minimal changes, because the kernel actually has the
authoritative knowledge of what the current state is, and the driver
actually knows which properties are costly and need to be optimized and
which ones don't matter. It has never even occurred to me that the
kernel would not compare next state to current state.

No-one ever documented any expectations, did they?


Thanks,
pq
Ville Syrjälä Sept. 30, 2022, 3:45 p.m. UTC | #6
On Fri, Sep 30, 2022 at 06:37:00PM +0300, Pekka Paalanen wrote:
> On Fri, 30 Sep 2022 18:09:55 +0300
> Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> 
> > That would actively discourage people from even attempting the
> > "just dump all the state into the ioctl" approach with async flips
> > since even the props whose value isn't even changing would be rejected.
> 
> About that.
> 
> To me it looks like just a classic case of broken communication.
> 
> The kernel developers assume that of course userspace will minimize the
> state set to only those properties that change, because...?
> 
> Userspace developers think that of course the kernel will optimize the
> state set into minimal changes, because the kernel actually has the
> authoritative knowledge of what the current state is, and the driver
> actually knows which properties are costly and need to be optimized and
> which ones don't matter. It has never even occurred to me that the
> kernel would not compare next state to current state.
> 
> No-one ever documented any expectations, did they?

Do you really want that for async flips? Async flips can't be
done atomically with anything else, so why are you even asking
the kernel to do that?
Ville Syrjälä Sept. 30, 2022, 3:58 p.m. UTC | #7
On Fri, Sep 30, 2022 at 06:45:09PM +0300, Ville Syrjälä wrote:
> On Fri, Sep 30, 2022 at 06:37:00PM +0300, Pekka Paalanen wrote:
> > On Fri, 30 Sep 2022 18:09:55 +0300
> > Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> > 
> > > That would actively discourage people from even attempting the
> > > "just dump all the state into the ioctl" approach with async flips
> > > since even the props whose value isn't even changing would be rejected.
> > 
> > About that.
> > 
> > To me it looks like just a classic case of broken communication.
> > 
> > The kernel developers assume that of course userspace will minimize the
> > state set to only those properties that change, because...?
> > 
> > Userspace developers think that of course the kernel will optimize the
> > state set into minimal changes, because the kernel actually has the
> > authoritative knowledge of what the current state is, and the driver
> > actually knows which properties are costly and need to be optimized and
> > which ones don't matter. It has never even occurred to me that the
> > kernel would not compare next state to current state.
> > 
> > No-one ever documented any expectations, did they?
> 
> Do you really want that for async flips? Async flips can't be
> done atomically with anything else, so why are you even asking
> the kernel to do that?

Also what if you want plane 1 to do an async flip, and plane 2 to do
a sync flip? With the single async flag per commit you will end up
with one of the following results:

plane 1      plane 2      outcome
can async    can async    async flip on both planes (totally not what you wanted)
can async    can't async  -EINVAL (what you actually wanted but got unfairly rejected)
can't async  can async    -EINVAL
can't async  can't async  -EINVAL

Those last two are actually reasonable outcomes since the plane
where you did want to async flip didn't support it. But the
first two are just nonsense results.
Pekka Paalanen Oct. 3, 2022, 8:48 a.m. UTC | #8
On Fri, 30 Sep 2022 18:45:09 +0300
Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:

> On Fri, Sep 30, 2022 at 06:37:00PM +0300, Pekka Paalanen wrote:
> > On Fri, 30 Sep 2022 18:09:55 +0300
> > Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> >   
> > > That would actively discourage people from even attempting the
> > > "just dump all the state into the ioctl" approach with async flips
> > > since even the props whose value isn't even changing would be rejected.  
> > 
> > About that.
> > 
> > To me it looks like just a classic case of broken communication.
> > 
> > The kernel developers assume that of course userspace will minimize the
> > state set to only those properties that change, because...?
> > 
> > Userspace developers think that of course the kernel will optimize the
> > state set into minimal changes, because the kernel actually has the
> > authoritative knowledge of what the current state is, and the driver
> > actually knows which properties are costly and need to be optimized and
> > which ones don't matter. It has never even occurred to me that the
> > kernel would not compare next state to current state.
> > 
> > No-one ever documented any expectations, did they?  
> 
> Do you really want that for async flips? Async flips can't be
> done atomically with anything else, so why are you even asking
> the kernel to do that?

I'm not talking about async flips only.

I'm talking about atomic commits in general. I don't think it's a good
idea to make async atomic commits behave fundamentally different from
sync atomic commits wrt. what non-changing state you are allowed to
list in your state set or not.

Isn't there common DRM code to convert an atomic commit state set into
state objects? It probably starts by copying the current state, and
then playing through the commit state set, setting all listed
properties to their new values? Why wouldn't that loop maintain the
knowledge of what actually changed?

When you copy the current data, reset all changed-flags to false. When
you apply each property from the commit set, compare the value and set
the changed-flag only if the value changes.

This manufacturing of the new tentative state set happens at atomic
commit ioctl time before the ioctl returns, right? So the current state
is well-defined: any previous atomic sync or async commit can be assumed to
have succeeded even if it hasn't applied in hardware yet if the commit
ioctl for it succeeded, right?


Thanks,
pq
Ville Syrjälä Oct. 3, 2022, 9:04 a.m. UTC | #9
On Mon, Oct 03, 2022 at 11:48:49AM +0300, Pekka Paalanen wrote:
> On Fri, 30 Sep 2022 18:45:09 +0300
> Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> 
> > On Fri, Sep 30, 2022 at 06:37:00PM +0300, Pekka Paalanen wrote:
> > > On Fri, 30 Sep 2022 18:09:55 +0300
> > > Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> > >   
> > > > That would actively discourage people from even attempting the
> > > > "just dump all the state into the ioctl" approach with async flips
> > > > since even the props whose value isn't even changing would be rejected.  
> > > 
> > > About that.
> > > 
> > > To me it looks like just a classic case of broken communication.
> > > 
> > > The kernel developers assume that of course userspace will minimize the
> > > state set to only those properties that change, because...?
> > > 
> > > Userspace developers think that of course the kernel will optimize the
> > > state set into minimal changes, because the kernel actually has the
> > > authoritative knowledge of what the current state is, and the driver
> > > actually knows which properties are costly and need to be optimized and
> > > which ones don't matter. It has never even occurred to me that the
> > > kernel would not compare next state to current state.
> > > 
> > > No-one ever documented any expectations, did they?  
> > 
> > Do you really want that for async flips? Async flips can't be
> > done atomically with anything else, so why are you even asking
> > the kernel to do that?
> 
> I'm not talking about async flips only.
> 
> I'm talking about atomic commits in general. I don't think it's a good
> idea to make async atomic commits behave fundamentally different from
> sync atomic commits wrt. what non-changing state you are allowed to
> list in your state set or not.
> 
> Isn't there common DRM code to convert an atomic commit state set into
> state objects? It probably starts by copying the current state, and
> then playing through the commit state set, setting all listed
> properties to their new values? Why wouldn't that loop maintain the
> knowledge of what actually changed?

Any such book keeping is entirely ad-hoc atm. It's also not super
obvious how much of it is actually useful.

You have to do a real commit on the crtc anyway if the crtc (or
on any of its associated objects) is listed in the commit, so
there's not necessarily much to be gained by tracking chages in
all properties.

And that behaviour again enters very muddy waters when combined
with the async flip flag for the entire commit. The current approach
being proposed seems to suggest that we can instead short circuit
async commits when nothing has changed. That is not at all how
sync atomic commits work.

> When you copy the current data, reset all changed-flags to false. When
> you apply each property from the commit set, compare the value and set
> the changed-flag only if the value changes.
> 
> This manufacturing of the new tentative state set happens at atomic
> commit ioctl time before the ioctl returns, right? So the current state
> is well-defined: any previous atomic sync or async commit can be assumed to
> have succeeded even if it hasn't applied in hardware yet if the commit
> ioctl for it succeeded, right?

Yes. We could certainly try to fully track all changes in
properties, but no has measured if there's any real benefit
of doing so.
Simon Ser Oct. 13, 2022, 4:02 p.m. UTC | #10
> > > So no tests that actually verify that the kernel properly rejects
> > > stuff stuff like modesets, gamma LUT updates, plane movement,
> > > etc.?
> >
> > Pondering this a bit more, it just occurred to me the current driver
> > level checks might easily lead to confusing behaviour. Eg. is
> > the ioctl going to succeed if you ask for an async change of some
> > random property while the crtc disabled, but fails if you ask for
> > the same async property change when the crtc is active?
> >
> > So another reason why rejecting most properties already at
> > the uapi level might be a good idea.
> 
> And just to be clear this is pretty much what I suggest:
> 
> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> index 79730fa1dd8e..471a2c703847 100644
> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> @@ -1392,6 +1392,13 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
>  				goto out;
>  			}
> 
> +			if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC &&
> +			    prop != dev->mode_config.prop_fb_id) {
> +				drm_mode_object_put(obj);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +
>  			if (copy_from_user(&prop_value,
>  					   prop_values_ptr + copied_props,
>  					   sizeof(prop_value))) {
> 
> 
> That would actively discourage people from even attempting the
> "just dump all the state into the ioctl" approach with async flips
> since even the props whose value isn't even changing would be rejected.

How does this sound?

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 945761968428..ffd16bdc7b83 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -972,14 +972,26 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
 			    struct drm_file *file_priv,
 			    struct drm_mode_object *obj,
 			    struct drm_property *prop,
-			    uint64_t prop_value)
+			    uint64_t prop_value,
+			    bool async_flip)
 {
 	struct drm_mode_object *ref;
 	int ret;
+	uint64_t old_val;
 
 	if (!drm_property_change_valid_get(prop, prop_value, &ref))
 		return -EINVAL;
 
+	if (async_flip && prop != prop->dev->mode_config.prop_fb_id) {
+		ret = drm_atomic_get_property(obj, prop, &old_val);
+		if (ret != 0 || old_val != prop_value) {
+			drm_dbg_atomic(prop->dev,
+				       "[PROP:%d:%s] cannot be changed during async flip\n",
+				       prop->base.id, prop->name);
+			return -EINVAL;
+		}
+	}
+
 	switch (obj->type) {
 	case DRM_MODE_OBJECT_CONNECTOR: {
 		struct drm_connector *connector = obj_to_connector(obj);
André Almeida Oct. 17, 2022, 2:35 p.m. UTC | #11
On 10/13/22 13:02, Simon Ser wrote:
>>>> So no tests that actually verify that the kernel properly rejects
>>>> stuff stuff like modesets, gamma LUT updates, plane movement,
>>>> etc.?
>>>
>>> Pondering this a bit more, it just occurred to me the current driver
>>> level checks might easily lead to confusing behaviour. Eg. is
>>> the ioctl going to succeed if you ask for an async change of some
>>> random property while the crtc disabled, but fails if you ask for
>>> the same async property change when the crtc is active?
>>>
>>> So another reason why rejecting most properties already at
>>> the uapi level might be a good idea.
>>
>> And just to be clear this is pretty much what I suggest:
>>
>> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
>> index 79730fa1dd8e..471a2c703847 100644
>> --- a/drivers/gpu/drm/drm_atomic_uapi.c
>> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
>> @@ -1392,6 +1392,13 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
>>   				goto out;
>>   			}
>>
>> +			if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC &&
>> +			    prop != dev->mode_config.prop_fb_id) {
>> +				drm_mode_object_put(obj);
>> +				ret = -EINVAL;
>> +				goto out;
>> +			}
>> +
>>   			if (copy_from_user(&prop_value,
>>   					   prop_values_ptr + copied_props,
>>   					   sizeof(prop_value))) {
>>
>>
>> That would actively discourage people from even attempting the
>> "just dump all the state into the ioctl" approach with async flips
>> since even the props whose value isn't even changing would be rejected.
> 
> How does this sound?
> 
> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> index 945761968428..ffd16bdc7b83 100644
> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> @@ -972,14 +972,26 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
>   			    struct drm_file *file_priv,
>   			    struct drm_mode_object *obj,
>   			    struct drm_property *prop,
> -			    uint64_t prop_value)
> +			    uint64_t prop_value,
> +			    bool async_flip)
>   {
>   	struct drm_mode_object *ref;
>   	int ret;
> +	uint64_t old_val;
>   
>   	if (!drm_property_change_valid_get(prop, prop_value, &ref))
>   		return -EINVAL;
>   
> +	if (async_flip && prop != prop->dev->mode_config.prop_fb_id) {
> +		ret = drm_atomic_get_property(obj, prop, &old_val);
> +		if (ret != 0 || old_val != prop_value) {
> +			drm_dbg_atomic(prop->dev,
> +				       "[PROP:%d:%s] cannot be changed during async flip\n",
> +				       prop->base.id, prop->name);

I would write this as "[PROP:%d:%s] No prop can be changed during async 
flips" to make it clear that it's not just this prop that can't, but any.

> +			return -EINVAL;
> +		}
> +	}
> +
>   	switch (obj->type) {
>   	case DRM_MODE_OBJECT_CONNECTOR: {
>   		struct drm_connector *connector = obj_to_connector(obj);
André Almeida Oct. 28, 2022, 12:36 p.m. UTC | #12
On 10/13/22 13:02, Simon Ser wrote:
>>>> So no tests that actually verify that the kernel properly rejects
>>>> stuff stuff like modesets, gamma LUT updates, plane movement,
>>>> etc.?
>>>
>>> Pondering this a bit more, it just occurred to me the current driver
>>> level checks might easily lead to confusing behaviour. Eg. is
>>> the ioctl going to succeed if you ask for an async change of some
>>> random property while the crtc disabled, but fails if you ask for
>>> the same async property change when the crtc is active?
>>>
>>> So another reason why rejecting most properties already at
>>> the uapi level might be a good idea.
>>
>> And just to be clear this is pretty much what I suggest:
>>
>> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
>> index 79730fa1dd8e..471a2c703847 100644
>> --- a/drivers/gpu/drm/drm_atomic_uapi.c
>> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
>> @@ -1392,6 +1392,13 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
>>   				goto out;
>>   			}
>>
>> +			if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC &&
>> +			    prop != dev->mode_config.prop_fb_id) {
>> +				drm_mode_object_put(obj);
>> +				ret = -EINVAL;
>> +				goto out;
>> +			}
>> +
>>   			if (copy_from_user(&prop_value,
>>   					   prop_values_ptr + copied_props,
>>   					   sizeof(prop_value))) {
>>
>>
>> That would actively discourage people from even attempting the
>> "just dump all the state into the ioctl" approach with async flips
>> since even the props whose value isn't even changing would be rejected.
> 
> How does this sound?
> 
> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> index 945761968428..ffd16bdc7b83 100644
> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> @@ -972,14 +972,26 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
>   			    struct drm_file *file_priv,
>   			    struct drm_mode_object *obj,
>   			    struct drm_property *prop,
> -			    uint64_t prop_value)
> +			    uint64_t prop_value,
> +			    bool async_flip)
>   {
>   	struct drm_mode_object *ref;
>   	int ret;
> +	uint64_t old_val;
>   
>   	if (!drm_property_change_valid_get(prop, prop_value, &ref))
>   		return -EINVAL;
>   
> +	if (async_flip && prop != prop->dev->mode_config.prop_fb_id) {
> +		ret = drm_atomic_get_property(obj, prop, &old_val);
> +		if (ret != 0 || old_val != prop_value) {
> +			drm_dbg_atomic(prop->dev,
> +				       "[PROP:%d:%s] cannot be changed during async flip\n",
> +				       prop->base.id, prop->name);
> +			return -EINVAL;
> +		}
> +	}
> +
>   	switch (obj->type) {
>   	case DRM_MODE_OBJECT_CONNECTOR: {
>   		struct drm_connector *connector = obj_to_connector(obj);


drm_atomic_get_property() needs the object lock to be used, so we need 
to check the property inside the switch-case like this:

-- >8 --

 From f3ee5a1163bfe5a88109d7084208940fe5566967 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@igalia.com>
Date: Thu, 27 Oct 2022 17:23:09 -0300
Subject: [PATCH] drm: Check for prop changes in atomic async flip
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

No prop changes are allowed during an async flip via atomic DRM API, so
make sure to reject them.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
  drivers/gpu/drm/drm_atomic_uapi.c   | 47 +++++++++++++++++++++++++++--
  drivers/gpu/drm/drm_crtc_internal.h |  2 +-
  drivers/gpu/drm/drm_mode_object.c   |  2 +-
  3 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index ee24ed7e2edb..f63f23305621 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -964,13 +964,28 @@ int drm_atomic_connector_commit_dpms(struct 
drm_atomic_state *state,
  	return ret;
  }

+static bool drm_atomic_check_prop_changes(int ret, uint64_t old_val, 
uint64_t prop_value,
+				  struct drm_property *prop)
+{
+	if (ret != 0 || old_val != prop_value) {
+		drm_dbg_atomic(prop->dev,
+			       "[PROP:%d:%s] No prop can be changed during async flip\n",
+			       prop->base.id, prop->name);
+		return true;
+	}
+
+	return false;
+}
+
  int drm_atomic_set_property(struct drm_atomic_state *state,
  			    struct drm_file *file_priv,
  			    struct drm_mode_object *obj,
  			    struct drm_property *prop,
-			    uint64_t prop_value)
+			    uint64_t prop_value,
+			    bool async_flip)
  {
  	struct drm_mode_object *ref;
+	uint64_t old_val;
  	int ret;

  	if (!drm_property_change_valid_get(prop, prop_value, &ref))
@@ -987,6 +1002,15 @@ int drm_atomic_set_property(struct 
drm_atomic_state *state,
  			break;
  		}

+		if (async_flip) {
+			ret = drm_atomic_connector_get_property(connector, connector_state,
+					prop, &old_val);
+			if (drm_atomic_check_prop_changes(ret, old_val, prop_value, prop)) {
+				ret = -EINVAL;
+				break;
+			}
+		}
+
  		ret = drm_atomic_connector_set_property(connector,
  				connector_state, file_priv,
  				prop, prop_value);
@@ -1002,6 +1026,14 @@ int drm_atomic_set_property(struct 
drm_atomic_state *state,
  			break;
  		}

+		if (async_flip) {
+			ret = drm_atomic_crtc_get_property(crtc, crtc_state, prop, &old_val);
+			if (drm_atomic_check_prop_changes(ret, old_val, prop_value, prop)) {
+				ret = -EINVAL;
+				break;
+			}
+		}
+
  		ret = drm_atomic_crtc_set_property(crtc,
  				crtc_state, prop, prop_value);
  		break;
@@ -1016,6 +1048,14 @@ int drm_atomic_set_property(struct 
drm_atomic_state *state,
  			break;
  		}

+		if (async_flip && prop != prop->dev->mode_config.prop_fb_id) {
+			ret = drm_atomic_plane_get_property(plane, plane_state, prop, &old_val);
+			if (drm_atomic_check_prop_changes(ret, old_val, prop_value, prop)) {
+				ret = -EINVAL;
+				break;
+			}
+		}
+
  		ret = drm_atomic_plane_set_property(plane,
  				plane_state, file_priv,
  				prop, prop_value);
@@ -1304,6 +1344,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
  	struct drm_out_fence_state *fence_state;
  	int ret = 0;
  	unsigned int i, j, num_fences;
+	bool async = false;

  	/* disallow for drivers not supporting atomic: */
  	if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
@@ -1340,6 +1381,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
  				       "commit failed: DRM_MODE_PAGE_FLIP_ASYNC not supported with 
atomic\n");
  			return -EINVAL;
  		}
+
+		async = true;
  	}

  	/* can't test and expect an event at the same time. */
@@ -1420,7 +1463,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
  			}

  			ret = drm_atomic_set_property(state, file_priv,
-						      obj, prop, prop_value);
+						      obj, prop, prop_value, async);
  			if (ret) {
  				drm_mode_object_put(obj);
  				goto out;
diff --git a/drivers/gpu/drm/drm_crtc_internal.h 
b/drivers/gpu/drm/drm_crtc_internal.h
index 56041b604881..42ff11706fd4 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -250,7 +250,7 @@ int drm_atomic_set_property(struct drm_atomic_state 
*state,
  			    struct drm_file *file_priv,
  			    struct drm_mode_object *obj,
  			    struct drm_property *prop,
-			    uint64_t prop_value);
+			    uint64_t prop_value, bool async_flip);
  int drm_atomic_get_property(struct drm_mode_object *obj,
  			    struct drm_property *property, uint64_t *val);

diff --git a/drivers/gpu/drm/drm_mode_object.c 
b/drivers/gpu/drm/drm_mode_object.c
index ba1608effc0f..64f519254895 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -536,7 +536,7 @@ static int set_property_atomic(struct 
drm_mode_object *obj,
  						       obj_to_connector(obj),
  						       prop_value);
  	} else {
-		ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value);
+		ret = drm_atomic_set_property(state, file_priv, obj, prop, 
prop_value, false);
  		if (ret)
  			goto out;
  		ret = drm_atomic_commit(state);
Simon Ser Nov. 17, 2022, 8:58 a.m. UTC | #13
Ville, any news on this?
Simon Ser Jan. 5, 2023, 4:01 p.m. UTC | #14
Hm, thinking about this again, there's still something which is a bit
off with the new approach. Let's say the caller sets MODE_ID to another
blob ID, but with the same blob payload. DRM core is smart enough to
figure out that the mode didn't change and skip the modeset. However,
the check implemented here isn't smart enough.

tl;dr there are still discrepancies between the regular code-path and
the async page-flip one. Does that matter?