[PATCH v3] DRM: Add DRM kms/fb cma helper
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Thu Jul 19 08:46:02 PDT 2012
Hi Lars,
On Thursday 19 July 2012 17:12:28 Lars-Peter Clausen wrote:
> On 07/19/2012 04:57 PM, Lars-Peter Clausen wrote:
> > On 07/19/2012 04:41 PM, Laurent Pinchart wrote:
> >> On Thursday 19 July 2012 16:02:41 Laurent Pinchart wrote:
> >>> On Thursday 19 July 2012 15:55:56 Lars-Peter Clausen wrote:
> >>>> On 07/19/2012 03:33 PM, Laurent Pinchart wrote:
> >>>>> On Thursday 19 July 2012 15:34:26 Lars-Peter Clausen wrote:
> >>>>>> On 07/19/2012 02:46 PM, Laurent Pinchart wrote:
> >>>>>>> On Monday 02 July 2012 16:37:47 Lars-Peter Clausen wrote:
> >>>>>>>> This patchset introduces a set of helper function for implementing
> >>>>>>>> the KMS framebuffer layer for drivers which use the drm gem CMA
> >>>>>>>> helper function.
> >>>>>>>>
> >>>>>>>> Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
> >>>>>>>>
> >>>>>>>> ---
> >>>>>>>> Note: This patch depends on Sascha's "DRM: add drm gem CMA helper"
> >>>>>>>> patch
> >>>>>>>>
> >>>>>>>> Changes since v2:
> >>>>>>>> * Adapt to changes in the GEM CMA helper
> >>>>>>>> * Add basic buffer size checking in drm_fb_cma_create
> >>>>>>>>
> >>>>>>>> Changes since v1:
> >>>>>>>> * Some spelling fixes
> >>>>>>>> * Add missing kfree in drm_fb_cma_alloc error path
> >>>>>>>> * Add multi-plane support
> >>>>>>>>
> >>>>>>>> ---
> >>>>>>>>
> >>>>>>>> drivers/gpu/drm/Kconfig | 10 +
> >>>>>>>> drivers/gpu/drm/Makefile | 1 +
> >>>>>>>> drivers/gpu/drm/drm_fb_cma_helper.c | 393
> >>>>>>>> +++++++++++++++++++++++++++
> >>>>>>>> include/drm/drm_fb_cma_helper.h | 27 +++
> >>>>>>>> 4 files changed, 431 insertions(+)
> >>>>>>>> create mode 100644 drivers/gpu/drm/drm_fb_cma_helper.c
> >>>>>>>> create mode 100644 include/drm/drm_fb_cma_helper.h
> >>>>>>>
> >>>>>>> [snip]
> >>>>>>>
> >>>>>>>> diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c
> >>>>>>>> b/drivers/gpu/drm/drm_fb_cma_helper.c new file mode 100644
> >>>>>>>> index 0000000..9042233
> >>>>>>>> --- /dev/null
> >>>>>>>> +++ b/drivers/gpu/drm/drm_fb_cma_helper.c
> >>>>>>>
> >>>>>>> [snip]
> >>>>>>>
> >>>>>>>> +/**
> >>>>>>>> + * drm_fb_cma_create() - (struct drm_mode_config_funcs
> >>>>>>>> *)->fb_create
> >>>>>>>> callback function
> >>>>>>>> + *
> >>>>>>>> + * If your hardware has special alignment or pitch requirements
> >>>>>>>> these
> >>>>>>>> should be
> >>>>>>>> + * checked before calling this function.
> >>>>>>>> + */
> >>>>>>>> +struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
> >>>>>>>> + struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
> >>>>>>>> +{
> >>>>>>>> + struct drm_fb_cma *fb_cma;
> >>>>>>>> + struct drm_gem_cma_object *objs[4];
> >>>>>>>> + struct drm_gem_object *obj;
> >>>>>>>> + int ret;
> >>>>>>>> + int i;
> >>>>>>>> +
> >>>>>>>> + for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format);
> >>
> >> i++)
> >>
> >>>>>>>> {
> >>>>>>>> + obj = drm_gem_object_lookup(dev, file_priv, mode_cmd-
> >>>>>>
> >>>>>> handles[i]);
> >>>>>>
> >>>>>>>> + if (!obj) {
> >>>>>>>> + dev_err(dev->dev, "Failed to lookup GEM object\n");
> >>>>>>>> + ret = -ENXIO;
> >>>>>>>> + goto err_gem_object_unreference;
> >>>>>>>> + }
> >>>>>>>> +
> >>>>>>>> + if (obj->size < mode_cmd->height * mode_cmd->pitches[i]) {
> >>>>>>>
> >>>>>>> Shouldn't this be
> >>>>>>>
> >>>>>>> if (obj->size < mode_cmd->height * mode_cmd->pitches[i]
> >>>>>>>
> >>>>>>> + mode_cmd->offsets[i])
> >>>>>>>
> >>>>>>> ?
> >>>>>>
> >>>>>> That's actually a good question. I'd expect the offset to be included
> >>>>>> in the pitch.
> >>>>>>
> >>>>>> If you access pixels like mem[offset + x * bpp + y * pitch] then
> >>>>>> pitch has to be greater equal to offset + max_x * bpp, otherwise
> >>>>>> you'd have overlapping lines.
> >>>>>
> >>>>> My understanding is that the offset is a linear offset from the start
> >>>>> of the buffer to allow X/Y panning. In that case the pitch is a frame
> >>>>> buffer property that is not be influenced by the offset at all.
> >>>>
> >>>> Hi,
> >>>>
> >>>> I think panning is normally done by setting the x and y offset for the
> >>>> crtc.
> >>>>
> >>>> But yes, you are right the offset might just be a linear offset to the
> >>>> start of the actual data. I was just thinking about the case where the
> >>>> different planes are interleaved. But for panning or non-interleaved
> >>>> planes it obviously is different.
> >>>>
> >>>> Though this leaves us with a problem. If the planes are interleaved and
> >>>> the offset is included in the pitch your check may fail, even though
> >>>> the buffer is large enough.
> >>>>
> >>>> Maybe we need to handle both cases differently. If offset < pitch check
> >>>> for
> >>>> obj->size < mode_cmd->height * mode_cmd->pitches[i] otherwise check for
> >>>> obj->size < mode_cmd->height * mode_cmd->pitches[i] +
> >>>> mode_cmd->offsets[i]
> >>>>
> >>>> But that doesn't quite work either if you have both interleaved planes
> >>>> and a linear offset...
> >>>
> >>> What about first finding out what those offsets are supposed to be used
> >>> for
> >>> ?
> >>>
> >>> Ville, git blame points to you as the author of the offsets field :-)
> >>> Could you please comment on this ?
> >>
> >> My bad, I was looking at drm_framebuffer and not drm_mode_fb_cmd2.
> >>
> >> Offset really looks like it is a linear offset from the beginning of the
> >> buffer. This allows placing several planes at different locations in a
> >> single buffer. I think we need to add mode_cmd->offsets[i]
> >> unconditionally when checking the size.
> >
> > There are two cases to consider interleaved and non-interleaved planes in
> > a single buffer.
> >
> > a) Separate planes
> > [Y Y Y Y ....]
> > [Y Y Y Y ....]
> > [ .......... ]
> > [Y Y Y Y ....]
> > [CBCR CBCR CBCR CBCR .... ]
> > [CBCR CBCR CBCR CBCR .... ]
> > [ ....................... ]
> > [CBCR CBCR CBCR CBCR .... ]
> >
> > Plane 0:
> > bpp = 1
> > offset = 0
> >
> > Plane 1:
> > bpp = 1
> > offset = plane0_size
> >
> >
> > b) Interleaved planes
> > [Y CBCR Y CBCR Y CBCR ....]
> > [Y CBCR Y CBCR Y CBCR ....]
> > [ ....................... ]
> > [Y CBCR Y CBCR Y CBCR ....]
> >
> > Plane 0:
> > bbp = 2
> > offset = 0
> >
> > Plane 1:
> > bbp = 2
> > offset = 1
>
> To make things more complicated add:
>
> c) Line interleaved planes
>
> [Y Y Y Y .... ]
> [CBCR CBCR CBCR CBCR .... ]
> [Y Y Y Y .... ]
> [CBCR CBCR CBCR CBCR .... ]
> [ ....................... ]
This is a valid use case, and I see the issue. We need to take into account
the fact that the last line of each plane doesn't include padding.
> So maybe:
>
> min_size = height * pitch;
> min_size -= bpp - drm_format_plane_cpp();
> min_size -= pitch - width * bpp;
> min_size += offset;
What about
hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
for ( ... ) {
...
width = mode_cmd->width / (i ? hsub : 1);
height = mode_cmd->height / (i ? vsub : 1);
min_size = (height - 1) * mode_cmd->pitches[i]
+ width * drm_format_plane_cpp(mode_cmd->pixel_format, i)
+ mode_cmd->offsets[i];
...
}
--
Regards,
Laurent Pinchart
More information about the dri-devel
mailing list