{"id":10434,"url":"https://patchwork.libcamera.org/api/1.1/patches/10434/?format=json","web_url":"https://patchwork.libcamera.org/patch/10434/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20201116164918.2055-6-david.plowman@raspberrypi.com>","date":"2020-11-16T16:49:13","name":"[libcamera-devel,05/10] libcamera: ipa: raspberrypi: agc: Fetch AWB status only once","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"f5ec372d270f7333281573413792bce41a9d523b","submitter":{"id":42,"url":"https://patchwork.libcamera.org/api/1.1/people/42/?format=json","name":"David Plowman","email":"david.plowman@raspberrypi.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/10434/mbox/","series":[{"id":1464,"url":"https://patchwork.libcamera.org/api/1.1/series/1464/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=1464","date":"2020-11-16T16:49:08","name":"Raspberry Pi AGC","version":1,"mbox":"https://patchwork.libcamera.org/series/1464/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/10434/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/10434/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D0303BE082\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 16 Nov 2020 16:49:32 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9EF39632DE;\n\tMon, 16 Nov 2020 17:49:32 +0100 (CET)","from mail-wr1-x436.google.com (mail-wr1-x436.google.com\n\t[IPv6:2a00:1450:4864:20::436])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A6668632D8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 16 Nov 2020 17:49:29 +0100 (CET)","by mail-wr1-x436.google.com with SMTP id j7so19410086wrp.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 16 Nov 2020 08:49:29 -0800 (PST)","from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72])\n\tby smtp.gmail.com with ESMTPSA id\n\tq16sm23716973wrn.13.2020.11.16.08.49.28\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 16 Nov 2020 08:49:28 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"NidqvYhV\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=3jOTqsdM+5vSReHOduxhhHeWX+jcNQzjs9vGsaKAjj8=;\n\tb=NidqvYhVeTQ16nbibmCfTfc8gH3CR+macAriZ0dsfCosr1dbDfzlnANSHKhtRb9x5q\n\tQqrSpX6WtBeVHbujcaasWrU9EF9a7v2CZM1HzTdAixVGHo9gRdyIUvAaW1bcjxqf2+Mw\n\t8sJfec3CWnfcABuD3SAWA/NLbBmzLPjB4NevLeD5DUyD89olhpmdRLkYmtfaDtVdwqpu\n\tw1mx6LeLpzsgXP3mScAnLLH6kb5KAjAArTUA4axdXehE5EEg7g3kD6FCbJxI6PGsWF5P\n\tFb344FX/E9sKwe9LFkeod99pnB94y12q/RsB26O1QrOb3gCKpHAWRZWVg4/KP8/byIM2\n\tKIcw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=3jOTqsdM+5vSReHOduxhhHeWX+jcNQzjs9vGsaKAjj8=;\n\tb=PRIOU44nijD2JKVoG/3WvKwDc2k1FLXbpFEufoSArf6LnsQU0xfZPibdfFz1XYUnF0\n\tUUa92j6N/dVI/Js7NancrqfjMhNlqb5UXixu+XPDg5Rzk2vjBCndAyCGBonSH+GRo0QF\n\thDqewKXf33gL9Atodft3mTdHhDpGkKEuPNQjE+caacSBaZcKg/56afbcquRqyeESIute\n\tgwU53xOHbTNvOJz0GFN6U052WiyVgfuvvJ28l45bDzIEnJQTRf8g1Tw0xqMibBYxM1qE\n\thqWdrFHXKs956hoA0od9pAZc1ynwUwGo/+LNQn0YOt7FQFCKqz4ME5wr2cLcxc/ujkAq\n\tGVMw==","X-Gm-Message-State":"AOAM533ybtmjC6XXZRn3/xtgdjPt0OTNiWQ1Opk1mBoUw7dUrGYtbSDE\n\tvGFAJAWDnTxS+OpFCVPT+FVvTP4rpeYD3w==","X-Google-Smtp-Source":"ABdhPJwA/o677mH523dHvj34Pah/tT3vRGIqXOvqVLXQj6UMJghFfsr7uWFGGCC+dYOBaD2uZkIpCQ==","X-Received":"by 2002:adf:e88b:: with SMTP id d11mr19378694wrm.4.1605545369068;\n\tMon, 16 Nov 2020 08:49:29 -0800 (PST)","From":"David Plowman <david.plowman@raspberrypi.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Mon, 16 Nov 2020 16:49:13 +0000","Message-Id":"<20201116164918.2055-6-david.plowman@raspberrypi.com>","X-Mailer":"git-send-email 2.20.1","In-Reply-To":"<20201116164918.2055-1-david.plowman@raspberrypi.com>","References":"<20201116164918.2055-1-david.plowman@raspberrypi.com>","MIME-Version":"1.0","Subject":"[libcamera-devel] [PATCH 05/10] libcamera: ipa: raspberrypi: agc:\n\tFetch AWB status only once","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Introduce a function to fetch the AwbStatus (fetchAwbStatus), and call\nit unconditionally at the top of Prepare so that both Prepare and\nProcess know thereafter that it's been done.\n\nSigned-off-by: David Plowman <david.plowman@raspberrypi.com>\n---\n src/ipa/raspberrypi/controller/rpi/agc.cpp | 37 ++++++++++++----------\n src/ipa/raspberrypi/controller/rpi/agc.hpp |  5 +--\n 2 files changed, 23 insertions(+), 19 deletions(-)","diff":"diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp\nindex ead28398..6de56def 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp\n@@ -5,6 +5,8 @@\n  * agc.cpp - AGC/AEC control algorithm\n  */\n \n+#include <assert.h>\n+\n #include <map>\n \n #include \"linux/bcm2835-isp.h\"\n@@ -235,6 +237,8 @@ void Agc::Prepare(Metadata *image_metadata)\n \tint lock_count = lock_count_;\n \tlock_count_ = 0;\n \tstatus_.digital_gain = 1.0;\n+\tfetchAwbStatus(image_metadata); // always fetch it so that Process knows it's been done\n+\n \tif (status_.total_exposure_value) {\n \t\t// Process has run, so we have meaningful values.\n \t\tDeviceStatus device_status;\n@@ -301,7 +305,7 @@ void Agc::Process(StatisticsPtr &stats, Metadata *image_metadata)\n \t// Some of the exposure has to be applied as digital gain, so work out\n \t// what that is. This function also tells us whether it's decided to\n \t// \"desaturate\" the image more quickly.\n-\tbool desaturate = applyDigitalGain(image_metadata, gain, target_Y);\n+\tbool desaturate = applyDigitalGain(gain, target_Y);\n \t// The results have to be filtered so as not to change too rapidly.\n \tfilterExposure(desaturate);\n \t// The last thing is to divide up the exposure value into a shutter time\n@@ -378,14 +382,19 @@ void Agc::fetchCurrentExposure(Metadata *image_metadata)\n \tcurrent_.total_exposure_no_dg = current_.shutter * current_.analogue_gain;\n }\n \n-static double compute_initial_Y(bcm2835_isp_stats *stats, Metadata *image_metadata,\n+void Agc::fetchAwbStatus(Metadata *image_metadata)\n+{\n+\tawb_.gain_r = 1.0; // in case not found in metadata\n+\tawb_.gain_g = 1.0;\n+\tawb_.gain_b = 1.0;\n+\tif (image_metadata->Get(\"awb.status\", awb_) != 0)\n+\t\tLOG(RPiAgc, Warning) << \"Agc: no AWB status found\";\n+}\n+\n+static double compute_initial_Y(bcm2835_isp_stats *stats, AwbStatus const &awb,\n \t\t\t\tdouble weights[])\n {\n \tbcm2835_isp_stats_region *regions = stats->agc_stats;\n-\tstruct AwbStatus awb;\n-\tawb.gain_r = awb.gain_g = awb.gain_b = 1.0; // in case no metadata\n-\tif (image_metadata->Get(\"awb.status\", awb) != 0)\n-\t\tLOG(RPiAgc, Warning) << \"Agc: no AWB status found\";\n \t// Note how the calculation below means that equal weights give you\n \t// \"average\" metering (i.e. all pixels equally important).\n \tdouble R_sum = 0, G_sum = 0, B_sum = 0, pixel_sum = 0;\n@@ -437,7 +446,7 @@ void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata,\n \ttarget_Y =\n \t\tconfig_.Y_target.Eval(config_.Y_target.Domain().Clip(lux.lux));\n \ttarget_Y = std::min(EV_GAIN_Y_TARGET_LIMIT, target_Y * ev_gain);\n-\tdouble initial_Y = compute_initial_Y(statistics, image_metadata,\n+\tdouble initial_Y = compute_initial_Y(statistics, awb_,\n \t\t\t\t\t     metering_mode_->weights);\n \tgain = std::min(10.0, target_Y / (initial_Y + .001));\n \tLOG(RPiAgc, Debug) << \"Initially Y \" << initial_Y << \" target \" << target_Y\n@@ -483,19 +492,13 @@ void Agc::computeTargetExposure(double gain)\n \tLOG(RPiAgc, Debug) << \"Target total_exposure \" << target_.total_exposure;\n }\n \n-bool Agc::applyDigitalGain(Metadata *image_metadata, double gain,\n-\t\t\t   double target_Y)\n+bool Agc::applyDigitalGain(double gain, double target_Y)\n {\n-\tdouble dg = 1.0;\n+\tdouble min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 });\n+\tassert(min_colour_gain != 0.0);\n+\tdouble dg = 1.0 / min_colour_gain;\n \t// I think this pipeline subtracts black level and rescales before we\n \t// get the stats, so no need to worry about it.\n-\tstruct AwbStatus awb;\n-\tif (image_metadata->Get(\"awb.status\", awb) == 0) {\n-\t\tdouble min_gain = std::min(awb.gain_r,\n-\t\t\t\t\t   std::min(awb.gain_g, awb.gain_b));\n-\t\tdg *= std::max(1.0, 1.0 / min_gain);\n-\t} else\n-\t\tLOG(RPiAgc, Warning) << \"Agc: no AWB status found\";\n \tLOG(RPiAgc, Debug) << \"after AWB, target dg \" << dg << \" gain \" << gain\n \t\t\t   << \" target_Y \" << target_Y;\n \t// Finally, if we're trying to reduce exposure but the target_Y is\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp\nindex 2442fc03..e7ac480f 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.hpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp\n@@ -83,11 +83,11 @@ private:\n \tAgcConfig config_;\n \tvoid housekeepConfig();\n \tvoid fetchCurrentExposure(Metadata *image_metadata);\n+\tvoid fetchAwbStatus(Metadata *image_metadata);\n \tvoid computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata,\n \t\t\t double &gain, double &target_Y);\n \tvoid computeTargetExposure(double gain);\n-\tbool applyDigitalGain(Metadata *image_metadata, double gain,\n-\t\t\t      double target_Y);\n+\tbool applyDigitalGain(double gain, double target_Y);\n \tvoid filterExposure(bool desaturate);\n \tvoid divideUpExposure();\n \tvoid writeAndFinish(Metadata *image_metadata, bool desaturate);\n@@ -95,6 +95,7 @@ private:\n \tAgcExposureMode *exposure_mode_;\n \tAgcConstraintMode *constraint_mode_;\n \tuint64_t frame_count_;\n+\tAwbStatus awb_;\n \tstruct ExposureValues {\n \t\tExposureValues() : shutter(0), analogue_gain(0),\n \t\t\t\t   total_exposure(0), total_exposure_no_dg(0) {}\n","prefixes":["libcamera-devel","05/10"]}