From patchwork Thu Jan 21 11:58:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 10925 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 4286AC0F2A for ; Thu, 21 Jan 2021 11:59:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0CE84681F4; Thu, 21 Jan 2021 12:59:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="r+cR7WJD"; dkim-atps=neutral Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 344D8681ED for ; Thu, 21 Jan 2021 12:58:57 +0100 (CET) Received: by mail-wr1-x42c.google.com with SMTP id a1so1458022wrq.6 for ; Thu, 21 Jan 2021 03:58:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=vcbJR/GzM1Wv9CIUg93uXumJ7m5L8+WjsRCxsYGlzdA=; b=r+cR7WJDRzFp0Qf3bbNrWxHyXfd/0Pjo/yBQ8BFoP+MsdloFGGo+EwJQKmN8so1GkP HSko52aBqu3hzZtQ/O7zW7Qd6wKxi61dyr/+4hq4exKFOJxyJdIw0EebHDSm3oL0gHpD 0Hjtsl9SyaCk4xpWYwNEUChtn7XNVp3KtJW0XQ6J3uVAKKRfScLOASteEsytQCN/W+3k c4nRzLQ0ov+ieDm2WJ0vY2RWVbHIc7ipueB+oSP4ef3iuumLLHsjVMk+mMgcJL/Q5u+e OkhnGVrN5YO12a+Uv4xOnt57eH71/Xj14FTj047n+yo+zjyMmDGD63fdUqAIb6xMBInV rNRw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vcbJR/GzM1Wv9CIUg93uXumJ7m5L8+WjsRCxsYGlzdA=; b=Ft9+Pl8u74Z+IUPM5FiVBpsZNNaKYSyeA6QbUM02VaRl9fIjxiv/3Xy1yOLMrt2jLv wL61di4opCodtCjxBhTjURx2QPtK9J3A8NtkYToo9bgQ9IsJAQHGRbI1uLvrYu0OHW8w 4uIUWysgl4gS+a//1wRF6H8apEK8Kjp294h/N/x37wNG34+AjOcsIh8lEtucJY1pkRaL Djc0RQpLklVoTGd1i1ZMR3MBoHLOPP51pQxN5lLBhyb2PHcMPKnLK+A0r2xMNUjT5bRJ FtYrC4Re4trisjJH58pFV8Nejc8i6gOzMIWpm0qR32vGh0Cg6qE3I7AHwm8P8Urkbx/d 9QfA== X-Gm-Message-State: AOAM530urbCI0h8aMKM2hwHuQjL2z+coqS7xbeFo/JUXAe4VBgFk2Mdz jX8H2wiTqVEicA3Aqy1epss5YgL+ONULPA== X-Google-Smtp-Source: ABdhPJxidI9RVQgXoqisi5lUfoeT23hZL95LU7tfnbKO/wCIVLuN619mtBCGfJiPvRVR28wfNz99KQ== X-Received: by 2002:a5d:4a11:: with SMTP id m17mr5881838wrq.39.1611230336505; Thu, 21 Jan 2021 03:58:56 -0800 (PST) Received: from naushir-VirtualBox.patuck.local ([88.97.76.4]) by smtp.gmail.com with ESMTPSA id h13sm8044930wrm.28.2021.01.21.03.58.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Jan 2021 03:58:55 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Thu, 21 Jan 2021 11:58:48 +0000 Message-Id: <20210121115849.682130-4-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210121115849.682130-1-naush@raspberrypi.com> References: <20210121115849.682130-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/4] ipa: raspberrypi: Pass the maximum allowable shutter speed into the 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" In order to provide an optimal split between shutter speed and gain, the AGC must know the maximum allowable shutter speed, as limited by the maximum frame duration (either application provided or the default). Add a new API function, SetMaxShutter, to the AgcAlgorihtm class. The IPA provides the the maximum shutter speed for AGC calculations. This applies to both the manual and auto AGC modes. Signed-off-by: Naushir Patuck Reviewed-by: David Plowman --- .../raspberrypi/controller/agc_algorithm.hpp | 1 + src/ipa/raspberrypi/controller/rpi/agc.cpp | 49 +++++++++++++------ src/ipa/raspberrypi/controller/rpi/agc.hpp | 2 + src/ipa/raspberrypi/raspberrypi.cpp | 12 +++++ 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/ipa/raspberrypi/controller/agc_algorithm.hpp b/src/ipa/raspberrypi/controller/agc_algorithm.hpp index 981f1de2f0e4..f97deb0fca59 100644 --- a/src/ipa/raspberrypi/controller/agc_algorithm.hpp +++ b/src/ipa/raspberrypi/controller/agc_algorithm.hpp @@ -19,6 +19,7 @@ public: virtual void SetEv(double ev) = 0; virtual void SetFlickerPeriod(double flicker_period) = 0; virtual void SetFixedShutter(double fixed_shutter) = 0; // microseconds + virtual void SetMaxShutter(double max_shutter) = 0; // microseconds virtual void SetFixedAnalogueGain(double fixed_analogue_gain) = 0; virtual void SetMeteringMode(std::string const &metering_mode_name) = 0; virtual void SetExposureMode(std::string const &exposure_mode_name) = 0; diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp index eddd1684da12..937bb70ece67 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp @@ -157,7 +157,7 @@ Agc::Agc(Controller *controller) frame_count_(0), lock_count_(0), last_target_exposure_(0.0), ev_(1.0), flicker_period_(0.0), - fixed_shutter_(0), fixed_analogue_gain_(0.0) + max_shutter_(0), fixed_shutter_(0), fixed_analogue_gain_(0.0) { memset(&awb_, 0, sizeof(awb_)); // Setting status_.total_exposure_value_ to zero initially tells us @@ -227,11 +227,23 @@ void Agc::SetFlickerPeriod(double flicker_period) flicker_period_ = flicker_period; } +static double clip_shutter(double shutter, double max_shutter) +{ + if (max_shutter) + shutter = std::min(shutter, max_shutter); + return shutter; +} + +void Agc::SetMaxShutter(double max_shutter) +{ + max_shutter_ = max_shutter; +} + void Agc::SetFixedShutter(double fixed_shutter) { fixed_shutter_ = fixed_shutter; // Set this in case someone calls Pause() straight after. - status_.shutter_time = fixed_shutter; + status_.shutter_time = clip_shutter(fixed_shutter_, max_shutter_); } void Agc::SetFixedAnalogueGain(double fixed_analogue_gain) @@ -261,7 +273,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode, { housekeepConfig(); - if (fixed_shutter_ != 0.0 && fixed_analogue_gain_ != 0.0) { + double fixed_shutter = clip_shutter(fixed_shutter_, max_shutter_); + if (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) { // We're going to reset the algorithm here with these fixed values. fetchAwbStatus(metadata); @@ -269,14 +282,14 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode, ASSERT(min_colour_gain != 0.0); // This is the equivalent of computeTargetExposure and applyDigitalGain. - target_.total_exposure_no_dg = fixed_shutter_ * fixed_analogue_gain_; + target_.total_exposure_no_dg = fixed_shutter * fixed_analogue_gain_; target_.total_exposure = target_.total_exposure_no_dg / min_colour_gain; // Equivalent of filterExposure. This resets any "history". filtered_ = target_; // Equivalent of divideUpExposure. - filtered_.shutter = fixed_shutter_; + filtered_.shutter = fixed_shutter; filtered_.analogue_gain = fixed_analogue_gain_; } else if (status_.total_exposure_value) { // On a mode switch, it's possible the exposure profile could change, @@ -290,7 +303,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode, // for any that weren't set. // Equivalent of divideUpExposure. - filtered_.shutter = fixed_shutter_ ? fixed_shutter_ : config_.default_exposure_time; + filtered_.shutter = fixed_shutter ? fixed_shutter : config_.default_exposure_time; filtered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain; } @@ -403,7 +416,8 @@ void Agc::housekeepConfig() { // First fetch all the up-to-date settings, so no one else has to do it. status_.ev = ev_; - status_.fixed_shutter = fixed_shutter_; + double fixed_shutter = clip_shutter(fixed_shutter_, max_shutter_); + status_.fixed_shutter = fixed_shutter; status_.fixed_analogue_gain = fixed_analogue_gain_; status_.flicker_period = flicker_period_; LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixed_shutter " @@ -582,13 +596,15 @@ void Agc::computeTargetExposure(double gain) target_.total_exposure = current_.total_exposure_no_dg * gain; // The final target exposure is also limited to what the exposure // mode allows. + double max_shutter = status_.fixed_shutter != 0.0 + ? status_.fixed_shutter + : exposure_mode_->shutter.back(); + max_shutter = clip_shutter(max_shutter, max_shutter_); double max_total_exposure = - (status_.fixed_shutter != 0.0 - ? status_.fixed_shutter - : exposure_mode_->shutter.back()) * + max_shutter * (status_.fixed_analogue_gain != 0.0 - ? status_.fixed_analogue_gain - : exposure_mode_->gain.back()); + ? status_.fixed_analogue_gain + : exposure_mode_->gain.back()); target_.total_exposure = std::min(target_.total_exposure, max_total_exposure); } @@ -671,6 +687,7 @@ void Agc::divideUpExposure() shutter_time = status_.fixed_shutter != 0.0 ? status_.fixed_shutter : exposure_mode_->shutter[0]; + shutter_time = clip_shutter(shutter_time, max_shutter_); analogue_gain = status_.fixed_analogue_gain != 0.0 ? status_.fixed_analogue_gain : exposure_mode_->gain[0]; @@ -678,14 +695,16 @@ void Agc::divideUpExposure() for (unsigned int stage = 1; stage < exposure_mode_->gain.size(); stage++) { if (status_.fixed_shutter == 0.0) { - if (exposure_mode_->shutter[stage] * - analogue_gain >= + double stage_shutter = + clip_shutter(exposure_mode_->shutter[stage], + max_shutter_); + if (stage_shutter * analogue_gain >= exposure_value) { shutter_time = exposure_value / analogue_gain; break; } - shutter_time = exposure_mode_->shutter[stage]; + shutter_time = stage_shutter; } if (status_.fixed_analogue_gain == 0.0) { if (exposure_mode_->gain[stage] * diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp index 05c334e4a1de..2ce3b1a1700a 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.hpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp @@ -78,6 +78,7 @@ public: unsigned int GetConvergenceFrames() const override; void SetEv(double ev) override; void SetFlickerPeriod(double flicker_period) override; + void SetMaxShutter(double max_shutter) override; // microseconds void SetFixedShutter(double fixed_shutter) override; // microseconds void SetFixedAnalogueGain(double fixed_analogue_gain) override; void SetMeteringMode(std::string const &metering_mode_name) override; @@ -126,6 +127,7 @@ private: std::string constraint_mode_name_; double ev_; double flicker_period_; + double max_shutter_; double fixed_shutter_; double fixed_analogue_gain_; }; diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 9e6e030c4997..2b71efc63f10 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -1008,6 +1008,18 @@ void IPARPi::applyFrameDurations(double min, double max) libcameraMetadata_.set(controls::FrameDurations, { static_cast(minFrameDuration_), static_cast(maxFrameDuration_) }); + + /* + * Calculate the maximum exposure time possible for the AGC to use. + * GetVBlanking() will update maxShutter with the largest exposure + * value possible. + */ + double maxShutter = std::numeric_limits::max(); + helper_->GetVBlanking(maxShutter, minFrameDuration_, maxFrameDuration_); + + RPiController::AgcAlgorithm *agc = dynamic_cast( + controller_.GetAlgorithm("agc")); + agc->SetMaxShutter(maxShutter); } void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)