[{"id":38291,"web_url":"https://patchwork.libcamera.org/comment/38291/","msgid":"<177194931825.1513537.2788085172972726863@t16>","date":"2026-02-24T16:08:38","subject":"Re: [PATCH v6 6/8] libcamera: camera: Hook into the LayerManager","submitter":{"id":215,"url":"https://patchwork.libcamera.org/api/people/215/","name":"Isaac Scott","email":"isaac.scott@ideasonboard.com"},"content":"Hi Paul,\n\nThank you for the patch!\n\nQuoting Paul Elder (2026-01-29 08:28:12)\n> Add hooks into the CameraManager to call into the LayerManager on all\n> relevant public-facing interface of Camera.\n> \n> The entry point for each function into the LayerManager has been\n> chosen based on the capabilities that we want to expose to Layer\n> implementations.\n> \n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> \n> ---\n> Changes in v6:\n> - merge the metadata returned by the layers in requestCompleted into the\n>   request's metadata to forward it to the application\n> \n> No change in v5\n> \n> No change in v4\n> \n> Changes in v3:\n> - send the copy of controls returned by LayerManager::start()\n> - each Camera now has a LayerController that it can call into,\n>   shortening each hook call significantly\n> \n> Changes in v2:\n> - move the LayerManager out of Camera into the CameraManager\n> - remove hooks for generateConfiguration() and streams()\n> - Camera now passes itself into the layer hooks, as it is required for\n>   the LayerManager to fetch the closure based on the camera to pass to\n>   each layer\n> ---\n>  include/libcamera/internal/camera.h |  4 ++++\n>  src/libcamera/camera.cpp            | 32 ++++++++++++++++++++++++++---\n>  2 files changed, 33 insertions(+), 3 deletions(-)\n> \n> diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h\n> index d28cd921a0f9..fdabc460a357 100644\n> --- a/include/libcamera/internal/camera.h\n> +++ b/include/libcamera/internal/camera.h\n> @@ -19,6 +19,8 @@\n>  \n>  #include <libcamera/camera.h>\n>  \n> +#include \"libcamera/internal/layer_manager.h\"\n> +\n>  namespace libcamera {\n>  \n>  class CameraControlValidator;\n> @@ -78,6 +80,8 @@ private:\n>         std::atomic<State> state_;\n>  \n>         std::unique_ptr<CameraControlValidator> validator_;\n> +\n> +       std::unique_ptr<LayerController> layers_;\n>  };\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp\n> index a2132e61a7bd..4ed9a21726d9 100644\n> --- a/src/libcamera/camera.cpp\n> +++ b/src/libcamera/camera.cpp\n> @@ -18,6 +18,7 @@\n>  #include <libcamera/base/log.h>\n>  #include <libcamera/base/thread.h>\n>  \n> +#include <libcamera/camera_manager.h>\n>  #include <libcamera/color_space.h>\n>  #include <libcamera/control_ids.h>\n>  #include <libcamera/framebuffer_allocator.h>\n> @@ -27,6 +28,8 @@\n>  \n>  #include \"libcamera/internal/camera.h\"\n>  #include \"libcamera/internal/camera_controls.h\"\n> +#include \"libcamera/internal/camera_manager.h\"\n> +#include \"libcamera/internal/layer_manager.h\"\n>  #include \"libcamera/internal/pipeline_handler.h\"\n>  #include \"libcamera/internal/request.h\"\n>  \n> @@ -774,18 +777,23 @@ void Camera::Private::setState(State state)\n>  void Camera::Private::emitBufferCompleted(Request *request, FrameBuffer *buffer)\n>  {\n>         Camera *camera = _o<Camera>();\n> +       layers_->bufferCompleted(request, buffer);\n>         camera->bufferCompleted.emit(request, buffer);\n>  }\n>  \n>  void Camera::Private::emitRequestCompleted(Request *request)\n>  {\n>         Camera *camera = _o<Camera>();\n> +       ControlList metadata = layers_->requestCompleted(request);\n> +       request->_d()->metadata().merge(metadata,\n> +                                       ControlList::MergePolicy::OverwriteExisting);\n>         camera->requestCompleted.emit(request);\n>  }\n>  \n>  void Camera::Private::emitDisconnected()\n>  {\n>         Camera *camera = _o<Camera>();\n> +       layers_->disconnected();\n>         camera->disconnected.emit();\n>  }\n>  \n> @@ -976,6 +984,10 @@ Camera::Camera(std::unique_ptr<Private> d, const std::string &id,\n>         _d()->id_ = id;\n>         _d()->streams_ = streams;\n>         _d()->validator_ = std::make_unique<CameraControlValidator>(this);\n> +       _d()->layers_ =\n> +               _d()->pipe()->cameraManager()->_d()->layerManager()->createController(this,\n> +                                                                                     _d()->properties_,\n> +                                                                                     _d()->controlInfo_);\n\nAh! I was about to ask what happens if there are no layers? But it seems\nI just needed to look closely-er.\n\nLooks good to me!\n\nReviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>\n\nBest wishes,\nIsaac\n\n>  }\n>  \n>  Camera::~Camera()\n> @@ -1065,6 +1077,8 @@ int Camera::acquire()\n>                 return -EBUSY;\n>         }\n>  \n> +       d->layers_->acquire();\n> +\n>         d->setState(Private::CameraAcquired);\n>  \n>         return 0;\n> @@ -1097,6 +1111,8 @@ int Camera::release()\n>                 d->pipe_->invokeMethod(&PipelineHandler::release,\n>                                        ConnectionTypeBlocking, this);\n>  \n> +       d->layers_->release();\n> +\n>         d->setState(Private::CameraAvailable);\n>  \n>         return 0;\n> @@ -1114,7 +1130,7 @@ int Camera::release()\n>   */\n>  const ControlInfoMap &Camera::controls() const\n>  {\n> -       return _d()->controlInfo_;\n> +       return _d()->layers_->controls();\n>  }\n>  \n>  /**\n> @@ -1127,7 +1143,7 @@ const ControlInfoMap &Camera::controls() const\n>   */\n>  const ControlList &Camera::properties() const\n>  {\n> -       return _d()->properties_;\n> +       return _d()->layers_->properties();\n>  }\n>  \n>  /**\n> @@ -1276,6 +1292,8 @@ int Camera::configure(CameraConfiguration *config)\n>                 d->activeStreams_.insert(stream);\n>         }\n>  \n> +       d->layers_->configure(config, d->controlInfo_);\n> +\n>         d->setState(Private::CameraConfigured);\n>  \n>         return 0;\n> @@ -1316,6 +1334,8 @@ std::unique_ptr<Request> Camera::createRequest(uint64_t cookie)\n>         /* Associate the request with the pipeline handler. */\n>         d->pipe_->registerRequest(request.get());\n>  \n> +       d->layers_->createRequest(cookie, request.get());\n> +\n>         return request;\n>  }\n>  \n> @@ -1417,6 +1437,8 @@ int Camera::queueRequest(Request *request)\n>         /* Pre-process AeEnable. */\n>         patchControlList(request->controls());\n>  \n> +       d->layers_->queueRequest(request);\n> +\n>         d->pipe_->invokeMethod(&PipelineHandler::queueRequest,\n>                                ConnectionTypeQueued, request);\n>  \n> @@ -1453,8 +1475,10 @@ int Camera::start(const ControlList *controls)\n>  \n>         ASSERT(d->requestSequence_ == 0);\n>  \n> +       ControlList *newControls = d->layers_->start(controls);\n> +\n>         if (controls) {\n> -               ControlList copy(*controls);\n> +               ControlList copy(*newControls);\n>                 patchControlList(copy);\n>                 ret = d->pipe_->invokeMethod(&PipelineHandler::start,\n>                                              ConnectionTypeBlocking, this, &copy);\n> @@ -1505,6 +1529,8 @@ int Camera::stop()\n>  \n>         d->setState(Private::CameraStopping);\n>  \n> +       d->layers_->stop();\n> +\n>         d->pipe_->invokeMethod(&PipelineHandler::stop, ConnectionTypeBlocking,\n>                                this);\n>  \n> -- \n> 2.47.2\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 80FA9BE175\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 24 Feb 2026 16:08:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C466B622A1;\n\tTue, 24 Feb 2026 17:08:42 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9BC3562080\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 24 Feb 2026 17:08:41 +0100 (CET)","from thinkpad.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 96F5AAB4;\n\tTue, 24 Feb 2026 17:07:44 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"dNz5hDcZ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1771949264;\n\tbh=M1RxY+0jvn3mgVj+gNGtHstkqd4Dcdo84EOJU0up5/k=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=dNz5hDcZE0Uu64mJ8YJHGkvsZREE8Ia2/9X9jhIy4RdzksnPemL4XJsCr6HGh6S3m\n\tdHXpkqHNGUKzcsOVfz+kokL1YVrDhf3LKIwLp+vZCIwVIaHe6G4hFZ7sIROpEpydVa\n\tSypu7juiGiK7o56Ql3ermMHb0A1epLb6FO+TmWXY=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20260129082814.1777779-7-paul.elder@ideasonboard.com>","References":"<20260129082814.1777779-1-paul.elder@ideasonboard.com>\n\t<20260129082814.1777779-7-paul.elder@ideasonboard.com>","Subject":"Re: [PATCH v6 6/8] libcamera: camera: Hook into the LayerManager","From":"Isaac Scott <isaac.scott@ideasonboard.com>","Cc":"Paul Elder <paul.elder@ideasonboard.com>","To":"Paul Elder <paul.elder@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Tue, 24 Feb 2026 16:08:38 +0000","Message-ID":"<177194931825.1513537.2788085172972726863@t16>","User-Agent":"alot/0.10","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]