Show a patch.

GET /api/patches/24483/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 24483,
    "url": "https://patchwork.libcamera.org/api/patches/24483/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/24483/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/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": "<20250927180004.84620-6-hansg@kernel.org>",
    "date": "2025-09-27T18:00:03",
    "name": "[v3,5/6] libcamera: software_isp: Add valid flag to struct SwIspStats",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "3e70044534db7bc9d50a26a24d90eea5cc0236d6",
    "submitter": {
        "id": 239,
        "url": "https://patchwork.libcamera.org/api/people/239/?format=api",
        "name": "Hans de Goede",
        "email": "hansg@kernel.org"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/24483/mbox/",
    "series": [
        {
            "id": 5462,
            "url": "https://patchwork.libcamera.org/api/series/5462/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5462",
            "date": "2025-09-27T17:59:58",
            "name": "ipa: software_isp: AGC: Fox AGC oscillation bug",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/5462/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/24483/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/24483/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 11A13BDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 27 Sep 2025 18:00:27 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 68D786B5FE;\n\tSat, 27 Sep 2025 20:00:26 +0200 (CEST)",
            "from sea.source.kernel.org (sea.source.kernel.org [172.234.252.31])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3FF5A6B606\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 27 Sep 2025 20:00:16 +0200 (CEST)",
            "from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58])\n\tby sea.source.kernel.org (Postfix) with ESMTP id 1BDF3429C2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 27 Sep 2025 18:00:15 +0000 (UTC)",
            "by smtp.kernel.org (Postfix) with ESMTPSA id 42299C4CEF8;\n\tSat, 27 Sep 2025 18:00:14 +0000 (UTC)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=kernel.org header.i=@kernel.org\n\theader.b=\"HKi+qpa4\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1758996015;\n\tbh=QalXbPH57usXHlRd899QCqINP1MdGetO/KuHHwL0sJQ=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=HKi+qpa4sYLoZM3ncLktxgc/HXuseYBekA5ik9MisiWtT6uoVk8LqY+Qkh3wBVjdc\n\tauqJpmP7YVyELqTxURp4jX2ThBIAZy4meP5dxtlp0W6W1MKoaqcDVzrUxmPmG3hSHW\n\tC2yvVmgLCqoQuX8TNWyxM4f0SV6lpfV76/RRiCCWp4hDLTzg8eo3fb+vfc3VmBkZAs\n\tt6bFZ4gMO3zrI424Ff2wRnQRZhYuZ0BO/vieKXoqGzSaYZmDtUGXmtmFMwUv6gRRlh\n\tQupYylwADzDYEut9TKdAwbCjY8bCs2dPUiffo6AOmAuEmlqVDR0h16mzFDy61WGN/k\n\tO+qBZht9eg2Kw==",
        "From": "Hans de Goede <hansg@kernel.org>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Hans de Goede <hansg@kernel.org>",
        "Subject": "[PATCH v3 5/6] libcamera: software_isp: Add valid flag to struct\n\tSwIspStats",
        "Date": "Sat, 27 Sep 2025 20:00:03 +0200",
        "Message-ID": "<20250927180004.84620-6-hansg@kernel.org>",
        "X-Mailer": "git-send-email 2.51.0",
        "In-Reply-To": "<20250927180004.84620-1-hansg@kernel.org>",
        "References": "<20250927180004.84620-1-hansg@kernel.org>",
        "MIME-Version": "1.0",
        "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": "Generating statistics for every single frame is not really necessary.\n\nHowever a roundtrip through ipa_->processStats() still need to be done\nevery frame, even if there are no stats to make the IPA generate metadata\nfor every frame.\n\nAdd a valid flag to the statistics struct to let the IPA know when there\nare no statistics for the frame being processed and modify the IPA to\nonly generate metadata for frames without valid statistics.\n\nThis is a preparation patch for skipping statistics generation for some\nframes.\n\nSigned-off-by: Hans de Goede <hansg@kernel.org>\n---\nChanges in v3:\n- Drop if (!stats_->valid) early exit from IPASoftSimple::processStats()\n- Save last AGC calculated new gain and exposure values and re-use these\n  for frames without statistics, this avoids delayedCtrl history underruns\n- Improve SwIspStats.valid documentation\n\nChanges in v2:\n- This is a new patch in v2 of this series\n---\n .../libcamera/internal/software_isp/swisp_stats.h   |  5 +++++\n src/ipa/simple/algorithms/agc.cpp                   | 13 +++++++++++++\n src/ipa/simple/algorithms/awb.cpp                   |  3 +++\n src/ipa/simple/algorithms/blc.cpp                   |  3 +++\n src/ipa/simple/ipa_context.h                        |  4 ++++\n src/libcamera/software_isp/debayer_cpu.cpp          |  2 +-\n src/libcamera/software_isp/swstats_cpu.cpp          |  4 +++-\n src/libcamera/software_isp/swstats_cpu.h            |  2 +-\n 8 files changed, 33 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h\nindex ae11f112..3c986018 100644\n--- a/include/libcamera/internal/software_isp/swisp_stats.h\n+++ b/include/libcamera/internal/software_isp/swisp_stats.h\n@@ -20,6 +20,11 @@ namespace libcamera {\n  * wrap around.\n  */\n struct SwIspStats {\n+\t/**\n+\t * \\brief True if the statistics buffer contains valid data, false if\n+\t *        no statistics were generated for this frame\n+\t */\n+\tbool valid;\n \t/**\n \t * \\brief Holds the sum of all sampled red pixels\n \t */\ndiff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp\nindex 3471cc88..af660a03 100644\n--- a/src/ipa/simple/algorithms/agc.cpp\n+++ b/src/ipa/simple/algorithms/agc.cpp\n@@ -91,6 +91,9 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou\n \tagain = std::clamp(again, context.configuration.agc.againMin,\n \t\t\t   context.configuration.agc.againMax);\n \n+\tcontext.activeState.agc.exposure = exposure;\n+\tcontext.activeState.agc.again = again;\n+\n \tLOG(IPASoftExposure, Debug)\n \t\t<< \"exposureMSV \" << exposureMSV\n \t\t<< \" exp \" << exposure << \" again \" << again;\n@@ -107,6 +110,16 @@ void Agc::process(IPAContext &context,\n \tmetadata.set(controls::ExposureTime, exposureTime.get<std::micro>());\n \tmetadata.set(controls::AnalogueGain, frameContext.sensor.gain);\n \n+\tif (!stats->valid) {\n+\t\t/*\n+\t\t * Use the new exposure and gain values calculated the last time\n+\t\t * there were valid stats.\n+\t\t */\n+\t\tframeContext.sensor.exposure = context.activeState.agc.exposure;\n+\t\tframeContext.sensor.gain = context.activeState.agc.again;\n+\t\treturn;\n+\t}\n+\n \t/*\n \t * Calculate Mean Sample Value (MSV) according to formula from:\n \t * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf\ndiff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp\nindex cf567e89..ddd0b791 100644\n--- a/src/ipa/simple/algorithms/awb.cpp\n+++ b/src/ipa/simple/algorithms/awb.cpp\n@@ -61,6 +61,9 @@ void Awb::process(IPAContext &context,\n \t};\n \tmetadata.set(controls::ColourGains, mdGains);\n \n+\tif (!stats->valid)\n+\t\treturn;\n+\n \t/*\n \t * Black level must be subtracted to get the correct AWB ratios, they\n \t * would be off if they were computed from the whole brightness range\ndiff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp\nindex 8c1e9ed0..616da0ee 100644\n--- a/src/ipa/simple/algorithms/blc.cpp\n+++ b/src/ipa/simple/algorithms/blc.cpp\n@@ -60,6 +60,9 @@ void BlackLevel::process(IPAContext &context,\n \t};\n \tmetadata.set(controls::SensorBlackLevels, blackLevels);\n \n+\tif (!stats->valid)\n+\t\treturn;\n+\n \tif (context.configuration.black.level.has_value())\n \t\treturn;\n \ndiff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h\nindex 468fccab..441f2a73 100644\n--- a/src/ipa/simple/ipa_context.h\n+++ b/src/ipa/simple/ipa_context.h\n@@ -37,6 +37,10 @@ struct IPASessionConfiguration {\n };\n \n struct IPAActiveState {\n+\tstruct {\n+\t\tint32_t exposure;\n+\t\tdouble again;\n+\t} agc;\n \tstruct {\n \t\tuint8_t level;\n \t\tint32_t lastExposure;\ndiff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\nindex 2dc85e5e..bfa60888 100644\n--- a/src/libcamera/software_isp/debayer_cpu.cpp\n+++ b/src/libcamera/software_isp/debayer_cpu.cpp\n@@ -851,7 +851,7 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n \t *\n \t * \\todo Pass real bufferId once stats buffer passing is changed.\n \t */\n-\tstats_->finishFrame(frame, 0);\n+\tstats_->finishFrame(frame, 0, true);\n \toutputBufferReady.emit(output);\n \tinputBufferReady.emit(input);\n }\ndiff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\nindex 4b77b360..da91f912 100644\n--- a/src/libcamera/software_isp/swstats_cpu.cpp\n+++ b/src/libcamera/software_isp/swstats_cpu.cpp\n@@ -313,11 +313,13 @@ void SwStatsCpu::startFrame(void)\n  * \\brief Finish statistics calculation for the current frame\n  * \\param[in] frame The frame number\n  * \\param[in] bufferId ID of the statistics buffer\n+ * \\param[in] valid Indicates if the statistics for the current frame are valid\n  *\n  * This may only be called after a successful setWindow() call.\n  */\n-void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId)\n+void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId, bool valid)\n {\n+\tstats_.valid = valid;\n \t*sharedStats_ = stats_;\n \tstatsReady.emit(frame, bufferId);\n }\ndiff --git a/src/libcamera/software_isp/swstats_cpu.h b/src/libcamera/software_isp/swstats_cpu.h\nindex 26a2f462..6ac3c4de 100644\n--- a/src/libcamera/software_isp/swstats_cpu.h\n+++ b/src/libcamera/software_isp/swstats_cpu.h\n@@ -41,7 +41,7 @@ public:\n \tint configure(const StreamConfiguration &inputCfg);\n \tvoid setWindow(const Rectangle &window);\n \tvoid startFrame();\n-\tvoid finishFrame(uint32_t frame, uint32_t bufferId);\n+\tvoid finishFrame(uint32_t frame, uint32_t bufferId, bool valid);\n \n \tvoid processLine0(unsigned int y, const uint8_t *src[])\n \t{\n",
    "prefixes": [
        "v3",
        "5/6"
    ]
}