[{"id":20251,"web_url":"https://patchwork.libcamera.org/comment/20251/","msgid":"<YWoIGHYkwokvw7Th@pendragon.ideasonboard.com>","date":"2021-10-15T23:00:40","subject":"Re: [libcamera-devel] [IPU3-IPA PATCH] libcamera-helpers: Integrate\n\tlatest MappedFrameBuffer","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nThank you for the patch.\n\nOn Fri, Oct 15, 2021 at 03:16:56PM +0100, Kieran Bingham wrote:\n> The MappedFrameBuffer helper class has been updated in the libcamera\n> source code.\n> \n> This makes use of the new enum MapFlags type, and corrects the mapping\n> changes that were made during 8708904fad6f (\"libcamera:\n> mapped_framebuffer: Return plane begin address by MappedBuffer::maps()\")\n> \n> This update also brings back isolated IPA functionality to this external\n> IPA, which is otherwise broken due to the offset/plane changes.\n> \n> The files are renamed to mapped_framebuffer to match the naming in\n> libcamera, but are kept within the 'libcamera-helper' hierarchy of the\n> IPA.\n> \n> Also, a minor todo is added to IPAIPU3::mapBuffers, to highlight that we\n> could potentially map Statistics buffers as read only rather than\n> read/write if we could correctly identify them.\n> \n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> ---\n>  include/libcamera-helpers/mapped_buffer.h     |  53 ---------\n>  .../libcamera-helpers/mapped_framebuffer.h    |  65 +++++++++++\n>  ipu3.cpp                                      |   8 +-\n>  ...pped_buffer.cpp => mapped_framebuffer.cpp} | 110 +++++++++++++++---\n>  src/libcamera-helpers/meson.build             |   2 +-\n>  5 files changed, 163 insertions(+), 75 deletions(-)\n>  delete mode 100644 include/libcamera-helpers/mapped_buffer.h\n>  create mode 100644 include/libcamera-helpers/mapped_framebuffer.h\n>  rename src/libcamera-helpers/{mapped_buffer.cpp => mapped_framebuffer.cpp} (56%)\n> \n> diff --git a/include/libcamera-helpers/mapped_buffer.h b/include/libcamera-helpers/mapped_buffer.h\n> deleted file mode 100644\n> index 6cfc57217d75..000000000000\n> --- a/include/libcamera-helpers/mapped_buffer.h\n> +++ /dev/null\n> @@ -1,53 +0,0 @@\n> -/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> -/*\n> - * Copyright (C) 2020, Google Inc.\n> - *\n> - * buffer.h - Internal buffer handling\n> - */\n> -#ifndef __LIBCAMERA_MAPPED_BUFFER_H__\n> -#define __LIBCAMERA_MAPPED_BUFFER_H__\n> -\n> -#include <sys/mman.h>\n> -#include <vector>\n> -\n> -#include <libcamera/base/class.h>\n> -#include <libcamera/base/span.h>\n> -\n> -#include <libcamera/framebuffer.h>\n> -\n> -namespace libcamera {\n> -\n> -class MappedBuffer\n> -{\n> -public:\n> -        using Plane = Span<uint8_t>;\n> -\n> -        ~MappedBuffer();\n> -\n> -        MappedBuffer(MappedBuffer &&other);\n> -        MappedBuffer &operator=(MappedBuffer &&other);\n> -\n> -        bool isValid() const { return error_ == 0; }\n> -        int error() const { return error_; }\n> -        const std::vector<Plane> &maps() const { return maps_; }\n> -\n> -protected:\n> -        MappedBuffer();\n> -\n> -        int error_;\n> -        std::vector<Plane> maps_;\n> -\n> -private:\n> -        LIBCAMERA_DISABLE_COPY(MappedBuffer)\n> -};\n> -\n> -class MappedFrameBuffer : public MappedBuffer\n> -{\n> -public:\n> -        MappedFrameBuffer(const FrameBuffer *buffer, int flags);\n> -};\n> -\n> -} /* namespace libcamera */\n> -\n> -#endif /* __LIBCAMERA_MAPPED_BUFFER_H__ */\n> -\n> diff --git a/include/libcamera-helpers/mapped_framebuffer.h b/include/libcamera-helpers/mapped_framebuffer.h\n> new file mode 100644\n> index 000000000000..42155279d44d\n> --- /dev/null\n> +++ b/include/libcamera-helpers/mapped_framebuffer.h\n> @@ -0,0 +1,65 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Google Inc.\n> + *\n> + * mapped_framebuffer.h - Frame buffer memory mapping support\n> + */\n> +#ifndef __LIBCAMERA_HELPER_MAPPED_FRAMEBUFFER_H__\n> +#define __LIBCAMERA_HELPER_MAPPED_FRAMEBUFFER_H__\n> +\n> +#include <stdint.h>\n> +#include <vector>\n> +\n> +#include <libcamera/base/class.h>\n> +#include <libcamera/base/flags.h>\n> +#include <libcamera/base/span.h>\n> +\n> +#include <libcamera/framebuffer.h>\n> +\n> +namespace libcamera {\n> +\n> +class MappedBuffer\n> +{\n> +public:\n> +\tusing Plane = Span<uint8_t>;\n> +\n> +\t~MappedBuffer();\n> +\n> +\tMappedBuffer(MappedBuffer &&other);\n> +\tMappedBuffer &operator=(MappedBuffer &&other);\n> +\n> +\tbool isValid() const { return error_ == 0; }\n> +\tint error() const { return error_; }\n> +\t/* \\todo rename to planes(). */\n> +\tconst std::vector<Plane> &maps() const { return planes_; }\n> +\n> +protected:\n> +\tMappedBuffer();\n> +\n> +\tint error_;\n> +\tstd::vector<Plane> planes_;\n> +\tstd::vector<Plane> maps_;\n> +\n> +private:\n> +\tLIBCAMERA_DISABLE_COPY(MappedBuffer)\n> +};\n> +\n> +class MappedFrameBuffer : public MappedBuffer\n> +{\n> +public:\n> +\tenum class MapFlag {\n> +\t\tRead = 1 << 0,\n> +\t\tWrite = 1 << 1,\n> +\t\tReadWrite = Read | Write,\n> +\t};\n> +\n> +\tusing MapFlags = Flags<MapFlag>;\n> +\n> +\tMappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags);\n> +};\n> +\n> +LIBCAMERA_FLAGS_ENABLE_OPERATORS(MappedFrameBuffer::MapFlag)\n> +\n> +} /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_HELPER_MAPPED_FRAMEBUFFER_H__ */\n> diff --git a/ipu3.cpp b/ipu3.cpp\n> index 3e89e6dd4e02..c1a254517845 100644\n> --- a/ipu3.cpp\n> +++ b/ipu3.cpp\n> @@ -20,7 +20,7 @@\n>  \n>  #include <libcamera/base/log.h>\n>  \n> -#include \"libcamera-helpers/mapped_buffer.h\"\n> +#include \"libcamera-helpers/mapped_framebuffer.h\"\n>  \n>  /* IA AIQ Wrapper API */\n>  #include \"aic/aic.h\"\n> @@ -258,10 +258,14 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo)\n>  \n>  void IPAIPU3::mapBuffers(const std::vector<IPABuffer> &buffers)\n>  {\n> +\t/*\n> +\t * todo: Statistics buffers could be mapped read-only if they\n\ns/todo:/\\todo/\n\nIt's a good point, it could make sense to pass usage information along\nwith the buffers.\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\t * could be easily identified.\n> +\t */\n>  \tfor (const IPABuffer &buffer : buffers) {\n>  \t\tconst FrameBuffer fb(buffer.planes);\n>  \t\tbuffers_.emplace(buffer.id,\n> -\t\t\t\t MappedFrameBuffer(&fb, PROT_READ | PROT_WRITE));\n> +\t\t\t\t MappedFrameBuffer(&fb, MappedFrameBuffer::MapFlag::ReadWrite));\n>  \t}\n>  }\n>  \n> diff --git a/src/libcamera-helpers/mapped_buffer.cpp b/src/libcamera-helpers/mapped_framebuffer.cpp\n> similarity index 56%\n> rename from src/libcamera-helpers/mapped_buffer.cpp\n> rename to src/libcamera-helpers/mapped_framebuffer.cpp\n> index 6f3248e1b31b..a65740831331 100644\n> --- a/src/libcamera-helpers/mapped_buffer.cpp\n> +++ b/src/libcamera-helpers/mapped_framebuffer.cpp\n> @@ -2,26 +2,27 @@\n>  /*\n>   * Copyright (C) 2021, Google Inc.\n>   *\n> - * mapped_buffer.cpp - Mapped Buffer handling\n> + * mapped_framebuffer.cpp - Mapped Framebuffer support\n>   */\n>  \n> -#include \"libcamera-helpers/mapped_buffer.h\"\n> +#include \"libcamera-helpers/mapped_framebuffer.h\"\n>  \n> +#include <algorithm>\n>  #include <errno.h>\n> -#include <string.h>\n> +#include <map>\n>  #include <sys/mman.h>\n>  #include <unistd.h>\n>  \n>  #include <libcamera/base/log.h>\n>  \n>  /**\n> - * \\file libcamera-helpers/mapped_buffer.h\n> - * \\brief Mapped Buffer handling\n> + * \\file libcamera-helpers/mapped_framebuffer.h\n> + * \\brief Frame buffer memory mapping support\n>   */\n>  \n>  namespace libcamera {\n>  \n> -LOG_DEFINE_CATEGORY(MappedBuffer)\n> +LOG_DECLARE_CATEGORY(Buffer)\n>  \n>  /**\n>   * \\class MappedBuffer\n> @@ -81,6 +82,7 @@ MappedBuffer::MappedBuffer(MappedBuffer &&other)\n>  MappedBuffer &MappedBuffer::operator=(MappedBuffer &&other)\n>  {\n>  \terror_ = other.error_;\n> +\tplanes_ = std::move(other.planes_);\n>  \tmaps_ = std::move(other.maps_);\n>  \tother.error_ = -ENOENT;\n>  \n> @@ -129,10 +131,18 @@ MappedBuffer::~MappedBuffer()\n>   */\n>  \n>  /**\n> - * \\var MappedBuffer::maps_\n> + * \\var MappedBuffer::planes_\n>   * \\brief Stores the internal mapped planes\n>   *\n>   * MappedBuffer derived classes shall store the mappings they create in this\n> + * vector which points the beginning of mapped plane addresses.\n> + */\n> +\n> +/**\n> + * \\var MappedBuffer::maps_\n> + * \\brief Stores the mapped buffer\n> + *\n> + * MappedBuffer derived classes shall store the mappings they create in this\n>   * vector which is parsed during destruct to unmap any memory mappings which\n>   * completed successfully.\n>   */\n> @@ -142,29 +152,91 @@ MappedBuffer::~MappedBuffer()\n>   * \\brief Map a FrameBuffer using the MappedBuffer interface\n>   */\n>  \n> +/**\n> + * \\enum MappedFrameBuffer::MapFlag\n> + * \\brief Specify the mapping mode for the FrameBuffer\n> + * \\var MappedFrameBuffer::Read\n> + * \\brief Create a read-only mapping\n> + * \\var MappedFrameBuffer::Write\n> + * \\brief Create a write-only mapping\n> + * \\var MappedFrameBuffer::ReadWrite\n> + * \\brief Create a mapping that can be both read and written\n> + */\n> +\n> +/**\n> + * \\typedef MappedFrameBuffer::MapFlags\n> + * \\brief A bitwise combination of MappedFrameBuffer::MapFlag values\n> + */\n> +\n>  /**\n>   * \\brief Map all planes of a FrameBuffer\n>   * \\param[in] buffer FrameBuffer to be mapped\n>   * \\param[in] flags Protection flags to apply to map\n>   *\n> - * Construct an object to map a frame buffer for CPU access.\n> - * The flags are passed directly to mmap and should be either PROT_READ,\n> - * PROT_WRITE, or a bitwise-or combination of both.\n> + * Construct an object to map a frame buffer for CPU access. The mapping can be\n> + * made as Read only, Write only or support Read and Write operations by setting\n> + * the MapFlag flags accordingly.\n>   */\n> -MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, int flags)\n> +MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags)\n>  {\n> -\tmaps_.reserve(buffer->planes().size());\n> +\tASSERT(!buffer->planes().empty());\n> +\tplanes_.reserve(buffer->planes().size());\n> +\n> +\tint mmapFlags = 0;\n> +\n> +\tif (flags & MapFlag::Read)\n> +\t\tmmapFlags |= PROT_READ;\n> +\n> +\tif (flags & MapFlag::Write)\n> +\t\tmmapFlags |= PROT_WRITE;\n> +\n> +\tstruct MappedBufferInfo {\n> +\t\tuint8_t *address = nullptr;\n> +\t\tsize_t mapLength = 0;\n> +\t\tsize_t dmabufLength = 0;\n> +\t};\n> +\tstd::map<int, MappedBufferInfo> mappedBuffers;\n> +\n> +\tfor (const FrameBuffer::Plane &plane : buffer->planes()) {\n> +\t\tconst int fd = plane.fd.fd();\n> +\t\tif (mappedBuffers.find(fd) == mappedBuffers.end()) {\n> +\t\t\tconst size_t length = lseek(fd, 0, SEEK_END);\n> +\t\t\tmappedBuffers[fd] = MappedBufferInfo{ nullptr, 0, length };\n> +\t\t}\n> +\n> +\t\tconst size_t length = mappedBuffers[fd].dmabufLength;\n> +\n> +\t\tif (plane.offset > length ||\n> +\t\t    plane.offset + plane.length > length) {\n> +\t\t\tLOG(Buffer, Fatal) << \"plane is out of buffer: \"\n> +\t\t\t\t\t   << \"buffer length=\" << length\n> +\t\t\t\t\t   << \", plane offset=\" << plane.offset\n> +\t\t\t\t\t   << \", plane length=\" << plane.length;\n> +\t\t\treturn;\n> +\t\t}\n> +\t\tsize_t &mapLength = mappedBuffers[fd].mapLength;\n> +\t\tmapLength = std::max(mapLength,\n> +\t\t\t\t     static_cast<size_t>(plane.offset + plane.length));\n> +\t}\n>  \n>  \tfor (const FrameBuffer::Plane &plane : buffer->planes()) {\n> -\t\tvoid *address = mmap(nullptr, plane.length, flags,\n> -\t\t\t\t     MAP_SHARED, plane.fd.fd(), 0);\n> -\t\tif (address == MAP_FAILED) {\n> -\t\t\terror_ = -errno;\n> -\t\t\tLOG(MappedBuffer, Error) << \"Failed to mmap plane\";\n> -\t\t\tbreak;\n> +\t\tconst int fd = plane.fd.fd();\n> +\t\tauto &info = mappedBuffers[fd];\n> +\t\tif (!info.address) {\n> +\t\t\tvoid *address = mmap(nullptr, info.mapLength, mmapFlags,\n> +\t\t\t\t\t     MAP_SHARED, fd, 0);\n> +\t\t\tif (address == MAP_FAILED) {\n> +\t\t\t\terror_ = -errno;\n> +\t\t\t\tLOG(Buffer, Error) << \"Failed to mmap plane: \"\n> +\t\t\t\t\t\t   << strerror(-error_);\n> +\t\t\t\treturn;\n> +\t\t\t}\n> +\n> +\t\t\tinfo.address = static_cast<uint8_t *>(address);\n> +\t\t\tmaps_.emplace_back(info.address, info.mapLength);\n>  \t\t}\n>  \n> -\t\tmaps_.emplace_back(static_cast<uint8_t *>(address), plane.length);\n> +\t\tplanes_.emplace_back(info.address + plane.offset, plane.length);\n>  \t}\n>  }\n>  \n> diff --git a/src/libcamera-helpers/meson.build b/src/libcamera-helpers/meson.build\n> index 444f21204d5d..084bf65345ae 100644\n> --- a/src/libcamera-helpers/meson.build\n> +++ b/src/libcamera-helpers/meson.build\n> @@ -2,5 +2,5 @@\n>  \n>  # Implementation of internal libcamera internals\n>  libcamera_helpers = files([\n> -    'mapped_buffer.cpp',\n> +    'mapped_framebuffer.cpp',\n>  ])","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 51EBAC324C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 15 Oct 2021 23:00:58 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A9BFA68F51;\n\tSat, 16 Oct 2021 01:00:57 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8FC8468541\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 16 Oct 2021 01:00:56 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EB5A029B;\n\tSat, 16 Oct 2021 01:00:55 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"WNeL+UQd\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1634338856;\n\tbh=3n2PsN8J4KNqAO+hLnpUOf+VO0a9wrziPWAIJZdi0Wg=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=WNeL+UQdmiJ+3FY5BJJkiSXZcT3+t6KiJV+1znFyz/QkgkB3fWm8d+fPJB5vBi7An\n\tL5zefU5NUY8aK0G72OVNlJW0znHKrxKnT2x2nzdh7xN5OkZPkdHbr9XO8ltgGRkQ6H\n\tqULOIsZfgxjR5gKDI9vxYGC1fIwx1y/dS6jivN/Y=","Date":"Sat, 16 Oct 2021 02:00:40 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<YWoIGHYkwokvw7Th@pendragon.ideasonboard.com>","References":"<20211015141656.242247-1-kieran.bingham@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20211015141656.242247-1-kieran.bingham@ideasonboard.com>","Subject":"Re: [libcamera-devel] [IPU3-IPA PATCH] libcamera-helpers: Integrate\n\tlatest MappedFrameBuffer","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]