From patchwork Mon Jun 28 20:22:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Michel Hautbois X-Patchwork-Id: 12736 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 BDE1CC321F for ; Mon, 28 Jun 2021 20:23:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1BEE5684D8; Mon, 28 Jun 2021 22:23:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ecW4Ei0D"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EAFC96028C for ; Mon, 28 Jun 2021 22:22:59 +0200 (CEST) Received: from tatooine.ideasonboard.com (unknown [IPv6:2a01:e0a:169:7140:c3ad:78d0:405e:fc33]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 850C42469; Mon, 28 Jun 2021 22:22:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1624911779; bh=HLV5ikFkBJGLKW4IBLAbblWhbwLbX0j/IMpYingacCM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ecW4Ei0DCgoJEAAs5XXnX69Euzk9dSwRrbS3BTdWqn4ivc8iC1hXuKSgMdb7RzPw5 XYx6gCFCgG7Keligw7Ijrp8iKKzCzCnlwFcBf+LoKi3SUszjifAamYOeLkow4cRGZV FQjgkn6Yz6flnaJ1OLzJyjaPRUoNYinfkce+KzUE= From: Jean-Michel Hautbois To: libcamera-devel@lists.libcamera.org Date: Mon, 28 Jun 2021 22:22:49 +0200 Message-Id: <20210628202255.138874-2-jeanmichel.hautbois@ideasonboard.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> References: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 1/7] ipa: libipa: Fixups in CameraSensorHelpers 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" A few lines needed to be wrapped under 80 lines. Remove some uneeded documentation and minor typos. Signed-off-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/ipa/libipa/camera_sensor_helper.cpp | 79 +++++++++++++------------ src/ipa/libipa/camera_sensor_helper.h | 32 +++++----- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp index 23335ed6..848842ce 100644 --- a/src/ipa/libipa/camera_sensor_helper.cpp +++ b/src/ipa/libipa/camera_sensor_helper.cpp @@ -2,11 +2,12 @@ /* * Copyright (C) 2021, Google Inc. * - * camera_sensor_helper.cpp - Helper class that performs sensor-specific parameter computations + * camera_sensor_helper.cpp - Helper class that performs sensor-specific + * parameter computations */ #include "camera_sensor_helper.h" -#include "libcamera/base/log.h" +#include /** * \file camera_sensor_helper.h @@ -29,17 +30,18 @@ namespace ipa { /** * \class CameraSensorHelper - * \brief Base class for computing sensor tuning parameters using sensor-specific constants + * \brief Base class for computing sensor tuning parameters using + * sensor-specific constants * - * Instances derived from CameraSensorHelper class are sensor specific. + * Instances derived from CameraSensorHelper class are sensor-specific. * Each supported sensor will have an associated base class defined. */ /** * \brief Construct a CameraSensorHelper instance * - * CameraSensorHelper derived class instances shall never be constructed manually - * but always through the CameraSensorHelperFactory::create() method. + * CameraSensorHelper derived class instances shall never be constructed + * manually but always through the CameraSensorHelperFactory::create() method. */ /** @@ -52,11 +54,11 @@ namespace ipa { * The parameters come from the MIPI Alliance Camera Specification for * Camera Command Set (CCS). * - * \return The gain code to pass to V4l2 + * \return The gain code to pass to V4L2 */ uint32_t CameraSensorHelper::gainCode(double gain) const { - ASSERT((analogueGainConstants_.m0 == 0) || (analogueGainConstants_.m1 == 0)); + ASSERT(analogueGainConstants_.m0 == 0 || analogueGainConstants_.m1 == 0); ASSERT(analogueGainConstants_.type == AnalogueGainLinear); return (analogueGainConstants_.c0 - analogueGainConstants_.c1 * gain) / @@ -64,8 +66,8 @@ uint32_t CameraSensorHelper::gainCode(double gain) const } /** - * \brief Compute the real gain from the V4l2 subdev control gain code - * \param[in] gainCode The V4l2 subdev control gain + * \brief Compute the real gain from the V4L2 subdev control gain code + * \param[in] gainCode The V4L2 subdev control gain * * This function aims to abstract the calculation of the gain letting the IPA * use the real gain for its estimations. It is the counterpart of the function @@ -78,7 +80,7 @@ uint32_t CameraSensorHelper::gainCode(double gain) const */ double CameraSensorHelper::gain(uint32_t gainCode) const { - ASSERT((analogueGainConstants_.m0 == 0) || (analogueGainConstants_.m1 == 0)); + ASSERT(analogueGainConstants_.m0 == 0 || analogueGainConstants_.m1 == 0); ASSERT(analogueGainConstants_.type == AnalogueGainLinear); return (analogueGainConstants_.m0 * static_cast(gainCode) + analogueGainConstants_.c0) / @@ -90,7 +92,7 @@ double CameraSensorHelper::gain(uint32_t gainCode) const * \brief The gain calculation modes as defined by the MIPI CCS * * Describes the image sensor analogue gain capabilities. - * Two modes are possible, depending on the sensor: Global and Alternate. + * Two modes are possible, depending on the sensor: Linear and Exponential. */ /** @@ -114,11 +116,12 @@ double CameraSensorHelper::gain(uint32_t gainCode) const /** * \var CameraSensorHelper::AnalogueGainExponential - * \brief Gain is computed using exponential gain estimation (introduced in CCS v1.1) + * \brief Gain is computed using exponential gain estimation + * (introduced in CCS v1.1) * * Starting with CCS v1.1, Alternate Global Analogue Gain is also available. - * If the image sensor supports it, then the global analogue gain can be controlled - * by linear and exponential gain formula: + * If the image sensor supports it, then the global analogue gain can be + * controlled by linear and exponential gain formula: * * \f$gain = analogLinearGainGlobal * 2^{analogExponentialGainGlobal}\f$ * \todo not implemented in libipa @@ -194,11 +197,13 @@ CameraSensorHelperFactory::CameraSensorHelperFactory(const std::string name) } /** - * \brief Create an instance of the CameraSensorHelper corresponding to the factory + * \brief Create an instance of the CameraSensorHelper corresponding to + * a named factory * \param[in] name Name of the factory * * \return A unique pointer to a new instance of the CameraSensorHelper subclass - * corresponding to the factory + * corresponding to the named factory or a null pointer if no such factory + * exists */ std::unique_ptr CameraSensorHelperFactory::create(const std::string &name) { @@ -220,33 +225,35 @@ std::unique_ptr CameraSensorHelperFactory::create(const std: * \brief Add a camera sensor helper class to the registry * \param[in] factory Factory to use to construct the camera sensor helper * - * The caller is responsible to guarantee the uniqueness of the camera sensor helper - * name. + * The caller is responsible to guarantee the uniqueness of the camera sensor + * helper name. */ void CameraSensorHelperFactory::registerType(CameraSensorHelperFactory *factory) { - std::vector &factories = CameraSensorHelperFactory::factories(); + std::vector &factories = + CameraSensorHelperFactory::factories(); factories.push_back(factory); } /** * \brief Retrieve the list of all camera sensor helper factories - * - * The static factories map is defined inside the function to ensures it gets - * initialized on first use, without any dependency on link order. - * * \return The list of camera sensor helper factories */ std::vector &CameraSensorHelperFactory::factories() { + /* The static factories map is defined inside the function to ensures + * it gets initialized on first use, without any dependency on link + * order. + */ static std::vector factories; return factories; } /** * \fn CameraSensorHelperFactory::createInstance() - * \brief Create an instance of the CameraSensorHelper corresponding to the factory + * \brief Create an instance of the CameraSensorHelper corresponding to the + * factory * * This virtual function is implemented by the REGISTER_CAMERA_SENSOR_HELPER() * macro. It creates a camera sensor helper instance associated with the camera @@ -267,14 +274,16 @@ std::vector &CameraSensorHelperFactory::factories() * \param[in] name Sensor model name used to register the class * \param[in] helper Class name of CameraSensorHelper derived class to register * - * Register a CameraSensorHelper subclass with the factory and make it available to - * try and match devices. + * Register a CameraSensorHelper subclass with the factory and make it available + * to try and match sensors. */ -/** - * \class CameraSensorHelperImx219 - * \brief Create and give helpers for the imx219 sensor +/* ----------------------------------------------------------------------------- + * Sensor-specific subclasses */ + +#ifndef __DOXYGEN__ + class CameraSensorHelperImx219 : public CameraSensorHelper { public: @@ -285,10 +294,6 @@ public: }; REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219) -/** - * \class CameraSensorHelperOv5670 - * \brief Create and give helpers for the ov5670 sensor - */ class CameraSensorHelperOv5670 : public CameraSensorHelper { public: @@ -299,10 +304,6 @@ public: }; REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670) -/** - * \class CameraSensorHelperOv5693 - * \brief Create and give helpers for the ov5693 sensor - */ class CameraSensorHelperOv5693 : public CameraSensorHelper { public: @@ -313,6 +314,8 @@ public: }; REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693) +#endif /* __DOXYGEN__ */ + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h index 1c47e8d5..a7e4ab3b 100644 --- a/src/ipa/libipa/camera_sensor_helper.h +++ b/src/ipa/libipa/camera_sensor_helper.h @@ -30,8 +30,8 @@ public: protected: enum AnalogueGainType { - AnalogueGainLinear = 0, - AnalogueGainExponential = 2, + AnalogueGainLinear, + AnalogueGainExponential, }; struct AnalogueGainConstants { @@ -60,24 +60,26 @@ public: static std::vector &factories(); protected: - LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelperFactory) virtual CameraSensorHelper *createInstance() = 0; +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelperFactory) + std::string name_; }; -#define REGISTER_CAMERA_SENSOR_HELPER(name, helper) \ -class helper##Factory final : public CameraSensorHelperFactory \ -{ \ -public: \ - helper##Factory() : CameraSensorHelperFactory(name) {} \ - \ -private: \ - CameraSensorHelper *createInstance() \ - { \ - return new helper(); \ - } \ -}; \ +#define REGISTER_CAMERA_SENSOR_HELPER(name, helper) \ +class helper##Factory final : public CameraSensorHelperFactory \ +{ \ +public: \ + helper##Factory() : CameraSensorHelperFactory(name) {} \ + \ +private: \ + CameraSensorHelper *createInstance() \ + { \ + return new helper(); \ + } \ +}; \ static helper##Factory global_##helper##Factory; } /* namespace ipa */ From patchwork Mon Jun 28 20:22:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Michel Hautbois X-Patchwork-Id: 12737 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 DE526C321F for ; Mon, 28 Jun 2021 20:23:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 11FC7684DF; Mon, 28 Jun 2021 22:23:04 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="E+AhN7OK"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2C82360508 for ; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) Received: from tatooine.ideasonboard.com (unknown [IPv6:2a01:e0a:169:7140:c3ad:78d0:405e:fc33]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BF575E1A; Mon, 28 Jun 2021 22:22:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1624911779; bh=xkdDA1ZOoupVOv9QCvdpZOzjk0vdTtZMgVmltEckeRU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E+AhN7OKSh4n3qHi+lYvPn3rbxS0TnIXDFuEKOzrvogrMyxMD4c7BX8ut186F8+bU 3a8CybOvYwz63Wnx5XIYrPisKIxm60tYgObEJtNBPSZvfToAgTZF/nvBVLrM61Ctgi +/dkCrbVOvRYo+bJ96z3+HwC2mZ7hI5DvFlhIg1s= From: Jean-Michel Hautbois To: libcamera-devel@lists.libcamera.org Date: Mon, 28 Jun 2021 22:22:50 +0200 Message-Id: <20210628202255.138874-3-jeanmichel.hautbois@ideasonboard.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> References: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 2/7] ipa: libipa: Create a common ISP header to store the structure types 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" Each ISP may use the same AWB or AGC algorithms. In order to avoid duplicated code, create a header with the main structures used for now. Signed-off-by: Jean-Michel Hautbois --- src/ipa/ipu3/ipu3_agc.h | 1 + src/ipa/ipu3/ipu3_awb.h | 30 +---------- src/ipa/libipa/isp.h | 110 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 29 deletions(-) create mode 100644 src/ipa/libipa/isp.h diff --git a/src/ipa/ipu3/ipu3_agc.h b/src/ipa/ipu3/ipu3_agc.h index 3deca3ae..6ca9af8e 100644 --- a/src/ipa/ipu3/ipu3_agc.h +++ b/src/ipa/ipu3/ipu3_agc.h @@ -17,6 +17,7 @@ #include #include "libipa/algorithm.h" +#include "libipa/isp.h" namespace libcamera { diff --git a/src/ipa/ipu3/ipu3_awb.h b/src/ipa/ipu3/ipu3_awb.h index 122cf68c..6ae111fd 100644 --- a/src/ipa/ipu3/ipu3_awb.h +++ b/src/ipa/ipu3/ipu3_awb.h @@ -14,6 +14,7 @@ #include #include "libipa/algorithm.h" +#include "libipa/isp.h" namespace libcamera { @@ -42,35 +43,6 @@ public: unsigned char padding[3]; } __attribute__((packed)); - /* \todo Make these three structs available to all the ISPs ? */ - struct RGB { - RGB(double _R = 0, double _G = 0, double _B = 0) - : R(_R), G(_G), B(_B) - { - } - double R, G, B; - RGB &operator+=(RGB const &other) - { - R += other.R, G += other.G, B += other.B; - return *this; - } - }; - - struct IspStatsRegion { - unsigned int counted; - unsigned int uncounted; - unsigned long long rSum; - unsigned long long gSum; - unsigned long long bSum; - }; - - struct AwbStatus { - double temperatureK; - double redGain; - double greenGain; - double blueGain; - }; - private: void generateZones(std::vector &zones); void generateAwbStats(const ipu3_uapi_stats_3a *stats); diff --git a/src/ipa/libipa/isp.h b/src/ipa/libipa/isp.h new file mode 100644 index 00000000..a15803d6 --- /dev/null +++ b/src/ipa/libipa/isp.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Ideas On Board + * + * isp.h - ISP statistics interface + */ +#ifndef __LIBCAMERA_IPA_LIBIPA_ISP_H__ +#define __LIBCAMERA_IPA_LIBIPA_ISP_H__ + +namespace libcamera { + +namespace ipa { +/** + * \struct RGB + * \brief RGB + * + * \fn RGB::RGB + * \brief Construct a RGB structure + * \param[in] _R Red value to set, defaults to 0 + * \param[in] _G Green value to set, defaults to 0 + * \param[in] _B Blue value to set, defaults to 0 + * + * \var RGB::R + * \brief Red value of the RGB structure + * + * \var RGB::G + * \brief Green value of the RGB structure + * + * \var RGB::B + * \brief Blue value of the RGB structure + * + * \fn RGB &RGB::operator+=(RGB const &other) + * \brief Add each RGB value to another RGB structure + * \param[in] other An RGB structure + * \return An RGB structure containing the added R, G and B values + */ +struct RGB { + RGB(double _R = 0, double _G = 0, double _B = 0) + : R(_R), G(_G), B(_B) + { + } + double R, G, B; + RGB &operator+=(RGB const &other) + { + R += other.R, G += other.G, B += other.B; + return *this; + } +}; + +/** + * \struct IspStatsRegion + * \brief RGB statistics for a given region + * + * The IspStatsRegion structure is intended to abstract the ISP specific + * statistics and use an agnostic algorithm to compute AWB. + * + * \var IspStatsRegion::counted + * \brief Number of pixels used to calculate the sums + * + * \var IspStatsRegion::uncounted + * \brief Remaining number of pixels in the region + * + * \var IspStatsRegion::rSum + * \brief Sum of the red values in the region + * + * \var IspStatsRegion::gSum + * \brief Sum of the green values in the region + * + * \var IspStatsRegion::bSum + * \brief Sum of the blue values in the region + */ +struct IspStatsRegion { + unsigned int counted; + unsigned int uncounted; + unsigned long long rSum; + unsigned long long gSum; + unsigned long long bSum; +}; + +/** + * \struct AwbStatus + * \brief AWB parameters calculated + * + * The AwbStatus structure is intended to store the AWB + * parameters calculated by the algorithm + * + * \var AwbStatus::temperatureK + * \brief Color temperature calculated + * + * \var AwbStatus::redGain + * \brief Gain calculated for the red channel + * + * \var AwbStatus::greenGain + * \brief Gain calculated for the green channel + * + * \var AwbStatus::blueGain + * \brief Gain calculated for the blue channel + */ +struct AwbStatus { + double temperatureK; + double redGain; + double greenGain; + double blueGain; +}; + +} /* namespace ipa */ + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_LIBIPA_ISP_H__ */ From patchwork Mon Jun 28 20:22:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Michel Hautbois X-Patchwork-Id: 12738 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 AC442C321F for ; Mon, 28 Jun 2021 20:23:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2546E684DA; Mon, 28 Jun 2021 22:23:05 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PQ5knaXr"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4B4E66028C for ; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) Received: from tatooine.ideasonboard.com (unknown [IPv6:2a01:e0a:169:7140:c3ad:78d0:405e:fc33]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EFC9B26FE; Mon, 28 Jun 2021 22:22:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1624911780; bh=Z1+aTxtelZoqMZmGab2uUv6Y2wd+AI/zZc5WyJunc8U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PQ5knaXrwVmGGoqvbAhC4+ruYb+B5oJf2Hw5WABufXOQ2I5EsIiE4tKg6PgjVgxW4 TsV62sGoGvs+Otz8YYOCicSP0I90DY1DOBbk2vwXJ0Y262i6uTv5ZrA2JhDCaevFQ1 LhmmsB9nxoBzES2I5HJT9Ye5sWI9t6b7F82N8T6k= From: Jean-Michel Hautbois To: libcamera-devel@lists.libcamera.org Date: Mon, 28 Jun 2021 22:22:51 +0200 Message-Id: <20210628202255.138874-4-jeanmichel.hautbois@ideasonboard.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> References: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 3/7] ipa: ipu3: Use a common IPU3 header for the constants 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" Every constants used can be needed by both AWB and AGC (for the moment). Use a common header to simplify their usage. Signed-off-by: Jean-Michel Hautbois --- src/ipa/ipu3/ipu3_agc.h | 2 ++ src/ipa/ipu3/ipu3_awb.h | 11 ++------- src/ipa/ipu3/ipu3_common.h | 49 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 src/ipa/ipu3/ipu3_common.h diff --git a/src/ipa/ipu3/ipu3_agc.h b/src/ipa/ipu3/ipu3_agc.h index 6ca9af8e..774c8385 100644 --- a/src/ipa/ipu3/ipu3_agc.h +++ b/src/ipa/ipu3/ipu3_agc.h @@ -7,6 +7,8 @@ #ifndef __LIBCAMERA_IPU3_AGC_H__ #define __LIBCAMERA_IPU3_AGC_H__ +#include "ipu3_common.h" + #include #include diff --git a/src/ipa/ipu3/ipu3_awb.h b/src/ipa/ipu3/ipu3_awb.h index 6ae111fd..f4100f4a 100644 --- a/src/ipa/ipu3/ipu3_awb.h +++ b/src/ipa/ipu3/ipu3_awb.h @@ -7,6 +7,8 @@ #ifndef __LIBCAMERA_IPU3_AWB_H__ #define __LIBCAMERA_IPU3_AWB_H__ +#include "ipu3_common.h" + #include #include @@ -34,15 +36,6 @@ public: void calculateWBGains(const ipu3_uapi_stats_3a *stats); void updateWbParameters(ipu3_uapi_params ¶ms, double agcGamma); - struct Ipu3AwbCell { - unsigned char greenRedAvg; - unsigned char redAvg; - unsigned char blueAvg; - unsigned char greenBlueAvg; - unsigned char satRatio; - unsigned char padding[3]; - } __attribute__((packed)); - private: void generateZones(std::vector &zones); void generateAwbStats(const ipu3_uapi_stats_3a *stats); diff --git a/src/ipa/ipu3/ipu3_common.h b/src/ipa/ipu3/ipu3_common.h new file mode 100644 index 00000000..38ef49ce --- /dev/null +++ b/src/ipa/ipu3/ipu3_common.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Ideas On Board + * + * isp.h - ISP statistics interface + */ +#ifndef __LIBCAMERA_IPA_IPU3_COMMON_H__ +#define __LIBCAMERA_IPA_IPU3_COMMON_H__ + +#include + +namespace libcamera { + +namespace ipa { + +/* Region size for the statistics generation algorithm */ +static constexpr uint32_t kAwbStatsSizeX = 16; +static constexpr uint32_t kAwbStatsSizeY = 12; +static constexpr uint32_t kAwbStatsSize = kAwbStatsSizeX * kAwbStatsSizeY + 1; + +static constexpr uint32_t kAgcStatsSizeX = 7; +static constexpr uint32_t kAgcStatsSizeY = 5; +static constexpr uint32_t kAgcStatsSize = kAgcStatsSizeX * kAgcStatsSizeY + 1; +static constexpr uint32_t kNumAgcWeightedZones = 15; +static constexpr double kCenteredWeights[kNumAgcWeightedZones] = { 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0 }; +static constexpr uint32_t kAgcStatsRegions[kAgcStatsSize] = { + 11, 9, 9, 9, 9, 9, 12, + 7, 5, 3, 3, 3, 6, 8, + 7, 5, 1, 0, 2, 6, 8, + 7, 5, 4, 4, 4, 6, 8, + 13, 10, 10, 10, 10, 10, 14 +}; + +static constexpr uint32_t kMinGreenLevelInZone = 16; + +struct Ipu3AwbCell { + unsigned char greenRedAvg; + unsigned char redAvg; + unsigned char blueAvg; + unsigned char greenBlueAvg; + unsigned char satRatio; + unsigned char padding[3]; +} __attribute__((packed)); + +} /* namespace ipa */ + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_IPU3_COMMON_H__ */ From patchwork Mon Jun 28 20:22:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Michel Hautbois X-Patchwork-Id: 12739 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 841C0C321F for ; Mon, 28 Jun 2021 20:23:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 24372684EA; Mon, 28 Jun 2021 22:23:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RXsaMKMn"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 83C63684D8 for ; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) Received: from tatooine.ideasonboard.com (unknown [IPv6:2a01:e0a:169:7140:c3ad:78d0:405e:fc33]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2D0532469; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1624911780; bh=Y0h3Bcoe7Rnm7xKKbZTDs4vuo3agSQr8boF6ViMbg+I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RXsaMKMn1ZMG66pWpwa8eP43kQAqJATB1+WD8fJylrqYaURtvgxPPfhAahOOp04RV 6hbKgD+qcPusAWiHZE05/Rskzjx1IrgMR6Xryc0XMNVsQERDfv4+vNOkIf7Vy39Alm i5N9+30SbKEngChQXazNiVDgrnN4XM3U6P1nLLU0= From: Jean-Michel Hautbois To: libcamera-devel@lists.libcamera.org Date: Mon, 28 Jun 2021 22:22:52 +0200 Message-Id: <20210628202255.138874-5-jeanmichel.hautbois@ideasonboard.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> References: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 4/7] ipa: ipu3: use process method for all algorithms 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" The main goal will be to have the same process() prototype for all algorithms, each of them would then grab the values needed using a metadata exchange way (for instance, current analogue gain, shutter time, or red/blue gains calculated in the AWB algorithm from AGC, etc.). Signed-off-by: Jean-Michel Hautbois --- src/ipa/ipu3/ipu3.cpp | 2 +- src/ipa/ipu3/ipu3_awb.cpp | 5 +++++ src/ipa/ipu3/ipu3_awb.h | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp index f43f8620..4466391a 100644 --- a/src/ipa/ipu3/ipu3.cpp +++ b/src/ipa/ipu3/ipu3.cpp @@ -296,7 +296,7 @@ void IPAIPU3::parseStatistics(unsigned int frame, agcAlgo_->process(stats, exposure_, gain); gain_ = camHelper_->gainCode(gain); - awbAlgo_->calculateWBGains(stats); + awbAlgo_->process(stats); if (agcAlgo_->updateControls()) setControls(frame); diff --git a/src/ipa/ipu3/ipu3_awb.cpp b/src/ipa/ipu3/ipu3_awb.cpp index 9b409c8f..a94935c5 100644 --- a/src/ipa/ipu3/ipu3_awb.cpp +++ b/src/ipa/ipu3/ipu3_awb.cpp @@ -351,6 +351,11 @@ void IPU3Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats) } } +void IPU3Awb::process(const ipu3_uapi_stats_3a *stats) +{ + calculateWBGains(stats); +} + void IPU3Awb::updateWbParameters(ipu3_uapi_params ¶ms, double agcGamma) { /* diff --git a/src/ipa/ipu3/ipu3_awb.h b/src/ipa/ipu3/ipu3_awb.h index f4100f4a..795e32e3 100644 --- a/src/ipa/ipu3/ipu3_awb.h +++ b/src/ipa/ipu3/ipu3_awb.h @@ -33,7 +33,7 @@ public: ~IPU3Awb(); void initialise(ipu3_uapi_params ¶ms, const Size &bdsOutputSize, struct ipu3_uapi_grid_config &bdsGrid); - void calculateWBGains(const ipu3_uapi_stats_3a *stats); + void process(const ipu3_uapi_stats_3a *stats); void updateWbParameters(ipu3_uapi_params ¶ms, double agcGamma); private: @@ -42,6 +42,7 @@ private: void clearAwbStats(); void awbGreyWorld(); uint32_t estimateCCT(double red, double green, double blue); + void calculateWBGains(const ipu3_uapi_stats_3a *stats); struct ipu3_uapi_grid_config awbGrid_; From patchwork Mon Jun 28 20:22:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Michel Hautbois X-Patchwork-Id: 12740 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 20E76C321F for ; Mon, 28 Jun 2021 20:23:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C0323684D8; Mon, 28 Jun 2021 22:23:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="T+qxM5m8"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A526A60508 for ; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) Received: from tatooine.ideasonboard.com (unknown [IPv6:2a01:e0a:169:7140:c3ad:78d0:405e:fc33]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5D829E1A; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1624911780; bh=tBFLU0Yeg3WjK5ACTVDZvPYeav6Mg9xubS1dBFY8Yuo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=T+qxM5m8xllxmC27Vs9iib5ZxfmY5yvvmU6vCCyegNLzkj17wk9gYiZqfS5utvA+Q 4PejKKi8DPzoL39W1m4SykaWUrTCetJdRATgTeVqLVT6mtxSztDN3hHPy2wPAgWrKk SRF53GRGhkni2Eoj6yIXdKN4o/1YDYJvdb7kZZZ8= From: Jean-Michel Hautbois To: libcamera-devel@lists.libcamera.org Date: Mon, 28 Jun 2021 22:22:53 +0200 Message-Id: <20210628202255.138874-6-jeanmichel.hautbois@ideasonboard.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> References: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 5/7] ipa: ipu3: Improve AWB behaviour 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" In order to use a better grid, clamp the values calculated from the BDS resolution to at least 2 times the minimum grid size. The number of zones needed to have sufficiently relevant statistics is now based on the region sizes and not on an arbitrary value. Last, the default green gains where not properly used, it should be 8192 and not 4096 to have a multiplier of 1.0 on the R/G/B gains. The default CCM is adjusted for Surface Go2 only, and should eventually be calculated in the CameraSensorHelper class. Signed-off-by: Jean-Michel Hautbois --- src/ipa/ipu3/ipu3.cpp | 12 ++++++++---- src/ipa/ipu3/ipu3_awb.cpp | 23 +++++++++++------------ src/ipa/ipu3/ipu3_awb.h | 1 + 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp index 4466391a..9a2def64 100644 --- a/src/ipa/ipu3/ipu3.cpp +++ b/src/ipa/ipu3/ipu3.cpp @@ -123,12 +123,16 @@ void IPAIPU3::calculateBdsGrid(const Size &bdsOutputSize) bdsGrid_ = {}; for (uint32_t widthShift = 3; widthShift <= 7; ++widthShift) { - uint32_t width = std::min(kMaxCellWidthPerSet, - bdsOutputSize.width >> widthShift); + uint32_t width = std::clamp(bdsOutputSize.width >> widthShift, + 2 * kAwbStatsSizeX, + kMaxCellWidthPerSet); + width = width << widthShift; for (uint32_t heightShift = 3; heightShift <= 7; ++heightShift) { - int32_t height = std::min(kMaxCellHeightPerSet, - bdsOutputSize.height >> heightShift); + uint32_t height = std::clamp(bdsOutputSize.height >> heightShift, + 2 * kAwbStatsSizeY, + kMaxCellHeightPerSet); + height = height << heightShift; uint32_t error = std::abs(static_cast(width - bdsOutputSize.width)) + std::abs(static_cast(height - bdsOutputSize.height)); diff --git a/src/ipa/ipu3/ipu3_awb.cpp b/src/ipa/ipu3/ipu3_awb.cpp index a94935c5..a39536b0 100644 --- a/src/ipa/ipu3/ipu3_awb.cpp +++ b/src/ipa/ipu3/ipu3_awb.cpp @@ -18,9 +18,6 @@ namespace ipa::ipu3 { LOG_DEFINE_CATEGORY(IPU3Awb) -static constexpr uint32_t kMinZonesCounted = 16; -static constexpr uint32_t kMinGreenLevelInZone = 32; - /** * \struct IspStatsRegion * \brief RGB statistics for a given region @@ -92,7 +89,7 @@ static constexpr uint32_t kMinGreenLevelInZone = 32; /* Default settings for Bayer noise reduction replicated from the Kernel */ static const struct ipu3_uapi_bnr_static_config imguCssBnrDefaults = { - .wb_gains = { 16, 16, 16, 16 }, + .wb_gains = { 8192, 8192, 8192, 8192 }, .wb_gains_thr = { 255, 255, 255, 255 }, .thr_coeffs = { 1700, 0, 31, 31, 0, 16 }, .thr_ctrl_shd = { 26, 26, 26, 26 }, @@ -130,7 +127,7 @@ static const struct ipu3_uapi_awb_config_s imguCssAwbDefaults = { /* Default color correction matrix defined as an identity matrix */ static const struct ipu3_uapi_ccm_mat_config imguCssCcmDefault = { 8191, 0, 0, 0, - 0, 8191, 0, 0, + 0, 6000, 0, 0, 0, 0, 8191, 0 }; @@ -166,6 +163,7 @@ IPU3Awb::IPU3Awb() asyncResults_.greenGain = 1.0; asyncResults_.redGain = 1.0; asyncResults_.temperatureK = 4500; + minZonesCounted_ = 0; } IPU3Awb::~IPU3Awb() @@ -241,7 +239,7 @@ void IPU3Awb::generateZones(std::vector &zones) for (unsigned int i = 0; i < kAwbStatsSizeX * kAwbStatsSizeY; i++) { RGB zone; double counted = awbStats_[i].counted; - if (counted >= kMinZonesCounted) { + if (counted >= minZonesCounted_) { zone.G = awbStats_[i].gSum / counted; if (zone.G >= kMinGreenLevelInZone) { zone.R = awbStats_[i].rSum / counted; @@ -258,6 +256,7 @@ void IPU3Awb::generateAwbStats(const ipu3_uapi_stats_3a *stats) uint32_t regionWidth = round(awbGrid_.width / static_cast(kAwbStatsSizeX)); uint32_t regionHeight = round(awbGrid_.height / static_cast(kAwbStatsSizeY)); + minZonesCounted_ = ((regionWidth * regionHeight) * 4) / 5; /* * Generate a (kAwbStatsSizeX x kAwbStatsSizeY) array from the IPU3 grid which is * (awbGrid_.width x awbGrid_.height). @@ -269,7 +268,7 @@ void IPU3Awb::generateAwbStats(const ipu3_uapi_stats_3a *stats) uint32_t cellY = ((cellPosition / awbGrid_.width) / regionHeight) % kAwbStatsSizeY; uint32_t awbRegionPosition = cellY * kAwbStatsSizeX + cellX; - cellPosition *= 8; + cellPosition *= sizeof(Ipu3AwbCell); /* Cast the initial IPU3 structure to simplify the reading */ Ipu3AwbCell *currentCell = reinterpret_cast(const_cast(&stats->awb_raw_buffer.meta_data[cellPosition])); @@ -361,12 +360,12 @@ void IPU3Awb::updateWbParameters(ipu3_uapi_params ¶ms, double agcGamma) /* * Green gains should not be touched and considered 1. * Default is 16, so do not change it at all. - * 4096 is the value for a gain of 1.0 + * 8192 is the value for a gain of 1.0 */ - params.acc_param.bnr.wb_gains.gr = 16; - params.acc_param.bnr.wb_gains.r = 4096 * asyncResults_.redGain; - params.acc_param.bnr.wb_gains.b = 4096 * asyncResults_.blueGain; - params.acc_param.bnr.wb_gains.gb = 16; + params.acc_param.bnr.wb_gains.gr = 8192; + params.acc_param.bnr.wb_gains.r = 8192 * asyncResults_.redGain; + params.acc_param.bnr.wb_gains.b = 8192 * asyncResults_.blueGain; + params.acc_param.bnr.wb_gains.gb = 8192; LOG(IPU3Awb, Debug) << "Color temperature estimated: " << asyncResults_.temperatureK << " and gamma calculated: " << agcGamma; diff --git a/src/ipa/ipu3/ipu3_awb.h b/src/ipa/ipu3/ipu3_awb.h index 795e32e3..23865c21 100644 --- a/src/ipa/ipu3/ipu3_awb.h +++ b/src/ipa/ipu3/ipu3_awb.h @@ -49,6 +49,7 @@ private: std::vector zones_; IspStatsRegion awbStats_[kAwbStatsSizeX * kAwbStatsSizeY]; AwbStatus asyncResults_; + uint32_t minZonesCounted_; }; } /* namespace ipa::ipu3 */ From patchwork Mon Jun 28 20:22:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Michel Hautbois X-Patchwork-Id: 12741 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 D1C54C321F for ; Mon, 28 Jun 2021 20:23:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5C64E684DA; Mon, 28 Jun 2021 22:23:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="QowV7j1O"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EA189684DB for ; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) Received: from tatooine.ideasonboard.com (unknown [IPv6:2a01:e0a:169:7140:c3ad:78d0:405e:fc33]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8E51D26FE; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1624911780; bh=0H5RRW/aa76Aso5YRFDVtrh9+lxoQDWTFOIFvrwtN2E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QowV7j1OHlNii6w/9SNk1P1shqNl36idreabYlTM/PIbs4NAc/Yey3Kvufx85tP3P SXyoYouFhREUqPrMRSTyQrevpSlPubgb98Ie6jT5CUSbPxP8tfnvd1XylgELjkvM3l ehUW6/mDpsaP3gL5VhNqsSLG07W8fdQgnonLGzKI= From: Jean-Michel Hautbois To: libcamera-devel@lists.libcamera.org Date: Mon, 28 Jun 2021 22:22:54 +0200 Message-Id: <20210628202255.138874-7-jeanmichel.hautbois@ideasonboard.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> References: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 6/7] ipa: ipu3: Call exposure and gain controls from AGC 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" IPAIPU3 does not need to directly know the exposure and gain limits. Move the control min and max values to IPU3Agc as for the moment it is the one which needs to use the values. Signed-off-by: Jean-Michel Hautbois --- src/ipa/ipu3/ipu3.cpp | 14 +++----------- src/ipa/ipu3/ipu3_agc.cpp | 28 +++++++++++++++++++++++----- src/ipa/ipu3/ipu3_agc.h | 11 +++++++++-- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp index 9a2def64..40b626ed 100644 --- a/src/ipa/ipu3/ipu3.cpp +++ b/src/ipa/ipu3/ipu3.cpp @@ -67,11 +67,7 @@ private: /* Camera sensor controls. */ uint32_t defVBlank_; uint32_t exposure_; - uint32_t minExposure_; - uint32_t maxExposure_; uint32_t gain_; - uint32_t minGain_; - uint32_t maxGain_; /* Interface to the AWB algorithm */ std::unique_ptr awbAlgo_; @@ -187,13 +183,9 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo) return -EINVAL; } - minExposure_ = std::max(itExp->second.min().get(), 1); - maxExposure_ = itExp->second.max().get(); - exposure_ = minExposure_; + exposure_ = itExp->second.def().get(); - minGain_ = std::max(itGain->second.min().get(), 1); - maxGain_ = itGain->second.max().get(); - gain_ = minGain_; + gain_ = itGain->second.def().get(); defVBlank_ = itVBlank->second.def().get(); @@ -205,7 +197,7 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo) awbAlgo_->initialise(params_, configInfo.bdsOutputSize, bdsGrid_); agcAlgo_ = std::make_unique(); - agcAlgo_->initialise(bdsGrid_, sensorInfo_); + agcAlgo_->initialise(bdsGrid_, configInfo); return 0; } diff --git a/src/ipa/ipu3/ipu3_agc.cpp b/src/ipa/ipu3/ipu3_agc.cpp index 6253ab94..042d67fa 100644 --- a/src/ipa/ipu3/ipu3_agc.cpp +++ b/src/ipa/ipu3/ipu3_agc.cpp @@ -10,10 +10,12 @@ #include #include #include +#include -#include +#include -#include +#include +#include #include "libipa/histogram.h" @@ -59,12 +61,28 @@ IPU3Agc::IPU3Agc() { } -void IPU3Agc::initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPACameraSensorInfo &sensorInfo) +void IPU3Agc::initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPAConfigInfo &configInfo) { aeGrid_ = bdsGrid; + ctrls_ = configInfo.entityControls.at(0); - lineDuration_ = sensorInfo.lineLength * 1.0s / sensorInfo.pixelRate; - maxExposureTime_ = kMaxExposure * lineDuration_; + const auto itExp = ctrls_.find(V4L2_CID_EXPOSURE); + if (itExp == ctrls_.end()) { + LOG(IPU3Agc, Debug) << "Can't find exposure control"; + return; + } + minExposure_ = itExp->second.min().get(); + maxExposure_ = itExp->second.max().get(); + lineDuration_ = configInfo.sensorInfo.lineLength * 1.0s / configInfo.sensorInfo.pixelRate; + maxExposureTime_ = maxExposure_ * lineDuration_; + + const auto itGain = ctrls_.find(V4L2_CID_ANALOGUE_GAIN); + if (itGain == ctrls_.end()) { + LOG(IPU3Agc, Debug) << "Can't find gain control"; + return; + } + minGain_ = std::max(itGain->second.min().get(), 1); + maxGain_ = itGain->second.max().get(); } void IPU3Agc::processBrightness(const ipu3_uapi_stats_3a *stats) diff --git a/src/ipa/ipu3/ipu3_agc.h b/src/ipa/ipu3/ipu3_agc.h index 774c8385..ce43c534 100644 --- a/src/ipa/ipu3/ipu3_agc.h +++ b/src/ipa/ipu3/ipu3_agc.h @@ -15,7 +15,7 @@ #include #include - +#include #include #include "libipa/algorithm.h" @@ -35,8 +35,8 @@ public: IPU3Agc(); ~IPU3Agc() = default; - void initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPACameraSensorInfo &sensorInfo); void process(const ipu3_uapi_stats_3a *stats, uint32_t &exposure, double &gain); + void initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPAConfigInfo &configInfo); bool converged() { return converged_; } bool updateControls() { return updateControls_; } /* \todo Use a metadata exchange between IPAs */ @@ -48,6 +48,13 @@ private: void lockExposureGain(uint32_t &exposure, double &gain); struct ipu3_uapi_grid_config aeGrid_; + ControlInfoMap ctrls_; + + uint32_t minExposure_; + uint32_t maxExposure_; + + uint32_t minGain_; + uint32_t maxGain_; uint64_t frameCount_; uint64_t lastFrame_; From patchwork Mon Jun 28 20:22:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Michel Hautbois X-Patchwork-Id: 12742 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 8BFD4C321F for ; Mon, 28 Jun 2021 20:23:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 398C4684E8; Mon, 28 Jun 2021 22:23:09 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cpGDCb8V"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1B428684DC for ; Mon, 28 Jun 2021 22:23:01 +0200 (CEST) Received: from tatooine.ideasonboard.com (unknown [IPv6:2a01:e0a:169:7140:c3ad:78d0:405e:fc33]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BE5F5E1A; Mon, 28 Jun 2021 22:23:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1624911780; bh=Lsk0agF3Lgm+Jm+zpWoPiJqfgdBJjIlJsKNRe5UV9fw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cpGDCb8VRNaRDVNq8A+BQOGFgI6/3Wt3ZINre4IjPPYxUiyfOR3HCwD/lt5QSNK7O rbFgB6DccbIKRWz+CdpP6vMkMnO64WnZ1d/ui1qxnWQKnbo/NEnpLOF3mDiUPqlJbL GY0eXcdFHdiIgcEhS0fFCwLbSp3LUE6PLVYHFO84= From: Jean-Michel Hautbois To: libcamera-devel@lists.libcamera.org Date: Mon, 28 Jun 2021 22:22:55 +0200 Message-Id: <20210628202255.138874-8-jeanmichel.hautbois@ideasonboard.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> References: <20210628202255.138874-1-jeanmichel.hautbois@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 7/7] ipa: ipu3: Implement a new AGC algorithm 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" This one comes from RPi for most if it, except that we are not exchanging any metadata between algorithms for now. When process() is called, the current analogue gain and shutter time are calculated. The AWB stats from IPU3 are then parsed to generate new statistics dedicated to AGC. This new grid is used to estimate the luminance and each region is weighted. A default centered metering is used as is should be the most used one. After calculating weighted regions, analogue gain and shutter time are divided up and the values are then sent back to the IPAIPU3. Signed-off-by: Jean-Michel Hautbois --- src/ipa/ipu3/ipu3_agc.cpp | 276 ++++++++++++++++++++++++-------------- src/ipa/ipu3/ipu3_agc.h | 23 +++- 2 files changed, 196 insertions(+), 103 deletions(-) diff --git a/src/ipa/ipu3/ipu3_agc.cpp b/src/ipa/ipu3/ipu3_agc.cpp index 042d67fa..0d421404 100644 --- a/src/ipa/ipu3/ipu3_agc.cpp +++ b/src/ipa/ipu3/ipu3_agc.cpp @@ -27,37 +27,19 @@ namespace ipa::ipu3 { LOG_DEFINE_CATEGORY(IPU3Agc) -/* Number of frames to wait before calculating stats on minimum exposure */ -static constexpr uint32_t kInitialFrameMinAECount = 4; -/* Number of frames to wait between new gain/exposure estimations */ -static constexpr uint32_t kFrameSkipCount = 6; - -/* Maximum ISO value for analogue gain */ -static constexpr uint32_t kMinISO = 100; -static constexpr uint32_t kMaxISO = 1500; - -/* Maximum analogue gain value - * \todo grab it from a camera helper */ -static constexpr uint32_t kMinGain = kMinISO / 100; -static constexpr uint32_t kMaxGain = kMaxISO / 100; - -/* \todo use calculated value based on sensor */ -static constexpr uint32_t kMinExposure = 1; -static constexpr uint32_t kMaxExposure = 1976; - /* Histogram constants */ static constexpr uint32_t knumHistogramBins = 256; -static constexpr double kEvGainTarget = 0.5; -/* A cell is 8 bytes and contains averages for RGB values and saturation ratio */ -static constexpr uint8_t kCellSize = 8; +/* seems to be a 8-bit pipeline */ +static constexpr uint8_t kPipelineBits = 8; IPU3Agc::IPU3Agc() : frameCount_(0), lastFrame_(0), converged_(false), updateControls_(false), iqMean_(0.0), gamma_(1.0), lineDuration_(0s), maxExposureTime_(0s), prevExposure_(0s), prevExposureNoDg_(0s), - currentExposure_(0s), currentExposureNoDg_(0s) + currentExposure_(0s), currentExposureNoDg_(0s), + currentShutter_(1.0s), currentAnalogueGain_(1.0) { } @@ -83,55 +65,79 @@ void IPU3Agc::initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPAConfigI } minGain_ = std::max(itGain->second.min().get(), 1); maxGain_ = itGain->second.max().get(); + + /* \todo: those values need to be extracted from a configuration file */ + shutterConstraints_.push_back(100us); + shutterConstraints_.push_back(10ms); + shutterConstraints_.push_back(33ms); + gainConstraints_.push_back(1.0); + gainConstraints_.push_back(4.0); + gainConstraints_.push_back(16.0); + + fixedShutter_ = 0s; + fixedAnalogueGain_ = 0.0; } -void IPU3Agc::processBrightness(const ipu3_uapi_stats_3a *stats) +/* Translate the IPU3 statistics into the default statistics region array */ +void IPU3Agc::generateStats(const ipu3_uapi_stats_3a *stats) { - const struct ipu3_uapi_grid_config statsAeGrid = stats->stats_4a_config.awb_config.grid; - Rectangle aeRegion = { statsAeGrid.x_start, - statsAeGrid.y_start, - static_cast(statsAeGrid.x_end - statsAeGrid.x_start) + 1, - static_cast(statsAeGrid.y_end - statsAeGrid.y_start) + 1 }; - Point topleft = aeRegion.topLeft(); - int topleftX = topleft.x >> aeGrid_.block_width_log2; - int topleftY = topleft.y >> aeGrid_.block_height_log2; - - /* Align to the grid cell width and height */ - uint32_t startX = topleftX << aeGrid_.block_width_log2; - uint32_t startY = topleftY * aeGrid_.width << aeGrid_.block_width_log2; - uint32_t endX = (startX + (aeRegion.size().width >> aeGrid_.block_width_log2)) << aeGrid_.block_width_log2; - uint32_t i, j; - uint32_t count = 0; - + uint32_t regionWidth = round(aeGrid_.width / static_cast(kAgcStatsSizeX)); + uint32_t regionHeight = round(aeGrid_.height / static_cast(kAgcStatsSizeY)); uint32_t hist[knumHistogramBins] = { 0 }; - for (j = topleftY; - j < topleftY + (aeRegion.size().height >> aeGrid_.block_height_log2); - j++) { - for (i = startX + startY; i < endX + startY; i += kCellSize) { - /* - * The grid width (and maybe height) is not reliable. - * We observed a bit shift which makes the value 160 to be 32 in the stats grid. - * Use the one passed at init time. - */ - if (stats->awb_raw_buffer.meta_data[i + 4 + j * aeGrid_.width] == 0) { - uint8_t Gr = stats->awb_raw_buffer.meta_data[i + 0 + j * aeGrid_.width]; - uint8_t Gb = stats->awb_raw_buffer.meta_data[i + 3 + j * aeGrid_.width]; - hist[(Gr + Gb) / 2]++; - count++; + + LOG(IPU3Agc, Debug) << "[" << (int)aeGrid_.width << "x" << (int)aeGrid_.height << "] regions" + << " scaled to [" << regionWidth << "x" << regionHeight << "] AGC stats"; + + /* + * Generate a (kAgcStatsSizeX x kAgcStatsSizeY) array from the IPU3 grid which is + * (aeGrid_.width x aeGrid_.height). + */ + for (unsigned int j = 0; j < kAgcStatsSizeY * regionHeight; j++) { + for (unsigned int i = 0; i < kAgcStatsSizeX * regionWidth; i++) { + uint32_t cellPosition = j * aeGrid_.width + i; + uint32_t cellX = (cellPosition / regionWidth) % kAgcStatsSizeX; + uint32_t cellY = ((cellPosition / aeGrid_.width) / regionHeight) % kAgcStatsSizeY; + + uint32_t agcRegionPosition = kAgcStatsRegions[cellY * kAgcStatsSizeX + cellX]; + weights_[agcRegionPosition] = kCenteredWeights[agcRegionPosition]; + cellPosition *= sizeof(Ipu3AwbCell); + + /* Cast the initial IPU3 structure to simplify the reading */ + Ipu3AwbCell *currentCell = reinterpret_cast(const_cast(&stats->awb_raw_buffer.meta_data[cellPosition])); + if (currentCell->satRatio == 0) { + /* The cell is not saturated, use the current cell */ + agcStats_[agcRegionPosition].counted++; + uint32_t greenValue = currentCell->greenRedAvg + currentCell->greenBlueAvg; + hist[greenValue / 2]++; + agcStats_[agcRegionPosition].gSum += greenValue / 2; + agcStats_[agcRegionPosition].rSum += currentCell->redAvg; + agcStats_[agcRegionPosition].bSum += currentCell->blueAvg; } } } - /* Limit the gamma effect for now */ - gamma_ = 1.1; - /* Estimate the quantile mean of the top 2% of the histogram */ iqMean_ = Histogram(Span(hist)).interQuantileMean(0.98, 1.0); } +void IPU3Agc::clearStats() +{ + for (unsigned int i = 0; i < kNumAgcWeightedZones; i++) { + agcStats_[i].bSum = 0; + agcStats_[i].rSum = 0; + agcStats_[i].gSum = 0; + agcStats_[i].counted = 0; + agcStats_[i].uncounted = 0; + } + + awb_.blueGain = 1.0; + awb_.greenGain = 1.0; + awb_.redGain = 1.0; +} + void IPU3Agc::filterExposure() { - double speed = 0.2; + double speed = 0.08; if (prevExposure_ == 0s) { /* DG stands for digital gain.*/ prevExposure_ = currentExposure_; @@ -156,65 +162,131 @@ void IPU3Agc::filterExposure() * total exposure, as there might not be enough digital gain available * in the ISP to hide it (which will cause nasty oscillation). */ - double fastReduceThreshold = 0.4; + double fastReduceThreshold = 0.3; if (prevExposureNoDg_ < prevExposure_ * fastReduceThreshold) prevExposureNoDg_ = prevExposure_ * fastReduceThreshold; LOG(IPU3Agc, Debug) << "After filtering, total_exposure " << prevExposure_; } -void IPU3Agc::lockExposureGain(uint32_t &exposure, double &gain) +double IPU3Agc::computeInitialY(IspStatsRegion regions[], AwbStatus const &awb, + double weights[], double gain) { - updateControls_ = false; + /* Note how the calculation below means that equal weights give you + * "average" metering (i.e. all pixels equally important). */ + double redSum = 0, greenSum = 0, blueSum = 0, pixelSum = 0; + for (unsigned int i = 0; i < kNumAgcWeightedZones; i++) { + double counted = regions[i].counted; + double rSum = std::min(regions[i].rSum * gain, ((1 << kPipelineBits) - 1) * counted); + double gSum = std::min(regions[i].gSum * gain, ((1 << kPipelineBits) - 1) * counted); + double bSum = std::min(regions[i].bSum * gain, ((1 << kPipelineBits) - 1) * counted); + redSum += rSum * weights[i]; + greenSum += gSum * weights[i]; + blueSum += bSum * weights[i]; + pixelSum += counted * weights[i]; + } + if (pixelSum == 0.0) { + LOG(IPU3Agc, Warning) << "computeInitialY: pixel_sum is zero"; + return 0; + } + double Y_sum = redSum * awb.redGain * .299 + + greenSum * awb.greenGain * .587 + + blueSum * awb.blueGain * .114; - /* Algorithm initialization should wait for first valid frames */ - /* \todo - have a number of frames given by DelayedControls ? - * - implement a function for IIR */ - if ((frameCount_ < kInitialFrameMinAECount) || (frameCount_ - lastFrame_ < kFrameSkipCount)) - return; + return Y_sum / pixelSum / (1 << kPipelineBits); +} - /* Are we correctly exposed ? */ - if (std::abs(iqMean_ - kEvGainTarget * knumHistogramBins) <= 1) { - LOG(IPU3Agc, Debug) << "!!! Good exposure with iqMean = " << iqMean_; - converged_ = true; - } else { - double newGain = kEvGainTarget * knumHistogramBins / iqMean_; - - /* extracted from Rpi::Agc::computeTargetExposure */ - libcamera::utils::Duration currentShutter = exposure * lineDuration_; - currentExposureNoDg_ = currentShutter * gain; - LOG(IPU3Agc, Debug) << "Actual total exposure " << currentExposureNoDg_ - << " Shutter speed " << currentShutter - << " Gain " << gain; - currentExposure_ = currentExposureNoDg_ * newGain; - libcamera::utils::Duration maxTotalExposure = maxExposureTime_ * kMaxGain; - currentExposure_ = std::min(currentExposure_, maxTotalExposure); - LOG(IPU3Agc, Debug) << "Target total exposure " << currentExposure_; - - /* \todo: estimate if we need to desaturate */ - filterExposure(); - - libcamera::utils::Duration newExposure = 0.0s; - if (currentShutter < maxExposureTime_) { - exposure = std::clamp(static_cast(exposure * currentExposure_ / currentExposureNoDg_), kMinExposure, kMaxExposure); - newExposure = currentExposure_ / exposure; - gain = std::clamp(static_cast(gain * currentExposure_ / newExposure), kMinGain, kMaxGain); - updateControls_ = true; - } else if (currentShutter >= maxExposureTime_) { - gain = std::clamp(static_cast(gain * currentExposure_ / currentExposureNoDg_), kMinGain, kMaxGain); - newExposure = currentExposure_ / gain; - exposure = std::clamp(static_cast(exposure * currentExposure_ / newExposure), kMinExposure, kMaxExposure); - updateControls_ = true; +void IPU3Agc::computeTargetExposure(double gain) +{ + currentExposure_ = currentExposureNoDg_ * gain; + /* \todo: have a list of shutter speeds */ + Duration maxShutterSpeed = shutterConstraints_.back(); + Duration maxTotalExposure = maxShutterSpeed * gainConstraints_.back(); + + currentExposure_ = std::min(currentExposure_, maxTotalExposure); + LOG(IPU3Agc, Debug) << "Target total_exposure " << currentExposure_; +} + +void IPU3Agc::divideUpExposure() +{ + Duration exposureValue = prevExposure_; + Duration shutterTime; + double analogueGain; + shutterTime = shutterConstraints_[0]; + shutterTime = std::min(shutterTime, shutterConstraints_.back()); + analogueGain = gainConstraints_[0]; + + if (shutterTime * analogueGain < exposureValue) { + for (unsigned int stage = 1; + stage < gainConstraints_.size(); stage++) { + if (fixedShutter_ == 0s) { + Duration stageShutter = + std::min(shutterConstraints_[stage], shutterConstraints_.back()); + if (stageShutter * analogueGain >= + exposureValue) { + shutterTime = + exposureValue / analogueGain; + break; + } + shutterTime = stageShutter; + } + if (fixedAnalogueGain_ == 0.0) { + if (gainConstraints_[stage] * shutterTime >= exposureValue) { + analogueGain = exposureValue / shutterTime; + break; + } + analogueGain = gainConstraints_[stage]; + } } - LOG(IPU3Agc, Debug) << "Adjust exposure " << exposure * lineDuration_ << " and gain " << gain; } - lastFrame_ = frameCount_; + LOG(IPU3Agc, Debug) << "Divided up shutter and gain are " << shutterTime << " and " + << analogueGain; + + /* \todo: flickering avoidance ? */ + filteredShutter_ = shutterTime; + filteredAnalogueGain_ = analogueGain; +} + +void IPU3Agc::computeGain(double ¤tGain) +{ + currentGain = 1.0; + /* \todo: the target Y needs to be grabbed from a configuration */ + double targetY = 0.162; + for (int i = 0; i < 8; i++) { + double initialY = computeInitialY(agcStats_, awb_, weights_, currentGain); + double extra_gain = std::min(10.0, targetY / (initialY + .001)); + + currentGain *= extra_gain; + LOG(IPU3Agc, Debug) << "Initial Y " << initialY << " target " << targetY + << " gives gain " << currentGain; + if (extra_gain < 1.01) + break; + } + + double newGain = 128 / iqMean_; + LOG(IPU3Agc, Debug) << "gain: " << currentGain << " new gain: " << newGain; } -void IPU3Agc::process(const ipu3_uapi_stats_3a *stats, uint32_t &exposure, double &gain) +void IPU3Agc::process(const ipu3_uapi_stats_3a *stats, uint32_t &exposure, double &analogueGain) { - processBrightness(stats); - lockExposureGain(exposure, gain); + ASSERT(stats->stats_3a_status.awb_en); + clearStats(); + generateStats(stats); + currentShutter_ = exposure * lineDuration_; + /* \todo: the gain needs to be calculated based on sensor informations */ + currentAnalogueGain_ = analogueGain; + currentExposureNoDg_ = currentShutter_ * currentAnalogueGain_; + + double currentGain = 1; + computeGain(currentGain); + computeTargetExposure(currentGain); + filterExposure(); + divideUpExposure(); + + exposure = filteredShutter_ / lineDuration_; + analogueGain = filteredAnalogueGain_; + + updateControls_ = true; frameCount_++; } diff --git a/src/ipa/ipu3/ipu3_agc.h b/src/ipa/ipu3/ipu3_agc.h index ce43c534..f1b1157b 100644 --- a/src/ipa/ipu3/ipu3_agc.h +++ b/src/ipa/ipu3/ipu3_agc.h @@ -35,8 +35,8 @@ public: IPU3Agc(); ~IPU3Agc() = default; - void process(const ipu3_uapi_stats_3a *stats, uint32_t &exposure, double &gain); void initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPAConfigInfo &configInfo); + void process(const ipu3_uapi_stats_3a *stats, uint32_t &exposure, double &analogueGain); bool converged() { return converged_; } bool updateControls() { return updateControls_; } /* \todo Use a metadata exchange between IPAs */ @@ -46,6 +46,17 @@ private: void processBrightness(const ipu3_uapi_stats_3a *stats); void filterExposure(); void lockExposureGain(uint32_t &exposure, double &gain); + void generateStats(const ipu3_uapi_stats_3a *stats); + void clearStats(); + void generateZones(std::vector &zones); + double computeInitialY(IspStatsRegion regions[], AwbStatus const &awb, double weights[], double gain); + void computeTargetExposure(double currentGain); + void divideUpExposure(); + void computeGain(double ¤tGain); + + AwbStatus awb_; + double weights_[kNumAgcWeightedZones]; + IspStatsRegion agcStats_[kNumAgcWeightedZones]; struct ipu3_uapi_grid_config aeGrid_; ControlInfoMap ctrls_; @@ -72,6 +83,16 @@ private: Duration prevExposureNoDg_; Duration currentExposure_; Duration currentExposureNoDg_; + + Duration currentShutter_; + std::vector shutterConstraints_; + Duration fixedShutter_; + Duration filteredShutter_; + + double currentAnalogueGain_; + std::vector gainConstraints_; + double fixedAnalogueGain_; + double filteredAnalogueGain_; }; } /* namespace ipa::ipu3 */