Patch Detail
Show a patch.
GET /api/patches/1627/?format=api
{ "id": 1627, "url": "https://patchwork.libcamera.org/api/patches/1627/?format=api", "web_url": "https://patchwork.libcamera.org/patch/1627/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20190704225334.26170-7-jacopo@jmondi.org>", "date": "2019-07-04T22:53:31", "name": "[libcamera-devel,6/9] libcamera: stream: Add operation to map buffers", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "99a2dea6716fea244cbde9addb6e56b5e52a9dd1", "submitter": { "id": 3, "url": "https://patchwork.libcamera.org/api/people/3/?format=api", "name": "Jacopo Mondi", "email": "jacopo@jmondi.org" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/1627/mbox/", "series": [ { "id": 407, "url": "https://patchwork.libcamera.org/api/series/407/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=407", "date": "2019-07-04T22:53:25", "name": "Add support for external bufferes", "version": 1, "mbox": "https://patchwork.libcamera.org/series/407/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/1627/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/1627/checks/", "tags": {}, "headers": { "Return-Path": "<jacopo@jmondi.org>", "Received": [ "from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net\n\t[217.70.183.197])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6E3B560C2C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 5 Jul 2019 00:52:31 +0200 (CEST)", "from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 060D11C0008;\n\tThu, 4 Jul 2019 22:52:30 +0000 (UTC)" ], "X-Originating-IP": "2.224.242.101", "From": "Jacopo Mondi <jacopo@jmondi.org>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Fri, 5 Jul 2019 00:53:31 +0200", "Message-Id": "<20190704225334.26170-7-jacopo@jmondi.org>", "X-Mailer": "git-send-email 2.21.0", "In-Reply-To": "<20190704225334.26170-1-jacopo@jmondi.org>", "References": "<20190704225334.26170-1-jacopo@jmondi.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH 6/9] libcamera: stream: Add operation to\n\tmap buffers", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.23", "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>", "X-List-Received-Date": "Thu, 04 Jul 2019 22:52:31 -0000" }, "content": "Add and operation to map external buffers provided by applications in\na Request to the Stream's internal buffers used by the pipeline handlers\nto interact with the video device.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n include/libcamera/buffer.h | 1 +\n include/libcamera/stream.h | 6 ++\n src/libcamera/stream.cpp | 116 +++++++++++++++++++++++++++++++++++++\n 3 files changed, 123 insertions(+)", "diff": "diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h\nindex 260a62e9e77e..d5d3dc90a096 100644\n--- a/include/libcamera/buffer.h\n+++ b/include/libcamera/buffer.h\n@@ -59,6 +59,7 @@ private:\n \tfriend class BufferPool;\n \tfriend class PipelineHandler;\n \tfriend class Request;\n+\tfriend class Stream;\n \tfriend class V4L2VideoDevice;\n \n \tvoid cancel();\ndiff --git a/include/libcamera/stream.h b/include/libcamera/stream.h\nindex 796f1aff2602..74415062cbdd 100644\n--- a/include/libcamera/stream.h\n+++ b/include/libcamera/stream.h\n@@ -85,6 +85,8 @@ public:\n \tconst StreamConfiguration &configuration() const { return configuration_; }\n \tMemoryType memoryType() const { return memoryType_; }\n \n+\tBuffer *mapBuffer(Buffer *applicationBuffer);\n+\n protected:\n \tfriend class Camera;\n \n@@ -94,6 +96,10 @@ protected:\n \tBufferPool bufferPool_;\n \tStreamConfiguration configuration_;\n \tMemoryType memoryType_;\n+\n+private:\n+\tstd::vector<Buffer *> mappableBuffers_;\n+\tstd::map<unsigned int, Buffer *> bufferMap_;\n };\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp\nindex 97e0f429c9fb..4585c0db77a4 100644\n--- a/src/libcamera/stream.cpp\n+++ b/src/libcamera/stream.cpp\n@@ -13,6 +13,8 @@\n #include <iomanip>\n #include <sstream>\n \n+#include <libcamera/request.h>\n+\n #include \"log.h\"\n \n /**\n@@ -470,6 +472,26 @@ void Stream::createBuffers(unsigned int count)\n \t\treturn;\n \n \tbufferPool_.createBuffers(count);\n+\n+\t/* Streams with internal memory usage do not need buffer mapping. */\n+\tif (memoryType_ == InternalMemory)\n+\t\treturn;\n+\n+\t/*\n+\t * Prepare for buffer mapping by queuing all buffers from the internal\n+\t * pool. Each external buffer presented by application will be mapped\n+\t * on an internal one.\n+\t */\n+\tmappableBuffers_.clear();\n+\tfor (Buffer &buffer : bufferPool_.buffers()) {\n+\t\t/*\n+\t\t * Reserve all planes to support mapping multiplanar buffers.\n+\t\t * \\todo I would use VIDEO_MAX_PLANES but it's a V4L2 thing.\n+\t\t */\n+\t\tbuffer.planes().resize(3);\n+\n+\t\tmappableBuffers_.push_back(&buffer);\n+\t}\n }\n \n /**\n@@ -480,6 +502,100 @@ void Stream::destroyBuffers()\n \tbufferPool_.destroyBuffers();\n }\n \n+/**\n+ * \\brief Map an application provided buffer to a stream buffer\n+ * \\param applicationBuffer The application provided buffer\n+ *\n+ * If a Stream has been configured to use application provided buffers a\n+ * mapping between the external buffers and the internal ones, which are\n+ * actually used to interface with the video device, is required.\n+ *\n+ * The most commonly used mechanism to perform zero-copy memory sharing\n+ * on Linux-based system is dmabuf, which allows user-space applications to\n+ * share buffers by exchanging dmabuf generated file descriptors. This\n+ * operations assumes that all application provided buffers have each of their\n+ * used memory planes exported as dmabuf file descriptor, to copy them in\n+ * the buffer to be then queued on the video device by pipeline handlers.\n+ *\n+ * Perform mapping by maintaining a cache in a map associating the dmabuf file\n+ * descriptor of the application provided buffer to one of the stream's internal\n+ * buffers to provide pipeline handlers the buffer to use to interact with video\n+ * devices.\n+ *\n+ * Once the buffer completes, the mapping should be reverted to return to\n+ * the application the buffer it first provided here.\n+ *\n+ * \\return The stream buffer which maps to the application provided buffer\n+ */\n+Buffer *Stream::mapBuffer(Buffer *applicationBuffer)\n+{\n+\tunsigned int key = applicationBuffer->planes()[0].dmabuf();\n+\n+\t/*\n+\t * Buffer hit: the application buffer has already been mapped, return\n+\t * the assigned stream buffer\n+\t */\n+\tauto mapped = bufferMap_.find(key);\n+\tif (mapped != bufferMap_.end()) {\n+\t\tBuffer *buffer = mapped->second;\n+\n+\t\t/*\n+\t\t * Keep the mappableBuffers_ vector warm: move the hit buffer to\n+\t\t * the vector end as on a buffer miss buffers are below evicted\n+\t\t * from the vector head.\n+\t\t */\n+\t\tauto it = std::find(mappableBuffers_.begin(),\n+\t\t\t\t mappableBuffers_.end(), buffer);\n+\n+\t\tASSERT(it != mappableBuffers_.end());\n+\t\tstd::rotate(it, it + 1, mappableBuffers_.end());\n+\n+\t\treturn buffer;\n+\t}\n+\n+\t/*\n+\t * Buffer miss: assign to the application buffer the stream buffer\n+\t * at mappableBuffers_ begin, then move it to the end.\n+\t */\n+\tBuffer *buffer = *(mappableBuffers_.begin());\n+\tstd::rotate(mappableBuffers_.begin(), mappableBuffers_.begin() + 1,\n+\t\t mappableBuffers_.end());\n+\n+\n+\t /* Remove the [key, buffer] entry buffer from the buffer map */\n+\tauto deadBuf = std::find_if(bufferMap_.begin(), bufferMap_.end(),\n+\t\t\t\t [&](std::pair<const unsigned int, Buffer *> &map) {\n+\t\t\t\t\treturn bufferMap_[map.first] == buffer;\n+\t\t\t\t });\n+\tif (deadBuf != bufferMap_.end())\n+\t\tbufferMap_.erase(deadBuf);\n+\n+\t/*\n+\t * Assign the buffer by copying the dmabuf file descriptors from the\n+\t * application provided buffer.\n+\t */\n+\tfor (unsigned int i = 0; i < applicationBuffer->planes().size(); ++i) {\n+\t\tint fd = applicationBuffer->planes()[i].dmabuf();\n+\n+\t\t/*\n+\t\t * The ARC camera stack seems to report more planes that the\n+\t\t * ones it actually uses.\n+\t\t */\n+\t\tif (fd < 0)\n+\t\t\tbreak;\n+\n+\t\tbuffer->planes()[i].setDmabuf(fd, 0);\n+\t}\n+\n+\t/* Pipeline handlers use request_ at buffer completion time. */\n+\tbuffer->request_ = applicationBuffer->request();\n+\n+\t/* And finally, store the mapping for later re-use and return it. */\n+\tbufferMap_[key] = buffer;\n+\n+\treturn buffer;\n+}\n+\n /**\n * \\var Stream::bufferPool_\n * \\brief The pool of buffers associated with the stream\n", "prefixes": [ "libcamera-devel", "6/9" ] }