From patchwork Thu Oct 28 11:15:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14499 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by patchwork.libcamera.org (Postfix) with ESMTPS id 33431BDB1C for ; Tue, 9 Nov 2021 17:42:53 +0000 (UTC) Received: from pendragon.ideasonboard.com (cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BEDC1DEE for ; Tue, 9 Nov 2021 18:42:52 +0100 (CET) Delivered-To: kbingham@ideasonboard.com Received: from perceval.ideasonboard.com by perceval.ideasonboard.com with LMTP id XharGCKGemFhEAAA4E0KoQ (envelope-from ) for ; Thu, 28 Oct 2021 13:14:42 +0200 Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [IPv6:2001:4b98:dc0:43:216:3eff:fe33:f827]) by perceval.ideasonboard.com (Postfix) with ESMTPS id 42798513; Thu, 28 Oct 2021 13:14:42 +0200 (CEST) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9BAEA60159; Thu, 28 Oct 2021 13:14:41 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 77070600BA for ; Thu, 28 Oct 2021 13:14:37 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id BC6ADFF802; Thu, 28 Oct 2021 11:14:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:11 +0200 Message-Id: <20211028111520.256612-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/10] libcamera: request: Make Request class Extensible X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" X-TUID: QFLPHLDQfT2F Resent-From: Kieran Bingham Resent-To: parsemail@patchwork.libcamera.org From: Laurent Pinchart Implement the D-Pointer design pattern in the Request class to allow changing internal data without affecting the public ABI. Move a few internal fields that are not needed to implement the public API to the Request::Private class already. More fields may be moved later. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- include/libcamera/internal/meson.build | 1 + include/libcamera/internal/request.h | 34 ++++++++++++++++++ include/libcamera/request.h | 6 ++-- src/libcamera/pipeline_handler.cpp | 7 ++-- src/libcamera/request.cpp | 50 +++++++++++++++++++++----- 5 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 include/libcamera/internal/request.h diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 665fd6de4ed3..cae65b0604ff 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -34,6 +34,7 @@ libcamera_internal_headers = files([ 'pipeline_handler.h', 'process.h', 'pub_key.h', + 'request.h', 'source_paths.h', 'sysfs.h', 'v4l2_device.h', diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h new file mode 100644 index 000000000000..df0cc014067e --- /dev/null +++ b/include/libcamera/internal/request.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * request.h - Request class private data + */ +#ifndef __LIBCAMERA_INTERNAL_REQUEST_H__ +#define __LIBCAMERA_INTERNAL_REQUEST_H__ + +#include + +namespace libcamera { + +class Camera; +class FrameBuffer; + +class Request::Private : public Extensible::Private +{ + LIBCAMERA_DECLARE_PUBLIC(Request) + +public: + Private(Camera *camera); + ~Private(); + + Camera *camera() const { return camera_; } + +private: + Camera *camera_; + bool cancelled_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_INTERNAL_REQUEST_H__ */ diff --git a/include/libcamera/request.h b/include/libcamera/request.h index d16904e6b679..d6bd0ba2ac17 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -25,8 +25,10 @@ class CameraControlValidator; class FrameBuffer; class Stream; -class Request +class Request : public Extensible { + LIBCAMERA_DECLARE_PRIVATE() + public: enum Status { RequestPending, @@ -70,7 +72,6 @@ private: bool completeBuffer(FrameBuffer *buffer); - Camera *camera_; ControlList *controls_; ControlList *metadata_; BufferMap bufferMap_; @@ -79,7 +80,6 @@ private: uint32_t sequence_; const uint64_t cookie_; Status status_; - bool cancelled_; }; } /* namespace libcamera */ diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index f69c4f03b80f..cada864687ff 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -19,6 +19,7 @@ #include "libcamera/internal/camera.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/media_device.h" +#include "libcamera/internal/request.h" #include "libcamera/internal/tracepoints.h" /** @@ -311,7 +312,7 @@ void PipelineHandler::queueRequest(Request *request) { LIBCAMERA_TRACEPOINT(request_queue, request); - Camera *camera = request->camera_; + Camera *camera = request->_d()->camera(); Camera::Private *data = camera->_d(); data->queuedRequests_.push_back(request); @@ -360,7 +361,7 @@ void PipelineHandler::queueRequest(Request *request) */ bool PipelineHandler::completeBuffer(Request *request, FrameBuffer *buffer) { - Camera *camera = request->camera_; + Camera *camera = request->_d()->camera(); camera->bufferCompleted.emit(request, buffer); return request->completeBuffer(buffer); } @@ -381,7 +382,7 @@ bool PipelineHandler::completeBuffer(Request *request, FrameBuffer *buffer) */ void PipelineHandler::completeRequest(Request *request) { - Camera *camera = request->camera_; + Camera *camera = request->_d()->camera(); request->complete(); diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 17fefab7ad0e..33fee1ac05ba 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -20,10 +20,11 @@ #include "libcamera/internal/camera.h" #include "libcamera/internal/camera_controls.h" #include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/request.h" #include "libcamera/internal/tracepoints.h" /** - * \file request.h + * \file libcamera/request.h * \brief Describes a frame capture request to be processed by a camera */ @@ -31,6 +32,37 @@ namespace libcamera { LOG_DEFINE_CATEGORY(Request) +/** + * \class Request::Private + * \brief Request private data + * + * The Request::Private class stores all private data associated with a + * request. It implements the d-pointer design pattern to hide core + * Request data from the public API, and exposes utility functions to + * internal users of the request (namely the PipelineHandler class and its + * subclasses). + */ + +/** + * \brief Create a Request::Private + * \param camera The Camera that creates the request + */ +Request::Private::Private(Camera *camera) + : camera_(camera), cancelled_(false) +{ +} + +Request::Private::~Private() +{ +} + +/** + * \fn Request::Private::camera() + * \brief Retrieve the camera this request has been queued to + * \return The Camera this request has been queued to, or nullptr if the + * request hasn't been queued + */ + /** * \enum Request::Status * Request completion status @@ -75,8 +107,8 @@ LOG_DEFINE_CATEGORY(Request) * completely opaque to libcamera. */ Request::Request(Camera *camera, uint64_t cookie) - : camera_(camera), sequence_(0), cookie_(cookie), - status_(RequestPending), cancelled_(false) + : Extensible(std::make_unique(camera)), sequence_(0), + cookie_(cookie), status_(RequestPending) { controls_ = new ControlList(controls::controls, camera->_d()->validator()); @@ -126,7 +158,7 @@ void Request::reuse(ReuseFlag flags) sequence_ = 0; status_ = RequestPending; - cancelled_ = false; + _d()->cancelled_ = false; controls_->clear(); metadata_->clear(); @@ -282,7 +314,7 @@ void Request::complete() ASSERT(status_ == RequestPending); ASSERT(!hasPendingBuffers()); - status_ = cancelled_ ? RequestCancelled : RequestComplete; + status_ = _d()->cancelled_ ? RequestCancelled : RequestComplete; LOG(Request, Debug) << toString(); @@ -299,17 +331,19 @@ void Request::complete() */ void Request::cancel() { + Private *const d = _d(); + LIBCAMERA_TRACEPOINT(request_cancel, this); ASSERT(status_ == RequestPending); for (FrameBuffer *buffer : pending_) { buffer->cancel(); - camera_->bufferCompleted.emit(this, buffer); + d->camera_->bufferCompleted.emit(this, buffer); } pending_.clear(); - cancelled_ = true; + d->cancelled_ = true; } /** @@ -335,7 +369,7 @@ bool Request::completeBuffer(FrameBuffer *buffer) buffer->_d()->setRequest(nullptr); if (buffer->metadata().status == FrameMetadata::FrameCancelled) - cancelled_ = true; + _d()->cancelled_ = true; return !hasPendingBuffers(); } From patchwork Thu Oct 28 11:15:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14397 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C47A6BF415 for ; Thu, 28 Oct 2021 11:14:43 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 503AB60253; Thu, 28 Oct 2021 13:14:42 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 27FBF600BA for ; Thu, 28 Oct 2021 13:14:38 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id B186DFF80E; Thu, 28 Oct 2021 11:14:37 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:12 +0200 Message-Id: <20211028111520.256612-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/10] libcamera: event_notifier: Add 'enable' constructor parameter X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add an 'enable' parameter to the EventNotifier class constructor. Currently an EvenNotifier is enabled as soon as it is constructed. Add an optional parameter to the class constructor to allow post-poning the notifier activation. As the 'enable' parameter has a default value of true, existing users of the class should not be updated. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham Reviewed-by: Umang Jain Reviewed-by: Laurent Pinchart --- include/libcamera/base/event_notifier.h | 2 +- src/libcamera/base/event_notifier.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/libcamera/base/event_notifier.h b/include/libcamera/base/event_notifier.h index f7722a32ef55..4d373a5290cc 100644 --- a/include/libcamera/base/event_notifier.h +++ b/include/libcamera/base/event_notifier.h @@ -25,7 +25,7 @@ public: Exception, }; - EventNotifier(int fd, Type type, Object *parent = nullptr); + EventNotifier(int fd, Type type, Object *parent = nullptr, bool enable = true); virtual ~EventNotifier(); Type type() const { return type_; } diff --git a/src/libcamera/base/event_notifier.cpp b/src/libcamera/base/event_notifier.cpp index fd93c0878c6f..40428cf24a50 100644 --- a/src/libcamera/base/event_notifier.cpp +++ b/src/libcamera/base/event_notifier.cpp @@ -26,8 +26,11 @@ namespace libcamera { * * The EventNotifier models a file descriptor event source that can be * monitored. It is created with the file descriptor to be monitored and the - * type of event, and is enabled by default. It will emit the \ref activated - * signal whenever an event of the monitored type occurs on the file descriptor. + * type of event. It will emit the \ref activated signal whenever an event of + * the monitored type occurs on the file descriptor. + * + * An EventNotifier is enabled by default when created, unless otherwise + * specified through the optional 'enable' constructor parameter. * * Supported type of events are EventNotifier::Read, EventNotifier::Write and * EventNotifier::Exception. The type is specified when constructing the @@ -62,11 +65,12 @@ namespace libcamera { * \param[in] fd The file descriptor to monitor * \param[in] type The event type to monitor * \param[in] parent The parent Object + * \param[in] enable Notifier enable flag */ -EventNotifier::EventNotifier(int fd, Type type, Object *parent) +EventNotifier::EventNotifier(int fd, Type type, Object *parent, bool enable) : Object(parent), fd_(fd), type_(type), enabled_(false) { - setEnabled(true); + setEnabled(enable); } EventNotifier::~EventNotifier() From patchwork Thu Oct 28 11:15:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14398 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C3C6EBF415 for ; Thu, 28 Oct 2021 11:14:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 81BFD60253; Thu, 28 Oct 2021 13:14:46 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 27C5A600C2 for ; Thu, 28 Oct 2021 13:14:38 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 5499DFF802; Thu, 28 Oct 2021 11:14:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:13 +0200 Message-Id: <20211028111520.256612-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/10] libcamera: Introduce Fence class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Fences are a synchronization mechanism that allows to receive event notifications of a file descriptor with an optional expiration timeout. Introduce the Fence class to model such a mechanism in libcamera. Signed-off-by: Jacopo Mondi --- include/libcamera/internal/fence.h | 64 +++++++++ include/libcamera/internal/meson.build | 1 + src/libcamera/fence.cpp | 185 +++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 251 insertions(+) create mode 100644 include/libcamera/internal/fence.h create mode 100644 src/libcamera/fence.cpp diff --git a/include/libcamera/internal/fence.h b/include/libcamera/internal/fence.h new file mode 100644 index 000000000000..5a78e0f864c7 --- /dev/null +++ b/include/libcamera/internal/fence.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * internal/fence.h - Synchronization fence + */ +#ifndef __LIBCAMERA_INTERNAL_FENCE_H__ +#define __LIBCAMERA_INTERNAL_FENCE_H__ + +#include + +#include +#include +#include +#include + +namespace libcamera { + +class Fence +{ +public: + explicit Fence(int fenceFd, unsigned int timeoutMs = kFenceTimeout); + Fence(Fence &&other); + + Fence &operator=(Fence &&other); + + int fd() const { return fd_.fd(); } + + unsigned int timeout() const { return timeout_; } + bool completed() const { return completed_; } + bool expired() const { return expired_; } + + void enable(); + void disable(); + + Signal<> complete; + +private: + LIBCAMERA_DISABLE_COPY(Fence) + + /* 300 milliseconds default timeout. */ + static constexpr unsigned int kFenceTimeout = 300; + + void moveFence(Fence &other); + + void activated(); + void timedout(); + + FileDescriptor fd_; + EventNotifier notifier_; + + Timer timer_; + unsigned int timeout_; + + bool completed_ = false; + bool expired_ = false; + + std::mutex mutex_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_INTERNAL_FENCE_H__ */ + diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index cae65b0604ff..32d5c3387de3 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -22,6 +22,7 @@ libcamera_internal_headers = files([ 'device_enumerator.h', 'device_enumerator_sysfs.h', 'device_enumerator_udev.h', + 'fence.h', 'formats.h', 'framebuffer.h', 'ipa_manager.h', diff --git a/src/libcamera/fence.cpp b/src/libcamera/fence.cpp new file mode 100644 index 000000000000..8fadb2c21f03 --- /dev/null +++ b/src/libcamera/fence.cpp @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * fence.cpp - Synchronization fence + */ + +#include +#include +#include + +namespace libcamera { + +/** + * \file internal/fence.h + * \brief Synchronization fence + */ + +/** + * \class Fence + * \brief Synchronization fence class + * + * A Fence is a synchronization mechanism that allows to wait for a read event + * to happen on a file descriptor before an optional timeout expires. + * + * A Fence is created with a default timeout of 300 milliseconds, which can + * be overridden through the 'timeout' constructor parameter. Passing a 0 + * timeout to the constructor disables timeouts completely. + * + * A Fence wraps a FileDescriptor and implements a move-only semantic, as Fence + * instances cannot be copied but only moved, causing the moved Fence to be + * reset by invalidating the wrapped FileDescriptor by disabling its + * notification and timeout mechanisms. + * + * When a read event is notified, the Fence is said to be 'completed', + * alternatively if the timeout expires before any event is notified the Fence + * is said to be 'expired'. + * + * In both cases, when an event notification happens or a timeout expires, the + * class emits the 'complete' signal, to which users of the class can connect + * to and check if the Fence has completed or has expired by calling the + * completed() and expired() functions. + * + * Fence instances are non-active by default (ie no events or timeout are + * generated) and need to be enabled by calling the enable() function. Likewise + * a Fence can be disabled by calling the disable() function. + * + * After a Fence has expired no events are generated and the Fence need to be + * manually re-enabled. Likewise, if the Fence is signalled the expiration + * timeout is cancelled. + */ + +/** + * \brief Create a synchronization fence + * \param[in] fenceFd The synchronization fence file descriptor + * \param[in] timeoutMs The optional fence timeout. Set to 0 to disable timeout + */ +Fence::Fence(int fenceFd, unsigned int timeoutMs) + : fd_(std::move(fenceFd)), + notifier_(fd_.fd(), EventNotifier::Read, nullptr, false), + timeout_(timeoutMs) +{ + notifier_.activated.connect(this, &Fence::activated); + + timer_.timeout.connect(this, &Fence::timedout); +} + +void Fence::moveFence(Fence &other) +{ + fd_ = std::move(other.fd_); + + other.disable(); + if (other.timer_.isRunning()) + other.timer_.stop(); + other.timeout_ = 0; +} + +/** + * \brief Move-construct a Fence + * \param[in] other The other fence to move + */ +Fence::Fence(Fence &&other) + : notifier_(other.fd(), EventNotifier::Read, nullptr, false) +{ + moveFence(other); + + notifier_.activated.connect(this, &Fence::activated); + timer_.timeout.connect(this, &Fence::timedout); +} + +/** + * \brief Move-assign the value of the \a other fence to this + * \param[in] other The other fence to move + * \return This fence + */ +Fence &Fence::operator=(Fence &&other) +{ + moveFence(other); + + notifier_ = EventNotifier(fd_.fd(), EventNotifier::Read, nullptr, false); + + return *this; +} + +/** + * \fn Fence::fd() const + * \brief Return the synchronization fence file descriptor + * \return The synchronization fence file descriptor + */ + +/** + * \fn Fence::timeout() + * \brief Retrieve the fence timeout + * \return The fence timeout in milliseconds + */ + +/** + * \fn Fence::completed() + * \brief Check if the fence has completed before timing out + * \return True if the fence has completed + */ + +/** + * \fn Fence::expired() + * \brief Check if the fence has expired before completing + * \return True if the fence has expired + */ + +/** + * \brief Enable a fence by enabling events notifications + */ +void Fence::enable() +{ + MutexLocker lock(mutex_); + + expired_ = false; + completed_ = false; + + notifier_.setEnabled(true); + if (timeout_) + timer_.start(timeout_); +} + +/** + * \brief Disable a fence by disabling events notifications + */ +void Fence::disable() +{ + notifier_.setEnabled(false); +} + +/** + * \var Fence::complete + * \brief The fence completion signal + * + * A Fence is completed if signalled or timeout. + */ + +void Fence::activated() +{ + MutexLocker lock(mutex_); + + if (timer_.isRunning()) + timer_.stop(); + + completed_ = true; + expired_ = false; + + complete.emit(); +} + +void Fence::timedout() +{ + MutexLocker lock(mutex_); + + expired_ = true; + completed_ = false; + + /* Disable events notification after timeout. */ + disable(); + + complete.emit(); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6727a777d804..6fb0d5f49b63 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -14,6 +14,7 @@ libcamera_sources = files([ 'delayed_controls.cpp', 'device_enumerator.cpp', 'device_enumerator_sysfs.cpp', + 'fence.cpp', 'file_descriptor.cpp', 'formats.cpp', 'framebuffer.cpp', From patchwork Thu Oct 28 11:15:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14399 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 8A7C4C324E for ; Thu, 28 Oct 2021 11:14:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DDD2360334; Thu, 28 Oct 2021 13:14:46 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 63722600BA for ; Thu, 28 Oct 2021 13:14:39 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id E8CD5FF80B; Thu, 28 Oct 2021 11:14:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:14 +0200 Message-Id: <20211028111520.256612-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/10] test: Add test for the Fence class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a test for the Fence class by testing completion and expiration of a Fence and testing that move semantic is implemented correctly. Signed-off-by: Jacopo Mondi --- test/fence.cpp | 148 +++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 149 insertions(+) create mode 100644 test/fence.cpp diff --git a/test/fence.cpp b/test/fence.cpp new file mode 100644 index 000000000000..9fb92b1c250b --- /dev/null +++ b/test/fence.cpp @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * fence.cpp - Fence test + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "test.h" + +using namespace libcamera; +using namespace std; + +class FenceTest : public Test +{ +protected: + int init(); + int run(); + void cleanup(); + +private: + void timeout(); + void completed(); + + int eventfd_; + Timer timer_; + EventDispatcher *dispatcher; + Fence *fence_; +}; + +int FenceTest::init() +{ + timer_.timeout.connect(this, &FenceTest::timeout); + dispatcher = Thread::current()->eventDispatcher(); + + eventfd_ = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (eventfd_ < 0) { + cerr << "Unable to create eventfd" << endl; + return TestFail; + } + + fence_ = new Fence(eventfd_); + if (!eventfd_) { + cerr << "Fence creation should not reset the file descriptor" << endl; + return TestFail; + } + + if (fence_->fd() != eventfd_) { + cerr << "Fence file descriptor should not be duplicated" << endl; + return TestFail; + } + + fence_->complete.connect(this, &FenceTest::completed); + + return 0; +} + +void FenceTest::timeout() +{ + uint64_t value = 1; + ssize_t ret = write(eventfd_, &value, sizeof(value)); + if (ret != sizeof(value)) + cerr << "Failed to write to event fd" << endl; + + /* Let the fence complete on the eventfd read event. */ + dispatcher->processEvents(); +} + +void FenceTest::completed() +{ + if (fence_->expired()) + return; + + uint64_t value; + ssize_t ret = read(eventfd_, &value, sizeof(value)); + if (ret != sizeof(value)) + cerr << "Failed to read from event fd" << endl; +} + +int FenceTest::run() +{ + /* Activate the fence and schedule a wake-up before it expires. */ + fence_->enable(); + timer_.start(50); + + dispatcher->processEvents(); + + if (fence_->expired()) { + cerr << "Fence should not have expired" << endl; + return TestFail; + } + + if (!fence_->completed()) { + cerr << "Fence should have completed" << endl; + return TestFail; + } + + /* Now let the fence expire. */ + fence_->enable(); + dispatcher->processEvents(); + + if (fence_->completed()) { + cerr << "Fence should not have completed" << endl; + return TestFail; + } + + if (!fence_->expired()) { + cerr << "Fence should have expired" << endl; + return TestFail; + } + + /* + * Test fence move semantic. + * + * Create two temporary fences and verify we can move them. + */ + Fence fence1(eventfd_, 500); + Fence fence2(0, 500); + fence2 = std::move(fence1); + + if (fence1.fd() != -1) { + cerr << "A moved fence should have an invalid fd" << endl; + return TestFail; + } + + if (fence2.fd() != eventfd_ || fence2.timeout() != 500) { + cerr << "Faile to move fence" << endl; + return TestFail; + } + + return 0; +} + +void FenceTest::cleanup() +{ + close(eventfd_); + delete fence_; +} + +TEST_REGISTER(FenceTest) diff --git a/test/meson.build b/test/meson.build index d0466f17d7b6..377e392628bf 100644 --- a/test/meson.build +++ b/test/meson.build @@ -40,6 +40,7 @@ internal_tests = [ ['event-dispatcher', 'event-dispatcher.cpp'], ['event-thread', 'event-thread.cpp'], ['file', 'file.cpp'], + ['fence', 'fence.cpp'], ['file-descriptor', 'file-descriptor.cpp'], ['flags', 'flags.cpp'], ['hotplug-cameras', 'hotplug-cameras.cpp'], From patchwork Thu Oct 28 11:15:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14400 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 8A845BF415 for ; Thu, 28 Oct 2021 11:14:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C576A600F9; Thu, 28 Oct 2021 13:14:47 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 06308600C0 for ; Thu, 28 Oct 2021 13:14:40 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 8FA7DFF802; Thu, 28 Oct 2021 11:14:39 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:15 +0200 Message-Id: <20211028111520.256612-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/10] libcamera: request: Add support for fences X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Prepare the Request::Private class to handle fences by providing a storage vector and interface functions to handle the number of pending and expired fences. The intended user of the interface is the PipelineHandler class Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- include/libcamera/internal/request.h | 21 +++++++ src/libcamera/request.cpp | 89 +++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h index df0cc014067e..2be4874756de 100644 --- a/include/libcamera/internal/request.h +++ b/include/libcamera/internal/request.h @@ -7,8 +7,12 @@ #ifndef __LIBCAMERA_INTERNAL_REQUEST_H__ #define __LIBCAMERA_INTERNAL_REQUEST_H__ +#include + #include +#include + namespace libcamera { class Camera; @@ -24,9 +28,26 @@ public: Camera *camera() const { return camera_; } + unsigned int pendingFences() const { return pendingFences_; } + unsigned int expiredFences() const { return expiredFences_; } + + void reuse(); + + std::vector &fences() { return fences_; } + void addFence(Fence &&fence); + void clearFences(); + + void fenceExpired(); + void fenceCompleted(); + private: Camera *camera_; bool cancelled_; + + unsigned int pendingFences_ = 0; + unsigned int expiredFences_ = 0; + + std::vector fences_; }; } /* namespace libcamera */ diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 33fee1ac05ba..e88eee1fac36 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -63,6 +63,92 @@ Request::Private::~Private() * request hasn't been queued */ +/** + * \fn Request::Private::pendingFences() + * \brief Retrieve the number of pending fences + * + * A Fence is pending if has not yet been signalled or it has not expired yet. + * + * \return The number of pending fences + */ + +/** + * \fn Request::Private::expiredFences() + * \brief Retrieve the number of expired fences + * \return The number of expired fences + */ + +/** + * \brief Reset the request for reuse + */ +void Request::Private::reuse() +{ + cancelled_ = false; + + fences_.clear(); + pendingFences_ = 0; + expiredFences_ = 0; +} + +/** + * \fn Request::Private::fences() + * \brief Retrieve a reference to the vector of pending fences + * \return A reference to the vector of pending fences + */ + +/** + * \brief Move a Fence into the Request + * + * Move a Fence into the Request and increase the pending fences + * counter. The Fence is now stored into the Request and the original + * one passed in as parameter is reset. + * + * Once the Fence completes, either because it is signalled or because + * it has expired, the caller shall notify the Request about this by + * calling fenceCompleted() or fenceExpired(); + */ +void Request::Private::addFence(Fence &&fence) +{ + fences_.push_back(std::move(fence)); + pendingFences_++; +} + +/** + * \brief Release all Fences stored in the request + * + * Clear the vector of fences in the Request by releasing all of them. + * All Fences are closed and their file descriptors reset to 0. + */ +void Request::Private::clearFences() +{ + ASSERT(!pendingFences_); + fences_.clear(); +} + +/** + * \brief Notify that a Fence has been signalled + * + * Notify to the Request that a Fence has completed. This function decrease the + * number of pending Fences in the request. + */ +void Request::Private::fenceCompleted() +{ + pendingFences_--; +} + +/** + * \brief Notify that a Fence has expired + * + * Notify to the Request that a Fence has expired. This function decrease the + * number of pending Fences in the request and increase the number of expired + * ones. + */ +void Request::Private::fenceExpired() +{ + expiredFences_++; + pendingFences_--; +} + /** * \enum Request::Status * Request completion status @@ -158,10 +244,11 @@ void Request::reuse(ReuseFlag flags) sequence_ = 0; status_ = RequestPending; - _d()->cancelled_ = false; controls_->clear(); metadata_->clear(); + + _d()->reuse(); } /** From patchwork Thu Oct 28 11:15:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14401 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 3D2FEC324E for ; Thu, 28 Oct 2021 11:14:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 92AF660156; Thu, 28 Oct 2021 13:14:48 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AAFE4600C8 for ; Thu, 28 Oct 2021 13:14:40 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 350B3FF802; Thu, 28 Oct 2021 11:14:40 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:16 +0200 Message-Id: <20211028111520.256612-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/10] libcamera: framebuffer: Add synchronization Fence X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add an optional synchronization file descriptor to the FrameBuffer constuctor. The fence is handled by the FrameBuffer::Private class by constructing a Fence class instance to wrap the file descriptor. Once the Request the FrameBuffer is part of has completed, the fence file descriptor will read as -1 if successfully handled by the library; otherwise the file descriptor value is kept and applications are responsible for closing it. Signed-off-by: Jacopo Mondi --- include/libcamera/framebuffer.h | 5 ++- include/libcamera/internal/framebuffer.h | 7 +++- src/libcamera/framebuffer.cpp | 46 +++++++++++++++++++++--- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h index 7f2f176af691..ac96790b76c0 100644 --- a/include/libcamera/framebuffer.h +++ b/include/libcamera/framebuffer.h @@ -57,7 +57,8 @@ public: unsigned int length; }; - FrameBuffer(const std::vector &planes, unsigned int cookie = 0); + FrameBuffer(const std::vector &planes, unsigned int cookie = 0, + int fence = -1); const std::vector &planes() const { return planes_; } Request *request() const; @@ -66,6 +67,8 @@ public: unsigned int cookie() const { return cookie_; } void setCookie(unsigned int cookie) { cookie_ = cookie; } + int fence() const; + void cancel() { metadata_.status = FrameMetadata::FrameCancelled; } private: diff --git a/include/libcamera/internal/framebuffer.h b/include/libcamera/internal/framebuffer.h index cd33c295466e..db1a4bd72354 100644 --- a/include/libcamera/internal/framebuffer.h +++ b/include/libcamera/internal/framebuffer.h @@ -11,6 +11,8 @@ #include +#include + namespace libcamera { class FrameBuffer::Private : public Extensible::Private @@ -18,14 +20,17 @@ class FrameBuffer::Private : public Extensible::Private LIBCAMERA_DECLARE_PUBLIC(FrameBuffer) public: - Private(); + Private(int fence); void setRequest(Request *request) { request_ = request; } bool isContiguous() const { return isContiguous_; } + const Fence &fence() const { return fence_; } + Fence &fence() { return fence_; } private: Request *request_; bool isContiguous_; + Fence fence_; }; } /* namespace libcamera */ diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp index d44a98babd05..c3e03896b184 100644 --- a/src/libcamera/framebuffer.cpp +++ b/src/libcamera/framebuffer.cpp @@ -111,8 +111,12 @@ LOG_DEFINE_CATEGORY(Buffer) * pipeline handlers. */ -FrameBuffer::Private::Private() - : request_(nullptr), isContiguous_(true) +/** + * \brief Construct a FrameBuffer::Private instance + * \param[in] fence The synchronization fence file descriptor + */ +FrameBuffer::Private::Private(int fence) + : request_(nullptr), isContiguous_(true), fence_(fence) { } @@ -137,6 +141,18 @@ FrameBuffer::Private::Private() * \return True if the planes are stored contiguously in memory, false otherwise */ +/** + * \fn const FrameBuffer::Private::fence() const + * \brief Return a const reference to the Fence + * \return A const reference to the frame buffer fence + */ + +/** + * \fn FrameBuffer::Private::fence() + * \brief Return a reference to the Fence + * \return A reference to the frame buffer fence + */ + /** * \class FrameBuffer * \brief Frame buffer data and its associated dynamic metadata @@ -211,9 +227,11 @@ FrameBuffer::Private::Private() * \brief Construct a FrameBuffer with an array of planes * \param[in] planes The frame memory planes * \param[in] cookie Cookie + * \param[in] fence Synchronization fence */ -FrameBuffer::FrameBuffer(const std::vector &planes, unsigned int cookie) - : Extensible(std::make_unique()), planes_(planes), +FrameBuffer::FrameBuffer(const std::vector &planes, unsigned int cookie, + int fence) + : Extensible(std::make_unique(fence)), planes_(planes), cookie_(cookie) { metadata_.planes_.resize(planes_.size()); @@ -305,6 +323,26 @@ Request *FrameBuffer::request() const * libcamera core never modifies the buffer cookie. */ +/** + * \fn FrameBuffer::fence() + * \brief Return the synchronization fence file descriptor + * + * The fence file descriptor is set by applications at construction time. + * + * Once the Request is queued to the Camera the fence is handled by the + * library and if successfully notified the fence will read as -1 after the + * Request has completed. + * + * If waiting for fence fails, the fence is instead kept in the FrameBuffer + * after the Request has completed and it is responsibility of the + * application to correctly close it. + */ +int FrameBuffer::fence() const +{ + const Fence &fence = _d()->fence(); + return fence.fd(); +} + /** * \fn FrameBuffer::cancel() * \brief Marks the buffer as cancelled From patchwork Thu Oct 28 11:15:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14402 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id DFE89BF415 for ; Thu, 28 Oct 2021 11:14:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 78FF260159; Thu, 28 Oct 2021 13:14:49 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 49F39600BA for ; Thu, 28 Oct 2021 13:14:41 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id D74E7FF804; Thu, 28 Oct 2021 11:14:40 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:17 +0200 Message-Id: <20211028111520.256612-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/10] libcamera: pipeline_handler: Split request queueing X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In order to prepare to handle synchronization fences at Request queueing time, split the PipelineHandler::queueRequest() function in two, by creating a list of waiting requests and introducing a new doQueueDevice() function that queues Requests to the device in the order the pipeline has received them. Signed-off-by: Jacopo Mondi --- include/libcamera/internal/pipeline_handler.h | 7 ++++ src/libcamera/pipeline_handler.cpp | 35 +++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index 41cba44d990f..afb7990ea21b 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -7,7 +7,9 @@ #ifndef __LIBCAMERA_INTERNAL_PIPELINE_HANDLER_H__ #define __LIBCAMERA_INTERNAL_PIPELINE_HANDLER_H__ +#include #include +#include #include #include #include @@ -76,9 +78,14 @@ private: void mediaDeviceDisconnected(MediaDevice *media); virtual void disconnect(); + void doQueueRequest(); + std::vector> mediaDevices_; std::vector> cameras_; + std::mutex waitingRequestsMutex_; + std::list waitingRequests_; + const char *name_; friend class PipelineHandlerFactory; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index cada864687ff..38edd00cebad 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -312,17 +313,45 @@ void PipelineHandler::queueRequest(Request *request) { LIBCAMERA_TRACEPOINT(request_queue, request); + { + MutexLocker lock(waitingRequestsMutex_); + waitingRequests_.push_back(request); + } + + doQueueRequest(); +} + +/** + * \brief Queue a request to the device + */ +void PipelineHandler::doQueueRequest() +{ + Request *request = nullptr; + { + MutexLocker lock(waitingRequestsMutex_); + + if (!waitingRequests_.size()) + return; + + request = waitingRequests_.front(); + waitingRequests_.pop_front(); + } + + /* Queue Request to the pipeline handler. */ Camera *camera = request->_d()->camera(); - Camera::Private *data = camera->_d(); - data->queuedRequests_.push_back(request); + Camera::Private *camData = camera->_d(); - request->sequence_ = data->requestSequence_++; + request->sequence_ = camData->requestSequence_++; + camData->queuedRequests_.push_back(request); int ret = queueRequestDevice(camera, request); if (ret) { request->cancel(); completeRequest(request); } + + /* Try to queue the next Request in the queue, if ready. */ + doQueueRequest(); } /** From patchwork Thu Oct 28 11:15:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14403 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 80029C324E for ; Thu, 28 Oct 2021 11:14:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1895360329; Thu, 28 Oct 2021 13:14:50 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E8123600C2 for ; Thu, 28 Oct 2021 13:14:41 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 7767FFF802; Thu, 28 Oct 2021 11:14:41 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:18 +0200 Message-Id: <20211028111520.256612-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/10] libcamera: pipeline: Introduce stopDevice() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Since a queue of waiting Requests has been introduced, not all Requests queued to the PipelineHandler are immediately queued to the device. As a Camera can be stopped at any time, it is required to complete the waiting requests after the ones queued to the device had been completed. Introduce a pure virtual PipelineHandler::stopDevice() function to be implemented by pipeline handlers and make the PipelineHandler::stop() function call it before completing pending requests. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- include/libcamera/internal/pipeline_handler.h | 3 ++- src/libcamera/pipeline/ipu3/ipu3.cpp | 4 +-- .../pipeline/raspberrypi/raspberrypi.cpp | 4 +-- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 4 +-- src/libcamera/pipeline/simple/simple.cpp | 4 +-- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 4 +-- src/libcamera/pipeline/vimc/vimc.cpp | 4 +-- src/libcamera/pipeline_handler.cpp | 27 +++++++++++++++++-- 8 files changed, 39 insertions(+), 15 deletions(-) diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index afb7990ea21b..5c3c0bc5a8b3 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -56,7 +56,7 @@ public: std::vector> *buffers) = 0; virtual int start(Camera *camera, const ControlList *controls) = 0; - virtual void stop(Camera *camera) = 0; + void stop(Camera *camera); bool hasPendingRequests(const Camera *camera) const; void queueRequest(Request *request); @@ -71,6 +71,7 @@ protected: void hotplugMediaDevice(MediaDevice *media); virtual int queueRequestDevice(Camera *camera, Request *request) = 0; + virtual void stopDevice(Camera *camera) = 0; CameraManager *manager_; diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index eb714aa61099..2b2d7904f275 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -135,7 +135,7 @@ public: std::vector> *buffers) override; int start(Camera *camera, const ControlList *controls) override; - void stop(Camera *camera) override; + void stopDevice(Camera *camera) override; int queueRequestDevice(Camera *camera, Request *request) override; @@ -791,7 +791,7 @@ error: return ret; } -void PipelineHandlerIPU3::stop(Camera *camera) +void PipelineHandlerIPU3::stopDevice(Camera *camera) { IPU3CameraData *data = cameraData(camera); int ret = 0; diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 1634ca98f481..b5b7a240d5ed 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -255,7 +255,7 @@ public: std::vector> *buffers) override; int start(Camera *camera, const ControlList *controls) override; - void stop(Camera *camera) override; + void stopDevice(Camera *camera) override; int queueRequestDevice(Camera *camera, Request *request) override; @@ -878,7 +878,7 @@ int PipelineHandlerRPi::start(Camera *camera, const ControlList *controls) return 0; } -void PipelineHandlerRPi::stop(Camera *camera) +void PipelineHandlerRPi::stopDevice(Camera *camera) { RPiCameraData *data = cameraData(camera); diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 980088628523..9860fa84a5ae 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -146,7 +146,7 @@ public: std::vector> *buffers) override; int start(Camera *camera, const ControlList *controls) override; - void stop(Camera *camera) override; + void stopDevice(Camera *camera) override; int queueRequestDevice(Camera *camera, Request *request) override; @@ -827,7 +827,7 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL return ret; } -void PipelineHandlerRkISP1::stop(Camera *camera) +void PipelineHandlerRkISP1::stopDevice(Camera *camera) { RkISP1CameraData *data = cameraData(camera); int ret; diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 701fb4be0b71..fdff4ebd5134 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -279,7 +279,7 @@ public: std::vector> *buffers) override; int start(Camera *camera, const ControlList *controls) override; - void stop(Camera *camera) override; + void stopDevice(Camera *camera) override; bool match(DeviceEnumerator *enumerator) override; @@ -1036,7 +1036,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL return 0; } -void SimplePipelineHandler::stop(Camera *camera) +void SimplePipelineHandler::stopDevice(Camera *camera) { SimpleCameraData *data = cameraData(camera); V4L2VideoDevice *video = data->video_; diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 264f5370cf32..40654a0bc40c 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -74,7 +74,7 @@ public: std::vector> *buffers) override; int start(Camera *camera, const ControlList *controls) override; - void stop(Camera *camera) override; + void stopDevice(Camera *camera) override; int queueRequestDevice(Camera *camera, Request *request) override; @@ -250,7 +250,7 @@ int PipelineHandlerUVC::start(Camera *camera, [[maybe_unused]] const ControlList return 0; } -void PipelineHandlerUVC::stop(Camera *camera) +void PipelineHandlerUVC::stopDevice(Camera *camera) { UVCCameraData *data = cameraData(camera); data->video_->streamOff(); diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index e453091da4b2..29960fe3f038 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -91,7 +91,7 @@ public: std::vector> *buffers) override; int start(Camera *camera, const ControlList *controls) override; - void stop(Camera *camera) override; + void stopDevice(Camera *camera) override; int queueRequestDevice(Camera *camera, Request *request) override; @@ -359,7 +359,7 @@ int PipelineHandlerVimc::start(Camera *camera, [[maybe_unused]] const ControlLis return 0; } -void PipelineHandlerVimc::stop(Camera *camera) +void PipelineHandlerVimc::stopDevice(Camera *camera) { VimcCameraData *data = cameraData(camera); data->video_->streamOff(); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 38edd00cebad..0f9fec1b618f 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -268,8 +268,7 @@ void PipelineHandler::unlock() */ /** - * \fn PipelineHandler::stop() - * \brief Stop capturing from all running streams + * \brief Stop capturing from all running streams and cancel pending requests * \param[in] camera The camera to stop * * This function stops capturing and processing requests immediately. All @@ -277,6 +276,30 @@ void PipelineHandler::unlock() * * \context This function is called from the CameraManager thread. */ +void PipelineHandler::stop(Camera *camera) +{ + /* Stop the pipeline handler and let the queued requests complete. */ + stopDevice(camera); + + /* Cancel and signal as complete all requests waiting for fences. */ + MutexLocker lock(waitingRequestsMutex_); + + for (auto &waitingRequest : waitingRequests_) { + waitingRequest->cancel(); + completeRequest(waitingRequest); + } + + waitingRequests_.clear(); +} + +/** + * \fn PipelineHandler::stopDevice() + * \brief Stop capturing from all running streams + * \param[in] camera The camera to stop + * + * This function stops capturing and processing requests immediately. All + * pending requests are cancelled and complete immediately in an error state. + */ /** * \brief Determine if the camera has any requests pending From patchwork Thu Oct 28 11:15:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14404 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 1B78AC324F for ; Thu, 28 Oct 2021 11:14:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B9AB660128; Thu, 28 Oct 2021 13:14:50 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 964DA60325 for ; Thu, 28 Oct 2021 13:14:42 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 21D27FF802; Thu, 28 Oct 2021 11:14:41 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:19 +0200 Message-Id: <20211028111520.256612-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/10] libcamera: pipeline_handler: Handle fences X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Before queueing a request to the device, any synchronization fence from the Request framebuffers has to be waited on. Start by moving the fences to the Request, in order to reset the ones in the FrameBuffers and then enable all of them one by one. When a fence completes, make sure all fences in the Request have been waited on or have expired and only after that actually queue the Request to the device. If any fence in the Request has expired cancel the request and do not queue it to the device. Signed-off-by: Jacopo Mondi --- include/libcamera/internal/pipeline_handler.h | 2 + src/libcamera/pipeline_handler.cpp | 78 ++++++++++++++++++- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index 5c3c0bc5a8b3..5b98011ac4f6 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -29,6 +29,7 @@ class CameraConfiguration; class CameraManager; class DeviceEnumerator; class DeviceMatch; +class Fence; class FrameBuffer; class MediaDevice; class PipelineHandler; @@ -79,6 +80,7 @@ private: void mediaDeviceDisconnected(MediaDevice *media); virtual void disconnect(); + void fenceCompleted(Request *request, FrameBuffer *buffer, Fence *fence); void doQueueRequest(); std::vector> mediaDevices_; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 0f9fec1b618f..39cb680e5386 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -18,6 +18,7 @@ #include #include "libcamera/internal/camera.h" +#include "libcamera/internal/framebuffer.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/request.h" @@ -336,11 +337,70 @@ void PipelineHandler::queueRequest(Request *request) { LIBCAMERA_TRACEPOINT(request_queue, request); + Request::Private *data = request->_d(); + { MutexLocker lock(waitingRequestsMutex_); waitingRequests_.push_back(request); } + for (FrameBuffer *buffer : request->pending_) { + if (buffer->fence() == -1) + continue; + + /* + * Move the Fence into the Request::Private list of + * fences. This resets the file descriptor fence in the + * FrameBuffer to -1. + */ + data->addFence(std::move(buffer->_d()->fence())); + + Fence *fence = &data->fences().back(); + fence->complete.connect(this, + [this, request, buffer, fence]() { + fenceCompleted(request, buffer, fence); + }); + } + + /* If no fences to wait on, we can queue the request immediately. */ + if (!data->pendingFences()) { + doQueueRequest(); + + return; + } + + /* + * Now that we have added all fences, enable them one by one. + * Enabling fences while adding them to the Request would race on the + * number of pending fences. + */ + for (Fence &fence : data->fences()) + fence.enable(); +} + +void PipelineHandler::fenceCompleted(Request *request, FrameBuffer *buffer, + Fence *fence) +{ + Request::Private *data = request->_d(); + + if (fence->expired()) { + /* + * Move the fence back to the framebuffer, so that it doesn't + * get closed and the file descriptor number is made + * available again to applications. + */ + FrameBuffer::Private *bufferData = buffer->_d(); + bufferData->fence() = std::move(*fence); + + data->fenceExpired(); + } else { + data->fenceCompleted(); + } + + if (data->pendingFences()) + return; + + data->clearFences(); doQueueRequest(); } @@ -357,23 +417,35 @@ void PipelineHandler::doQueueRequest() return; request = waitingRequests_.front(); + if (request->_d()->pendingFences()) + return; + waitingRequests_.pop_front(); } - /* Queue Request to the pipeline handler. */ Camera *camera = request->_d()->camera(); Camera::Private *camData = camera->_d(); request->sequence_ = camData->requestSequence_++; - camData->queuedRequests_.push_back(request); + /* Cancel the request if one of the fences has failed. */ + if (request->_d()->expiredFences()) { + request->cancel(); + completeRequest(request); + + doQueueRequest(); + + return; + } + + /* Queue Request to the pipeline handler. */ + camData->queuedRequests_.push_back(request); int ret = queueRequestDevice(camera, request); if (ret) { request->cancel(); completeRequest(request); } - /* Try to queue the next Request in the queue, if ready. */ doQueueRequest(); } From patchwork Thu Oct 28 11:15:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14405 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 99EE3BF415 for ; Thu, 28 Oct 2021 11:14:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 495E660157; Thu, 28 Oct 2021 13:14:51 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 44749600C0 for ; Thu, 28 Oct 2021 13:14:43 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id BD5A5FF802; Thu, 28 Oct 2021 11:14:42 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:20 +0200 Message-Id: <20211028111520.256612-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/10] android: Remove CameraWorker X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The CameraWorker class purpose was to handle acquire fences for incoming capture requests directed to libcamera. Now that fences are handled by the core library, it is not required to handle them in the HAL and the CameraWorker and CaptureRequest classes can be dropped. Update the core in CameraDevice class accordingly to queue Requests directly to the libcamera::Camera and set the release_fence to the value of the FrameBuffer::fence() for streams of type ::Direct. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- src/android/camera_device.cpp | 39 ++++------ src/android/camera_device.h | 5 +- src/android/camera_request.cpp | 3 +- src/android/camera_request.h | 3 +- src/android/camera_worker.cpp | 129 --------------------------------- src/android/camera_worker.h | 72 ------------------ src/android/meson.build | 1 - 7 files changed, 19 insertions(+), 233 deletions(-) delete mode 100644 src/android/camera_worker.cpp delete mode 100644 src/android/camera_worker.h diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index f2e0bdbdbbf6..16237674ea24 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -406,7 +406,6 @@ void CameraDevice::flush() state_ = State::Flushing; } - worker_.stop(); camera_->stop(); MutexLocker stateLock(stateMutex_); @@ -419,7 +418,6 @@ void CameraDevice::stop() if (state_ == State::Stopped) return; - worker_.stop(); camera_->stop(); descriptors_ = {}; @@ -714,9 +712,10 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list) } std::unique_ptr -CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer, +CameraDevice::createFrameBuffer(const Camera3RequestDescriptor::StreamBuffer &streamBuffer, PixelFormat pixelFormat, const Size &size) { + const buffer_handle_t camera3buffer = *streamBuffer.camera3Buffer; CameraBuffer buf(camera3buffer, pixelFormat, size, PROT_READ); if (!buf.isValid()) { LOG(HAL, Fatal) << "Failed to create CameraBuffer"; @@ -736,7 +735,8 @@ CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer, planes[i].length = buf.size(i); } - return std::make_unique(planes); + return std::make_unique(planes, 0, + streamBuffer.fence); } int CameraDevice::processControls(Camera3RequestDescriptor *descriptor) @@ -912,13 +912,9 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques /* * Inspect the camera stream type, create buffers opportunely - * and add them to the Request if required. Only acquire fences - * for streams of type Direct are handled by the CameraWorker, - * while fences for streams of type Internal and Mapped are - * handled at post-processing time. + * and add them to the Request if required. */ FrameBuffer *frameBuffer = nullptr; - int acquireFence = -1; switch (cameraStream->type()) { case CameraStream::Type::Mapped: /* @@ -939,11 +935,10 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques * lifetime management only. */ buffer.frameBuffer = - createFrameBuffer(*buffer.camera3Buffer, + createFrameBuffer(buffer, cameraStream->configuration().pixelFormat, cameraStream->configuration().size); frameBuffer = buffer.frameBuffer.get(); - acquireFence = buffer.fence; LOG(HAL, Debug) << ss.str() << " (direct)"; break; @@ -970,12 +965,12 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques } descriptor->request_->addBuffer(cameraStream->stream(), - frameBuffer, acquireFence); + frameBuffer); } /* * Translate controls from Android to libcamera and queue the request - * to the CameraWorker thread. + * to the camera. */ int ret = processControls(descriptor.get()); if (ret) @@ -1001,26 +996,23 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques } if (state_ == State::Stopped) { - worker_.start(); - ret = camera_->start(); if (ret) { LOG(HAL, Error) << "Failed to start camera"; - worker_.stop(); return ret; } state_ = State::Running; } - CaptureRequest *request = descriptor->request_.get(); + Request *request = descriptor->request_.get(); { MutexLocker descriptorsLock(descriptorsMutex_); descriptors_.push(std::move(descriptor)); } - worker_.queueRequest(request); + camera_->queueRequest(request); return 0; } @@ -1042,16 +1034,17 @@ void CameraDevice::requestComplete(Request *request) /* * Streams of type Direct have been queued to the * libcamera::Camera and their acquire fences have - * already been waited on by the CameraWorker. + * been handled by the library. + * + * If the fence has been signalled correctly it will be -1 and + * closed, otherwise it is set to the 'acquire_fence' value and + * the framework will have to close it. * * Acquire fences of streams of type Internal and Mapped * will be handled during post-processing. - * - * \todo Instrument the CameraWorker to set the acquire - * fence to -1 once it has handled it and remove this check. */ if (stream->type() == CameraStream::Type::Direct) - buffer.fence = -1; + buffer.fence = buffer.frameBuffer->fence(); buffer.status = Camera3RequestDescriptor::Status::Success; } diff --git a/src/android/camera_device.h b/src/android/camera_device.h index 2a414020f1ad..d83f77a8cf22 100644 --- a/src/android/camera_device.h +++ b/src/android/camera_device.h @@ -30,7 +30,6 @@ #include "camera_capabilities.h" #include "camera_metadata.h" #include "camera_stream.h" -#include "camera_worker.h" #include "jpeg/encoder.h" class Camera3RequestDescriptor; @@ -86,7 +85,7 @@ private: void stop(); std::unique_ptr - createFrameBuffer(const buffer_handle_t camera3buffer, + createFrameBuffer(const Camera3RequestDescriptor::StreamBuffer &streamBuffer, libcamera::PixelFormat pixelFormat, const libcamera::Size &size); void abortRequest(Camera3RequestDescriptor *descriptor) const; @@ -105,8 +104,6 @@ private: unsigned int id_; camera3_device_t camera3Device_; - CameraWorker worker_; - libcamera::Mutex stateMutex_; /* Protects access to the camera state. */ State state_; diff --git a/src/android/camera_request.cpp b/src/android/camera_request.cpp index 5bac1b8f7a5f..f656c3ebe448 100644 --- a/src/android/camera_request.cpp +++ b/src/android/camera_request.cpp @@ -49,8 +49,7 @@ Camera3RequestDescriptor::Camera3RequestDescriptor( * Create the CaptureRequest, stored as a unique_ptr<> to tie its * lifetime to the descriptor. */ - request_ = std::make_unique(camera, - reinterpret_cast(this)); + request_ = camera->createRequest(reinterpret_cast(this)); } Camera3RequestDescriptor::~Camera3RequestDescriptor() = default; diff --git a/src/android/camera_request.h b/src/android/camera_request.h index cfafa4450d71..e019c38784ba 100644 --- a/src/android/camera_request.h +++ b/src/android/camera_request.h @@ -20,7 +20,6 @@ #include #include "camera_metadata.h" -#include "camera_worker.h" class CameraBuffer; class CameraStream; @@ -60,7 +59,7 @@ public: std::vector buffers_; CameraMetadata settings_; - std::unique_ptr request_; + std::unique_ptr request_; std::unique_ptr resultMetadata_; bool complete_ = false; diff --git a/src/android/camera_worker.cpp b/src/android/camera_worker.cpp deleted file mode 100644 index dabb305407a2..000000000000 --- a/src/android/camera_worker.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2020, Google Inc. - * - * camera_worker.cpp - Process capture requests on behalf of the Camera HAL - */ - -#include "camera_worker.h" - -#include -#include -#include -#include - -#include "camera_device.h" - -using namespace libcamera; - -LOG_DECLARE_CATEGORY(HAL) - -/* - * \class CaptureRequest - * \brief Wrap a libcamera::Request associated with buffers and fences - * - * A CaptureRequest is constructed by the CameraDevice, filled with - * buffers and fences provided by the camera3 framework and then processed - * by the CameraWorker which queues it to the libcamera::Camera after handling - * fences. - */ -CaptureRequest::CaptureRequest(Camera *camera, uint64_t cookie) - : camera_(camera) -{ - request_ = camera_->createRequest(cookie); -} - -void CaptureRequest::addBuffer(Stream *stream, FrameBuffer *buffer, int fence) -{ - request_->addBuffer(stream, buffer); - acquireFences_.push_back(fence); -} - -void CaptureRequest::queue() -{ - camera_->queueRequest(request_.get()); -} - -/* - * \class CameraWorker - * \brief Process a CaptureRequest on an internal thread - * - * The CameraWorker class wraps a Worker that runs on an internal thread - * and schedules processing of CaptureRequest through it. - */ -CameraWorker::CameraWorker() -{ - worker_.moveToThread(this); -} - -void CameraWorker::start() -{ - Thread::start(); -} - -void CameraWorker::stop() -{ - exit(); - wait(); -} - -void CameraWorker::run() -{ - exec(); - dispatchMessages(Message::Type::InvokeMessage); -} - -void CameraWorker::queueRequest(CaptureRequest *request) -{ - /* Async process the request on the worker which runs its own thread. */ - worker_.invokeMethod(&Worker::processRequest, ConnectionTypeQueued, - request); -} - -/* - * \class CameraWorker::Worker - * \brief Process a CaptureRequest handling acquisition fences - */ -int CameraWorker::Worker::waitFence(int fence) -{ - /* - * \todo Better characterize the timeout. Currently equal to the one - * used by the Rockchip Camera HAL on ChromeOS. - */ - constexpr unsigned int timeoutMs = 300; - struct pollfd fds = { fence, POLLIN, 0 }; - - do { - int ret = poll(&fds, 1, timeoutMs); - if (ret == 0) - return -ETIME; - - if (ret > 0) { - if (fds.revents & (POLLERR | POLLNVAL)) - return -EINVAL; - - return 0; - } - } while (errno == EINTR || errno == EAGAIN); - - return -errno; -} - -void CameraWorker::Worker::processRequest(CaptureRequest *request) -{ - /* Wait on all fences before queuing the Request. */ - for (int fence : request->fences()) { - if (fence == -1) - continue; - - int ret = waitFence(fence); - close(fence); - if (ret < 0) { - LOG(HAL, Error) << "Failed waiting for fence: " - << fence << ": " << strerror(-ret); - return; - } - } - - request->queue(); -} diff --git a/src/android/camera_worker.h b/src/android/camera_worker.h deleted file mode 100644 index c94f16325925..000000000000 --- a/src/android/camera_worker.h +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2020, Google Inc. - * - * camera_worker.h - Process capture requests on behalf of the Camera HAL - */ -#ifndef __ANDROID_CAMERA_WORKER_H__ -#define __ANDROID_CAMERA_WORKER_H__ - -#include -#include - -#include -#include - -#include -#include -#include -#include - -class CameraDevice; - -class CaptureRequest -{ -public: - CaptureRequest(libcamera::Camera *camera, uint64_t cookie); - - const std::vector &fences() const { return acquireFences_; } - libcamera::ControlList &controls() { return request_->controls(); } - const libcamera::ControlList &metadata() const - { - return request_->metadata(); - } - unsigned long cookie() const { return request_->cookie(); } - - void addBuffer(libcamera::Stream *stream, - libcamera::FrameBuffer *buffer, int fence); - void queue(); - -private: - libcamera::Camera *camera_; - std::vector acquireFences_; - std::unique_ptr request_; -}; - -class CameraWorker : private libcamera::Thread -{ -public: - CameraWorker(); - - void start(); - void stop(); - - void queueRequest(CaptureRequest *request); - -protected: - void run() override; - -private: - class Worker : public libcamera::Object - { - public: - void processRequest(CaptureRequest *request); - - private: - int waitFence(int fence); - }; - - Worker worker_; -}; - -#endif /* __ANDROID_CAMERA_WORKER_H__ */ diff --git a/src/android/meson.build b/src/android/meson.build index 332b177ca805..75b4bf207085 100644 --- a/src/android/meson.build +++ b/src/android/meson.build @@ -47,7 +47,6 @@ android_hal_sources = files([ 'camera_ops.cpp', 'camera_request.cpp', 'camera_stream.cpp', - 'camera_worker.cpp', 'jpeg/encoder_libjpeg.cpp', 'jpeg/exif.cpp', 'jpeg/post_processor_jpeg.cpp',