From patchwork Wed Aug 5 15:14:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 9230 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 458B2BD86F for ; Wed, 5 Aug 2020 15:15:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 140AF605B8; Wed, 5 Aug 2020 17:15:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="QpVRn4Jz"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 12C1660599 for ; Wed, 5 Aug 2020 17:15:12 +0200 (CEST) Received: from Q.local (cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A46D8B90; Wed, 5 Aug 2020 17:15:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1596640511; bh=ybsy37bbS0FJ5GnFEaly8S/4eQECIx+M/OrEaRVRFmo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QpVRn4JzZMtaFqzPeitIzvMIGeSpQ7nvDmpY8LMd5d3sgCVnqnkMzb/jmqcdR9wVp qSive8DnAwAqrjy01YH8y3i2TAUP02k0z2gHUXuiHIpiKFWDfwyyXd6Vz+mlk/nPPV IK8g4AYbIlOKMJMw958ptHkFjFAL/tASSH3IiFEY= From: Kieran Bingham To: libcamera devel Date: Wed, 5 Aug 2020 16:14:57 +0100 Message-Id: <20200805151507.227503-4-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200805151507.227503-1-kieran.bingham@ideasonboard.com> References: <20200805151507.227503-1-kieran.bingham@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 03/13] libcamera: buffer: Create a MappedBuffer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 Reviewed-by: Laurent Pinchart --- v3 - Documentation fixups v4: - Use reference when unmapping, rather than a copy of the planes. - Move MappedPlane to MappedBuffer::Plane - Remove valid_ - Make constructor protected - Rename move constructor parameters from rhs to other - Rework move constructor documentation. --- include/libcamera/internal/buffer.h | 47 +++++++++ src/libcamera/buffer.cpp | 152 +++++++++++++++++++++++++++- 2 files changed, 198 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..b7b0173f93f5 --- /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 +#include + +#include +#include + +namespace libcamera { + +class MappedBuffer +{ +public: + using Plane = Span; + + ~MappedBuffer(); + + MappedBuffer(MappedBuffer &&other); + MappedBuffer &operator=(MappedBuffer &&other); + + bool isValid() const { return error_ == 0; } + int error() const { return error_; } + const std::vector &maps() const { return maps_; } + +protected: + MappedBuffer(); + + int error_; + std::vector 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..8666f1992a77 100644 --- a/src/libcamera/buffer.cpp +++ b/src/libcamera/buffer.cpp @@ -6,6 +6,7 @@ */ #include +#include "libcamera/internal/buffer.h" #include #include @@ -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,152 @@ 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 the CPU. + * + * This class is not meant to be constructed directly, but instead derived + * classes should be used to implement the correct mapping of a source buffer. + * + * This allows treating CPU accessible memory through a generic interface + * regardless of whether it originates from a libcamera FrameBuffer or other + * source. + */ + +/** + * \typedef MappedBuffer::Plane + * \brief A mapped region of memory accessible to the CPU + * + * The MappedBuffer::Plane uses the Span interface to describe the mapped memory + * region. + */ + +/** + * \brief Construct an empty MappedBuffer + * + * Base class initialisation for MappedBuffer. + */ +MappedBuffer::MappedBuffer() + : error_(0) +{ +} + +/** + * \brief Move constructor, construct the MappedBuffer with the contents of \a + * other using move semantics + * \param[in] other The other MappedBuffer + * + * Moving a MappedBuffer moves the mappings contained in the \a other to the new + * MappedBuffer and invalidates the \a other. + * + * No mappings are unmapped or destroyed in this process. + */ +MappedBuffer::MappedBuffer(MappedBuffer &&other) +{ + *this = std::move(other); +} + +/** + * \brief Move assignment operator, replace the mappings with those of \a other + * mappings + * \param[in] other The other MappedBuffer + * + * Moving a MappedBuffer moves the mappings contained in the \a other to the new + * MappedBuffer and invalidates the \a other. + * + * No mappings are unmapped or destroyed in this process. + */ +MappedBuffer &MappedBuffer::operator=(MappedBuffer &&other) +{ + error_ = other.error_; + maps_ = std::move(other.maps_); + other.error_ = -ENOENT; + + return *this; +} + +MappedBuffer::~MappedBuffer() +{ + for (Plane &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 to provide access to the mapped memory. + * + * \return A vector of the mapped planes + */ + +/** + * \var MappedBuffer::error_ + * \brief Stores the error value if present + * + * MappedBuffer derived classes 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 derived classes 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 Map a FrameBuffer using the MappedBuffer interface + */ + +/** + * \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); + if (address == MAP_FAILED) { + error_ = -errno; + LOG(Buffer, Error) << "Failed to mmap plane"; + break; + } + + maps_.emplace_back(static_cast(address), plane.length); + } +} + } /* namespace libcamera */