[libcamera-devel] [RFC PATCH 1/8] libcamera: buffer: Create a MappedFrameBuffer
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Fri Jul 24 18:58:40 CEST 2020
Hi Kieran,
Thank you for the patch.
On Mon, Jul 20, 2020 at 11:42:25PM +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.
>
> Mappings are removed upon destruction.
>
> Signed-off-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> ---
>
> This introduces an automatically mapping/unmapping MappedFrameBuffer
> object, with a move constructor (essential to prevent un-desirable
> unmapping).
>
>
>
> include/libcamera/buffer.h | 23 ++++++++++++++++++++
Should this be an internal helper ? The main foreseen flow is for
applications to create frame buffers from dmabuf fds they recently
outside of libcamera, so I would expect them to handle memory mapping.
I'd thus rather start with an internal helper, which we could graduate
to a public API later if needed/desired.
> src/libcamera/buffer.cpp | 43 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 66 insertions(+)
>
> diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h
> index 6bb2e4f8558f..881d736da2db 100644
> --- a/include/libcamera/buffer.h
> +++ b/include/libcamera/buffer.h
> @@ -71,6 +71,29 @@ private:
> unsigned int cookie_;
> };
>
> +class MappedFrameBuffer {
> +public:
> + MappedFrameBuffer(const FrameBuffer *buffer, int flags);
> + ~MappedFrameBuffer();
> +
> + /* Move constructor only, copying is not permitted. */
We usually don't put comments in the header files. This should go to the
\class documentation block below.
> + MappedFrameBuffer(MappedFrameBuffer &&rhs);
Do you actually need this ? If it's only for the purpose of preventing
copy-construction, you can simply write
MappedFrameBuffer(const MappedFrameBuffer &other) = delete;
MappedFrameBuffer operator=(const MappedFrameBuffer &other) = delete;
The C++ rules governing implicitly-defined and defaulted copy and move
constructors and assignment operators are not the easiest to follow.
It's usually best to be explicit. If you need move semantics,
MappedFrameBuffer(const MappedFrameBuffer &other) = delete;
MappedFrameBuffer operator=(const MappedFrameBuffer &other) = delete;
MappedFrameBuffer(MappedFrameBuffer &&other);
MappedFrameBuffer operator=(MappedFrameBuffer &&other);
(either neither or both of the move constructor and the move assignment
operator should be defined) otherwise you can leave the latter two out.
> +
> + struct MappedPlane {
> + void *address;
> + size_t length;
> + };
Would it make sense to use Span<uint8_t> to replace MappedPlane ?
> +
> + bool isValid() const { return valid_; }
> + int error() const { return error_; }
> + const std::vector<MappedPlane> &maps() const { return maps_; }
> +
> +private:
> + int error_;
> + bool valid_;
> + std::vector<MappedPlane> maps_;
> +};
> +
> } /* namespace libcamera */
>
> #endif /* __LIBCAMERA_BUFFER_H__ */
> diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp
> index 1a1d4bac7aed..28b43d937f57 100644
> --- a/src/libcamera/buffer.cpp
> +++ b/src/libcamera/buffer.cpp
> @@ -290,4 +290,47 @@ int FrameBuffer::copyFrom(const FrameBuffer *src)
> return 0;
> }
>
Missing
/**
* \class MappedFrameBuffer
* ...
*/
> +/**
> + * \brief Map all planes of a FrameBuffer
As this is a constructor, I think it should be documented as "Construct
..." to follow the usual pattern.
> + * \param[in] src Buffer to be mapped
s/src/buffer/
> + * \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)
> + : error_(0)
> +{
> + 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);
> +
> + if (address == MAP_FAILED) {
> + error_ = -errno;
> + LOG(Buffer, Error) << "Failed to mmap plane";
> + continue;
Shouldn't you break ?
> + }
> +
> + maps_.push_back({address, plane.length});
> + }
> +
> + valid_ = buffer->planes().size() == maps_.size();
> +}
> +
> +MappedFrameBuffer::~MappedFrameBuffer()
> +{
> + for (MappedPlane map : maps_)
for (MappedPlane &map : maps_)
> + munmap(map.address, map.length);
> +}
> +
> +MappedFrameBuffer::MappedFrameBuffer(MappedFrameBuffer &&rhs)
> +{
> + error_ = rhs.error_;
> + valid_ = rhs.valid_;
> + maps_ = std::move(rhs.maps_);
This is the default move constructor, so you could simply write
MappedFrameBuffer(MappedFrameBuffer &&other) = default;
in the class definition. However, I think you should keep this, and add
rhs.error_ = 0;
rhs.valid_ = false;
Note that you can implement the move constructor in terms of the move
assignment operator:
*this = std::move(other);
> +}
> +
> } /* namespace libcamera */
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list