[libcamera-devel,v2,01/10] camera_sensor: Add minimum and maximum line length to IPACameraSensorInfo
diff mbox series

Message ID 20221006131744.5179-2-naush@raspberrypi.com
State Superseded
Headers show
Series
  • Raspberry Pi: Horizontal blanking control
Related show

Commit Message

Naushir Patuck Oct. 6, 2022, 1:17 p.m. UTC
Add fields for minimum and maximum line length (in units of pixels) to the
IPACameraSensorInfo structure. This replaces the existing lineLength field.

Update the ipu3, raspberrypi and rkisp1 IPAs to use IPACameraSensorInfo::minLineLength
instead of IPACameraSensorInfo::lineLength, as logically we will always want to
use the fastest sensor readout by default.

Since the IPAs now use minLineLength for their calculations, set the starting
value of the V4L2_CID_HBLANK control to its minimum in CameraSensor::init().

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 include/libcamera/ipa/core.mojom    | 21 +++++++++++++++------
 src/ipa/ipu3/ipu3.cpp               |  6 ++++--
 src/ipa/raspberrypi/raspberrypi.cpp |  2 +-
 src/ipa/rkisp1/rkisp1.cpp           |  2 +-
 src/libcamera/camera_sensor.cpp     | 15 +++++++++++++--
 5 files changed, 34 insertions(+), 12 deletions(-)

Comments

Laurent Pinchart Oct. 7, 2022, 10:28 p.m. UTC | #1
Hi Naush,

Thank you for the patch.

On Thu, Oct 06, 2022 at 02:17:35PM +0100, Naushir Patuck via libcamera-devel wrote:
> Add fields for minimum and maximum line length (in units of pixels) to the
> IPACameraSensorInfo structure. This replaces the existing lineLength field.
> 
> Update the ipu3, raspberrypi and rkisp1 IPAs to use IPACameraSensorInfo::minLineLength
> instead of IPACameraSensorInfo::lineLength, as logically we will always want to
> use the fastest sensor readout by default.
> 
> Since the IPAs now use minLineLength for their calculations, set the starting
> value of the V4L2_CID_HBLANK control to its minimum in CameraSensor::init().
> 
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> Tested-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> ---
>  include/libcamera/ipa/core.mojom    | 21 +++++++++++++++------
>  src/ipa/ipu3/ipu3.cpp               |  6 ++++--
>  src/ipa/raspberrypi/raspberrypi.cpp |  2 +-
>  src/ipa/rkisp1/rkisp1.cpp           |  2 +-
>  src/libcamera/camera_sensor.cpp     | 15 +++++++++++++--
>  5 files changed, 34 insertions(+), 12 deletions(-)
> 
> diff --git a/include/libcamera/ipa/core.mojom b/include/libcamera/ipa/core.mojom
> index 74f3339e56f2..2bc3028c22d6 100644
> --- a/include/libcamera/ipa/core.mojom
> +++ b/include/libcamera/ipa/core.mojom
> @@ -172,10 +172,17 @@ module libcamera;
>   */
>  
>  /**
> - * \var IPACameraSensorInfo::lineLength
> - * \brief Total line length in pixels
> + * \var IPACameraSensorInfo::minLineLength
> + * \brief The minimum line length in pixels
>   *
> - * The total line length in pixel clock periods, including blanking.
> + * The minimum allowable line length in pixel clock periods, including blanking.
> + */
> +
> +/**
> + * \var IPACameraSensorInfo::maxLineLength
> + * \brief The maximum line length in pixels
> + *
> + * The maximum allowable line length in pixel clock periods, including blanking.
>   */
>  
>  /**
> @@ -189,7 +196,7 @@ module libcamera;
>   * To obtain the minimum frame duration:
>   *
>   * \verbatim
> -       frameDuration(s) = minFrameLength(lines) * lineLength(pixels) / pixelRate(pixels per second)
> +       frameDuration(s) = minFrameLength(lines) * minLineLength(pixels) / pixelRate(pixels per second)
>     \endverbatim
>   */
>  
> @@ -204,7 +211,7 @@ module libcamera;
>   * To obtain the maximum frame duration:
>   *
>   * \verbatim
> -       frameDuration(s) = maxFrameLength(lines) * lineLength(pixels) / pixelRate(pixels per second)
> +       frameDuration(s) = maxFrameLength(lines) * maxLineLength(pixels) / pixelRate(pixels per second)
>     \endverbatim
>   */
>  struct IPACameraSensorInfo {
> @@ -217,7 +224,9 @@ struct IPACameraSensorInfo {
>  	Size outputSize;
>  
>  	uint64 pixelRate;
> -	uint32 lineLength;
> +
> +	uint32 minLineLength;
> +	uint32 maxLineLength;
>  
>  	uint32 minFrameLength;
>  	uint32 maxFrameLength;
> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
> index b93a09d40c39..7e26fc5639c2 100644
> --- a/src/ipa/ipu3/ipu3.cpp
> +++ b/src/ipa/ipu3/ipu3.cpp
> @@ -336,7 +336,8 @@ int IPAIPU3::init(const IPASettings &settings,
>  
>  	/* Clean context */
>  	context_.configuration = {};
> -	context_.configuration.sensor.lineDuration = sensorInfo.lineLength * 1.0s / sensorInfo.pixelRate;
> +	context_.configuration.sensor.lineDuration = sensorInfo.minLineLength
> +						     * 1.0s / sensorInfo.pixelRate;

The * should be aligned below the =. Same below.

>  
>  	/* Load the tuning data file. */
>  	File file(settings.configurationFile);
> @@ -499,7 +500,8 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo,
>  	context_.frameContexts.clear();
>  
>  	/* Initialise the sensor configuration. */
> -	context_.configuration.sensor.lineDuration = sensorInfo_.lineLength * 1.0s / sensorInfo_.pixelRate;
> +	context_.configuration.sensor.lineDuration = sensorInfo_.minLineLength
> +						     * 1.0s / sensorInfo_.pixelRate;
>  
>  	/*
>  	 * Compute the sensor V4L2 controls to be used by the algorithms and
> diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
> index 8d731435764e..358a119da222 100644
> --- a/src/ipa/raspberrypi/raspberrypi.cpp
> +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> @@ -356,7 +356,7 @@ void IPARPi::setMode(const IPACameraSensorInfo &sensorInfo)
>  	 * Calculate the line length as the ratio between the line length in
>  	 * pixels and the pixel rate.
>  	 */
> -	mode_.lineLength = sensorInfo.lineLength * (1.0s / sensorInfo.pixelRate);
> +	mode_.lineLength = sensorInfo.minLineLength * (1.0s / sensorInfo.pixelRate);
>  
>  	/*
>  	 * Set the frame length limits for the mode to ensure exposure and
> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
> index 32feb1682749..ddb22d98eb41 100644
> --- a/src/ipa/rkisp1/rkisp1.cpp
> +++ b/src/ipa/rkisp1/rkisp1.cpp
> @@ -246,7 +246,7 @@ int IPARkISP1::configure([[maybe_unused]] const IPACameraSensorInfo &info,
>  	context_.configuration.hw.revision = hwRevision_;
>  
>  	context_.configuration.sensor.size = info.outputSize;
> -	context_.configuration.sensor.lineDuration = info.lineLength * 1.0s / info.pixelRate;
> +	context_.configuration.sensor.lineDuration = info.minLineLength * 1.0s / info.pixelRate;
>  
>  	/*
>  	 * When the AGC computes the new exposure values for a frame, it needs
> diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp
> index 911fd0beae4e..83f81d655395 100644
> --- a/src/libcamera/camera_sensor.cpp
> +++ b/src/libcamera/camera_sensor.cpp
> @@ -176,6 +176,15 @@ int CameraSensor::init()
>  	if (ret)
>  		return ret;
>  
> +	/* Set HBLANK to the minimum as a starting value. */

I would capture the rationale here.

	/*
	 * Set HBLANK to the minimum to start with a well-defined line length,
	 * allowing IPA modules that do not modify HBLANK to use the sensor
	 * minimum line length in their calculations.
	 */

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

No need to resubmit if only those small changes are required.

> +	const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> +	ControlList ctrl(subdev_->controls());
> +
> +	ctrl.set(V4L2_CID_HBLANK, hblank.min().get<int32_t>());
> +	ret = subdev_->setControls(&ctrl);
> +	if (ret)
> +		return ret;
> +
>  	return applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff);
>  }
>  
> @@ -883,10 +892,12 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const
>  		return -EINVAL;
>  	}
>  
> -	int32_t hblank = ctrls.get(V4L2_CID_HBLANK).get<int32_t>();
> -	info->lineLength = info->outputSize.width + hblank;
>  	info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
>  
> +	const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> +	info->minLineLength = info->outputSize.width + hblank.min().get<int32_t>();
> +	info->maxLineLength = info->outputSize.width + hblank.max().get<int32_t>();
> +
>  	const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK);
>  	info->minFrameLength = info->outputSize.height + vblank.min().get<int32_t>();
>  	info->maxFrameLength = info->outputSize.height + vblank.max().get<int32_t>();
Naushir Patuck Oct. 8, 2022, 6:12 a.m. UTC | #2
Hi Laurent,


On Fri, 7 Oct 2022 at 23:28, Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> Hi Naush,
>
> Thank you for the patch.
>
> On Thu, Oct 06, 2022 at 02:17:35PM +0100, Naushir Patuck via
> libcamera-devel wrote:
> > Add fields for minimum and maximum line length (in units of pixels) to
> the
> > IPACameraSensorInfo structure. This replaces the existing lineLength
> field.
> >
> > Update the ipu3, raspberrypi and rkisp1 IPAs to use
> IPACameraSensorInfo::minLineLength
> > instead of IPACameraSensorInfo::lineLength, as logically we will always
> want to
> > use the fastest sensor readout by default.
> >
> > Since the IPAs now use minLineLength for their calculations, set the
> starting
> > value of the V4L2_CID_HBLANK control to its minimum in
> CameraSensor::init().
> >
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > Tested-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > ---
> >  include/libcamera/ipa/core.mojom    | 21 +++++++++++++++------
> >  src/ipa/ipu3/ipu3.cpp               |  6 ++++--
> >  src/ipa/raspberrypi/raspberrypi.cpp |  2 +-
> >  src/ipa/rkisp1/rkisp1.cpp           |  2 +-
> >  src/libcamera/camera_sensor.cpp     | 15 +++++++++++++--
> >  5 files changed, 34 insertions(+), 12 deletions(-)
> >
> > diff --git a/include/libcamera/ipa/core.mojom
> b/include/libcamera/ipa/core.mojom
> > index 74f3339e56f2..2bc3028c22d6 100644
> > --- a/include/libcamera/ipa/core.mojom
> > +++ b/include/libcamera/ipa/core.mojom
> > @@ -172,10 +172,17 @@ module libcamera;
> >   */
> >
> >  /**
> > - * \var IPACameraSensorInfo::lineLength
> > - * \brief Total line length in pixels
> > + * \var IPACameraSensorInfo::minLineLength
> > + * \brief The minimum line length in pixels
> >   *
> > - * The total line length in pixel clock periods, including blanking.
> > + * The minimum allowable line length in pixel clock periods, including
> blanking.
> > + */
> > +
> > +/**
> > + * \var IPACameraSensorInfo::maxLineLength
> > + * \brief The maximum line length in pixels
> > + *
> > + * The maximum allowable line length in pixel clock periods, including
> blanking.
> >   */
> >
> >  /**
> > @@ -189,7 +196,7 @@ module libcamera;
> >   * To obtain the minimum frame duration:
> >   *
> >   * \verbatim
> > -       frameDuration(s) = minFrameLength(lines) * lineLength(pixels) /
> pixelRate(pixels per second)
> > +       frameDuration(s) = minFrameLength(lines) * minLineLength(pixels)
> / pixelRate(pixels per second)
> >     \endverbatim
> >   */
> >
> > @@ -204,7 +211,7 @@ module libcamera;
> >   * To obtain the maximum frame duration:
> >   *
> >   * \verbatim
> > -       frameDuration(s) = maxFrameLength(lines) * lineLength(pixels) /
> pixelRate(pixels per second)
> > +       frameDuration(s) = maxFrameLength(lines) * maxLineLength(pixels)
> / pixelRate(pixels per second)
> >     \endverbatim
> >   */
> >  struct IPACameraSensorInfo {
> > @@ -217,7 +224,9 @@ struct IPACameraSensorInfo {
> >       Size outputSize;
> >
> >       uint64 pixelRate;
> > -     uint32 lineLength;
> > +
> > +     uint32 minLineLength;
> > +     uint32 maxLineLength;
> >
> >       uint32 minFrameLength;
> >       uint32 maxFrameLength;
> > diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
> > index b93a09d40c39..7e26fc5639c2 100644
> > --- a/src/ipa/ipu3/ipu3.cpp
> > +++ b/src/ipa/ipu3/ipu3.cpp
> > @@ -336,7 +336,8 @@ int IPAIPU3::init(const IPASettings &settings,
> >
> >       /* Clean context */
> >       context_.configuration = {};
> > -     context_.configuration.sensor.lineDuration = sensorInfo.lineLength
> * 1.0s / sensorInfo.pixelRate;
> > +     context_.configuration.sensor.lineDuration =
> sensorInfo.minLineLength
> > +                                                  * 1.0s /
> sensorInfo.pixelRate;
>
> The * should be aligned below the =. Same below.
>
> >
> >       /* Load the tuning data file. */
> >       File file(settings.configurationFile);
> > @@ -499,7 +500,8 @@ int IPAIPU3::configure(const IPAConfigInfo
> &configInfo,
> >       context_.frameContexts.clear();
> >
> >       /* Initialise the sensor configuration. */
> > -     context_.configuration.sensor.lineDuration =
> sensorInfo_.lineLength * 1.0s / sensorInfo_.pixelRate;
> > +     context_.configuration.sensor.lineDuration =
> sensorInfo_.minLineLength
> > +                                                  * 1.0s /
> sensorInfo_.pixelRate;
> >
> >       /*
> >        * Compute the sensor V4L2 controls to be used by the algorithms
> and
> > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> b/src/ipa/raspberrypi/raspberrypi.cpp
> > index 8d731435764e..358a119da222 100644
> > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > @@ -356,7 +356,7 @@ void IPARPi::setMode(const IPACameraSensorInfo
> &sensorInfo)
> >        * Calculate the line length as the ratio between the line length
> in
> >        * pixels and the pixel rate.
> >        */
> > -     mode_.lineLength = sensorInfo.lineLength * (1.0s /
> sensorInfo.pixelRate);
> > +     mode_.lineLength = sensorInfo.minLineLength * (1.0s /
> sensorInfo.pixelRate);
> >
> >       /*
> >        * Set the frame length limits for the mode to ensure exposure and
> > diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
> > index 32feb1682749..ddb22d98eb41 100644
> > --- a/src/ipa/rkisp1/rkisp1.cpp
> > +++ b/src/ipa/rkisp1/rkisp1.cpp
> > @@ -246,7 +246,7 @@ int IPARkISP1::configure([[maybe_unused]] const
> IPACameraSensorInfo &info,
> >       context_.configuration.hw.revision = hwRevision_;
> >
> >       context_.configuration.sensor.size = info.outputSize;
> > -     context_.configuration.sensor.lineDuration = info.lineLength *
> 1.0s / info.pixelRate;
> > +     context_.configuration.sensor.lineDuration = info.minLineLength *
> 1.0s / info.pixelRate;
> >
> >       /*
> >        * When the AGC computes the new exposure values for a frame, it
> needs
> > diff --git a/src/libcamera/camera_sensor.cpp
> b/src/libcamera/camera_sensor.cpp
> > index 911fd0beae4e..83f81d655395 100644
> > --- a/src/libcamera/camera_sensor.cpp
> > +++ b/src/libcamera/camera_sensor.cpp
> > @@ -176,6 +176,15 @@ int CameraSensor::init()
> >       if (ret)
> >               return ret;
> >
> > +     /* Set HBLANK to the minimum as a starting value. */
>
> I would capture the rationale here.
>
>         /*
>          * Set HBLANK to the minimum to start with a well-defined line
> length,
>          * allowing IPA modules that do not modify HBLANK to use the sensor
>          * minimum line length in their calculations.
>          */
>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> No need to resubmit if only those small changes are required.
>
> > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > +     ControlList ctrl(subdev_->controls());
> > +
> > +     ctrl.set(V4L2_CID_HBLANK, hblank.min().get<int32_t>());
> > +     ret = subdev_->setControls(&ctrl);
> > +     if (ret)
> > +             return ret;
>

Actually, doing the setControls here unconditionally is probably incorrect.

If the control is read-only, we will return an error.  We probably want to
do something like what I did for the IPA where we test for
HBLANK::min() == HBLANK::max(), and if true, assume the control is
read-only and don't do the setControl().

Sorry I should have caught that, but my testing was done on sensors
with adjustable HBLANK controls. I'll update the statement and post
a revised patch first thing on Monday.

Regards,
Naush



> > +
> >       return
> applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff);
> >  }
> >
> > @@ -883,10 +892,12 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo
> *info) const
> >               return -EINVAL;
> >       }
> >
> > -     int32_t hblank = ctrls.get(V4L2_CID_HBLANK).get<int32_t>();
> > -     info->lineLength = info->outputSize.width + hblank;
> >       info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
> >
> > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > +     info->minLineLength = info->outputSize.width +
> hblank.min().get<int32_t>();
> > +     info->maxLineLength = info->outputSize.width +
> hblank.max().get<int32_t>();
> > +
> >       const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK);
> >       info->minFrameLength = info->outputSize.height +
> vblank.min().get<int32_t>();
> >       info->maxFrameLength = info->outputSize.height +
> vblank.max().get<int32_t>();
>
> --
> Regards,
>
> Laurent Pinchart
>
Jacopo Mondi Oct. 10, 2022, 11:10 a.m. UTC | #3
Hi

On Sat, Oct 08, 2022 at 07:12:55AM +0100, Naushir Patuck via libcamera-devel wrote:
> Hi Laurent,
>
>
> On Fri, 7 Oct 2022 at 23:28, Laurent Pinchart <
> laurent.pinchart@ideasonboard.com> wrote:
>
> > Hi Naush,
> >
> > Thank you for the patch.
> >
> > On Thu, Oct 06, 2022 at 02:17:35PM +0100, Naushir Patuck via
> > libcamera-devel wrote:
> > > Add fields for minimum and maximum line length (in units of pixels) to
> > the
> > > IPACameraSensorInfo structure. This replaces the existing lineLength
> > field.
> > >
> > > Update the ipu3, raspberrypi and rkisp1 IPAs to use
> > IPACameraSensorInfo::minLineLength
> > > instead of IPACameraSensorInfo::lineLength, as logically we will always
> > want to
> > > use the fastest sensor readout by default.
> > >
> > > Since the IPAs now use minLineLength for their calculations, set the
> > starting
> > > value of the V4L2_CID_HBLANK control to its minimum in
> > CameraSensor::init().
> > >
> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > > Tested-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > ---
> > >  include/libcamera/ipa/core.mojom    | 21 +++++++++++++++------
> > >  src/ipa/ipu3/ipu3.cpp               |  6 ++++--
> > >  src/ipa/raspberrypi/raspberrypi.cpp |  2 +-
> > >  src/ipa/rkisp1/rkisp1.cpp           |  2 +-
> > >  src/libcamera/camera_sensor.cpp     | 15 +++++++++++++--
> > >  5 files changed, 34 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/include/libcamera/ipa/core.mojom
> > b/include/libcamera/ipa/core.mojom
> > > index 74f3339e56f2..2bc3028c22d6 100644
> > > --- a/include/libcamera/ipa/core.mojom
> > > +++ b/include/libcamera/ipa/core.mojom
> > > @@ -172,10 +172,17 @@ module libcamera;
> > >   */
> > >
> > >  /**
> > > - * \var IPACameraSensorInfo::lineLength
> > > - * \brief Total line length in pixels
> > > + * \var IPACameraSensorInfo::minLineLength
> > > + * \brief The minimum line length in pixels
> > >   *
> > > - * The total line length in pixel clock periods, including blanking.
> > > + * The minimum allowable line length in pixel clock periods, including
> > blanking.
> > > + */
> > > +
> > > +/**
> > > + * \var IPACameraSensorInfo::maxLineLength
> > > + * \brief The maximum line length in pixels
> > > + *
> > > + * The maximum allowable line length in pixel clock periods, including
> > blanking.
> > >   */
> > >
> > >  /**
> > > @@ -189,7 +196,7 @@ module libcamera;
> > >   * To obtain the minimum frame duration:
> > >   *
> > >   * \verbatim
> > > -       frameDuration(s) = minFrameLength(lines) * lineLength(pixels) /
> > pixelRate(pixels per second)
> > > +       frameDuration(s) = minFrameLength(lines) * minLineLength(pixels)
> > / pixelRate(pixels per second)
> > >     \endverbatim
> > >   */
> > >
> > > @@ -204,7 +211,7 @@ module libcamera;
> > >   * To obtain the maximum frame duration:
> > >   *
> > >   * \verbatim
> > > -       frameDuration(s) = maxFrameLength(lines) * lineLength(pixels) /
> > pixelRate(pixels per second)
> > > +       frameDuration(s) = maxFrameLength(lines) * maxLineLength(pixels)
> > / pixelRate(pixels per second)
> > >     \endverbatim
> > >   */
> > >  struct IPACameraSensorInfo {
> > > @@ -217,7 +224,9 @@ struct IPACameraSensorInfo {
> > >       Size outputSize;
> > >
> > >       uint64 pixelRate;
> > > -     uint32 lineLength;
> > > +
> > > +     uint32 minLineLength;
> > > +     uint32 maxLineLength;
> > >
> > >       uint32 minFrameLength;
> > >       uint32 maxFrameLength;
> > > diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
> > > index b93a09d40c39..7e26fc5639c2 100644
> > > --- a/src/ipa/ipu3/ipu3.cpp
> > > +++ b/src/ipa/ipu3/ipu3.cpp
> > > @@ -336,7 +336,8 @@ int IPAIPU3::init(const IPASettings &settings,
> > >
> > >       /* Clean context */
> > >       context_.configuration = {};
> > > -     context_.configuration.sensor.lineDuration = sensorInfo.lineLength
> > * 1.0s / sensorInfo.pixelRate;
> > > +     context_.configuration.sensor.lineDuration =
> > sensorInfo.minLineLength
> > > +                                                  * 1.0s /
> > sensorInfo.pixelRate;
> >
> > The * should be aligned below the =. Same below.
> >
> > >
> > >       /* Load the tuning data file. */
> > >       File file(settings.configurationFile);
> > > @@ -499,7 +500,8 @@ int IPAIPU3::configure(const IPAConfigInfo
> > &configInfo,
> > >       context_.frameContexts.clear();
> > >
> > >       /* Initialise the sensor configuration. */
> > > -     context_.configuration.sensor.lineDuration =
> > sensorInfo_.lineLength * 1.0s / sensorInfo_.pixelRate;
> > > +     context_.configuration.sensor.lineDuration =
> > sensorInfo_.minLineLength
> > > +                                                  * 1.0s /
> > sensorInfo_.pixelRate;
> > >
> > >       /*
> > >        * Compute the sensor V4L2 controls to be used by the algorithms
> > and
> > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> > b/src/ipa/raspberrypi/raspberrypi.cpp
> > > index 8d731435764e..358a119da222 100644
> > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > @@ -356,7 +356,7 @@ void IPARPi::setMode(const IPACameraSensorInfo
> > &sensorInfo)
> > >        * Calculate the line length as the ratio between the line length
> > in
> > >        * pixels and the pixel rate.
> > >        */
> > > -     mode_.lineLength = sensorInfo.lineLength * (1.0s /
> > sensorInfo.pixelRate);
> > > +     mode_.lineLength = sensorInfo.minLineLength * (1.0s /
> > sensorInfo.pixelRate);
> > >
> > >       /*
> > >        * Set the frame length limits for the mode to ensure exposure and
> > > diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
> > > index 32feb1682749..ddb22d98eb41 100644
> > > --- a/src/ipa/rkisp1/rkisp1.cpp
> > > +++ b/src/ipa/rkisp1/rkisp1.cpp
> > > @@ -246,7 +246,7 @@ int IPARkISP1::configure([[maybe_unused]] const
> > IPACameraSensorInfo &info,
> > >       context_.configuration.hw.revision = hwRevision_;
> > >
> > >       context_.configuration.sensor.size = info.outputSize;
> > > -     context_.configuration.sensor.lineDuration = info.lineLength *
> > 1.0s / info.pixelRate;
> > > +     context_.configuration.sensor.lineDuration = info.minLineLength *
> > 1.0s / info.pixelRate;
> > >
> > >       /*
> > >        * When the AGC computes the new exposure values for a frame, it
> > needs
> > > diff --git a/src/libcamera/camera_sensor.cpp
> > b/src/libcamera/camera_sensor.cpp
> > > index 911fd0beae4e..83f81d655395 100644
> > > --- a/src/libcamera/camera_sensor.cpp
> > > +++ b/src/libcamera/camera_sensor.cpp
> > > @@ -176,6 +176,15 @@ int CameraSensor::init()
> > >       if (ret)
> > >               return ret;
> > >
> > > +     /* Set HBLANK to the minimum as a starting value. */
> >
> > I would capture the rationale here.
> >
> >         /*
> >          * Set HBLANK to the minimum to start with a well-defined line
> > length,
> >          * allowing IPA modules that do not modify HBLANK to use the sensor
> >          * minimum line length in their calculations.
> >          */
> >
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >
> > No need to resubmit if only those small changes are required.
> >
> > > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > > +     ControlList ctrl(subdev_->controls());
> > > +
> > > +     ctrl.set(V4L2_CID_HBLANK, hblank.min().get<int32_t>());
> > > +     ret = subdev_->setControls(&ctrl);
> > > +     if (ret)
> > > +             return ret;
> >
>
> Actually, doing the setControls here unconditionally is probably incorrect.
>
> If the control is read-only, we will return an error.  We probably want to
> do something like what I did for the IPA where we test for
> HBLANK::min() == HBLANK::max(), and if true, assume the control is
> read-only and don't do the setControl().
>
> Sorry I should have caught that, but my testing was done on sensors
> with adjustable HBLANK controls. I'll update the statement and post
> a revised patch first thing on Monday.
>

I wonder if we shouldn't use (for hblank as well as per vblank) the
control's default value in the IPA calculations instead of assuming
(and here forcing) the minium value. Specifically, during the
IPA::configure() where we intialize values using the minium value
seems rather an arbitrary assumptions. After IPA::configure() the IPA
should be free to change H/VBlank as they like in the min/max ranges,
but for intiialization...

Also most drivers (should?) update the blanking values to a sensible
defaul when a new mode is applied. Shouldn't we rely on their
selection ?


> Regards,
> Naush
>
>
>
> > > +
> > >       return
> > applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff);
> > >  }
> > >
> > > @@ -883,10 +892,12 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo
> > *info) const
> > >               return -EINVAL;
> > >       }
> > >
> > > -     int32_t hblank = ctrls.get(V4L2_CID_HBLANK).get<int32_t>();
> > > -     info->lineLength = info->outputSize.width + hblank;
> > >       info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
> > >
> > > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > > +     info->minLineLength = info->outputSize.width +
> > hblank.min().get<int32_t>();
> > > +     info->maxLineLength = info->outputSize.width +
> > hblank.max().get<int32_t>();
> > > +
> > >       const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK);
> > >       info->minFrameLength = info->outputSize.height +
> > vblank.min().get<int32_t>();
> > >       info->maxFrameLength = info->outputSize.height +
> > vblank.max().get<int32_t>();
> >
> > --
> > Regards,
> >
> > Laurent Pinchart
> >
Dave Stevenson Oct. 10, 2022, 1:44 p.m. UTC | #4
Hi Jacopo

On Mon, 10 Oct 2022 at 12:10, Jacopo Mondi via libcamera-devel
<libcamera-devel@lists.libcamera.org> wrote:
>
> Hi
>
> On Sat, Oct 08, 2022 at 07:12:55AM +0100, Naushir Patuck via libcamera-devel wrote:
> > Hi Laurent,
> >
> >
> > On Fri, 7 Oct 2022 at 23:28, Laurent Pinchart <
> > laurent.pinchart@ideasonboard.com> wrote:
> >
> > > Hi Naush,
> > >
> > > Thank you for the patch.
> > >
> > > On Thu, Oct 06, 2022 at 02:17:35PM +0100, Naushir Patuck via
> > > libcamera-devel wrote:
> > > > Add fields for minimum and maximum line length (in units of pixels) to
> > > the
> > > > IPACameraSensorInfo structure. This replaces the existing lineLength
> > > field.
> > > >
> > > > Update the ipu3, raspberrypi and rkisp1 IPAs to use
> > > IPACameraSensorInfo::minLineLength
> > > > instead of IPACameraSensorInfo::lineLength, as logically we will always
> > > want to
> > > > use the fastest sensor readout by default.
> > > >
> > > > Since the IPAs now use minLineLength for their calculations, set the
> > > starting
> > > > value of the V4L2_CID_HBLANK control to its minimum in
> > > CameraSensor::init().
> > > >
> > > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > > > Tested-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > > ---
> > > >  include/libcamera/ipa/core.mojom    | 21 +++++++++++++++------
> > > >  src/ipa/ipu3/ipu3.cpp               |  6 ++++--
> > > >  src/ipa/raspberrypi/raspberrypi.cpp |  2 +-
> > > >  src/ipa/rkisp1/rkisp1.cpp           |  2 +-
> > > >  src/libcamera/camera_sensor.cpp     | 15 +++++++++++++--
> > > >  5 files changed, 34 insertions(+), 12 deletions(-)
> > > >
> > > > diff --git a/include/libcamera/ipa/core.mojom
> > > b/include/libcamera/ipa/core.mojom
> > > > index 74f3339e56f2..2bc3028c22d6 100644
> > > > --- a/include/libcamera/ipa/core.mojom
> > > > +++ b/include/libcamera/ipa/core.mojom
> > > > @@ -172,10 +172,17 @@ module libcamera;
> > > >   */
> > > >
> > > >  /**
> > > > - * \var IPACameraSensorInfo::lineLength
> > > > - * \brief Total line length in pixels
> > > > + * \var IPACameraSensorInfo::minLineLength
> > > > + * \brief The minimum line length in pixels
> > > >   *
> > > > - * The total line length in pixel clock periods, including blanking.
> > > > + * The minimum allowable line length in pixel clock periods, including
> > > blanking.
> > > > + */
> > > > +
> > > > +/**
> > > > + * \var IPACameraSensorInfo::maxLineLength
> > > > + * \brief The maximum line length in pixels
> > > > + *
> > > > + * The maximum allowable line length in pixel clock periods, including
> > > blanking.
> > > >   */
> > > >
> > > >  /**
> > > > @@ -189,7 +196,7 @@ module libcamera;
> > > >   * To obtain the minimum frame duration:
> > > >   *
> > > >   * \verbatim
> > > > -       frameDuration(s) = minFrameLength(lines) * lineLength(pixels) /
> > > pixelRate(pixels per second)
> > > > +       frameDuration(s) = minFrameLength(lines) * minLineLength(pixels)
> > > / pixelRate(pixels per second)
> > > >     \endverbatim
> > > >   */
> > > >
> > > > @@ -204,7 +211,7 @@ module libcamera;
> > > >   * To obtain the maximum frame duration:
> > > >   *
> > > >   * \verbatim
> > > > -       frameDuration(s) = maxFrameLength(lines) * lineLength(pixels) /
> > > pixelRate(pixels per second)
> > > > +       frameDuration(s) = maxFrameLength(lines) * maxLineLength(pixels)
> > > / pixelRate(pixels per second)
> > > >     \endverbatim
> > > >   */
> > > >  struct IPACameraSensorInfo {
> > > > @@ -217,7 +224,9 @@ struct IPACameraSensorInfo {
> > > >       Size outputSize;
> > > >
> > > >       uint64 pixelRate;
> > > > -     uint32 lineLength;
> > > > +
> > > > +     uint32 minLineLength;
> > > > +     uint32 maxLineLength;
> > > >
> > > >       uint32 minFrameLength;
> > > >       uint32 maxFrameLength;
> > > > diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
> > > > index b93a09d40c39..7e26fc5639c2 100644
> > > > --- a/src/ipa/ipu3/ipu3.cpp
> > > > +++ b/src/ipa/ipu3/ipu3.cpp
> > > > @@ -336,7 +336,8 @@ int IPAIPU3::init(const IPASettings &settings,
> > > >
> > > >       /* Clean context */
> > > >       context_.configuration = {};
> > > > -     context_.configuration.sensor.lineDuration = sensorInfo.lineLength
> > > * 1.0s / sensorInfo.pixelRate;
> > > > +     context_.configuration.sensor.lineDuration =
> > > sensorInfo.minLineLength
> > > > +                                                  * 1.0s /
> > > sensorInfo.pixelRate;
> > >
> > > The * should be aligned below the =. Same below.
> > >
> > > >
> > > >       /* Load the tuning data file. */
> > > >       File file(settings.configurationFile);
> > > > @@ -499,7 +500,8 @@ int IPAIPU3::configure(const IPAConfigInfo
> > > &configInfo,
> > > >       context_.frameContexts.clear();
> > > >
> > > >       /* Initialise the sensor configuration. */
> > > > -     context_.configuration.sensor.lineDuration =
> > > sensorInfo_.lineLength * 1.0s / sensorInfo_.pixelRate;
> > > > +     context_.configuration.sensor.lineDuration =
> > > sensorInfo_.minLineLength
> > > > +                                                  * 1.0s /
> > > sensorInfo_.pixelRate;
> > > >
> > > >       /*
> > > >        * Compute the sensor V4L2 controls to be used by the algorithms
> > > and
> > > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> > > b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > index 8d731435764e..358a119da222 100644
> > > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > @@ -356,7 +356,7 @@ void IPARPi::setMode(const IPACameraSensorInfo
> > > &sensorInfo)
> > > >        * Calculate the line length as the ratio between the line length
> > > in
> > > >        * pixels and the pixel rate.
> > > >        */
> > > > -     mode_.lineLength = sensorInfo.lineLength * (1.0s /
> > > sensorInfo.pixelRate);
> > > > +     mode_.lineLength = sensorInfo.minLineLength * (1.0s /
> > > sensorInfo.pixelRate);
> > > >
> > > >       /*
> > > >        * Set the frame length limits for the mode to ensure exposure and
> > > > diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
> > > > index 32feb1682749..ddb22d98eb41 100644
> > > > --- a/src/ipa/rkisp1/rkisp1.cpp
> > > > +++ b/src/ipa/rkisp1/rkisp1.cpp
> > > > @@ -246,7 +246,7 @@ int IPARkISP1::configure([[maybe_unused]] const
> > > IPACameraSensorInfo &info,
> > > >       context_.configuration.hw.revision = hwRevision_;
> > > >
> > > >       context_.configuration.sensor.size = info.outputSize;
> > > > -     context_.configuration.sensor.lineDuration = info.lineLength *
> > > 1.0s / info.pixelRate;
> > > > +     context_.configuration.sensor.lineDuration = info.minLineLength *
> > > 1.0s / info.pixelRate;
> > > >
> > > >       /*
> > > >        * When the AGC computes the new exposure values for a frame, it
> > > needs
> > > > diff --git a/src/libcamera/camera_sensor.cpp
> > > b/src/libcamera/camera_sensor.cpp
> > > > index 911fd0beae4e..83f81d655395 100644
> > > > --- a/src/libcamera/camera_sensor.cpp
> > > > +++ b/src/libcamera/camera_sensor.cpp
> > > > @@ -176,6 +176,15 @@ int CameraSensor::init()
> > > >       if (ret)
> > > >               return ret;
> > > >
> > > > +     /* Set HBLANK to the minimum as a starting value. */
> > >
> > > I would capture the rationale here.
> > >
> > >         /*
> > >          * Set HBLANK to the minimum to start with a well-defined line
> > > length,
> > >          * allowing IPA modules that do not modify HBLANK to use the sensor
> > >          * minimum line length in their calculations.
> > >          */
> > >
> > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >
> > > No need to resubmit if only those small changes are required.
> > >
> > > > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > > > +     ControlList ctrl(subdev_->controls());
> > > > +
> > > > +     ctrl.set(V4L2_CID_HBLANK, hblank.min().get<int32_t>());
> > > > +     ret = subdev_->setControls(&ctrl);
> > > > +     if (ret)
> > > > +             return ret;
> > >
> >
> > Actually, doing the setControls here unconditionally is probably incorrect.
> >
> > If the control is read-only, we will return an error.  We probably want to
> > do something like what I did for the IPA where we test for
> > HBLANK::min() == HBLANK::max(), and if true, assume the control is
> > read-only and don't do the setControl().
> >
> > Sorry I should have caught that, but my testing was done on sensors
> > with adjustable HBLANK controls. I'll update the statement and post
> > a revised patch first thing on Monday.
> >
>
> I wonder if we shouldn't use (for hblank as well as per vblank) the
> control's default value in the IPA calculations instead of assuming
> (and here forcing) the minium value. Specifically, during the
> IPA::configure() where we intialize values using the minium value
> seems rather an arbitrary assumptions. After IPA::configure() the IPA
> should be free to change H/VBlank as they like in the min/max ranges,
> but for intiialization...
>
> Also most drivers (should?) update the blanking values to a sensible
> defaul when a new mode is applied. Shouldn't we rely on their
> selection ?

Is it correct behaviour for a sensor driver to change a r/w HBLANK
when changing mode? Changing limits for HBLANK is almost certainly the
case, but AIUI generally controls shouldn't change values unless they
are then invalid.

I'll agree that not updating the value has annoyances when the client
doesn't automatically compute and set HBLANK, but conversely updating
it is annoying for cases where the app doesn't support it and you have
deliberately set it to a long value (any mode change resets your
chosen value, despite it being valid).

libcamera always selecting the mode (even if the same) leading to a
reset when I was trying to test configurable HBLANK was where I
encountered this ambiguity.

  Dave

> > Regards,
> > Naush
> >
> >
> >
> > > > +
> > > >       return
> > > applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff);
> > > >  }
> > > >
> > > > @@ -883,10 +892,12 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo
> > > *info) const
> > > >               return -EINVAL;
> > > >       }
> > > >
> > > > -     int32_t hblank = ctrls.get(V4L2_CID_HBLANK).get<int32_t>();
> > > > -     info->lineLength = info->outputSize.width + hblank;
> > > >       info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
> > > >
> > > > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > > > +     info->minLineLength = info->outputSize.width +
> > > hblank.min().get<int32_t>();
> > > > +     info->maxLineLength = info->outputSize.width +
> > > hblank.max().get<int32_t>();
> > > > +
> > > >       const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK);
> > > >       info->minFrameLength = info->outputSize.height +
> > > vblank.min().get<int32_t>();
> > > >       info->maxFrameLength = info->outputSize.height +
> > > vblank.max().get<int32_t>();
> > >
> > > --
> > > Regards,
> > >
> > > Laurent Pinchart
> > >
Jacopo Mondi Oct. 10, 2022, 2:08 p.m. UTC | #5
Hi Dave

On Mon, Oct 10, 2022 at 02:44:41PM +0100, Dave Stevenson wrote:
> Hi Jacopo
>
> On Mon, 10 Oct 2022 at 12:10, Jacopo Mondi via libcamera-devel
> <libcamera-devel@lists.libcamera.org> wrote:
> >
> > Hi
> >
> > On Sat, Oct 08, 2022 at 07:12:55AM +0100, Naushir Patuck via libcamera-devel wrote:
> > > Hi Laurent,
> > >
> > >
> > > On Fri, 7 Oct 2022 at 23:28, Laurent Pinchart <
> > > laurent.pinchart@ideasonboard.com> wrote:
> > >
> > > > Hi Naush,
> > > >
> > > > Thank you for the patch.
> > > >
> > > > On Thu, Oct 06, 2022 at 02:17:35PM +0100, Naushir Patuck via
> > > > libcamera-devel wrote:
> > > > > Add fields for minimum and maximum line length (in units of pixels) to
> > > > the
> > > > > IPACameraSensorInfo structure. This replaces the existing lineLength
> > > > field.
> > > > >
> > > > > Update the ipu3, raspberrypi and rkisp1 IPAs to use
> > > > IPACameraSensorInfo::minLineLength
> > > > > instead of IPACameraSensorInfo::lineLength, as logically we will always
> > > > want to
> > > > > use the fastest sensor readout by default.
> > > > >
> > > > > Since the IPAs now use minLineLength for their calculations, set the
> > > > starting
> > > > > value of the V4L2_CID_HBLANK control to its minimum in
> > > > CameraSensor::init().
> > > > >
> > > > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > > > > Tested-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > > > ---
> > > > >  include/libcamera/ipa/core.mojom    | 21 +++++++++++++++------
> > > > >  src/ipa/ipu3/ipu3.cpp               |  6 ++++--
> > > > >  src/ipa/raspberrypi/raspberrypi.cpp |  2 +-
> > > > >  src/ipa/rkisp1/rkisp1.cpp           |  2 +-
> > > > >  src/libcamera/camera_sensor.cpp     | 15 +++++++++++++--
> > > > >  5 files changed, 34 insertions(+), 12 deletions(-)
> > > > >
> > > > > diff --git a/include/libcamera/ipa/core.mojom
> > > > b/include/libcamera/ipa/core.mojom
> > > > > index 74f3339e56f2..2bc3028c22d6 100644
> > > > > --- a/include/libcamera/ipa/core.mojom
> > > > > +++ b/include/libcamera/ipa/core.mojom
> > > > > @@ -172,10 +172,17 @@ module libcamera;
> > > > >   */
> > > > >
> > > > >  /**
> > > > > - * \var IPACameraSensorInfo::lineLength
> > > > > - * \brief Total line length in pixels
> > > > > + * \var IPACameraSensorInfo::minLineLength
> > > > > + * \brief The minimum line length in pixels
> > > > >   *
> > > > > - * The total line length in pixel clock periods, including blanking.
> > > > > + * The minimum allowable line length in pixel clock periods, including
> > > > blanking.
> > > > > + */
> > > > > +
> > > > > +/**
> > > > > + * \var IPACameraSensorInfo::maxLineLength
> > > > > + * \brief The maximum line length in pixels
> > > > > + *
> > > > > + * The maximum allowable line length in pixel clock periods, including
> > > > blanking.
> > > > >   */
> > > > >
> > > > >  /**
> > > > > @@ -189,7 +196,7 @@ module libcamera;
> > > > >   * To obtain the minimum frame duration:
> > > > >   *
> > > > >   * \verbatim
> > > > > -       frameDuration(s) = minFrameLength(lines) * lineLength(pixels) /
> > > > pixelRate(pixels per second)
> > > > > +       frameDuration(s) = minFrameLength(lines) * minLineLength(pixels)
> > > > / pixelRate(pixels per second)
> > > > >     \endverbatim
> > > > >   */
> > > > >
> > > > > @@ -204,7 +211,7 @@ module libcamera;
> > > > >   * To obtain the maximum frame duration:
> > > > >   *
> > > > >   * \verbatim
> > > > > -       frameDuration(s) = maxFrameLength(lines) * lineLength(pixels) /
> > > > pixelRate(pixels per second)
> > > > > +       frameDuration(s) = maxFrameLength(lines) * maxLineLength(pixels)
> > > > / pixelRate(pixels per second)
> > > > >     \endverbatim
> > > > >   */
> > > > >  struct IPACameraSensorInfo {
> > > > > @@ -217,7 +224,9 @@ struct IPACameraSensorInfo {
> > > > >       Size outputSize;
> > > > >
> > > > >       uint64 pixelRate;
> > > > > -     uint32 lineLength;
> > > > > +
> > > > > +     uint32 minLineLength;
> > > > > +     uint32 maxLineLength;
> > > > >
> > > > >       uint32 minFrameLength;
> > > > >       uint32 maxFrameLength;
> > > > > diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
> > > > > index b93a09d40c39..7e26fc5639c2 100644
> > > > > --- a/src/ipa/ipu3/ipu3.cpp
> > > > > +++ b/src/ipa/ipu3/ipu3.cpp
> > > > > @@ -336,7 +336,8 @@ int IPAIPU3::init(const IPASettings &settings,
> > > > >
> > > > >       /* Clean context */
> > > > >       context_.configuration = {};
> > > > > -     context_.configuration.sensor.lineDuration = sensorInfo.lineLength
> > > > * 1.0s / sensorInfo.pixelRate;
> > > > > +     context_.configuration.sensor.lineDuration =
> > > > sensorInfo.minLineLength
> > > > > +                                                  * 1.0s /
> > > > sensorInfo.pixelRate;
> > > >
> > > > The * should be aligned below the =. Same below.
> > > >
> > > > >
> > > > >       /* Load the tuning data file. */
> > > > >       File file(settings.configurationFile);
> > > > > @@ -499,7 +500,8 @@ int IPAIPU3::configure(const IPAConfigInfo
> > > > &configInfo,
> > > > >       context_.frameContexts.clear();
> > > > >
> > > > >       /* Initialise the sensor configuration. */
> > > > > -     context_.configuration.sensor.lineDuration =
> > > > sensorInfo_.lineLength * 1.0s / sensorInfo_.pixelRate;
> > > > > +     context_.configuration.sensor.lineDuration =
> > > > sensorInfo_.minLineLength
> > > > > +                                                  * 1.0s /
> > > > sensorInfo_.pixelRate;
> > > > >
> > > > >       /*
> > > > >        * Compute the sensor V4L2 controls to be used by the algorithms
> > > > and
> > > > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> > > > b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > > index 8d731435764e..358a119da222 100644
> > > > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > > @@ -356,7 +356,7 @@ void IPARPi::setMode(const IPACameraSensorInfo
> > > > &sensorInfo)
> > > > >        * Calculate the line length as the ratio between the line length
> > > > in
> > > > >        * pixels and the pixel rate.
> > > > >        */
> > > > > -     mode_.lineLength = sensorInfo.lineLength * (1.0s /
> > > > sensorInfo.pixelRate);
> > > > > +     mode_.lineLength = sensorInfo.minLineLength * (1.0s /
> > > > sensorInfo.pixelRate);
> > > > >
> > > > >       /*
> > > > >        * Set the frame length limits for the mode to ensure exposure and
> > > > > diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
> > > > > index 32feb1682749..ddb22d98eb41 100644
> > > > > --- a/src/ipa/rkisp1/rkisp1.cpp
> > > > > +++ b/src/ipa/rkisp1/rkisp1.cpp
> > > > > @@ -246,7 +246,7 @@ int IPARkISP1::configure([[maybe_unused]] const
> > > > IPACameraSensorInfo &info,
> > > > >       context_.configuration.hw.revision = hwRevision_;
> > > > >
> > > > >       context_.configuration.sensor.size = info.outputSize;
> > > > > -     context_.configuration.sensor.lineDuration = info.lineLength *
> > > > 1.0s / info.pixelRate;
> > > > > +     context_.configuration.sensor.lineDuration = info.minLineLength *
> > > > 1.0s / info.pixelRate;
> > > > >
> > > > >       /*
> > > > >        * When the AGC computes the new exposure values for a frame, it
> > > > needs
> > > > > diff --git a/src/libcamera/camera_sensor.cpp
> > > > b/src/libcamera/camera_sensor.cpp
> > > > > index 911fd0beae4e..83f81d655395 100644
> > > > > --- a/src/libcamera/camera_sensor.cpp
> > > > > +++ b/src/libcamera/camera_sensor.cpp
> > > > > @@ -176,6 +176,15 @@ int CameraSensor::init()
> > > > >       if (ret)
> > > > >               return ret;
> > > > >
> > > > > +     /* Set HBLANK to the minimum as a starting value. */
> > > >
> > > > I would capture the rationale here.
> > > >
> > > >         /*
> > > >          * Set HBLANK to the minimum to start with a well-defined line
> > > > length,
> > > >          * allowing IPA modules that do not modify HBLANK to use the sensor
> > > >          * minimum line length in their calculations.
> > > >          */
> > > >
> > > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > >
> > > > No need to resubmit if only those small changes are required.
> > > >
> > > > > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > > > > +     ControlList ctrl(subdev_->controls());
> > > > > +
> > > > > +     ctrl.set(V4L2_CID_HBLANK, hblank.min().get<int32_t>());
> > > > > +     ret = subdev_->setControls(&ctrl);
> > > > > +     if (ret)
> > > > > +             return ret;
> > > >
> > >
> > > Actually, doing the setControls here unconditionally is probably incorrect.
> > >
> > > If the control is read-only, we will return an error.  We probably want to
> > > do something like what I did for the IPA where we test for
> > > HBLANK::min() == HBLANK::max(), and if true, assume the control is
> > > read-only and don't do the setControl().
> > >
> > > Sorry I should have caught that, but my testing was done on sensors
> > > with adjustable HBLANK controls. I'll update the statement and post
> > > a revised patch first thing on Monday.
> > >
> >
> > I wonder if we shouldn't use (for hblank as well as per vblank) the
> > control's default value in the IPA calculations instead of assuming
> > (and here forcing) the minium value. Specifically, during the
> > IPA::configure() where we intialize values using the minium value
> > seems rather an arbitrary assumptions. After IPA::configure() the IPA
> > should be free to change H/VBlank as they like in the min/max ranges,
> > but for intiialization...
> >
> > Also most drivers (should?) update the blanking values to a sensible
> > defaul when a new mode is applied. Shouldn't we rely on their
> > selection ?
>
> Is it correct behaviour for a sensor driver to change a r/w HBLANK
> when changing mode? Changing limits for HBLANK is almost certainly the
> case, but AIUI generally controls shouldn't change values unless they
> are then invalid.
>
> I'll agree that not updating the value has annoyances when the client
> doesn't automatically compute and set HBLANK, but conversely updating
> it is annoying for cases where the app doesn't support it and you have
> deliberately set it to a long value (any mode change resets your
> chosen value, despite it being valid).
>

We've discussed the same in your review of my ar0521 changes...
I actually think it makes sense for a driver to reset blankings when a
new mode is applied to something sensible, possibily something that
maximizes the frame rate ?

You have a point, that users not aware of this change will suddenly
found the blankings to be modified, but at the same time when it comes
to user-facing features, no changing blankings when changing mode
could result in a relevant change in the produced FPS rate..

I do expect an "uninformed" userspace not to change blankings, stream
at a reasonable frame rate, change mode and maintain the same frame
rate.

"Informed" userspace should be capable of chaning blankings as they
like, so I don't expect this to impact it.

However, I understand this again is on the topic "userspace knows
everthing" vs "drivers do the right thing".

Anyway, I think we need to define a policy and align to that, whatever
it ends up being..

> libcamera always selecting the mode (even if the same) leading to a
> reset when I was trying to test configurable HBLANK was where I
> encountered this ambiguity.
>

I understand, but you're setting HBLANK outside of libcamera and
expect that not to be changed. It's annoying for debugging and
developing, I understand, but isn't it expected that the library takes
over and overrides pre-existing settings ?

>   Dave
>
> > > Regards,
> > > Naush
> > >
> > >
> > >
> > > > > +
> > > > >       return
> > > > applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff);
> > > > >  }
> > > > >
> > > > > @@ -883,10 +892,12 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo
> > > > *info) const
> > > > >               return -EINVAL;
> > > > >       }
> > > > >
> > > > > -     int32_t hblank = ctrls.get(V4L2_CID_HBLANK).get<int32_t>();
> > > > > -     info->lineLength = info->outputSize.width + hblank;
> > > > >       info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
> > > > >
> > > > > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > > > > +     info->minLineLength = info->outputSize.width +
> > > > hblank.min().get<int32_t>();
> > > > > +     info->maxLineLength = info->outputSize.width +
> > > > hblank.max().get<int32_t>();
> > > > > +
> > > > >       const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK);
> > > > >       info->minFrameLength = info->outputSize.height +
> > > > vblank.min().get<int32_t>();
> > > > >       info->maxFrameLength = info->outputSize.height +
> > > > vblank.max().get<int32_t>();
> > > >
> > > > --
> > > > Regards,
> > > >
> > > > Laurent Pinchart
> > > >
Laurent Pinchart Oct. 18, 2022, 12:07 a.m. UTC | #6
Hello,

On Mon, Oct 10, 2022 at 04:08:56PM +0200, Jacopo Mondi wrote:
> On Mon, Oct 10, 2022 at 02:44:41PM +0100, Dave Stevenson wrote:
> > On Mon, 10 Oct 2022 at 12:10, Jacopo Mondi wrote:
> > > On Sat, Oct 08, 2022 at 07:12:55AM +0100, Naushir Patuck wrote:
> > > > On Fri, 7 Oct 2022 at 23:28, Laurent Pinchart wrote:
> > > > > On Thu, Oct 06, 2022 at 02:17:35PM +0100, Naushir Patuck wrote:
> > > > > > Add fields for minimum and maximum line length (in units of pixels) to the
> > > > > > IPACameraSensorInfo structure. This replaces the existing lineLength field.
> > > > > >
> > > > > > Update the ipu3, raspberrypi and rkisp1 IPAs to use IPACameraSensorInfo::minLineLength
> > > > > > instead of IPACameraSensorInfo::lineLength, as logically we will always want to
> > > > > > use the fastest sensor readout by default.
> > > > > >
> > > > > > Since the IPAs now use minLineLength for their calculations, set the starting
> > > > > > value of the V4L2_CID_HBLANK control to its minimum in CameraSensor::init().
> > > > > >
> > > > > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > > > > > Tested-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > > > > ---
> > > > > >  include/libcamera/ipa/core.mojom    | 21 +++++++++++++++------
> > > > > >  src/ipa/ipu3/ipu3.cpp               |  6 ++++--
> > > > > >  src/ipa/raspberrypi/raspberrypi.cpp |  2 +-
> > > > > >  src/ipa/rkisp1/rkisp1.cpp           |  2 +-
> > > > > >  src/libcamera/camera_sensor.cpp     | 15 +++++++++++++--
> > > > > >  5 files changed, 34 insertions(+), 12 deletions(-)
> > > > > >
> > > > > > diff --git a/include/libcamera/ipa/core.mojom b/include/libcamera/ipa/core.mojom
> > > > > > index 74f3339e56f2..2bc3028c22d6 100644
> > > > > > --- a/include/libcamera/ipa/core.mojom
> > > > > > +++ b/include/libcamera/ipa/core.mojom
> > > > > > @@ -172,10 +172,17 @@ module libcamera;
> > > > > >   */
> > > > > >
> > > > > >  /**
> > > > > > - * \var IPACameraSensorInfo::lineLength
> > > > > > - * \brief Total line length in pixels
> > > > > > + * \var IPACameraSensorInfo::minLineLength
> > > > > > + * \brief The minimum line length in pixels
> > > > > >   *
> > > > > > - * The total line length in pixel clock periods, including blanking.
> > > > > > + * The minimum allowable line length in pixel clock periods, including blanking.
> > > > > > + */
> > > > > > +
> > > > > > +/**
> > > > > > + * \var IPACameraSensorInfo::maxLineLength
> > > > > > + * \brief The maximum line length in pixels
> > > > > > + *
> > > > > > + * The maximum allowable line length in pixel clock periods, including blanking.
> > > > > >   */
> > > > > >
> > > > > >  /**
> > > > > > @@ -189,7 +196,7 @@ module libcamera;
> > > > > >   * To obtain the minimum frame duration:
> > > > > >   *
> > > > > >   * \verbatim
> > > > > > -       frameDuration(s) = minFrameLength(lines) * lineLength(pixels) / pixelRate(pixels per second)
> > > > > > +       frameDuration(s) = minFrameLength(lines) * minLineLength(pixels) / pixelRate(pixels per second)
> > > > > >     \endverbatim
> > > > > >   */
> > > > > >
> > > > > > @@ -204,7 +211,7 @@ module libcamera;
> > > > > >   * To obtain the maximum frame duration:
> > > > > >   *
> > > > > >   * \verbatim
> > > > > > -       frameDuration(s) = maxFrameLength(lines) * lineLength(pixels) / pixelRate(pixels per second)
> > > > > > +       frameDuration(s) = maxFrameLength(lines) * maxLineLength(pixels) / pixelRate(pixels per second)
> > > > > >     \endverbatim
> > > > > >   */
> > > > > >  struct IPACameraSensorInfo {
> > > > > > @@ -217,7 +224,9 @@ struct IPACameraSensorInfo {
> > > > > >       Size outputSize;
> > > > > >
> > > > > >       uint64 pixelRate;
> > > > > > -     uint32 lineLength;
> > > > > > +
> > > > > > +     uint32 minLineLength;
> > > > > > +     uint32 maxLineLength;
> > > > > >
> > > > > >       uint32 minFrameLength;
> > > > > >       uint32 maxFrameLength;
> > > > > > diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
> > > > > > index b93a09d40c39..7e26fc5639c2 100644
> > > > > > --- a/src/ipa/ipu3/ipu3.cpp
> > > > > > +++ b/src/ipa/ipu3/ipu3.cpp
> > > > > > @@ -336,7 +336,8 @@ int IPAIPU3::init(const IPASettings &settings,
> > > > > >
> > > > > >       /* Clean context */
> > > > > >       context_.configuration = {};
> > > > > > -     context_.configuration.sensor.lineDuration = sensorInfo.lineLength * 1.0s / sensorInfo.pixelRate;
> > > > > > +     context_.configuration.sensor.lineDuration = sensorInfo.minLineLength
> > > > > > +                                                  * 1.0s / sensorInfo.pixelRate;
> > > > >
> > > > > The * should be aligned below the =. Same below.
> > > > >
> > > > > >
> > > > > >       /* Load the tuning data file. */
> > > > > >       File file(settings.configurationFile);
> > > > > > @@ -499,7 +500,8 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo,
> > > > > >       context_.frameContexts.clear();
> > > > > >
> > > > > >       /* Initialise the sensor configuration. */
> > > > > > -     context_.configuration.sensor.lineDuration = sensorInfo_.lineLength * 1.0s / sensorInfo_.pixelRate;
> > > > > > +     context_.configuration.sensor.lineDuration = sensorInfo_.minLineLength
> > > > > > +                                                  * 1.0s / sensorInfo_.pixelRate;
> > > > > >
> > > > > >       /*
> > > > > >        * Compute the sensor V4L2 controls to be used by the algorithms and
> > > > > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > > > index 8d731435764e..358a119da222 100644
> > > > > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > > > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > > > @@ -356,7 +356,7 @@ void IPARPi::setMode(const IPACameraSensorInfo &sensorInfo)
> > > > > >        * Calculate the line length as the ratio between the line length in
> > > > > >        * pixels and the pixel rate.
> > > > > >        */
> > > > > > -     mode_.lineLength = sensorInfo.lineLength * (1.0s / sensorInfo.pixelRate);
> > > > > > +     mode_.lineLength = sensorInfo.minLineLength * (1.0s / sensorInfo.pixelRate);
> > > > > >
> > > > > >       /*
> > > > > >        * Set the frame length limits for the mode to ensure exposure and
> > > > > > diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
> > > > > > index 32feb1682749..ddb22d98eb41 100644
> > > > > > --- a/src/ipa/rkisp1/rkisp1.cpp
> > > > > > +++ b/src/ipa/rkisp1/rkisp1.cpp
> > > > > > @@ -246,7 +246,7 @@ int IPARkISP1::configure([[maybe_unused]] const IPACameraSensorInfo &info,
> > > > > >       context_.configuration.hw.revision = hwRevision_;
> > > > > >
> > > > > >       context_.configuration.sensor.size = info.outputSize;
> > > > > > -     context_.configuration.sensor.lineDuration = info.lineLength * 1.0s / info.pixelRate;
> > > > > > +     context_.configuration.sensor.lineDuration = info.minLineLength * 1.0s / info.pixelRate;
> > > > > >
> > > > > >       /*
> > > > > >        * When the AGC computes the new exposure values for a frame, it needs
> > > > > > diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp
> > > > > > index 911fd0beae4e..83f81d655395 100644
> > > > > > --- a/src/libcamera/camera_sensor.cpp
> > > > > > +++ b/src/libcamera/camera_sensor.cpp
> > > > > > @@ -176,6 +176,15 @@ int CameraSensor::init()
> > > > > >       if (ret)
> > > > > >               return ret;
> > > > > >
> > > > > > +     /* Set HBLANK to the minimum as a starting value. */
> > > > >
> > > > > I would capture the rationale here.
> > > > >
> > > > >         /*
> > > > >          * Set HBLANK to the minimum to start with a well-defined line length,
> > > > >          * allowing IPA modules that do not modify HBLANK to use the sensor
> > > > >          * minimum line length in their calculations.
> > > > >          */
> > > > >
> > > > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > > >
> > > > > No need to resubmit if only those small changes are required.
> > > > >
> > > > > > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > > > > > +     ControlList ctrl(subdev_->controls());
> > > > > > +
> > > > > > +     ctrl.set(V4L2_CID_HBLANK, hblank.min().get<int32_t>());
> > > > > > +     ret = subdev_->setControls(&ctrl);
> > > > > > +     if (ret)
> > > > > > +             return ret;
> > > >
> > > > Actually, doing the setControls here unconditionally is probably incorrect.
> > > >
> > > > If the control is read-only, we will return an error.  We probably want to
> > > > do something like what I did for the IPA where we test for
> > > > HBLANK::min() == HBLANK::max(), and if true, assume the control is
> > > > read-only and don't do the setControl().
> > > >
> > > > Sorry I should have caught that, but my testing was done on sensors
> > > > with adjustable HBLANK controls. I'll update the statement and post
> > > > a revised patch first thing on Monday.
> > >
> > > I wonder if we shouldn't use (for hblank as well as per vblank) the
> > > control's default value in the IPA calculations instead of assuming
> > > (and here forcing) the minium value. Specifically, during the
> > > IPA::configure() where we intialize values using the minium value
> > > seems rather an arbitrary assumptions. After IPA::configure() the IPA
> > > should be free to change H/VBlank as they like in the min/max ranges,
> > > but for intiialization...

It is arbitrary, but I think it will lead to less abitrary results than
using the default value reported by the sensor driver. There's no policy
for the hblank default in the V4L2 API, so you would essentially get a
completely unpredictable behaviour. With the minimum it gets a bit
better. IPA modules should control hblank in any case, so it shouldn't
matter too much what we do here in the long run. This discussion is
about the transition, to avoid breaking IPU3 (which Kieran has
successfully tested on Soraka) and RkISP1 (which I'm about to test).

> > > Also most drivers (should?) update the blanking values to a sensible
> > > defaul when a new mode is applied. Shouldn't we rely on their
> > > selection ?
> >
> > Is it correct behaviour for a sensor driver to change a r/w HBLANK
> > when changing mode? Changing limits for HBLANK is almost certainly the
> > case, but AIUI generally controls shouldn't change values unless they
> > are then invalid.
> >
> > I'll agree that not updating the value has annoyances when the client
> > doesn't automatically compute and set HBLANK, but conversely updating
> > it is annoying for cases where the app doesn't support it and you have
> > deliberately set it to a long value (any mode change resets your
> > chosen value, despite it being valid).
> 
> We've discussed the same in your review of my ar0521 changes...
> I actually think it makes sense for a driver to reset blankings when a
> new mode is applied to something sensible, possibily something that
> maximizes the frame rate ?
> 
> You have a point, that users not aware of this change will suddenly
> found the blankings to be modified, but at the same time when it comes
> to user-facing features, no changing blankings when changing mode
> could result in a relevant change in the produced FPS rate..

Not only in the FPS. Consider a case with two modes, lores and hires. As
sensors typically express horizontal blanking as a horizontal total
size, the hblank control max value will be larger for lores than hires.
If the sensor were to set the default hblank to a value valid for lores
but not hires, switching from lores -> hires -> lores would change the
effective hblank value even if userspace doesn't touch the hblank
control at all.

> I do expect an "uninformed" userspace not to change blankings, stream
> at a reasonable frame rate, change mode and maintain the same frame
> rate.
> 
> "Informed" userspace should be capable of chaning blankings as they
> like, so I don't expect this to impact it.

Lots of mode-based drivers hardcode the blanking values. This may result
in the same or different frames rates for different modes, but the frame
rate is usually a "standard" round value (e.g. 25fps, 30fps, 60fps, ...
not 34.12 fps). When such a driver is moved to configurable h/v blank,
if we don't reset the current h/v blank values when changing the mode,
the frame rates will indeed become quite random. I thus think resetting
the values make sense.

On the other hand, V4L2 doesn't generally reset controls that have a
valid valud on mode change. This could lead to applications getting
confused, but I agree that, if an application has set the h/v blank
values explicitly, it should likely be able to set them after a mode set
too, and have full control of the device. The issue raised by Dave below
(*) is relevant though.

> However, I understand this again is on the topic "userspace knows
> everthing" vs "drivers do the right thing".
> 
> Anyway, I think we need to define a policy and align to that, whatever
> it ends up being..

Agreed.

> > libcamera always selecting the mode (even if the same) leading to a
> > reset when I was trying to test configurable HBLANK was where I
> > encountered this ambiguity.
> 
> I understand, but you're setting HBLANK outside of libcamera and
> expect that not to be changed. It's annoying for debugging and
> developing, I understand, but isn't it expected that the library takes
> over and overrides pre-existing settings ?

(*) It's not just about libcamera. There are lots of applications that
don't touch h/v blank, and being able to set them with a separate tool
(v4l2-ctl for instance) before running those applications is a useful
feature. V4L2 retains control values when a device is closed for this
very purpose. It can be useful during development, but also during
normal operation. I would argue it was a bit of a historical mistake to
allow this for complex cameras though, it's a fragile hack at best. The
question here is whether we can disable this hack for blanking controls
or not. At this point, I would tend to say yes.

I think the h/v blank issues should be discussed on the linux-media
mailing list, and I'd bring up in the discussion the idea of defining
new HTS/VTS controls. How to transition existing sensor drivers without
breaking anything would be interesting to explore.

> > > > > > +
> > > > > >       return applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff);
> > > > > >  }
> > > > > >
> > > > > > @@ -883,10 +892,12 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const
> > > > > >               return -EINVAL;
> > > > > >       }
> > > > > >
> > > > > > -     int32_t hblank = ctrls.get(V4L2_CID_HBLANK).get<int32_t>();
> > > > > > -     info->lineLength = info->outputSize.width + hblank;
> > > > > >       info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
> > > > > >
> > > > > > +     const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
> > > > > > +     info->minLineLength = info->outputSize.width + hblank.min().get<int32_t>();
> > > > > > +     info->maxLineLength = info->outputSize.width + hblank.max().get<int32_t>();
> > > > > > +
> > > > > >       const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK);
> > > > > >       info->minFrameLength = info->outputSize.height + vblank.min().get<int32_t>();
> > > > > >       info->maxFrameLength = info->outputSize.height + vblank.max().get<int32_t>();

Patch
diff mbox series

diff --git a/include/libcamera/ipa/core.mojom b/include/libcamera/ipa/core.mojom
index 74f3339e56f2..2bc3028c22d6 100644
--- a/include/libcamera/ipa/core.mojom
+++ b/include/libcamera/ipa/core.mojom
@@ -172,10 +172,17 @@  module libcamera;
  */
 
 /**
- * \var IPACameraSensorInfo::lineLength
- * \brief Total line length in pixels
+ * \var IPACameraSensorInfo::minLineLength
+ * \brief The minimum line length in pixels
  *
- * The total line length in pixel clock periods, including blanking.
+ * The minimum allowable line length in pixel clock periods, including blanking.
+ */
+
+/**
+ * \var IPACameraSensorInfo::maxLineLength
+ * \brief The maximum line length in pixels
+ *
+ * The maximum allowable line length in pixel clock periods, including blanking.
  */
 
 /**
@@ -189,7 +196,7 @@  module libcamera;
  * To obtain the minimum frame duration:
  *
  * \verbatim
-       frameDuration(s) = minFrameLength(lines) * lineLength(pixels) / pixelRate(pixels per second)
+       frameDuration(s) = minFrameLength(lines) * minLineLength(pixels) / pixelRate(pixels per second)
    \endverbatim
  */
 
@@ -204,7 +211,7 @@  module libcamera;
  * To obtain the maximum frame duration:
  *
  * \verbatim
-       frameDuration(s) = maxFrameLength(lines) * lineLength(pixels) / pixelRate(pixels per second)
+       frameDuration(s) = maxFrameLength(lines) * maxLineLength(pixels) / pixelRate(pixels per second)
    \endverbatim
  */
 struct IPACameraSensorInfo {
@@ -217,7 +224,9 @@  struct IPACameraSensorInfo {
 	Size outputSize;
 
 	uint64 pixelRate;
-	uint32 lineLength;
+
+	uint32 minLineLength;
+	uint32 maxLineLength;
 
 	uint32 minFrameLength;
 	uint32 maxFrameLength;
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index b93a09d40c39..7e26fc5639c2 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -336,7 +336,8 @@  int IPAIPU3::init(const IPASettings &settings,
 
 	/* Clean context */
 	context_.configuration = {};
-	context_.configuration.sensor.lineDuration = sensorInfo.lineLength * 1.0s / sensorInfo.pixelRate;
+	context_.configuration.sensor.lineDuration = sensorInfo.minLineLength
+						     * 1.0s / sensorInfo.pixelRate;
 
 	/* Load the tuning data file. */
 	File file(settings.configurationFile);
@@ -499,7 +500,8 @@  int IPAIPU3::configure(const IPAConfigInfo &configInfo,
 	context_.frameContexts.clear();
 
 	/* Initialise the sensor configuration. */
-	context_.configuration.sensor.lineDuration = sensorInfo_.lineLength * 1.0s / sensorInfo_.pixelRate;
+	context_.configuration.sensor.lineDuration = sensorInfo_.minLineLength
+						     * 1.0s / sensorInfo_.pixelRate;
 
 	/*
 	 * Compute the sensor V4L2 controls to be used by the algorithms and
diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
index 8d731435764e..358a119da222 100644
--- a/src/ipa/raspberrypi/raspberrypi.cpp
+++ b/src/ipa/raspberrypi/raspberrypi.cpp
@@ -356,7 +356,7 @@  void IPARPi::setMode(const IPACameraSensorInfo &sensorInfo)
 	 * Calculate the line length as the ratio between the line length in
 	 * pixels and the pixel rate.
 	 */
-	mode_.lineLength = sensorInfo.lineLength * (1.0s / sensorInfo.pixelRate);
+	mode_.lineLength = sensorInfo.minLineLength * (1.0s / sensorInfo.pixelRate);
 
 	/*
 	 * Set the frame length limits for the mode to ensure exposure and
diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
index 32feb1682749..ddb22d98eb41 100644
--- a/src/ipa/rkisp1/rkisp1.cpp
+++ b/src/ipa/rkisp1/rkisp1.cpp
@@ -246,7 +246,7 @@  int IPARkISP1::configure([[maybe_unused]] const IPACameraSensorInfo &info,
 	context_.configuration.hw.revision = hwRevision_;
 
 	context_.configuration.sensor.size = info.outputSize;
-	context_.configuration.sensor.lineDuration = info.lineLength * 1.0s / info.pixelRate;
+	context_.configuration.sensor.lineDuration = info.minLineLength * 1.0s / info.pixelRate;
 
 	/*
 	 * When the AGC computes the new exposure values for a frame, it needs
diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp
index 911fd0beae4e..83f81d655395 100644
--- a/src/libcamera/camera_sensor.cpp
+++ b/src/libcamera/camera_sensor.cpp
@@ -176,6 +176,15 @@  int CameraSensor::init()
 	if (ret)
 		return ret;
 
+	/* Set HBLANK to the minimum as a starting value. */
+	const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
+	ControlList ctrl(subdev_->controls());
+
+	ctrl.set(V4L2_CID_HBLANK, hblank.min().get<int32_t>());
+	ret = subdev_->setControls(&ctrl);
+	if (ret)
+		return ret;
+
 	return applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff);
 }
 
@@ -883,10 +892,12 @@  int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const
 		return -EINVAL;
 	}
 
-	int32_t hblank = ctrls.get(V4L2_CID_HBLANK).get<int32_t>();
-	info->lineLength = info->outputSize.width + hblank;
 	info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
 
+	const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
+	info->minLineLength = info->outputSize.width + hblank.min().get<int32_t>();
+	info->maxLineLength = info->outputSize.width + hblank.max().get<int32_t>();
+
 	const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK);
 	info->minFrameLength = info->outputSize.height + vblank.min().get<int32_t>();
 	info->maxFrameLength = info->outputSize.height + vblank.max().get<int32_t>();