[Intel-gfx] [PATCH 15/23] drm/i915: Link planes in a bigjoiner configuration.
Matt Roper
matthew.d.roper at intel.com
Tue Oct 1 16:44:09 UTC 2019
On Fri, Sep 20, 2019 at 01:42:27PM +0200, Maarten Lankhorst wrote:
> Make sure that when a plane is set in a bigjoiner mode, we will add
> their counterpart to the atomic state as well. This will allow us to
> make sure all state is available when planes are checked.
>
> Because of the funny interactions with bigjoiner and planar YUV
> formats, we may end up adding a lot of planes, so we have to keep
> iterating until we no longer add any planes.
>
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
> ---
> .../gpu/drm/i915/display/intel_atomic_plane.c | 31 +++-
> .../gpu/drm/i915/display/intel_atomic_plane.h | 4 +
> drivers/gpu/drm/i915/display/intel_display.c | 142 ++++++++++++++++--
> .../drm/i915/display/intel_display_types.h | 11 ++
> 4 files changed, 172 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
> index 964db7774d10..cc088676f0a2 100644
> --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c
> +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
> @@ -182,16 +182,36 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
> old_plane_state, new_plane_state);
> }
>
> -static struct intel_crtc *
> -get_crtc_from_states(const struct intel_plane_state *old_plane_state,
> - const struct intel_plane_state *new_plane_state)
> -{
> +struct intel_crtc *
> +intel_plane_get_crtc_from_states(struct intel_atomic_state *state,
This function name seems ambiguous now since it isn't clear whether
we're getting the plane's hardware CRTC or its uapi CRTC. Maybe call it
something like intel_plane_state_get_uapi_crtc()?
> + const struct intel_plane_state *old_plane_state,
> + const struct intel_plane_state *new_plane_state)
> + {
> + struct drm_i915_private *dev_priv = to_i915(state->base.dev);
> + struct intel_plane *plane = to_intel_plane(new_plane_state->base.plane);
> +
> if (new_plane_state->base.crtc)
> return to_intel_crtc(new_plane_state->base.crtc);
>
> if (old_plane_state->base.crtc)
> return to_intel_crtc(old_plane_state->base.crtc);
>
> + if (new_plane_state->bigjoiner_slave) {
> + const struct intel_plane_state *new_master_plane_state =
> + intel_atomic_get_new_plane_state(state, new_plane_state->bigjoiner_plane);
> +
> + if (new_master_plane_state->base.crtc)
> + return intel_get_crtc_for_pipe(dev_priv, plane->pipe);
> + }
Will this cause problems if we adjust properties of planes on a a
uapi-disabled CRTC? E.g., I believe userspace can fiddle with stuff
like rotation properties on disabled planes/crtcs and now I believe that
causes us to needlessly pull in the bigjoiner master crtc and
corresponding plane?
> +
> + if (old_plane_state->bigjoiner_slave) {
> + const struct intel_plane_state *old_master_plane_state =
> + intel_atomic_get_old_plane_state(state, old_plane_state->bigjoiner_plane);
> +
> + if (old_master_plane_state->base.crtc)
> + return intel_get_crtc_for_pipe(dev_priv, plane->pipe);
> + }
> +
> return NULL;
> }
>
> @@ -206,7 +226,8 @@ static int intel_plane_atomic_check(struct drm_plane *_plane,
> const struct intel_plane_state *old_plane_state =
> intel_atomic_get_old_plane_state(state, plane);
> struct intel_crtc *crtc =
> - get_crtc_from_states(old_plane_state, new_plane_state);
> + intel_plane_get_crtc_from_states(state, old_plane_state,
> + new_plane_state);
> const struct intel_crtc_state *old_crtc_state;
> struct intel_crtc_state *new_crtc_state;
>
> diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h b/drivers/gpu/drm/i915/display/intel_atomic_plane.h
> index 33fb85cd3909..901a50e6e2d3 100644
> --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h
> +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.h
> @@ -42,5 +42,9 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat
> struct intel_crtc_state *crtc_state,
> const struct intel_plane_state *old_plane_state,
> struct intel_plane_state *plane_state);
> +struct intel_crtc *
> +intel_plane_get_crtc_from_states(struct intel_atomic_state *state,
> + const struct intel_plane_state *old_plane_state,
> + const struct intel_plane_state *new_plane_state);
>
> #endif /* __INTEL_ATOMIC_PLANE_H__ */
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index df588bf47559..06ceac4f1436 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -11811,24 +11811,101 @@ static bool check_single_encoder_cloning(struct drm_atomic_state *state,
> return true;
> }
>
> +static int icl_add_dependent_planes(struct intel_atomic_state *state,
> + struct intel_plane_state *plane_state)
> +{
> + struct intel_plane_state *new_plane_state;
> + struct intel_plane *plane;
> + int ret = 0;
> +
> + plane = plane_state->bigjoiner_plane;
> + if (plane && !intel_atomic_get_new_plane_state(state, plane)) {
> + new_plane_state = intel_atomic_get_plane_state(state, plane);
> + if (IS_ERR(new_plane_state))
> + return PTR_ERR(new_plane_state);
> +
> + ret = 1;
> + }
> +
> + plane = plane_state->planar_linked_plane;
> + if (plane && !intel_atomic_get_new_plane_state(state, plane)) {
> + new_plane_state = intel_atomic_get_plane_state(state, plane);
> + if (IS_ERR(new_plane_state))
> + return PTR_ERR(new_plane_state);
> +
> + ret = 1;
> + }
> +
> + return ret;
> +}
> +
> static int icl_add_linked_planes(struct intel_atomic_state *state)
> {
> - struct intel_plane *plane, *linked;
> - struct intel_plane_state *plane_state, *linked_plane_state;
> + struct intel_plane *plane;
> + struct intel_plane_state *old_plane_state, *new_plane_state;
> + struct intel_crtc *crtc, *linked_crtc;
> + struct intel_crtc_state *old_crtc_state, *new_crtc_state, *linked_crtc_state;
> + bool added;
> int i;
>
> - for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
> - linked = plane_state->planar_linked_plane;
> + /*
> + * Iteratively add plane_state->linked_plane and plane_state->bigjoiner_plane
> + *
> + * This needs to be done repeatedly, because of is a funny interaction;
> + * the Y-plane may be assigned differently on the other bigjoiner crtc,
> + * and we could end up with the following evil recursion, when only adding a
> + * single plane to state:
> + *
> + * XRGB8888 master plane 6 adds NV12 slave Y-plane 6, which adds slave UV plane 0,
> + * which adds master UV plane 0, which adds master Y-plane 7, which adds XRGB8888
> + * slave plane 7.
> + *
> + * We could pull in even more because of old_plane_state vs new_plane_state.
> + *
> + * Max depth = 5 (or 7 for evil case) in this case.
> + * Number of passes will be less, because newly added planes show up in the
> + * same iteration round when added_plane->index > plane->index.
> + */
> + do {
> + added = false;
>
> - if (!linked)
> - continue;
> + for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
> + int ret, ret2;
> +
> + ret = icl_add_dependent_planes(state, old_plane_state);
> + if (ret < 0)
> + return ret;
> +
> + ret2 = icl_add_dependent_planes(state, new_plane_state);
> + if (ret2 < 0)
> + return ret2;
>
> - linked_plane_state = intel_atomic_get_plane_state(state, linked);
> - if (IS_ERR(linked_plane_state))
> - return PTR_ERR(linked_plane_state);
> + added |= ret || ret2;
> + }
> + } while (added);
> +
> + /*
> + * Make sure bigjoiner slave crtc's are also pulled in. This is not done automatically
> + * when adding slave planes, because plane_state->crtc is null.
> + */
> + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
> + linked_crtc = old_crtc_state->bigjoiner_linked_crtc;
> + if (linked_crtc) {
> + linked_crtc_state =
> + intel_atomic_get_crtc_state(&state->base, linked_crtc);
> +
> + if (IS_ERR(linked_crtc_state))
> + return PTR_ERR(linked_crtc_state);
> + }
> +
> + linked_crtc = new_crtc_state->bigjoiner_linked_crtc;
> + if (linked_crtc && linked_crtc != old_crtc_state->bigjoiner_linked_crtc) {
> + linked_crtc_state =
> + intel_atomic_get_crtc_state(&state->base, linked_crtc);
>
> - WARN_ON(linked_plane_state->planar_linked_plane != plane);
> - WARN_ON(linked_plane_state->planar_slave == plane_state->planar_slave);
> + if (IS_ERR(linked_crtc_state))
> + return PTR_ERR(linked_crtc_state);
> + }
> }
>
> return 0;
> @@ -13799,6 +13876,7 @@ static int intel_atomic_check_bigjoiner(struct intel_atomic_state *state)
> struct drm_i915_private *dev_priv = to_i915(state->base.dev);
> struct intel_crtc_state *old_crtc_state, *new_crtc_state, *slave_crtc_state, *master_crtc_state;
> struct intel_crtc *crtc, *slave, *master;
> + struct intel_plane *plane;
> int i, ret = 0;
>
> if (INTEL_GEN(dev_priv) < 11)
> @@ -13894,6 +13972,48 @@ static int intel_atomic_check_bigjoiner(struct intel_atomic_state *state)
> return ret;
> }
>
> + /*
> + * Setup and teardown the new bigjoiner plane mappings.
> + */
> + for_each_intel_plane(&dev_priv->drm, plane) {
> + struct intel_plane_state *plane_state;
> + struct intel_plane *other_plane = NULL;
> +
> + crtc = intel_get_crtc_for_pipe(dev_priv, plane->pipe);
> + old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
> + new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
> +
> + if (!new_crtc_state || !needs_modeset(new_crtc_state))
> + continue;
> +
> + if (new_crtc_state->bigjoiner) {
> + struct intel_crtc *other_crtc =
> + new_crtc_state->bigjoiner_linked_crtc;
> + bool found = false;
> +
> + for_each_intel_plane_on_crtc(&dev_priv->drm, other_crtc, other_plane) {
> + if (other_plane->id != plane->id)
> + continue;
> +
> + found = true;
> + break;
> + }
> +
> + /* All pipes should have identical planes. */
> + if (WARN_ON(!found))
> + return -EINVAL;
> + } else if (!old_crtc_state->bigjoiner) {
> + continue;
> + }
> +
> + plane_state = intel_atomic_get_plane_state(state, plane);
> + if (IS_ERR(plane_state))
> + return PTR_ERR(plane_state);
> +
> + plane_state->bigjoiner_plane = other_plane;
> + plane_state->bigjoiner_slave = new_crtc_state->bigjoiner_slave;
> + }
Is my understanding correct that we always grab the corresponding plane
on the other CRTC when the big joiner is active? I.e., even in cases
where the uapi plane is restricted to just one half of the screen, we're
still going to grab the bigjoiner slave plane? I guess trying to
restrict this to only cases where the uapi plane covers both pipes would
make this whole thing even more complicated.
Matt
> +
> return 0;
> }
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index ace372a76330..f05f4830a529 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -571,6 +571,17 @@ struct intel_plane_state {
> */
> struct intel_plane *planar_linked_plane;
>
> + /*
> + * bigjoiner_plane:
> + *
> + * When 2 pipes are joined in a bigjoiner configuration,
> + * points to the same plane on the other pipe.
> + *
> + * bigjoiner_slave is set on the slave pipe.
> + */
> + struct intel_plane *bigjoiner_plane;
> + u32 bigjoiner_slave;
> +
> /*
> * planar_slave:
> * If set don't update use the linked plane's state for updating
> --
> 2.20.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Matt Roper
Graphics Software Engineer
VTT-OSGC Platform Enablement
Intel Corporation
(916) 356-2795
More information about the Intel-gfx
mailing list