[libcamera-devel] [PATCH 3/3] pipeline: rkisp1: Plumb SensorConfiguration

Paul Elder paul.elder at ideasonboard.com
Tue Jan 16 10:17:54 CET 2024


Add support to the rkisp1 pipeline handler for validating and
configuring SensorConfiguration.

Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
---
 src/libcamera/pipeline/rkisp1/rkisp1.cpp      | 97 ++++++++++++++++---
 src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 37 +++++--
 src/libcamera/pipeline/rkisp1/rkisp1_path.h   |  3 +-
 3 files changed, 115 insertions(+), 22 deletions(-)

diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index fb67ba8f4..74da9c1b1 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -128,7 +128,8 @@ public:
 	const Transform &combinedTransform() { return combinedTransform_; }
 
 private:
-	bool fitsAllPaths(const StreamConfiguration &cfg);
+	bool fitsAllPaths(const StreamConfiguration &cfg,
+			  std::optional<unsigned int> sensorBPP);
 
 	/*
 	 * The RkISP1CameraData instance is guaranteed to be valid as long as the
@@ -448,17 +449,18 @@ RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera,
 	data_ = data;
 }
 
-bool RkISP1CameraConfiguration::fitsAllPaths(const StreamConfiguration &cfg)
+bool RkISP1CameraConfiguration::fitsAllPaths(const StreamConfiguration &cfg,
+					     std::optional<unsigned int> sensorBPP)
 {
 	const CameraSensor *sensor = data_->sensor_.get();
 	StreamConfiguration config;
 
 	config = cfg;
-	if (data_->mainPath_->validate(sensor, &config) != Valid)
+	if (data_->mainPath_->validate(sensor, &config, sensorBPP) != Valid)
 		return false;
 
 	config = cfg;
-	if (data_->selfPath_ && data_->selfPath_->validate(sensor, &config) != Valid)
+	if (data_->selfPath_ && data_->selfPath_->validate(sensor, &config, sensorBPP) != Valid)
 		return false;
 
 	return true;
@@ -475,6 +477,24 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()
 
 	status = validateColorSpaces(ColorSpaceFlag::StreamsShareColorSpace);
 
+	/*
+	 * For the sensor configuration, default to the first supported bit
+	 * depth for the sensor configuration if an unsupported one is
+	 * supplied.
+	 */
+	std::optional<unsigned int> bitDepth;
+	if (sensorConfig) {
+		bitDepth = sensorConfig->bitDepth;
+		if (bitDepth != 8 && bitDepth != 10 && bitDepth != 12) {
+			V4L2SubdeviceFormat format = {};
+			format.mbus_code = data_->sensor_->mbusCodes().at(0);
+
+			sensorConfig->bitDepth = format.bitsPerPixel();
+			bitDepth = sensorConfig->bitDepth;
+			status = Adjusted;
+		}
+	}
+
 	/* Cap the number of entries to the available streams. */
 	if (config_.size() > pathCount) {
 		config_.resize(pathCount);
@@ -510,7 +530,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()
 	 */
 	std::vector<unsigned int> order(config_.size());
 	std::iota(order.begin(), order.end(), 0);
-	if (config_.size() == 2 && fitsAllPaths(config_[0]))
+	if (config_.size() == 2 && fitsAllPaths(config_[0], bitDepth))
 		std::reverse(order.begin(), order.end());
 
 	bool mainPathAvailable = true;
@@ -521,7 +541,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()
 		/* Try to match stream without adjusting configuration. */
 		if (mainPathAvailable) {
 			StreamConfiguration tryCfg = cfg;
-			if (data_->mainPath_->validate(sensor, &tryCfg) == Valid) {
+			if (data_->mainPath_->validate(sensor, &tryCfg, bitDepth) == Valid) {
 				mainPathAvailable = false;
 				cfg = tryCfg;
 				cfg.setStream(const_cast<Stream *>(&data_->mainPathStream_));
@@ -531,7 +551,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()
 
 		if (selfPathAvailable) {
 			StreamConfiguration tryCfg = cfg;
-			if (data_->selfPath_->validate(sensor, &tryCfg) == Valid) {
+			if (data_->selfPath_->validate(sensor, &tryCfg, bitDepth) == Valid) {
 				selfPathAvailable = false;
 				cfg = tryCfg;
 				cfg.setStream(const_cast<Stream *>(&data_->selfPathStream_));
@@ -542,7 +562,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()
 		/* Try to match stream allowing adjusting configuration. */
 		if (mainPathAvailable) {
 			StreamConfiguration tryCfg = cfg;
-			if (data_->mainPath_->validate(sensor, &tryCfg) == Adjusted) {
+			if (data_->mainPath_->validate(sensor, &tryCfg, bitDepth) == Adjusted) {
 				mainPathAvailable = false;
 				cfg = tryCfg;
 				cfg.setStream(const_cast<Stream *>(&data_->mainPathStream_));
@@ -553,7 +573,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()
 
 		if (selfPathAvailable) {
 			StreamConfiguration tryCfg = cfg;
-			if (data_->selfPath_->validate(sensor, &tryCfg) == Adjusted) {
+			if (data_->selfPath_->validate(sensor, &tryCfg, bitDepth) == Adjusted) {
 				selfPathAvailable = false;
 				cfg = tryCfg;
 				cfg.setStream(const_cast<Stream *>(&data_->selfPathStream_));
@@ -570,28 +590,75 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()
 
 	/* Select the sensor format. */
 	PixelFormat rawFormat;
+	Size rawSize;
 	Size maxSize;
 
 	for (const StreamConfiguration &cfg : config_) {
 		const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
-		if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)
+		if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) {
 			rawFormat = cfg.pixelFormat;
+			rawSize = cfg.size;
+		}
 
+		/* path->validate binds this to a sensor-supported resolution */
 		maxSize = std::max(maxSize, cfg.size);
 	}
 
+	if (rawFormat.isValid() && sensorConfig) {
+		if (sensorConfig->outputSize != rawSize) {
+			sensorConfig->outputSize = rawSize;
+			status = Adjusted;
+		}
+
+		const PixelFormatInfo &info = PixelFormatInfo::info(rawFormat);
+		if (sensorConfig->bitDepth != info.bitsPerPixel) {
+			sensorConfig->bitDepth = info.bitsPerPixel;
+			status = Adjusted;
+		}
+	} else if (!rawFormat.isValid() && sensorConfig) {
+		/*
+		 * TODO Handle this properly taking into account the upscaling
+		 * capabilities and dual ISP mode (for the i.MX8MP).
+		 *
+		 * x1.5 should be a reasonable hardcoded ballpark for now.
+		 */
+		double factor = 1.5;
+		Size before = sensorConfig->outputSize;
+		Size upscaleLimit = {
+			static_cast<unsigned int>(maxSize.width / factor),
+			static_cast<unsigned int>(maxSize.height / factor)
+		};
+
+		if (sensorConfig->outputSize < upscaleLimit)
+			sensorConfig->outputSize = maxSize;
+
+		if (before != sensorConfig->outputSize)
+			status = Adjusted;
+
+		/* No need to validate bpp for non-raw */
+	}
+
 	std::vector<unsigned int> mbusCodes;
+	Size size = maxSize;
 
 	if (rawFormat.isValid()) {
 		mbusCodes = { rawFormats.at(rawFormat) };
+		size = rawSize;
+	} else if (sensorConfig) {
+		for (const auto &value : rawFormats) {
+			const PixelFormatInfo &info = PixelFormatInfo::info(value.first);
+			if (info.bitsPerPixel == sensorConfig->bitDepth)
+				mbusCodes.push_back(value.second);
+		}
 	} else {
 		std::transform(rawFormats.begin(), rawFormats.end(),
 			       std::back_inserter(mbusCodes),
 			       [](const auto &value) { return value.second; });
 	}
 
-	sensorFormat_ = sensor->getFormat(mbusCodes, maxSize);
+	sensorFormat_ = sensor->getFormat(mbusCodes, size);
 
+	/* This should never happen if sensorConfig is valid */
 	if (sensorFormat_.size.isNull())
 		sensorFormat_.size = sensor->resolution();
 
@@ -730,7 +797,13 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)
 	V4L2SubdeviceFormat format = config->sensorFormat();
 	LOG(RkISP1, Debug) << "Configuring sensor with " << format;
 
-	ret = sensor->setFormat(&format, config->combinedTransform());
+	if (config->sensorConfig) {
+		ret = sensor->applyConfiguration(*config->sensorConfig,
+						 config->combinedTransform(), &format);
+	} else {
+		ret = sensor->setFormat(&format, config->combinedTransform());
+	}
+
 	if (ret < 0)
 		return ret;
 
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
index eaab7e857..a598b289b 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
@@ -220,7 +220,8 @@ RkISP1Path::generateConfiguration(const CameraSensor *sensor, const Size &size,
 }
 
 CameraConfiguration::Status RkISP1Path::validate(const CameraSensor *sensor,
-						 StreamConfiguration *cfg)
+						 StreamConfiguration *cfg,
+						 std::optional<unsigned int> sensorBPP)
 {
 	const std::vector<unsigned int> &mbusCodes = sensor->mbusCodes();
 	const Size &resolution = sensor->resolution();
@@ -231,10 +232,15 @@ CameraConfiguration::Status RkISP1Path::validate(const CameraSensor *sensor,
 	/*
 	 * Validate the pixel format. If the requested format isn't supported,
 	 * default to either NV12 (all versions of the ISP are guaranteed to
-	 * support NV12 on both the main and self paths) if the requested format
-	 * is not a raw format, or to the supported raw format with the highest
-	 * bits per pixel otherwise.
+	 * support NV12 on both the main and self paths) if the requested
+	 * format is not a raw format, or otherwise to a supported raw format
+	 * with the same number of bits per pixel, or to maximum bits per pixel
+	 * if the same is not supported.
 	 */
+	const PixelFormatInfo &formatInfo = PixelFormatInfo::info(cfg->pixelFormat);
+	unsigned int reqRawBitsPerPixel = formatInfo.bitsPerPixel;
+	PixelFormat reqRawFormat;
+
 	unsigned int rawBitsPerPixel = 0;
 	PixelFormat rawFormat;
 	bool found = false;
@@ -250,12 +256,22 @@ CameraConfiguration::Status RkISP1Path::validate(const CameraSensor *sensor,
 				continue;
 
 			/*
-			 * Store the raw format with the highest bits per pixel
-			 * for later usage.
+			 * If the bits per pixel is supplied from the sensor
+			 * configuration, choose a raw format that complies
+			 * with it. Otherwise store the raw format with the
+			 * highest bits per pixel for later usage.
 			 */
-			if (info.bitsPerPixel > rawBitsPerPixel) {
-				rawBitsPerPixel = info.bitsPerPixel;
-				rawFormat = format;
+			if (sensorBPP) {
+				if (info.bitsPerPixel == sensorBPP)
+					rawFormat = format;
+			} else {
+				if (info.bitsPerPixel == reqRawBitsPerPixel)
+					reqRawFormat = format;
+
+				if (info.bitsPerPixel > rawBitsPerPixel) {
+					rawBitsPerPixel = info.bitsPerPixel;
+					rawFormat = format;
+				}
 			}
 		}
 
@@ -265,6 +281,9 @@ CameraConfiguration::Status RkISP1Path::validate(const CameraSensor *sensor,
 		}
 	}
 
+	if (reqRawFormat.isValid())
+		rawFormat = reqRawFormat;
+
 	bool isRaw = PixelFormatInfo::info(cfg->pixelFormat).colourEncoding ==
 		     PixelFormatInfo::ColourEncodingRAW;
 
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
index c96bd5557..784bcea77 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
+++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
@@ -44,7 +44,8 @@ public:
 						  const Size &resolution,
 						  StreamRole role);
 	CameraConfiguration::Status validate(const CameraSensor *sensor,
-					     StreamConfiguration *cfg);
+					     StreamConfiguration *cfg,
+					     std::optional<unsigned int> sensorBPP);
 
 	int configure(const StreamConfiguration &config,
 		      const V4L2SubdeviceFormat &inputFormat);
-- 
2.39.2



More information about the libcamera-devel mailing list