[PATCH 3/5] pipeline_handler: Add acquireDevice() method to mirror existing releaseDevice()
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Sun Aug 25 02:49:57 CEST 2024
On Wed, Aug 21, 2024 at 06:55:45PM +0200, Cheng-Hao Yang wrote:
> Hi Hans,
>
> Thanks for the patch. Actually in mtkisp7, we did something very similar
> [1].
> (And I just caught a bug by checking your changes. Thanks :)
>
> [1]:
> https://chromium-review.googlesource.com/c/chromiumos/third_party/libcamera/+/5525900
>
> On Tue, Aug 20, 2024 at 9:50 PM Hans de Goede <hdegoede at redhat.com> wrote:
>
> > ATM libcamera always keeps all /dev/video# and /dev/v4l2_subdev# nodes
> > for a pipeline open after enumerating the camera.
> >
> > This is a problem for uvcvideo and atomisp /dev/video# nodes as well as
> > for VCM /dev/v4l2_subdev# nodes. Keeping these open stops the underlying
> > hw-devices from being able to enter runtime-suspend causing significant
> > unnecessary power-usage.
> >
> > Add a stub acquireDevice() method to the PipelineHandler class which
> > pipeline handlers can override to delay opening /dev nodes until
> > the camera is acquired.
> >
> > Note pipeline handlers typically also will need access to /dev nodes
> > for their CameraConfig::validate() implementation for tryFormat() calls.
> > Making sure that /dev nodes are opened as necessary from validate() is
> > left up to the pipeline handler implementation.
> >
> > Signed-off-by: Hans de Goede <hdegoede at redhat.com>
> > ---
> > include/libcamera/internal/pipeline_handler.h | 3 +-
> > src/libcamera/camera.cpp | 2 +-
> > src/libcamera/pipeline_handler.cpp | 43 +++++++++++++++----
> > 3 files changed, 37 insertions(+), 11 deletions(-)
> >
> > diff --git a/include/libcamera/internal/pipeline_handler.h
> > b/include/libcamera/internal/pipeline_handler.h
> > index cad5812f..597f7c3e 100644
> > --- a/include/libcamera/internal/pipeline_handler.h
> > +++ b/include/libcamera/internal/pipeline_handler.h
> > @@ -45,7 +45,7 @@ public:
> > MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,
> > const DeviceMatch &dm);
> >
> > - bool acquire();
> > + bool acquire(Camera *camera);
> > void release(Camera *camera);
> >
> > virtual std::unique_ptr<CameraConfiguration>
> > generateConfiguration(Camera *camera,
> > @@ -79,6 +79,7 @@ protected:
> > virtual int queueRequestDevice(Camera *camera, Request *request) =
> > 0;
> > virtual void stopDevice(Camera *camera) = 0;
> >
> > + virtual bool acquireDevice(Camera *camera);
> > virtual void releaseDevice(Camera *camera);
> >
> > CameraManager *manager_;
> > diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
> > index 382a68f7..4e393f89 100644
> > --- a/src/libcamera/camera.cpp
> > +++ b/src/libcamera/camera.cpp
> > @@ -995,7 +995,7 @@ int Camera::acquire()
> > if (ret < 0)
> > return ret == -EACCES ? -EBUSY : ret;
> >
> > - if (!d->pipe_->acquire()) {
> > + if (!d->pipe_->acquire(this)) {
> > LOG(Camera, Info)
> > << "Pipeline handler in use by another process";
> > return -EBUSY;
> > diff --git a/src/libcamera/pipeline_handler.cpp
> > b/src/libcamera/pipeline_handler.cpp
> > index 1fc22d6a..e1342306 100644
> > --- a/src/libcamera/pipeline_handler.cpp
> > +++ b/src/libcamera/pipeline_handler.cpp
> > @@ -163,20 +163,22 @@ MediaDevice
> > *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
> > * has already acquired it
> > * \sa release()
> > */
> > -bool PipelineHandler::acquire()
> > +bool PipelineHandler::acquire(Camera *camera)
> > {
> > MutexLocker locker(lock_);
> >
> > - if (useCount_) {
> > - ++useCount_;
> > - return true;
> > + if (useCount_ == 0) {
> > + for (std::shared_ptr<MediaDevice> &media : mediaDevices_) {
> > + if (!media->lock()) {
> > + unlockMediaDevices();
> > + return false;
> > + }
> > + }
> > }
> >
> > - for (std::shared_ptr<MediaDevice> &media : mediaDevices_) {
> > - if (!media->lock()) {
> > - unlockMediaDevices();
> > - return false;
> > - }
> > + if (!acquireDevice(camera)) {
> > + unlockMediaDevices();
> >
>
> I think we should only unlock media devices if it's the first acquire
> being called, as there might be other ongoing usages on other
> cameras [2]. Therefore:
> ```
> if (useCount_ == 0)
> unlockMediaDevices();
> ```
>
> [2]:
> https://chromium-review.googlesource.com/c/chromiumos/third_party/libcamera/+/5525900/7/src/libcamera/pipeline_handler.cpp#181
>
> + return false;
> > }
> >
> > ++useCount_;
> > @@ -213,12 +215,35 @@ void PipelineHandler::release(Camera *camera)
> > --useCount_;
> > }
> >
> > +/**
> > + * \brief Acquire resources associated with this camera
> > + * \param[in] camera The camera for which to acquire resources
> > + *
> > + * Pipeline handlers may override this in order to get resources
> > + * such as open /dev nodes are allocate buffers when a camera is
s at open /dev nodes at opening devices/
s/are allocate/and allocating/
As discussed previously, I think we need to improve the
application-facing API to make resource and power management more
explicit. Camera::acquire() was never meant for this purpose. I
understand we need a short term solution to the power consumption issue
for UVC cameras without an enormous amount of yak shaving, and I'm fine
with this patch series as an interim measure, but I don't want to see
acquireDevice() being used in random ways by pipeline handlers other
than UVC before we address the more general problem. This should be
documented here.
> > + * acquired.
Please reflow these paragraphs to 80 columns.
> > + *
> > + * Note this is called once for every camera which is acquired,
s/which/that/
> > + * so if there are shared resources the pipeline handler must take
s/shared resources/resources shared by multiple cameras/
> > + * care to not release them until releaseDevice() has been called for
> > + * all previously acquired cameras.
Doesn't this paragraph belong to releaseDevice() ?
> > + *
> > + * \return True on success, false on failure.
> > + * \sa releaseDevice()
> > + */
> > +bool PipelineHandler::acquireDevice([[maybe_unused]] Camera *camera)
> > +{
> > + return true;
> > +}
> > +
> > /**
> > * \brief Release resources associated with this camera
> > * \param[in] camera The camera for which to release resources
> > *
> > * Pipeline handlers may override this in order to perform cleanup
> > operations
> > * when a camera is released, such as freeing memory.
> > + *
> > + * \sa acquireDevice()
> > */
> > void PipelineHandler::releaseDevice([[maybe_unused]] Camera *camera)
> > {
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list