From 83148ce8be55e49d30da9006582a1c1eb6371815 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Tue, 5 Feb 2019 16:32:22 +0100 Subject: libcamera: Add Buffer Management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide classes that represent frame buffers and pools of frame buffers. An image within the system may use one or more Plane objects to track each plane in the case of multi-planar image formats. The Buffer class manages all of the data required to render or interpret the raw image data. Signed-off-by: Laurent Pinchart Signed-off-by: Jacopo Mondi Signed-off-by: Kieran Bingham Signed-off-by: Niklas Söderlund --- include/libcamera/buffer.h | 74 ++++++++++++ include/libcamera/libcamera.h | 1 + include/libcamera/meson.build | 1 + src/libcamera/buffer.cpp | 253 ++++++++++++++++++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 5 files changed, 330 insertions(+) create mode 100644 include/libcamera/buffer.h create mode 100644 src/libcamera/buffer.cpp diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h new file mode 100644 index 00000000..21a1ec4c --- /dev/null +++ b/include/libcamera/buffer.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * buffer.h - Buffer handling + */ +#ifndef __LIBCAMERA_BUFFER_H__ +#define __LIBCAMERA_BUFFER_H__ + +#include + +#include + +namespace libcamera { + +class BufferPool; + +class Plane final +{ +public: + Plane(); + ~Plane(); + + int dmabuf() const { return fd_; } + int setDmabuf(int fd, unsigned int length); + + void *mem(); + unsigned int length() const { return length_; } + +private: + int mmap(); + int munmap(); + + int fd_; + unsigned int length_; + void *mem_; +}; + +class Buffer final +{ +public: + Buffer(); + + unsigned int index() const { return index_; } + std::vector &planes() { return planes_; } + + Signal completed; + +private: + friend class BufferPool; + + unsigned int index_; + + std::vector planes_; +}; + +class BufferPool final +{ +public: + ~BufferPool(); + + void createBuffers(unsigned int count); + void destroyBuffers(); + + unsigned int count() const { return buffers_.size(); } + std::vector &buffers() { return buffers_; } + +private: + std::vector buffers_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_BUFFER_H__ */ diff --git a/include/libcamera/libcamera.h b/include/libcamera/libcamera.h index 272dfd5e..8167e809 100644 --- a/include/libcamera/libcamera.h +++ b/include/libcamera/libcamera.h @@ -7,6 +7,7 @@ #ifndef __LIBCAMERA_LIBCAMERA_H__ #define __LIBCAMERA_LIBCAMERA_H__ +#include #include #include #include diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 54a68078..8c14423b 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -1,4 +1,5 @@ libcamera_api = files([ + 'buffer.h', 'camera.h', 'camera_manager.h', 'event_dispatcher.h', diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp new file mode 100644 index 00000000..5f6114cf --- /dev/null +++ b/src/libcamera/buffer.cpp @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * buffer.cpp - Buffer handling + */ + +#include +#include +#include +#include + +#include + +#include "log.h" + +/** + * \file buffer.h + * \brief Buffer handling + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(Buffer) + +/** + * \class Plane + * \brief A memory region to store a single plane of a frame + * + * Planar pixel formats use multiple memory regions to store planes + * corresponding to the different colour components of a frame. The Plane class + * tracks the specific details of a memory region used to store a single plane + * for a given frame and provides the means to access the memory, both for the + * application and for DMA. A Buffer then contains one or multiple planes + * depending on its pixel format. + * + * To support DMA access, planes are associated with dmabuf objects represented + * by file handles. Each plane carries a dmabuf file handle and an offset within + * the buffer. Those file handles may refer to the same dmabuf object, depending + * on whether the devices accessing the memory regions composing the image + * support non-contiguous DMA to planes ore require DMA-contiguous memory. + * + * To support CPU access, planes carry the CPU address of their backing memory. + * Similarly to the dmabuf file handles, the CPU addresses for planes composing + * an image may or may not be contiguous. + */ + +Plane::Plane() + : fd_(-1), length_(0), mem_(0) +{ +} + +Plane::~Plane() +{ + munmap(); + + if (fd_ != -1) + close(fd_); +} + +/** + * \fn Plane::dmabuf() + * \brief Get the dmabuf file handle backing the buffer + */ + +/** + * \brief Set the dmabuf file handle backing the buffer + * \param[in] fd The dmabuf file handle + * \param[in] length The size of the memory region + * + * The \a fd dmabuf file handle is duplicated and stored. The caller may close + * the original file handle. + * + * \return 0 on success or a negative error value otherwise. + */ +int Plane::setDmabuf(int fd, unsigned int length) +{ + if (fd < 0) { + LOG(Buffer, Error) << "Invalid dmabuf fd provided"; + return -EINVAL; + } + + if (fd_ != -1) { + close(fd_); + fd_ = -1; + } + + fd_ = dup(fd); + if (fd_ == -1) { + int ret = -errno; + LOG(Buffer, Error) + << "Failed to duplicate dmabuf: " << strerror(-ret); + return ret; + } + + length_ = length; + + return 0; +} + +/** + * \brief Map the plane memory data to a CPU accessible address + * + * The file descriptor to map the memory from must be set by a call to + * setDmaBuf() before calling this function. + * + * \sa setDmaBuf() + * + * \return 0 on success or a negative error value otherwise. + */ +int Plane::mmap() +{ + void *map; + + if (mem_) + return 0; + + map = ::mmap(NULL, length_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0); + if (map == MAP_FAILED) { + int ret = -errno; + LOG(Buffer, Error) + << "Failed to mmap plane: " << strerror(-ret); + return ret; + } + + mem_ = map; + + return 0; +} + +/** + * \brief Unmap any existing CPU accessible mapping + * + * Unmap the memory mapped by an earlier call to mmap(). + * + * \return 0 on success or a negative error value otherwise. + */ +int Plane::munmap() +{ + int ret = 0; + + if (mem_) + ret = ::munmap(mem_, length_); + + if (ret) { + ret = -errno; + LOG(Buffer, Warning) + << "Failed to unmap plane: " << strerror(-ret); + } else { + mem_ = 0; + } + + return ret; +} + +/** + * \fn Plane::mem() + * \brief Retrieve the CPU accessible memory address of the Plane + * \return The CPU accessible memory address on success or nullptr otherwise. + */ +void *Plane::mem() +{ + if (!mem_) + mmap(); + + return mem_; +} + +/** + * \fn Plane::length() + * \brief Retrieve the length of the memory region + * \return The length of the memory region + */ + +/** + * \class Buffer + * \brief A memory buffer to store an image + * + * The Buffer class represents the memory buffers used to store a + * full frame image, which may contain multiple separate memory Plane + * objects if the image format is multi-planar. + */ + +Buffer::Buffer() + : index_(-1) +{ +} + +/** + * \fn Buffer::index() + * \brief Retrieve the Buffer index + * \return The buffer index + */ + +/** + * \fn Buffer::planes() + * \brief Retrieve the planes within the buffer + * \return A reference to a vector holding all Planes within the buffer + */ + +/** + * \var Buffer::completed + * \brief A Signal to provide notifications that the specific Buffer is ready + */ + +/** + * \class BufferPool + * \brief A pool of buffers + * + * The BufferPool class groups together a collection of Buffers to store frames. + * The buffers must be exported by a device before they can be imported into + * another device for further use. + */ + +BufferPool::~BufferPool() +{ + destroyBuffers(); +} + +/** + * \brief Create buffers in the Pool + * \param[in] count The number of buffers to create + */ +void BufferPool::createBuffers(unsigned int count) +{ + unsigned int index = 0; + + buffers_.resize(count); + for (Buffer &buffer : buffers_) + buffer.index_ = index++; +} + +/** + * \brief Release all buffers from pool + */ +void BufferPool::destroyBuffers() +{ + buffers_.resize(0); +} + +/** + * \fn BufferPool::count() + * \brief Retrieve the number of buffers contained within the pool + * \return The number of buffers contained in the pool + */ + +/** + * \fn BufferPool::buffers() + * \brief Retrieve all the buffers in the pool + * \return A vector containing all the buffers in the pool. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 9f6ff99e..a4e9cc8f 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -1,4 +1,5 @@ libcamera_sources = files([ + 'buffer.cpp', 'camera.cpp', 'camera_manager.cpp', 'device_enumerator.cpp', -- cgit v1.2.1