From patchwork Fri Apr 5 14:47:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 19855 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id BA31DC32CC for ; Fri, 5 Apr 2024 14:47:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 455D963365; Fri, 5 Apr 2024 16:47:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ICWwGSSC"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 579126335E for ; Fri, 5 Apr 2024 16:47:54 +0200 (CEST) Received: from pyrite.hamster-moth.ts.net (h175-177-049-156.catv02.itscom.jp [175.177.49.156]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9878F8E1; Fri, 5 Apr 2024 16:47:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1712328435; bh=UkIMdnPquCi1Z1Jv8wJhrkji5gwobMzv8tKEA1PGHdM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ICWwGSSCIWHY9LMOVC4IkDb8+dWjhSplx2KNk1BUrR/dmqy436Ezge97LnCbSMeQK gI/ZN39xKIu/a5XyH4AeKJF6E1zy0nSV/OgH/0CYwYjnj+FU+ygRU4ZT+C/u4JpEil rhDf1okULx6+6Y2WfLveDwWF9Es7BC/ILLeh7H4M= From: Paul Elder To: libcamera-devel@lists.libcamera.org Cc: Paul Elder Subject: [PATCH 5/5] ipa: rkisp1: agc: Plumb mode-selection and frame duration controls Date: Fri, 5 Apr 2024 23:47:29 +0900 Message-Id: <20240405144729.2992219-6-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240405144729.2992219-1-paul.elder@ideasonboard.com> References: <20240405144729.2992219-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Plumb controls for setting metering mode, exposure mode, constraint mode, and frame duration limits. Also report them as available controls, as well as in metadata. Signed-off-by: Paul Elder --- src/ipa/rkisp1/algorithms/agc.cpp | 67 ++++++++++++++++++++------- src/ipa/rkisp1/algorithms/agc.h | 5 ++ src/ipa/rkisp1/algorithms/algorithm.h | 2 + src/ipa/rkisp1/ipa_context.h | 4 ++ src/ipa/rkisp1/rkisp1.cpp | 10 ++++ 5 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index a1b6eb39..ed4d6330 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,7 @@ int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData, return -EINVAL; } + std::vector availableMeteringModes; for (const auto &[key, value] : yamlMeteringModes.asDict()) { if (controls::AeMeteringModeNameValueMap.find(key) == controls::AeMeteringModeNameValueMap.end()) { @@ -67,9 +69,14 @@ int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData, return -ENODATA; } - meteringModes_[controls::AeMeteringModeNameValueMap.at(key)] = weights; + int32_t control = controls::AeMeteringModeNameValueMap.at(key); + meteringModes_[control] = weights; + availableMeteringModes.push_back(control); } + Algorithm::controls_[&controls::AeMeteringMode] = + ControlInfo(availableMeteringModes); + return 0; } @@ -131,9 +138,25 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData) context.ctrlMap.merge(controls()); + defaultConstraintMode_ = constraintModes().begin()->first; + defaultExposureMode_ = exposureModeHelpers().begin()->first; + defaultMeteringMode_ = meteringModes_.begin()->first; + + Algorithm::controls_.merge(ControlInfoMap::Map(controls())); + return 0; } +void Agc::configureExposureModeHelpers(IPAContext &context, utils::Duration maxShutterSpeed) +{ + for (auto &[id, helper] : exposureModeHelpers()) { + helper->configure(context.configuration.sensor.minShutterSpeed, + maxShutterSpeed, + context.configuration.sensor.minAnalogueGain, + context.configuration.sensor.maxAnalogueGain); + } +} + /** * \brief Configure the AGC given a configInfo * \param[in] context The shared IPA context @@ -153,12 +176,8 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) context.activeState.agc.manual.dgain = 1; context.activeState.agc.autoEnabled = !context.configuration.raw; - /* - * \todo We should use the first available mode rather than assume that - * the "Normal" modes are present in tuning data. - */ - context.activeState.agc.constraintMode = controls::ConstraintNormal; - context.activeState.agc.exposureMode = controls::ExposureNormal; + context.activeState.agc.constraintMode = defaultConstraintMode_; + context.activeState.agc.exposureMode = defaultExposureMode_; /* * Define the measurement window for AGC as a centered rectangle @@ -169,13 +188,7 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) context.configuration.agc.measureWindow.h_size = 3 * configInfo.outputSize.width / 4; context.configuration.agc.measureWindow.v_size = 3 * configInfo.outputSize.height / 4; - for (auto &[id, helper] : exposureModeHelpers()) { - /* \todo Run this again when FrameDurationLimits is passed in */ - helper->configure(context.configuration.sensor.minShutterSpeed, - context.configuration.sensor.maxShutterSpeed, - context.configuration.sensor.minAnalogueGain, - context.configuration.sensor.maxAnalogueGain); - } + configureExposureModeHelpers(context, context.configuration.sensor.maxShutterSpeed); return 0; } @@ -223,6 +236,20 @@ void Agc::queueRequest(IPAContext &context, frameContext.agc.exposure = agc.manual.exposure; frameContext.agc.gain = agc.manual.gain; } + + const auto &meteringMode = controls.get(controls::AeMeteringMode); + frameContext.agc.meteringMode = meteringMode.value_or(defaultMeteringMode_); + + const auto &exposureMode = controls.get(controls::AeExposureMode); + frameContext.agc.exposureMode = exposureMode.value_or(defaultExposureMode_); + + const auto &constraintMode = controls.get(controls::AeConstraintMode); + frameContext.agc.constraintMode = constraintMode.value_or(defaultConstraintMode_); + + const auto &frameDurationLimits = controls.get(controls::FrameDurationLimits); + frameContext.agc.maxShutterSpeed = frameDurationLimits + ? std::chrono::milliseconds((*frameDurationLimits).back()) + : 60ms; } /** @@ -262,8 +289,7 @@ void Agc::prepare(IPAContext &context, const uint32_t frame, params->meas.hst_config.hist_weight, context.hw->numHistogramWeights }; - /* \todo Get this from control */ - std::vector &modeWeights = meteringModes_.at(controls::MeteringMatrix); + std::vector &modeWeights = meteringModes_.at(frameContext.agc.meteringMode); std::copy(modeWeights.begin(), modeWeights.end(), weights.begin()); std::stringstream str; @@ -290,6 +316,7 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, * frameContext.sensor.exposure; metadata.set(controls::AnalogueGain, frameContext.sensor.gain); metadata.set(controls::ExposureTime, exposureTime.get()); + metadata.set(controls::AeEnable, frameContext.agc.autoEnabled); /* \todo Use VBlank value calculated from each frame exposure. */ uint32_t vTotal = context.configuration.sensor.size.height @@ -297,6 +324,10 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, utils::Duration frameDuration = context.configuration.sensor.lineDuration * vTotal; metadata.set(controls::FrameDuration, frameDuration.get()); + + metadata.set(controls::AeMeteringMode, frameContext.agc.meteringMode); + metadata.set(controls::AeExposureMode, frameContext.agc.exposureMode); + metadata.set(controls::AeConstraintMode, frameContext.agc.constraintMode); } void Agc::parseStatistics(const rkisp1_stat_buffer *stats, @@ -378,6 +409,10 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, ASSERT(stats->meas_type & RKISP1_CIF_ISP_STAT_AUTOEXP); + utils::Duration maxShutterSpeed = std::min(context.configuration.sensor.maxShutterSpeed, + frameContext.agc.maxShutterSpeed); + configureExposureModeHelpers(context, maxShutterSpeed); + parseStatistics(stats, context); /* diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h index 43e3d5b2..c05ba4be 100644 --- a/src/ipa/rkisp1/algorithms/agc.h +++ b/src/ipa/rkisp1/algorithms/agc.h @@ -47,6 +47,7 @@ private: int parseMeteringModes(IPAContext &context, const YamlObject &tuningData, const char *prop); uint8_t predivider(Size &size); + void configureExposureModeHelpers(IPAContext &context, utils::Duration maxShutterSpeed); void fillMetadata(IPAContext &context, IPAFrameContext &frameContext, ControlList &metadata); @@ -58,6 +59,10 @@ private: Span expMeans_; std::map> meteringModes_; + + int32_t defaultConstraintMode_; + int32_t defaultExposureMode_; + int32_t defaultMeteringMode_; }; } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/ipa/rkisp1/algorithms/algorithm.h b/src/ipa/rkisp1/algorithms/algorithm.h index 9454c9a1..c3a002b8 100644 --- a/src/ipa/rkisp1/algorithms/algorithm.h +++ b/src/ipa/rkisp1/algorithms/algorithm.h @@ -25,6 +25,8 @@ public: bool disabled_; bool supportsRaw_; + + ControlInfoMap::Map controls_; }; } /* namespace ipa::rkisp1 */ diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index a70c7eb3..dc876da0 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -114,6 +114,10 @@ struct IPAFrameContext : public FrameContext { double gain; double dgain; bool autoEnabled; + int32_t meteringMode; + int32_t exposureMode; + int32_t constraintMode; + utils::Duration maxShutterSpeed; } agc; struct { diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp index d66dfdd7..3654b5a6 100644 --- a/src/ipa/rkisp1/rkisp1.cpp +++ b/src/ipa/rkisp1/rkisp1.cpp @@ -80,6 +80,7 @@ private: std::map mappedBuffers_; ControlInfoMap sensorControls_; + ControlInfoMap::Map algoControls_; /* Interface to the Camera Helper */ std::unique_ptr camHelper_; @@ -193,6 +194,14 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision, if (ret) return ret; + for (auto const &a : algorithms()) { + Algorithm *algo = static_cast(a.get()); + + /* \todo Avoid merging duplicate controls */ + if (!algo->controls_.empty()) + algoControls_.merge(ControlInfoMap::Map(algo->controls_)); + } + /* Initialize controls. */ updateControls(sensorInfo, sensorControls, ipaControls); @@ -377,6 +386,7 @@ void IPARkISP1::updateControls(const IPACameraSensorInfo &sensorInfo, ControlInfoMap *ipaControls) { ControlInfoMap::Map ctrlMap = rkisp1Controls; + ctrlMap.merge(algoControls_); /* * Compute exposure time limits from the V4L2_CID_EXPOSURE control