[v4,10/13] libcamera: mali-c55: Correct input/output format representation
diff mbox series

Message ID 20240709143913.3276983-11-dan.scally@ideasonboard.com
State New
Headers show
Series
  • Miscellaneous Mali-C55 Pipeline Fixes
Related show

Commit Message

Dan Scally July 9, 2024, 2:39 p.m. UTC
At present we configure raw streams by looping through the pixel
formats we support and finding one with an associated media bus
format code that the sensor can produce. In the new representation
of raw data from the kernel driver this will not work - the sensor
could produce 8, 10, 12, 14 or 16 bit data and the ISP will force
it to RAW16, which is the only actually supported output.

To fix the issue move to simply finding a pixel format with a bayer
order that matches that of the media bus format produced by the
sensor. If the sensor can produce multiple formats with the same
bayer order use the one with the largest bitdepth.

Finally, remove the claim to support RAW formats of less than 16 bits.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
---
 src/libcamera/pipeline/mali-c55/mali-c55.cpp | 121 +++++++++++--------
 1 file changed, 73 insertions(+), 48 deletions(-)

Comments

Kieran Bingham Oct. 9, 2024, 2:54 p.m. UTC | #1
Quoting Daniel Scally (2024-07-09 15:39:10)
> At present we configure raw streams by looping through the pixel
> formats we support and finding one with an associated media bus
> format code that the sensor can produce. In the new representation
> of raw data from the kernel driver this will not work - the sensor
> could produce 8, 10, 12, 14 or 16 bit data and the ISP will force
> it to RAW16, which is the only actually supported output.
> 
> To fix the issue move to simply finding a pixel format with a bayer
> order that matches that of the media bus format produced by the
> sensor. If the sensor can produce multiple formats with the same
> bayer order use the one with the largest bitdepth.
> 
> Finally, remove the claim to support RAW formats of less than 16 bits.
> 
> Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
> ---
>  src/libcamera/pipeline/mali-c55/mali-c55.cpp | 121 +++++++++++--------
>  1 file changed, 73 insertions(+), 48 deletions(-)
> 
> diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> index 156560c1..c456a798 100644
> --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> @@ -57,22 +57,6 @@ const std::map<libcamera::PixelFormat, unsigned int> maliC55FmtToCode = {
>         { formats::NV21, MEDIA_BUS_FMT_YUV10_1X30 },
>  
>         /* RAW formats, FR pipe only. */
> -       { formats::SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8 },
> -       { formats::SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8 },
> -       { formats::SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8 },
> -       { formats::SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8 },
> -       { formats::SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10 },
> -       { formats::SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10 },
> -       { formats::SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10 },
> -       { formats::SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10 },
> -       { formats::SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12 },
> -       { formats::SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12 },
> -       { formats::SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12 },
> -       { formats::SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12 },
> -       { formats::SGBRG14, MEDIA_BUS_FMT_SGBRG14_1X14 },
> -       { formats::SRGGB14, MEDIA_BUS_FMT_SRGGB14_1X14 },
> -       { formats::SBGGR14, MEDIA_BUS_FMT_SBGGR14_1X14 },
> -       { formats::SGRBG14, MEDIA_BUS_FMT_SGRBG14_1X14 },
>         { formats::SGBRG16, MEDIA_BUS_FMT_SGBRG16_1X16 },
>         { formats::SRGGB16, MEDIA_BUS_FMT_SRGGB16_1X16 },
>         { formats::SBGGR16, MEDIA_BUS_FMT_SBGGR16_1X16 },
> @@ -98,7 +82,8 @@ public:
>         const std::vector<Size> sizes(unsigned int mbusCode) const;
>         const Size resolution() const;
>  
> -       PixelFormat bestRawFormat() const;
> +       int pixfmtToMbusCode(const PixelFormat &pixFmt) const;
> +       const PixelFormat &bestRawFormat() const;
>  
>         PixelFormat adjustRawFormat(const PixelFormat &pixFmt) const;
>         Size adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const;
> @@ -208,33 +193,75 @@ const Size MaliC55CameraData::resolution() const
>         return tpgResolution_;
>  }
>  
> -PixelFormat MaliC55CameraData::bestRawFormat() const
> +/*
> + * The Mali C55 ISP can only produce 16-bit RAW output in bypass modes, but the
> + * sensors connected to it might produce 8/10/12/16 bits. We simply search the
> + * sensor's supported formats for the one with a matching bayer order and the
> + * greatest bitdepth.
> + */
> +int MaliC55CameraData::pixfmtToMbusCode(const PixelFormat &pixFmt) const
>  {
> +       auto it = maliC55FmtToCode.find(pixFmt);
> +       if (it == maliC55FmtToCode.end())
> +               return -EINVAL;
> +
> +       BayerFormat bayerFormat = BayerFormat::fromMbusCode(it->second);
> +       if (!bayerFormat.isValid())
> +               return -EINVAL;
> +
> +       V4L2Subdevice::Formats formats = sd_->formats(0);
> +       unsigned int sensorMbusCode = 0;
>         unsigned int bitDepth = 0;
> -       PixelFormat rawFormat;
>  
> -       /*
> -        * Iterate over all the supported PixelFormat and find the one
> -        * supported by the camera with the largest bitdepth.
> -        */
> -       for (const auto &maliFormat : maliC55FmtToCode) {
> -               PixelFormat pixFmt = maliFormat.first;
> -               if (!isFormatRaw(pixFmt))
> +       for (const auto &[code, sizes] : formats) {
> +               BayerFormat sdBayerFormat = BayerFormat::fromMbusCode(code);
> +               if (!sdBayerFormat.isValid())
>                         continue;
>  
> -               unsigned int rawCode = maliFormat.second;
> -               const auto rawSizes = sizes(rawCode);
> -               if (rawSizes.empty())
> +               if (sdBayerFormat.order != bayerFormat.order)
>                         continue;
>  
> -               BayerFormat bayer = BayerFormat::fromMbusCode(rawCode);
> -               if (bayer.bitDepth > bitDepth) {
> -                       bitDepth = bayer.bitDepth;
> -                       rawFormat = pixFmt;
> +               if (sdBayerFormat.bitDepth > bitDepth) {
> +                       bitDepth = sdBayerFormat.bitDepth;
> +                       sensorMbusCode = code;
>                 }
>         }
>  
> -       return rawFormat;
> +       if (!sensorMbusCode)
> +               return -EINVAL;
> +
> +       return sensorMbusCode;
> +}
> +
> +/*
> + * Find a RAW PixelFormat supported by both the ISP and the sensor.
> + *
> + * The situation is mildly complicated by the fact that we expect the sensor to
> + * output something like RAW8/10/12/16, but the ISP can only accept as input
> + * RAW20 and can only produce as output RAW16. The one constant in that is the
> + * bayer order of the data, so we'll simply check that the sensor produces a
> + * format with a bayer order that matches that of one of the formats we support,
> + * and select that.
> + */
> +const PixelFormat &MaliC55CameraData::bestRawFormat() const
> +{
> +       static const PixelFormat invalidPixFmt = {};
> +
> +       for (const auto &fmt : sd_->formats(0)) {
> +               BayerFormat sensorBayer = BayerFormat::fromMbusCode(fmt.first);
> +
> +               for (const auto &[pixFmt, rawCode] : maliC55FmtToCode) {
> +                       if (!isFormatRaw(pixFmt))
> +                               continue;
> +
> +                       BayerFormat bayer = BayerFormat::fromMbusCode(rawCode);
> +                       if (bayer.order == sensorBayer.order)
> +                               return pixFmt;
> +               }
> +       }
> +
> +       LOG(MaliC55, Fatal) << "Sensor doesn't provide a compatible format";

Please don't make this Fatal. That would 'crash' libcamera applications
(such as pipewire) in the event it was run on a sensor driver that
didn't have a format compatible with Mali-C55, even if perhaps there was
another camera that was compatible...

I think this can just be Error.

Other than that,


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> +       return invalidPixFmt;
>  }
>  
>  /*
> @@ -243,13 +270,11 @@ PixelFormat MaliC55CameraData::bestRawFormat() const
>   */
>  PixelFormat MaliC55CameraData::adjustRawFormat(const PixelFormat &rawFmt) const
>  {
> -       /* Make sure the provided raw format is supported by the pipeline. */
> -       auto it = maliC55FmtToCode.find(rawFmt);
> -       if (it == maliC55FmtToCode.end())
> +       /* Make sure the RAW mbus code is supported by the image source. */
> +       int rawCode = pixfmtToMbusCode(rawFmt);
> +       if (rawCode < 0)
>                 return bestRawFormat();
>  
> -       /* Now make sure the RAW mbus code is supported by the image source. */
> -       unsigned int rawCode = it->second;
>         const auto rawSizes = sizes(rawCode);
>         if (rawSizes.empty())
>                 return bestRawFormat();
> @@ -259,16 +284,14 @@ PixelFormat MaliC55CameraData::adjustRawFormat(const PixelFormat &rawFmt) const
>  
>  Size MaliC55CameraData::adjustRawSizes(const PixelFormat &rawFmt, const Size &size) const
>  {
> -       /* Just make sure the format is supported. */
> -       auto it = maliC55FmtToCode.find(rawFmt);
> -       if (it == maliC55FmtToCode.end())
> -               return {};
> -
>         /* Expand the RAW size to the minimum ISP input size. */
>         Size rawSize = size.expandedTo(kMaliC55MinInputSize);
>  
>         /* Check if the size is natively supported. */
> -       unsigned int rawCode = it->second;
> +       int rawCode = pixfmtToMbusCode(rawFmt);
> +       if (rawCode < 0)
> +               return {};
> +
>         const auto rawSizes = sizes(rawCode);
>         auto sizeIt = std::find(rawSizes.begin(), rawSizes.end(), rawSize);
>         if (sizeIt != rawSizes.end())
> @@ -418,8 +441,7 @@ CameraConfiguration::Status MaliC55CameraConfiguration::validate()
>  
>         /* If there's a RAW config, sensor configuration follows it. */
>         if (rawConfig) {
> -               const auto it = maliC55FmtToCode.find(rawConfig->pixelFormat);
> -               sensorFormat_.code = it->second;
> +               sensorFormat_.code = data_->pixfmtToMbusCode(rawConfig->pixelFormat);
>                 sensorFormat_.size = rawConfig->size.expandedTo(minSensorSize);
>  
>                 return status;
> @@ -614,7 +636,10 @@ PipelineHandlerMaliC55::generateConfiguration(Camera *camera,
>  
>                         if (isRaw) {
>                                 /* Make sure the mbus code is supported. */
> -                               unsigned int rawCode = maliFormat.second;
> +                               int rawCode = data->pixfmtToMbusCode(pixFmt);
> +                               if (rawCode < 0)
> +                                       continue;
> +
>                                 const auto sizes = data->sizes(rawCode);
>                                 if (sizes.empty())
>                                         continue;
> -- 
> 2.34.1
>

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
index 156560c1..c456a798 100644
--- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
+++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
@@ -57,22 +57,6 @@  const std::map<libcamera::PixelFormat, unsigned int> maliC55FmtToCode = {
 	{ formats::NV21, MEDIA_BUS_FMT_YUV10_1X30 },
 
 	/* RAW formats, FR pipe only. */
-	{ formats::SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8 },
-	{ formats::SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8 },
-	{ formats::SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8 },
-	{ formats::SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8 },
-	{ formats::SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10 },
-	{ formats::SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10 },
-	{ formats::SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10 },
-	{ formats::SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10 },
-	{ formats::SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12 },
-	{ formats::SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12 },
-	{ formats::SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12 },
-	{ formats::SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12 },
-	{ formats::SGBRG14, MEDIA_BUS_FMT_SGBRG14_1X14 },
-	{ formats::SRGGB14, MEDIA_BUS_FMT_SRGGB14_1X14 },
-	{ formats::SBGGR14, MEDIA_BUS_FMT_SBGGR14_1X14 },
-	{ formats::SGRBG14, MEDIA_BUS_FMT_SGRBG14_1X14 },
 	{ formats::SGBRG16, MEDIA_BUS_FMT_SGBRG16_1X16 },
 	{ formats::SRGGB16, MEDIA_BUS_FMT_SRGGB16_1X16 },
 	{ formats::SBGGR16, MEDIA_BUS_FMT_SBGGR16_1X16 },
@@ -98,7 +82,8 @@  public:
 	const std::vector<Size> sizes(unsigned int mbusCode) const;
 	const Size resolution() const;
 
-	PixelFormat bestRawFormat() const;
+	int pixfmtToMbusCode(const PixelFormat &pixFmt) const;
+	const PixelFormat &bestRawFormat() const;
 
 	PixelFormat adjustRawFormat(const PixelFormat &pixFmt) const;
 	Size adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const;
@@ -208,33 +193,75 @@  const Size MaliC55CameraData::resolution() const
 	return tpgResolution_;
 }
 
-PixelFormat MaliC55CameraData::bestRawFormat() const
+/*
+ * The Mali C55 ISP can only produce 16-bit RAW output in bypass modes, but the
+ * sensors connected to it might produce 8/10/12/16 bits. We simply search the
+ * sensor's supported formats for the one with a matching bayer order and the
+ * greatest bitdepth.
+ */
+int MaliC55CameraData::pixfmtToMbusCode(const PixelFormat &pixFmt) const
 {
+	auto it = maliC55FmtToCode.find(pixFmt);
+	if (it == maliC55FmtToCode.end())
+		return -EINVAL;
+
+	BayerFormat bayerFormat = BayerFormat::fromMbusCode(it->second);
+	if (!bayerFormat.isValid())
+		return -EINVAL;
+
+	V4L2Subdevice::Formats formats = sd_->formats(0);
+	unsigned int sensorMbusCode = 0;
 	unsigned int bitDepth = 0;
-	PixelFormat rawFormat;
 
-	/*
-	 * Iterate over all the supported PixelFormat and find the one
-	 * supported by the camera with the largest bitdepth.
-	 */
-	for (const auto &maliFormat : maliC55FmtToCode) {
-		PixelFormat pixFmt = maliFormat.first;
-		if (!isFormatRaw(pixFmt))
+	for (const auto &[code, sizes] : formats) {
+		BayerFormat sdBayerFormat = BayerFormat::fromMbusCode(code);
+		if (!sdBayerFormat.isValid())
 			continue;
 
-		unsigned int rawCode = maliFormat.second;
-		const auto rawSizes = sizes(rawCode);
-		if (rawSizes.empty())
+		if (sdBayerFormat.order != bayerFormat.order)
 			continue;
 
-		BayerFormat bayer = BayerFormat::fromMbusCode(rawCode);
-		if (bayer.bitDepth > bitDepth) {
-			bitDepth = bayer.bitDepth;
-			rawFormat = pixFmt;
+		if (sdBayerFormat.bitDepth > bitDepth) {
+			bitDepth = sdBayerFormat.bitDepth;
+			sensorMbusCode = code;
 		}
 	}
 
-	return rawFormat;
+	if (!sensorMbusCode)
+		return -EINVAL;
+
+	return sensorMbusCode;
+}
+
+/*
+ * Find a RAW PixelFormat supported by both the ISP and the sensor.
+ *
+ * The situation is mildly complicated by the fact that we expect the sensor to
+ * output something like RAW8/10/12/16, but the ISP can only accept as input
+ * RAW20 and can only produce as output RAW16. The one constant in that is the
+ * bayer order of the data, so we'll simply check that the sensor produces a
+ * format with a bayer order that matches that of one of the formats we support,
+ * and select that.
+ */
+const PixelFormat &MaliC55CameraData::bestRawFormat() const
+{
+	static const PixelFormat invalidPixFmt = {};
+
+	for (const auto &fmt : sd_->formats(0)) {
+		BayerFormat sensorBayer = BayerFormat::fromMbusCode(fmt.first);
+
+		for (const auto &[pixFmt, rawCode] : maliC55FmtToCode) {
+			if (!isFormatRaw(pixFmt))
+				continue;
+
+			BayerFormat bayer = BayerFormat::fromMbusCode(rawCode);
+			if (bayer.order == sensorBayer.order)
+				return pixFmt;
+		}
+	}
+
+	LOG(MaliC55, Fatal) << "Sensor doesn't provide a compatible format";
+	return invalidPixFmt;
 }
 
 /*
@@ -243,13 +270,11 @@  PixelFormat MaliC55CameraData::bestRawFormat() const
  */
 PixelFormat MaliC55CameraData::adjustRawFormat(const PixelFormat &rawFmt) const
 {
-	/* Make sure the provided raw format is supported by the pipeline. */
-	auto it = maliC55FmtToCode.find(rawFmt);
-	if (it == maliC55FmtToCode.end())
+	/* Make sure the RAW mbus code is supported by the image source. */
+	int rawCode = pixfmtToMbusCode(rawFmt);
+	if (rawCode < 0)
 		return bestRawFormat();
 
-	/* Now make sure the RAW mbus code is supported by the image source. */
-	unsigned int rawCode = it->second;
 	const auto rawSizes = sizes(rawCode);
 	if (rawSizes.empty())
 		return bestRawFormat();
@@ -259,16 +284,14 @@  PixelFormat MaliC55CameraData::adjustRawFormat(const PixelFormat &rawFmt) const
 
 Size MaliC55CameraData::adjustRawSizes(const PixelFormat &rawFmt, const Size &size) const
 {
-	/* Just make sure the format is supported. */
-	auto it = maliC55FmtToCode.find(rawFmt);
-	if (it == maliC55FmtToCode.end())
-		return {};
-
 	/* Expand the RAW size to the minimum ISP input size. */
 	Size rawSize = size.expandedTo(kMaliC55MinInputSize);
 
 	/* Check if the size is natively supported. */
-	unsigned int rawCode = it->second;
+	int rawCode = pixfmtToMbusCode(rawFmt);
+	if (rawCode < 0)
+		return {};
+
 	const auto rawSizes = sizes(rawCode);
 	auto sizeIt = std::find(rawSizes.begin(), rawSizes.end(), rawSize);
 	if (sizeIt != rawSizes.end())
@@ -418,8 +441,7 @@  CameraConfiguration::Status MaliC55CameraConfiguration::validate()
 
 	/* If there's a RAW config, sensor configuration follows it. */
 	if (rawConfig) {
-		const auto it = maliC55FmtToCode.find(rawConfig->pixelFormat);
-		sensorFormat_.code = it->second;
+		sensorFormat_.code = data_->pixfmtToMbusCode(rawConfig->pixelFormat);
 		sensorFormat_.size = rawConfig->size.expandedTo(minSensorSize);
 
 		return status;
@@ -614,7 +636,10 @@  PipelineHandlerMaliC55::generateConfiguration(Camera *camera,
 
 			if (isRaw) {
 				/* Make sure the mbus code is supported. */
-				unsigned int rawCode = maliFormat.second;
+				int rawCode = data->pixfmtToMbusCode(pixFmt);
+				if (rawCode < 0)
+					continue;
+
 				const auto sizes = data->sizes(rawCode);
 				if (sizes.empty())
 					continue;