{"id":26879,"url":"https://patchwork.libcamera.org/api/patches/26879/?format=json","web_url":"https://patchwork.libcamera.org/patch/26879/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/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":"<20260615-libipa-algorithms-v1-2-e949c937422e@ideasonboard.com>","date":"2026-06-15T14:05:27","name":"[02/11] ipa: mali-c55: awb: Port to use libipa AwbAlgorithm","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"c8d20728b70bddbb79935ca11ea8326aa1bb16d4","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/?format=json","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/26879/mbox/","series":[{"id":5992,"url":"https://patchwork.libcamera.org/api/series/5992/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5992","date":"2026-06-15T14:05:25","name":"ipa: libipa: Introduce libipa algorithms","version":1,"mbox":"https://patchwork.libcamera.org/series/5992/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/26879/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/26879/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 EF64BC324C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 15 Jun 2026 14:05:57 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 52144623E7;\n\tMon, 15 Jun 2026 16:05:53 +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 80508623E7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 15 Jun 2026 16:05:47 +0200 (CEST)","from [192.168.1.104] (net-93-65-100-155.cust.vodafonedsl.it\n\t[93.65.100.155])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 95B0CAB4;\n\tMon, 15 Jun 2026 16:05:14 +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=\"H53iUCxg\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1781532314;\n\tbh=21E4tZLP2C1KoqRbobeEZiEboXquXxQviTk97QD8mew=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=H53iUCxgt0gOKw69NPhymcOzGgKHkYaQD30uHsDpwJbxOt1lProZ7H0G5Bco1nxkW\n\tx4ARjpPCDXyy6MR3ToV9ltClFJnBbHrchtYXP3gkluGLUMoLlgvMFNo2MuVMMhP/7A\n\tm30IUH2ri5kpEYVCeyYpdVj2MgKDAHDRIsX1HIyg=","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Date":"Mon, 15 Jun 2026 16:05:27 +0200","Subject":"[PATCH 02/11] ipa: mali-c55: awb: Port to use libipa AwbAlgorithm","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"7bit","Message-Id":"<20260615-libipa-algorithms-v1-2-e949c937422e@ideasonboard.com>","References":"<20260615-libipa-algorithms-v1-0-e949c937422e@ideasonboard.com>","In-Reply-To":"<20260615-libipa-algorithms-v1-0-e949c937422e@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","X-Mailer":"b4 0.14.3","X-Developer-Signature":"v=1; a=openpgp-sha256; l=16990;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=21E4tZLP2C1KoqRbobeEZiEboXquXxQviTk97QD8mew=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBqMAa4LfItJ/ELlMDSF13DbjhPy3oY+qW6VL7VE\n\tONYb4TSBNiJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCajAGuAAKCRByNAaPFqFW\n\tPE9zD/9VSxjC2jTlCwuTeI2piIHXH3oQby+njLbouVeZLErQcb0idrbRdSY7EYM/ksnqg0zMawe\n\tWC4PXZWpBr37TnPkhPL+bGfQ6M5YKDdVwRTQZ1YI8nhoL0O9DY6dGmHTvco/Fp3+K1xeKMlugem\n\t+Y8VImGOLtHd0JuMpY5/UtfNANNb89Kwk4C1rUuH/YvQCupOyfQj+mJMjA2EXvSduB13jC2g7Ig\n\te1RqoV+wXAmnRnIesvTdkY2snzmNNrxIm7r8oxTJ06ouT96nr/mNL4V1JnPvUxJjuDiV9RSYo0g\n\t4Ivqeh1s7aiktRf5zD8X+hJNg3dZpYW1FiVoXvRwG3RXPry2m4ik+rCn/g0iQzJ4KjDzxXiwCpf\n\tBt3jqs5FUtA8kfwSbnrqvte8EhaXzyN5hg2vT+MBor5RyTD42z06LgHDoKzfiT0hMsFwvZcSYsX\n\tCAWlkN2mL3fwLUohe4qR2Yk5lDbrdy9nOaF44sJ8wO/qw5mtBBtMoPmgFEzW657FTumv/BR65Ge\n\tk9UidtarQLr+uHBXFrgjCvoO+QlMml9wAb/JXL9S8GATX9NNf/9OQuuZZX5iloxUYkWudhinQAj\n\t4y0U1Q+/Pjr8pmUGA3z1dkmPcn0Ys7fuvDxZ+lBd4LAI5F5/sdX6fXBmQBxg58CGRW1qTupPlYD\n\tOdNmsHNDoHrGOig==","X-Developer-Key":"i=jacopo.mondi@ideasonboard.com; a=openpgp;\n\tfpr=72392EDC88144A65C701EA9BA5826A2587AD026B","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":"Port the Mali-C55 Awb algorithm to use the new libipa implementation\nof AwbAlgorithm.\n\nThe awbAlgo_ class member is initialized with the Q<4, 8> type that\nrepresents the register format and the MaliC55AwbStats type handles\nthe WB statistics format as produced by the Mali-C55 which already\ncalculates the mean values as R/G and B/G values.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n src/ipa/mali-c55/algorithms/awb.cpp | 198 ++++++++++++++++++------------------\n src/ipa/mali-c55/algorithms/awb.h   |  30 ++++--\n src/ipa/mali-c55/ipa_context.cpp    |   6 ++\n src/ipa/mali-c55/ipa_context.h      |  17 ++--\n src/ipa/mali-c55/mali-c55.cpp       |  27 +++--\n 5 files changed, 152 insertions(+), 126 deletions(-)","diff":"diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp\nindex 8a671b52be59..97964f395325 100644\n--- a/src/ipa/mali-c55/algorithms/awb.cpp\n+++ b/src/ipa/mali-c55/algorithms/awb.cpp\n@@ -2,7 +2,7 @@\n /*\n  * Copyright (C) 2024, Ideas On Board Oy\n  *\n- * Mali C55 grey world auto white balance algorithm\n+ * Mali C55 auto white balance algorithm\n  */\n \n #include \"awb.h\"\n@@ -14,63 +14,65 @@\n \n #include <libcamera/control_ids.h>\n \n-#include \"libipa/fixedpoint.h\"\n-\n namespace libcamera {\n \n namespace ipa::mali_c55::algorithms {\n \n LOG_DEFINE_CATEGORY(MaliC55Awb)\n \n-/* Number of frames at which we should run AWB at full speed */\n-static constexpr uint32_t kNumStartupFrames = 4;\n+/* \\todo Mali-C55 doesn't support the Lux algorithm. */\n+static constexpr unsigned int kDefaultLux = 500;\n+\n+class MaliC55AwbStats final : public AwbStats\n+{\n+public:\n+\tMaliC55AwbStats() = default;\n+\tMaliC55AwbStats(const RGB<double> &rgbMeans)\n+\t\t: AwbStats(rgbMeans)\n+\t{\n+\t\t/* The Mali-C55 ISP already provides stats as R/G and B/G ratios. */\n+\t\trg_ = rgbMeans_.r();\n+\t\tbg_ = rgbMeans_.b();\n+\t}\n \n-Awb::Awb()\n+\t/* Minimum mean value below which AWB can't operate. */\n+\tdouble minColourValue() const override\n+\t{\n+\t\treturn 0.2;\n+\t}\n+};\n+\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::init\n+ */\n+int Awb::init(IPAContext &context, const ValueNode &tuningData)\n {\n+\treturn awbAlgo_.init(tuningData, context.ctrlMap);\n }\n \n-int Awb::configure([[maybe_unused]] IPAContext &context,\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::configure\n+ */\n+int Awb::configure(IPAContext &context,\n \t\t   [[maybe_unused]] const IPACameraSensorInfo &configInfo)\n {\n-\t/*\n-\t * Initially we have no idea what the colour balance will be like, so\n-\t * for the first frame we will make no assumptions and leave the R/B\n-\t * channels unmodified.\n-\t */\n-\tcontext.activeState.awb.rGain = 1.0f;\n-\tcontext.activeState.awb.bGain = 1.0f;\n-\n-\treturn 0;\n+\treturn awbAlgo_.configure(context.activeState.awb,\n+\t\t\t\t  context.configuration.awb);\n }\n \n-void Awb::fillGainsParamBlock(MaliC55Params *params, IPAContext &context,\n-\t\t\t\tIPAFrameContext &frameContext)\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::queueRequest\n+ */\n+void Awb::queueRequest(IPAContext &context,\n+\t\t       const uint32_t frame,\n+\t\t       IPAFrameContext &frameContext,\n+\t\t       const ControlList &controls)\n {\n-\tUQ<4, 8> rGain = context.activeState.awb.rGain;\n-\tUQ<4, 8> bGain = context.activeState.awb.bGain;\n-\n-\t/*\n-\t * The gains here map as follows:\n-\t *\tgain00 = R\n-\t *\tgain01 = Gr\n-\t *\tgain10 = Gb\n-\t *\tgain11 = B\n-\t *\n-\t * This holds true regardless of the bayer order of the input data, as\n-\t * the mapping is done internally in the ISP.\n-\t */\n-\tauto block = params->block<MaliC55Blocks::AwbGains>();\n-\n-\tblock->gain00 = rGain.quantized();\n-\tblock->gain01 = UQ<4, 8>(1.0f).quantized();\n-\tblock->gain10 = UQ<4, 8>(1.0f).quantized();\n-\tblock->gain11 = bGain.quantized();\n-\n-\tframeContext.awb.rGain = rGain;\n-\tframeContext.awb.bGain = bGain;\n+\tawbAlgo_.queueRequest(context.activeState.awb, frame, frameContext.awb,\n+\t\t\t      controls);\n }\n \n-void Awb::fillConfigParamBlock(MaliC55Params *params)\n+void Awb::configAwbMeas(MaliC55Params *params)\n {\n \tauto block = params->block<MaliC55Blocks::AwbConfig>();\n \n@@ -117,56 +119,77 @@ void Awb::fillConfigParamBlock(MaliC55Params *params)\n \tblock->cb_low = 64;\n }\n \n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::prepare\n+ */\n void Awb::prepare(IPAContext &context, const uint32_t frame,\n \t\t  IPAFrameContext &frameContext, MaliC55Params *params)\n {\n-\tfillGainsParamBlock(params, context, frameContext);\n+\tawbAlgo_.prepare(context.activeState.awb, frameContext.awb);\n+\n+\t/*\n+\t * The gains here map as follows:\n+\t *\tgain00 = R\n+\t *\tgain01 = Gr\n+\t *\tgain10 = Gb\n+\t *\tgain11 = B\n+\t *\n+\t * This holds true regardless of the bayer order of the input data, as\n+\t * the mapping is done internally in the ISP.\n+\t */\n+\tauto block = params->block<MaliC55Blocks::AwbGains>();\n+\tblock.setEnabled(true);\n+\n+\tblock->gain00 = UQ<4, 8>(static_cast<float>(frameContext.awb.gains.r()))\n+\t\t\t\t.quantized();\n+\tblock->gain01 = UQ<4, 8>(1.0f).quantized();\n+\tblock->gain10 = UQ<4, 8>(1.0f).quantized();\n+\tblock->gain11 = UQ<4, 8>(static_cast<float>(frameContext.awb.gains.b()))\n+\t\t\t\t.quantized();\n \n \tif (frame > 0)\n \t\treturn;\n \n-\tfillConfigParamBlock(params);\n+\tconfigAwbMeas(params);\n }\n \n-void Awb::process(IPAContext &context, const uint32_t frame,\n-\t\t  IPAFrameContext &frameContext, const mali_c55_stats_buffer *stats,\n-\t\t  [[maybe_unused]] ControlList &metadata)\n+MaliC55AwbStats Awb::calculateRgbMeans(const IPAFrameContext &frameContext,\n+\t\t\t\t       const mali_c55_stats_buffer *stats) const\n {\n-\tconst struct mali_c55_awb_average_ratios *awb_ratios = stats->awb_ratios;\n+\tconst struct mali_c55_awb_average_ratios *awb = stats->awb_ratios;\n \n \t/*\n \t * The ISP produces average R:G and B:G ratios for zones. We take the\n-\t * average of all the zones with data and simply invert them to provide\n-\t * gain figures that we can apply to approximate a grey world.\n+\t * average of all the zones with data and calculate the mean values.\n \t */\n-\tunsigned int counted_zones = 0;\n-\tfloat rgSum = 0, bgSum = 0;\n+\tunsigned int active_zones = 0;\n+\tdouble rgSum = 0, bgSum = 0;\n \n \tfor (unsigned int i = 0; i < 225; i++) {\n-\t\tif (!awb_ratios[i].num_pixels)\n+\t\tif (!awb[i].num_pixels)\n \t\t\tcontinue;\n \n \t\t/*\n-\t\t * The statistics are in Q4.8 format, so we convert to float\n+\t\t * The statistics are in Q4.8 format, so we convert to double\n \t\t * here.\n \t\t */\n-\t\trgSum += UQ<4, 8>(awb_ratios[i].avg_rg_gr).value();\n-\t\tbgSum += UQ<4, 8>(awb_ratios[i].avg_bg_br).value();\n-\t\tcounted_zones++;\n+\t\trgSum += UQ<4, 8>(awb[i].avg_rg_gr).value();\n+\t\tbgSum += UQ<4, 8>(awb[i].avg_bg_br).value();\n+\t\tactive_zones++;\n \t}\n \n \t/*\n \t * Sometimes the first frame's statistics have no valid pixels, in which\n \t * case we'll just assume a grey world until they say otherwise.\n \t */\n-\tfloat rgAvg, bgAvg;\n-\tif (!counted_zones) {\n-\t\trgAvg = 1.0;\n-\t\tbgAvg = 1.0;\n-\t} else {\n-\t\trgAvg = rgSum / counted_zones;\n-\t\tbgAvg = bgSum / counted_zones;\n-\t}\n+\tif (!active_zones)\n+\t\treturn {};\n+\n+\tRGB<double> rgbMeans = { {\n+\t\trgSum / active_zones,\n+\t\t1.0,\n+\t\tbgSum / active_zones,\n+\t} };\n \n \t/*\n \t * The statistics are generated _after_ white balancing is performed in\n@@ -174,41 +197,22 @@ void Awb::process(IPAContext &context, const uint32_t frame,\n \t * figure by the gains that were applied when the statistics for this\n \t * frame were generated.\n \t */\n-\tfloat rRatio = rgAvg / frameContext.awb.rGain.value();\n-\tfloat bRatio = bgAvg / frameContext.awb.bGain.value();\n+\trgbMeans /= frameContext.awb.gains.max(0.01);\n \n-\t/*\n-\t * And then we can simply invert the ratio to find the gain we should\n-\t * apply.\n-\t */\n-\tfloat rGain = 1 / rRatio;\n-\tfloat bGain = 1 / bRatio;\n+\treturn MaliC55AwbStats(rgbMeans);\n+}\n \n-\t/*\n-\t * Running at full speed, this algorithm results in oscillations in the\n-\t * colour balance. To remove those we dampen the speed at which it makes\n-\t * changes in gain, unless we're in the startup phase in which case we\n-\t * want to fix the miscolouring as quickly as possible.\n-\t */\n-\tfloat speed = frame < kNumStartupFrames ? 1.0f : 0.2f;\n-\trGain = speed * rGain + context.activeState.awb.rGain.value() * (1.0f - speed);\n-\tbGain = speed * bGain + context.activeState.awb.bGain.value() * (1.0f - speed);\n-\n-\tcontext.activeState.awb.rGain = rGain;\n-\tcontext.activeState.awb.bGain = bGain;\n-\n-\tmetadata.set(controls::ColourGains, {\n-\t\tframeContext.awb.rGain.value(),\n-\t\tframeContext.awb.bGain.value(),\n-\t});\n-\n-\tLOG(MaliC55Awb, Debug) << \"For frame number \" << frame << \": \"\n-\t\t<< \"Average R/G Ratio: \" << rgAvg\n-\t\t<< \", Average B/G Ratio: \" << bgAvg\n-\t\t<< \"\\nrGain applied to this frame: \" << frameContext.awb.rGain\n-\t\t<< \", bGain applied to this frame: \" << frameContext.awb.bGain\n-\t\t<< \"\\nrGain to apply: \" << context.activeState.awb.rGain\n-\t\t<< \", bGain to apply: \" << context.activeState.awb.bGain;\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::process\n+ */\n+void Awb::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n+\t\t  IPAFrameContext &frameContext, const mali_c55_stats_buffer *stats,\n+\t\t  ControlList &metadata)\n+{\n+\tMaliC55AwbStats awbStats = calculateRgbMeans(frameContext, stats);\n+\n+\tawbAlgo_.process(context.activeState.awb, frameContext.awb, awbStats,\n+\t\t\t kDefaultLux, metadata);\n }\n \n REGISTER_IPA_ALGORITHM(Awb, \"Awb\")\ndiff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h\nindex 683a62af263a..cc7ef583eafc 100644\n--- a/src/ipa/mali-c55/algorithms/awb.h\n+++ b/src/ipa/mali-c55/algorithms/awb.h\n@@ -2,24 +2,41 @@\n /*\n  * Copyright (C) 2024, Ideas on Board Oy\n  *\n- * Mali C55 grey world auto white balance algorithm\n+ * Mali C55 auto white balance algorithm\n  */\n \n+#pragma once\n+\n+#include <linux/media/arm/mali-c55-config.h>\n+\n+#include <libcamera/controls.h>\n+\n+#include \"libcamera/internal/value_node.h\"\n+\n+#include \"libipa/awb.h\"\n+#include \"libipa/fixedpoint.h\"\n+\n #include \"algorithm.h\"\n #include \"ipa_context.h\"\n+#include \"params.h\"\n \n namespace libcamera {\n \n namespace ipa::mali_c55::algorithms {\n \n+class MaliC55AwbStats;\n+\n class Awb : public Algorithm\n {\n public:\n-\tAwb();\n \t~Awb() = default;\n \n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t      const IPACameraSensorInfo &configInfo) override;\n+\tvoid queueRequest(IPAContext &context, const uint32_t frame,\n+\t\t\t  IPAFrameContext &frameContext,\n+\t\t\t  const ControlList &controls) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n \t\t     MaliC55Params *params) override;\n@@ -29,10 +46,11 @@ public:\n \t\t     ControlList &metadata) override;\n \n private:\n-\tvoid fillGainsParamBlock(MaliC55Params *params,\n-\t\t\t\t IPAContext &context,\n-\t\t\t\t IPAFrameContext &frameContext);\n-\tvoid fillConfigParamBlock(MaliC55Params *params);\n+\tvoid configAwbMeas(MaliC55Params *params);\n+\tMaliC55AwbStats calculateRgbMeans(const IPAFrameContext &frameContext,\n+\t\t\t\t\t  const mali_c55_stats_buffer *stats) const;\n+\n+\tAwbAlgorithm<UQ<4, 8>> awbAlgo_;\n };\n \n } /* namespace ipa::mali_c55::algorithms */\ndiff --git a/src/ipa/mali-c55/ipa_context.cpp b/src/ipa/mali-c55/ipa_context.cpp\nindex 1b203e2b2605..a1e4c39f3870 100644\n--- a/src/ipa/mali-c55/ipa_context.cpp\n+++ b/src/ipa/mali-c55/ipa_context.cpp\n@@ -96,6 +96,12 @@ namespace libcamera::ipa::mali_c55 {\n  *\n  * \\var IPAContext::frameContexts\n  * \\brief Ring buffer of per-frame contexts\n+ *\n+ * \\var IPAContext::ctrlMap\n+ * \\brief A ControlInfoMap::Map of controls populated by the algorithms\n+ *\n+ * \\var IPAContext::camHelper\n+ * \\brief The camera sensor helper\n  */\n \n } /* namespace libcamera::ipa::mali_c55 */\ndiff --git a/src/ipa/mali-c55/ipa_context.h b/src/ipa/mali-c55/ipa_context.h\nindex ac4b83773803..3d884ea17eb8 100644\n--- a/src/ipa/mali-c55/ipa_context.h\n+++ b/src/ipa/mali-c55/ipa_context.h\n@@ -12,8 +12,10 @@\n \n #include \"libcamera/internal/bayer_format.h\"\n \n+#include <libipa/camera_sensor_helper.h>\n #include <libipa/fc_queue.h>\n \n+#include \"libipa/awb.h\"\n #include \"libipa/fixedpoint.h\"\n \n namespace libcamera {\n@@ -29,6 +31,8 @@ struct IPASessionConfiguration {\n \t\tdouble maxAnalogueGain;\n \t} agc;\n \n+\tipa::awb::Session awb;\n+\n \tstruct {\n \t\tBayerFormat::Order bayerOrder;\n \t\tutils::Duration lineDuration;\n@@ -54,10 +58,7 @@ struct IPAActiveState {\n \t\tuint32_t temperatureK;\n \t} agc;\n \n-\tstruct {\n-\t\tUQ<4, 8> rGain;\n-\t\tUQ<4, 8> bGain;\n-\t} awb;\n+\tipa::awb::ActiveState awb;\n };\n \n struct IPAFrameContext : public FrameContext {\n@@ -67,10 +68,7 @@ struct IPAFrameContext : public FrameContext {\n \t\tUQ<5, 8> ispGain;\n \t} agc;\n \n-\tstruct {\n-\t\tUQ<4, 8> rGain;\n-\t\tUQ<4, 8> bGain;\n-\t} awb;\n+\tipa::awb::FrameContext awb;\n };\n \n struct IPAContext {\n@@ -85,6 +83,9 @@ struct IPAContext {\n \tFCQueue<IPAFrameContext> frameContexts;\n \n \tControlInfoMap::Map ctrlMap;\n+\n+\t/* Interface to the Camera Helper */\n+\tstd::unique_ptr<CameraSensorHelper> camHelper;\n };\n \n } /* namespace ipa::mali_c55 */\ndiff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp\nindex 1d3af0627fdb..c35cc10bea01 100644\n--- a/src/ipa/mali-c55/mali-c55.cpp\n+++ b/src/ipa/mali-c55/mali-c55.cpp\n@@ -77,9 +77,6 @@ private:\n \n \tControlInfoMap sensorControls_;\n \n-\t/* Interface to the Camera Helper */\n-\tstd::unique_ptr<CameraSensorHelper> camHelper_;\n-\n \t/* Local parameter storage */\n \tstruct IPAContext context_;\n };\n@@ -101,8 +98,8 @@ std::string IPAMaliC55::logPrefix() const\n int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig,\n \t\t     ControlInfoMap *ipaControls)\n {\n-\tcamHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n-\tif (!camHelper_) {\n+\tcontext_.camHelper = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n+\tif (!context_.camHelper) {\n \t\tLOG(IPAMaliC55, Error)\n \t\t\t<< \"Failed to create camera sensor helper for \"\n \t\t\t<< settings.sensorModel;\n@@ -145,10 +142,10 @@ void IPAMaliC55::setControls()\n \n \tif (activeState.agc.autoEnabled) {\n \t\texposure = activeState.agc.automatic.exposure;\n-\t\tgain = camHelper_->gainCode(activeState.agc.automatic.sensorGain);\n+\t\tgain = context_.camHelper->gainCode(activeState.agc.automatic.sensorGain);\n \t} else {\n \t\texposure = activeState.agc.manual.exposure;\n-\t\tgain = camHelper_->gainCode(activeState.agc.manual.sensorGain);\n+\t\tgain = context_.camHelper->gainCode(activeState.agc.manual.sensorGain);\n \t}\n \n \tControlList ctrls(sensorControls_);\n@@ -194,17 +191,17 @@ void IPAMaliC55::updateSessionConfiguration(const IPACameraSensorInfo &info,\n \tcontext_.configuration.agc.minShutterSpeed = minExposure * context_.configuration.sensor.lineDuration;\n \tcontext_.configuration.agc.maxShutterSpeed = maxExposure * context_.configuration.sensor.lineDuration;\n \tcontext_.configuration.agc.defaultExposure = defExposure;\n-\tcontext_.configuration.agc.minAnalogueGain = camHelper_->gain(minGain);\n-\tcontext_.configuration.agc.maxAnalogueGain = camHelper_->gain(maxGain);\n+\tcontext_.configuration.agc.minAnalogueGain = context_.camHelper->gain(minGain);\n+\tcontext_.configuration.agc.maxAnalogueGain = context_.camHelper->gain(maxGain);\n \n-\tif (camHelper_->blackLevel().has_value()) {\n+\tif (context_.camHelper->blackLevel().has_value()) {\n \t\t/*\n \t\t * The black level from CameraSensorHelper is a 16-bit value.\n \t\t * The Mali-C55 ISP expects 20-bit settings, so we shift it to\n \t\t * the appropriate width\n \t\t */\n \t\tcontext_.configuration.sensor.blackLevel =\n-\t\t\tcamHelper_->blackLevel().value() << 4;\n+\t\t\tcontext_.camHelper->blackLevel().value() << 4;\n \t}\n }\n \n@@ -255,9 +252,9 @@ void IPAMaliC55::updateControls(const IPACameraSensorInfo &sensorInfo,\n \n \t/* Compute the analogue gain limits. */\n \tconst ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;\n-\tfloat minGain = camHelper_->gain(v4l2Gain.min().get<int32_t>());\n-\tfloat maxGain = camHelper_->gain(v4l2Gain.max().get<int32_t>());\n-\tfloat defGain = camHelper_->gain(v4l2Gain.def().get<int32_t>());\n+\tfloat minGain = context_.camHelper->gain(v4l2Gain.min().get<int32_t>());\n+\tfloat maxGain = context_.camHelper->gain(v4l2Gain.max().get<int32_t>());\n+\tfloat defGain = context_.camHelper->gain(v4l2Gain.def().get<int32_t>());\n \tctrlMap[&controls::AnalogueGain] = ControlInfo(minGain, maxGain, defGain);\n \n \t/*\n@@ -355,7 +352,7 @@ void IPAMaliC55::processStats(unsigned int request, unsigned int bufferId,\n \tframeContext.agc.exposure =\n \t\tsensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n \tframeContext.agc.sensorGain =\n-\t\tcamHelper_->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());\n+\t\tcontext_.camHelper->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());\n \n \tControlList metadata(controls::controls);\n \n","prefixes":["02/11"]}