[libcamera-devel,RFC,v2,2/5] libcamera: MappedFrameBuffer: Use stored plane offset
diff mbox series

Message ID 20230821131039.127370-3-gabbymg94@gmail.com
State New
Headers show
Series
  • Add UVC Metadata buffer timestamp support
Related show

Commit Message

Gabrielle George Aug. 21, 2023, 1:10 p.m. UTC
As it is written, the MappedFrameBuffer causes a failure in mmap when
attempting to map UVC metadata planes.  UVC metadata (four character
code UVCH) does not support exporting buffers as file descriptors, so
mmap can be used to give libcamera access to the metadata buffer
planes. It is convenient to use the already-existing
MappedFrameBuffers class, but the class must be modified to support
mapping using file descriptors of the video node itself.

To do this, mmap needs information obtained through a call to
QUERYBUF, namely, the plane offset for buffer planes. Modify the
constructor of a MappedFrameBuffer to use the plane offset directly in
the call to mmap, rather than the hard-coded 0 value.

The current version does not work when a buffer cannot be exported as
a dma buf fd. The fd argument to mmap must be the one obtained on a
call to open() for the video node (ie, /dev/videoX). This method of
mapping buffer planes requires the arguments to mmap to be exactly the
length and offset QUERYBUF provides.  Mmap will return a -EINVAL if
this is not the case.

Signed-off-by: Gabby George <gabbymg94@gmail.com>
---
 .../libcamera/internal/mapped_framebuffer.h   |  3 ++-
 src/libcamera/mapped_framebuffer.cpp          | 20 ++++++++++++++-----
 2 files changed, 17 insertions(+), 6 deletions(-)

Comments

Vedant Paranjape Aug. 21, 2023, 2:01 p.m. UTC | #1
Hello Gabby,

Thanks for your patch !

On Mon, Aug 21, 2023 at 6:40 PM Gabby George <gabbymg94@gmail.com> wrote:
>
> As it is written, the MappedFrameBuffer causes a failure in mmap when

s/As it is written/ /
s/the/The

> attempting to map UVC metadata planes.  UVC metadata (four character
> code UVCH) does not support exporting buffers as file descriptors, so
> mmap can be used to give libcamera access to the metadata buffer
> planes. It is convenient to use the already-existing
> MappedFrameBuffers class, but the class must be modified to support
> mapping using file descriptors of the video node itself.
>
> To do this, mmap needs information obtained through a call to
> QUERYBUF, namely, the plane offset for buffer planes. Modify the
> constructor of a MappedFrameBuffer to use the plane offset directly in
> the call to mmap, rather than the hard-coded 0 value.
>
> The current version does not work when a buffer cannot be exported as
> a dma buf fd. The fd argument to mmap must be the one obtained on a
> call to open() for the video node (ie, /dev/videoX). This method of
> mapping buffer planes requires the arguments to mmap to be exactly the
> length and offset QUERYBUF provides.  Mmap will return a -EINVAL if

s/Mmap/mmap

> this is not the case.
>
> Signed-off-by: Gabby George <gabbymg94@gmail.com>
> ---
>  .../libcamera/internal/mapped_framebuffer.h   |  3 ++-
>  src/libcamera/mapped_framebuffer.cpp          | 20 ++++++++++++++-----
>  2 files changed, 17 insertions(+), 6 deletions(-)
>
> diff --git a/include/libcamera/internal/mapped_framebuffer.h b/include/libcamera/internal/mapped_framebuffer.h
> index fb39adbf..04096d1b 100644
> --- a/include/libcamera/internal/mapped_framebuffer.h
> +++ b/include/libcamera/internal/mapped_framebuffer.h
> @@ -54,7 +54,8 @@ public:
>
>         using MapFlags = Flags<MapFlag>;
>
> -       MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags);
> +       MappedFrameBuffer(const FrameBuffer *buffer,
> +                         MapFlags flags, bool usePlaneOffset = false);
>  };
>
>  LIBCAMERA_FLAGS_ENABLE_OPERATORS(MappedFrameBuffer::MapFlag)
> diff --git a/src/libcamera/mapped_framebuffer.cpp b/src/libcamera/mapped_framebuffer.cpp
> index 6860069b..3d2cc332 100644
> --- a/src/libcamera/mapped_framebuffer.cpp
> +++ b/src/libcamera/mapped_framebuffer.cpp
> @@ -172,12 +172,13 @@ MappedBuffer::~MappedBuffer()
>   * \brief Map all planes of a FrameBuffer
>   * \param[in] buffer FrameBuffer to be mapped
>   * \param[in] flags Protection flags to apply to map
> + * \param[in] usePlaneOffset Use offset stored in buffer's plane; default false
>   *
>   * Construct an object to map a frame buffer for CPU access. The mapping can be
>   * made as Read only, Write only or support Read and Write operations by setting
>   * the MapFlag flags accordingly.
>   */
> -MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
> +MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags, bool usePlaneOffset)
>  {
>         ASSERT(!buffer->planes().empty());
>         planes_.reserve(buffer->planes().size());
> @@ -223,8 +224,14 @@ MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
>                 const int fd = plane.fd.get();
>                 auto &info = mappedBuffers[fd];
>                 if (!info.address) {
> -                       void *address = mmap(nullptr, info.mapLength, mmapFlags,
> -                                            MAP_SHARED, fd, 0);
> +                       void *address;
> +                       if (usePlaneOffset) {
> +                               address = mmap(nullptr, plane.length, mmapFlags,
> +                                              MAP_SHARED, fd, plane.offset);
> +                       } else {
> +                               address = mmap(nullptr, info.mapLength, mmapFlags,
> +                                              MAP_SHARED, fd, 0);
> +                       }

You could make this an oneliner using ternary operators, it would look
more compact I believe.

size_t length = usePlaneOffset ? plane.length : info.mapLength ;
off_t offset = usePlaneOffset ? plane.offset : 0
void *address = mmap(.., length, ..., offset);

>                         if (address == MAP_FAILED) {
>                                 error_ = -errno;
>                                 LOG(Buffer, Error) << "Failed to mmap plane: "
> @@ -233,10 +240,13 @@ MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
>                         }
>
>                         info.address = static_cast<uint8_t *>(address);
> -                       maps_.emplace_back(info.address, info.mapLength);
> +                       maps_.emplace_back(info.address, usePlaneOffset ? plane.length :
> +                                                                                                                         info.mapLength);
>                 }
>
> -               planes_.emplace_back(info.address + plane.offset, plane.length);
> +               uint8_t *storedAddress = usePlaneOffset ? info.address :
> +                                                         info.address + plane.offset;

I maybe wrong here, but looking at the code, shouldn't the operators
be opposite ? something like this ?

uint8_t *storedAddress = usePlaneOffset ? info.address + plane.offset
: info.address;

> +               planes_.emplace_back(storedAddress, plane.length);
>         }
>  }
>
> --
> 2.34.1
>

Regards,
Vedant Paranjape
Laurent Pinchart Aug. 28, 2023, 8:40 p.m. UTC | #2
Hello,

On Mon, Aug 21, 2023 at 07:31:29PM +0530, Vedant Paranjape via libcamera-devel wrote:
> On Mon, Aug 21, 2023 at 6:40 PM Gabby George wrote:
> >
> > As it is written, the MappedFrameBuffer causes a failure in mmap when
> 
> s/As it is written/ /
> s/the/The
> 
> > attempting to map UVC metadata planes.  UVC metadata (four character
> > code UVCH) does not support exporting buffers as file descriptors, so

I think you meant dmabuf file descriptors here. The precision is
important, as file descriptors can be many things.

> > mmap can be used to give libcamera access to the metadata buffer
> > planes. It is convenient to use the already-existing
> > MappedFrameBuffers class, but the class must be modified to support
> > mapping using file descriptors of the video node itself.
> >
> > To do this, mmap needs information obtained through a call to
> > QUERYBUF, namely, the plane offset for buffer planes. Modify the
> > constructor of a MappedFrameBuffer to use the plane offset directly in
> > the call to mmap, rather than the hard-coded 0 value.

I don't think I like this :-( It feels a bit of an abuse of this class.
I'd rather implement the mapping manually in the UVC pipeline handler.

> > The current version does not work when a buffer cannot be exported as
> > a dma buf fd. The fd argument to mmap must be the one obtained on a
> > call to open() for the video node (ie, /dev/videoX). This method of
> > mapping buffer planes requires the arguments to mmap to be exactly the
> > length and offset QUERYBUF provides.  Mmap will return a -EINVAL if
> 
> s/Mmap/mmap
> 
> > this is not the case.
> >
> > Signed-off-by: Gabby George <gabbymg94@gmail.com>
> > ---
> >  .../libcamera/internal/mapped_framebuffer.h   |  3 ++-
> >  src/libcamera/mapped_framebuffer.cpp          | 20 ++++++++++++++-----
> >  2 files changed, 17 insertions(+), 6 deletions(-)
> >
> > diff --git a/include/libcamera/internal/mapped_framebuffer.h b/include/libcamera/internal/mapped_framebuffer.h
> > index fb39adbf..04096d1b 100644
> > --- a/include/libcamera/internal/mapped_framebuffer.h
> > +++ b/include/libcamera/internal/mapped_framebuffer.h
> > @@ -54,7 +54,8 @@ public:
> >
> >         using MapFlags = Flags<MapFlag>;
> >
> > -       MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags);
> > +       MappedFrameBuffer(const FrameBuffer *buffer,
> > +                         MapFlags flags, bool usePlaneOffset = false);
> >  };
> >
> >  LIBCAMERA_FLAGS_ENABLE_OPERATORS(MappedFrameBuffer::MapFlag)
> > diff --git a/src/libcamera/mapped_framebuffer.cpp b/src/libcamera/mapped_framebuffer.cpp
> > index 6860069b..3d2cc332 100644
> > --- a/src/libcamera/mapped_framebuffer.cpp
> > +++ b/src/libcamera/mapped_framebuffer.cpp
> > @@ -172,12 +172,13 @@ MappedBuffer::~MappedBuffer()
> >   * \brief Map all planes of a FrameBuffer
> >   * \param[in] buffer FrameBuffer to be mapped
> >   * \param[in] flags Protection flags to apply to map
> > + * \param[in] usePlaneOffset Use offset stored in buffer's plane; default false
> >   *
> >   * Construct an object to map a frame buffer for CPU access. The mapping can be
> >   * made as Read only, Write only or support Read and Write operations by setting
> >   * the MapFlag flags accordingly.
> >   */
> > -MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
> > +MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags, bool usePlaneOffset)
> >  {
> >         ASSERT(!buffer->planes().empty());
> >         planes_.reserve(buffer->planes().size());
> > @@ -223,8 +224,14 @@ MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
> >                 const int fd = plane.fd.get();
> >                 auto &info = mappedBuffers[fd];
> >                 if (!info.address) {
> > -                       void *address = mmap(nullptr, info.mapLength, mmapFlags,
> > -                                            MAP_SHARED, fd, 0);
> > +                       void *address;
> > +                       if (usePlaneOffset) {
> > +                               address = mmap(nullptr, plane.length, mmapFlags,
> > +                                              MAP_SHARED, fd, plane.offset);
> > +                       } else {
> > +                               address = mmap(nullptr, info.mapLength, mmapFlags,
> > +                                              MAP_SHARED, fd, 0);
> > +                       }
> 
> You could make this an oneliner using ternary operators, it would look
> more compact I believe.
> 
> size_t length = usePlaneOffset ? plane.length : info.mapLength ;
> off_t offset = usePlaneOffset ? plane.offset : 0
> void *address = mmap(.., length, ..., offset);
> 
> >                         if (address == MAP_FAILED) {
> >                                 error_ = -errno;
> >                                 LOG(Buffer, Error) << "Failed to mmap plane: "
> > @@ -233,10 +240,13 @@ MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
> >                         }
> >
> >                         info.address = static_cast<uint8_t *>(address);
> > -                       maps_.emplace_back(info.address, info.mapLength);
> > +                       maps_.emplace_back(info.address, usePlaneOffset ? plane.length :
> > +                                                                                                                         info.mapLength);
> >                 }
> >
> > -               planes_.emplace_back(info.address + plane.offset, plane.length);
> > +               uint8_t *storedAddress = usePlaneOffset ? info.address :
> > +                                                         info.address + plane.offset;
> 
> I maybe wrong here, but looking at the code, shouldn't the operators
> be opposite ? something like this ?
> 
> uint8_t *storedAddress = usePlaneOffset ? info.address + plane.offset
> : info.address;
> 
> > +               planes_.emplace_back(storedAddress, plane.length);
> >         }
> >  }
> >

Patch
diff mbox series

diff --git a/include/libcamera/internal/mapped_framebuffer.h b/include/libcamera/internal/mapped_framebuffer.h
index fb39adbf..04096d1b 100644
--- a/include/libcamera/internal/mapped_framebuffer.h
+++ b/include/libcamera/internal/mapped_framebuffer.h
@@ -54,7 +54,8 @@  public:
 
 	using MapFlags = Flags<MapFlag>;
 
-	MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags);
+	MappedFrameBuffer(const FrameBuffer *buffer,
+			  MapFlags flags, bool usePlaneOffset = false);
 };
 
 LIBCAMERA_FLAGS_ENABLE_OPERATORS(MappedFrameBuffer::MapFlag)
diff --git a/src/libcamera/mapped_framebuffer.cpp b/src/libcamera/mapped_framebuffer.cpp
index 6860069b..3d2cc332 100644
--- a/src/libcamera/mapped_framebuffer.cpp
+++ b/src/libcamera/mapped_framebuffer.cpp
@@ -172,12 +172,13 @@  MappedBuffer::~MappedBuffer()
  * \brief Map all planes of a FrameBuffer
  * \param[in] buffer FrameBuffer to be mapped
  * \param[in] flags Protection flags to apply to map
+ * \param[in] usePlaneOffset Use offset stored in buffer's plane; default false
  *
  * Construct an object to map a frame buffer for CPU access. The mapping can be
  * made as Read only, Write only or support Read and Write operations by setting
  * the MapFlag flags accordingly.
  */
-MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
+MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags, bool usePlaneOffset)
 {
 	ASSERT(!buffer->planes().empty());
 	planes_.reserve(buffer->planes().size());
@@ -223,8 +224,14 @@  MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
 		const int fd = plane.fd.get();
 		auto &info = mappedBuffers[fd];
 		if (!info.address) {
-			void *address = mmap(nullptr, info.mapLength, mmapFlags,
-					     MAP_SHARED, fd, 0);
+			void *address;
+			if (usePlaneOffset) {
+				address = mmap(nullptr, plane.length, mmapFlags,
+					       MAP_SHARED, fd, plane.offset);
+			} else {
+				address = mmap(nullptr, info.mapLength, mmapFlags,
+					       MAP_SHARED, fd, 0);
+			}
 			if (address == MAP_FAILED) {
 				error_ = -errno;
 				LOG(Buffer, Error) << "Failed to mmap plane: "
@@ -233,10 +240,13 @@  MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)
 			}
 
 			info.address = static_cast<uint8_t *>(address);
-			maps_.emplace_back(info.address, info.mapLength);
+			maps_.emplace_back(info.address, usePlaneOffset ? plane.length :
+															  info.mapLength);
 		}
 
-		planes_.emplace_back(info.address + plane.offset, plane.length);
+		uint8_t *storedAddress = usePlaneOffset ? info.address :
+		                                          info.address + plane.offset;
+		planes_.emplace_back(storedAddress, plane.length);
 	}
 }