From patchwork Thu Aug 11 15:02:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 17080 X-Patchwork-Delegate: jacopo@jmondi.org 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 D97C5BE173 for ; Thu, 11 Aug 2022 15:02:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9B3C363338; Thu, 11 Aug 2022 17:02:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1660230160; bh=YBSL0m/ZatXDKFzO1smEbnnzup40c/qz/H/qUpQcA3s=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=jM2MgrCzDnOiciKCOggrMHFSRTMIvOQeSsOW6UFW6SzdP5Kwawe5z+fn/FIPqGJzT jHWdJubcWgvuE+w6tEzQNWcqR1gWIvSjIwLQUitK3UFTYc9Cr0B5CL1yZSthHSfPhN +2Svzw6bqg2aL4vU0kH87fSioOusXdpprt33pesgYQRx393QIWC1rHIqeeHrEmkDrk YMQyzTjSeTjVX+dyTs2Ia0KTmAVEwbspmB6z8z4h0DnG53ZKEAYnWZ4goWQ9vzS7yY DIYCU2p4Ohu2928zLF2svYf543E2VgbRaokHryUiAAA41DeNFb5HYccRsfKddX8ViF JMPSBjnKFoTmQ== Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AFA1E63330 for ; Thu, 11 Aug 2022 17:02:38 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by mail.gandi.net (Postfix) with ESMTPSA id A7ED01BF20A; Thu, 11 Aug 2022 15:02:37 +0000 (UTC) To: libcamera-devel@lists.libcamera.org Date: Thu, 11 Aug 2022 17:02:17 +0200 Message-Id: <20220811150219.62066-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220811150219.62066-1-jacopo@jmondi.org> References: <20220811150219.62066-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 4/6] ipa: raspberry: Port to the new AEGC controls 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: , X-Patchwork-Original-From: Jacopo Mondi via libcamera-devel From: Jacopo Mondi Reply-To: Jacopo Mondi Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The newly introduced controls to driver the AEGC algorithm allow to control the computation of the exposure time and analogue gain separately. The RPi AEGC implementation already computes the shutter and gain values separately but does not expose separate functions to control them. Augment the AgcAlgorithm interface to allow to pause/resume the shutter and gain automatic computations separately and plumb them to the newly introduced controls. Add safety checks to ignore ExposureTime and AnalogueGain values if the algorithms are not paused, and report the correct AeState value by checking if both algorithms have been paused or if they have converged. Signed-off-by: Jacopo Mondi Reviewed-by: Paul Elder --- .../raspberrypi/controller/agc_algorithm.h | 6 ++ src/ipa/raspberrypi/controller/rpi/agc.cpp | 24 +++++- src/ipa/raspberrypi/controller/rpi/agc.h | 8 +- src/ipa/raspberrypi/raspberrypi.cpp | 76 ++++++++++++++++--- 4 files changed, 99 insertions(+), 15 deletions(-) diff --git a/src/ipa/raspberrypi/controller/agc_algorithm.h b/src/ipa/raspberrypi/controller/agc_algorithm.h index 3a91444c3a61..bf9c501db553 100644 --- a/src/ipa/raspberrypi/controller/agc_algorithm.h +++ b/src/ipa/raspberrypi/controller/agc_algorithm.h @@ -17,6 +17,12 @@ class AgcAlgorithm : public Algorithm public: AgcAlgorithm(Controller *controller) : Algorithm(controller) {} /* An AGC algorithm must provide the following: */ + virtual void pauseShutter(); + virtual void resumeShutter(); + virtual bool isShutterPaused() const; + virtual void pauseGain(); + virtual void resumeGain(); + virtual bool isGainPaused() const; virtual unsigned int getConvergenceFrames() const = 0; virtual void setEv(double ev) = 0; virtual void setFlickerPeriod(libcamera::utils::Duration flickerPeriod) = 0; diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp index bd54a639d637..3d04724349f7 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp @@ -275,18 +275,36 @@ bool Agc::isPaused() const return false; } -void Agc::pause() +void Agc::pauseShutter() { fixedShutter_ = status_.shutterTime; - fixedAnalogueGain_ = status_.analogueGain; } -void Agc::resume() +void Agc::resumeShutter() { fixedShutter_ = 0s; +} + +bool Agc::isShutterPaused() const +{ + return fixedShutter_ != 0s; +} + +void Agc::pauseGain() +{ + fixedAnalogueGain_ = status_.analogueGain; +} + +void Agc::resumeGain() +{ fixedAnalogueGain_ = 0; } +bool Agc::isGainPaused() const +{ + return fixedAnalogueGain_ != 0; +} + unsigned int Agc::getConvergenceFrames() const { /* diff --git a/src/ipa/raspberrypi/controller/rpi/agc.h b/src/ipa/raspberrypi/controller/rpi/agc.h index 6d6b0e5ad857..cfb57f41848b 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.h +++ b/src/ipa/raspberrypi/controller/rpi/agc.h @@ -77,8 +77,12 @@ public: int read(const libcamera::YamlObject ¶ms) override; /* AGC handles "pausing" for itself. */ bool isPaused() const override; - void pause() override; - void resume() override; + void pauseShutter() override; + void resumeShutter() override; + bool isShutterPaused() const override; + void pauseGain() override; + void resumeGain() override; + bool isGainPaused() const override; unsigned int getConvergenceFrames() const override; void setEv(double ev) override; void setFlickerPeriod(libcamera::utils::Duration flickerPeriod) override; diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 69c73f8c780a..c041aac008eb 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -74,8 +74,13 @@ constexpr Duration controllerMinFrameDuration = 1.0s / 30.0; /* List of controls handled by the Raspberry Pi IPA */ static const ControlInfoMap::Map ipaControls{ - { &controls::AeEnable, ControlInfo(false, true) }, + { &controls::ExposureTimeMode, + ControlInfo(static_cast(controls::ExposureTimeModeAuto), + static_cast(controls::ExposureTimeModeManual)) }, { &controls::ExposureTime, ControlInfo(0, 66666) }, + { &controls::AnalogueGainMode, + ControlInfo(static_cast(controls::AnalogueGainModeAuto), + static_cast(controls::AnalogueGainModeManual)) }, { &controls::AnalogueGain, ControlInfo(1.0f, 16.0f) }, { &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) }, { &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) }, @@ -556,9 +561,18 @@ void IPARPi::reportMetadata() } AgcStatus *agcStatus = rpiMetadata_.getLocked("agc.status"); - if (agcStatus) { - libcameraMetadata_.set(controls::AeLocked, agcStatus->locked); + if (agcStatus) libcameraMetadata_.set(controls::DigitalGain, agcStatus->digitalGain); + + RPiController::AgcAlgorithm *agc = dynamic_cast( + controller_.getAlgorithm("agc")); + if (agc) { + if (agc->isShutterPaused() && agc->isGainPaused()) + libcameraMetadata_.set(controls::AeState, controls::AeStateIdle); + else if (agcStatus) + libcameraMetadata_.set(controls::AeState, + agcStatus->locked ? controls::AeStateConverged + : controls::AeStateSearching); } LuxStatus *luxStatus = rpiMetadata_.getLocked("lux.status"); @@ -703,20 +717,22 @@ void IPARPi::queueRequest(const ControlList &controls) << " = " << ctrl.second.toString(); switch (ctrl.first) { - case controls::AE_ENABLE: { - RPiController::Algorithm *agc = controller_.getAlgorithm("agc"); + case controls::EXPOSURE_TIME_MODE: { + RPiController::AgcAlgorithm *agc = dynamic_cast( + controller_.getAlgorithm("agc")); if (!agc) { LOG(IPARPI, Warning) - << "Could not set AE_ENABLE - no AGC algorithm"; + << "Could not set EXPOSURE_TIME_MODE - no AGC algorithm"; break; } - if (ctrl.second.get() == false) - agc->pause(); + if (ctrl.second.get() == controls::ExposureTimeModeManual) + agc->pauseShutter(); else - agc->resume(); + agc->resumeShutter(); - libcameraMetadata_.set(controls::AeEnable, ctrl.second.get()); + libcameraMetadata_.set(controls::ExposureTimeMode, + ctrl.second.get()); break; } @@ -729,6 +745,13 @@ void IPARPi::queueRequest(const ControlList &controls) break; } + /* + * Ignore manual exposure time when the auto exposure + * algorithm is running. + */ + if (!agc->isShutterPaused()) + break; + /* The control provides units of microseconds. */ agc->setFixedShutter(ctrl.second.get() * 1.0us); @@ -736,6 +759,25 @@ void IPARPi::queueRequest(const ControlList &controls) break; } + case controls::ANALOGUE_GAIN_MODE: { + RPiController::AgcAlgorithm *agc = dynamic_cast( + controller_.getAlgorithm("agc")); + if (!agc) { + LOG(IPARPI, Warning) + << "Could not set ANALOGUE_GAIN_MODE - no AGC algorithm"; + break; + } + + if (ctrl.second.get() == controls::AnalogueGainModeManual) + agc->pauseGain(); + else + agc->resumeGain(); + + libcameraMetadata_.set(controls::AnalogueGainMode, + ctrl.second.get()); + break; + } + case controls::ANALOGUE_GAIN: { RPiController::AgcAlgorithm *agc = dynamic_cast( controller_.getAlgorithm("agc")); @@ -745,6 +787,13 @@ void IPARPi::queueRequest(const ControlList &controls) break; } + /* + * Ignore manual analogue gain value when the auto gain + * algorithm is running. + */ + if (!agc->isGainPaused()) + break; + agc->setFixedAnalogueGain(ctrl.second.get()); libcameraMetadata_.set(controls::AnalogueGain, @@ -801,6 +850,13 @@ void IPARPi::queueRequest(const ControlList &controls) break; } + /* + * Ignore AE_EXPOSURE_MODE if the shutter or the gain + * are in auto mode. + */ + if (!agc->isShutterPaused() || !agc->isGainPaused()) + break; + int32_t idx = ctrl.second.get(); if (ExposureModeTable.count(idx)) { agc->setExposureMode(ExposureModeTable.at(idx));