[PATCH] drm/atomic-helper: Add option to update planes only on active crtc

Daniel Vetter daniel at ffwll.ch
Thu Jul 23 00:00:38 PDT 2015


On Thu, Jul 23, 2015 at 05:53:43AM +0200, Maarten Lankhorst wrote:
> Op 22-07-15 om 18:02 schreef Daniel Vetter:
> > With drivers supporting runtime pm it's generally not a good idea to
> > touch the hardware when it's off. Add an option to the commit_planes
> > helper to support this case.
> >
> > Note that the helpers already add all planes on a crtc when a modeset
> > happens, hence plane updates will not be lost if drivers set this to
> > true.
> >
> > v2: Check for NULL state->crtc before chasing the pointer. Also check
> > both old and new crtc if there's a switch. Finally just outright
> > disallow switching crtcs for a plane if the plane is in active use, on
> > most hardware that doesn't make sense.
> >
> > Cc: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
> > Cc: Thierry Reding <treding at nvidia.com>
> > Cc: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
> > Cc: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
> > Signed-off-by: Daniel Vetter <daniel.vetter at intel.com>
> > ---
> >  drivers/gpu/drm/drm_atomic_helper.c    | 29 +++++++++++++++++++++++++++--
> >  drivers/gpu/drm/exynos/exynos_drm_fb.c |  2 +-
> >  drivers/gpu/drm/msm/msm_atomic.c       |  2 +-
> >  drivers/gpu/drm/omapdrm/omap_drv.c     |  2 +-
> >  drivers/gpu/drm/rcar-du/rcar_du_kms.c  |  2 +-
> >  drivers/gpu/drm/sti/sti_drm_drv.c      |  2 +-
> >  drivers/gpu/drm/tegra/drm.c            |  2 +-
> >  include/drm/drm_atomic_helper.h        |  3 ++-
> >  8 files changed, 35 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index 99656815641d..2122c2b844da 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -471,6 +471,14 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
> >  		if (!funcs || !funcs->atomic_check)
> >  			continue;
> >  
> > +		if (plane->state->crtc && plane_state->crtc &&
> > +		    plane->state->crtc != plane_state->crtc &&
> > +		    plane->state->crtc->state->active) {
> > +			DRM_DEBUG_ATOMIC("[PLANE:%d] changing crtc while still active\n",
> > +					 plane->base.id);
> > +			return -EINVAL;
> > +		}
> > +
> >  		ret = funcs->atomic_check(plane, plane_state);
> >  		if (ret) {
> >  			DRM_DEBUG_ATOMIC("[PLANE:%d] atomic driver check failed\n",
> > @@ -995,7 +1003,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
> >  
> >  	drm_atomic_helper_commit_modeset_disables(dev, state);
> >  
> > -	drm_atomic_helper_commit_planes(dev, state);
> > +	drm_atomic_helper_commit_planes(dev, state, false);
> >  
> >  	drm_atomic_helper_commit_modeset_enables(dev, state);
> >  
> > @@ -1110,10 +1118,16 @@ fail:
> >  }
> >  EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
> >  
> > +bool plane_crtc_active(struct drm_plane_state *state)
> > +{
> > +	return state->crtc && state->crtc->state->active;
> > +}
> > +
> >  /**
> >   * drm_atomic_helper_commit_planes - commit plane state
> >   * @dev: DRM device
> >   * @old_state: atomic state object with old state structures
> > + * @active_only: Only commit on active CRTC if set
> >   *
> >   * This function commits the new plane state using the plane and atomic helper
> >   * functions for planes and crtcs. It assumes that the atomic state has already
> > @@ -1128,7 +1142,8 @@ EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
> >   * drm_atomic_helper_commit_planes_on_crtc() instead.
> >   */
> >  void drm_atomic_helper_commit_planes(struct drm_device *dev,
> > -				     struct drm_atomic_state *old_state)
> > +				     struct drm_atomic_state *old_state,
> > +				     bool active_only)
> >  {
> >  	struct drm_crtc *crtc;
> >  	struct drm_crtc_state *old_crtc_state;
> > @@ -1144,6 +1159,9 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
> >  		if (!funcs || !funcs->atomic_begin)
> >  			continue;
> >  
> > +		if (active_only && !crtc->state->active)
> > +			continue;
> > +
> >  		funcs->atomic_begin(crtc);
> >  	}
> >  
> > @@ -1155,6 +1173,10 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
> >  		if (!funcs)
> >  			continue;
> >  
> > +		if (active_only && !plane_crtc_active(plane->state) &&
> > +		    !plane_crtc_active(old_plane_state))
> > +			continue;
> > +
> >  		/*
> >  		 * Special-case disabling the plane if drivers support it.
> >  		 */
> >
> The check is still wrong. It should only check if the new
> plane_state->crtc is active, if it's not call the disable_plane hook,
> but only when get_existing_crtc_state(old_plane_state->crtc)->active &&
> !needs_modeset(old_plane_state->crtc->state).

That's why I'm simply disallowing reassigning the plane if it's still in
use. If I understand you correct your case is:
BEFORE: plane active on CRTC A and CRTC A is active.
AFTER: plane active on CRTC B, but CRTC B is not active.

I agree that the correct thing would be to only disable the plane on CRTC
A in that case. But if we make it the rule that generic drivers don't
support reassigning the plane if it's active (and generic userspace can't
rely on that working) then the above just can't happen.

Or is there another case where the above falls short?

> The other helper should be a disable_planes helper that blindly calls
> disable_plane for planes that are on crtc's and require modeset for the
> crtc on the previous plane_state.

Yeah, I'll try to stitch that helper together.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the dri-devel mailing list