From patchwork Tue Nov 30 23:36:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14915 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 B628CC324F for ; Tue, 30 Nov 2021 23:35:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 255D260718; Wed, 1 Dec 2021 00:35:50 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2DE6A60592 for ; Wed, 1 Dec 2021 00:35:48 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 98E7D1BF203; Tue, 30 Nov 2021 23:35:47 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:24 +0100 Message-Id: <20211130233634.34173-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 | 3 ++- src/libcamera/base/timer.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcamera/base/event_dispatcher_poll.cpp b/src/libcamera/base/event_dispatcher_poll.cpp index 8ee22d5adcc4..20cc6e617189 100644 --- a/src/libcamera/base/event_dispatcher_poll.cpp +++ b/src/libcamera/base/event_dispatcher_poll.cpp @@ -214,7 +214,8 @@ int EventDispatcherPoll::poll(std::vector *pollfds) timeout = { 0, 0 }; LOG(Event, Debug) - << "timeout " << timeout.tv_sec << "." + << "timeout " << nextTimer << " " + << timeout.tv_sec << "." << std::setfill('0') << std::setw(9) << timeout.tv_nsec; } 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 Tue Nov 30 23:36:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14916 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 990D7BDB13 for ; Tue, 30 Nov 2021 23:35:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5DA8E6072E; Wed, 1 Dec 2021 00:35:52 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DE5AD60592 for ; Wed, 1 Dec 2021 00:35:49 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 5F1C41BF208; Tue, 30 Nov 2021 23:35:48 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:25 +0100 Message-Id: <20211130233634.34173-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 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 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 Tue Nov 30 23:36: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: 14917 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 12B96C324F for ; Tue, 30 Nov 2021 23:35:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8976060732; Wed, 1 Dec 2021 00:35:52 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DF62160710 for ; Wed, 1 Dec 2021 00:35:50 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 1AA821BF207; Tue, 30 Nov 2021 23:35:49 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:26 +0100 Message-Id: <20211130233634.34173-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 --- include/libcamera/fence.h | 31 ++++++++++ include/libcamera/meson.build | 1 + src/libcamera/fence.cpp | 108 ++++++++++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 141 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..95f2dd07f10b --- /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 reset() { 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..2bab8d7de76a --- /dev/null +++ b/src/libcamera/fence.cpp @@ -0,0 +1,108 @@ +/* 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 fence class + * + * The Fence class is a thin abstraction around a UniqueFD which simply allows + * to access it as a const pointer or to move its ownership to the caller. + * + * Synchronization fences are most commonly used in association with frame + * buffers. A FrameBuffer can be associated with a Fence (\sa + * Request::addBuffer()) 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. + * + * By using synchronization fences, application can then synchronize between + * frame buffer consumers and produces, as in example a video output device and + * camera, to gurantee that new data transfers only happen once the existing + * frames have been displayed. + * + * The Fence class only abstracts the underlying mechanism used by libcamera to + * implement synchronization primitives and allow to wait until an event is + * signalled, but does not implement event notification itself which is instead + * implemented by the core library. + * + * \sa Request::prepare() + * + * 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 + * file descriptor. 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. + * + * 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 contructed with a UniqueFD whose ownship 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 gurantees + * 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 reset 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 + * resetting 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. + */ + +/** + * \brief Create a synchronization fence + * \param[in] fd The synchronization fence unique file descriptor + * + * The unique file descriptor ownership is moved to the Fence. + */ +Fence::Fence(UniqueFD fd) + : fd_(std::move(fd)) +{ +} + +/** + * \fn Fence::isValid() + * \brief Retrieve if a Fence is valid + * + * A Fence is valid if the UniqueFD it wraps is valid + * + * \return True if the Fence is valid, false otherwise + */ + +/** + * \fn Fence::fd() + * \brief Retrieve a constant pointer to the UniqueFD + * \return A const pointer to the UniqueFD + */ + +/** + * \fn Fence::reset() + * \brief Reset the Fence by moving the UniqueFD ownership to the caller + * + * Reset the Fence by releasing the wrapped UniqueFD. Ownership of the UniqueFD + * is moved to the caller. + * + * \return The 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 Tue Nov 30 23:36: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: 14918 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 81F77BDB13 for ; Tue, 30 Nov 2021 23:35:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 44C6460718; Wed, 1 Dec 2021 00:35:54 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 22AC760710 for ; Wed, 1 Dec 2021 00:35:52 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 3B5A31BF206; Tue, 30 Nov 2021 23:35:51 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:27 +0100 Message-Id: <20211130233634.34173-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 --- include/libcamera/framebuffer.h | 4 ++ include/libcamera/internal/framebuffer.h | 7 +++ src/libcamera/framebuffer.cpp | 66 ++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h index 357bbe189551..2f2ecbda6cb4 100644 --- a/include/libcamera/framebuffer.h +++ b/include/libcamera/framebuffer.h @@ -18,6 +18,7 @@ namespace libcamera { +class Fence; class Request; struct FrameMetadata { @@ -65,6 +66,9 @@ public: unsigned int cookie() const { return cookie_; } void setCookie(unsigned int cookie) { cookie_ = cookie; } + Fence *fence() const; + std::unique_ptr resetFence(); + void cancel() { metadata_.status = FrameMetadata::FrameCancelled; } private: diff --git a/include/libcamera/internal/framebuffer.h b/include/libcamera/internal/framebuffer.h index 908b478985e7..e2609300d209 100644 --- a/include/libcamera/internal/framebuffer.h +++ b/include/libcamera/internal/framebuffer.h @@ -7,12 +7,16 @@ #pragma once +#include + #include #include namespace libcamera { +class Fence; + class FrameBuffer::Private : public Extensible::Private { LIBCAMERA_DECLARE_PUBLIC(FrameBuffer) @@ -23,7 +27,10 @@ public: void setRequest(Request *request) { request_ = request; } bool isContiguous() const { return isContiguous_; } + void setFence(std::unique_ptr fence); + private: + std::unique_ptr fence_; Request *request_; bool isContiguous_; }; diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp index 701212f3ae21..2e6f07fb0e56 100644 --- a/src/libcamera/framebuffer.cpp +++ b/src/libcamera/framebuffer.cpp @@ -13,6 +13,8 @@ #include #include +#include + /** * \file libcamera/framebuffer.h * \brief Frame buffer handling @@ -129,6 +131,30 @@ FrameBuffer::Private::Private() * handlers, it is called by the pipeline handlers themselves. */ +/** + * \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 resets 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 reset the fence and handle it + * opportunely before using the buffer again. + */ +void FrameBuffer::Private::setFence(std::unique_ptr fence) +{ + fence_ = std::move(fence); +} + /** * \fn FrameBuffer::Private::isContiguous() * \brief Check if the frame buffer stores planes contiguously in memory @@ -329,6 +355,46 @@ Request *FrameBuffer::request() const * libcamera core never modifies the buffer cookie. */ +/** + * \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::resetFence() 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 resetting the Fence before + * calling Request::addBuffer() again. + * + * \sa Request::addBuffer() + * + * \return A const pointer to the Fence if any, nullptr otherwise + */ +Fence *FrameBuffer::fence() const +{ + return _d()->fence_.get(); +} + +/** + * \brief Extract the Fence associated with this Framebuffer + * + * This function moves the buffer's fence ownership to the caller. + * After the fence has been reset, 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 resetting the Fence before + * calling Request::addBuffer() again. + * + * \return A unique pointer to the Fence if set, or nullptr if the fence has + * been reset already + */ +std::unique_ptr FrameBuffer::resetFence() +{ + return std::move(_d()->fence_); +} + /** * \fn FrameBuffer::cancel() * \brief Marks the buffer as cancelled From patchwork Tue Nov 30 23:36: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: 14919 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 0074EC324F for ; Tue, 30 Nov 2021 23:35:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 940D460710; Wed, 1 Dec 2021 00:35:54 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3950160737 for ; Wed, 1 Dec 2021 00:35:53 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 6FA9E1BF206; Tue, 30 Nov 2021 23:35:52 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:28 +0100 Message-Id: <20211130233634.34173-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 --- 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..699ea1db2e16 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->fence()); + + if (fence && fence->isValid()) + buffer->_d()->setFence(std::move(fence)); + return 0; } From patchwork Tue Nov 30 23:36: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: 14920 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 1F52BBDB13 for ; Tue, 30 Nov 2021 23:35:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CEE9260738; Wed, 1 Dec 2021 00:35:55 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 646FD60727 for ; Wed, 1 Dec 2021 00:35:54 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 6D6521BF206; Tue, 30 Nov 2021 23:35:53 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:29 +0100 Message-Id: <20211130233634.34173-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 | 343 +++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 344 insertions(+) create mode 100644 test/fence.cpp diff --git a/test/fence.cpp b/test/fence.cpp new file mode 100644 index 000000000000..ee909a46b3ea --- /dev/null +++ b/test/fence.cpp @@ -0,0 +1,343 @@ +/* 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->resetFence(); + 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 uniqueFd = fence->reset(); + int fd = uniqueFd.release(); + if (fd != efd_) { + cerr << "The expired fence file descriptor should not change" << endl; + return TestFail; + } + + close(fd); + + 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->resetFence(); + 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..99b7e27b4bfb 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'], ['flags', 'flags.cpp'], ['hotplug-cameras', 'hotplug-cameras.cpp'], ['mapped-buffer', 'mapped-buffer.cpp'], From patchwork Tue Nov 30 23:36: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: 14921 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 5CB83C324F for ; Tue, 30 Nov 2021 23:35:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1EE3060732; Wed, 1 Dec 2021 00:35:57 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 67F7660727 for ; Wed, 1 Dec 2021 00:35:55 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id AD6781BF206; Tue, 30 Nov 2021 23:35:54 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:30 +0100 Message-Id: <20211130233634.34173-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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/libcamera/internal/pipeline_handler.h | 6 ++++ .../libcamera/internal/tracepoints/request.tp | 9 ++++++ src/libcamera/pipeline_handler.cpp | 30 +++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index 3de27ae93645..6aa3378547ba 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -8,6 +8,7 @@ #pragma once #include +#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..2aa62e474195 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,25 @@ void PipelineHandler::queueRequest(Request *request) } } +/** + * \brief Queue requests to the device + * + * Iterate the lst of waiting requests and queue them to the hardware one + * by one. + */ +void PipelineHandler::doQueueRequests() +{ + while (true) { + if (waitingRequests_.empty()) + return; + + Request *request = waitingRequests_.front(); + waitingRequests_.pop(); + + doQueueRequest(request); + } +} + /** * \fn PipelineHandler::queueRequestDevice() * \brief Queue a request to the device From patchwork Tue Nov 30 23:36: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: 14922 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 B9E14C3250 for ; Tue, 30 Nov 2021 23:35:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5031160730; Wed, 1 Dec 2021 00:35:57 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5CB9560724 for ; Wed, 1 Dec 2021 00:35:56 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 9AB6A1BF206; Tue, 30 Nov 2021 23:35:55 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:31 +0100 Message-Id: <20211130233634.34173-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 --- 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 2aa62e474195..8f1f20e896b0 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 Tue Nov 30 23:36: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: 14923 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 5A76BBDB13 for ; Tue, 30 Nov 2021 23:35:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 199BE6072B; Wed, 1 Dec 2021 00:35:59 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7817F60718 for ; Wed, 1 Dec 2021 00:35:57 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 951AC1BF206; Tue, 30 Nov 2021 23:35:56 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:32 +0100 Message-Id: <20211130233634.34173-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 --- include/libcamera/internal/request.h | 15 +++ src/libcamera/request.cpp | 131 +++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) 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 699ea1db2e16..3d66ac6d2b03 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,135 @@ 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 emit the Request::prepared signal, but will + * be set in error state by setting the Request::cancelled_ flag to true. + * + * The intended user of this function is the PipelineHandler base class, which + * 'prepares' a Request before queuing it to the hardware device. A Request is + * ready for being queued to the hardware if the Request::prepared_ flag is set + * to true and if Request::cancelled_ is set to false. + */ +void Request::Private::prepare(std::chrono::milliseconds timeout) +{ + prepared_ = false; + + /* Create and connect one notifier for each synchronization fence. */ + for (FrameBuffer *buffer : pending_) { + + if (!buffer->fence()) + continue; + + notifiers_[buffer] = std::make_unique(buffer->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 the cancelled_ flag it is set to true and the Request + * is cancelled by the slot associated with this signal. + * + * 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->resetFence(); + + /* 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(); + + cancelled_ = true; + prepared_ = true; + prepared.emit(); } /** From patchwork Tue Nov 30 23:36: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: 14924 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 B9338C324F for ; Tue, 30 Nov 2021 23:35:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5CF3760725; Wed, 1 Dec 2021 00:35:59 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5F28860718 for ; Wed, 1 Dec 2021 00:35:58 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id A7E101BF206; Tue, 30 Nov 2021 23:35:57 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:33 +0100 Message-Id: <20211130233634.34173-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 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 | 48 ++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 8f1f20e896b0..0a6a2e6ee983 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) @@ -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,11 +349,20 @@ 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); } /** * \brief Queue one requests to the device + * + * If a Request has failed during the preparation phase it is cancelled. + * + * If queuing a Request to the pipeline handler fails, the Request is cancelled + * as well. */ void PipelineHandler::doQueueRequest(Request *request) { @@ -355,6 +374,12 @@ void PipelineHandler::doQueueRequest(Request *request) request->_d()->sequence_ = data->requestSequence_++; + if (request->_d()->cancelled_) { + request->_d()->cancel(); + completeRequest(request); + return; + } + int ret = queueRequestDevice(camera, request); if (ret) { request->_d()->cancel(); @@ -365,19 +390,18 @@ void PipelineHandler::doQueueRequest(Request *request) /** * \brief Queue requests to the device * - * Iterate the lst of waiting requests and queue them to the hardware one - * by one. + * Iterate the queue of waiting requests and queue them in order the hardware if + * they have completed their preparation phase. */ void PipelineHandler::doQueueRequests() { - while (true) { - if (waitingRequests_.empty()) - return; - + while (!waitingRequests_.empty()) { Request *request = waitingRequests_.front(); - waitingRequests_.pop(); + if (!request->_d()->prepared_) + break; doQueueRequest(request); + waitingRequests_.pop(); } } From patchwork Tue Nov 30 23:36: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: 14925 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 7BC28C3250 for ; Tue, 30 Nov 2021 23:36:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0457E6072B; Wed, 1 Dec 2021 00:36:01 +0100 (CET) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DF8326072E for ; Wed, 1 Dec 2021 00:35:59 +0100 (CET) Received: (Authenticated sender: jacopo@jmondi.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 95C2D1BF206; Tue, 30 Nov 2021 23:35:58 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Dec 2021 00:36:34 +0100 Message-Id: <20211130233634.34173-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211130233634.34173-1-jacopo@jmondi.org> References: <20211130233634.34173-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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 | 46 ++++++------ 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, 36 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..b7114c615733 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,24 @@ 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 the fence has been closed, send -1 to the framework. */ + std::unique_ptr fence = buffer.frameBuffer->resetFence(); + if (!fence || !fence->isValid()) + break; + + /* + * If handling of the fence has failed, send to the + * framework the acquire_fence fd as release_fence so + * it can close it. + */ + buffer.fence = std::move(fence->reset()); + } buffer.status = Camera3RequestDescriptor::Status::Success; } @@ -1172,7 +1172,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 +1186,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',