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
next prev parent 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