[libcamera-devel,RFC,2/6] libcamera: ipu3: Implement tryValidate() in IPU3CameraConfiguration
diff mbox series

Message ID 20210204100541.657503-3-hiroh@chromium.org
State New
Headers show
Series
  • Support stream mapping in Android HAL adaptation layer
Related show

Commit Message

Hirokazu Honda Feb. 4, 2021, 10:05 a.m. UTC
IPU3CameraConfiguration::tryValidate() is implemented. It is
mostly the same as the validate() implementation.

Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
---
 src/libcamera/pipeline/ipu3/imgu.cpp |   2 +-
 src/libcamera/pipeline/ipu3/imgu.h   |   2 +-
 src/libcamera/pipeline/ipu3/ipu3.cpp | 160 +++++++++++++++++++++++++++
 3 files changed, 162 insertions(+), 2 deletions(-)

--
2.30.0.365.g02bc693789-goog

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp
index 5b1c0318..36c5c03c 100644
--- a/src/libcamera/pipeline/ipu3/imgu.cpp
+++ b/src/libcamera/pipeline/ipu3/imgu.cpp
@@ -377,7 +377,7 @@  int ImgUDevice::init(MediaDevice *media, unsigned int index)
  * \return An ImgUDevice::PipeConfig instance on success, an empty configuration
  * otherwise
  */
-ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe)
+ImgUDevice::PipeConfig ImgUDevice::calculatePipeConfig(Pipe *pipe) const
 {
 	pipeConfigs.clear();

diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h
index c73ac5a5..4204f50d 100644
--- a/src/libcamera/pipeline/ipu3/imgu.h
+++ b/src/libcamera/pipeline/ipu3/imgu.h
@@ -43,7 +43,7 @@  public:

 	int init(MediaDevice *media, unsigned int index);

-	PipeConfig calculatePipeConfig(Pipe *pipe);
+	PipeConfig calculatePipeConfig(Pipe *pipe) const;

 	int configure(const PipeConfig &pipeConfig, V4L2DeviceFormat *inputFormat);

diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index db0d6b91..89f1983a 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -73,11 +73,15 @@  public:
 	IPU3CameraConfiguration(IPU3CameraData *data);

 	Status validate() override;
+	bool tryValidate(std::vector<std::pair<StreamConfiguration, Status>> &config) const override;

 	const StreamConfiguration &cio2Format() const { return cio2Configuration_; }
 	const ImgUDevice::PipeConfig imguConfig() const { return pipeConfig_; }

 private:
+	bool tryValidateInternal(
+		std::vector<std::pair<StreamConfiguration, Status>> &configs,
+		ImgUDevice::PipeConfig &pipeConfig) const;
 	/*
 	 * The IPU3CameraData instance is guaranteed to be valid as long as the
 	 * corresponding Camera instance is valid. In order to borrow a
@@ -140,6 +144,162 @@  IPU3CameraConfiguration::IPU3CameraConfiguration(IPU3CameraData *data)
 	data_ = data;
 }

+
+bool IPU3CameraConfiguration::tryValidateInternal(
+	std::vector<std::pair<StreamConfiguration, Status>> &configs,
+	ImgUDevice::PipeConfig &pipeConfig) const
+{
+	if (configs.empty() || configs.size() > IPU3_MAX_STREAMS)
+		return false;
+
+	unsigned int rawCount = 0;
+	unsigned int yuvCount = 0;
+	Size maxYuvSize;
+	for (size_t i = 0; i < configs.size(); ++i) {
+		const auto &cfg = configs[i].first;
+		const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
+		if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) {
+			rawCount++;
+		} else {
+			yuvCount++;
+			maxYuvSize.expandTo(cfg.size);
+		}
+	}
+	LOG(IPU3, Debug) << rawCount << ", " << yuvCount;
+	if (rawCount > 1 || yuvCount > 2)
+		return false;
+
+	StreamConfiguration cio2Configuration =
+		data_->cio2_.generateConfiguration({});
+	if (!cio2Configuration.pixelFormat.isValid())
+		return false;
+	LOG(IPU3, Debug) << "CIO2 configuration: " << cio2Configuration.toString();
+
+	ImgUDevice::Pipe pipe{};
+	pipe.input = cio2Configuration.size;
+
+	bool mainOutputAvailable = true;
+	for (auto &[cfg, status] : configs) {
+		const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
+		const StreamConfiguration originalCfg = cfg;
+
+		LOG(IPU3, Debug) << "Validating " << cfg.toString()
+				 << " to the raw stream";
+		if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) {
+			cfg.size = cio2Configuration.size;
+			cfg.pixelFormat = cio2Configuration.pixelFormat;
+			cfg.bufferCount = cio2Configuration.bufferCount;
+			cfg.stride = info.stride(cfg.size.width, 0, 64);
+			cfg.frameSize = info.frameSize(cfg.size, 64);
+			cfg.setStream(const_cast<Stream *>(&data_->rawStream_));
+			LOG(IPU3, Debug) << "Assigned " << cfg.toString()
+					 << " to the raw stream";
+		} else {
+			unsigned int limit;
+			limit = utils::alignDown(cio2Configuration.size.width - 1,
+						 IMGU_OUTPUT_WIDTH_MARGIN);
+			cfg.size.width = std::clamp(cfg.size.width,
+						    IMGU_OUTPUT_MIN_SIZE.width,
+						    limit);
+
+			limit = utils::alignDown(cio2Configuration.size.height - 1,
+						 IMGU_OUTPUT_HEIGHT_MARGIN);
+			cfg.size.height = std::clamp(cfg.size.height,
+						     IMGU_OUTPUT_MIN_SIZE.height,
+						     limit);
+
+			cfg.size.alignDownTo(IMGU_OUTPUT_WIDTH_ALIGN,
+					     IMGU_OUTPUT_HEIGHT_ALIGN);
+
+			cfg.pixelFormat = formats::NV12;
+			cfg.bufferCount = IPU3_BUFFER_COUNT;
+			cfg.stride = info.stride(cfg.size.width, 0, 1);
+			cfg.frameSize = info.frameSize(cfg.size, 1);
+
+			if (mainOutputAvailable &&
+			    (originalCfg.size == maxYuvSize || yuvCount == 1)) {
+				cfg.setStream(const_cast<Stream *>(&data_->outStream_));
+				mainOutputAvailable = false;
+
+				pipe.main = cfg.size;
+				if (yuvCount == 1)
+					pipe.viewfinder = pipe.main;
+
+				LOG(IPU3, Debug) << "Assigned " << cfg.toString()
+						 << " to the main output";
+			} else {
+				cfg.setStream(const_cast<Stream *>(&data_->vfStream_));
+				pipe.viewfinder = cfg.size;
+
+				LOG(IPU3, Debug) << "Assigned " << cfg.toString()
+						 << " to the viewfinder output";
+			}
+		}
+		if (cfg.pixelFormat != originalCfg.pixelFormat ||
+		    cfg.size != originalCfg.size) {
+			LOG(IPU3, Debug)
+				<< "Stream  configuration adjusted to "
+				<< cfg.toString();
+
+			status = Adjusted;
+		}
+	}
+
+	if (yuvCount) {
+		pipeConfig = data_->imgu_->calculatePipeConfig(&pipe);
+		if (pipeConfig.isNull())
+			return false;
+	}
+	return true;
+}
+
+bool IPU3CameraConfiguration::tryValidate(
+	std::vector<std::pair<StreamConfiguration, Status>> &configs) const
+{
+	if (configs.empty())
+		return Invalid;
+
+	struct AcceptedConfig {
+		StreamConfiguration config;
+		Status status;
+		unsigned int index;
+	};
+	std::vector<AcceptedConfig> acceptedConfigs;
+	for (unsigned int i = 0; i < configs.size(); ++i) {
+		LOG(IPU3, Debug) << "Trying config #" << i
+				 << ": " << configs[i].first.toString();
+		std::vector<std::pair<StreamConfiguration, Status>>
+			tryConfigs(acceptedConfigs.size() + 1);
+		for (unsigned int j = 0; j < acceptedConfigs.size(); ++j) {
+			tryConfigs[j].first = acceptedConfigs[j].config;
+			tryConfigs[j].second = Valid;
+		}
+		tryConfigs.back().first = configs[i].first;
+		tryConfigs.back().second = Valid;
+		ImgUDevice::PipeConfig tryPipeConfig;
+		if (!tryValidateInternal(tryConfigs, tryPipeConfig))
+			continue;
+
+		for (unsigned int j = 0; j < acceptedConfigs.size(); ++j) {
+			acceptedConfigs[j].config = tryConfigs[j].first;
+			acceptedConfigs[j].status = tryConfigs[j].second;
+		}
+		acceptedConfigs.push_back(
+			{ tryConfigs[i].first, tryConfigs[i].second, i });
+	}
+
+	for (unsigned int i = 0; i < configs.size(); ++i)
+		configs[i].second = Invalid;
+
+	for (auto &&ac : acceptedConfigs) {
+		unsigned int i = ac.index;
+		configs[i].first = std::move(ac.config);
+		configs[i].second = ac.status;
+	}
+
+	return !acceptedConfigs.empty();
+}
+
 CameraConfiguration::Status IPU3CameraConfiguration::validate()
 {
 	Status status = Valid;