[v6,6/8] libcamera: camera: Hook into the LayerManager
diff mbox series

Message ID 20260129082814.1777779-7-paul.elder@ideasonboard.com
State New
Headers show
Series
  • Add Layers support
Related show

Commit Message

Paul Elder Jan. 29, 2026, 8:28 a.m. UTC
Add hooks into the CameraManager to call into the LayerManager on all
relevant public-facing interface of Camera.

The entry point for each function into the LayerManager has been
chosen based on the capabilities that we want to expose to Layer
implementations.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>

---
Changes in v6:
- merge the metadata returned by the layers in requestCompleted into the
  request's metadata to forward it to the application

No change in v5

No change in v4

Changes in v3:
- send the copy of controls returned by LayerManager::start()
- each Camera now has a LayerController that it can call into,
  shortening each hook call significantly

Changes in v2:
- move the LayerManager out of Camera into the CameraManager
- remove hooks for generateConfiguration() and streams()
- Camera now passes itself into the layer hooks, as it is required for
  the LayerManager to fetch the closure based on the camera to pass to
  each layer
---
 include/libcamera/internal/camera.h |  4 ++++
 src/libcamera/camera.cpp            | 32 ++++++++++++++++++++++++++---
 2 files changed, 33 insertions(+), 3 deletions(-)

Comments

Isaac Scott Feb. 24, 2026, 4:08 p.m. UTC | #1
Hi Paul,

Thank you for the patch!

Quoting Paul Elder (2026-01-29 08:28:12)
> Add hooks into the CameraManager to call into the LayerManager on all
> relevant public-facing interface of Camera.
> 
> The entry point for each function into the LayerManager has been
> chosen based on the capabilities that we want to expose to Layer
> implementations.
> 
> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> 
> ---
> Changes in v6:
> - merge the metadata returned by the layers in requestCompleted into the
>   request's metadata to forward it to the application
> 
> No change in v5
> 
> No change in v4
> 
> Changes in v3:
> - send the copy of controls returned by LayerManager::start()
> - each Camera now has a LayerController that it can call into,
>   shortening each hook call significantly
> 
> Changes in v2:
> - move the LayerManager out of Camera into the CameraManager
> - remove hooks for generateConfiguration() and streams()
> - Camera now passes itself into the layer hooks, as it is required for
>   the LayerManager to fetch the closure based on the camera to pass to
>   each layer
> ---
>  include/libcamera/internal/camera.h |  4 ++++
>  src/libcamera/camera.cpp            | 32 ++++++++++++++++++++++++++---
>  2 files changed, 33 insertions(+), 3 deletions(-)
> 
> diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h
> index d28cd921a0f9..fdabc460a357 100644
> --- a/include/libcamera/internal/camera.h
> +++ b/include/libcamera/internal/camera.h
> @@ -19,6 +19,8 @@
>  
>  #include <libcamera/camera.h>
>  
> +#include "libcamera/internal/layer_manager.h"
> +
>  namespace libcamera {
>  
>  class CameraControlValidator;
> @@ -78,6 +80,8 @@ private:
>         std::atomic<State> state_;
>  
>         std::unique_ptr<CameraControlValidator> validator_;
> +
> +       std::unique_ptr<LayerController> layers_;
>  };
>  
>  } /* namespace libcamera */
> diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
> index a2132e61a7bd..4ed9a21726d9 100644
> --- a/src/libcamera/camera.cpp
> +++ b/src/libcamera/camera.cpp
> @@ -18,6 +18,7 @@
>  #include <libcamera/base/log.h>
>  #include <libcamera/base/thread.h>
>  
> +#include <libcamera/camera_manager.h>
>  #include <libcamera/color_space.h>
>  #include <libcamera/control_ids.h>
>  #include <libcamera/framebuffer_allocator.h>
> @@ -27,6 +28,8 @@
>  
>  #include "libcamera/internal/camera.h"
>  #include "libcamera/internal/camera_controls.h"
> +#include "libcamera/internal/camera_manager.h"
> +#include "libcamera/internal/layer_manager.h"
>  #include "libcamera/internal/pipeline_handler.h"
>  #include "libcamera/internal/request.h"
>  
> @@ -774,18 +777,23 @@ void Camera::Private::setState(State state)
>  void Camera::Private::emitBufferCompleted(Request *request, FrameBuffer *buffer)
>  {
>         Camera *camera = _o<Camera>();
> +       layers_->bufferCompleted(request, buffer);
>         camera->bufferCompleted.emit(request, buffer);
>  }
>  
>  void Camera::Private::emitRequestCompleted(Request *request)
>  {
>         Camera *camera = _o<Camera>();
> +       ControlList metadata = layers_->requestCompleted(request);
> +       request->_d()->metadata().merge(metadata,
> +                                       ControlList::MergePolicy::OverwriteExisting);
>         camera->requestCompleted.emit(request);
>  }
>  
>  void Camera::Private::emitDisconnected()
>  {
>         Camera *camera = _o<Camera>();
> +       layers_->disconnected();
>         camera->disconnected.emit();
>  }
>  
> @@ -976,6 +984,10 @@ Camera::Camera(std::unique_ptr<Private> d, const std::string &id,
>         _d()->id_ = id;
>         _d()->streams_ = streams;
>         _d()->validator_ = std::make_unique<CameraControlValidator>(this);
> +       _d()->layers_ =
> +               _d()->pipe()->cameraManager()->_d()->layerManager()->createController(this,
> +                                                                                     _d()->properties_,
> +                                                                                     _d()->controlInfo_);

Ah! I was about to ask what happens if there are no layers? But it seems
I just needed to look closely-er.

Looks good to me!

Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>

Best wishes,
Isaac

>  }
>  
>  Camera::~Camera()
> @@ -1065,6 +1077,8 @@ int Camera::acquire()
>                 return -EBUSY;
>         }
>  
> +       d->layers_->acquire();
> +
>         d->setState(Private::CameraAcquired);
>  
>         return 0;
> @@ -1097,6 +1111,8 @@ int Camera::release()
>                 d->pipe_->invokeMethod(&PipelineHandler::release,
>                                        ConnectionTypeBlocking, this);
>  
> +       d->layers_->release();
> +
>         d->setState(Private::CameraAvailable);
>  
>         return 0;
> @@ -1114,7 +1130,7 @@ int Camera::release()
>   */
>  const ControlInfoMap &Camera::controls() const
>  {
> -       return _d()->controlInfo_;
> +       return _d()->layers_->controls();
>  }
>  
>  /**
> @@ -1127,7 +1143,7 @@ const ControlInfoMap &Camera::controls() const
>   */
>  const ControlList &Camera::properties() const
>  {
> -       return _d()->properties_;
> +       return _d()->layers_->properties();
>  }
>  
>  /**
> @@ -1276,6 +1292,8 @@ int Camera::configure(CameraConfiguration *config)
>                 d->activeStreams_.insert(stream);
>         }
>  
> +       d->layers_->configure(config, d->controlInfo_);
> +
>         d->setState(Private::CameraConfigured);
>  
>         return 0;
> @@ -1316,6 +1334,8 @@ std::unique_ptr<Request> Camera::createRequest(uint64_t cookie)
>         /* Associate the request with the pipeline handler. */
>         d->pipe_->registerRequest(request.get());
>  
> +       d->layers_->createRequest(cookie, request.get());
> +
>         return request;
>  }
>  
> @@ -1417,6 +1437,8 @@ int Camera::queueRequest(Request *request)
>         /* Pre-process AeEnable. */
>         patchControlList(request->controls());
>  
> +       d->layers_->queueRequest(request);
> +
>         d->pipe_->invokeMethod(&PipelineHandler::queueRequest,
>                                ConnectionTypeQueued, request);
>  
> @@ -1453,8 +1475,10 @@ int Camera::start(const ControlList *controls)
>  
>         ASSERT(d->requestSequence_ == 0);
>  
> +       ControlList *newControls = d->layers_->start(controls);
> +
>         if (controls) {
> -               ControlList copy(*controls);
> +               ControlList copy(*newControls);
>                 patchControlList(copy);
>                 ret = d->pipe_->invokeMethod(&PipelineHandler::start,
>                                              ConnectionTypeBlocking, this, &copy);
> @@ -1505,6 +1529,8 @@ int Camera::stop()
>  
>         d->setState(Private::CameraStopping);
>  
> +       d->layers_->stop();
> +
>         d->pipe_->invokeMethod(&PipelineHandler::stop, ConnectionTypeBlocking,
>                                this);
>  
> -- 
> 2.47.2
>

Patch
diff mbox series

diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h
index d28cd921a0f9..fdabc460a357 100644
--- a/include/libcamera/internal/camera.h
+++ b/include/libcamera/internal/camera.h
@@ -19,6 +19,8 @@ 
 
 #include <libcamera/camera.h>
 
+#include "libcamera/internal/layer_manager.h"
+
 namespace libcamera {
 
 class CameraControlValidator;
@@ -78,6 +80,8 @@  private:
 	std::atomic<State> state_;
 
 	std::unique_ptr<CameraControlValidator> validator_;
+
+	std::unique_ptr<LayerController> layers_;
 };
 
 } /* namespace libcamera */
diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
index a2132e61a7bd..4ed9a21726d9 100644
--- a/src/libcamera/camera.cpp
+++ b/src/libcamera/camera.cpp
@@ -18,6 +18,7 @@ 
 #include <libcamera/base/log.h>
 #include <libcamera/base/thread.h>
 
+#include <libcamera/camera_manager.h>
 #include <libcamera/color_space.h>
 #include <libcamera/control_ids.h>
 #include <libcamera/framebuffer_allocator.h>
@@ -27,6 +28,8 @@ 
 
 #include "libcamera/internal/camera.h"
 #include "libcamera/internal/camera_controls.h"
+#include "libcamera/internal/camera_manager.h"
+#include "libcamera/internal/layer_manager.h"
 #include "libcamera/internal/pipeline_handler.h"
 #include "libcamera/internal/request.h"
 
@@ -774,18 +777,23 @@  void Camera::Private::setState(State state)
 void Camera::Private::emitBufferCompleted(Request *request, FrameBuffer *buffer)
 {
 	Camera *camera = _o<Camera>();
+	layers_->bufferCompleted(request, buffer);
 	camera->bufferCompleted.emit(request, buffer);
 }
 
 void Camera::Private::emitRequestCompleted(Request *request)
 {
 	Camera *camera = _o<Camera>();
+	ControlList metadata = layers_->requestCompleted(request);
+	request->_d()->metadata().merge(metadata,
+					ControlList::MergePolicy::OverwriteExisting);
 	camera->requestCompleted.emit(request);
 }
 
 void Camera::Private::emitDisconnected()
 {
 	Camera *camera = _o<Camera>();
+	layers_->disconnected();
 	camera->disconnected.emit();
 }
 
@@ -976,6 +984,10 @@  Camera::Camera(std::unique_ptr<Private> d, const std::string &id,
 	_d()->id_ = id;
 	_d()->streams_ = streams;
 	_d()->validator_ = std::make_unique<CameraControlValidator>(this);
+	_d()->layers_ =
+		_d()->pipe()->cameraManager()->_d()->layerManager()->createController(this,
+										      _d()->properties_,
+										      _d()->controlInfo_);
 }
 
 Camera::~Camera()
@@ -1065,6 +1077,8 @@  int Camera::acquire()
 		return -EBUSY;
 	}
 
+	d->layers_->acquire();
+
 	d->setState(Private::CameraAcquired);
 
 	return 0;
@@ -1097,6 +1111,8 @@  int Camera::release()
 		d->pipe_->invokeMethod(&PipelineHandler::release,
 				       ConnectionTypeBlocking, this);
 
+	d->layers_->release();
+
 	d->setState(Private::CameraAvailable);
 
 	return 0;
@@ -1114,7 +1130,7 @@  int Camera::release()
  */
 const ControlInfoMap &Camera::controls() const
 {
-	return _d()->controlInfo_;
+	return _d()->layers_->controls();
 }
 
 /**
@@ -1127,7 +1143,7 @@  const ControlInfoMap &Camera::controls() const
  */
 const ControlList &Camera::properties() const
 {
-	return _d()->properties_;
+	return _d()->layers_->properties();
 }
 
 /**
@@ -1276,6 +1292,8 @@  int Camera::configure(CameraConfiguration *config)
 		d->activeStreams_.insert(stream);
 	}
 
+	d->layers_->configure(config, d->controlInfo_);
+
 	d->setState(Private::CameraConfigured);
 
 	return 0;
@@ -1316,6 +1334,8 @@  std::unique_ptr<Request> Camera::createRequest(uint64_t cookie)
 	/* Associate the request with the pipeline handler. */
 	d->pipe_->registerRequest(request.get());
 
+	d->layers_->createRequest(cookie, request.get());
+
 	return request;
 }
 
@@ -1417,6 +1437,8 @@  int Camera::queueRequest(Request *request)
 	/* Pre-process AeEnable. */
 	patchControlList(request->controls());
 
+	d->layers_->queueRequest(request);
+
 	d->pipe_->invokeMethod(&PipelineHandler::queueRequest,
 			       ConnectionTypeQueued, request);
 
@@ -1453,8 +1475,10 @@  int Camera::start(const ControlList *controls)
 
 	ASSERT(d->requestSequence_ == 0);
 
+	ControlList *newControls = d->layers_->start(controls);
+
 	if (controls) {
-		ControlList copy(*controls);
+		ControlList copy(*newControls);
 		patchControlList(copy);
 		ret = d->pipe_->invokeMethod(&PipelineHandler::start,
 					     ConnectionTypeBlocking, this, &copy);
@@ -1505,6 +1529,8 @@  int Camera::stop()
 
 	d->setState(Private::CameraStopping);
 
+	d->layers_->stop();
+
 	d->pipe_->invokeMethod(&PipelineHandler::stop, ConnectionTypeBlocking,
 			       this);