[libcamera-devel,v5,00/19] ipu3: rework pipe confiuguration
diff mbox

Message ID 20200731153320.58107-1-jacopo@jmondi.org
State Superseded, archived
Delegated to: Jacopo Mondi
Headers show

Commit Message

Jacopo Mondi July 31, 2020, 3:33 p.m. UTC
I have addressed minor comments and added a few more details in comment and
documentation here and there.

I have simplified a bit the ImgU pipe configuration by removing not-required
casts, by making the code a bit less dense, and with a small rename.

The diff between v4 and v5 is so minimal I reported the full diff below.

I tested results against the IPU3 pipe configuration tool by instrumenting
a version of it to run on a set of known values and compare the results between
its calculation and libcamera:
https://jmondi.org/cgit/intel-ipu3-pipe-config/commit/?id=78bc59f8bfe8c14908f612008a62edc621660cf3

All patches reviewed but I'm not pushing yet as I would like Kieran's ack, as
he's working on JPEG and moving the ground under his feet while developing seems
not nice.


Thanks
   j

Jacopo Mondi (19):
  libcamera: ipu3: Rename mbusCodesToInfo
  libcamera: utils: Add alignUp and alignDown functions
  libcamera: geometry: Add isNull() function to Rectangle class
  libcamera: ipu3: Remove streams from generateConfiguration
  libcamera: ipu3: Make sure the config is valid
  libcamera: ipu3: cio2: Report format and sizes
  libcamera: ipu3: Do not overwrite StreamConfiguration
  libcamera: ipu3: Report StreamFormats
  libcamera: ipu3: Remove initialization of Size
  libcamera: ipu3: Validate the stream combination
  libcamera: camera: Zero streams before validate()
  libcamera: ipu3: cio2: Add a const sensor() method
  libcamera: ipu3: Adjust and assign streams in validate()
  libcamera: ipu3: Remove streams from IPU3CameraConfiguration
  libcamera: ipu3: Remove camera_ from IPU3CameraConfiguration
  libcamera: ipu3: imgu: Calculate ImgU pipe configuration
  libcamera: ipu3: Validate the pipe configuration
  libcamera: ipu3: Configure ImgU with the computed parameters
  libcamera: ipu3: imgu: Rename configureInput()

 include/libcamera/geometry.h         |   1 +
 include/libcamera/internal/utils.h   |  10 +
 src/libcamera/camera.cpp             |   4 +-
 src/libcamera/geometry.cpp           |   6 +
 src/libcamera/pipeline/ipu3/cio2.cpp |  54 +++-
 src/libcamera/pipeline/ipu3/cio2.h   |   6 +
 src/libcamera/pipeline/ipu3/imgu.    |   0
 src/libcamera/pipeline/ipu3/imgu.cpp | 386 +++++++++++++++++++++++-
 src/libcamera/pipeline/ipu3/imgu.h   |  22 +-
 src/libcamera/pipeline/ipu3/ipu3.cpp | 424 +++++++++++++--------------
 src/libcamera/utils.cpp              |  16 +
 test/geometry.cpp                    |  14 +
 test/utils.cpp                       |  11 +
 13 files changed, 714 insertions(+), 240 deletions(-)
 create mode 100644 src/libcamera/pipeline/ipu3/imgu.

--
2.27.0

Comments

Laurent Pinchart July 31, 2020, 3:41 p.m. UTC | #1
Hi Jacopo,

Thank you for the patches.

On Fri, Jul 31, 2020 at 05:33:01PM +0200, Jacopo Mondi wrote:
> I have addressed minor comments and added a few more details in comment and
> documentation here and there.
> 
> I have simplified a bit the ImgU pipe configuration by removing not-required
> casts, by making the code a bit less dense, and with a small rename.
> 
> The diff between v4 and v5 is so minimal I reported the full diff below.

I'll thus review it below :-)

> I tested results against the IPU3 pipe configuration tool by instrumenting
> a version of it to run on a set of known values and compare the results between
> its calculation and libcamera:
> https://jmondi.org/cgit/intel-ipu3-pipe-config/commit/?id=78bc59f8bfe8c14908f612008a62edc621660cf3
> 
> All patches reviewed but I'm not pushing yet as I would like Kieran's ack, as
> he's working on JPEG and moving the ground under his feet while developing seems
> not nice.
> 
> diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp
> index a3ea3eabe318..cf26980c75f1 100644
> --- a/src/libcamera/pipeline/ipu3/imgu.cpp
> +++ b/src/libcamera/pipeline/ipu3/imgu.cpp
> @@ -25,6 +25,14 @@ LOG_DECLARE_CATEGORY(IPU3)
> 
>  namespace {
> 
> +/*
> + * The procedure to calculate the ImgU pipe configuration has been ported
> + * from the pipe_config.py python script, available at:
> + * https://github.com/intel/intel-ipu3-pipecfg
> + * at revision: 61e83f2f7606 ("Add more information into README")
> + */
> +
>  static constexpr unsigned int FILTER_H = 4;
> 
>  static constexpr unsigned int IF_ALIGN_W = 2;
> @@ -103,10 +111,8 @@ float findScaleFactor(float sf, const std::vector<float> &range,
> 
>  bool isSameRatio(const Size &in, const Size &out)
>  {
> -	float inRatio = static_cast<float>(in.width) /
> -			static_cast<float>(in.height);
> -	float outRatio = static_cast<float>(out.width) /
> -			 static_cast<float>(out.height);
> +	float inRatio = static_cast<float>(in.width) / in.height;
> +	float outRatio = static_cast<float>(out.width) / out.height;
> 
>  	if (std::abs(inRatio - outRatio) > 0.1)
>  		return false;
> @@ -123,16 +129,18 @@ void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
>  	float bdsHeight;
> 
>  	if (!isSameRatio(pipe->input, gdc)) {
> -		bool found = false;
> -		float estIFHeight = static_cast<float>(iif.width *  gdc.height) /
> +		float estIFHeight = (iif.width * gdc.height) /
>  				    static_cast<float>(gdc.width);
>  		estIFHeight = utils::clamp<float>(estIFHeight, minIFHeight, iif.height);
> +		bool found = false;
> +
>  		ifHeight = utils::alignUp(estIFHeight, IF_ALIGN_H);
> -		while (ifHeight >= minIFHeight &&
> -		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
> -			bdsHeight = static_cast<float>(ifHeight) / bdsSF;
> +		while (ifHeight >= minIFHeight && ifHeight / bdsSF >= minBDSHeight) {
> +
> +			bdsHeight = ifHeight / bdsSF;
>  			if (std::fmod(bdsHeight, 1.0) == 0) {
>  				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
> +
>  				if (!(bdsIntHeight % BDS_ALIGN_H)) {
>  					found = true;
>  					break;
> @@ -143,11 +151,12 @@ void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
>  		}
> 
>  		ifHeight = utils::alignUp(estIFHeight, IF_ALIGN_H);
> -		while (ifHeight <= iif.height &&
> -		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
> -			bdsHeight = static_cast<float>(ifHeight) / bdsSF;
> +		while (ifHeight <= iif.height && ifHeight / bdsSF >= minBDSHeight) {
> +
> +			bdsHeight = ifHeight / bdsSF;
>  			if (std::fmod(bdsHeight, 1.0) == 0) {
>  				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
> +
>  				if (!(bdsIntHeight % BDS_ALIGN_H)) {
>  					found = true;
>  					break;
> @@ -159,14 +168,15 @@ void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
> 
>  		if (found) {
>  			unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
> +
>  			pipeConfigs.push_back({ bdsSF, { iif.width, ifHeight },
>  						{ bdsWidth, bdsIntHeight }, gdc });
>  			return;
>  		}
>  	} else {
>  		ifHeight = utils::alignUp(iif.height, IF_ALIGN_H);
> -		while (ifHeight > minIFHeight &&
> -		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
> +		while (ifHeight > minIFHeight && ifHeight / bdsSF >= minBDSHeight) {
> +
>  			bdsHeight = ifHeight / bdsSF;
>  			if (std::fmod(ifHeight, 1.0) == 0 && std::fmod(bdsHeight, 1.0) == 0) {
>  				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
> @@ -183,8 +193,7 @@ void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
>  	}
>  }
> 
> -void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc,
> -		  float bdsSF)
> +void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc, float bdsSF)
>  {
>  	unsigned int minBDSWidth = gdc.width + FILTER_H * 2;
> 
> @@ -218,15 +227,14 @@ void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc,
>  Size calculateGDC(ImgUDevice::Pipe *pipe)
>  {
>  	const Size &in = pipe->input;
> -	const Size &main = pipe->output;
> +	const Size &main = pipe->main;
>  	const Size &vf = pipe->viewfinder;
>  	Size gdc;
> 
>  	if (!vf.isNull()) {
>  		gdc.width = main.width;
> 
> -		float ratio = static_cast<float>(main.width * vf.height) /
> -			      static_cast<float>(vf.width);
> +		float ratio = (main.width * vf.height) / static_cast<float>(vf.width);
>  		gdc.height = std::max(static_cast<float>(main.height), ratio);
> 
>  		return gdc;
> @@ -237,14 +245,13 @@ Size calculateGDC(ImgUDevice::Pipe *pipe)
>  		return gdc;
>  	}
> 
> -	float totalSF = static_cast<float>(in.width) /
> -			static_cast<float>(main.width);
> +	float totalSF = static_cast<float>(in.width) / main.width;
>  	float bdsSF = totalSF > 2 ? 2 : 1;
>  	float yuvSF = totalSF / bdsSF;
>  	float sf = findScaleFactor(yuvSF, gdcScalingFactors);
> 
> -	gdc.width = static_cast<float>(main.width) * sf;
> -	gdc.height = static_cast<float>(main.height) * sf;
> +	gdc.width = main.width * sf;
> +	gdc.height = main.height * sf;
> 
>  	return gdc;
>  }
> @@ -259,6 +266,7 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)
>  	float ifCropH = static_cast<float>(in.height - pipe.iif.height);
>  	float gdcCropW = static_cast<float>(pipe.bds.width - pipe.gdc.width) * pipe.bds_sf;
>  	float gdcCropH = static_cast<float>(pipe.bds.height - pipe.gdc.height) * pipe.bds_sf;
> +
>  	fov.w = (inW - (ifCropW + gdcCropW)) / inW;
>  	fov.h = (inH - (ifCropH + gdcCropH)) / inH;
> 
> @@ -304,11 +312,11 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)
>   * \var Pipe::input
>   * \brief The input image size
>   *
> - * \var Pipe::output
> + * \var Pipe::main
>   * \brief The requested main output size
>   *
>   * \var Pipe::viewfinder
> - * \brief The requested viewfinder size
> + * \brief The requested viewfinder output size
>   */
> 
>  /**
> @@ -378,7 +386,7 @@ ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe)
> 
>  	LOG(IPU3, Debug) << "Calculating pipe configuration for: ";
>  	LOG(IPU3, Debug) << "input: " << pipe->input.toString();
> -	LOG(IPU3, Debug) << "main: " << pipe->output.toString();
> +	LOG(IPU3, Debug) << "main: " << pipe->main.toString();
>  	LOG(IPU3, Debug) << "vf: " << pipe->viewfinder.toString();
> 
>  	const Size &in = pipe->input;
> @@ -387,9 +395,9 @@ ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe)
>  	unsigned int ifWidth = utils::alignUp(in.width, IF_ALIGN_W);
>  	unsigned int ifHeight = in.height;
>  	unsigned int minIfWidth = in.width - IF_CROP_MAX_W;
> -	float bdsSF = static_cast<float>(in.width) /
> -		      static_cast<float>(gdc.width);
> +	float bdsSF = static_cast<float>(in.width) / gdc.width;
>  	float sf = findScaleFactor(bdsSF, bdsScalingFactors, true);
> +
>  	while (ifWidth >= minIfWidth) {
>  		Size iif{ ifWidth, ifHeight };
>  		calculateBDS(pipe, iif, gdc, sf);
> diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h
> index ff8dab7d645c..c73ac5a5a37c 100644
> --- a/src/libcamera/pipeline/ipu3/imgu.h
> +++ b/src/libcamera/pipeline/ipu3/imgu.h
> @@ -37,7 +37,7 @@ public:
> 
>  	struct Pipe {
>  		Size input;
> -		Size output;
> +		Size main;
>  		Size viewfinder;
>  	};
> 
> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> index 06afc7d79dac..161a88da8497 100644
> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> @@ -225,11 +225,12 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate()
>  			 * margins from the CIO2 output frame size.
>  			 *
>  			 * The ImgU outputs needs to be strictly smaller than
> -			 * the CIO2 output frame and rounded down to 64
> -			 * pixels in width and 32 pixels in height. This comes
> -			 * from inspecting the pipe configuration script results
> -			 * and the available suggested configurations in the
> -			 * ChromeOS BSP .xml camera tuning files.
> +			 * the CIO2 output frame and rounded down to 64 pixels
> +			 * in width and 32 pixels in height. This assumption
> +			 * comes from inspecting the pipe configuration script
> +			 * results and the available suggested configurations in
> +			 * the ChromeOS BSP .xml camera tuning files and shall
> +			 * be validated.
>  			 *
>  			 * \todo Clarify what are the hardware constraints
>  			 * that require this alignements, if any. It might
> @@ -267,9 +268,9 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate()
>  				cfg->setStream(const_cast<Stream *>(&data_->outStream_));
>  				mainOutputAvailable = false;
> 
> -				pipe.output = cfg->size;
> +				pipe.main = cfg->size;
>  				if (yuvCount == 1)
> -					pipe.viewfinder = pipe.output;
> +					pipe.viewfinder = pipe.main;
> 
>  				LOG(IPU3, Debug) << "Assigned " << cfg->toString()
>  						 << " to the main output";
> @@ -333,8 +334,8 @@ CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera,
>  			 * to the ImgU  maximum output size) and aligned down to
>  			 * the required frame margin.
>  			 *
> -			 * The alignment constraints should be clarified
> -			 * as per the todo item in validate().
> +			 * \todo Clarify the alignment constraints as exaplained

s/exaplained/explained/

> +			 * in validate()
>  			 */
>  			size = sensorResolution.boundedTo(IMGU_OUTPUT_MAX_SIZE);
>  			size.width = utils::alignDown(size.width - 1,
> 
> Jacopo Mondi (19):
>   libcamera: ipu3: Rename mbusCodesToInfo
>   libcamera: utils: Add alignUp and alignDown functions
>   libcamera: geometry: Add isNull() function to Rectangle class
>   libcamera: ipu3: Remove streams from generateConfiguration
>   libcamera: ipu3: Make sure the config is valid
>   libcamera: ipu3: cio2: Report format and sizes
>   libcamera: ipu3: Do not overwrite StreamConfiguration
>   libcamera: ipu3: Report StreamFormats
>   libcamera: ipu3: Remove initialization of Size
>   libcamera: ipu3: Validate the stream combination
>   libcamera: camera: Zero streams before validate()
>   libcamera: ipu3: cio2: Add a const sensor() method
>   libcamera: ipu3: Adjust and assign streams in validate()
>   libcamera: ipu3: Remove streams from IPU3CameraConfiguration
>   libcamera: ipu3: Remove camera_ from IPU3CameraConfiguration
>   libcamera: ipu3: imgu: Calculate ImgU pipe configuration
>   libcamera: ipu3: Validate the pipe configuration
>   libcamera: ipu3: Configure ImgU with the computed parameters
>   libcamera: ipu3: imgu: Rename configureInput()
> 
>  include/libcamera/geometry.h         |   1 +
>  include/libcamera/internal/utils.h   |  10 +
>  src/libcamera/camera.cpp             |   4 +-
>  src/libcamera/geometry.cpp           |   6 +
>  src/libcamera/pipeline/ipu3/cio2.cpp |  54 +++-
>  src/libcamera/pipeline/ipu3/cio2.h   |   6 +
>  src/libcamera/pipeline/ipu3/imgu.    |   0
>  src/libcamera/pipeline/ipu3/imgu.cpp | 386 +++++++++++++++++++++++-
>  src/libcamera/pipeline/ipu3/imgu.h   |  22 +-
>  src/libcamera/pipeline/ipu3/ipu3.cpp | 424 +++++++++++++--------------
>  src/libcamera/utils.cpp              |  16 +
>  test/geometry.cpp                    |  14 +
>  test/utils.cpp                       |  11 +
>  13 files changed, 714 insertions(+), 240 deletions(-)
>  create mode 100644 src/libcamera/pipeline/ipu3/imgu.
>
Kieran Bingham Aug. 3, 2020, 9:20 a.m. UTC | #2
Hi Jacopo,

I've gone through this series quickly, and my work is based upon it.

You already seem to have two RB tags for each patch, so rather than do a
detailed review, I'll just say "Acked-by: Kieran Bingham
<kieran.bingham@ideasonboard.com>" for the whole series, and I'm happy
to get this in and keep pushing forwards :-)

--
Kieran


On 31/07/2020 16:33, Jacopo Mondi wrote:
> I have addressed minor comments and added a few more details in comment and
> documentation here and there.
> 
> I have simplified a bit the ImgU pipe configuration by removing not-required
> casts, by making the code a bit less dense, and with a small rename.
> 
> The diff between v4 and v5 is so minimal I reported the full diff below.
> 
> I tested results against the IPU3 pipe configuration tool by instrumenting
> a version of it to run on a set of known values and compare the results between
> its calculation and libcamera:
> https://jmondi.org/cgit/intel-ipu3-pipe-config/commit/?id=78bc59f8bfe8c14908f612008a62edc621660cf3
> 
> All patches reviewed but I'm not pushing yet as I would like Kieran's ack, as
> he's working on JPEG and moving the ground under his feet while developing seems
> not nice.
> 
> diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp
> index a3ea3eabe318..cf26980c75f1 100644
> --- a/src/libcamera/pipeline/ipu3/imgu.cpp
> +++ b/src/libcamera/pipeline/ipu3/imgu.cpp
> @@ -25,6 +25,14 @@ LOG_DECLARE_CATEGORY(IPU3)
> 
>  namespace {
> 
> +/*
> + * The procedure to calculate the ImgU pipe configuration has been ported
> + * from the pipe_config.py python script, available at:
> + * https://github.com/intel/intel-ipu3-pipecfg
> + * at revision: 61e83f2f7606 ("Add more information into README")
> + */
> +
>  static constexpr unsigned int FILTER_H = 4;
> 
>  static constexpr unsigned int IF_ALIGN_W = 2;
> @@ -103,10 +111,8 @@ float findScaleFactor(float sf, const std::vector<float> &range,
> 
>  bool isSameRatio(const Size &in, const Size &out)
>  {
> -	float inRatio = static_cast<float>(in.width) /
> -			static_cast<float>(in.height);
> -	float outRatio = static_cast<float>(out.width) /
> -			 static_cast<float>(out.height);
> +	float inRatio = static_cast<float>(in.width) / in.height;
> +	float outRatio = static_cast<float>(out.width) / out.height;
> 
>  	if (std::abs(inRatio - outRatio) > 0.1)
>  		return false;
> @@ -123,16 +129,18 @@ void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
>  	float bdsHeight;
> 
>  	if (!isSameRatio(pipe->input, gdc)) {
> -		bool found = false;
> -		float estIFHeight = static_cast<float>(iif.width *  gdc.height) /
> +		float estIFHeight = (iif.width * gdc.height) /
>  				    static_cast<float>(gdc.width);
>  		estIFHeight = utils::clamp<float>(estIFHeight, minIFHeight, iif.height);
> +		bool found = false;
> +
>  		ifHeight = utils::alignUp(estIFHeight, IF_ALIGN_H);
> -		while (ifHeight >= minIFHeight &&
> -		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
> -			bdsHeight = static_cast<float>(ifHeight) / bdsSF;
> +		while (ifHeight >= minIFHeight && ifHeight / bdsSF >= minBDSHeight) {
> +
> +			bdsHeight = ifHeight / bdsSF;
>  			if (std::fmod(bdsHeight, 1.0) == 0) {
>  				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
> +
>  				if (!(bdsIntHeight % BDS_ALIGN_H)) {
>  					found = true;
>  					break;
> @@ -143,11 +151,12 @@ void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
>  		}
> 
>  		ifHeight = utils::alignUp(estIFHeight, IF_ALIGN_H);
> -		while (ifHeight <= iif.height &&
> -		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
> -			bdsHeight = static_cast<float>(ifHeight) / bdsSF;
> +		while (ifHeight <= iif.height && ifHeight / bdsSF >= minBDSHeight) {
> +
> +			bdsHeight = ifHeight / bdsSF;
>  			if (std::fmod(bdsHeight, 1.0) == 0) {
>  				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
> +
>  				if (!(bdsIntHeight % BDS_ALIGN_H)) {
>  					found = true;
>  					break;
> @@ -159,14 +168,15 @@ void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
> 
>  		if (found) {
>  			unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
> +
>  			pipeConfigs.push_back({ bdsSF, { iif.width, ifHeight },
>  						{ bdsWidth, bdsIntHeight }, gdc });
>  			return;
>  		}
>  	} else {
>  		ifHeight = utils::alignUp(iif.height, IF_ALIGN_H);
> -		while (ifHeight > minIFHeight &&
> -		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
> +		while (ifHeight > minIFHeight && ifHeight / bdsSF >= minBDSHeight) {
> +
>  			bdsHeight = ifHeight / bdsSF;
>  			if (std::fmod(ifHeight, 1.0) == 0 && std::fmod(bdsHeight, 1.0) == 0) {
>  				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
> @@ -183,8 +193,7 @@ void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
>  	}
>  }
> 
> -void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc,
> -		  float bdsSF)
> +void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc, float bdsSF)
>  {
>  	unsigned int minBDSWidth = gdc.width + FILTER_H * 2;
> 
> @@ -218,15 +227,14 @@ void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc,
>  Size calculateGDC(ImgUDevice::Pipe *pipe)
>  {
>  	const Size &in = pipe->input;
> -	const Size &main = pipe->output;
> +	const Size &main = pipe->main;
>  	const Size &vf = pipe->viewfinder;
>  	Size gdc;
> 
>  	if (!vf.isNull()) {
>  		gdc.width = main.width;
> 
> -		float ratio = static_cast<float>(main.width * vf.height) /
> -			      static_cast<float>(vf.width);
> +		float ratio = (main.width * vf.height) / static_cast<float>(vf.width);
>  		gdc.height = std::max(static_cast<float>(main.height), ratio);
> 
>  		return gdc;
> @@ -237,14 +245,13 @@ Size calculateGDC(ImgUDevice::Pipe *pipe)
>  		return gdc;
>  	}
> 
> -	float totalSF = static_cast<float>(in.width) /
> -			static_cast<float>(main.width);
> +	float totalSF = static_cast<float>(in.width) / main.width;
>  	float bdsSF = totalSF > 2 ? 2 : 1;
>  	float yuvSF = totalSF / bdsSF;
>  	float sf = findScaleFactor(yuvSF, gdcScalingFactors);
> 
> -	gdc.width = static_cast<float>(main.width) * sf;
> -	gdc.height = static_cast<float>(main.height) * sf;
> +	gdc.width = main.width * sf;
> +	gdc.height = main.height * sf;
> 
>  	return gdc;
>  }
> @@ -259,6 +266,7 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)
>  	float ifCropH = static_cast<float>(in.height - pipe.iif.height);
>  	float gdcCropW = static_cast<float>(pipe.bds.width - pipe.gdc.width) * pipe.bds_sf;
>  	float gdcCropH = static_cast<float>(pipe.bds.height - pipe.gdc.height) * pipe.bds_sf;
> +
>  	fov.w = (inW - (ifCropW + gdcCropW)) / inW;
>  	fov.h = (inH - (ifCropH + gdcCropH)) / inH;
> 
> @@ -304,11 +312,11 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)
>   * \var Pipe::input
>   * \brief The input image size
>   *
> - * \var Pipe::output
> + * \var Pipe::main
>   * \brief The requested main output size
>   *
>   * \var Pipe::viewfinder
> - * \brief The requested viewfinder size
> + * \brief The requested viewfinder output size
>   */
> 
>  /**
> @@ -378,7 +386,7 @@ ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe)
> 
>  	LOG(IPU3, Debug) << "Calculating pipe configuration for: ";
>  	LOG(IPU3, Debug) << "input: " << pipe->input.toString();
> -	LOG(IPU3, Debug) << "main: " << pipe->output.toString();
> +	LOG(IPU3, Debug) << "main: " << pipe->main.toString();
>  	LOG(IPU3, Debug) << "vf: " << pipe->viewfinder.toString();
> 
>  	const Size &in = pipe->input;
> @@ -387,9 +395,9 @@ ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe)
>  	unsigned int ifWidth = utils::alignUp(in.width, IF_ALIGN_W);
>  	unsigned int ifHeight = in.height;
>  	unsigned int minIfWidth = in.width - IF_CROP_MAX_W;
> -	float bdsSF = static_cast<float>(in.width) /
> -		      static_cast<float>(gdc.width);
> +	float bdsSF = static_cast<float>(in.width) / gdc.width;
>  	float sf = findScaleFactor(bdsSF, bdsScalingFactors, true);
> +
>  	while (ifWidth >= minIfWidth) {
>  		Size iif{ ifWidth, ifHeight };
>  		calculateBDS(pipe, iif, gdc, sf);
> diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h
> index ff8dab7d645c..c73ac5a5a37c 100644
> --- a/src/libcamera/pipeline/ipu3/imgu.h
> +++ b/src/libcamera/pipeline/ipu3/imgu.h
> @@ -37,7 +37,7 @@ public:
> 
>  	struct Pipe {
>  		Size input;
> -		Size output;
> +		Size main;
>  		Size viewfinder;
>  	};
> 
> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> index 06afc7d79dac..161a88da8497 100644
> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> @@ -225,11 +225,12 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate()
>  			 * margins from the CIO2 output frame size.
>  			 *
>  			 * The ImgU outputs needs to be strictly smaller than
> -			 * the CIO2 output frame and rounded down to 64
> -			 * pixels in width and 32 pixels in height. This comes
> -			 * from inspecting the pipe configuration script results
> -			 * and the available suggested configurations in the
> -			 * ChromeOS BSP .xml camera tuning files.
> +			 * the CIO2 output frame and rounded down to 64 pixels
> +			 * in width and 32 pixels in height. This assumption
> +			 * comes from inspecting the pipe configuration script
> +			 * results and the available suggested configurations in
> +			 * the ChromeOS BSP .xml camera tuning files and shall
> +			 * be validated.
>  			 *
>  			 * \todo Clarify what are the hardware constraints
>  			 * that require this alignements, if any. It might
> @@ -267,9 +268,9 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate()
>  				cfg->setStream(const_cast<Stream *>(&data_->outStream_));
>  				mainOutputAvailable = false;
> 
> -				pipe.output = cfg->size;
> +				pipe.main = cfg->size;
>  				if (yuvCount == 1)
> -					pipe.viewfinder = pipe.output;
> +					pipe.viewfinder = pipe.main;
> 
>  				LOG(IPU3, Debug) << "Assigned " << cfg->toString()
>  						 << " to the main output";
> @@ -333,8 +334,8 @@ CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera,
>  			 * to the ImgU  maximum output size) and aligned down to
>  			 * the required frame margin.
>  			 *
> -			 * The alignment constraints should be clarified
> -			 * as per the todo item in validate().
> +			 * \todo Clarify the alignment constraints as exaplained
> +			 * in validate()
>  			 */
>  			size = sensorResolution.boundedTo(IMGU_OUTPUT_MAX_SIZE);
>  			size.width = utils::alignDown(size.width - 1,
> 
> Thanks
>    j
> 
> Jacopo Mondi (19):
>   libcamera: ipu3: Rename mbusCodesToInfo
>   libcamera: utils: Add alignUp and alignDown functions
>   libcamera: geometry: Add isNull() function to Rectangle class
>   libcamera: ipu3: Remove streams from generateConfiguration
>   libcamera: ipu3: Make sure the config is valid
>   libcamera: ipu3: cio2: Report format and sizes
>   libcamera: ipu3: Do not overwrite StreamConfiguration
>   libcamera: ipu3: Report StreamFormats
>   libcamera: ipu3: Remove initialization of Size
>   libcamera: ipu3: Validate the stream combination
>   libcamera: camera: Zero streams before validate()
>   libcamera: ipu3: cio2: Add a const sensor() method
>   libcamera: ipu3: Adjust and assign streams in validate()
>   libcamera: ipu3: Remove streams from IPU3CameraConfiguration
>   libcamera: ipu3: Remove camera_ from IPU3CameraConfiguration
>   libcamera: ipu3: imgu: Calculate ImgU pipe configuration
>   libcamera: ipu3: Validate the pipe configuration
>   libcamera: ipu3: Configure ImgU with the computed parameters
>   libcamera: ipu3: imgu: Rename configureInput()
> 
>  include/libcamera/geometry.h         |   1 +
>  include/libcamera/internal/utils.h   |  10 +
>  src/libcamera/camera.cpp             |   4 +-
>  src/libcamera/geometry.cpp           |   6 +
>  src/libcamera/pipeline/ipu3/cio2.cpp |  54 +++-
>  src/libcamera/pipeline/ipu3/cio2.h   |   6 +
>  src/libcamera/pipeline/ipu3/imgu.    |   0
>  src/libcamera/pipeline/ipu3/imgu.cpp | 386 +++++++++++++++++++++++-
>  src/libcamera/pipeline/ipu3/imgu.h   |  22 +-
>  src/libcamera/pipeline/ipu3/ipu3.cpp | 424 +++++++++++++--------------
>  src/libcamera/utils.cpp              |  16 +
>  test/geometry.cpp                    |  14 +
>  test/utils.cpp                       |  11 +
>  13 files changed, 714 insertions(+), 240 deletions(-)
>  create mode 100644 src/libcamera/pipeline/ipu3/imgu.
> 
> --
> 2.27.0
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
>

Patch
diff mbox

diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp
index a3ea3eabe318..cf26980c75f1 100644
--- a/src/libcamera/pipeline/ipu3/imgu.cpp
+++ b/src/libcamera/pipeline/ipu3/imgu.cpp
@@ -25,6 +25,14 @@  LOG_DECLARE_CATEGORY(IPU3)

 namespace {

+/*
+ * The procedure to calculate the ImgU pipe configuration has been ported
+ * from the pipe_config.py python script, available at:
+ * https://github.com/intel/intel-ipu3-pipecfg
+ * at revision: 61e83f2f7606 ("Add more information into README")
+ */
+
 static constexpr unsigned int FILTER_H = 4;

 static constexpr unsigned int IF_ALIGN_W = 2;
@@ -103,10 +111,8 @@  float findScaleFactor(float sf, const std::vector<float> &range,

 bool isSameRatio(const Size &in, const Size &out)
 {
-	float inRatio = static_cast<float>(in.width) /
-			static_cast<float>(in.height);
-	float outRatio = static_cast<float>(out.width) /
-			 static_cast<float>(out.height);
+	float inRatio = static_cast<float>(in.width) / in.height;
+	float outRatio = static_cast<float>(out.width) / out.height;

 	if (std::abs(inRatio - outRatio) > 0.1)
 		return false;
@@ -123,16 +129,18 @@  void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
 	float bdsHeight;

 	if (!isSameRatio(pipe->input, gdc)) {
-		bool found = false;
-		float estIFHeight = static_cast<float>(iif.width *  gdc.height) /
+		float estIFHeight = (iif.width * gdc.height) /
 				    static_cast<float>(gdc.width);
 		estIFHeight = utils::clamp<float>(estIFHeight, minIFHeight, iif.height);
+		bool found = false;
+
 		ifHeight = utils::alignUp(estIFHeight, IF_ALIGN_H);
-		while (ifHeight >= minIFHeight &&
-		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
-			bdsHeight = static_cast<float>(ifHeight) / bdsSF;
+		while (ifHeight >= minIFHeight && ifHeight / bdsSF >= minBDSHeight) {
+
+			bdsHeight = ifHeight / bdsSF;
 			if (std::fmod(bdsHeight, 1.0) == 0) {
 				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
+
 				if (!(bdsIntHeight % BDS_ALIGN_H)) {
 					found = true;
 					break;
@@ -143,11 +151,12 @@  void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
 		}

 		ifHeight = utils::alignUp(estIFHeight, IF_ALIGN_H);
-		while (ifHeight <= iif.height &&
-		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
-			bdsHeight = static_cast<float>(ifHeight) / bdsSF;
+		while (ifHeight <= iif.height && ifHeight / bdsSF >= minBDSHeight) {
+
+			bdsHeight = ifHeight / bdsSF;
 			if (std::fmod(bdsHeight, 1.0) == 0) {
 				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
+
 				if (!(bdsIntHeight % BDS_ALIGN_H)) {
 					found = true;
 					break;
@@ -159,14 +168,15 @@  void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc

 		if (found) {
 			unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
+
 			pipeConfigs.push_back({ bdsSF, { iif.width, ifHeight },
 						{ bdsWidth, bdsIntHeight }, gdc });
 			return;
 		}
 	} else {
 		ifHeight = utils::alignUp(iif.height, IF_ALIGN_H);
-		while (ifHeight > minIFHeight &&
-		       static_cast<float>(ifHeight) / bdsSF >= minBDSHeight) {
+		while (ifHeight > minIFHeight && ifHeight / bdsSF >= minBDSHeight) {
+
 			bdsHeight = ifHeight / bdsSF;
 			if (std::fmod(ifHeight, 1.0) == 0 && std::fmod(bdsHeight, 1.0) == 0) {
 				unsigned int bdsIntHeight = static_cast<unsigned int>(bdsHeight);
@@ -183,8 +193,7 @@  void calculateBDSHeight(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc
 	}
 }

-void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc,
-		  float bdsSF)
+void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc, float bdsSF)
 {
 	unsigned int minBDSWidth = gdc.width + FILTER_H * 2;

@@ -218,15 +227,14 @@  void calculateBDS(ImgUDevice::Pipe *pipe, const Size &iif, const Size &gdc,
 Size calculateGDC(ImgUDevice::Pipe *pipe)
 {
 	const Size &in = pipe->input;
-	const Size &main = pipe->output;
+	const Size &main = pipe->main;
 	const Size &vf = pipe->viewfinder;
 	Size gdc;

 	if (!vf.isNull()) {
 		gdc.width = main.width;

-		float ratio = static_cast<float>(main.width * vf.height) /
-			      static_cast<float>(vf.width);
+		float ratio = (main.width * vf.height) / static_cast<float>(vf.width);
 		gdc.height = std::max(static_cast<float>(main.height), ratio);

 		return gdc;
@@ -237,14 +245,13 @@  Size calculateGDC(ImgUDevice::Pipe *pipe)
 		return gdc;
 	}

-	float totalSF = static_cast<float>(in.width) /
-			static_cast<float>(main.width);
+	float totalSF = static_cast<float>(in.width) / main.width;
 	float bdsSF = totalSF > 2 ? 2 : 1;
 	float yuvSF = totalSF / bdsSF;
 	float sf = findScaleFactor(yuvSF, gdcScalingFactors);

-	gdc.width = static_cast<float>(main.width) * sf;
-	gdc.height = static_cast<float>(main.height) * sf;
+	gdc.width = main.width * sf;
+	gdc.height = main.height * sf;

 	return gdc;
 }
@@ -259,6 +266,7 @@  FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)
 	float ifCropH = static_cast<float>(in.height - pipe.iif.height);
 	float gdcCropW = static_cast<float>(pipe.bds.width - pipe.gdc.width) * pipe.bds_sf;
 	float gdcCropH = static_cast<float>(pipe.bds.height - pipe.gdc.height) * pipe.bds_sf;
+
 	fov.w = (inW - (ifCropW + gdcCropW)) / inW;
 	fov.h = (inH - (ifCropH + gdcCropH)) / inH;

@@ -304,11 +312,11 @@  FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)
  * \var Pipe::input
  * \brief The input image size
  *
- * \var Pipe::output
+ * \var Pipe::main
  * \brief The requested main output size
  *
  * \var Pipe::viewfinder
- * \brief The requested viewfinder size
+ * \brief The requested viewfinder output size
  */

 /**
@@ -378,7 +386,7 @@  ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe)

 	LOG(IPU3, Debug) << "Calculating pipe configuration for: ";
 	LOG(IPU3, Debug) << "input: " << pipe->input.toString();
-	LOG(IPU3, Debug) << "main: " << pipe->output.toString();
+	LOG(IPU3, Debug) << "main: " << pipe->main.toString();
 	LOG(IPU3, Debug) << "vf: " << pipe->viewfinder.toString();

 	const Size &in = pipe->input;
@@ -387,9 +395,9 @@  ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe)
 	unsigned int ifWidth = utils::alignUp(in.width, IF_ALIGN_W);
 	unsigned int ifHeight = in.height;
 	unsigned int minIfWidth = in.width - IF_CROP_MAX_W;
-	float bdsSF = static_cast<float>(in.width) /
-		      static_cast<float>(gdc.width);
+	float bdsSF = static_cast<float>(in.width) / gdc.width;
 	float sf = findScaleFactor(bdsSF, bdsScalingFactors, true);
+
 	while (ifWidth >= minIfWidth) {
 		Size iif{ ifWidth, ifHeight };
 		calculateBDS(pipe, iif, gdc, sf);
diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h
index ff8dab7d645c..c73ac5a5a37c 100644
--- a/src/libcamera/pipeline/ipu3/imgu.h
+++ b/src/libcamera/pipeline/ipu3/imgu.h
@@ -37,7 +37,7 @@  public:

 	struct Pipe {
 		Size input;
-		Size output;
+		Size main;
 		Size viewfinder;
 	};

diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 06afc7d79dac..161a88da8497 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -225,11 +225,12 @@  CameraConfiguration::Status IPU3CameraConfiguration::validate()
 			 * margins from the CIO2 output frame size.
 			 *
 			 * The ImgU outputs needs to be strictly smaller than
-			 * the CIO2 output frame and rounded down to 64
-			 * pixels in width and 32 pixels in height. This comes
-			 * from inspecting the pipe configuration script results
-			 * and the available suggested configurations in the
-			 * ChromeOS BSP .xml camera tuning files.
+			 * the CIO2 output frame and rounded down to 64 pixels
+			 * in width and 32 pixels in height. This assumption
+			 * comes from inspecting the pipe configuration script
+			 * results and the available suggested configurations in
+			 * the ChromeOS BSP .xml camera tuning files and shall
+			 * be validated.
 			 *
 			 * \todo Clarify what are the hardware constraints
 			 * that require this alignements, if any. It might
@@ -267,9 +268,9 @@  CameraConfiguration::Status IPU3CameraConfiguration::validate()
 				cfg->setStream(const_cast<Stream *>(&data_->outStream_));
 				mainOutputAvailable = false;

-				pipe.output = cfg->size;
+				pipe.main = cfg->size;
 				if (yuvCount == 1)
-					pipe.viewfinder = pipe.output;
+					pipe.viewfinder = pipe.main;

 				LOG(IPU3, Debug) << "Assigned " << cfg->toString()
 						 << " to the main output";
@@ -333,8 +334,8 @@  CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera,
 			 * to the ImgU  maximum output size) and aligned down to
 			 * the required frame margin.
 			 *
-			 * The alignment constraints should be clarified
-			 * as per the todo item in validate().
+			 * \todo Clarify the alignment constraints as exaplained
+			 * in validate()
 			 */
 			size = sensorResolution.boundedTo(IMGU_OUTPUT_MAX_SIZE);
 			size.width = utils::alignDown(size.width - 1,