[libcamera-devel,8/9] libcamera: ipu3: Support PipelineConfigFile option
diff mbox series

Message ID 20220209071917.559993-9-hanlinchen@chromium.org
State New
Headers show
Series
  • Introduce Pipeline configuration preference for IPU3
Related show

Commit Message

Hanlin Chen Feb. 9, 2022, 7:19 a.m. UTC
Add PipelineConfigFile option for ipu3, which supports setting a yaml
configuration file which contains preferred ImgU configurations when
certain output resolutions are requested.

This is a supplement of the current calculation designed by
https://github.com/intel/intel-ipu3-pipecfg.

This changes the result of IPU3CameraConfiguration::validate() and
PipelineHandlerIPU3::generateConfiguration(), and only validates
stream configurations defined in the file. The user can cancel the option
by calling setOptions() again without the option.

Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>
---
 src/libcamera/pipeline/ipu3/ipu3.cpp | 215 ++++++++++++++++++++++++++-
 1 file changed, 214 insertions(+), 1 deletion(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 6c5617cd..2d43b760 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -16,6 +16,7 @@ 
 
 #include <libcamera/camera.h>
 #include <libcamera/control_ids.h>
+#include <libcamera/option_ids.h>
 #include <libcamera/formats.h>
 #include <libcamera/ipa/ipu3_ipa_interface.h>
 #include <libcamera/ipa/ipu3_ipa_proxy.h>
@@ -35,11 +36,16 @@ 
 #include "cio2.h"
 #include "frames.h"
 #include "imgu.h"
+#include "pipe_config_pref.h"
 
 namespace libcamera {
 
 LOG_DEFINE_CATEGORY(IPU3)
 
+static const ControlInfoMap::Map IPU3Options = {
+	{ &options::PipelineConfigFile, ControlInfo(0, 512, std::string()) },
+};
+
 static const ControlInfoMap::Map IPU3Controls = {
 	{ &controls::draft::PipelineDepth, ControlInfo(2, 3) },
 };
@@ -62,6 +68,11 @@  public:
 	void cancelPendingRequests();
 	void frameStart(uint32_t sequence);
 
+	bool hasPreference() const
+	{
+		return pipeConfigPreference_.isValid();
+	}
+
 	CIO2Device cio2_;
 	ImgUDevice *imgu_;
 
@@ -85,6 +96,8 @@  public:
 
 	ControlInfoMap ipaControls_;
 
+	PipeConfigPreference pipeConfigPreference_;
+
 private:
 	void queueFrameAction(unsigned int id,
 			      const ipa::ipu3::IPU3Action &action);
@@ -107,6 +120,10 @@  public:
 	Transform combinedTransform_;
 
 private:
+	Status adjustTransform();
+	Status validateByCalulation();
+	Status validateByPipeConfigPreference();
+
 	/*
 	 * The IPU3CameraData instance is guaranteed to be valid as long as the
 	 * corresponding Camera instance is valid. In order to borrow a
@@ -131,6 +148,8 @@  public:
 
 	PipelineHandlerIPU3(CameraManager *manager);
 
+	int setOptions(Camera *camera, const ControlList *options) override;
+
 	CameraConfiguration *generateConfiguration(Camera *camera,
 		const StreamRoles &roles) override;
 	int configure(Camera *camera, CameraConfiguration *config) override;
@@ -151,6 +170,7 @@  private:
 		return static_cast<IPU3CameraData *>(camera->_d());
 	}
 
+	int initOptions(IPU3CameraData *data);
 	int initControls(IPU3CameraData *data);
 	int updateControls(IPU3CameraData *data);
 	int registerCameras();
@@ -158,6 +178,11 @@  private:
 	int allocateBuffers(Camera *camera);
 	int freeBuffers(Camera *camera);
 
+	CameraConfiguration *generateConfigurationByCalculation(Camera *camera,
+								const StreamRoles &roles);
+	CameraConfiguration *generateConfigurationByPreference(Camera *camera,
+							       const StreamRoles &roles);
+
 	ImgUDevice imgu0_;
 	ImgUDevice imgu1_;
 	MediaDevice *cio2MediaDev_;
@@ -172,7 +197,7 @@  IPU3CameraConfiguration::IPU3CameraConfiguration(IPU3CameraData *data)
 	data_ = data;
 }
 
-CameraConfiguration::Status IPU3CameraConfiguration::validate()
+CameraConfiguration::Status IPU3CameraConfiguration::adjustTransform()
 {
 	Status status = Valid;
 
@@ -221,6 +246,25 @@  CameraConfiguration::Status IPU3CameraConfiguration::validate()
 	 * apply to the sensor to save us working it out again.
 	 */
 	combinedTransform_ = combined;
+	return status;
+}
+
+CameraConfiguration::Status IPU3CameraConfiguration::validate()
+{
+	if (data_->hasPreference())
+		return validateByPipeConfigPreference();
+
+	return validateByCalulation();
+}
+
+CameraConfiguration::Status IPU3CameraConfiguration::validateByCalulation()
+{
+	Status status = Valid;
+
+	if (config_.empty())
+		return Invalid;
+
+	status = adjustTransform();
 
 	/* Cap the number of entries to the available streams. */
 	if (config_.size() > kMaxStreams) {
@@ -412,13 +456,118 @@  CameraConfiguration::Status IPU3CameraConfiguration::validate()
 	return status;
 }
 
+CameraConfiguration::Status IPU3CameraConfiguration::validateByPipeConfigPreference()
+{
+	if (config_.empty() || config_.size() > 2)
+		return Invalid;
+
+	Status status = adjustTransform();
+
+	bool mainAvailable = false;
+	StreamConfiguration *mainStream = nullptr;
+	StreamConfiguration *viewfinderStream = nullptr;
+
+	/* Assign the mainStream as the stream with the larger size. */
+	for (StreamConfiguration &cfg : config_) {
+		const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
+		if (info.colourEncoding != PixelFormatInfo::ColourEncodingYUV) {
+			return Invalid;
+		}
+		if (!mainAvailable) {
+			mainStream = &cfg;
+		} else if (mainStream->size < cfg.size) {
+			viewfinderStream = mainStream;
+			mainStream = &cfg;
+		}
+	}
+
+	/*
+	 * \todo Query and use the configuration for the still pipe when the
+	 * pipeline handler is refactored to use both ImgU device for a camera.
+	 */
+	PipeConfigPreference::PipeConfig videoPipe;
+	PipeConfigPreference::PipeConfig stillPipe;
+
+	int ret = data_->pipeConfigPreference_.queryPipeConfig(
+		mainStream->size,
+		(viewfinderStream) ? viewfinderStream->size : PipeConfigPreference::Disabled,
+		PipeConfigPreference::Disabled,
+		PipeConfigPreference::Disabled,
+		videoPipe, stillPipe);
+	if (ret) {
+		LOG(IPU3, Error)
+			<< "Fail to find a valid configuration: "
+			<< " main: " << mainStream->size
+			<< " viewfinder: "
+			<< ((viewfinderStream) ? viewfinderStream->size : PipeConfigPreference::Disabled);
+		return Invalid;
+	}
+
+	cio2Configuration_.size = videoPipe.cio2;
+	cio2Configuration_.pixelFormat = formats::SGRBG10_IPU3;
+	cio2Configuration_.bufferCount = kBufferCount;
+
+	pipeConfig_.bds = videoPipe.bds;
+	pipeConfig_.iif = videoPipe.iff;
+	pipeConfig_.gdc = videoPipe.gdc;
+
+	const PixelFormatInfo &info = PixelFormatInfo::info(formats::NV12);
+
+	mainStream->pixelFormat = formats::NV12;
+	mainStream->bufferCount = kBufferCount;
+	mainStream->stride = info.stride(mainStream->size.width, 0, 1);
+	mainStream->frameSize = info.frameSize(mainStream->size, 1);
+	mainStream->setStream(const_cast<Stream *>(&data_->outStream_));
+
+	if (viewfinderStream) {
+		viewfinderStream->pixelFormat = formats::NV12;
+		viewfinderStream->bufferCount = kBufferCount;
+		viewfinderStream->stride = info.stride(viewfinderStream->size.width, 0, 1);
+		viewfinderStream->frameSize = info.frameSize(viewfinderStream->size, 1);
+		viewfinderStream->setStream(const_cast<Stream *>(&data_->vfStream_));
+	}
+
+	return status;
+}
+
 PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager)
 	: PipelineHandler(manager), cio2MediaDev_(nullptr), imguMediaDev_(nullptr)
 {
 }
 
+int PipelineHandlerIPU3::setOptions(Camera *camera,
+				    const ControlList *options)
+{
+	IPU3CameraData *data = cameraData(camera);
+
+	PipeConfigPreference &preference = data->pipeConfigPreference_;
+	preference.invalid();
+
+	if (options && options->contains(options::PipelineConfigFile)) {
+		std::string path = options->get(options::PipelineConfigFile);
+		int ret = preference.parsePreferenceFile(path);
+		if (ret) {
+			LOG(IPU3, Error) << "Fail to load pipline config "
+					 << "preference file: " << path;
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera,
 								const StreamRoles &roles)
+{
+	IPU3CameraData *data = cameraData(camera);
+	if (data->hasPreference())
+		return generateConfigurationByPreference(camera, roles);
+
+	return generateConfigurationByCalculation(camera, roles);
+}
+
+CameraConfiguration *PipelineHandlerIPU3::generateConfigurationByCalculation(
+	Camera *camera, const StreamRoles &roles)
 {
 	IPU3CameraData *data = cameraData(camera);
 	IPU3CameraConfiguration *config = new IPU3CameraConfiguration(data);
@@ -505,6 +654,57 @@  CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera,
 	return config;
 }
 
+CameraConfiguration *PipelineHandlerIPU3::generateConfigurationByPreference(
+	Camera *camera, const StreamRoles &roles)
+{
+	IPU3CameraData *data = cameraData(camera);
+	IPU3CameraConfiguration *config = new IPU3CameraConfiguration(data);
+	PipeConfigPreference &preference = data->pipeConfigPreference_;
+
+	if (roles.empty())
+		return config;
+
+	for (const StreamRole role : roles) {
+		std::map<PixelFormat, std::vector<SizeRange>> streamFormats;
+		PixelFormat pixelFormat = formats::NV12;
+		Size size;
+
+		switch (role) {
+		case StreamRole::StillCapture:
+			size = preference.maxStillResolution();
+			streamFormats[pixelFormat] = { { preference.maxStillResolution(),
+							 preference.maxStillResolution() } };
+			break;
+
+		case StreamRole::Viewfinder:
+		case StreamRole::VideoRecording:
+			size = preference.maxVideoResolution();
+			streamFormats[pixelFormat] = { { preference.maxVideoResolution(),
+							 preference.maxVideoResolution() } };
+			break;
+
+		case StreamRole::Raw:
+		default:
+			LOG(IPU3, Error)
+				<< "Requested stream role not supported: " << role;
+			delete config;
+			return nullptr;
+		}
+
+		StreamFormats formats(streamFormats);
+		StreamConfiguration cfg(formats);
+		cfg.size = size;
+		cfg.pixelFormat = pixelFormat;
+		cfg.bufferCount = IPU3CameraConfiguration::kBufferCount;
+		config->addConfiguration(cfg);
+	}
+
+	if (config->validate() == CameraConfiguration::Invalid)
+		return {};
+
+	return config;
+}
+
 int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
 {
 	IPU3CameraConfiguration *config =
@@ -971,6 +1171,15 @@  int PipelineHandlerIPU3::initControls(IPU3CameraData *data)
 	return updateControls(data);
 }
 
+int PipelineHandlerIPU3::initOptions(IPU3CameraData *data)
+{
+	/* Expose IPU3 options. */
+	ControlInfoMap::Map options = IPU3Options;
+	data->optionInfo_ = ControlInfoMap(std::move(options), options::options);
+
+	return 0;
+}
+
 /**
  * \brief Update the camera controls
  * \param[in] data The camera data
@@ -1118,6 +1327,10 @@  int PipelineHandlerIPU3::registerCameras()
 		/* Initialize the camera properties. */
 		data->properties_ = cio2->sensor()->properties();
 
+		ret = initOptions(data.get());
+		if (ret)
+			continue;
+
 		ret = initControls(data.get());
 		if (ret)
 			continue;