diff options
-rw-r--r-- | include/libcamera/ipa/ipu3.mojom | 5 | ||||
-rw-r--r-- | src/ipa/ipu3/ipu3.cpp | 72 | ||||
-rw-r--r-- | src/libcamera/pipeline/ipu3/ipu3.cpp | 95 |
3 files changed, 114 insertions, 58 deletions
diff --git a/include/libcamera/ipa/ipu3.mojom b/include/libcamera/ipa/ipu3.mojom index 911a3a07..d561c224 100644 --- a/include/libcamera/ipa/ipu3.mojom +++ b/include/libcamera/ipa/ipu3.mojom @@ -38,7 +38,10 @@ struct IPAConfigInfo { }; interface IPAIPU3Interface { - init(libcamera.IPASettings settings) => (int32 ret); + init(libcamera.IPASettings settings, + libcamera.IPACameraSensorInfo sensorInfo, + libcamera.ControlInfoMap sensorControls) + => (int32 ret, libcamera.ControlInfoMap ipaControls); start() => (int32 ret); stop(); diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp index c903f751..36a06966 100644 --- a/src/ipa/ipu3/ipu3.cpp +++ b/src/ipa/ipu3/ipu3.cpp @@ -5,7 +5,9 @@ * ipu3.cpp - IPU3 Image Processing Algorithms */ +#include <array> #include <stdint.h> +#include <utility> #include <linux/intel-ipu3.h> #include <linux/v4l2-controls.h> @@ -37,7 +39,11 @@ namespace ipa::ipu3 { class IPAIPU3 : public IPAIPU3Interface { public: - int init(const IPASettings &settings) override; + int init(const IPASettings &settings, + const IPACameraSensorInfo &sensorInfo, + const ControlInfoMap &sensorControls, + ControlInfoMap *ipaControls) override; + int start() override; void stop() override {} @@ -85,14 +91,74 @@ private: struct ipu3_uapi_grid_config bdsGrid_; }; -int IPAIPU3::init(const IPASettings &settings) +/** + * Initialize the IPA module and its controls. + * + * This function receives the camera sensor information from the pipeline + * handler, computes the limits of the controls it handles and returns + * them in the \a ipaControls output parameter. + */ +int IPAIPU3::init(const IPASettings &settings, + const IPACameraSensorInfo &sensorInfo, + const ControlInfoMap &sensorControls, + ControlInfoMap *ipaControls) { camHelper_ = CameraSensorHelperFactory::create(settings.sensorModel); if (camHelper_ == nullptr) { - LOG(IPAIPU3, Error) << "Failed to create camera sensor helper for " << settings.sensorModel; + LOG(IPAIPU3, Error) + << "Failed to create camera sensor helper for " + << settings.sensorModel; return -ENODEV; } + /* Initialize Controls. */ + ControlInfoMap::Map controls{}; + + /* + * Compute exposure time limits. + * + * Initialize the control using the line length and pixel rate of the + * current configuration converted to microseconds. Use the + * V4L2_CID_EXPOSURE control to get exposure min, max and default and + * convert it from lines to microseconds. + */ + double lineDuration = sensorInfo.lineLength / (sensorInfo.pixelRate / 1e6); + const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second; + int32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration; + int32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration; + int32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration; + controls[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure, + defExposure); + + /* + * Compute the frame duration limits. + * + * The frame length is computed assuming a fixed line length combined + * with the vertical frame sizes. + */ + const ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second; + uint32_t hblank = v4l2HBlank.def().get<int32_t>(); + uint32_t lineLength = sensorInfo.outputSize.width + hblank; + + const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second; + std::array<uint32_t, 3> frameHeights{ + v4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height, + v4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height, + v4l2VBlank.def().get<int32_t>() + sensorInfo.outputSize.height, + }; + + std::array<int64_t, 3> frameDurations; + for (unsigned int i = 0; i < frameHeights.size(); ++i) { + uint64_t frameSize = lineLength * frameHeights[i]; + frameDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U); + } + + controls[&controls::FrameDurationLimits] = ControlInfo(frameDurations[0], + frameDurations[1], + frameDurations[2]); + + *ipaControls = ControlInfoMap(std::move(controls), controls::controls); + return 0; } diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 9c23788e..6e26a7b7 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -88,6 +88,8 @@ public: std::queue<Request *> pendingRequests_; + ControlInfoMap ipaControls_; + private: void queueFrameAction(unsigned int id, const ipa::ipu3::IPU3Action &action); @@ -954,7 +956,6 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data) return ret; ControlInfoMap::Map controls = IPU3Controls; - const ControlInfoMap &sensorControls = sensor->controls(); const std::vector<int32_t> &testPatternModes = sensor->testPatternModes(); if (!testPatternModes.empty()) { std::vector<ControlValue> values; @@ -967,58 +968,6 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data) } /* - * Compute exposure time limits. - * - * Initialize the control using the line length and pixel rate of the - * current configuration converted to microseconds. Use the - * V4L2_CID_EXPOSURE control to get exposure min, max and default and - * convert it from lines to microseconds. - */ - double lineDuration = sensorInfo.lineLength - / (sensorInfo.pixelRate / 1e6); - const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second; - int32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration; - int32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration; - int32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration; - - /* - * \todo Report the actual exposure time, use the default for the - * moment. - */ - data->exposureTime_ = defExposure; - - controls[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure, - defExposure); - - /* - * Compute the frame duration limits. - * - * The frame length is computed assuming a fixed line length combined - * with the vertical frame sizes. - */ - const ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second; - uint32_t hblank = v4l2HBlank.def().get<int32_t>(); - uint32_t lineLength = sensorInfo.outputSize.width + hblank; - - const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second; - std::array<uint32_t, 3> frameHeights{ - v4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height, - v4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height, - v4l2VBlank.def().get<int32_t>() + sensorInfo.outputSize.height, - }; - - std::array<int64_t, 3> frameDurations; - for (unsigned int i = 0; i < frameHeights.size(); ++i) { - uint64_t frameSize = lineLength * frameHeights[i]; - frameDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U); - } - - controls[&controls::FrameDurationLimits] = - ControlInfo(frameDurations[0], - frameDurations[1], - frameDurations[2]); - - /* * Compute the scaler crop limits. * * Initialize the control use the 'Viewfinder' configuration (1280x720) @@ -1071,6 +1020,21 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data) controls[&controls::ScalerCrop] = ControlInfo(minCrop, maxCrop, maxCrop); + /* + * \todo Report the actual exposure time, use the default for the + * moment. + */ + const auto exposureInfo = data->ipaControls_.find(&controls::ExposureTime); + if (exposureInfo == data->ipaControls_.end()) { + LOG(IPU3, Error) << "Exposure control not initialized by the IPA"; + return -EINVAL; + } + data->exposureTime_ = exposureInfo->second.def().get<int32_t>(); + + /* Add the IPA registered controls to list of camera controls. */ + for (const auto &ipaControl : data->ipaControls_) + controls[ipaControl.first] = ipaControl.second; + data->controlInfo_ = ControlInfoMap(std::move(controls), controls::controls); @@ -1223,8 +1187,31 @@ int IPU3CameraData::loadIPA() ipa_->queueFrameAction.connect(this, &IPU3CameraData::queueFrameAction); + /* + * Pass the sensor info to the IPA to initialize controls. + * + * \todo Find a way to initialize IPA controls without basing their + * limits on a particular sensor mode. We currently pass sensor + * information corresponding to the largest sensor resolution, and the + * IPA uses this to compute limits for supported controls. There's a + * discrepancy between the need to compute IPA control limits at init + * time, and the fact that those limits may depend on the sensor mode. + * Research is required to find out to handle this issue. + */ CameraSensor *sensor = cio2_.sensor(); - int ret = ipa_->init(IPASettings{ "", sensor->model() }); + V4L2SubdeviceFormat sensorFormat = {}; + sensorFormat.size = sensor->resolution(); + int ret = sensor->setFormat(&sensorFormat); + if (ret) + return ret; + + IPACameraSensorInfo sensorInfo{}; + ret = sensor->sensorInfo(&sensorInfo); + if (ret) + return ret; + + ret = ipa_->init(IPASettings{ "", sensor->model() }, sensorInfo, + sensor->controls(), &ipaControls_); if (ret) { LOG(IPU3, Error) << "Failed to initialise the IPU3 IPA"; return ret; |