Show a patch.

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

{
    "id": 24484,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/24484/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/24484/",
    "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": "<20250927180004.84620-7-hansg@kernel.org>",
    "date": "2025-09-27T18:00:04",
    "name": "[v3,6/6] libcamera: software_isp: Run sw-statistics once every 4th frame",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "b94c880b315f47e67bba75170d200a84f38e666d",
    "submitter": {
        "id": 239,
        "url": "https://patchwork.libcamera.org/api/1.1/people/239/?format=api",
        "name": "Hans de Goede",
        "email": "hansg@kernel.org"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/24484/mbox/",
    "series": [
        {
            "id": 5462,
            "url": "https://patchwork.libcamera.org/api/1.1/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/24484/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/24484/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 418DFC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 27 Sep 2025 18:00:29 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B4E9C6B605;\n\tSat, 27 Sep 2025 20:00:28 +0200 (CEST)",
            "from tor.source.kernel.org (tor.source.kernel.org [172.105.4.254])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 507D26B611\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 27 Sep 2025 20:00:17 +0200 (CEST)",
            "from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58])\n\tby tor.source.kernel.org (Postfix) with ESMTP id 70383620A9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 27 Sep 2025 18:00:16 +0000 (UTC)",
            "by smtp.kernel.org (Postfix) with ESMTPSA id 6995DC113CF;\n\tSat, 27 Sep 2025 18:00:15 +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=\"gJwGsTak\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1758996016;\n\tbh=k+ifv+/UE1SUwzkMWeT6njsoiq5gwpUmHDTnph+s+dc=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=gJwGsTaka1f7d22tB5lcaxELWiE7TWC+Zj8NcCgBeMJxXm6ffhCZjDbw93R4gnYGM\n\ttWqy8f5gkHoxJ9zzf15+57biTfF7I2CumujWrH5hYQmTxuoUGC9dk2B76Zqz8k0D/I\n\tCWt/wwpkrVyNPtl8WBA4OE/Y7GJ97cv6muO/daKSrYjCkweM8/WBGWdPnY+bSwVFaz\n\tKsbOjxoO9DKGvU1uaZs+KvJhmdGDnpu+4QytvXu3HizjYrex2MLaQ1NJf/hcUB9Jbv\n\t7dhXQ3BmB441ah/fyjavXTueU6zFeb02ob8nXi2RDcRgAQesFgT+fm/GuZ3CFvZDpk\n\tfYIF81p7wrwjQ==",
        "From": "Hans de Goede <hansg@kernel.org>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Hans de Goede <hansg@kernel.org>",
        "Subject": "[PATCH v3 6/6] libcamera: software_isp: Run sw-statistics once every\n\t4th frame",
        "Date": "Sat, 27 Sep 2025 20:00:04 +0200",
        "Message-ID": "<20250927180004.84620-7-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": "Run sw-statistics once every 4th frame, instead of every frame. There are\n2 reasons for this:\n\n1. There really is no need to have statistics for every frame and only\ndoing this every 4th frame helps save some CPU time.\n\n2. The generic nature of the simple pipeline-handler, so no information\nabout possible CSI receiver frame-delays. In combination with the software\nISP often being used with sensors without sensor info in the sensor-helper\ncode, so no reliable control-delay information means that the software ISP\nis prone to AGC oscillation. Skipping statistics gathering also means\nskipping running the AGC algorithm slowing it down, avoiding this\noscillation.\n\nNote ideally the AGC oscillation problem would be fixed by adding sensor\nmetadata support all through the stack so that the exact gain and exposure\nused for a specific frame are reliably provided by the sensor metadata.\n\nSigned-off-by: Hans de Goede <hansg@kernel.org>\n---\nChanges in v2:\n- This is a new patch in v2 of this series\n---\n src/libcamera/software_isp/debayer_cpu.cpp | 25 +++++++++++++---------\n src/libcamera/software_isp/debayer_cpu.h   |  4 ++--\n src/libcamera/software_isp/swstats_cpu.cpp |  5 +++++\n src/libcamera/software_isp/swstats_cpu.h   |  3 +++\n 4 files changed, 25 insertions(+), 12 deletions(-)",
    "diff": "diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\nindex bfa60888..9010333e 100644\n--- a/src/libcamera/software_isp/debayer_cpu.cpp\n+++ b/src/libcamera/software_isp/debayer_cpu.cpp\n@@ -655,7 +655,7 @@ void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])\n \tlineBufferIndex_ = (lineBufferIndex_ + 1) % (patternHeight + 1);\n }\n \n-void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)\n+void DebayerCpu::process2(uint32_t frame, const uint8_t *src, uint8_t *dst)\n {\n \tunsigned int yEnd = window_.y + window_.height;\n \t/* Holds [0] previous- [1] current- [2] next-line */\n@@ -681,7 +681,8 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)\n \tfor (unsigned int y = window_.y; y < yEnd; y += 2) {\n \t\tshiftLinePointers(linePointers, src);\n \t\tmemcpyNextLine(linePointers);\n-\t\tstats_->processLine0(y, linePointers);\n+\t\tif (frame % SwStatsCpu::kStatPerNumFrames == 0)\n+\t\t\tstats_->processLine0(y, linePointers);\n \t\t(this->*debayer0_)(dst, linePointers);\n \t\tsrc += inputConfig_.stride;\n \t\tdst += outputConfig_.stride;\n@@ -696,7 +697,8 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)\n \tif (window_.y == 0) {\n \t\tshiftLinePointers(linePointers, src);\n \t\tmemcpyNextLine(linePointers);\n-\t\tstats_->processLine0(yEnd, linePointers);\n+\t\tif (frame % SwStatsCpu::kStatPerNumFrames == 0)\n+\t\t\tstats_->processLine0(yEnd, linePointers);\n \t\t(this->*debayer0_)(dst, linePointers);\n \t\tsrc += inputConfig_.stride;\n \t\tdst += outputConfig_.stride;\n@@ -710,7 +712,7 @@ void DebayerCpu::process2(const uint8_t *src, uint8_t *dst)\n \t}\n }\n \n-void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)\n+void DebayerCpu::process4(uint32_t frame, const uint8_t *src, uint8_t *dst)\n {\n \tconst unsigned int yEnd = window_.y + window_.height;\n \t/*\n@@ -733,7 +735,8 @@ void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)\n \tfor (unsigned int y = window_.y; y < yEnd; y += 4) {\n \t\tshiftLinePointers(linePointers, src);\n \t\tmemcpyNextLine(linePointers);\n-\t\tstats_->processLine0(y, linePointers);\n+\t\tif (frame % SwStatsCpu::kStatPerNumFrames == 0)\n+\t\t\tstats_->processLine0(y, linePointers);\n \t\t(this->*debayer0_)(dst, linePointers);\n \t\tsrc += inputConfig_.stride;\n \t\tdst += outputConfig_.stride;\n@@ -746,7 +749,8 @@ void DebayerCpu::process4(const uint8_t *src, uint8_t *dst)\n \n \t\tshiftLinePointers(linePointers, src);\n \t\tmemcpyNextLine(linePointers);\n-\t\tstats_->processLine2(y, linePointers);\n+\t\tif (frame % SwStatsCpu::kStatPerNumFrames == 0)\n+\t\t\tstats_->processLine2(y, linePointers);\n \t\t(this->*debayer2_)(dst, linePointers);\n \t\tsrc += inputConfig_.stride;\n \t\tdst += outputConfig_.stride;\n@@ -821,12 +825,13 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n \t\treturn;\n \t}\n \n-\tstats_->startFrame();\n+\tif (frame % SwStatsCpu::kStatPerNumFrames == 0)\n+\t\tstats_->startFrame();\n \n \tif (inputConfig_.patternSize.height == 2)\n-\t\tprocess2(in.planes()[0].data(), out.planes()[0].data());\n+\t\tprocess2(frame, in.planes()[0].data(), out.planes()[0].data());\n \telse\n-\t\tprocess4(in.planes()[0].data(), out.planes()[0].data());\n+\t\tprocess4(frame, in.planes()[0].data(), out.planes()[0].data());\n \n \tmetadata.planes()[0].bytesused = out.planes()[0].size();\n \n@@ -851,7 +856,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, true);\n+\tstats_->finishFrame(frame, 0, frame % SwStatsCpu::kStatPerNumFrames == 0);\n \toutputBufferReady.emit(output);\n \tinputBufferReady.emit(input);\n }\ndiff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\nindex 9d343e46..03e0d784 100644\n--- a/src/libcamera/software_isp/debayer_cpu.h\n+++ b/src/libcamera/software_isp/debayer_cpu.h\n@@ -133,8 +133,8 @@ private:\n \tvoid setupInputMemcpy(const uint8_t *linePointers[]);\n \tvoid shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src);\n \tvoid memcpyNextLine(const uint8_t *linePointers[]);\n-\tvoid process2(const uint8_t *src, uint8_t *dst);\n-\tvoid process4(const uint8_t *src, uint8_t *dst);\n+\tvoid process2(uint32_t frame, const uint8_t *src, uint8_t *dst);\n+\tvoid process4(uint32_t frame, const uint8_t *src, uint8_t *dst);\n \n \t/* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */\n \tstatic constexpr unsigned int kMaxLineBuffers = 5;\ndiff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\nindex da91f912..35ba0a46 100644\n--- a/src/libcamera/software_isp/swstats_cpu.cpp\n+++ b/src/libcamera/software_isp/swstats_cpu.cpp\n@@ -89,6 +89,11 @@ namespace libcamera {\n  * \\brief Signals that the statistics are ready\n  */\n \n+/**\n+ * \\var SwStatsCpu::kStatPerNumFrames\n+ * \\brief Run stats once every kStatPerNumFrames frames\n+ */\n+\n /**\n  * \\typedef SwStatsCpu::statsProcessFn\n  * \\brief Called when there is data to get statistics from\ndiff --git a/src/libcamera/software_isp/swstats_cpu.h b/src/libcamera/software_isp/swstats_cpu.h\nindex 6ac3c4de..ea0e6d5a 100644\n--- a/src/libcamera/software_isp/swstats_cpu.h\n+++ b/src/libcamera/software_isp/swstats_cpu.h\n@@ -32,6 +32,9 @@ public:\n \tSwStatsCpu();\n \t~SwStatsCpu() = default;\n \n+\t/* Run stats once every 4 frames */\n+\tstatic constexpr uint32_t kStatPerNumFrames = 4;\n+\n \tbool isValid() const { return sharedStats_.fd().isValid(); }\n \n \tconst SharedFD &getStatsFD() { return sharedStats_.fd(); }\n",
    "prefixes": [
        "v3",
        "6/6"
    ]
}