[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