Patch Detail
Show a patch.
GET /api/1.1/patches/14923/?format=api
{ "id": 14923, "url": "https://patchwork.libcamera.org/api/1.1/patches/14923/?format=api", "web_url": "https://patchwork.libcamera.org/patch/14923/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/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": "<20211130233634.34173-10-jacopo@jmondi.org>", "date": "2021-11-30T23:36:32", "name": "[libcamera-devel,v3,09/11] libcamera: request: Add Request::Private::prepare()", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "b597baba0f43eb6e4e5042c0245f8447ebf7bc53", "submitter": { "id": 3, "url": "https://patchwork.libcamera.org/api/1.1/people/3/?format=api", "name": "Jacopo Mondi", "email": "jacopo@jmondi.org" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/14923/mbox/", "series": [ { "id": 2788, "url": "https://patchwork.libcamera.org/api/1.1/series/2788/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2788", "date": "2021-11-30T23:36:23", "name": "libcamera: Add support for Fence", "version": 3, "mbox": "https://patchwork.libcamera.org/series/2788/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/14923/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/14923/checks/", "tags": {}, "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 5A76BBDB13\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 30 Nov 2021 23:35:59 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 199BE6072B;\n\tWed, 1 Dec 2021 00:35:59 +0100 (CET)", "from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net\n\t[217.70.183.201])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7817F60718\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 1 Dec 2021 00:35:57 +0100 (CET)", "(Authenticated sender: jacopo@jmondi.org)\n\tby relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 951AC1BF206;\n\tTue, 30 Nov 2021 23:35:56 +0000 (UTC)" ], "From": "Jacopo Mondi <jacopo@jmondi.org>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Wed, 1 Dec 2021 00:36:32 +0100", "Message-Id": "<20211130233634.34173-10-jacopo@jmondi.org>", "X-Mailer": "git-send-email 2.33.1", "In-Reply-To": "<20211130233634.34173-1-jacopo@jmondi.org>", "References": "<20211130233634.34173-1-jacopo@jmondi.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v3 09/11] libcamera: request: Add\n\tRequest::Private::prepare()", "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>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Add a prepare() function to the Private Request representation.\n\nThe prepare() function is used by the PipelineHandler class to\nprepare a Request to be queued to the hardware.\n\nThe current implementation of prepare() handles the fences associated\nwith the Framebuffers part of a Request. The function starts an event\nnotifier for each of those and emits the Request::prepared signal when\nall fences have been signalled or an optional timeout has expired.\n\nThe optional timeout allows to interrupt blocked waits and notify the\nRequest as failed so that it can be cancelled.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n include/libcamera/internal/request.h | 15 +++\n src/libcamera/request.cpp | 131 +++++++++++++++++++++++++++\n 2 files changed, 146 insertions(+)", "diff": "diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h\nindex 1340ffa2a683..740ab21ac7e0 100644\n--- a/include/libcamera/internal/request.h\n+++ b/include/libcamera/internal/request.h\n@@ -7,10 +7,17 @@\n #ifndef __LIBCAMERA_INTERNAL_REQUEST_H__\n #define __LIBCAMERA_INTERNAL_REQUEST_H__\n \n+#include <chrono>\n+#include <map>\n #include <memory>\n \n+#include <libcamera/base/event_notifier.h>\n+#include <libcamera/base/timer.h>\n+\n #include <libcamera/request.h>\n \n+using namespace std::chrono_literals;\n+\n namespace libcamera {\n \n class Camera;\n@@ -32,16 +39,24 @@ public:\n \tvoid cancel();\n \tvoid reuse();\n \n+\tvoid prepare(std::chrono::milliseconds timeout = 0ms);\n+\tSignal<> prepared;\n+\n private:\n \tfriend class PipelineHandler;\n \n \tvoid doCancelRequest();\n+\tvoid notifierActivated(FrameBuffer *buffer);\n+\tvoid timeout();\n \n \tCamera *camera_;\n \tbool cancelled_;\n \tuint32_t sequence_ = 0;\n+\tbool prepared_ = false;\n \n \tstd::unordered_set<FrameBuffer *> pending_;\n+\tstd::map<FrameBuffer *, std::unique_ptr<EventNotifier>> notifiers_;\n+\tstd::unique_ptr<Timer> timer_;\n };\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp\nindex 699ea1db2e16..3d66ac6d2b03 100644\n--- a/src/libcamera/request.cpp\n+++ b/src/libcamera/request.cpp\n@@ -135,6 +135,8 @@ void Request::Private::doCancelRequest()\n \n \tcancelled_ = true;\n \tpending_.clear();\n+\tnotifiers_.clear();\n+\ttimer_.reset();\n }\n \n /**\n@@ -163,6 +165,135 @@ void Request::Private::reuse()\n \tsequence_ = 0;\n \tcancelled_ = false;\n \tpending_.clear();\n+\tnotifiers_.clear();\n+\ttimer_.reset();\n+}\n+\n+/**\n+ * \\brief Prepare the Request to be queued to the device\n+ * \\param[in] timeout Optional expiration timeout\n+ *\n+ * Prepare a Request to be queued to the hardware device by ensuring it is\n+ * ready for the incoming memory transfers.\n+ *\n+ * This currently means waiting on each frame buffer acquire fence to be\n+ * signalled. An optional expiration timeout can be specified. If not all the\n+ * fences have been signalled correctly before the timeout expires the Request\n+ * is cancelled.\n+ *\n+ * The function immediately emits the prepared signal if all the prepare\n+ * operations have been completed synchronously. If instead the prepare\n+ * operations require to wait the completion of asynchronous events, such as\n+ * fences notifications or timer expiration, the prepared signal is emitted upon\n+ * the asynchronous event completion.\n+ *\n+ * As we currently only handle fences, the function emits the prepared signal\n+ * immediately if there are no fences to wait on. Otherwise the prepared signal\n+ * is emitted when all fences have been signalled or the optional timeout has\n+ * expired.\n+ *\n+ * If not all the fences have been correctly signalled or the optional timeout\n+ * has expired the Request will emit the Request::prepared signal, but will\n+ * be set in error state by setting the Request::cancelled_ flag to true.\n+ *\n+ * The intended user of this function is the PipelineHandler base class, which\n+ * 'prepares' a Request before queuing it to the hardware device. A Request is\n+ * ready for being queued to the hardware if the Request::prepared_ flag is set\n+ * to true and if Request::cancelled_ is set to false.\n+ */\n+void Request::Private::prepare(std::chrono::milliseconds timeout)\n+{\n+\tprepared_ = false;\n+\n+\t/* Create and connect one notifier for each synchronization fence. */\n+\tfor (FrameBuffer *buffer : pending_) {\n+\n+\t\tif (!buffer->fence())\n+\t\t\tcontinue;\n+\n+\t\tnotifiers_[buffer] = std::make_unique<EventNotifier>(buffer->fence()->fd()->get(),\n+\t\t\t\t\t\t\t\t EventNotifier::Read);\n+\t}\n+\n+\tif (notifiers_.empty()) {\n+\t\tprepared_ = true;\n+\t\tprepared.emit();\n+\t\treturn;\n+\t}\n+\n+\tfor (auto &it : notifiers_) {\n+\t\tFrameBuffer *buffer = it.first;\n+\t\tstd::unique_ptr<EventNotifier> ¬ifier = it.second;\n+\n+\t\tnotifier->activated.connect(this, [this, buffer] {\n+\t\t\t\t\t\t\tnotifierActivated(buffer);\n+\t\t\t\t\t });\n+\t}\n+\n+\t/*\n+\t * In case a timeout is specified, create a timer and set it up.\n+\t *\n+\t * The timer must be created here instead of in the Request constructor,\n+\t * in order to be bound to the pipeline handler thread.\n+\t */\n+\tif (timeout != 0ms) {\n+\t\ttimer_ = std::make_unique<Timer>();\n+\t\ttimer_->timeout.connect(this, &Request::Private::timeout);\n+\t\ttimer_->start(timeout);\n+\t}\n+}\n+\n+/**\n+ * \\var Request::Private::prepared\n+ * \\brief Request preparation completed Signal\n+ *\n+ * The signal is emitted once the request preparation has completed (prepared_\n+ * == true) and is ready for being queued. The Request might complete with\n+ * errors in which case the cancelled_ flag it is set to true and the Request\n+ * is cancelled by the slot associated with this signal.\n+ *\n+ * The intended slot for this signal is the PipelineHandler::doQueueRequests()\n+ * function which queues Request after they have been prepared or cancel them\n+ * if they have failed preparing.\n+ */\n+\n+void Request::Private::notifierActivated(FrameBuffer *buffer)\n+{\n+\t/* Close the fence if successfully signalled. */\n+\tASSERT(buffer);\n+\tbuffer->resetFence();\n+\n+\t/* Remove the entry from the map and check if other fences are pending. */\n+\tauto it = notifiers_.find(buffer);\n+\tASSERT(it != notifiers_.end());\n+\tnotifiers_.erase(it);\n+\n+\tRequest *request = _o<Request>();\n+\tLOG(Request, Debug)\n+\t\t<< \"Request \" << request->cookie() << \" buffer \" << buffer\n+\t\t<< \" fence signalled\";\n+\n+\tif (!notifiers_.empty())\n+\t\treturn;\n+\n+\t/* All fences completed, delete the timer and move to state Ready. */\n+\ttimer_.reset();\n+\tprepared_ = true;\n+\tprepared.emit();\n+}\n+\n+void Request::Private::timeout()\n+{\n+\t/* A timeout can only happen if there are fences not yet signalled. */\n+\tASSERT(!notifiers_.empty());\n+\tnotifiers_.clear();\n+\n+\tRequest *request = _o<Request>();\n+\tLOG(Request, Debug) << \"Request prepare timeout: \" << request->cookie();\n+\n+\tcancelled_ = true;\n+\tprepared_ = true;\n+\tprepared.emit();\n }\n \n /**\n", "prefixes": [ "libcamera-devel", "v3", "09/11" ] }