[libcamera-devel,01/27] libcamera: Add Buffer Management

Message ID 20190206060818.13907-2-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • Capture frames throught requests
Related show

Commit Message

Laurent Pinchart Feb. 6, 2019, 6:07 a.m. UTC
From: Kieran Bingham <kieran.bingham@ideasonboard.com>

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 <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
---
 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

Patch

diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h
new file mode 100644
index 000000000000..21a1ec4c574e
--- /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 <vector>
+
+#include <libcamera/signal.h>
+
+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<Plane> &planes() { return planes_; }
+
+	Signal<Buffer *> completed;
+
+private:
+	friend class BufferPool;
+
+	unsigned int index_;
+
+	std::vector<Plane> planes_;
+};
+
+class BufferPool final
+{
+public:
+	~BufferPool();
+
+	void createBuffers(unsigned int count);
+	void destroyBuffers();
+
+	unsigned int count() const { return buffers_.size(); }
+	std::vector<Buffer> &buffers() { return buffers_; }
+
+private:
+	std::vector<Buffer> buffers_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_BUFFER_H__ */
diff --git a/include/libcamera/libcamera.h b/include/libcamera/libcamera.h
index 272dfd5e4a67..8167e8099ac0 100644
--- a/include/libcamera/libcamera.h
+++ b/include/libcamera/libcamera.h
@@ -7,6 +7,7 @@ 
 #ifndef __LIBCAMERA_LIBCAMERA_H__
 #define __LIBCAMERA_LIBCAMERA_H__
 
+#include <libcamera/buffer.h>
 #include <libcamera/camera.h>
 #include <libcamera/camera_manager.h>
 #include <libcamera/event_dispatcher.h>
diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index 54a680787e5c..8c14423bc444 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 000000000000..5f6114cf3bc5
--- /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 <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <libcamera/buffer.h>
+
+#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 9f6ff99eebe2..a4e9cc8f936c 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',