Patch Detail
Show a patch.
GET /api/1.1/patches/27196/?format=api
{ "id": 27196, "url": "https://patchwork.libcamera.org/api/1.1/patches/27196/?format=api", "web_url": "https://patchwork.libcamera.org/patch/27196/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20260703153819.1088752-18-barnabas.pocze@ideasonboard.com>", "date": "2026-07-03T15:38:19", "name": "[RFC,v1,17/17] ipa: simple: agc: Use `AgcMeanLuminance` if sensor helper is available", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "e61dd03363c819db8ff8146d93ecfd95e769f661", "submitter": { "id": 216, "url": "https://patchwork.libcamera.org/api/1.1/people/216/?format=api", "name": "Barnabás Pőcze", "email": "barnabas.pocze@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/27196/mbox/", "series": [ { "id": 6036, "url": "https://patchwork.libcamera.org/api/1.1/series/6036/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=6036", "date": "2026-07-03T15:38:02", "name": "ipa: libipa: agc rework", "version": 1, "mbox": "https://patchwork.libcamera.org/series/6036/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/27196/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/27196/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 C39A6C3323\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 3 Jul 2026 15:38:46 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 482976601D;\n\tFri, 3 Jul 2026 17:38:45 +0200 (CEST)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 99FD765FC5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 3 Jul 2026 17:38:26 +0200 (CEST)", "from pb-laptop.local (185.221.140.128.nat.pool.zt.hu\n\t[185.221.140.128])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8BCBADF3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 3 Jul 2026 17:37:40 +0200 (CEST)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"fpNMW/nT\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1783093060;\n\tbh=GXzn8M8jH7x9pvaQEZpWK5TfAICmqncbl1I+BrEZruM=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=fpNMW/nTxKapBxY4Gh0KFpxjsFV7i+hBrpnKu7kn1fPZ6FhF/54pZlFmSkwYpxWHB\n\te2lz2vNKvDdLTDFcC6L1ca0ypjqf2q93anCpLOted2plimQ5BTKTxoxZv8KrBNB5zK\n\tNTQKYiWPpQfOw7uglIfVZctYISiDHM//PHa/hpUw=", "From": "=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Subject": "[RFC PATCH v1 17/17] ipa: simple: agc: Use `AgcMeanLuminance` if\n\tsensor helper is available", "Date": "Fri, 3 Jul 2026 17:38:19 +0200", "Message-ID": "<20260703153819.1088752-18-barnabas.pocze@ideasonboard.com>", "X-Mailer": "git-send-email 2.54.0", "In-Reply-To": "<20260703153819.1088752-1-barnabas.pocze@ideasonboard.com>", "References": "<20260703153819.1088752-1-barnabas.pocze@ideasonboard.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "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>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n---\n src/ipa/simple/algorithms/agc.cpp | 153 +++++++++++++++++++++++++-----\n src/ipa/simple/algorithms/agc.h | 9 +-\n src/ipa/simple/ipa_context.h | 4 +\n 3 files changed, 143 insertions(+), 23 deletions(-)", "diff": "diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp\nindex db4f63eba5..7d035618e8 100644\n--- a/src/ipa/simple/algorithms/agc.cpp\n+++ b/src/ipa/simple/algorithms/agc.cpp\n@@ -7,7 +7,12 @@\n \n #include \"agc.h\"\n \n+#include <variant>\n+\n #include <libcamera/base/log.h>\n+#include <libcamera/base/utils.h>\n+\n+#include <libipa/histogram.h>\n \n namespace libcamera {\n \n@@ -15,38 +20,119 @@ LOG_DEFINE_CATEGORY(IPASoftExposure)\n \n namespace ipa::soft::algorithms {\n \n-int Agc::init(IPAContext &context, [[maybe_unused]] const ValueNode &tuningData)\n+namespace {\n+\n+class AgcTraits : public AgcMeanLuminance::Traits\n {\n-\treturn agc_.configure(context.configuration.agc.simple, context.activeState.agc.simple, {\n+public:\n+\tAgcTraits(const SwIspStats &stats)\n+\t\t: stats_(stats)\n+\t{\n+\t}\n+\n+\tdouble estimateLuminance(double gain) const override\n+\t{\n+\t\tdouble sum = 0;\n+\t\tdouble count = 0;\n+\n+\t\tfor (const auto &[i, cnt] : utils::enumerate(stats_.yHistogram)) {\n+\t\t\tsum += std::min(1.0, gain * i / stats_.yHistogram.size()) * cnt;\n+\t\t\tcount += cnt;\n+\t\t}\n+\n+\t\treturn sum / count;\n+\t}\n+\n+private:\n+\tconst SwIspStats &stats_;\n+};\n+\n+}\n+\n+int Agc::init(IPAContext &context, const ValueNode &tuningData)\n+{\n+\tconst AgcAlgorithm::ConfigurationParams config = {\n \t\t.sensor = context.camHelper.get(),\n \t\t.sensorInfo = context.sensorInfo,\n \t\t.sensorControls = context.sensorControls,\n \t\t.ctrlMap = context.ctrlMap,\n \t\t.autoAllowed = true,\n-\t});\n+\t};\n+\n+\tif (config.sensor)\n+\t\tagc_.emplace<AgcMeanLuminanceAlgorithm>();\n+\telse\n+\t\tagc_.emplace<AgcSimpleAlgorithm>();\n+\n+\treturn std::visit(utils::overloaded {\n+\t\t[&](AgcSimpleAlgorithm &impl) {\n+\t\t\treturn impl.configure(context.configuration.agc.simple,\n+\t\t\t\t\t context.activeState.agc.simple,\n+\t\t\t\t\t config);\n+\t\t},\n+\t\t[&](AgcMeanLuminanceAlgorithm &impl) {\n+\t\t\tint ret = impl.init(tuningData);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\n+\t\t\treturn impl.configure(context.configuration.agc.ml,\n+\t\t\t\t\t context.activeState.agc.ml,\n+\t\t\t\t\t config);\n+\t\t},\n+\t}, agc_);\n }\n \n int Agc::configure(IPAContext &context, [[maybe_unused]] const IPAConfigInfo &configInfo)\n {\n-\treturn agc_.configure(context.configuration.agc.simple, context.activeState.agc.simple, {\n+\tconst AgcAlgorithm::ConfigurationParams config = {\n \t\t.sensor = context.camHelper.get(),\n \t\t.sensorInfo = context.sensorInfo,\n \t\t.sensorControls = context.sensorControls,\n \t\t.ctrlMap = context.ctrlMap,\n-\t\t.autoAllowed = true, // \\todo not if raw?\n-\t});\n+\t\t.autoAllowed = true, // \\todo if not raw?\n+\t};\n+\n+\treturn std::visit(utils::overloaded {\n+\t\t[&](AgcSimpleAlgorithm &impl) {\n+\t\t\treturn impl.configure(context.configuration.agc.simple,\n+\t\t\t\t\t context.activeState.agc.simple,\n+\t\t\t\t\t config);\n+\t\t},\n+\t\t[&](AgcMeanLuminanceAlgorithm &impl) {\n+\t\t\treturn impl.configure(context.configuration.agc.ml,\n+\t\t\t\t\t context.activeState.agc.ml,\n+\t\t\t\t\t config);\n+\t\t},\n+\t}, agc_);\n }\n \n void Agc::queueRequest(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAFrameContext &frameContext, const ControlList &controls)\n {\n-\tagc_.queueRequest(context.configuration.agc.simple, context.activeState.agc.simple,\n-\t\t\t frameContext.agc.simple, controls);\n+\tstd::visit(utils::overloaded {\n+\t\t[&](AgcSimpleAlgorithm &impl) {\n+\t\t\timpl.queueRequest(context.configuration.agc.simple,\n+\t\t\t\t\t context.activeState.agc.simple,\n+\t\t\t\t\t frameContext.agc.simple, controls);\n+\t\t},\n+\t\t[&](AgcMeanLuminanceAlgorithm &impl) {\n+\t\t\timpl.queueRequest(context.configuration.agc.ml,\n+\t\t\t\t\t context.activeState.agc.ml,\n+\t\t\t\t\t frameContext.agc.ml, controls);\n+\t\t},\n+\t}, agc_);\n }\n \n void Agc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \t\t IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params)\n {\n-\tagc_.prepare(context.activeState.agc.simple, frameContext.agc.simple);\n+\tstd::visit(utils::overloaded {\n+\t\t[&](AgcSimpleAlgorithm &impl) {\n+\t\t\timpl.prepare(context.activeState.agc.simple, frameContext.agc.simple);\n+\t\t},\n+\t\t[&](AgcMeanLuminanceAlgorithm &impl) {\n+\t\t\timpl.prepare(context.activeState.agc.ml, frameContext.agc.ml);\n+\t\t},\n+\t}, agc_);\n }\n \n void Agc::process(IPAContext &context,\n@@ -55,20 +141,43 @@ void Agc::process(IPAContext &context,\n \t\t const SwIspStats *stats,\n \t\t ControlList &metadata)\n {\n-\tif (stats->valid) {\n-\t\tagc_.process(context.configuration.agc.simple, context.activeState.agc.simple, frameContext.agc.simple, {{\n-\t\t\t.exposure = frameContext.sensor.exposure,\n-\t\t\t.gain = frameContext.sensor.gain,\n-\t\t\t.stats = *stats,\n-\t\t\t.blackLevel = context.activeState.blc.level,\n-\t\t}}, metadata);\n-\t} else {\n-\t\tagc_.process(context.configuration.agc.simple, context.activeState.agc.simple,\n-\t\t\t frameContext.agc.simple, {}, metadata);\n-\t}\n+\tstd::visit(utils::overloaded {\n+\t\t[&](AgcSimpleAlgorithm &impl) {\n+\t\t\tif (stats->valid) {\n+\t\t\t\timpl.process(context.configuration.agc.simple, context.activeState.agc.simple, frameContext.agc.simple, {{\n+\t\t\t\t\t.exposure = frameContext.sensor.exposure,\n+\t\t\t\t\t.gain = frameContext.sensor.gain,\n+\t\t\t\t\t.stats = *stats,\n+\t\t\t\t\t.blackLevel = context.activeState.blc.level,\n+\t\t\t\t}}, metadata);\n+\t\t\t} else {\n+\t\t\t\timpl.process(context.configuration.agc.simple, context.activeState.agc.simple,\n+\t\t\t\t\t frameContext.agc.simple, {}, metadata);\n+\t\t\t}\n+\n+\t\t\tframeContext.agc.exposure = frameContext.agc.simple.exposure;\n+\t\t\tframeContext.agc.gain = frameContext.agc.simple.gain;\n+\t\t},\n+\t\t[&](AgcMeanLuminanceAlgorithm &impl) {\n+\t\t\tif (stats->valid) {\n+\t\t\t\tHistogram hist(stats->yHistogram);\n+\n+\t\t\t\timpl.process(context.configuration.agc.ml, context.activeState.agc.ml, frameContext.agc.ml, {{\n+\t\t\t\t\t.traits = AgcTraits(*stats),\n+\t\t\t\t\t.hist = hist,\n+\t\t\t\t\t.exposure = uint32_t(frameContext.sensor.exposure),\n+\t\t\t\t\t.gain = frameContext.sensor.gain,\n+\t\t\t\t}}, metadata);\n+\n+\t\t\t} else {\n+\t\t\t\timpl.process(context.configuration.agc.ml, context.activeState.agc.ml,\n+\t\t\t\t\t frameContext.agc.ml, {}, metadata);\n+\t\t\t}\n \n-\tframeContext.agc.exposure = frameContext.agc.simple.exposure;\n-\tframeContext.agc.gain = frameContext.agc.simple.gain;\n+\t\t\tframeContext.agc.exposure = frameContext.agc.ml.exposure;\n+\t\t\tframeContext.agc.gain = frameContext.agc.ml.gain;\n+\t\t},\n+\t}, agc_);\n }\n \n REGISTER_IPA_ALGORITHM(Agc, \"Agc\")\ndiff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h\nindex 869817fc95..5dac17ab1d 100644\n--- a/src/ipa/simple/algorithms/agc.h\n+++ b/src/ipa/simple/algorithms/agc.h\n@@ -7,6 +7,10 @@\n \n #pragma once\n \n+#include <variant>\n+\n+#include <libipa/agc_mean_luminance.h>\n+\n #include \"algorithm.h\"\n #include \"agc_simple.h\"\n \n@@ -30,7 +34,10 @@ public:\n \t\t ControlList &metadata) override;\n \n private:\n-\tAgcSimpleAlgorithm agc_;\n+\tstd::variant<\n+\t\tAgcSimpleAlgorithm,\n+\t\tAgcMeanLuminanceAlgorithm\n+\t> agc_;\n };\n \n } /* namespace ipa::soft::algorithms */\ndiff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h\nindex 36e1d8bba8..b4a11b04cd 100644\n--- a/src/ipa/simple/ipa_context.h\n+++ b/src/ipa/simple/ipa_context.h\n@@ -15,6 +15,7 @@\n #include \"libcamera/internal/matrix.h\"\n #include \"libcamera/internal/vector.h\"\n \n+#include <libipa/agc_mean_luminance.h>\n #include <libipa/camera_sensor_helper.h>\n #include <libipa/fc_queue.h>\n \n@@ -29,6 +30,7 @@ namespace ipa::soft {\n struct IPASessionConfiguration {\n \tstruct {\n \t\tAgcSimpleAlgorithm::Session simple;\n+\t\tAgcMeanLuminanceAlgorithm::Session ml;\n \t\tdouble again10, againMinStep;\n \t} agc;\n \tstruct {\n@@ -39,6 +41,7 @@ struct IPASessionConfiguration {\n struct IPAActiveState {\n \tstruct {\n \t\tAgcSimpleAlgorithm::ActiveState simple;\n+\t\tAgcMeanLuminanceAlgorithm::ActiveState ml;\n \t} agc;\n \n \tstruct {\n@@ -67,6 +70,7 @@ struct IPAFrameContext : public FrameContext {\n \n \tstruct {\n \t\tAgcSimpleAlgorithm::FrameContext simple;\n+\t\tAgcMeanLuminanceAlgorithm::FrameContext ml;\n \t\tint32_t exposure;\n \t\tdouble gain;\n \t} agc;\n", "prefixes": [ "RFC", "v1", "17/17" ] }