Re: [PATCH v6 9/9] drm/omap: Add a 'right overlay' to plane state

From: Neil Armstrong
Date: Tue Nov 09 2021 - 08:31:34 EST


Hi,

On 27/10/2021 14:50, Tomi Valkeinen wrote:
> On 18/10/2021 17:28, Neil Armstrong wrote:
>> From: Benoit Parrot <bparrot@xxxxxx>
>>
>> If the drm_plane has a source width that's greater than the max width
>> supported by a single hw overlay, then we assign a 'r_overlay' to it in
>> omap_plane_atomic_check().
>>
>> Both overlays should have the capabilities required to handle the source
>> framebuffer. The only parameters that vary between the left and right
>> hwoverlays are the src_w, crtc_w, src_x and crtc_x as we just even chop
>> the fb into left and right halves.
>>
>> We also take care of not creating odd width size when dealing with YUV
>> formats.
>>
>> Since both halves need to be 'appear' side by side the zpos is
>> recalculated when dealing with dual overlay cases so that the other
>> planes zpos is consistent.
>>
>> Depending on user space usage it is possible that on occasion the number
>> of requested planes exceeds the numbers of overlays required to display
>> them. In that case a failure would be returned for the plane that cannot
>> be handled at that time. It is up to user space to make sure the H/W
>> resource are not over-subscribed.
>>
>> Signed-off-by: Benoit Parrot <bparrot@xxxxxx>
>> Signed-off-by: Neil Armstrong <narmstrong@xxxxxxxxxxxx>
>> ---
>>   drivers/gpu/drm/omapdrm/omap_drv.c     |  91 ++++++++++++++++++-
>>   drivers/gpu/drm/omapdrm/omap_fb.c      |  33 ++++++-
>>   drivers/gpu/drm/omapdrm/omap_fb.h      |   4 +-
>>   drivers/gpu/drm/omapdrm/omap_overlay.c |  23 ++++-
>>   drivers/gpu/drm/omapdrm/omap_overlay.h |   3 +-
>>   drivers/gpu/drm/omapdrm/omap_plane.c   | 120 +++++++++++++++++++++++--
>>   drivers/gpu/drm/omapdrm/omap_plane.h   |   1 +
>>   7 files changed, 263 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
>> index c7912374d393..f088b6313950 100644
>> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
>> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
>> @@ -117,6 +117,95 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state)
>>       dispc_runtime_put(priv->dispc);
>>   }
>>   +static int drm_atomic_state_normalized_zpos_cmp(const void *a, const void *b)
>> +{
>> +    const struct drm_plane_state *sa = *(struct drm_plane_state **)a;
>> +    const struct drm_plane_state *sb = *(struct drm_plane_state **)b;
>> +
>> +    if (sa->normalized_zpos != sb->normalized_zpos)
>> +        return sa->normalized_zpos - sb->normalized_zpos;
>> +    else
>> +        return sa->plane->base.id - sb->plane->base.id;
>> +}
>
> I think this, or the function below, needs a comment. I don't think it's obvious what's the logic here. It's mostly a copy of drm_atomic_normalize_zpos and drm_atomic_helper_crtc_normalize_zpos, if I'm not mistaken, it migth be good to point out what the difference is.

It's explained in the commit message:
>> Since both halves need to be 'appear' side by side the zpos is
>> recalculated when dealing with dual overlay cases so that the other
>> planes zpos is consistent.

Not sure what to add more, should I add it as comment in the code ?

>
> I'm also wondering if these normalize_zpos functions should be split to a separate patch (without the is_omap_plane_dual_overlay call part).

It's tied to the introduction of 'right overlay', impossible to implement it without the
dual overlays functions and variables.

>
>> +static int omap_atomic_update_normalize_zpos(struct drm_device *dev,
>> +                         struct drm_atomic_state *state)
>> +{
>> +    struct drm_crtc *crtc;
>> +    struct drm_crtc_state *old_state, *new_state;
>> +    struct drm_plane *plane;
>> +    int c, i, n, inc;
>> +    int total_planes = dev->mode_config.num_total_plane;
>> +    struct drm_plane_state **states;
>> +    int ret = 0;
>> +
>> +    states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL);
>> +    if (!states)
>> +        return -ENOMEM;
>> +
>> +    for_each_oldnew_crtc_in_state(state, crtc, old_state, new_state, c) {
>> +        if (old_state->plane_mask == new_state->plane_mask &&
>> +            !new_state->zpos_changed)
>> +            continue;
>> +
>> +        /* Reset plane increment and index value for every crtc */
>> +        n = 0;
>> +
>> +        /*
>> +         * Normalization process might create new states for planes
>> +         * which normalized_zpos has to be recalculated.
>> +         */
>> +        drm_for_each_plane_mask(plane, dev, new_state->plane_mask) {
>> +            struct drm_plane_state *plane_state =
>> +                drm_atomic_get_plane_state(new_state->state,
>> +                               plane);
>> +            if (IS_ERR(plane_state)) {
>> +                ret = PTR_ERR(plane_state);
>> +                goto done;
>> +            }
>> +            states[n++] = plane_state;
>> +        }
>> +
>> +        sort(states, n, sizeof(*states),
>> +             drm_atomic_state_normalized_zpos_cmp, NULL);
>> +
>> +        for (i = 0, inc = 0; i < n; i++) {
>> +            plane = states[i]->plane;
>> +
>> +            states[i]->normalized_zpos = i + inc;
>> +            DRM_DEBUG_ATOMIC("[PLANE:%d:%s] updated normalized zpos value %d\n",
>> +                     plane->base.id, plane->name,
>> +                     states[i]->normalized_zpos);
>> +
>> +            if (is_omap_plane_dual_overlay(states[i]))
>> +                inc++;
>> +        }
>> +        new_state->zpos_changed = true;
>> +    }
>> +
>> +done:
>> +    kfree(states);
>> +    return ret;
>> +}
>> +
>> +static int omap_atomic_check(struct drm_device *dev,
>> +                 struct drm_atomic_state *state)
>> +{
>> +    int ret;
>> +
>> +    ret = drm_atomic_helper_check(dev, state);
>> +    if (ret)
>> +        return ret;
>> +
>> +    if (dev->mode_config.normalize_zpos) {
>> +        ret = omap_atomic_update_normalize_zpos(dev, state);
>> +        if (ret)
>> +            return ret;
>> +    }
>> +
>> +    return 0;
>> +}
>> +

[...]

Thanks,
Neil