[PATCH 2/6] drm/shmem-helper: Add additional KMS helpers

Daniel Vetter daniel at ffwll.ch
Wed Feb 3 14:57:31 UTC 2021


On Wed, Feb 3, 2021 at 3:26 PM Thomas Zimmermann <tzimmermann at suse.de> wrote:
>
> Hi
>
> Am 03.02.21 um 15:01 schrieb Daniel Vetter:
> > On Wed, Feb 03, 2021 at 02:10:42PM +0100, Thomas Zimmermann wrote:
> >> Several drivers use GEM SHMEM buffer objects as shadow buffers for
> >> the actual framebuffer memory. Right now, drivers do these vmap
> >> operations in their commit tail, which is actually not allowed by the
> >> locking rules for the dma-buf reservation lock. The involved SHMEM
> >> BO has to be vmapped in the plane's prepare_fb callback and vunmapped
> >> in cleanup_fb.
> >>
> >> This patch introduces a DRM library that implements KMS helpers for
> >> GEM SHMEM buffer objects. The first set of helpers is the plane state
> >> for shadow planes. The provided implementations for prepare_fb and
> >> cleanup_fb vmap and vunmap all BOs of struct drm_plane_state.fb. The
> >> mappings are afterwards available in the plane's commit-tail functions.
> >>
> >> All rsp drivers use the simple KMS helpers, so we add the plane callbacks
> >> and wrappers for simple KMS.
> >>
> >> Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
> >> ---
> >>   drivers/gpu/drm/Kconfig                    |   7 +
> >>   drivers/gpu/drm/Makefile                   |   1 +
> >>   drivers/gpu/drm/drm_gem_shmem_kms_helper.c | 159 +++++++++++++++++++++
> >>   include/drm/drm_gem_shmem_kms_helper.h     |  56 ++++++++
> >>   4 files changed, 223 insertions(+)
> >>   create mode 100644 drivers/gpu/drm/drm_gem_shmem_kms_helper.c
> >>   create mode 100644 include/drm/drm_gem_shmem_kms_helper.h
> >>
> >> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> index 8bf103de1594..b8d8b00ab5d4 100644
> >> --- a/drivers/gpu/drm/Kconfig
> >> +++ b/drivers/gpu/drm/Kconfig
> >> @@ -214,6 +214,13 @@ config DRM_GEM_SHMEM_HELPER
> >>      help
> >>        Choose this if you need the GEM shmem helper functions
> >>
> >> +config DRM_GEM_SHMEM_KMS_HELPER
> >> +    bool
> >> +    depends on DRM_GEM_SHMEM_HELPER
> >> +    help
> >> +    help
> >> +      Choose this if you need the GEM SHMEM helper functions for KMS
> >
> > I think we should just stuff this into simple pipe helpers directly. Also
> > needs some kerneldoc and ideally intro section of some sorts, but I guess
> > that was just missing for RFC.
>
> The missing docs is why it's an RFC. i was concerned about the
> additional simple-pipe callbacks, but I'm glad you're OK with them. I
> thought about simple_pipe state (as you mentioned below) or
> drm_private_state, but found it all too complex for this simple problem.

Yeah I think for this it's overkill, and it shouldn't be hard to add a
simple_pipe_state later on. Imo once you need a private state your
driver has proably outgrown simple pipe helpers.

> > Thinking a bit bigger and looking at the first patch, I wonder whether we
> > shouldn't outright integrate this simple pipe helpers. Adding all the
> > hooks for plane_state (instead of a simple_pipe_state or something like
> > that) feels a bit icky to me. But on the driver side the integration with
> > just the single macro line is very neat, so that's redeeming feature.
>
> I do disagree with integrating the shadow-plane code into simple-pipe.
> Right now it's SHMEM-depended and CMA-based simple-pipe drivers would
> probably not want to depend on this. The other reason is that I can
> certainly generalize the shadow planes away from SHMEM helpers; and use
> them for these vbox and ast patchsets as well. These drivers use VRAM
> helpers and full KMS helpers. I guess shadow planes could then be moved
> into drm_gem_framebuffer.c. There's other plane-helper code there already.
>
> Unfortunately, I only realized this after sending out the patch set. :)

Yeah I also noticed we have the current simple gem fb helper in there
already, so maybe just stuff it in there. Whether the simple glue for
shme/gem/cma/whatever integration is in drm_simple_pipe.c or
drm_gem_framebuffer.c kinda doesn't matter much. Just yet another
library felt a bit like overkill.

Cheers, Daniel

>
> Best regards
> Thomas
>
> >
> > Note doing a drm_simple_display_pipe_state would be a bit tricky to do,
> > since we'd need custome duplicate_state functions to make sure there's
> > only ever exactly one:
> >
> > struct drm_simple_display_pipe_state {
> >       struct drm_crtc_state crtc_state;
> >       struct drm_plane_state plane_state;
> >
> >       struct dma_buf_map map[4];
> > };
> >
> > But that's a bit a bigger step, maybe when we also need to subclass crtc
> > stuff we can look into this. Or maybe that's then too much feature creep,
> > dunno. Implemenation shouldn't be too tricky:
> > - crtc state just duplicates itself (including plane_state duplication).
> >    In release it also cleans up the plane state.
> > - plane state grabs the crtc state instead, and then does a cast. destroy
> >    hook does nothing (to avoid touching freed memory, since we always dupe
> >    the crtc state when the plane state exists we know the crtc destroy hook
> >    will clean things up).
> >
> > That means drm_atomic_state has 2 pointers pointing into the same
> > allocation, but that should be all fine.
> >
> > Aside from this bikeshed here pondering a bit how this best first into our
> > simple pipe helpers I think this all looks very clean.
> > -Daniel
> >
> >> +
> >>   config DRM_SCHED
> >>      tristate
> >>      depends on DRM
> >> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> >> index 926adef289db..37a73dee5baf 100644
> >> --- a/drivers/gpu/drm/Makefile
> >> +++ b/drivers/gpu/drm/Makefile
> >> @@ -53,6 +53,7 @@ drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
> >>   drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
> >>   drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
> >>   drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
> >> +drm_kms_helper-$(CONFIG_DRM_GEM_SHMEM_KMS_HELPER) += drm_gem_shmem_kms_helper.o
> >>
> >>   obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
> >>   obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
> >> diff --git a/drivers/gpu/drm/drm_gem_shmem_kms_helper.c b/drivers/gpu/drm/drm_gem_shmem_kms_helper.c
> >> new file mode 100644
> >> index 000000000000..8843c5837f98
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/drm_gem_shmem_kms_helper.c
> >> @@ -0,0 +1,159 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +
> >> +#include <drm/drm_atomic_state_helper.h>
> >> +#include <drm/drm_gem_framebuffer_helper.h>
> >> +#include <drm/drm_gem_shmem_helper.h>
> >> +#include <drm/drm_gem_shmem_kms_helper.h>
> >> +#include <drm/drm_simple_kms_helper.h>
> >> +
> >> +/*
> >> + * Helpers for struct drm_plane_funcs
> >> + *
> >> + */
> >> +
> >> +static struct drm_plane_state *
> >> +drm_gem_shmem_duplicate_shadow_plane_state(struct drm_plane *plane,
> >> +                                       struct drm_plane_state *plane_state)
> >> +{
> >> +    struct drm_gem_shmem_shadow_plane_state *new_shadow_plane_state;
> >> +
> >> +    if (!plane_state)
> >> +            return NULL;
> >> +
> >> +    new_shadow_plane_state = kzalloc(sizeof(*new_shadow_plane_state), GFP_KERNEL);
> >> +    if (!new_shadow_plane_state)
> >> +            return NULL;
> >> +    __drm_atomic_helper_plane_duplicate_state(plane, &new_shadow_plane_state->base);
> >> +
> >> +    return &new_shadow_plane_state->base;
> >> +}
> >> +
> >> +static void drm_gem_shmem_destroy_shadow_plane_state(struct drm_plane *plane,
> >> +                                                 struct drm_plane_state *plane_state)
> >> +{
> >> +    struct drm_gem_shmem_shadow_plane_state *shadow_plane_state =
> >> +            to_drm_gem_shmem_shadow_plane_state(plane_state);
> >> +
> >> +    __drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base);
> >> +    kfree(shadow_plane_state);
> >> +}
> >> +
> >> +static void drm_gem_shmem_reset_shadow_plane(struct drm_plane *plane)
> >> +{
> >> +    struct drm_gem_shmem_shadow_plane_state *shadow_plane_state;
> >> +
> >> +    if (plane->state) {
> >> +            drm_gem_shmem_destroy_shadow_plane_state(plane, plane->state);
> >> +            plane->state = NULL; /* must be set to NULL here */
> >> +    }
> >> +
> >> +    shadow_plane_state = kzalloc(sizeof(*shadow_plane_state), GFP_KERNEL);
> >> +    if (!shadow_plane_state)
> >> +            return;
> >> +    __drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base);
> >> +}
> >> +
> >> +/*
> >> + * Helpers for struct drm_plane_helper_funcs
> >> + */
> >> +
> >> +static int drm_gem_shmem_prepare_shadow_fb(struct drm_plane *plane,
> >> +                                       struct drm_plane_state *plane_state)
> >> +{
> >> +    struct drm_gem_shmem_shadow_plane_state *shadow_plane_state =
> >> +            to_drm_gem_shmem_shadow_plane_state(plane_state);
> >> +    struct drm_framebuffer *fb = plane_state->fb;
> >> +    struct drm_gem_object *obj;
> >> +    struct dma_buf_map map;
> >> +    int ret;
> >> +    size_t i;
> >> +
> >> +    if (!fb)
> >> +            return 0;
> >> +
> >> +    ret = drm_gem_fb_prepare_fb(plane, plane_state);
> >> +    if (ret)
> >> +            return ret;
> >> +
> >> +    for (i = 0; i < ARRAY_SIZE(shadow_plane_state->map); ++i) {
> >> +            obj = drm_gem_fb_get_obj(fb, i);
> >> +            if (!obj)
> >> +                    continue;
> >> +            ret = drm_gem_shmem_vmap(obj, &map);
> >> +            if (ret)
> >> +                    goto err_drm_gem_shmem_vunmap;
> >> +            shadow_plane_state->map[i] = map;
> >> +    }
> >> +
> >> +    return 0;
> >> +
> >> +err_drm_gem_shmem_vunmap:
> >> +    while (i) {
> >> +            --i;
> >> +            obj = drm_gem_fb_get_obj(fb, i);
> >> +            if (!obj)
> >> +                    continue;
> >> +            drm_gem_shmem_vunmap(obj, &shadow_plane_state->map[i]);
> >> +    }
> >> +    return ret;
> >> +}
> >> +
> >> +static void drm_gem_shmem_cleanup_shadow_fb(struct drm_plane *plane,
> >> +                                        struct drm_plane_state *plane_state)
> >> +{
> >> +    struct drm_gem_shmem_shadow_plane_state *shadow_plane_state =
> >> +            to_drm_gem_shmem_shadow_plane_state(plane_state);
> >> +    struct drm_framebuffer *fb = plane_state->fb;
> >> +    size_t i = ARRAY_SIZE(shadow_plane_state->map);
> >> +    struct drm_gem_object *obj;
> >> +
> >> +    if (!fb)
> >> +            return;
> >> +
> >> +    while (i) {
> >> +            --i;
> >> +            obj = drm_gem_fb_get_obj(fb, i);
> >> +            if (!obj)
> >> +                    continue;
> >> +            drm_gem_shmem_vunmap(obj, &shadow_plane_state->map[i]);
> >> +    }
> >> +}
> >> +
> >> +/*
> >> + * Simple KMS helpers
> >> + */
> >> +
> >> +int drm_gem_shmem_simple_kms_prepare_shadow_fb(struct drm_simple_display_pipe *pipe,
> >> +                                           struct drm_plane_state *plane_state)
> >> +{
> >> +    return drm_gem_shmem_prepare_shadow_fb(&pipe->plane, plane_state);
> >> +}
> >> +EXPORT_SYMBOL(drm_gem_shmem_simple_kms_prepare_shadow_fb);
> >> +
> >> +void drm_gem_shmem_simple_kms_cleanup_shadow_fb(struct drm_simple_display_pipe *pipe,
> >> +                                            struct drm_plane_state *plane_state)
> >> +{
> >> +    drm_gem_shmem_cleanup_shadow_fb(&pipe->plane, plane_state);
> >> +}
> >> +EXPORT_SYMBOL(drm_gem_shmem_simple_kms_cleanup_shadow_fb);
> >> +
> >> +void drm_gem_shmem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe)
> >> +{
> >> +    drm_gem_shmem_reset_shadow_plane(&pipe->plane);
> >> +}
> >> +EXPORT_SYMBOL(drm_gem_shmem_simple_kms_reset_shadow_plane);
> >> +
> >> +struct drm_plane_state *
> >> +drm_gem_shmem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe *pipe,
> >> +                                                  struct drm_plane_state *plane_state)
> >> +{
> >> +    return drm_gem_shmem_duplicate_shadow_plane_state(&pipe->plane, plane_state);
> >> +}
> >> +EXPORT_SYMBOL(drm_gem_shmem_simple_kms_duplicate_shadow_plane_state);
> >> +
> >> +void drm_gem_shmem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pipe *pipe,
> >> +                                                     struct drm_plane_state *plane_state)
> >> +{
> >> +    drm_gem_shmem_destroy_shadow_plane_state(&pipe->plane, plane_state);
> >> +}
> >> +EXPORT_SYMBOL(drm_gem_shmem_simple_kms_destroy_shadow_plane_state);
> >> diff --git a/include/drm/drm_gem_shmem_kms_helper.h b/include/drm/drm_gem_shmem_kms_helper.h
> >> new file mode 100644
> >> index 000000000000..bd42c9c0a39e
> >> --- /dev/null
> >> +++ b/include/drm/drm_gem_shmem_kms_helper.h
> >> @@ -0,0 +1,56 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +
> >> +#ifndef __DRM_GEM_SHMEM_KMS_HELPER_H__
> >> +#define __DRM_GEM_SHMEM_KMS_HELPER_H__
> >> +
> >> +#include <linux/dma-buf-map.h>
> >> +
> >> +#include <drm/drm_plane.h>
> >> +
> >> +struct drm_simple_display_pipe;
> >> +
> >> +struct drm_gem_shmem_shadow_plane_state {
> >> +    struct drm_plane_state base;
> >> +
> >> +    /* Transitional state - do not export or duplicate */
> >> +
> >> +    struct dma_buf_map map[4];
> >> +};
> >> +
> >> +static inline struct drm_gem_shmem_shadow_plane_state *
> >> +to_drm_gem_shmem_shadow_plane_state(struct drm_plane_state *state)
> >> +{
> >> +    return container_of(state, struct drm_gem_shmem_shadow_plane_state, base);
> >> +}
> >> +
> >> +/*
> >> + * Simple KMS helpers
> >> + */
> >> +
> >> +int drm_gem_shmem_simple_kms_prepare_shadow_fb(struct drm_simple_display_pipe *pipe,
> >> +                                           struct drm_plane_state *plane_state);
> >> +void drm_gem_shmem_simple_kms_cleanup_shadow_fb(struct drm_simple_display_pipe *pipe,
> >> +                                            struct drm_plane_state *plane_state);
> >> +void drm_gem_shmem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe);
> >> +struct drm_plane_state *
> >> +drm_gem_shmem_simple_kms_duplicate_shadow_plane_state(struct drm_simple_display_pipe *pipe,
> >> +                                                  struct drm_plane_state *plane_state);
> >> +void
> >> +drm_gem_shmem_simple_kms_destroy_shadow_plane_state(struct drm_simple_display_pipe *pipe,
> >> +                                                struct drm_plane_state *plane_state);
> >> +
> >> +/**
> >> + * DRM_GEM_SHMEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS -
> >> + *  Initializes struct drm_simple_display_pipe_funcs for SHMEM shadow planes
> >> + *
> >> + * Drivers may use GEM SHMEM BOs as shadow buffers over the framebuffer memory. This
> >> + * macro initializes struct drm_simple_display_pipe_funcs to use the rsp helper functions.
> >> + */
> >> +#define DRM_GEM_SHMEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS \
> >> +    .prepare_fb = drm_gem_shmem_simple_kms_prepare_shadow_fb, \
> >> +    .cleanup_fb = drm_gem_shmem_simple_kms_cleanup_shadow_fb, \
> >> +    .reset_plane = drm_gem_shmem_simple_kms_reset_shadow_plane, \
> >> +    .duplicate_plane_state = drm_gem_shmem_simple_kms_duplicate_shadow_plane_state, \
> >> +    .destroy_plane_state   = drm_gem_shmem_simple_kms_destroy_shadow_plane_state
> >> +
> >> +#endif /* __DRM_GEM_SHMEM_KMS_HELPER_H__ */
> >> --
> >> 2.30.0
> >>
> >
>
> --
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
>


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the dri-devel mailing list