From patchwork Wed Dec 1 14:29:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14961 X-Patchwork-Delegate: jacopo@jmondi.org 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 D2A7EC3250 for ; Wed, 1 Dec 2021 14:28:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 797D96073F; Wed, 1 Dec 2021 15:28:51 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BF746604FC for ; Wed, 1 Dec 2021 15:28:49 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id DF9AFC0008; Wed, 1 Dec 2021 14:28:48 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:26 +0100 Message-Id: <20211201142936.107405-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 01/11] libcamera: Print Timer identifier 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 Timer debug output does not report to which timer a condition refers to. Fix that by printing the Timer address. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/base/event_dispatcher_poll.cpp | 9 +++++---- src/libcamera/base/timer.cpp | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcamera/base/event_dispatcher_poll.cpp b/src/libcamera/base/event_dispatcher_poll.cpp index 8ee22d5adcc4..7c5a3bb39ff9 100644 --- a/src/libcamera/base/event_dispatcher_poll.cpp +++ b/src/libcamera/base/event_dispatcher_poll.cpp @@ -213,10 +213,11 @@ int EventDispatcherPoll::poll(std::vector *pollfds) else timeout = { 0, 0 }; - LOG(Event, Debug) - << "timeout " << timeout.tv_sec << "." - << std::setfill('0') << std::setw(9) - << timeout.tv_nsec; + LOG(Event, Debug) + << "next timer " << nextTimer << " expires in " + << timeout.tv_sec << "." + << std::setfill('0') << std::setw(9) + << timeout.tv_nsec; } return ppoll(pollfds->data(), pollfds->size(), diff --git a/src/libcamera/base/timer.cpp b/src/libcamera/base/timer.cpp index 9c54352d46bd..187336e3a1a4 100644 --- a/src/libcamera/base/timer.cpp +++ b/src/libcamera/base/timer.cpp @@ -96,7 +96,7 @@ void Timer::start(std::chrono::milliseconds duration) void Timer::start(std::chrono::steady_clock::time_point deadline) { if (Thread::current() != thread()) { - LOG(Timer, Error) << "Timer can't be started from another thread"; + LOG(Timer, Error) << "Timer " << this << " << can't be started from another thread"; return; } @@ -128,7 +128,7 @@ void Timer::stop() return; if (Thread::current() != thread()) { - LOG(Timer, Error) << "Timer can't be stopped from another thread"; + LOG(Timer, Error) << "Timer " << this << " can't be stopped from another thread"; return; } From patchwork Wed Dec 1 14:29:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14962 X-Patchwork-Delegate: jacopo@jmondi.org 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 16CE8BDB13 for ; Wed, 1 Dec 2021 14:28:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CD49A6073D; Wed, 1 Dec 2021 15:28:53 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AEDE760740 for ; Wed, 1 Dec 2021 15:28:51 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 037E1C0008; Wed, 1 Dec 2021 14:28:49 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:27 +0100 Message-Id: <20211201142936.107405-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 02/11] 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 allows 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 Reviewed-by: Laurent Pinchart --- include/libcamera/internal/meson.build | 1 + include/libcamera/internal/request.h | 49 ++++ .../libcamera/internal/tracepoints/request.tp | 13 +- include/libcamera/request.h | 19 +- src/libcamera/pipeline_handler.cpp | 15 +- src/libcamera/request.cpp | 230 ++++++++++++------ 6 files changed, 219 insertions(+), 108 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..1340ffa2a683 --- /dev/null +++ b/include/libcamera/internal/request.h @@ -0,0 +1,49 @@ +/* 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; + + bool completeBuffer(FrameBuffer *buffer); + void complete(); + void cancel(); + void reuse(); + +private: + friend class PipelineHandler; + + void doCancelRequest(); + + Camera *camera_; + bool cancelled_; + uint32_t sequence_ = 0; + + 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..f039ffd4f88d 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,13 +80,13 @@ TRACEPOINT_EVENT( libcamera, request_complete_buffer, TP_ARGS( - libcamera::Request *, req, + libcamera::Request::Private *, req, libcamera::FrameBuffer *, buf ), TP_FIELDS( ctf_integer_hex(uintptr_t, request, reinterpret_cast(req)) - ctf_integer(uint64_t, cookie, req->cookie()) - ctf_integer(int, status, req->status()) + ctf_integer(uint64_t, cookie, req->_o()->cookie()) + ctf_integer(int, status, req->_o()->status()) ctf_integer_hex(uintptr_t, buffer, reinterpret_cast(buf)) ctf_enum(libcamera, buffer_status, uint32_t, buf_status, buf->metadata().status) ) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index f434335b243a..8c78970d88ab 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..692202473360 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,139 @@ 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() +{ + doCancelRequest(); +} + +/** + * \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(); +} + +/** + * \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::doCancelRequest() +{ + 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); + + doCancelRequest(); +} + +/** + * \copydoc Request::reuse() + */ +void Request::Private::reuse() +{ + sequence_ = 0; + cancelled_ = false; + pending_.clear(); +} + /** * \enum Request::Status * Request completion status @@ -75,8 +208,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 +246,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 +320,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 +359,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 +373,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 +398,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 +424,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 Wed Dec 1 14:29:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14963 X-Patchwork-Delegate: jacopo@jmondi.org 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 8112FC3250 for ; Wed, 1 Dec 2021 14:28:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 075B460746; Wed, 1 Dec 2021 15:28:54 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 785216073C for ; Wed, 1 Dec 2021 15:28:52 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id B91B1C0005; Wed, 1 Dec 2021 14:28:51 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:28 +0100 Message-Id: <20211201142936.107405-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 03/11] 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 UniqueFD 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 Reviewed-by: Laurent Pinchart --- include/libcamera/fence.h | 31 ++++++++++ include/libcamera/meson.build | 1 + src/libcamera/fence.cpp | 113 ++++++++++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 146 insertions(+) create mode 100644 include/libcamera/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..c0c916c264b4 --- /dev/null +++ b/include/libcamera/fence.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * internal/fence.h - Synchronization fence + */ + +#pragma once + +#include +#include + +namespace libcamera { + +class Fence +{ +public: + Fence(UniqueFD fd); + + bool isValid() const { return fd_.isValid(); } + const UniqueFD &fd() const { return fd_; } + + UniqueFD release() { return std::move(fd_); } + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(Fence) + + UniqueFD fd_; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 5f42977c034b..8c2cae00d877 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -6,6 +6,7 @@ libcamera_public_headers = files([ 'camera.h', 'camera_manager.h', 'controls.h', + 'fence.h', 'framebuffer.h', 'framebuffer_allocator.h', 'geometry.h', diff --git a/src/libcamera/fence.cpp b/src/libcamera/fence.cpp new file mode 100644 index 000000000000..bd737e9848e1 --- /dev/null +++ b/src/libcamera/fence.cpp @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * fence.cpp - Synchronization fence + */ + +#include "libcamera/fence.h" + +namespace libcamera { + +/** + * + * \file libcamera/fence.h + * \brief Synchronization fence + */ + +/** + * \class Fence + * \brief Synchronization primitive to manage resources + * + * The Fence class models a synchronization primitive that can be used by + * applications to explicitly synchronize resource usage, and can be shared by + * multiple processes. + * + * Synchronization fences are most commonly used in association with frame + * buffers. A FrameBuffer can be associated with a Fence so that the library can + * wait for the Fence to be signalled before allowing the camera device to + * actually access the memory area described by the FrameBuffer. + * + * \sa Request::addBuffer() + * + * By using synchronization fences, application can then synchronize between + * frame buffer consumers and producers, as for example a display device and a + * camera, to guarantee that new data transfers only happen once the existing + * frames have been displayed. + * + * A Fence can be realized by different event notification primitives, the most + * common of which is represented by waiting for read events to happen on a + * kernel sync file. This is currently the only mechanism supported by + * libcamera, but others can be implemented by extending or subclassing this + * class and implementing opportune handling in the core library. + * + * kernel sync file + * + * \internal + * + * The Fence class is a thin abstraction around a UniqueFD which simply allows + * to access it as a const reference or to move its ownership to the caller. + * + * The usage of the Fence class allows to abstract the underlying + * synchronization mechanism in use and implement an interface towards other + * library components that will not change when new synchronization primitives + * will be added as fences. + * + * A Fence is constructed with a UniqueFD whose ownership is moved in the Fence. + * A FrameBuffer can be associated with a Fence by passing it to the + * Request::addBuffer() function, which will move the Fence into the FrameBuffer + * itself. Once a Request is queued to the Camera, a preparation phase + * guarantees that before actually applying the Request to the hardware, all the + * valid fences of the frame buffers in a Request are correctly signalled. Once + * a Fence has completed, the library will release the FrameBuffer fence so that + * application won't be allowed to access it. + * + * An optional timeout can be started while waiting for a fence to complete. If + * waiting on a Fence fails for whatever reason, the FrameBuffer's fence is not + * reset and is made available to application for them to handle it, by + * releasing the Fence to correctly close the underlying UniqueFD. + * + * A failure in waiting for a Fence to complete will result in the Request to + * complete in failed state. + * + * \sa Request::prepare() + * \sa PipelineHandler::doQueueRequests() + */ + +/** + * \brief Create a synchronization fence + * \param[in] fd The synchronization fence file descriptor + * + * The file descriptor ownership is moved to the Fence. + */ +Fence::Fence(UniqueFD fd) + : fd_(std::move(fd)) +{ +} + +/** + * \fn Fence::isValid() + * \brief Check if a Fence is valid + * + * A Fence is valid if the file descriptor it wraps is valid. + * + * \return True if the Fence is valid, false otherwise + */ + +/** + * \fn Fence::fd() + * \brief Retrieve a constant reference to the file descriptor + * \return A const reference to the fence file descriptor + */ + +/** + * \fn Fence::release() + * \brief Release the ownership of the file descriptor + * + * Release the ownership of the wrapped file descriptor by returning it to the + * caller. + * + * \return The wrapper UniqueFD + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index b763110e74a6..b4882a2577f5 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', 'formats.cpp', 'framebuffer.cpp', 'framebuffer_allocator.cpp', From patchwork Wed Dec 1 14:29:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14964 X-Patchwork-Delegate: jacopo@jmondi.org 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 5066FBDB13 for ; Wed, 1 Dec 2021 14:28:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8B85F607BD; Wed, 1 Dec 2021 15:28:54 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 570C360740 for ; Wed, 1 Dec 2021 15:28:53 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id AFB77C000D; Wed, 1 Dec 2021 14:28:52 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:29 +0100 Message-Id: <20211201142936.107405-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 04/11] libcamera: framebuffer: Add Fence to FrameBuffer 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 unique pointer to a synchronization Fence. The Fence will be used to signal the availability of the Framebuffer for incoming data transfer. The Fence will be associated to a FrameBuffer at Request::addBuffer() time, and if correctly signalled, reset by the core at Request queue time. If a FrameBuffer completes with errors, due to a Fence wait failure, the Fence will still be owned by the FrameBuffer and it is application responsibility to correctly reset it before reusing the buffer. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- include/libcamera/framebuffer.h | 4 ++ include/libcamera/internal/framebuffer.h | 8 ++++ src/libcamera/framebuffer.cpp | 58 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h index 357bbe189551..39ebbdaebf47 100644 --- a/include/libcamera/framebuffer.h +++ b/include/libcamera/framebuffer.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -18,6 +19,7 @@ namespace libcamera { +class Fence; class Request; struct FrameMetadata { @@ -65,6 +67,8 @@ public: unsigned int cookie() const { return cookie_; } void setCookie(unsigned int cookie) { cookie_ = cookie; } + std::unique_ptr releaseFence(); + void cancel() { metadata_.status = FrameMetadata::FrameCancelled; } private: diff --git a/include/libcamera/internal/framebuffer.h b/include/libcamera/internal/framebuffer.h index 908b478985e7..fc9f4a2fc768 100644 --- a/include/libcamera/internal/framebuffer.h +++ b/include/libcamera/internal/framebuffer.h @@ -7,8 +7,12 @@ #pragma once +#include +#include + #include +#include #include namespace libcamera { @@ -23,7 +27,11 @@ public: void setRequest(Request *request) { request_ = request; } bool isContiguous() const { return isContiguous_; } + Fence *fence() const { return fence_.get(); } + void setFence(std::unique_ptr fence) { fence_ = std::move(fence); } + private: + std::unique_ptr fence_; Request *request_; bool isContiguous_; }; diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp index 701212f3ae21..a2cb0486e14d 100644 --- a/src/libcamera/framebuffer.cpp +++ b/src/libcamera/framebuffer.cpp @@ -140,6 +140,45 @@ FrameBuffer::Private::Private() * \return True if the planes are stored contiguously in memory, false otherwise */ +/** + * \fn FrameBuffer::Private::fence() + * \brief Retrieve a const pointer to the Fence + * + * This function does only return a reference to the the fence and does not + * change its ownership. The fence is stored in the FrameBuffer and can only be + * reset with FrameBuffer::releaseFence() in case the buffer has completed with + * error due to a Fence wait failure. + * + * If buffer with a Fence completes with errors due to a failure in handling + * the fence, applications are responsible for releasing the Fence before + * calling Request::addBuffer() again. + * + * \sa Request::addBuffer() + * + * \return A const pointer to the Fence if any, nullptr otherwise + */ + +/** + * \fn FrameBuffer::Private::setFence() + * \brief Move a \a fence in this buffer + * \param[in] fence The synchronization fence + * + * This function associates a Fence with this Framebuffer. The intended caller + * is the Request::addBuffer() function. + * + * Once a FrameBuffer is associated with a Fence, the FrameBuffer will only be + * made available to the hardware device once the synchronization Fence has been + * correctly signalled. + * + * \sa Request::prepare() + * + * If the FrameBuffer completes successfully the core releases the Fence and the + * Buffer can be reused immediately. If handling of the Fence fails during the + * request preparation, the Fence is not reset and is left in the FrameBuffer. + * It is applications responsibility to correctly release the fence and handle + * it opportunely before using the buffer again. + */ + /** * \class FrameBuffer * \brief Frame buffer data and its associated dynamic metadata @@ -329,6 +368,25 @@ Request *FrameBuffer::request() const * libcamera core never modifies the buffer cookie. */ +/** + * \brief Extract the Fence associated with this Framebuffer + * + * This function moves the buffer's fence ownership to the caller. + * After the fence has been released, calling this function always return + * nullptr. + * + * If buffer with a Fence completes with errors due to a failure in handling + * the fence, applications are responsible for releasing the Fence before + * calling Request::addBuffer() again. + * + * \return A unique pointer to the Fence if set, or nullptr if the fence has + * been released already + */ +std::unique_ptr FrameBuffer::releaseFence() +{ + return std::move(_d()->fence_); +} + /** * \fn FrameBuffer::cancel() * \brief Marks the buffer as cancelled From patchwork Wed Dec 1 14:29:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14965 X-Patchwork-Delegate: jacopo@jmondi.org 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 EFBAAC3250 for ; Wed, 1 Dec 2021 14:28:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B361F607C7; Wed, 1 Dec 2021 15:28:56 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4B89E6073F for ; Wed, 1 Dec 2021 15:28:54 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 8D972C0002; Wed, 1 Dec 2021 14:28:53 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:30 +0100 Message-Id: <20211201142936.107405-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 05/11] 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 optional synchronization fence to Request::addBuffer() to allow associating a Fence with a FrameBuffer part of a Request. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- include/libcamera/request.h | 4 +++- src/libcamera/request.cpp | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 8c78970d88ab..1eb537e9b09b 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -17,6 +17,7 @@ #include #include +#include namespace libcamera { @@ -51,7 +52,8 @@ public: ControlList &controls() { return *controls_; } 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 = nullptr); FrameBuffer *findBuffer(const Stream *stream) const; uint32_t sequence() const; diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 692202473360..5ddb4b0592b3 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -294,6 +295,7 @@ void Request::reuse(ReuseFlag flags) * \brief Add a FrameBuffer with its associated Stream to the Request * \param[in] stream The stream the buffer belongs to * \param[in] buffer The FrameBuffer to add to the request + * \param[in] fence The optional synchronization Fence * * A reference to the buffer is stored in the request. The caller is responsible * for ensuring that the buffer will remain valid until the request complete @@ -302,11 +304,24 @@ void Request::reuse(ReuseFlag flags) * A request can only contain one buffer per stream. If a buffer has already * been added to the request for the same stream, this function returns -EEXIST. * + * A synchronization Fence can be optionally associated with the \a buffer. + * + * When a valid fence is provided to this function, \a fence is moved to \a + * buffer and this Request will only be queued to the device once the + * synchronization fences of all its buffers have been correctly signalled. + * + * If the \a fence associated with \a buffer fails, the application is + * responsible for resetting it before associating this buffer with a new + * Request by calling this function again. + * + * \sa FrameBuffer::resetFence() + * * \return 0 on success or a negative error code otherwise * \retval -EEXIST The request already contains a buffer for the stream * \retval -EINVAL The buffer does not reference a valid Stream */ -int Request::addBuffer(const Stream *stream, FrameBuffer *buffer) +int Request::addBuffer(const Stream *stream, FrameBuffer *buffer, + std::unique_ptr fence) { if (!stream) { LOG(Request, Error) << "Invalid stream reference"; @@ -323,6 +338,15 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer) _d()->pending_.insert(buffer); bufferMap_[stream] = buffer; + /* + * Make sure the fence has been extracted from the buffer + * to avoid waiting on a stale fence. + */ + ASSERT(!buffer->_d()->fence()); + + if (fence && fence->isValid()) + buffer->_d()->setFence(std::move(fence)); + return 0; } From patchwork Wed Dec 1 14:29:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14966 X-Patchwork-Delegate: jacopo@jmondi.org 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 3C646C3251 for ; Wed, 1 Dec 2021 14:28:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E2B53607CE; Wed, 1 Dec 2021 15:28:56 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7393760738 for ; Wed, 1 Dec 2021 15:28:55 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 7F4E3C0002; Wed, 1 Dec 2021 14:28:54 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:31 +0100 Message-Id: <20211201142936.107405-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 06/11] 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 | 340 +++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 341 insertions(+) create mode 100644 test/fence.cpp diff --git a/test/fence.cpp b/test/fence.cpp new file mode 100644 index 000000000000..ee1c8343e01c --- /dev/null +++ b/test/fence.cpp @@ -0,0 +1,340 @@ +/* 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 + +#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() override; + int run() override; + void cleanup() override; + +private: + int validateExpiredRequest(Request *request); + void requestComplete(Request *request); + void signalFence(); + + std::unique_ptr fence_; + EventDispatcher *dispatcher_; + UniqueFD 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 efd2_; + int efd_; +}; + +FenceTest::FenceTest() + : CameraTest("platform/vimc.0 Sensor B") +{ +} + +int FenceTest::init() +{ + dispatcher_ = Thread::current()->eventDispatcher(); + + eventFd_ = UniqueFD(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + if (!eventFd_.isValid()) { + 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. + */ + efd_ = eventFd_.get(); + + 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(); + if (nbuffers_ < 2) { + cerr << "Not enough buffers available" << endl; + return TestFail; + } + + signalledRequestId_ = nbuffers_ - 2; + expiredRequestId_ = nbuffers_ - 1; + + return TestPass; +} + +int FenceTest::validateExpiredRequest(Request *request) +{ + FrameBuffer *buffer = request->buffers().begin()->second; + + std::unique_ptr fence = buffer->releaseFence(); + 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; + } + + UniqueFD fd = fence->release(); + if (fd.get() != efd_) { + cerr << "The expired fence file descriptor should not change" << endl; + return TestFail; + } + + expectFenceFailure_ = false; + + return 0; +} + +/* Callback to signal a fence waiting on the eventfd file descriptor. */ +void FenceTest::signalFence() +{ + uint64_t value = 1; + write(efd2_, &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. */ + std::unique_ptr bufferFence = buffer->releaseFence(); + if (bufferFence) { + 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. + */ + UniqueFD eventFd2(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + if (!eventFd2.isValid()) { + cerr << "Unable to create eventfd" << endl; + expectedCompletionResult_ = false; + return; + } + efd2_ = eventFd2.get(); + + std::unique_ptr fence = + std::make_unique(std::move(eventFd2)); + 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. */ + fence_ = std::make_unique(std::move(eventFd_)); + if (!fence_->isValid()) { + cerr << "Fence should be valid" << endl; + return TestFail; + } + + ret = request->addBuffer(stream_, buffer.get(), std::move(fence_)); + } else { + /* All other requests will have no Fence. */ + 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 daaa3862cdd6..2c9487e203e2 100644 --- a/test/meson.build +++ b/test/meson.build @@ -39,6 +39,7 @@ internal_tests = [ ['event', 'event.cpp'], ['event-dispatcher', 'event-dispatcher.cpp'], ['event-thread', 'event-thread.cpp'], + ['fence', 'fence.cpp'], ['file', 'file.cpp'], ['flags', 'flags.cpp'], ['hotplug-cameras', 'hotplug-cameras.cpp'], From patchwork Wed Dec 1 14:29:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14967 X-Patchwork-Delegate: jacopo@jmondi.org 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 31497BDB13 for ; Wed, 1 Dec 2021 14:28:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E44BF60746; Wed, 1 Dec 2021 15:28:58 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 551A06073F for ; Wed, 1 Dec 2021 15:28:56 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id AFAC5C0002; Wed, 1 Dec 2021 14:28:55 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:32 +0100 Message-Id: <20211201142936.107405-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 07/11] 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 Reviewed-by: Laurent Pinchart +#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::queue waitingRequests_; + const char *name_; friend class PipelineHandlerFactory; diff --git a/include/libcamera/internal/tracepoints/request.tp b/include/libcamera/internal/tracepoints/request.tp index f039ffd4f88d..f1e54497aa03 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..2374c2891c64 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(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 + * + * Iterate the list of waiting requests and queue them to the device one + * by one. + */ +void PipelineHandler::doQueueRequests() +{ + while (!waitingRequests_.empty()) { + Request *request = waitingRequests_.front(); + waitingRequests_.pop(); + + doQueueRequest(request); + } +} + /** * \fn PipelineHandler::queueRequestDevice() * \brief Queue a request to the device From patchwork Wed Dec 1 14:29:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14968 X-Patchwork-Delegate: jacopo@jmondi.org 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 82460C3250 for ; Wed, 1 Dec 2021 14:28:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1E33460744; Wed, 1 Dec 2021 15:28:59 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 57BA060732 for ; Wed, 1 Dec 2021 15:28:57 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 8CABAC0002; Wed, 1 Dec 2021 14:28:56 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:33 +0100 Message-Id: <20211201142936.107405-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 08/11] 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: Laurent Pinchart --- 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 | 30 +++++++++++++++++-- 8 files changed, 42 insertions(+), 15 deletions(-) diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index 6aa3378547ba..ec986a518b5c 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 fa2848533b29..cb6ba1c2db18 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -303,7 +303,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; @@ -924,7 +924,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 36ef6a02ae90..8cca8a15a3c3 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 2374c2891c64..863d206a7ddd 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,33 @@ 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. */ + while (!waitingRequests_.empty()) { + Request *request = waitingRequests_.front(); + + request->_d()->cancel(); + completeRequest(request); + waitingRequests_.pop(); + } + + /* 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 Wed Dec 1 14:29:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14969 X-Patchwork-Delegate: jacopo@jmondi.org 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 EC87EC3251 for ; Wed, 1 Dec 2021 14:28:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8A7ED607C5; Wed, 1 Dec 2021 15:28:59 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5FDC260743 for ; Wed, 1 Dec 2021 15:28:58 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 874D5C0002; Wed, 1 Dec 2021 14:28:57 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:34 +0100 Message-Id: <20211201142936.107405-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 09/11] 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 emits the Request::prepared signal when all fences have been signalled or an optional timeout has expired. The optional timeout allows to interrupt blocked waits and notify the Request as failed so that it can be cancelled. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- include/libcamera/internal/request.h | 15 +++ src/libcamera/request.cpp | 132 ++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 1 deletion(-) diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h index 1340ffa2a683..740ab21ac7e0 100644 --- a/include/libcamera/internal/request.h +++ b/include/libcamera/internal/request.h @@ -7,10 +7,17 @@ #ifndef __LIBCAMERA_INTERNAL_REQUEST_H__ #define __LIBCAMERA_INTERNAL_REQUEST_H__ +#include +#include #include +#include +#include + #include +using namespace std::chrono_literals; + namespace libcamera { class Camera; @@ -32,16 +39,24 @@ public: void cancel(); void reuse(); + void prepare(std::chrono::milliseconds timeout = 0ms); + Signal<> prepared; + private: friend class PipelineHandler; void doCancelRequest(); + void notifierActivated(FrameBuffer *buffer); + void timeout(); Camera *camera_; bool cancelled_; uint32_t sequence_ = 0; + bool prepared_ = false; std::unordered_set pending_; + std::map> notifiers_; + std::unique_ptr timer_; }; } /* namespace libcamera */ diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 5ddb4b0592b3..59fb02b4a0b7 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -135,6 +135,8 @@ void Request::Private::doCancelRequest() cancelled_ = true; pending_.clear(); + notifiers_.clear(); + timer_.reset(); } /** @@ -163,6 +165,134 @@ void Request::Private::reuse() sequence_ = 0; cancelled_ = false; 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 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 cancelled. + * + * The function immediately emits the prepared signal if all the prepare + * operations have been completed synchronously. If instead the prepare + * operations require to wait the completion of asynchronous events, such as + * fences notifications or timer expiration, the prepared signal is emitted upon + * the asynchronous event completion. + * + * As we currently only handle fences, the function emits the prepared signal + * immediately if there are no fences to wait on. Otherwise the prepared signal + * is emitted when all fences have been signalled or the optional timeout has + * expired. + * + * If not all the fences have been correctly signalled or the optional timeout + * has expired the Request will be cancelled and the Request::prepared signal + * emitted. + * + * The intended user of this function is the PipelineHandler base class, which + * 'prepares' a Request before queuing it to the hardware device. + */ +void Request::Private::prepare(std::chrono::milliseconds timeout) +{ + prepared_ = false; + + /* Create and connect one notifier for each synchronization fence. */ + for (FrameBuffer *buffer : pending_) { + const Fence *fence = buffer->_d()->fence(); + + if (!fence) + continue; + + notifiers_[buffer] = std::make_unique(fence->fd().get(), + EventNotifier::Read); + } + + if (notifiers_.empty()) { + prepared_ = true; + prepared.emit(); + return; + } + + for (auto &it : notifiers_) { + FrameBuffer *buffer = it.first; + std::unique_ptr ¬ifier = it.second; + + notifier->activated.connect(this, [this, buffer] { + notifierActivated(buffer); + }); + } + + /* + * In case a timeout is specified, create a timer and set it up. + * + * The timer must be created here instead of in the Request constructor, + * in order to be bound to the pipeline handler thread. + */ + if (timeout != 0ms) { + timer_ = std::make_unique(); + timer_->timeout.connect(this, &Request::Private::timeout); + timer_->start(timeout); + } +} + +/** + * \var Request::Private::prepared + * \brief Request preparation completed Signal + * + * The signal is emitted once the request preparation has completed (prepared_ + * == true) and is ready for being queued. The Request might complete with + * errors in which case it is cancelled. + * + * The intended slot for this signal is the PipelineHandler::doQueueRequests() + * function which queues Request after they have been prepared or cancel them + * if they have failed preparing. + */ + +void Request::Private::notifierActivated(FrameBuffer *buffer) +{ + /* Close the fence if successfully signalled. */ + ASSERT(buffer); + buffer->releaseFence(); + + /* Remove the entry from the map and check if other fences are pending. */ + auto it = notifiers_.find(buffer); + ASSERT(it != notifiers_.end()); + notifiers_.erase(it); + + Request *request = _o(); + LOG(Request, Debug) + << "Request " << request->cookie() << " buffer " << buffer + << " fence signalled"; + + if (!notifiers_.empty()) + return; + + /* All fences completed, delete the timer and move to state Ready. */ + timer_.reset(); + prepared_ = true; + prepared.emit(); +} + +void Request::Private::timeout() +{ + /* A timeout can only happen if there are fences not yet signalled. */ + ASSERT(!notifiers_.empty()); + notifiers_.clear(); + + Request *request = _o(); + LOG(Request, Debug) << "Request prepare timeout: " << request->cookie(); + + cancel(); + + prepared_ = true; + prepared.emit(); } /** @@ -314,7 +444,7 @@ void Request::reuse(ReuseFlag flags) * responsible for resetting it before associating this buffer with a new * Request by calling this function again. * - * \sa FrameBuffer::resetFence() + * \sa FrameBuffer::releaseFence() * * \return 0 on success or a negative error code otherwise * \retval -EEXIST The request already contains a buffer for the stream From patchwork Wed Dec 1 14:29:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14970 X-Patchwork-Delegate: jacopo@jmondi.org 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 5BD94BDB13 for ; Wed, 1 Dec 2021 14:29:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1E97660741; Wed, 1 Dec 2021 15:29:01 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DA6B360732 for ; Wed, 1 Dec 2021 15:28:59 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 9A1B9C0008; Wed, 1 Dec 2021 14:28:58 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:35 +0100 Message-Id: <20211201142936.107405-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 10/11] 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 if it has completed its preparation phase and queue it to the device. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline_handler.cpp | 37 +++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 863d206a7ddd..5b5cb9c18dad 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 @@ -18,6 +19,7 @@ #include "libcamera/internal/camera.h" #include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/framebuffer.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/request.h" #include "libcamera/internal/tracepoints.h" @@ -36,6 +38,8 @@ * the REGISTER_PIPELINE_HANDLER() macro. */ +using namespace std::chrono_literals; + namespace libcamera { LOG_DEFINE_CATEGORY(Pipeline) @@ -323,10 +327,16 @@ bool PipelineHandler::hasPendingRequests(const Camera *camera) const * \param[in] request The request to queue * * This function queues a capture request to the pipeline handler for - * processing. The request is first added to the internal list of queued - * requests, and then passed to the pipeline handler with a call to - * queueRequestDevice(). If the pipeline handler fails in queuing the request - * to the hardware the request is cancelled. + * processing. The request is first added to the internal list of waiting + * requests which have to be prepared to make sure they are ready for being + * queued to the pipeline handler. + * + * The queue of waiting requests is iterated and all prepared requests are + * passed to the pipeline handler in the same order they have been queued by + * calling this function. + * + * If a Request fails during the preparation phase or if the pipeline handler + * fails in queuing the request to the hardware the request is cancelled. * * Keeping track of queued requests ensures automatic completion of all requests * when the pipeline handler is stopped with stop(). Request completion shall be @@ -339,7 +349,11 @@ void PipelineHandler::queueRequest(Request *request) LIBCAMERA_TRACEPOINT(request_queue, request); waitingRequests_.push(request); - doQueueRequests(); + + request->_d()->prepared.connect(this, [this]() { + doQueueRequests(); + }); + request->_d()->prepare(300ms); } /** @@ -355,6 +369,11 @@ void PipelineHandler::doQueueRequest(Request *request) request->_d()->sequence_ = data->requestSequence_++; + if (request->_d()->cancelled_) { + completeRequest(request); + return; + } + int ret = queueRequestDevice(camera, request); if (ret) { request->_d()->cancel(); @@ -363,18 +382,20 @@ void PipelineHandler::doQueueRequest(Request *request) } /** - * \brief Queue requests to the device + * \brief Queue prepared requests to the device * * Iterate the list of waiting requests and queue them to the device one - * by one. + * by one if they have been prepared. */ void PipelineHandler::doQueueRequests() { while (!waitingRequests_.empty()) { Request *request = waitingRequests_.front(); - waitingRequests_.pop(); + if (!request->_d()->prepared_) + break; doQueueRequest(request); + waitingRequests_.pop(); } } From patchwork Wed Dec 1 14:29:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14971 X-Patchwork-Delegate: jacopo@jmondi.org 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 82F12C3250 for ; Wed, 1 Dec 2021 14:29:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4B30B607CE; Wed, 1 Dec 2021 15:29:02 +0100 (CET) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3ADF9607BD for ; Wed, 1 Dec 2021 15:29:01 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 1A058C0007; Wed, 1 Dec 2021 14:28:59 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 15:29:36 +0100 Message-Id: <20211201142936.107405-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211201142936.107405-1-jacopo@jmondi.org> References: <20211201142936.107405-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 11/11] 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. While at it make CameraRequest::StreamBuffer::fence a UniqueFD to ease the management of the fences file descriptor values. Signed-off-by: Jacopo Mondi --- src/android/camera_device.cpp | 39 ++++------ src/android/camera_device.h | 3 - src/android/camera_request.cpp | 8 +- src/android/camera_request.h | 6 +- src/android/camera_stream.cpp | 10 +-- src/android/camera_worker.cpp | 129 --------------------------------- src/android/camera_worker.h | 70 ------------------ src/android/meson.build | 1 - 8 files changed, 29 insertions(+), 237 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 1938b10509fa..3a2969c70a45 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -15,10 +15,12 @@ #include #include +#include #include #include #include +#include #include #include @@ -406,7 +408,6 @@ void CameraDevice::flush() state_ = State::Flushing; } - worker_.stop(); camera_->stop(); MutexLocker stateLock(stateMutex_); @@ -419,7 +420,6 @@ void CameraDevice::stop() if (state_ == State::Stopped) return; - worker_.stop(); camera_->stop(); descriptors_ = {}; @@ -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: /* @@ -943,7 +939,6 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques 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, std::make_unique(std::move(buffer.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 +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. + * already been waited on by the library. * * 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) { + /* If handling of the fence has failed restore buffer.fence. */ + std::unique_ptr fence = buffer.frameBuffer->releaseFence(); + if (fence) + buffer.fence = fence->release(); + } buffer.status = Camera3RequestDescriptor::Status::Success; } @@ -1172,7 +1165,7 @@ void CameraDevice::sendCaptureResults() std::vector resultBuffers; resultBuffers.reserve(descriptor->buffers_.size()); - for (const auto &buffer : descriptor->buffers_) { + for (auto &buffer : descriptor->buffers_) { camera3_buffer_status status = CAMERA3_BUFFER_STATUS_ERROR; if (buffer.status == Camera3RequestDescriptor::Status::Success) @@ -1186,7 +1179,7 @@ void CameraDevice::sendCaptureResults() */ resultBuffers.push_back({ buffer.stream->camera3Stream(), buffer.camera3Buffer, status, - -1, buffer.fence }); + -1, buffer.fence.release() }); } captureResult.num_output_buffers = resultBuffers.size(); diff --git a/src/android/camera_device.h b/src/android/camera_device.h index 51fe7da2cb47..494d79d2a3ea 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..c46689a52d6d 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; @@ -57,8 +56,11 @@ Camera3RequestDescriptor::StreamBuffer::StreamBuffer( CameraStream *cameraStream, const camera3_stream_buffer_t &buffer, Camera3RequestDescriptor *requestDescriptor) : stream(cameraStream), camera3Buffer(buffer.buffer), - fence(buffer.acquire_fence), request(requestDescriptor) + request(requestDescriptor) { + /* Do not reset buffer.acquire_fence by moving it to fence. */ + int fenceFd = buffer.acquire_fence; + fence = UniqueFD(std::move(fenceFd)); } Camera3RequestDescriptor::StreamBuffer::~StreamBuffer() = default; diff --git a/src/android/camera_request.h b/src/android/camera_request.h index f3cb6d643961..4372ad775c19 100644 --- a/src/android/camera_request.h +++ b/src/android/camera_request.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -20,7 +21,6 @@ #include #include "camera_metadata.h" -#include "camera_worker.h" class CameraBuffer; class CameraStream; @@ -45,7 +45,7 @@ public: CameraStream *stream; buffer_handle_t *camera3Buffer; std::unique_ptr frameBuffer; - int fence; + libcamera::UniqueFD fence; Status status = Status::Success; libcamera::FrameBuffer *internalBuffer = nullptr; const libcamera::FrameBuffer *srcBuffer = nullptr; @@ -71,7 +71,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_stream.cpp b/src/android/camera_stream.cpp index 9023c13c40f0..08252341e9cf 100644 --- a/src/android/camera_stream.cpp +++ b/src/android/camera_stream.cpp @@ -169,16 +169,16 @@ int CameraStream::process(Camera3RequestDescriptor::StreamBuffer *streamBuffer) ASSERT(type_ != Type::Direct); /* Handle waiting on fences on the destination buffer. */ - if (streamBuffer->fence != -1) { - int ret = waitFence(streamBuffer->fence); + if (streamBuffer->fence.isValid()) { + int ret = waitFence(streamBuffer->fence.get()); if (ret < 0) { LOG(HAL, Error) << "Failed waiting for fence: " - << streamBuffer->fence << ": " << strerror(-ret); + << streamBuffer->fence.get() << ": " + << strerror(-ret); return ret; } - ::close(streamBuffer->fence); - streamBuffer->fence = -1; + streamBuffer->fence.reset(); } const StreamConfiguration &output = configuration(); 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 26ecc2732046..000000000000 --- a/src/android/camera_worker.h +++ /dev/null @@ -1,70 +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 - */ - -#pragma once - -#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_; -}; 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',