public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Simona Vetter <simona.vetter@ffwll.ch>
To: Maxime Ripard <mripard@kernel.org>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Thomas Zimmermann <tzimmermann@suse.de>,
	David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
	Andrzej Hajda <andrzej.hajda@intel.com>,
	Neil Armstrong <neil.armstrong@linaro.org>,
	Robert Foss <rfoss@kernel.org>,
	Laurent Pinchart <Laurent.pinchart@ideasonboard.com>,
	Jonas Karlman <jonas@kwiboo.se>,
	Jernej Skrabec <jernej.skrabec@gmail.com>,
	Jyri Sarha <jyri.sarha@iki.fi>,
	Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>,
	Devarsh Thakkar <devarsht@ti.com>,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 13/29] drm/atomic_helper: Compare actual and readout states once the commit is done
Date: Fri, 17 Oct 2025 15:21:36 +0200	[thread overview]
Message-ID: <aPJC4CisqouIX-Wi@phenom.ffwll.local> (raw)
In-Reply-To: <20250902-drm-state-readout-v1-13-14ad5315da3f@kernel.org>

On Tue, Sep 02, 2025 at 10:32:41AM +0200, Maxime Ripard wrote:
> The new atomic state readout infrastructure can be hard to test because
> getting access to every firmware variation is hard, but also because
> most firmware setup will be pretty basic and won't test a wide range of
> features. Noticing whether it was sucessful or not is also not very
> convenient.
> 
> In order to make it easier, we can however provide some infrastructure
> to read out a new state every time a non-blocking commit is made, and
> compare the readout one with the committed one. And since we do this
> only on non-blocking commits, the time penalty doesn't matter.
> 
> To do so, we introduce a new hook for every state, atomic_compare_state,
> that takes two state instances and is supposed to return whether they
> are identical or not.
> 
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 113 ++++++++++++++++++++++++++++++++++++
>  include/drm/drm_atomic.h            |  14 +++++
>  include/drm/drm_bridge.h            |  14 +++++
>  include/drm/drm_connector.h         |  14 +++++
>  include/drm/drm_crtc.h              |  14 +++++
>  include/drm/drm_plane.h             |  14 +++++
>  6 files changed, 183 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 14d9bc282ca570964e494936090898b2dc6bee31..aa8f52b5d5a5e6146a6472eebaf02e675c35ccd2 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -428,10 +428,120 @@ void drm_atomic_helper_readout_state(struct drm_device *dev)
>  	drm_atomic_helper_install_readout_state(state);
>  	drm_atomic_state_put(state);
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_readout_state);
>  
> +static bool drm_atomic_helper_readout_compare(struct drm_atomic_state *committed_state)
> +{
> +	struct drm_device *dev = committed_state->dev;
> +	struct drm_printer p = drm_err_printer(dev, NULL);
> +	struct drm_private_state *new_obj_state;
> +	struct drm_private_obj *obj;
> +	struct drm_plane_state *new_plane_state;
> +	struct drm_plane *plane;
> +	struct drm_crtc_state *new_crtc_state;
> +	struct drm_crtc *crtc;
> +	struct drm_connector_state *new_conn_state;
> +	struct drm_connector *conn;
> +	struct drm_atomic_state *readout_state;
> +	unsigned int i;
> +	bool identical = true;
> +
> +	readout_state = drm_atomic_build_readout_state(dev);
> +	if (WARN_ON(IS_ERR(readout_state)))
> +		return false;
> +
> +	for_each_new_plane_in_state(committed_state, plane, new_plane_state, i) {
> +		const struct drm_plane_funcs *plane_funcs =
> +			plane->funcs;
> +		struct drm_plane_state *readout_plane_state;
> +
> +		readout_plane_state = drm_atomic_get_old_plane_state(readout_state, plane);
> +		if (!readout_plane_state) {
> +			identical = false;
> +			continue;
> +		}
> +
> +		if (!plane_funcs->atomic_compare_state)
> +			continue;
> +
> +		if (!plane_funcs->atomic_compare_state(plane, &p, new_plane_state, readout_plane_state)) {
> +			drm_warn(dev, "[PLANE:%d:%s] Committed and Readout PLANE state don't match\n",
> +				 plane->base.id, plane->name);
> +			identical = false;
> +			continue;
> +		}
> +	}
> +
> +	for_each_new_crtc_in_state(committed_state, crtc, new_crtc_state, i) {
> +		const struct drm_crtc_funcs *crtc_funcs = crtc->funcs;
> +		struct drm_crtc_state *readout_crtc_state;
> +
> +		readout_crtc_state = drm_atomic_get_old_crtc_state(readout_state, crtc);
> +		if (!readout_crtc_state) {
> +			identical = false;
> +			continue;
> +		}
> +
> +		if (!crtc_funcs->atomic_compare_state)
> +			continue;
> +
> +		if (!crtc_funcs->atomic_compare_state(crtc, &p, new_crtc_state, readout_crtc_state)) {
> +			drm_warn(dev, "[CRTC:%d:%s] Committed and Readout CRTC state don't match\n",
> +				 crtc->base.id, crtc->name);
> +			identical = false;
> +			continue;
> +		}
> +	}
> +
> +	for_each_new_connector_in_state(committed_state, conn, new_conn_state, i) {
> +		const struct drm_connector_funcs *conn_funcs =
> +			conn->funcs;
> +		struct drm_connector_state *readout_conn_state;
> +
> +		readout_conn_state = drm_atomic_get_old_connector_state(readout_state, conn);
> +		if (!readout_conn_state) {
> +			identical = false;
> +			continue;
> +		}
> +
> +		if (!conn_funcs->atomic_compare_state)
> +			continue;
> +
> +		if (!conn_funcs->atomic_compare_state(conn, &p, new_conn_state, readout_conn_state)) {
> +			drm_warn(dev, "[CONNECTOR:%d:%s] Committed and Readout connector state don't match\n",
> +				 conn->base.id, conn->name);
> +			identical = false;
> +			continue;
> +		}
> +	}
> +
> +	for_each_new_private_obj_in_state(committed_state, obj, new_obj_state, i) {
> +		const struct drm_private_state_funcs *obj_funcs = obj->funcs;
> +		struct drm_private_state *readout_obj_state;
> +
> +		readout_obj_state = drm_atomic_get_old_private_obj_state(readout_state, obj);
> +		if (!readout_obj_state) {
> +			identical = false;
> +			continue;
> +		}
> +
> +		if (!obj_funcs->atomic_compare_state)
> +			continue;
> +
> +		if (!obj_funcs->atomic_compare_state(obj, &p, new_obj_state, readout_obj_state)) {
> +			drm_warn(dev, "Committed and Readout private object state don't match\n");
> +			identical = false;
> +			continue;
> +		}
> +	}
> +
> +	drm_atomic_state_put(readout_state);
> +
> +	return identical;
> +}
> +
>  /**
>   * DOC: overview
>   *
>   * This helper library provides implementations of check and commit functions on
>   * top of the CRTC modeset helper callbacks and the plane helper callbacks. It
> @@ -2382,10 +2492,13 @@ static void commit_tail(struct drm_atomic_state *state, bool nonblock)
>  						 (unsigned long)commit_time_ms,
>  						 new_self_refresh_mask);
>  
>  	drm_atomic_helper_commit_cleanup_done(state);
>  
> +	if (!nonblock)
> +		drm_atomic_helper_readout_compare(state);
> +
>  	drm_atomic_state_put(state);
>  }
>  
>  static void commit_work(struct work_struct *work)
>  {
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index f13f926d21047e42bb9ac692c2dd4b88f2ebd91c..d75a9c7e23adf7fa264df766b47526f75e9cc753 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -226,10 +226,24 @@ struct drm_private_state_funcs {
>  	 * Frees the private object state created with @atomic_duplicate_state.
>  	 */
>  	void (*atomic_destroy_state)(struct drm_private_obj *obj,
>  				     struct drm_private_state *state);
>  
> +	/**
> +	 * @atomic_compare_state
> +	 *
> +	 * Compares two &struct drm_private_state instances.
> +	 *
> +	 * RETURNS:
> +	 *
> +	 * True if the states are identical, false otherwise.
> +	 */
> +	bool (*atomic_compare_state)(struct drm_private_obj *obj,
> +				     struct drm_printer *p,
> +				     struct drm_private_state *a,
> +				     struct drm_private_state *b);
> +
>  	/**
>  	 * @atomic_print_state:
>  	 *
>  	 * If driver subclasses &struct drm_private_state, it should implement
>  	 * this optional hook for printing additional driver specific state.
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 15b63053f01869786831936ba28b7efc1e55e2e8..5ea63b51a4dd4cb00468afcf7d126c774f63ade0 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -511,10 +511,24 @@ struct drm_bridge_funcs {
>  	int (*atomic_readout_state)(struct drm_bridge *bridge,
>  				    struct drm_bridge_state *bridge_state,
>  				    struct drm_crtc_state *crtc_state,
>  				    struct drm_connector_state *conn_state);
>  
> +	/**
> +	 * @atomic_compare_state
> +	 *
> +	 * Compares two &struct drm_bridge_state instances.
> +	 *
> +	 * RETURNS:
> +	 *
> +	 * True if the states are identical, false otherwise.
> +	 */
> +	bool (*atomic_compare_state)(struct drm_bridge *bridge,
> +				     struct drm_printer *p,
> +				     struct drm_bridge_state *a,
> +				     struct drm_bridge_state *b);
> +
>  	/**
>  	 * @atomic_duplicate_state:
>  	 *
>  	 * Duplicate the current bridge state object (which is guaranteed to be
>  	 * non-NULL).
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index f68bd9627c085c6d2463b847aaa245ccc651f27b..dc2c77b04df9010cbfb2028de8ef8c747003c489 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1534,10 +1534,24 @@ struct drm_connector_funcs {
>  	 * This callback is mandatory for atomic drivers.
>  	 */
>  	void (*atomic_destroy_state)(struct drm_connector *connector,
>  				     struct drm_connector_state *state);
>  

Both these callbacks for connector/crtc/plane need to be moved into the
respective _helper_funcs structs, because they're not uapi stuff.
priv/bridge funcs do not have this split, because they're not uapi visible
objects.
-Sima

> +	/**
> +	 * @atomic_compare_state
> +	 *
> +	 * Compares two &struct drm_connector_state instances.
> +	 *
> +	 * RETURNS:
> +	 *
> +	 * True if the states are identical, false otherwise.
> +	 */
> +	bool (*atomic_compare_state)(struct drm_connector *connector,
> +				     struct drm_printer *p,
> +				     struct drm_connector_state *a,
> +				     struct drm_connector_state *b);
> +
>  	/**
>  	 * @atomic_set_property:
>  	 *
>  	 * Decode a driver-private property value and store the decoded value
>  	 * into the passed-in state structure. Since the atomic core decodes all
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 11e3299cfad1572c6e507918c7cceae7a28ba4cf..21c20ecdda40f3d155d3c140e06b3801270f5262 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -676,10 +676,24 @@ struct drm_crtc_funcs {
>  	 * This callback is mandatory for atomic drivers.
>  	 */
>  	void (*atomic_destroy_state)(struct drm_crtc *crtc,
>  				     struct drm_crtc_state *state);
>  
> +	/**
> +	 * @atomic_compare_state
> +	 *
> +	 * Compares two &struct drm_crtc_state instances.
> +	 *
> +	 * RETURNS:
> +	 *
> +	 * True if the states are identical, false otherwise.
> +	 */
> +	bool (*atomic_compare_state)(struct drm_crtc *crtc,
> +				     struct drm_printer *p,
> +				     struct drm_crtc_state *a,
> +				     struct drm_crtc_state *b);
> +
>  	/**
>  	 * @atomic_set_property:
>  	 *
>  	 * Decode a driver-private property value and store the decoded value
>  	 * into the passed-in state structure. Since the atomic core decodes all
> diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
> index 691a267c857a228f674ef02a63fb6d1ff9e379a8..c24c10ccc8e8f2ba23e77e279aef61ae86e320c7 100644
> --- a/include/drm/drm_plane.h
> +++ b/include/drm/drm_plane.h
> @@ -449,10 +449,24 @@ struct drm_plane_funcs {
>  	 * This callback is mandatory for atomic drivers.
>  	 */
>  	void (*atomic_destroy_state)(struct drm_plane *plane,
>  				     struct drm_plane_state *state);
>  
> +	/**
> +	 * @atomic_compare_state
> +	 *
> +	 * Compares two &struct drm_plane_state instances.
> +	 *
> +	 * RETURNS:
> +	 *
> +	 * True if the states are identical, false otherwise.
> +	 */
> +	bool (*atomic_compare_state)(struct drm_plane *plane,
> +				     struct drm_printer *p,
> +				     struct drm_plane_state *a,
> +				     struct drm_plane_state *b);
> +
>  	/**
>  	 * @atomic_set_property:
>  	 *
>  	 * Decode a driver-private property value and store the decoded value
>  	 * into the passed-in state structure. Since the atomic core decodes all
> 
> -- 
> 2.50.1
> 

-- 
Simona Vetter
Software Engineer
http://blog.ffwll.ch

  reply	other threads:[~2025-10-17 13:21 UTC|newest]

Thread overview: 105+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-02  8:32 [PATCH 00/29] drm: Implement state readout support Maxime Ripard
2025-09-02  8:32 ` [PATCH 01/29] drm/atomic: Document atomic state lifetime Maxime Ripard
2025-09-02 13:08   ` Thomas Zimmermann
2025-09-02 18:59     ` Laurent Pinchart
2025-09-23  9:22     ` Maxime Ripard
2025-09-02  8:32 ` [PATCH 02/29] drm/atomic: Fix unused but set warning in for_each_old_plane_in_state Maxime Ripard
2025-09-02 13:10   ` Thomas Zimmermann
2025-09-02 19:25   ` Laurent Pinchart
2025-09-02  8:32 ` [PATCH 03/29] drm/atomic: Fix unused but set warning in for_each_old_private_obj_in_state Maxime Ripard
2025-09-02 13:10   ` Thomas Zimmermann
2025-09-02 19:26   ` Laurent Pinchart
2025-09-02  8:32 ` [PATCH 04/29] drm/atomic_helper: Skip over NULL private_obj pointers Maxime Ripard
2025-09-02 13:13   ` Thomas Zimmermann
2025-09-02 19:29     ` Laurent Pinchart
2025-09-23  9:23     ` Maxime Ripard
2025-09-02  8:32 ` [PATCH 05/29] drm/atomic_state_helper: Fix bridge state initialization Maxime Ripard
2025-09-02 13:18   ` Thomas Zimmermann
2025-09-15 11:27     ` Maxime Ripard
2025-09-15 13:12       ` Thomas Zimmermann
2025-09-23  9:33         ` Maxime Ripard
2025-10-01  6:45           ` Thomas Zimmermann
2025-09-15 12:54     ` Dmitry Baryshkov
2025-09-02 19:49   ` Laurent Pinchart
2025-09-02  8:32 ` [PATCH 06/29] drm/bridge: Implement atomic_print_state Maxime Ripard
2025-09-02 13:22   ` Thomas Zimmermann
2025-09-02 20:22     ` Laurent Pinchart
2025-09-15 11:28       ` Maxime Ripard
2025-09-15 12:56         ` Dmitry Baryshkov
2025-09-02  8:32 ` [PATCH 07/29] drm/atomic: Implement drm_atomic_print_old_state Maxime Ripard
2025-09-02 13:26   ` Thomas Zimmermann
2025-09-09 12:44     ` Maxime Ripard
2025-09-02 20:35   ` Laurent Pinchart
2025-09-02  8:32 ` [PATCH 08/29] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Maxime Ripard
2025-09-02 13:30   ` Thomas Zimmermann
2025-09-02 20:52   ` Laurent Pinchart
2025-09-15 11:35     ` Maxime Ripard
2025-09-02  8:32 ` [PATCH 09/29] drm/modeset: Create atomic_reset hook Maxime Ripard
2025-09-02 21:04   ` Laurent Pinchart
2025-09-15 11:37     ` Maxime Ripard
2025-09-02  8:32 ` [PATCH 10/29] drm/atomic: Add atomic_state_readout infrastructure Maxime Ripard
2025-09-02 13:44   ` Thomas Zimmermann
2025-09-15  8:42     ` Maxime Ripard
2025-09-15  9:11       ` Thomas Zimmermann
2025-09-23  9:37         ` Maxime Ripard
2025-10-01  7:01           ` Thomas Zimmermann
2025-09-15 18:38       ` Dmitry Baryshkov
2025-09-23  9:38         ` Maxime Ripard
2025-09-23 10:28           ` Dmitry Baryshkov
2025-09-23 10:32             ` Laurent Pinchart
2025-09-23 10:43               ` Dmitry Baryshkov
2025-09-23 11:41                 ` Laurent Pinchart
2025-09-23 15:20                   ` Dmitry Baryshkov
2025-09-24  9:56               ` Maxime Ripard
2025-09-24  9:53             ` Maxime Ripard
2025-09-15 18:40   ` Dmitry Baryshkov
2025-09-23  9:45     ` Maxime Ripard
2025-09-23 10:30       ` Dmitry Baryshkov
2025-10-17 13:12         ` Simona Vetter
2025-10-17 13:29   ` Simona Vetter
2025-10-17 13:41   ` Simona Vetter
2025-09-02  8:32 ` [PATCH 11/29] drm/crtc: Drop no_vblank bit field Maxime Ripard
2025-09-02 13:45   ` Thomas Zimmermann
2025-09-30 10:00   ` (subset) " Maxime Ripard
2025-09-02  8:32 ` [PATCH 12/29] drm/atomic_helper: Pass nonblock to commit_tail Maxime Ripard
2025-09-02 13:46   ` Thomas Zimmermann
2025-09-02  8:32 ` [PATCH 13/29] drm/atomic_helper: Compare actual and readout states once the commit is done Maxime Ripard
2025-10-17 13:21   ` Simona Vetter [this message]
2025-10-21  9:27   ` Simona Vetter
2025-10-31 21:01   ` Simona Vetter
2025-09-02  8:32 ` [PATCH 14/29] drm/atomic_state_helper: Provide comparison macros Maxime Ripard
2025-09-02  8:32 ` [PATCH 15/29] drm/atomic_state_helper: Provide atomic_compare_state helpers Maxime Ripard
2025-09-02  8:32 ` [PATCH 16/29] drm/encoder: Create get_current_crtc hook Maxime Ripard
2025-10-17 13:19   ` Simona Vetter
2025-09-02  8:32 ` [PATCH 17/29] drm/bridge_connector: Implement hw readout for connector Maxime Ripard
2025-09-02  8:32 ` [PATCH 18/29] drm/tidss: Convert to drm logging Maxime Ripard
2025-09-02 13:49   ` Thomas Zimmermann
2025-09-30 10:00   ` (subset) " Maxime Ripard
2025-09-02  8:32 ` [PATCH 19/29] drm/tidss: Remove ftrace-like logs Maxime Ripard
2025-09-02 13:50   ` Thomas Zimmermann
2025-09-30 10:00   ` (subset) " Maxime Ripard
2025-09-02  8:32 ` [PATCH 20/29] drm/tidss: crtc: Change variable name Maxime Ripard
2025-09-02 13:51   ` Thomas Zimmermann
2025-09-30 10:00   ` (subset) " Maxime Ripard
2025-09-02  8:32 ` [PATCH 21/29] drm/tidss: crtc: Implement destroy_state Maxime Ripard
2025-09-02 13:52   ` Thomas Zimmermann
2025-09-30 10:00   ` (subset) " Maxime Ripard
2025-09-02  8:32 ` [PATCH 22/29] drm/tidss: crtc: Cleanup reset implementation Maxime Ripard
2025-09-02 13:54   ` Thomas Zimmermann
2025-09-30 10:00   ` (subset) " Maxime Ripard
2025-09-02  8:32 ` [PATCH 23/29] drm/tidss: dispc: Add format lookup by hw value Maxime Ripard
2025-10-08 12:40   ` Tomi Valkeinen
2025-09-02  8:32 ` [PATCH 24/29] drm/tidss: dispc: Improve mode checking logs Maxime Ripard
2025-09-02 14:06   ` Thomas Zimmermann
2025-09-02  8:32 ` [PATCH 25/29] drm/tidss: dispc: Move dispc_device definition to headers Maxime Ripard
2025-09-02  8:32 ` [PATCH 26/29] drm/tidss: dispc: make accessors accessible to other parts of the driver Maxime Ripard
2025-09-02  8:32 ` [PATCH 27/29] drm/tidss: Implement readout support Maxime Ripard
2025-10-08 12:44   ` Tomi Valkeinen
2025-09-02  8:32 ` [PATCH 28/29] drm/tidss: encoder: implement get_current_crtc Maxime Ripard
2025-09-02  8:32 ` [PATCH 29/29] drm/bridge: sii902x: Implement hw state readout Maxime Ripard
2025-09-02 14:13 ` [PATCH 00/29] drm: Implement state readout support Thomas Zimmermann
2025-09-23  9:15   ` Maxime Ripard
2025-10-17 13:11     ` Simona Vetter
2025-10-08 13:07 ` Tomi Valkeinen
2025-10-08 13:57   ` Maxime Ripard
2025-10-08 14:15     ` Tomi Valkeinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aPJC4CisqouIX-Wi@phenom.ffwll.local \
    --to=simona.vetter@ffwll.ch \
    --cc=Laurent.pinchart@ideasonboard.com \
    --cc=airlied@gmail.com \
    --cc=andrzej.hajda@intel.com \
    --cc=devarsht@ti.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jernej.skrabec@gmail.com \
    --cc=jonas@kwiboo.se \
    --cc=jyri.sarha@iki.fi \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mripard@kernel.org \
    --cc=neil.armstrong@linaro.org \
    --cc=rfoss@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tomi.valkeinen@ideasonboard.com \
    --cc=tzimmermann@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox