From patchwork Wed Mar 22 16:13:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 18441 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 1D290C329D for ; Wed, 22 Mar 2023 16:13:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 43A1A62715; Wed, 22 Mar 2023 17:13:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1679501598; bh=T5UmdV72nfTRwNUVi7eQo2sbBcMiLO+uLhjRMQVEiy4=; 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=oZqjzVbthTSITcs7FW4NkMCfpieY5oc/XOqLue0ZSRi6SEI+YF5ydIKlY+/nNPlLB RFSMdn5RTHP+QfLyWafwR+6rYvceOSBPZ5tTfUY4AIvzq83kSf+ouWsI34/nZ+a7Yk ov0w9vCZC0dLuNRtlEfBbVrwQHbcO8rLQc5pGXUKCpMe6WS0fAN2CQhYJLmfnqwreV FpI3od6RktHRITiIjB6vsdZWIrAf26XErK3HN0YKaYyWkbIjf2UJWvwWMJDK1ezyY+ UTa1YjxPEEijoIPOsMHcxMbZNMow6vGDpfhF6zy4MZFPG7mvyWfHx/Q9SDROH+qPNt muxSJtGv0XXMg== Received: from mail-io1-xd2a.google.com (mail-io1-xd2a.google.com [IPv6:2607:f8b0:4864:20::d2a]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B3C45626DA for ; Wed, 22 Mar 2023 17:13:14 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="NIAoES7W"; dkim-atps=neutral Received: by mail-io1-xd2a.google.com with SMTP id s4so8682117ioj.11 for ; Wed, 22 Mar 2023 09:13:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1679501594; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0clupoib3wTLjICcDff6DmuNnVx8wOrUSKdGYrk+q6I=; b=NIAoES7W8XFY2Ivk7m/YXYLKGKBKtwcjg1Dz/HSMkZY6Zz0GJLNF+qq06IcEVqn3B3 RmqwkjZlZepvRGqQDRdOysoS29+d9U0cYkhOtpaAlC8zFWGpezVtGkMwqRmPf0U3encd KNhDhYIS7KB6o10y99X2WmdTHEl26haKNsvFTpABFGYZWzgOHwEZKVz3vY++s+seBM8L 3aS+78nDTvUHRMjZCH8llp6dz5XVqoMPdLrn0SxThzw7oVElP47QIqo8twpkbDUol5Lj R+MA0CQsMedtP+aH8xdqkdAGxLgk9klA+1rSrxhaA1z28P+jBCJNw2vczd8e4zPwUci7 yE8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1679501594; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0clupoib3wTLjICcDff6DmuNnVx8wOrUSKdGYrk+q6I=; b=eA8RjeIAdBsLBiLbZZbDZb3DFujgJXL9uDa2fKxSxmWykqUwtpIlyS3A9pP6vx7gTH aPFrYDMk42fDjfByp5Bxz8Sp5+IZkwxjm4m7e7GtDj/NqkD7yZevDyWvXeb5nAfmdGQm 1lJijGhhtcowNeJ6WR7r/D8/nWDyJ7fkmUm25xz61ySMXFHu9r12To8iSPNTTUUuDLLu ficpq+uzEslZdz65e4KCjg3opbzQP3FfLeKsBOnSiIhbLH18JMA++5mxkg1UHrs7niTr LHVybCruBHMKjJyfk6BaDhhAXr8Ub+wU0lHMNJn/a3kBrltJoGA9VkIDAz/B6bRpLOVJ t21Q== X-Gm-Message-State: AO0yUKXruoSV2VMVSRhpbCIMGjcGqxH4LjoJZjtWEZ+dw5i/nXkjM28G /dU6j/Wx8JWalqTOFLzWMpE8RFHcKh2sbwE0rVkUQQ== X-Google-Smtp-Source: AK7set8pXynw/dxNeSXaupCxLJrXzURHhpjr35ABPZOgD2lDJZbjMmimzNgknwlCYBJ6bUJ3tv6cmw== X-Received: by 2002:a5e:c605:0:b0:74c:8cec:548e with SMTP id f5-20020a5ec605000000b0074c8cec548emr4997612iok.4.1679501594087; Wed, 22 Mar 2023 09:13:14 -0700 (PDT) Received: from localhost.localdomain ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id n24-20020a02a918000000b004050d92f6d4sm5100119jam.50.2023.03.22.09.13.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Mar 2023 09:13:13 -0700 (PDT) To: libcamera-devel@lists.libcamera.org Date: Wed, 22 Mar 2023 16:13:17 +0000 Message-Id: <20230322161317.18055-4-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230322161317.18055-1-naush@raspberrypi.com> References: <20230322161317.18055-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v1 3/3] ipa: raspberrypi: Ensure shutter speed and gain are clipped in 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: , X-Patchwork-Original-From: Naushir Patuck via libcamera-devel From: Naushir Patuck Reply-To: Naushir Patuck Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Limit the AGC gain calculations to the minimum value given by SensorLimits. The maximum value remains unclipped as any gain over the SensorLimits maximum will be made up by digital gain. Rename clipShutter to limitShutter for consistency, and have the latter limit the shutter speed to both upper and lower bounds. Signed-off-by: Naushir Patuck Reviewed-by: David Plowman --- src/ipa/raspberrypi/controller/rpi/agc.cpp | 47 +++++++++++++++++----- src/ipa/raspberrypi/controller/rpi/agc.h | 3 +- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp index eaabc5fa9cd0..ee81537c653c 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp @@ -309,14 +309,14 @@ void Agc::setFixedShutter(Duration fixedShutter) { fixedShutter_ = fixedShutter; /* Set this in case someone calls disableAuto() straight after. */ - status_.shutterTime = clipShutter(fixedShutter_); + status_.shutterTime = limitShutter(fixedShutter_); } void Agc::setFixedAnalogueGain(double fixedAnalogueGain) { fixedAnalogueGain_ = fixedAnalogueGain; /* Set this in case someone calls disableAuto() straight after. */ - status_.analogueGain = fixedAnalogueGain; + status_.analogueGain = limitGain(fixedAnalogueGain); } void Agc::setMeteringMode(std::string const &meteringModeName) @@ -342,7 +342,7 @@ void Agc::switchMode(CameraMode const &cameraMode, housekeepConfig(); - Duration fixedShutter = clipShutter(fixedShutter_); + Duration fixedShutter = limitShutter(fixedShutter_); if (fixedShutter && fixedAnalogueGain_) { /* We're going to reset the algorithm here with these fixed values. */ @@ -516,7 +516,7 @@ void Agc::housekeepConfig() { /* First fetch all the up-to-date settings, so no one else has to do it. */ status_.ev = ev_; - status_.fixedShutter = clipShutter(fixedShutter_); + status_.fixedShutter = limitShutter(fixedShutter_); status_.fixedAnalogueGain = fixedAnalogueGain_; status_.flickerPeriod = flickerPeriod_; LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixedShutter " @@ -703,7 +703,7 @@ void Agc::computeTargetExposure(double gain) Duration maxShutter = status_.fixedShutter ? status_.fixedShutter : exposureMode_->shutter.back(); - maxShutter = clipShutter(maxShutter); + maxShutter = limitShutter(maxShutter); Duration maxTotalExposure = maxShutter * (status_.fixedAnalogueGain != 0.0 @@ -803,15 +803,16 @@ void Agc::divideUpExposure() double analogueGain; shutterTime = status_.fixedShutter ? status_.fixedShutter : exposureMode_->shutter[0]; - shutterTime = clipShutter(shutterTime); + shutterTime = limitShutter(shutterTime); analogueGain = status_.fixedAnalogueGain != 0.0 ? status_.fixedAnalogueGain : exposureMode_->gain[0]; + analogueGain = limitGain(analogueGain); if (shutterTime * analogueGain < exposureValue) { for (unsigned int stage = 1; stage < exposureMode_->gain.size(); stage++) { if (!status_.fixedShutter) { Duration stageShutter = - clipShutter(exposureMode_->shutter[stage]); + limitShutter(exposureMode_->shutter[stage]); if (stageShutter * analogueGain >= exposureValue) { shutterTime = exposureValue / analogueGain; break; @@ -824,6 +825,7 @@ void Agc::divideUpExposure() break; } analogueGain = exposureMode_->gain[stage]; + analogueGain = limitGain(analogueGain); } } } @@ -846,6 +848,7 @@ void Agc::divideUpExposure() * gain as a side-effect. */ analogueGain = std::min(analogueGain, exposureMode_->gain.back()); + analogueGain = limitGain(analogueGain); shutterTime = newShutterTime; } LOG(RPiAgc, Debug) << "After flicker avoidance, shutter " @@ -872,13 +875,37 @@ void Agc::writeAndFinish(Metadata *imageMetadata, bool desaturate) << " analogue gain " << filtered_.analogueGain; } -Duration Agc::clipShutter(Duration shutter) +Duration Agc::limitShutter(Duration shutter) { - if (sensorLimits_.maxShutter) - shutter = std::min(shutter, sensorLimits_.maxShutter); + /* + * shutter == 0 is a special case for fixed shutter values, and must pass + * through unchanged + */ + if (!shutter) + return shutter; + + shutter = std::clamp(shutter, sensorLimits_.minShutter, + sensorLimits_.maxShutter); return shutter; } +double Agc::limitGain(double gain) const +{ + /* + * Only limit the lower bounds of the gain value to what the sensor limits. + * The upper bound on analogue gain will be made up with additional digital + * gain applied by the ISP. + * + * gain == 0.0 is a special case for fixed shutter values, and must pass + * through unchanged + */ + if (!gain) + return gain; + + gain = std::max(gain, sensorLimits_.minAnalogueGain); + return gain; +} + /* Register algorithm with the system. */ static Algorithm *create(Controller *controller) { diff --git a/src/ipa/raspberrypi/controller/rpi/agc.h b/src/ipa/raspberrypi/controller/rpi/agc.h index 150a5f6e4428..c48acbba61f0 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.h +++ b/src/ipa/raspberrypi/controller/rpi/agc.h @@ -103,7 +103,8 @@ private: void filterExposure(bool desaturate); void divideUpExposure(); void writeAndFinish(Metadata *imageMetadata, bool desaturate); - libcamera::utils::Duration clipShutter(libcamera::utils::Duration shutter); + libcamera::utils::Duration limitShutter(libcamera::utils::Duration shutter); + double limitGain(double gain) const; AgcMeteringMode *meteringMode_; AgcExposureMode *exposureMode_; AgcConstraintMode *constraintMode_;