From patchwork Sat Nov 20 11:13:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14669 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 9C32FC324F for ; Sat, 20 Nov 2021 11:12:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0AC966038B; Sat, 20 Nov 2021 12:12:24 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3DAE86033C for ; Sat, 20 Nov 2021 12:12:23 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 851C5100004; Sat, 20 Nov 2021 11:12:22 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:02 +0100 Message-Id: <20211120111313.106621-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 01/12] 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" From: Laurent Pinchart Implement the D-Pointer design pattern in the Request class to allow changing internal data without affecting the public ABI. Move the internal fields that are not needed to implement the public API to the Request::Private class already. This allow to remove the friend class declaration for the PipelineHandler class, which can now use the Request::Private API. Signed-off-by: Laurent Pinchart [Move all internal fields to Request::Private and remove friend declaration] Signed-off-by: Jacopo Mondi --- include/libcamera/internal/meson.build | 1 + include/libcamera/internal/request.h | 51 ++++ .../libcamera/internal/tracepoints/request.tp | 9 +- include/libcamera/request.h | 19 +- src/libcamera/pipeline_handler.cpp | 15 +- src/libcamera/request.cpp | 256 ++++++++++++------ 6 files changed, 245 insertions(+), 106 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..59bddde3a090 --- /dev/null +++ b/include/libcamera/internal/request.h @@ -0,0 +1,51 @@ +/* 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 + +#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_; } + bool hasPendingBuffers() const; + + uint64_t cookie() const; + Request::Status status() const; + + bool completeBuffer(FrameBuffer *buffer); + void complete(); + void cancel(); + void reuse(); + + uint32_t sequence_ = 0; + +private: + void _cancel(); + + Camera *camera_; + bool cancelled_; + + std::unordered_set pending_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_INTERNAL_REQUEST_H__ */ diff --git a/include/libcamera/internal/tracepoints/request.tp b/include/libcamera/internal/tracepoints/request.tp index 37d8c46f4d96..37cd2f8864ce 100644 --- a/include/libcamera/internal/tracepoints/request.tp +++ b/include/libcamera/internal/tracepoints/request.tp @@ -5,8 +5,9 @@ * request.tp - Tracepoints for the request object */ +#include + #include -#include TRACEPOINT_EVENT_CLASS( libcamera, @@ -62,7 +63,7 @@ TRACEPOINT_EVENT_INSTANCE( request, request_complete, TP_ARGS( - libcamera::Request *, req + libcamera::Request::Private *, req ) ) @@ -71,7 +72,7 @@ TRACEPOINT_EVENT_INSTANCE( request, request_cancel, TP_ARGS( - libcamera::Request *, req + libcamera::Request::Private *, req ) ) @@ -79,7 +80,7 @@ TRACEPOINT_EVENT( libcamera, request_complete_buffer, TP_ARGS( - libcamera::Request *, req, + libcamera::Request::Private *, req, libcamera::FrameBuffer *, buf ), TP_FIELDS( diff --git a/include/libcamera/request.h b/include/libcamera/request.h index d16904e6b679..f0c5163d987e 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, @@ -52,34 +54,23 @@ public: int addBuffer(const Stream *stream, FrameBuffer *buffer); FrameBuffer *findBuffer(const Stream *stream) const; - uint32_t sequence() const { return sequence_; } + uint32_t sequence() const; uint64_t cookie() const { return cookie_; } Status status() const { return status_; } - bool hasPendingBuffers() const { return !pending_.empty(); } + bool hasPendingBuffers() const; std::string toString() const; private: LIBCAMERA_DISABLE_COPY(Request) - friend class PipelineHandler; - - void complete(); - void cancel(); - - bool completeBuffer(FrameBuffer *buffer); - - Camera *camera_; ControlList *controls_; ControlList *metadata_; BufferMap bufferMap_; - std::unordered_set pending_; - 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..67fdf1d8db01 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,15 +312,15 @@ 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); - request->sequence_ = data->requestSequence_++; + request->_d()->sequence_ = data->requestSequence_++; int ret = queueRequestDevice(camera, request); if (ret) { - request->cancel(); + request->_d()->cancel(); completeRequest(request); } } @@ -360,9 +361,9 @@ 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); + return request->_d()->completeBuffer(buffer); } /** @@ -381,9 +382,9 @@ bool PipelineHandler::completeBuffer(Request *request, FrameBuffer *buffer) */ void PipelineHandler::completeRequest(Request *request) { - Camera *camera = request->camera_; + Camera *camera = request->_d()->camera(); - request->complete(); + request->_d()->complete(); Camera::Private *data = camera->_d(); diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 17fefab7ad0e..90c436648405 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -5,7 +5,7 @@ * request.cpp - Capture request handling */ -#include +#include "libcamera/internal/request.h" #include #include @@ -23,7 +23,7 @@ #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 +31,165 @@ 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() +{ + _cancel(); +} + +/** + * \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 + */ + +/** + * \brief Check if a request has buffers yet to be completed + * + * \return True if the request has buffers pending for completion, false + * otherwise + */ +bool Request::Private::hasPendingBuffers() const +{ + return !pending_.empty(); +} + +/** + * \copydoc Request::cookie() + * + * Used by the tracing framework + */ +uint64_t Request::Private::cookie() const +{ + return _o()->cookie(); +} + +/** + * \copydoc Request::status() + * + * Used by the tracing framework + */ +Request::Status Request::Private::status() const +{ + return _o()->status(); +} + +/** + * \brief Complete a buffer for the request + * \param[in] buffer The buffer that has completed + * + * A request tracks the status of all buffers it contains through a set of + * pending buffers. This function removes the \a buffer from the set to mark it + * as complete. All buffers associate with the request shall be marked as + * complete by calling this function once and once only before reporting the + * request as complete with the complete() function. + * + * \return True if all buffers contained in the request have completed, false + * otherwise + */ +bool Request::Private::completeBuffer(FrameBuffer *buffer) +{ + LIBCAMERA_TRACEPOINT(request_complete_buffer, this, buffer); + + int ret = pending_.erase(buffer); + ASSERT(ret == 1); + + buffer->_d()->setRequest(nullptr); + + if (buffer->metadata().status == FrameMetadata::FrameCancelled) + cancelled_ = true; + + return !hasPendingBuffers(); +} + +/** + * \brief Complete a queued request + * + * Mark the request as complete by updating its status to RequestComplete, + * unless buffers have been cancelled in which case the status is set to + * RequestCancelled. + */ +void Request::Private::complete() +{ + Request *request = _o(); + + ASSERT(request->status() == RequestPending); + ASSERT(!hasPendingBuffers()); + + request->status_ = cancelled_ ? RequestCancelled : RequestComplete; + + LOG(Request, Debug) << request->toString(); + + LIBCAMERA_TRACEPOINT(request_complete, this); +} + +void Request::Private::_cancel() +{ + Request *request = _o(); + + for (FrameBuffer *buffer : pending_) { + buffer->cancel(); + camera_->bufferCompleted.emit(request, buffer); + } + + cancelled_ = true; + pending_.clear(); +} + +/** + * \brief Cancel a queued request + * + * Mark the request and its associated buffers as cancelled and complete it. + * + * Set each pending buffer in error state and emit the buffer completion signal + * before completing the Request. + */ +void Request::Private::cancel() +{ + LIBCAMERA_TRACEPOINT(request_cancel, this); + + Request *request = _o(); + ASSERT(request->status() == RequestPending); + + _cancel(); +} + +/** + * \copydoc Request::reuse() + */ +void Request::Private::reuse() +{ + sequence_ = 0; + cancelled_ = false; + pending_.clear(); +} +/** + * \var Request::Private::sequence_ + * \brief The request sequence number + * + * \copydoc Request::sequence() + */ + /** * \enum Request::Status * Request completion status @@ -75,8 +234,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)), + cookie_(cookie), status_(RequestPending) { controls_ = new ControlList(controls::controls, camera->_d()->validator()); @@ -113,20 +272,19 @@ void Request::reuse(ReuseFlag flags) { LIBCAMERA_TRACEPOINT(request_reuse, this); - pending_.clear(); + _d()->reuse(); + if (flags & ReuseBuffers) { for (auto pair : bufferMap_) { FrameBuffer *buffer = pair.second; buffer->_d()->setRequest(this); - pending_.insert(buffer); + _d()->pending_.insert(buffer); } } else { bufferMap_.clear(); } - sequence_ = 0; status_ = RequestPending; - cancelled_ = false; controls_->clear(); metadata_->clear(); @@ -188,7 +346,7 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer) } buffer->_d()->setRequest(this); - pending_.insert(buffer); + _d()->pending_.insert(buffer); bufferMap_[stream] = buffer; return 0; @@ -227,7 +385,6 @@ FrameBuffer *Request::findBuffer(const Stream *stream) const */ /** - * \fn Request::sequence() * \brief Retrieve the sequence number for the request * * When requests are queued, they are given a sequential number to track the @@ -242,6 +399,10 @@ FrameBuffer *Request::findBuffer(const Stream *stream) const * * \return The request sequence number */ +uint32_t Request::sequence() const +{ + return _d()->sequence_; +} /** * \fn Request::cookie() @@ -263,81 +424,14 @@ FrameBuffer *Request::findBuffer(const Stream *stream) const */ /** - * \fn Request::hasPendingBuffers() * \brief Check if a request has buffers yet to be completed * * \return True if the request has buffers pending for completion, false * otherwise */ - -/** - * \brief Complete a queued request - * - * Mark the request as complete by updating its status to RequestComplete, - * unless buffers have been cancelled in which case the status is set to - * RequestCancelled. - */ -void Request::complete() -{ - ASSERT(status_ == RequestPending); - ASSERT(!hasPendingBuffers()); - - status_ = cancelled_ ? RequestCancelled : RequestComplete; - - LOG(Request, Debug) << toString(); - - LIBCAMERA_TRACEPOINT(request_complete, this); -} - -/** - * \brief Cancel a queued request - * - * Mark the request and its associated buffers as cancelled and complete it. - * - * Set each pending buffer in error state and emit the buffer completion signal - * before completing the Request. - */ -void Request::cancel() -{ - LIBCAMERA_TRACEPOINT(request_cancel, this); - - ASSERT(status_ == RequestPending); - - for (FrameBuffer *buffer : pending_) { - buffer->cancel(); - camera_->bufferCompleted.emit(this, buffer); - } - - pending_.clear(); - cancelled_ = true; -} - -/** - * \brief Complete a buffer for the request - * \param[in] buffer The buffer that has completed - * - * A request tracks the status of all buffers it contains through a set of - * pending buffers. This function removes the \a buffer from the set to mark it - * as complete. All buffers associate with the request shall be marked as - * complete by calling this function once and once only before reporting the - * request as complete with the complete() function. - * - * \return True if all buffers contained in the request have completed, false - * otherwise - */ -bool Request::completeBuffer(FrameBuffer *buffer) +bool Request::hasPendingBuffers() const { - LIBCAMERA_TRACEPOINT(request_complete_buffer, this, buffer); - - int ret = pending_.erase(buffer); - ASSERT(ret == 1); - - buffer->_d()->setRequest(nullptr); - - if (buffer->metadata().status == FrameMetadata::FrameCancelled) - cancelled_ = true; - - return !hasPendingBuffers(); + return !_d()->pending_.empty(); } /** @@ -356,8 +450,8 @@ std::string Request::toString() const static const char *statuses = "PCX"; /* Example Output: Request(55:P:1/2:6523524) */ - ss << "Request(" << sequence_ << ":" << statuses[status_] << ":" - << pending_.size() << "/" << bufferMap_.size() << ":" + ss << "Request(" << sequence() << ":" << statuses[status_] << ":" + << _d()->pending_.size() << "/" << bufferMap_.size() << ":" << cookie_ << ")"; return ss.str(); From patchwork Sat Nov 20 11:13:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14670 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 9F43EBDB13 for ; Sat, 20 Nov 2021 11:12:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3D412603BE; Sat, 20 Nov 2021 12:12:26 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E8B0C6037A for ; Sat, 20 Nov 2021 12:12:23 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 68847100002; Sat, 20 Nov 2021 11:12:23 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:03 +0100 Message-Id: <20211120111313.106621-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 02/12] libcamera: fence: Introduce 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" Introduce a Fence class which models a synchronization primitive that allows to notify the availability of a resource. The Fence is modeled as a wrapper of a FileDescriptor instance where read events are used to signal the Fence. The class can be later extended to support additional signalling mechanisms. Signed-off-by: Jacopo Mondi --- include/libcamera/fence.h | 36 +++++++++ include/libcamera/internal/fence.h | 37 +++++++++ include/libcamera/internal/meson.build | 1 + include/libcamera/meson.build | 1 + src/libcamera/fence.cpp | 104 +++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 6 files changed, 180 insertions(+) create mode 100644 include/libcamera/fence.h create mode 100644 include/libcamera/internal/fence.h create mode 100644 src/libcamera/fence.cpp diff --git a/include/libcamera/fence.h b/include/libcamera/fence.h new file mode 100644 index 000000000000..5ae0ff6208d7 --- /dev/null +++ b/include/libcamera/fence.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * internal/fence.h - Synchronization fence + */ +#ifndef __LIBCAMERA_FENCE_H__ +#define __LIBCAMERA_FENCE_H__ + +#include + +#include + +#include + +namespace libcamera { + +class Fence : public Extensible +{ + LIBCAMERA_DECLARE_PRIVATE() + +public: + Fence(const FileDescriptor &fd); + + bool isValid() const; + const FileDescriptor &fd(); + + void close(); + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(Fence) +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_FENCE_H__ */ diff --git a/include/libcamera/internal/fence.h b/include/libcamera/internal/fence.h new file mode 100644 index 000000000000..5f03c0804d44 --- /dev/null +++ b/include/libcamera/internal/fence.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * internal/fence.h - Internal synchronization fence + */ +#ifndef __LIBCAMERA_INTERNAL_FENCE_H__ +#define __LIBCAMERA_INTERNAL_FENCE_H__ + +#include + +#include +#include + +#include +#include + +namespace libcamera { + +class Fence::Private : public Extensible::Private +{ + LIBCAMERA_DECLARE_PUBLIC(Fence) + +public: + Private(const FileDescriptor &fd); + + bool isValid() const { return fd_.isValid(); } + const FileDescriptor &fd() { return fd_; } + void close(); + +private: + FileDescriptor fd_; +}; + +} /* 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/include/libcamera/meson.build b/include/libcamera/meson.build index 7155ff203f6e..3721feb1ec92 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -7,6 +7,7 @@ libcamera_public_headers = files([ 'camera_manager.h', 'compiler.h', 'controls.h', + 'fence.h', 'file_descriptor.h', 'framebuffer.h', 'framebuffer_allocator.h', diff --git a/src/libcamera/fence.cpp b/src/libcamera/fence.cpp new file mode 100644 index 000000000000..9ad86b3fa115 --- /dev/null +++ b/src/libcamera/fence.cpp @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * fence.cpp - Synchronization fence + */ + +#include "libcamera/internal/fence.h" + +#include +#include + +namespace libcamera { + +/** + * + * \file libcamera/fence.h + * \brief Synchronization fence + * + * \file internal/fence.h + * \brief Internal synchronization fence representation + */ + +/** + * \class Fence::Private + * \brief Private synchronization Fence implementation + */ + +/** + * \brief Construct a Fence::Private + * \param[in] fd The filedescriptor owned by the Fence + */ +Fence::Private::Private(const FileDescriptor &fd) + : fd_(std::move(fd)) +{ +} + +/** + * \fn Fence::Private::isValid() + * \brief Retrieve if a Fence is valid + * + * A Fence is valid if the FileDescriptor it wraps is valid + * + * \return True if the Fence is valid, false otherwise + */ + +/** + * \fn Fence::Private::fd() + * \brief Retrieve a refernce to the FileDescriptor wrapped by this Fence + * + * \todo Document how to extract the FileDescriptor in case the Fence has failed + * + * \return A reference to the FileDescriptor this Fence wraps + */ + +/** + * \brief Close the Fence by releasing the wrapped FileDescriptor + */ +void Fence::Private::close() +{ + fd_ = FileDescriptor(); +} + +/** + * \class Fence + * \brief Synchronization fence class + * + * \todo Documentation + */ + +/** + * \brief Create a synchronization fence + * \param[in] fd The synchronization fence file descriptor + */ +Fence::Fence(const FileDescriptor &fd) + : Extensible(std::make_unique(fd)) +{ +} + +/** + * \copydoc Fence::Private::isValid() + */ +bool Fence::isValid() const +{ + return _d()->isValid(); +} + +/** + * \copydoc Fence::Private::fd() + */ +const FileDescriptor &Fence::fd() +{ + return _d()->fd(); +} + +/** + * \copydoc Fence::Private::close() + */ +void Fence::close() +{ + _d()->close(); +} + +} /* 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 Sat Nov 20 11:13:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14671 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 CB839BDB13 for ; Sat, 20 Nov 2021 11:12:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 96DED60442; Sat, 20 Nov 2021 12:12:28 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6F5C960378 for ; Sat, 20 Nov 2021 12:12:24 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 05BC2100002; Sat, 20 Nov 2021 11:12:23 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:04 +0100 Message-Id: <20211120111313.106621-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 03/12] libcamera: framebuffer: private: Add 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 to the FrameBuffer::Private class a uniquely owned Fence instance. The Fence will be used to signal the availability of the Framebuffer to incoming data transfer. Add a set of function to set, cancel and retrieve a refence to the Fence. Signed-off-by: Jacopo Mondi --- include/libcamera/framebuffer.h | 3 +++ include/libcamera/internal/framebuffer.h | 9 ++++++++ src/libcamera/framebuffer.cpp | 26 ++++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h index 7f2f176af691..aa2a1f5193c7 100644 --- a/include/libcamera/framebuffer.h +++ b/include/libcamera/framebuffer.h @@ -19,6 +19,7 @@ namespace libcamera { +class Fence; class Request; struct FrameMetadata { @@ -66,6 +67,8 @@ public: unsigned int cookie() const { return cookie_; } void setCookie(unsigned int cookie) { cookie_ = cookie; } + Fence *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..9e1699a6875d 100644 --- a/include/libcamera/internal/framebuffer.h +++ b/include/libcamera/internal/framebuffer.h @@ -7,10 +7,14 @@ #ifndef __LIBCAMERA_INTERNAL_FRAMEBUFFER_H__ #define __LIBCAMERA_INTERNAL_FRAMEBUFFER_H__ +#include + #include #include +#include + namespace libcamera { class FrameBuffer::Private : public Extensible::Private @@ -23,8 +27,13 @@ public: void setRequest(Request *request) { request_ = request; } bool isContiguous() const { return isContiguous_; } + void setFence(std::unique_ptr &&fence) { fence_ = std::move(fence); } + void closeFence() { fence_.reset(); } + Fence *fence() const { return fence_.get(); } + private: Request *request_; + std::unique_ptr fence_; bool isContiguous_; }; diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp index 337ea1155a38..63c4ce6ab450 100644 --- a/src/libcamera/framebuffer.cpp +++ b/src/libcamera/framebuffer.cpp @@ -126,6 +126,23 @@ FrameBuffer::Private::Private() * handlers, it is called by the pipeline handlers themselves. */ +/** + * \fn FrameBuffer::Private::setFence() + * \brief Set the synchronization fence for this buffer + * \param[in] fence The synchronization fence + */ + +/** + * \fn FrameBuffer::Private::closeFence() + * \brief Close the synchronization fence for this buffer + */ + +/** + * \fn FrameBuffer::Private::fence() + * \brief Retrieve a pointer to the synchronization fence of this buffer + * \return A pointer to the buffer fence, nullptr if the buffer has not fence + */ + /** * \fn FrameBuffer::Private::isContiguous() * \brief Check if the frame buffer stores planes contiguously in memory @@ -305,6 +322,15 @@ Request *FrameBuffer::request() const * libcamera core never modifies the buffer cookie. */ +/** + * \brief Retrieve a reference to the Fence associated with this Framebuffer + * \return A pointer to the Fence, if set, nullptr otherwise + */ +Fence *FrameBuffer::fence() const +{ + return _d()->fence(); +} + /** * \fn FrameBuffer::cancel() * \brief Marks the buffer as cancelled From patchwork Sat Nov 20 11:13:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14672 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 404AEC324F for ; Sat, 20 Nov 2021 11:12:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C530A6048E; Sat, 20 Nov 2021 12:12:28 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 12F1D6033C for ; Sat, 20 Nov 2021 12:12:25 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 99372100002; Sat, 20 Nov 2021 11:12:24 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:05 +0100 Message-Id: <20211120111313.106621-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 04/12] libcamera: request: Add Fence to Request::addBuffer() 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 overloaded version of Request::addBuffer() that allows application to specify a Fence instance to be associated with the Framebuffer. Signed-off-by: Jacopo Mondi --- include/libcamera/request.h | 5 ++++ src/libcamera/request.cpp | 58 ++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index f0c5163d987e..37aebc41834e 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -22,6 +22,7 @@ namespace libcamera { class Camera; class CameraControlValidator; +class Fence; class FrameBuffer; class Stream; @@ -52,6 +53,8 @@ public: ControlList &metadata() { return *metadata_; } const BufferMap &buffers() const { return bufferMap_; } int addBuffer(const Stream *stream, FrameBuffer *buffer); + int addBuffer(const Stream *stream, FrameBuffer *buffer, + std::unique_ptr &&fence); FrameBuffer *findBuffer(const Stream *stream) const; uint32_t sequence() const; @@ -65,6 +68,8 @@ public: private: LIBCAMERA_DISABLE_COPY(Request) + int _addBuffer(const Stream *stream, FrameBuffer *buffer); + ControlList *controls_; ControlList *metadata_; BufferMap bufferMap_; diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 90c436648405..1d47698a6263 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -19,6 +19,7 @@ #include "libcamera/internal/camera.h" #include "libcamera/internal/camera_controls.h" +#include "libcamera/internal/fence.h" #include "libcamera/internal/framebuffer.h" #include "libcamera/internal/tracepoints.h" @@ -316,6 +317,26 @@ void Request::reuse(ReuseFlag flags) * \return The map of Stream to FrameBuffer */ +int Request::_addBuffer(const Stream *stream, FrameBuffer *buffer) +{ + if (!stream) { + LOG(Request, Error) << "Invalid stream reference"; + return -EINVAL; + } + + auto it = bufferMap_.find(stream); + if (it != bufferMap_.end()) { + LOG(Request, Error) << "FrameBuffer already set for stream"; + return -EEXIST; + } + + buffer->_d()->setRequest(this); + _d()->pending_.insert(buffer); + bufferMap_[stream] = buffer; + + return 0; +} + /** * \brief Add a FrameBuffer with its associated Stream to the Request * \param[in] stream The stream the buffer belongs to @@ -334,22 +355,33 @@ void Request::reuse(ReuseFlag flags) */ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer) { - if (!stream) { - LOG(Request, Error) << "Invalid stream reference"; - return -EINVAL; - } + int ret = _addBuffer(stream, buffer); + if (ret) + return ret; + + /* + * Drop the buffer Fence, if any. + * + * Buffers can be re-used and might still have a Fence associated from + * a previous run if the Fence has failed. Drop it here. + */ + buffer->_d()->closeFence(); - auto it = bufferMap_.find(stream); - if (it != bufferMap_.end()) { - LOG(Request, Error) << "FrameBuffer already set for stream"; - return -EEXIST; - } + return 0; +} - buffer->_d()->setRequest(this); - _d()->pending_.insert(buffer); - bufferMap_[stream] = buffer; +/** + * \brief Add a FrameBuffer with its associated Stream and Fence + * \copydoc Request::addBuffer(const Stream *stream, FrameBuffer *buffer) + * \param[in] fence The synchronization fence associated with \a buffer + */ +int Request::addBuffer(const Stream *stream, FrameBuffer *buffer, + std::unique_ptr &&fence) +{ + if (fence->isValid()) + buffer->_d()->setFence(std::move(fence)); - return 0; + return _addBuffer(stream, buffer); } /** From patchwork Sat Nov 20 11:13:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14673 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 D8F4FC3250 for ; Sat, 20 Nov 2021 11:12:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0424160492; Sat, 20 Nov 2021 12:12:29 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A32C460376 for ; Sat, 20 Nov 2021 12:12:25 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 3AEB9100002; Sat, 20 Nov 2021 11:12:25 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:06 +0100 Message-Id: <20211120111313.106621-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 05/12] test: fence: 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 a Fence failure case, and by testing a successfully signalled fence capture cycle. Signed-off-by: Jacopo Mondi --- test/fence.cpp | 339 +++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 340 insertions(+) create mode 100644 test/fence.cpp diff --git a/test/fence.cpp b/test/fence.cpp new file mode 100644 index 000000000000..7434542a89f8 --- /dev/null +++ b/test/fence.cpp @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * fence.cpp - Fence test + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "camera_test.h" +#include "test.h" + +using namespace std::chrono_literals; +using namespace libcamera; +using namespace std; + +class FenceTest : public CameraTest, public Test +{ +public: + FenceTest(); + +protected: + int init(); + int run(); + void cleanup(); + +private: + int validateExpiredRequest(Request *request); + void requestComplete(Request *request); + void signalFence(); + + std::unique_ptr fence_; + EventDispatcher *dispatcher_; + FileDescriptor eventFd_; + Timer fenceTimer_; + + std::vector> requests_; + std::unique_ptr config_; + FrameBufferAllocator *allocator_; + + Stream *stream_; + + bool expectedCompletionResult_ = true; + bool expectFenceFailure_ = true; + + unsigned int completedRequest_; + + unsigned int signalledRequestId_; + unsigned int expiredRequestId_; + unsigned int nbuffers_; + + int efd2Copy_; + int efdCopy_; +}; + +FenceTest::FenceTest() + : CameraTest("platform/vimc.0 Sensor B") +{ +} + +int FenceTest::init() +{ + dispatcher_ = Thread::current()->eventDispatcher(); + + int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (efd < 0) { + cerr << "Unable to create eventfd" << endl; + return TestFail; + } + + /* + * Keep a copy of the original fd value to validate that an expired + * fence has the same fd value. + */ + efdCopy_ = efd; + + FileDescriptor eventFd(std::move(efd)); + fence_ = std::make_unique(eventFd); + if (!fence_->isValid()) { + cerr << "Fence should be valid when created with a valid FileDescriptor" << endl; + return TestFail; + } + + if (fence_->fd().fd() != efdCopy_) { + cerr << "Fence creation should not duplicate file descriptor" << endl; + return TestFail; + } + + config_ = camera_->generateConfiguration({ StreamRole::Viewfinder }); + if (!config_ || config_->size() != 1) { + cerr << "Failed to generate default configuration" << endl; + return TestFail; + } + + if (camera_->acquire()) { + cerr << "Failed to acquire the camera" << endl; + return TestFail; + } + + if (camera_->configure(config_.get())) { + cerr << "Failed to set default configuration" << endl; + return TestFail; + } + + StreamConfiguration &cfg = config_->at(0); + stream_ = cfg.stream(); + + allocator_ = new FrameBufferAllocator(camera_); + if (allocator_->allocate(stream_) < 0) + return TestFail; + + nbuffers_ = allocator_->buffers(stream_).size(); + signalledRequestId_ = nbuffers_ - 2; + expiredRequestId_ = nbuffers_ - 1; + + return TestPass; +} + +int FenceTest::validateExpiredRequest(Request *request) +{ + FrameBuffer *buffer = request->buffers().begin()->second; + + Fence *fence = buffer->fence(); + if (!fence) { + cerr << "The expired fence should be present" << endl; + return TestFail; + } + + if (!fence->isValid()) { + cerr << "The expired fence should be valid" << endl; + return TestFail; + } + + if (fence->fd().fd() != efdCopy_) { + cerr << "The expired fence file descriptor should not change" << endl; + return TestFail; + } + + fence->close(); + + expectFenceFailure_ = false; + + return 0; +} + +/* Callback to signal a fence waiting on the eventfd file descriptor. */ +void FenceTest::signalFence() +{ + uint64_t value = 1; + write(efd2Copy_, &value, sizeof(value)); + dispatcher_->processEvents(); +} + +void FenceTest::requestComplete(Request *request) +{ + uint64_t cookie = request->cookie(); + completedRequest_ = cookie; + + /* We expect the last request to fail, if it doesn't happen, test fails. */ + if (expectFenceFailure_ && cookie == expiredRequestId_ && + request->status() != Request::RequestCancelled) { + cerr << "The last request should have failed: " << cookie << endl; + + expectedCompletionResult_ = false; + dispatcher_->interrupt(); + return; + } + + /* All other requests but the last one should be completed. */ + if (expectFenceFailure_ && cookie < expiredRequestId_ && + request->status() != Request::RequestComplete) { + cerr << "All requests but last should complete: " << cookie << endl; + + expectedCompletionResult_ = false; + dispatcher_->interrupt(); + return; + } + + /* + * If the last request has failed already, all the ones queued after + * that shall complete. + */ + if (!expectFenceFailure_ && + request->status() != Request::RequestComplete) { + cerr << "Unexpected request failure: " << cookie << endl; + + expectedCompletionResult_ = false; + dispatcher_->interrupt(); + return; + } + + /* + * The last request has failed. + * Validate its fence status and do not re-queue it. + */ + if (cookie == expiredRequestId_) { + int ret = validateExpiredRequest(request); + if (ret) + expectedCompletionResult_ = false; + + dispatcher_->interrupt(); + return; + } + + const Request::BufferMap &buffers = request->buffers(); + const Stream *stream = buffers.begin()->first; + FrameBuffer *buffer = buffers.begin()->second; + + /* A succesfully completed request should have the Fence closed. */ + if (buffer->fence()) { + cerr << "Unexpected valid fence in completed request" << endl; + + expectedCompletionResult_ = false; + dispatcher_->interrupt(); + return; + } + + request->reuse(); + + if (cookie == signalledRequestId_) { + /* + * The second time this request is about to be queued add + * a fence to it. + * + * The main loop should signal it by using a timer to write to + * the eventfd file descriptor before the fence expires. + */ + int efd2 = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (efd2 < 0) { + cerr << "Unable to create eventfd" << endl; + expectedCompletionResult_ = false; + return; + } + efd2Copy_ = efd2; + + FileDescriptor eventFd(std::move(efd2)); + std::unique_ptr fence = std::make_unique(eventFd); + request->addBuffer(stream, buffer, std::move(fence)); + } else { + /* All the other requests continue to operate without fences. */ + request->addBuffer(stream, buffer); + } + + camera_->queueRequest(request); + + /* + * Interrupt the dispatcher to return control to the main loop and + * activate the fenceTimer + . */ + dispatcher_->interrupt(); +} + +int FenceTest::run() +{ + for (const auto &[i, buffer] : utils::enumerate(allocator_->buffers(stream_))) { + std::unique_ptr request = camera_->createRequest(i); + if (!request) { + cerr << "Failed to create request" << endl; + return TestFail; + } + + int ret; + if (i == expiredRequestId_) + /* This request will have a fence, and it will expire. */ + ret = request->addBuffer(stream_, buffer.get(), std::move(fence_)); + else + ret = request->addBuffer(stream_, buffer.get()); + + if (ret) { + cerr << "Failed to associate buffer with request" << endl; + return TestFail; + } + + requests_.push_back(std::move(request)); + } + + camera_->requestCompleted.connect(this, &FenceTest::requestComplete); + + if (camera_->start()) { + cerr << "Failed to start camera" << endl; + return TestFail; + } + + for (std::unique_ptr &request : requests_) { + if (camera_->queueRequest(request.get())) { + cerr << "Failed to queue request" << endl; + return TestFail; + } + } + + expectedCompletionResult_ = true; + + /* This timer serves to signal fences associated with "signalledRequestId_" */ + Timer fenceTimer; + fenceTimer.timeout.connect(this, &FenceTest::signalFence); + + /* Loop for one second. */ + Timer timer; + timer.start(1000); + while (timer.isRunning() && expectedCompletionResult_) { + if (completedRequest_ == signalledRequestId_) + /* + * signalledRequestId_ has just completed and it has + * been re-queued with a fence. Start the timer to + * signal the fence in 10 msec. + */ + fenceTimer.start(10); + + dispatcher_->processEvents(); + } + + camera_->requestCompleted.disconnect(); + + if (camera_->stop()) { + cerr << "Failed to stop camera" << endl; + return TestFail; + } + + return expectedCompletionResult_ ? TestPass : TestFail; +} + +void FenceTest::cleanup() +{ + delete allocator_; +} + +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 Sat Nov 20 11:13:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14674 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 54EC6BDB13 for ; Sat, 20 Nov 2021 11:12:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2D2B660499; Sat, 20 Nov 2021 12:12:29 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 42FB1603C4 for ; Sat, 20 Nov 2021 12:12:26 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id CE7F0100002; Sat, 20 Nov 2021 11:12:25 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:07 +0100 Message-Id: <20211120111313.106621-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 06/12] 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 the doQueueRequest() 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 | 6 +++++ .../libcamera/internal/tracepoints/request.tp | 9 +++++++ src/libcamera/pipeline_handler.cpp | 27 +++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index 41cba44d990f..608e6f79039f 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -7,6 +7,7 @@ #ifndef __LIBCAMERA_INTERNAL_PIPELINE_HANDLER_H__ #define __LIBCAMERA_INTERNAL_PIPELINE_HANDLER_H__ +#include #include #include #include @@ -76,9 +77,14 @@ private: void mediaDeviceDisconnected(MediaDevice *media); virtual void disconnect(); + void doQueueRequest(Request *request); + void doQueueRequests(); + std::vector> mediaDevices_; std::vector> cameras_; + std::deque waitingRequests_; + const char *name_; friend class PipelineHandlerFactory; diff --git a/include/libcamera/internal/tracepoints/request.tp b/include/libcamera/internal/tracepoints/request.tp index 37cd2f8864ce..87219b8d8e6f 100644 --- a/include/libcamera/internal/tracepoints/request.tp +++ b/include/libcamera/internal/tracepoints/request.tp @@ -58,6 +58,15 @@ TRACEPOINT_EVENT_INSTANCE( ) ) +TRACEPOINT_EVENT_INSTANCE( + libcamera, + request, + request_device_queue, + TP_ARGS( + libcamera::Request *, req + ) +) + TRACEPOINT_EVENT_INSTANCE( libcamera, request, diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 67fdf1d8db01..b8dd03647954 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -312,6 +312,17 @@ void PipelineHandler::queueRequest(Request *request) { LIBCAMERA_TRACEPOINT(request_queue, request); + waitingRequests_.push_back(request); + doQueueRequests(); +} + +/** + * \brief Queue one requests to the device + */ +void PipelineHandler::doQueueRequest(Request *request) +{ + LIBCAMERA_TRACEPOINT(request_device_queue, request); + Camera *camera = request->_d()->camera(); Camera::Private *data = camera->_d(); data->queuedRequests_.push_back(request); @@ -325,6 +336,22 @@ void PipelineHandler::queueRequest(Request *request) } } +/** + * \brief Queue requests to the device + */ +void PipelineHandler::doQueueRequests() +{ + while (true) { + if (waitingRequests_.empty()) + return; + + Request *request = waitingRequests_.front(); + waitingRequests_.pop_front(); + + doQueueRequest(request); + } +} + /** * \fn PipelineHandler::queueRequestDevice() * \brief Queue a request to the device From patchwork Sat Nov 20 11:13:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14675 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 B21E9C3251 for ; Sat, 20 Nov 2021 11:12:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5F23D6049B; Sat, 20 Nov 2021 12:12:29 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E76B260378 for ; Sat, 20 Nov 2021 12:12:26 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 71A26100002; Sat, 20 Nov 2021 11:12:26 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:08 +0100 Message-Id: <20211120111313.106621-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 07/12] 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 --- 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 | 29 +++++++++++++++++-- 8 files changed, 41 insertions(+), 15 deletions(-) diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index 608e6f79039f..4ca3049b074c 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -55,7 +55,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); @@ -70,6 +70,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 c65afdb2912a..8da1cd93c4dc 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -134,7 +134,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; @@ -792,7 +792,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 5e1f227398a9..d8f5b2990fe6 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -299,7 +299,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; @@ -922,7 +922,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 b8dd03647954..3b9145992c8f 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -267,8 +267,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 @@ -276,6 +275,32 @@ 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 waiting requests. */ + for (auto &waitingRequest : waitingRequests_) { + waitingRequest->_d()->cancel(); + completeRequest(waitingRequest); + } + + waitingRequests_.clear(); + + /* Make sure no requests are pending. */ + Camera::Private *data = camera->_d(); + ASSERT(data->queuedRequests_.empty()); +} + +/** + * \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 Sat Nov 20 11:13:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14676 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 2C35EC324F for ; Sat, 20 Nov 2021 11:12:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EFE956042B; Sat, 20 Nov 2021 12:12:29 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8DDC66039C for ; Sat, 20 Nov 2021 12:12:27 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 1AB69100002; Sat, 20 Nov 2021 11:12:26 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:09 +0100 Message-Id: <20211120111313.106621-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 08/12] libcamera: request: Add Request::Private::prepare() 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 prepare() function to the Private Request representation. The prepare() function is used by the PipelineHandler class to prepare a Request to be queued to the hardware. The current implementation of prepare() handles the fences associated with the Framebuffers part of a Request. The function starts an event notifier for each of those and notifies the Request as Ready to be queued once all the fences have been signalled. An optional timeout allows to interrupt blocked waits and notify the Request as failed. Signed-off-by: Jacopo Mondi --- include/libcamera/internal/request.h | 21 ++++ src/libcamera/request.cpp | 150 +++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h index 59bddde3a090..26b25fb12261 100644 --- a/include/libcamera/internal/request.h +++ b/include/libcamera/internal/request.h @@ -7,10 +7,16 @@ #ifndef __LIBCAMERA_INTERNAL_REQUEST_H__ #define __LIBCAMERA_INTERNAL_REQUEST_H__ +#include #include +#include +#include + #include +using namespace std::chrono_literals; + namespace libcamera { class Camera; @@ -21,6 +27,12 @@ class Request::Private : public Extensible::Private LIBCAMERA_DECLARE_PUBLIC(Request) public: + enum class Status { + Pending, + Ready, + Failed + }; + Private(Camera *camera); ~Private(); @@ -29,21 +41,30 @@ public: uint64_t cookie() const; Request::Status status() const; + Status privateStatus() const { return status_; } bool completeBuffer(FrameBuffer *buffer); void complete(); void cancel(); void reuse(); + Status prepare(std::chrono::milliseconds timeout = 0ms); + Signal<> prepared; + uint32_t sequence_ = 0; private: void _cancel(); + void notifierActivated(const std::unique_ptr ¬ifier); + void timeout(); Camera *camera_; bool cancelled_; + Status status_ = Status::Pending; std::unordered_set pending_; + std::unordered_set> notifiers_; + std::unique_ptr timer_; }; } /* namespace libcamera */ diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 1d47698a6263..98f9719e5cf2 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -43,6 +43,22 @@ LOG_DEFINE_CATEGORY(Request) * subclasses). */ +/** + * \enum Request::Private::Status + * \brief Request private status + * + * The Request private status describes the lifecycle of the Request between + * the time it is queued to the Camera and the time it is queued to the device. + * + * A Request is created in Status::Pending state. Before actually queueing the + * Request the PipelineHandler base class prepare() the Request, whose status + * transitions to either Status::Ready or Status::Failed. + * + * \var Request::Private::Status::Pending + * \var Request::Private::Status::Ready + * \var Request::Private::Status::Failed + */ + /** * \brief Create a Request::Private * \param camera The Camera that creates the request @@ -95,6 +111,17 @@ Request::Status Request::Private::status() const return _o()->status(); } +/** + * \fn Request::Private::privateStatus() + * \brief Retrieve the Request private status + * + * The private status, as described by the Request::Private:Status enumeration, + * describes the Request status between the time it is queued to the Camera and + * the time the Request is applied to the hardware. + * + * \return The Request private state + */ + /** * \brief Complete a buffer for the request * \param[in] buffer The buffer that has completed @@ -155,6 +182,8 @@ void Request::Private::_cancel() cancelled_ = true; pending_.clear(); + notifiers_.clear(); + timer_.reset(); } /** @@ -182,8 +211,84 @@ void Request::Private::reuse() { sequence_ = 0; cancelled_ = false; + status_ = Status::Pending; pending_.clear(); + notifiers_.clear(); + timer_.reset(); +} + +/** + * \brief Prepare the Request to be queued to the device + * \param[in] timeout Optional expiration timeout + * + * Prepare a Request to be queued to the hardware device it by ensuring it is + * ready for the incoming memory transfers. + * + * This currently means waiting on each frame buffer acquire fence to be + * signalled. An optional expiration timeout can be specified. If not all the + * fences have been signalled correctly before the timeout expires the Request + * is marked as Failed, otherwise it is set to the Ready state. + * + * \sa Request::Private::Status + * + * The function returns Status::Ready if all the prepare operations have been + * completed synchronously. If Status::Ready is returned the Request can be + * queued immediately and the prepared signal is not emitted. If instead the + * prepare operation requires to wait the completion of asynchronous events, + * such as fence notifications or timer expiration this function returns + * Status::Pending and the asynchronous event completion is notified by emitting + * the prepared signal. + * + * As we currently only handle fences, the function return Status::Ready if + * there are no fences to wait on. Status::Prepared is otherwise returned and + * the prepared signal is emitted when all fences have been signalled or the + * optional timeout has expired. + * + * The intended user of this function is the PipelineHandler base class, which + * 'prepares' a Request before queuing it to the hardware device. + * + * \return The Request status + */ +Request::Private::Status Request::Private::prepare(std::chrono::milliseconds timeout) +{ + FrameBuffer::Private *bufferData; + + /* Create and connect one notifier for each synchronization fence. */ + for (FrameBuffer *buffer : pending_) { + bufferData = buffer->_d(); + + if (!bufferData->fence()) + continue; + + int fenceFd = bufferData->fence()->fd().fd(); + notifiers_.emplace(new EventNotifier(fenceFd, EventNotifier::Read)); + } + + if (notifiers_.empty()) { + status_ = Status::Ready; + return status_; + } + + for (const std::unique_ptr ¬ifier : notifiers_) + notifier->activated.connect(this, [this, ¬ifier] { + notifierActivated(notifier); + }); + + /* In case a timeout is specified, create a timer and set it up. */ + if (timeout != 0ms) { + timer_ = std::make_unique(); + timer_->timeout.connect(this, &Request::Private::timeout); + timer_->start(timeout); + } + + return Status::Pending; } + +/** + * \var Request::Private::prepared + * \brief Request preparation completed Signal + */ + /** * \var Request::Private::sequence_ * \brief The request sequence number @@ -191,6 +296,51 @@ void Request::Private::reuse() * \copydoc Request::sequence() */ +void Request::Private::notifierActivated(const std::unique_ptr ¬ifier) +{ + auto it = notifiers_.find(notifier); + ASSERT(it != notifiers_.end()); + + /* We need to close the fence if successfully signalled. */ + int fd = notifier->fd(); + bool found = false; + for (FrameBuffer *buffer : pending_) { + FrameBuffer::Private *bufferData = buffer->_d(); + + if (!bufferData->fence()) + continue; + + if (bufferData->fence()->fd().fd() != fd) + continue; + + bufferData->closeFence(); + found = true; + break; + } + ASSERT(found); + + notifiers_.erase(it); + if (!notifiers_.empty()) + return; + + /* All fences completed, delete the timer and move to state Ready. */ + timer_.reset(); + status_ = Status::Ready; + prepared.emit(); +} + +void Request::Private::timeout() +{ + /* A timeout can only happen if there are fences not yet signalled. */ + ASSERT(!notifiers_.empty()); + notifiers_.clear(); + + LOG(Request, Error) << "Request prepare timeout"; + + status_ = Status::Failed; + prepared.emit(); +} + /** * \enum Request::Status * Request completion status From patchwork Sat Nov 20 11:13:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14677 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 629C6C3252 for ; Sat, 20 Nov 2021 11:12:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A43596043C; Sat, 20 Nov 2021 12:12:30 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2EFE06039C for ; Sat, 20 Nov 2021 12:12:28 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id B7D19100002; Sat, 20 Nov 2021 11:12:27 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:10 +0100 Message-Id: <20211120111313.106621-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 09/12] libcamera: pipeline_handler: Prepare Request 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. Connect the Request::Private::prepared signal to the function that queues requests to the hardware and call Request::Private::prepare(). When the waiting request queue is inspected, verify the Request::Private status to discern if a Request has failed preparing or it can be queued to the hardware. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline_handler.cpp | 32 +++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 3b9145992c8f..82ef214d16f2 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -7,6 +7,7 @@ #include "libcamera/internal/pipeline_handler.h" +#include #include #include @@ -17,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" @@ -36,6 +38,8 @@ * the REGISTER_PIPELINE_HANDLER() macro. */ +using namespace std::chrono_literals; + namespace libcamera { LOG_DEFINE_CATEGORY(Pipeline) @@ -338,7 +342,14 @@ void PipelineHandler::queueRequest(Request *request) LIBCAMERA_TRACEPOINT(request_queue, request); waitingRequests_.push_back(request); - doQueueRequests(); + + request->_d()->prepared.connect(this, [this]() { + doQueueRequests(); + }); + + Request::Private::Status status = request->_d()->prepare(300ms); + if (status == Request::Private::Status::Ready) + doQueueRequests(); } /** @@ -354,6 +365,12 @@ void PipelineHandler::doQueueRequest(Request *request) request->_d()->sequence_ = data->requestSequence_++; + if (request->_d()->privateStatus() == Request::Private::Status::Failed) { + request->_d()->cancel(); + completeRequest(request); + return; + } + int ret = queueRequestDevice(camera, request); if (ret) { request->_d()->cancel(); @@ -371,9 +388,18 @@ void PipelineHandler::doQueueRequests() return; Request *request = waitingRequests_.front(); - waitingRequests_.pop_front(); + Request::Private::Status status = request->_d()->privateStatus(); + + switch (status) { + case Request::Private::Status::Pending: + return; - doQueueRequest(request); + case Request::Private::Status::Failed: + case Request::Private::Status::Ready: + waitingRequests_.pop_front(); + doQueueRequest(request); + break; + } } } From patchwork Sat Nov 20 11:13: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: 14678 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 517EBBDB13 for ; Sat, 20 Nov 2021 11:12:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 181C36038C; Sat, 20 Nov 2021 12:12:35 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CB85E60490 for ; Sat, 20 Nov 2021 12:12:28 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 56F57100002; Sat, 20 Nov 2021 11:12:28 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:11 +0100 Message-Id: <20211120111313.106621-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 10/12] 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 --- src/android/camera_device.cpp | 43 +++++------ src/android/camera_device.h | 3 - 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, 24 insertions(+), 230 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..29f0abd96ba9 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -406,7 +407,6 @@ void CameraDevice::flush() state_ = State::Flushing; } - worker_.stop(); camera_->stop(); MutexLocker stateLock(stateMutex_); @@ -419,7 +419,6 @@ void CameraDevice::stop() if (state_ == State::Stopped) return; - worker_.stop(); camera_->stop(); descriptors_ = {}; @@ -912,13 +911,10 @@ 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. */ + FileDescriptor fenceFd; FrameBuffer *frameBuffer = nullptr; - int acquireFence = -1; switch (cameraStream->type()) { case CameraStream::Type::Mapped: /* @@ -943,7 +939,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques cameraStream->configuration().pixelFormat, cameraStream->configuration().size); frameBuffer = buffer.frameBuffer.get(); - acquireFence = buffer.fence; + fenceFd = FileDescriptor(std::move(buffer.fence)); LOG(HAL, Debug) << ss.str() << " (direct)"; break; @@ -969,13 +965,14 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques return -ENOMEM; } + std::unique_ptr fence = std::make_unique(fenceFd); descriptor->request_->addBuffer(cameraStream->stream(), - frameBuffer, acquireFence); + frameBuffer, std::move(fence)); } /* * 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 +998,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 +1036,23 @@ 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; + if (stream->type() == CameraStream::Type::Direct) { + Fence *fence = buffer.frameBuffer->fence(); + if (!fence) + break; + + FileDescriptor fenceFd = std::move(fence->fd()); + buffer.fence = fenceFd.fd(); + } buffer.status = Camera3RequestDescriptor::Status::Success; } diff --git a/src/android/camera_device.h b/src/android/camera_device.h index 2a414020f1ad..c8cc78688bec 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; @@ -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 8162aa78e953..917769070cd9 100644 --- a/src/android/camera_request.cpp +++ b/src/android/camera_request.cpp @@ -47,8 +47,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 8d1204e5590b..69e1fe9fc379 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; @@ -71,7 +70,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', From patchwork Sat Nov 20 11:13: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: 14679 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 7E3B3C324F for ; Sat, 20 Nov 2021 11:12:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3EA8C603F9; Sat, 20 Nov 2021 12:12:35 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 69F996049F for ; Sat, 20 Nov 2021 12:12:29 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 01450100002; Sat, 20 Nov 2021 11:12:28 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:12 +0100 Message-Id: <20211120111313.106621-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 11/12] test: camera: Fix trivial spelling mistaken 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 error message should be: "Failed to associate buffer with request" Fix that. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- test/camera/capture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/camera/capture.cpp b/test/camera/capture.cpp index 41ae00d7a4c0..f3824f95cbd3 100644 --- a/test/camera/capture.cpp +++ b/test/camera/capture.cpp @@ -109,7 +109,7 @@ protected: } if (request->addBuffer(stream, buffer.get())) { - cout << "Failed to associating buffer with request" << endl; + cout << "Failed to associate buffer with request" << endl; return TestFail; } From patchwork Sat Nov 20 11:13: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: 14680 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 C8325C3250 for ; Sat, 20 Nov 2021 11:12:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 604B760441; Sat, 20 Nov 2021 12:12:35 +0100 (CET) Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 05E7C604FB for ; Sat, 20 Nov 2021 12:12:30 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 8C49B100002; Sat, 20 Nov 2021 11:12:29 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sat, 20 Nov 2021 12:13:13 +0100 Message-Id: <20211120111313.106621-13-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211120111313.106621-1-jacopo@jmondi.org> References: <20211120111313.106621-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 12/12] libcamera: Add tracing to meson summary 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 meson option summary currently does not report if the support for tracing is enabled or not. Add it. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- meson.build | 1 + src/libcamera/meson.build | 3 +++ 2 files changed, 4 insertions(+) diff --git a/meson.build b/meson.build index 7892a9e38c1c..15793e1834ce 100644 --- a/meson.build +++ b/meson.build @@ -179,6 +179,7 @@ summary({ 'qcam application': qcam_enabled, 'lc-compliance application': lc_compliance_enabled, 'Unit tests': test_enabled, + 'Tracing support': tracing_enabled, }, section : 'Configuration', bool_yn : true) diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6fb0d5f49b63..6a3f5160fdcd 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -71,8 +71,11 @@ if libgnutls.found() endif if liblttng.found() + tracing_enabled = true config_h.set('HAVE_TRACING', 1) libcamera_sources += files(['tracepoints.cpp']) +else + tracing_enabled = false endif if libudev.found()