[libcamera-devel] [PATCH v3 03/13] libcamera: buffer: Create a MappedBuffer
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Wed Aug 5 02:29:04 CEST 2020
Hi Kieran,
Thank you for the patch.
On Tue, Aug 04, 2020 at 10:47:01PM +0100, Kieran Bingham wrote:
> Provide a MappedFrameBuffer helper class which will map
> all of the Planes within a FrameBuffer and provide CPU addressable
> pointers for those planes.
>
> The MappedFrameBuffer implements the interface of the MappedBuffer
> allowing other buffer types to be constructed of the same form, with a
> common interface and cleanup.
>
> This allows MappedBuffer instances to be created from Camera3Buffer types.
>
> Mappings are removed upon destruction.
>
> Signed-off-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
>
> ---
> v3
> - Documentation fixups
> ---
> include/libcamera/internal/buffer.h | 47 ++++++++
> src/libcamera/buffer.cpp | 162 +++++++++++++++++++++++++++-
> 2 files changed, 208 insertions(+), 1 deletion(-)
> create mode 100644 include/libcamera/internal/buffer.h
>
> diff --git a/include/libcamera/internal/buffer.h b/include/libcamera/internal/buffer.h
> new file mode 100644
> index 000000000000..e86a003cd8ba
> --- /dev/null
> +++ b/include/libcamera/internal/buffer.h
> @@ -0,0 +1,47 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
> + *
> + * buffer.h - Internal buffer handling
> + */
> +#ifndef __LIBCAMERA_INTERNAL_BUFFER_H__
> +#define __LIBCAMERA_INTERNAL_BUFFER_H__
> +
> +#include <sys/mman.h>
> +#include <vector>
> +
> +#include <libcamera/buffer.h>
> +#include <libcamera/span.h>
> +
> +namespace libcamera {
> +
> +using MappedPlane = Span<uint8_t>;
> +
> +class MappedBuffer
> +{
> +public:
How about moving MappedPlane here, and naming it Plane ?
using Plane = Span<uint8_t>;
This makes it clear that Plane is meant to be used with MappedBuffer.
> + MappedBuffer();
Do you want to allow construction of the base class, or only of derived
classes ? In the latter case, you should move this constructor to the
protected section below.
> + ~MappedBuffer();
> +
> + MappedBuffer(MappedBuffer &&rhs);
> + MappedBuffer &operator=(MappedBuffer &&rhs);
The parameter is customarily called other for the copy and move
constructors and assignment operators. rhs is usually used in
conjunction with lhs for non-member operators.
> +
> + bool isValid() const { return valid_; }
> + int error() const { return error_; }
> + const std::vector<MappedPlane> &maps() const { return maps_; }
> +
> +protected:
> + int error_;
> + bool valid_;
Do you need both ? Could isValid() return error_ == 0 ?
> + std::vector<MappedPlane> maps_;
> +};
> +
> +class MappedFrameBuffer : public MappedBuffer
> +{
> +public:
> + MappedFrameBuffer(const FrameBuffer *buffer, int flags);
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_INTERNAL_BUFFER_H__ */
> diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp
> index 8278f8a92af4..5f7dff60a48b 100644
> --- a/src/libcamera/buffer.cpp
> +++ b/src/libcamera/buffer.cpp
> @@ -6,6 +6,7 @@
> */
>
> #include <libcamera/buffer.h>
> +#include "libcamera/internal/buffer.h"
>
> #include <errno.h>
> #include <string.h>
> @@ -15,7 +16,8 @@
> #include "libcamera/internal/log.h"
>
> /**
> - * \file buffer.h
> + * \file libcamera/buffer.h
> + * \file libcamera/internal/buffer.h
> * \brief Buffer handling
> */
>
> @@ -290,4 +292,162 @@ int FrameBuffer::copyFrom(const FrameBuffer *src)
> return 0;
> }
>
> +/**
> + * \class MappedBuffer
> + * \brief Provide an interface to support managing memory mapped buffers
> + *
> + * The MappedBuffer interface provides access to a set of MappedPlanes which
> + * are available for access by a CPU.
s/a CPU/the CPU/ ?
You're clearly thinking as a kernel developer :-)
> + *
> + * The MappedBuffer interface does not implement any valid constructor but
> + * defines the move operators and destructors for the derived implementations,
> + * which are able to construct according to their derived types and given
> + * flags.
That's a bit of implementation details. Maybe "This class is not meant
to be constructed directly, and thus has no public default constructor.
Derived classes shall be used instead." ?
> + *
> + * This allows treating CPU accessible memory through a generic interface
> + * regardless of whether it originates from a libcamera FrameBuffer or other
> + * source.
> + */
> +
> +/**
> + * \brief Construct an empty MappedBuffer
> + *
> + * A default constructor is required to allow subclassing the MappedBuffer
> + * class. Construct an initialised, but invalid MappedBuffer.
You can drop the first sentence, you're explaining C++ :-)
> + */
> +MappedBuffer::MappedBuffer()
> + : error_(0), valid_(false)
> +{
> +}
> +
> +/**
> + * \brief Construct a MappedBuffer by taking the \a rhs mappings
Construct the MappedBuffer with the contents of \a other using move
semantics
(This is the usual way to document move constructors in
https://en.cppreference.com/, which we're mimicking in libcamera.)
> + * \param[in] rhs The other MappedBuffer
> + *
> + * Moving a MappedBuffer moves the mappings contained in the \a rhs to the new
> + * MappedBuffer and invalidates the \a rhs. No mappings are unmapped or
> + * destroyed in this process.
> + */
> +MappedBuffer::MappedBuffer(MappedBuffer &&rhs)
> +{
> + *this = std::move(rhs);
> +}
> +
> +/**
> + * \brief Move assingment operator, move a MappedBuffer by taking the \a rhs mappings
s/assingment/assignement/
But for the same reason as above,
Replace the contents with those of \a other using move semantics
> + * \param[in] rhs The other MappedBuffer
> + *
> + * Moving a MappedBuffer moves the mappings contained in the \a rhs to the new
s/the \a rhs/\a other/
s/ new// (this is not a newly constructed instance)
> + * MappedBuffer and invalidates the \a rhs. No mappings are unmapped or
s/the \a rhs/\a other/
> + * destroyed in this process.
> + */
> +MappedBuffer &MappedBuffer::operator=(MappedBuffer &&rhs)
> +{
> + error_ = rhs.error_;
> + valid_ = rhs.valid_;
> + maps_ = std::move(rhs.maps_);
> + rhs.valid_ = false;
> + rhs.error_ = 0;
> +
> + return *this;
> +}
> +
> +MappedBuffer::~MappedBuffer()
> +{
> + for (MappedPlane map : maps_)
> + munmap(map.data(), map.size());
> +}
> +
> +/**
> + * \fn MappedBuffer::isValid()
> + * \brief Check if the MappedBuffer instance is valid
> + * \return True if the MappedBuffer has valid mappings, false otherwise
> + */
> +
> +/**
> + * \fn MappedBuffer::error()
> + * \brief Retrieve the map error status
> + *
> + * This function retrieves the error status from the MappedBuffer.
> + * The error status is a negative number as defined by errno.h. If
> + * no error occurred, this function returns 0.
> + *
> + * \return 0 on success or a negative error code otherwise
> + */
> +
> +/**
> + * \fn MappedBuffer::maps()
> + * \brief Retrieve the mapped planes
> + *
> + * This function retrieves the successfully mapped planes stored as a vector
> + * of Span<uint8_t> to provide access to the mapped memory.
> + *
> + * \return A vector of the mapped planes.
s/.$//
> + */
> +
> +/**
> + * \var MappedBuffer::valid_
> + * \brief Stores the status of the mapping
> + *
> + * MappedBuffer implementations shall set this to represent if the mapping
s/implementations/derived classes/ ? Same below.
> + * was successfully completed without errors.
> + */
> +
> +/**
> + * \var MappedBuffer::error_
> + * \brief Stores the error value if present
> + *
> + * MappedBuffer implementations shall set this to a negative value as defined
> + * by errno.h if an error occured during the mapping process
> + */
> +
> +/**
> + * \var MappedBuffer::maps_
> + * \brief Stores the internal
> + *
> + * MappedBuffer implementations shall store the mappings they create in this
> + * vector which is parsed during destruct to unmap any memory mappings which
> + * completed successfully.
> + */
> +
> +/**
> + * \class MappedFrameBuffer
> + * \brief Maps a FrameBuffer using the MappedBuffer interface
s/Maps/Map/
> + *
> + * The MappedFrameBuffer interface maps a FrameBuffer instance
s/$/./
Or maybe drop the sentence as it duplicates the brief.
> + *
> + * The MappedBuffer interface does not implement any constructor but defines
> + * the move operators and destructors for the derived implementations, which
> + * are able to construct according to their derived types and given flags.
Is this a leftover from a copy & paste ? I think ou can drop this
paragraph.
> + */
> +
> +/**
> + * \brief Map all planes of a FrameBuffer
> + * \param[in] buffer FrameBuffer to be mapped
> + * \param[in] flags Protection flags to apply to map
> + *
> + * Construct an object to map a frame buffer for CPU access.
> + * The flags are passed directly to mmap and should be either PROT_READ,
> + * PROT_WRITE, or a bitwise-or combination of both.
> + */
> +MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, int flags)
> +{
> + maps_.reserve(buffer->planes().size());
> +
> + for (const FrameBuffer::Plane &plane : buffer->planes()) {
> + void *address = mmap(nullptr, plane.length, flags,
> + MAP_SHARED, plane.fd.fd(), 0);
> +
You can drop the blank line.
> + if (address == MAP_FAILED) {
> + error_ = -errno;
> + LOG(Buffer, Error) << "Failed to mmap plane";
> + break;
> + }
> +
> + maps_.emplace_back(static_cast<uint8_t *>(address), plane.length);
> + }
> +
> + valid_ = buffer->planes().size() == maps_.size();
> +}
> +
> } /* namespace libcamera */
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list