Show a patch.

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

{
    "id": 26840,
    "url": "https://patchwork.libcamera.org/api/patches/26840/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/26840/",
    "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": "<20260604095105.68798-21-mzamazal@redhat.com>",
    "date": "2026-06-04T09:51:02",
    "name": "[RFC,v3,16/17] libcamera: software_isp: Share statistics buffers with IPA",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "6c643af0e92b6842911cd4a25fde299b11f2ab9c",
    "submitter": {
        "id": 177,
        "url": "https://patchwork.libcamera.org/api/people/177/?format=api",
        "name": "Milan Zamazal",
        "email": "mzamazal@redhat.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/26840/mbox/",
    "series": [
        {
            "id": 5976,
            "url": "https://patchwork.libcamera.org/api/series/5976/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5976",
            "date": "2026-06-04T09:50:42",
            "name": "Software ISP: Share params and stats buffers",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/5976/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/26840/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/26840/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 A2F22C328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  4 Jun 2026 09:52:08 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5A2096374E;\n\tThu,  4 Jun 2026 11:52:08 +0200 (CEST)",
            "from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 238FF63282\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  4 Jun 2026 11:52:07 +0200 (CEST)",
            "from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com\n\t(ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97])\n\tby relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n\tcipher=TLS_AES_256_GCM_SHA384) id us-mta-322-HH73T_iWOCaCmv-zWXH0BQ-1;\n\tThu, 04 Jun 2026 05:52:01 -0400",
            "from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com\n\t(mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\tkey-exchange X25519 server-signature RSA-PSS (2048 bits)\n\tserver-digest SHA256) (No client certificate requested)\n\tby mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTPS id 597431800350; Thu,  4 Jun 2026 09:52:00 +0000 (UTC)",
            "from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.156])\n\tby mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTP id DC40C30001A1; Thu,  4 Jun 2026 09:51:58 +0000 (UTC)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"DKFdrE9i\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1780566726;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=BP/CI+Knz7wRLzbuGBA2ELDt8uLx0ag7k7fD9ZXPSE4=;\n\tb=DKFdrE9il2Y01leDVR7yrFPikvR7Qka741LcD41bfPNLZ1X0gMvWKiexLx3+rQbtTtLO4S\n\tXlP7mPrO30BwevGSQK0G+Or8gD2wY2Q7quG38j26V21XAAOjPOVFlUfVpDvfD3JCq58D2Q\n\tW4JWb4+HDWvxT+CWM52NtK+kKilXj7g=",
        "X-MC-Unique": "HH73T_iWOCaCmv-zWXH0BQ-1",
        "X-Mimecast-MFC-AGG-ID": "HH73T_iWOCaCmv-zWXH0BQ_1780566720",
        "From": "Milan Zamazal <mzamazal@redhat.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Milan Zamazal <mzamazal@redhat.com>, =?utf-8?b?QmFybmFiw6FzIFDFkWN6?=\n\t=?utf-8?q?e?= <barnabas.pocze@ideasonboard.com>,\n\tjohannes.goede@oss.qualcomm.com",
        "Subject": "[RFC PATCH v3 16/17] libcamera: software_isp: Share statistics\n\tbuffers with IPA",
        "Date": "Thu,  4 Jun 2026 11:51:02 +0200",
        "Message-ID": "<20260604095105.68798-21-mzamazal@redhat.com>",
        "In-Reply-To": "<20260604095105.68798-1-mzamazal@redhat.com>",
        "References": "<20260604095105.68798-1-mzamazal@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.4",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-MFC-PROC-ID": "qYXt8pm0NZ8OEn2gnnZopTQE9mH6pVf7ODnwoweGqlM_1780566720",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Transfer-Encoding": "8bit",
        "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true",
        "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": "The last step to complete statistics buffer sharing is to pass all the\nallocated statistics buffers to the IPA and refer to them using their ids.\nThis allows to remove the buffer copying in SwStatsCpu::finishFrame.\n\nWe can also remove now the methods that served for handling the former\nsingle buffer shared between debayering and IPA.\n\nSigned-off-by: Milan Zamazal <mzamazal@redhat.com>\n---\n .../internal/software_isp/swstats_cpu.h       |  5 +--\n include/libcamera/ipa/soft.mojom              |  2 +-\n src/ipa/simple/soft_simple.cpp                | 42 +++++++++----------\n src/libcamera/software_isp/debayer.cpp        | 10 -----\n src/libcamera/software_isp/debayer.h          |  2 -\n src/libcamera/software_isp/debayer_cpu.h      |  1 -\n src/libcamera/software_isp/debayer_egl.h      |  2 -\n src/libcamera/software_isp/software_isp.cpp   |  2 +-\n src/libcamera/software_isp/swstats_cpu.cpp    | 28 ++++---------\n 9 files changed, 31 insertions(+), 63 deletions(-)",
    "diff": "diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h\nindex cf2f88fcb..74d70bd20 100644\n--- a/include/libcamera/internal/software_isp/swstats_cpu.h\n+++ b/include/libcamera/internal/software_isp/swstats_cpu.h\n@@ -12,6 +12,7 @@\n #pragma once\n \n #include <map>\n+#include <memory>\n #include <stdint.h>\n #include <vector>\n \n@@ -47,10 +48,6 @@ public:\n \t */\n \tstatic constexpr uint32_t kStatPerNumFrames = 4;\n \n-\tbool isValid() const { return sharedStats_->begin()->second.fd().isValid(); }\n-\n-\tconst SharedFD &getStatsFD() { return sharedStats_->begin()->second.fd(); }\n-\n \tconst Size &patternSize() { return patternSize_; }\n \n \tint configure(const StreamConfiguration &inputCfg, unsigned int statsBufferCount = 1);\ndiff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom\nindex c2c5fe382..a3739de00 100644\n--- a/include/libcamera/ipa/soft.mojom\n+++ b/include/libcamera/ipa/soft.mojom\n@@ -14,7 +14,7 @@ struct IPAConfigInfo {\n \n interface IPASoftInterface {\n \tinit(libcamera.IPASettings settings,\n-\t     libcamera.SharedFD fdStats,\n+\t     map<uint32, libcamera.SharedFD> fdStats,\n \t     map<uint32, libcamera.SharedFD> fdParams,\n \t     libcamera.IPACameraSensorInfo sensorInfo,\n \t     libcamera.ControlInfoMap sensorControls)\ndiff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\nindex ded75a970..ff585b75e 100644\n--- a/src/ipa/simple/soft_simple.cpp\n+++ b/src/ipa/simple/soft_simple.cpp\n@@ -52,7 +52,7 @@ public:\n \t~IPASoftSimple();\n \n \tint init(const IPASettings &settings,\n-\t\t const SharedFD &fdStats,\n+\t\t const std::map<uint32_t, SharedFD> &fdStats,\n \t\t const std::map<uint32_t, SharedFD> &fdParams,\n \t\t const IPACameraSensorInfo &sensorInfo,\n \t\t const ControlInfoMap &sensorControls,\n@@ -76,7 +76,7 @@ private:\n \tvoid updateExposure(double exposureMSV);\n \n \tstd::map<unsigned int, DebayerParams *> paramsBuffers_;\n-\tSwIspStats *stats_;\n+\tstd::map<unsigned int, SwIspStats *> statsBuffers_;\n \tstd::unique_ptr<CameraSensorHelper> camHelper_;\n \tControlInfoMap sensorInfoMap_;\n \n@@ -86,14 +86,14 @@ private:\n \n IPASoftSimple::~IPASoftSimple()\n {\n-\tif (stats_)\n-\t\tmunmap(stats_, sizeof(SwIspStats));\n+\tfor (auto &item : statsBuffers_)\n+\t\tmunmap(item.second, sizeof(SwIspStats));\n \tfor (auto &item : paramsBuffers_)\n \t\tmunmap(item.second, sizeof(DebayerParams));\n }\n \n int IPASoftSimple::init(const IPASettings &settings,\n-\t\t\tconst SharedFD &fdStats,\n+\t\t\tconst std::map<uint32_t, SharedFD> &fdStats,\n \t\t\tconst std::map<uint32_t, SharedFD> &fdParams,\n \t\t\tconst IPACameraSensorInfo &sensorInfo,\n \t\t\tconst ControlInfoMap &sensorControls,\n@@ -137,11 +137,20 @@ int IPASoftSimple::init(const IPASettings &settings,\n \t\treturn ret;\n \n \t*ccmEnabled = context_.ccmEnabled;\n-\tstats_ = nullptr;\n+\tfor (auto &[bufferId, sharedFd] : fdStats) {\n+\t\tif (!sharedFd.isValid()) {\n+\t\t\tLOG(IPASoft, Error) << \"Invalid Statistics handle\";\n+\t\t\treturn -ENODEV;\n+\t\t}\n+\n+\t\tvoid *mem = mmap(nullptr, sizeof(SwIspStats), PROT_READ,\n+\t\t\t\t MAP_SHARED, sharedFd.get(), 0);\n+\t\tif (mem == MAP_FAILED) {\n+\t\t\tLOG(IPASoft, Error) << \"Unable to map Statistics\";\n+\t\t\treturn -errno;\n+\t\t}\n \n-\tif (!fdStats.isValid()) {\n-\t\tLOG(IPASoft, Error) << \"Invalid Statistics handle\";\n-\t\treturn -ENODEV;\n+\t\tstatsBuffers_[bufferId] = static_cast<SwIspStats *>(mem);\n \t}\n \n \tfor (auto &[bufferId, sharedFd] : fdParams) {\n@@ -166,17 +175,6 @@ int IPASoftSimple::init(const IPASettings &settings,\n \t\tparamsBuffers_[bufferId] = params;\n \t}\n \n-\t{\n-\t\tvoid *mem = mmap(nullptr, sizeof(SwIspStats), PROT_READ,\n-\t\t\t\t MAP_SHARED, fdStats.get(), 0);\n-\t\tif (mem == MAP_FAILED) {\n-\t\t\tLOG(IPASoft, Error) << \"Unable to map Statistics\";\n-\t\t\treturn -errno;\n-\t\t}\n-\n-\t\tstats_ = static_cast<SwIspStats *>(mem);\n-\t}\n-\n \tControlInfoMap::Map ctrlMap = context_.ctrlMap;\n \t*ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls);\n \n@@ -303,6 +301,8 @@ void IPASoftSimple::processStats(const uint32_t frame,\n {\n \tIPAFrameContext &frameContext = context_.frameContexts.get(frame);\n \n+\tconst SwIspStats *stats = statsBuffers_.at(statsBufferId);\n+\n \tframeContext.sensor.exposure =\n \t\tsensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n \tint32_t again = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();\n@@ -310,7 +310,7 @@ void IPASoftSimple::processStats(const uint32_t frame,\n \n \tControlList metadata(controls::controls);\n \tfor (const auto &algo : algorithms())\n-\t\talgo->process(context_, frame, frameContext, stats_, metadata);\n+\t\talgo->process(context_, frame, frameContext, stats, metadata);\n \tmetadataReady.emit(frame, metadata);\n \tstatsProcessed.emit(statsBufferId);\n \ndiff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp\nindex 341930e5b..533311200 100644\n--- a/src/libcamera/software_isp/debayer.cpp\n+++ b/src/libcamera/software_isp/debayer.cpp\n@@ -138,16 +138,6 @@ Debayer::~Debayer()\n  * \\return The valid size ranges or an empty range if there are none\n  */\n \n-/**\n- * \\fn const SharedFD &Debayer::getStatsFD()\n- * \\brief Get the file descriptor for the statistics\n- *\n- * This file descriptor provides access to the output statistics buffer\n- * associated with the current debayering process.\n- *\n- * \\return The file descriptor pointing to the statistics data\n- */\n-\n /**\n  * \\fn unsigned int Debayer::frameSize()\n  * \\brief Get the output frame size\ndiff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h\nindex 259261b1a..b0a1ed151 100644\n--- a/src/libcamera/software_isp/debayer.h\n+++ b/src/libcamera/software_isp/debayer.h\n@@ -57,8 +57,6 @@ public:\n \n \tvirtual SizeRange sizes(PixelFormat inputFormat, const Size &inputSize) = 0;\n \n-\tvirtual const SharedFD &getStatsFD() = 0;\n-\n \tunsigned int frameSize() { return outputConfig_.frameSize; }\n \n \tSignal<FrameBuffer *> inputBufferReady;\ndiff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\nindex 37e45e9ea..62b43c4a9 100644\n--- a/src/libcamera/software_isp/debayer_cpu.h\n+++ b/src/libcamera/software_isp/debayer_cpu.h\n@@ -53,7 +53,6 @@ public:\n \tint start() override;\n \tvoid stop() override;\n \tSizeRange sizes(PixelFormat inputFormat, const Size &inputSize) override;\n-\tconst SharedFD &getStatsFD() override { return stats_->getStatsFD(); }\n \n private:\n \tfriend class DebayerCpuThread;\ndiff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h\nindex 36c856c10..d7d1bc618 100644\n--- a/src/libcamera/software_isp/debayer_egl.h\n+++ b/src/libcamera/software_isp/debayer_egl.h\n@@ -61,8 +61,6 @@ public:\n \tint start() override;\n \tvoid stop() override;\n \n-\tconst SharedFD &getStatsFD() override { return stats_->getStatsFD(); }\n-\n \tSizeRange sizes(PixelFormat inputFormat, const Size &inputSize) override;\n \n private:\ndiff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp\nindex 2a019e6bc..020226585 100644\n--- a/src/libcamera/software_isp/software_isp.cpp\n+++ b/src/libcamera/software_isp/software_isp.cpp\n@@ -162,7 +162,7 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe,\n \t}\n \n \tret = ipa_->init(IPASettings{ ipaTuningFile, sensor->model() },\n-\t\t\t debayer_->getStatsFD(),\n+\t\t\t fdStats,\n \t\t\t fdParams,\n \t\t\t sensorInfo,\n \t\t\t sensor->controls(),\ndiff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\nindex e6beb9692..0269e8249 100644\n--- a/src/libcamera/software_isp/swstats_cpu.cpp\n+++ b/src/libcamera/software_isp/swstats_cpu.cpp\n@@ -48,20 +48,6 @@ namespace libcamera {\n  * exchange.\n  */\n \n-/**\n- * \\fn bool SwStatsCpu::isValid() const\n- * \\brief Gets whether the statistics object is valid\n- *\n- * \\return True if it's valid, false otherwise\n- */\n-\n-/**\n- * \\fn const SharedFD &SwStatsCpu::getStatsFD()\n- * \\brief Get the file descriptor for the statistics\n- *\n- * \\return The file descriptor\n- */\n-\n /**\n  * \\fn const Size &SwStatsCpu::patternSize()\n  * \\brief Get the pattern size\n@@ -355,21 +341,21 @@ void SwStatsCpu::finishFrame(uint32_t frame,\n \t\t\t     const uint32_t statsBufferId)\n {\n \tbool valid = frame % kStatPerNumFrames == 0;\n-\tSharedMemObject<SwIspStats> &stats = sharedStats_->at(statsBufferId);\n+\tSharedMemObject<SwIspStats> &shared = sharedStats_->at(statsBufferId);\n \n \tif (valid) {\n-\t\tstats->sum_ = RGB<uint64_t>({ 0, 0, 0 });\n-\t\tstats->yHistogram.fill(0);\n+\t\tshared->sum_ = RGB<uint64_t>({ 0, 0, 0 });\n+\t\tshared->yHistogram.fill(0);\n \t\tfor (const auto &s : stats_) {\n-\t\t\tstats->sum_ += s.sum_;\n+\t\t\tshared->sum_ += s.sum_;\n \t\t\tfor (unsigned int j = 0; j < SwIspStats::kYHistogramSize; j++)\n-\t\t\t\tstats->yHistogram[j] += s.yHistogram[j];\n+\t\t\t\tshared->yHistogram[j] += s.yHistogram[j];\n \t\t}\n \n-\t\tstats->sum_ >>= sumShift_;\n+\t\tshared->sum_ >>= sumShift_;\n \t}\n \n-\tstats->valid = valid;\n+\tshared->valid = valid;\n \tstatsReady.emit(frame, statsBufferId);\n }\n \n",
    "prefixes": [
        "RFC",
        "v3",
        "16/17"
    ]
}