{"id":26857,"url":"https://patchwork.libcamera.org/api/patches/26857/?format=json","web_url":"https://patchwork.libcamera.org/patch/26857/","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":"<20260608150349.134371-15-mzamazal@redhat.com>","date":"2026-06-08T15:03:43","name":"[RFC,v4,14/17] libcamera: software_isp: Allocate statistics buffers","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"f6f66cc233dec77153219176133bbc9f9d60c0c6","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/?format=json","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/26857/mbox/","series":[{"id":5982,"url":"https://patchwork.libcamera.org/api/series/5982/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5982","date":"2026-06-08T15:03:29","name":"Software ISP: Share params and stats buffers","version":4,"mbox":"https://patchwork.libcamera.org/series/5982/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/26857/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/26857/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 09BD2C328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  8 Jun 2026 15:04:40 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A456B61F17;\n\tMon,  8 Jun 2026 17:04:39 +0200 (CEST)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.129.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8FD7961F17\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  8 Jun 2026 17:04:37 +0200 (CEST)","from mx-prod-mc-08.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-507-GN0p5DgMNfWq-7D05UGImg-1;\n\tMon, 08 Jun 2026 11:04:32 -0400","from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n\t(mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n\t[10.30.177.111])\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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTPS id 7E0F91801BDB; Mon,  8 Jun 2026 15:04:31 +0000 (UTC)","from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.48.51])\n\tby mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTP id 70998180058F; Mon,  8 Jun 2026 15:04:29 +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=\"HCXHLClf\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1780931076;\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=zWeLxjDraEA849kiojcF/8v79ehP0dh5ZDYofMM4Ksk=;\n\tb=HCXHLClfSTrnX28RF+tlJr7PKLd2W6OBon4yBpilMkHipJULBQc14rNRPaXRuzoisbZFs3\n\tJsjZzGPzdJwNUYC5DuXp4r6/eGSWXBsssdwgefRNKuhvC3eXFG0q4NoyhIJwo0yiUMxw0U\n\t4XdbGWdFdBHnjuRRBUAQP15M/uenfVY=","X-MC-Unique":"GN0p5DgMNfWq-7D05UGImg-1","X-Mimecast-MFC-AGG-ID":"GN0p5DgMNfWq-7D05UGImg_1780931071","From":"Milan Zamazal <mzamazal@redhat.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Milan Zamazal <mzamazal@redhat.com>, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?=\n\t<barnabas.pocze@ideasonboard.com>,  johannes.goede@oss.qualcomm.com","Subject":"[RFC PATCH v4 14/17] libcamera: software_isp: Allocate statistics\n\tbuffers","Date":"Mon,  8 Jun 2026 17:03:43 +0200","Message-ID":"<20260608150349.134371-15-mzamazal@redhat.com>","In-Reply-To":"<20260608150349.134371-1-mzamazal@redhat.com>","References":"<20260608150349.134371-1-mzamazal@redhat.com>","MIME-Version":"1.0","X-Scanned-By":"MIMEDefang 3.4.1 on 10.30.177.111","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"y-QcyD1bi5-qHSilh6r3vJJePVNjGj4AyLFQtk-ddx8_1780931071","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":"In order to be able to use multiple shared statistics buffers, we must\nallocate them.  They are allocated in SoftwareIsp and passed to\nSwIspStats.  This changes the previous behavior when the (single) shared\nstatistics buffer was created in SwIspStats.  Centralizing it to\nSoftwareIsp makes sharing multiple buffers with IPA easier.\n\nCurrently only one of the allocated buffers is used.  This will be\nchanged once the buffers are shared with IPA in a followup patch.\n\nSigned-off-by: Milan Zamazal <mzamazal@redhat.com>\n---\n .../internal/software_isp/software_isp.h      |  5 +++\n .../internal/software_isp/swstats_cpu.h       | 11 ++---\n src/libcamera/software_isp/software_isp.cpp   | 44 ++++++++++++++++---\n src/libcamera/software_isp/swstats_cpu.cpp    | 26 ++++++-----\n 4 files changed, 62 insertions(+), 24 deletions(-)","diff":"diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h\nindex 3e879c630..451596163 100644\n--- a/include/libcamera/internal/software_isp/software_isp.h\n+++ b/include/libcamera/internal/software_isp/software_isp.h\n@@ -33,6 +33,7 @@\n #include \"libcamera/internal/pipeline_handler.h\"\n #include \"libcamera/internal/shared_mem_object.h\"\n #include \"libcamera/internal/software_isp/debayer_params.h\"\n+#include \"libcamera/internal/software_isp/swstats_cpu.h\"\n \n namespace libcamera {\n \n@@ -91,6 +92,10 @@ public:\n private:\n \tvoid paramsBufferReady(const uint32_t paramsBufferId);\n \tbool allocateParamsBuffers(const unsigned int bufferCount);\n+\tstd::unique_ptr<SwStatsCpu> allocateStatsBuffers(\n+\t\tconst CameraManager &cm,\n+\t\tstd::map<uint32_t, SharedFD> &fdStats,\n+\t\tconst unsigned int bufferCount);\n \tvoid setSensorCtrls(const ControlList &sensorControls);\n \tvoid statsReady(uint32_t frame, const uint32_t statsBufferId);\n \tvoid statsProcessed(const uint32_t statsBufferId);\ndiff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h\nindex 4356eb826..7a66c9367 100644\n--- a/include/libcamera/internal/software_isp/swstats_cpu.h\n+++ b/include/libcamera/internal/software_isp/swstats_cpu.h\n@@ -1,7 +1,7 @@\n /* SPDX-License-Identifier: LGPL-2.1-or-later */\n /*\n  * Copyright (C) 2023, Linaro Ltd\n- * Copyright (C) 2023, Red Hat Inc.\n+ * Copyright (C) 2023-2026 Red Hat Inc.\n  *\n  * Authors:\n  * Hans de Goede <hdegoede@redhat.com>\n@@ -11,6 +11,7 @@\n \n #pragma once\n \n+#include <map>\n #include <stdint.h>\n #include <vector>\n \n@@ -35,7 +36,7 @@ struct StreamConfiguration;\n class SwStatsCpu\n {\n public:\n-\tSwStatsCpu(const CameraManager &cm);\n+\tSwStatsCpu(const CameraManager &cm, std::unique_ptr<std::map<uint32_t, SharedMemObject<SwIspStats>>> sharedStats);\n \t~SwStatsCpu() = default;\n \n \t/*\n@@ -46,9 +47,9 @@ public:\n \t */\n \tstatic constexpr uint32_t kStatPerNumFrames = 4;\n \n-\tbool isValid() const { return sharedStats_.fd().isValid(); }\n+\tbool isValid() const { return sharedStats_->begin()->second.fd().isValid(); }\n \n-\tconst SharedFD &getStatsFD() { return sharedStats_.fd(); }\n+\tconst SharedFD &getStatsFD() { return sharedStats_->begin()->second.fd(); }\n \n \tconst Size &patternSize() { return patternSize_; }\n \n@@ -122,7 +123,7 @@ private:\n \tunsigned int sumShift_;\n \n \tstd::vector<SwIspStats> stats_;\n-\tSharedMemObject<SwIspStats> sharedStats_;\n+\tstd::unique_ptr<std::map<uint32_t, SharedMemObject<SwIspStats>>> sharedStats_;\n \tBenchmark bench_;\n };\n \ndiff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp\nindex c44e035b8..c4da647e8 100644\n--- a/src/libcamera/software_isp/software_isp.cpp\n+++ b/src/libcamera/software_isp/software_isp.cpp\n@@ -14,6 +14,8 @@\n #include <sys/mman.h>\n #include <sys/types.h>\n #include <unistd.h>\n+#include <utility>\n+#include <vector>\n \n #include <libcamera/base/log.h>\n #include <libcamera/base/shared_fd.h>\n@@ -26,7 +28,10 @@\n \n #include \"libcamera/internal/bayer_format.h\"\n #include \"libcamera/internal/framebuffer.h\"\n+#include \"libcamera/internal/ipa_manager.h\"\n+#include \"libcamera/internal/shared_mem_object.h\"\n #include \"libcamera/internal/software_isp/debayer_params.h\"\n+#include \"libcamera/internal/software_isp/swisp_stats.h\"\n \n #include \"debayer_cpu.h\"\n #if HAVE_DEBAYER_EGL\n@@ -99,17 +104,15 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe,\n \n \tconst CameraManager &cm = *pipe->cameraManager();\n \n-\tauto stats = std::make_unique<SwStatsCpu>(cm);\n-\tif (!stats->isValid()) {\n-\t\tLOG(SoftwareIsp, Error) << \"Failed to create SwStatsCpu object\";\n-\t\treturn;\n-\t}\n-\tstats->statsReady.connect(this, &SoftwareIsp::statsReady);\n-\n \tstd::map<uint32_t, SharedFD> fdParams;\n \tfor (auto &[bufferId, item] : sharedParams_)\n \t\tfdParams[bufferId] = item.fd();\n \n+\tstd::map<uint32_t, SharedFD> fdStats;\n+\tauto stats = allocateStatsBuffers(cm, fdStats, bufferCount);\n+\tif (!stats)\n+\t\treturn;\n+\n #if HAVE_DEBAYER_EGL\n \tconst GlobalConfiguration &configuration = cm._d()->configuration();\n \tstd::optional<std::string> softISPMode = configuration.option<std::string>({ \"software_isp\", \"mode\" });\n@@ -203,6 +206,33 @@ bool SoftwareIsp::allocateParamsBuffers(const unsigned int bufferCount)\n \treturn true;\n }\n \n+std::unique_ptr<SwStatsCpu> SoftwareIsp::allocateStatsBuffers(\n+\tconst CameraManager &cm,\n+\tstd::map<uint32_t, SharedFD> &fdStats,\n+\tconst unsigned int bufferCount)\n+{\n+\tauto sharedStats = std::make_unique<std::map<uint32_t, SharedMemObject<SwIspStats>>>();\n+\tfor (unsigned int bufferId = 0; bufferId < bufferCount; bufferId++) {\n+\t\tauto shared = SharedMemObject<SwIspStats>(\"softIsp_stats\");\n+\t\tif (!shared) {\n+\t\t\tLOG(SoftwareIsp, Error) << \"Failed to create shared memory for statistics\";\n+\t\t\treturn nullptr;\n+\t\t}\n+\t\tif (!shared.fd().isValid()) {\n+\t\t\tLOG(SoftwareIsp, Error) << \"Invalid fd of shared statistics\";\n+\t\t\treturn nullptr;\n+\t\t}\n+\n+\t\tfdStats[bufferId] = shared.fd();\n+\t\tsharedStats->emplace(bufferId, std::move(shared));\n+\t}\n+\n+\tauto stats = std::make_unique<SwStatsCpu>(cm, std::move(sharedStats));\n+\tstats->statsReady.connect(this, &SoftwareIsp::statsReady);\n+\n+\treturn stats;\n+}\n+\n /**\n  * \\fn int SoftwareIsp::loadConfiguration([[maybe_unused]] const std::string &filename)\n  * \\brief Load a configuration from a file\ndiff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp\nindex a10535004..15eca4769 100644\n--- a/src/libcamera/software_isp/swstats_cpu.cpp\n+++ b/src/libcamera/software_isp/swstats_cpu.cpp\n@@ -11,6 +11,8 @@\n \n #include \"libcamera/internal/software_isp/swstats_cpu.h\"\n \n+#include <memory>\n+\n #include <libcamera/base/log.h>\n \n #include <libcamera/stream.h>\n@@ -36,9 +38,11 @@ namespace libcamera {\n  */\n \n /**\n- * \\fn SwStatsCpu::SwStatsCpu(const CameraManager &cm)\n+ * \\fn SwStatsCpu::SwStatsCpu(const CameraManager &cm, std::unique_ptr<std::map<uint32_t, SharedMemObject<SwIspStats>>> sharedStats)\n  * \\brief Construct a SwStatsCpu object\n  * \\param[in] cm The camera manager\n+ * \\param[in] sharedStats Mapping of statistics buffer ids to statistics\n+ *   instances that are shared with the IPA\n  *\n  * Creates a SwStatsCpu object and initialises shared memory for statistics\n  * exchange.\n@@ -159,12 +163,9 @@ namespace libcamera {\n \n LOG_DEFINE_CATEGORY(SwStatsCpu)\n \n-SwStatsCpu::SwStatsCpu(const CameraManager &cm)\n-\t: sharedStats_(\"softIsp_stats\"), bench_(cm, \"CPU stats\")\n+SwStatsCpu::SwStatsCpu(const CameraManager &cm, std::unique_ptr<std::map<uint32_t, SharedMemObject<SwIspStats>>> sharedStats)\n+\t: sharedStats_(std::move(sharedStats)), bench_(cm, \"CPU stats\")\n {\n-\tif (!sharedStats_)\n-\t\tLOG(SwStatsCpu, Error)\n-\t\t\t<< \"Failed to create shared memory for statistics\";\n }\n \n static constexpr unsigned int kRedYMul = 77; /* 0.299 * 256 */\n@@ -406,20 +407,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 \n \tif (valid) {\n-\t\tsharedStats_->sum_ = RGB<uint64_t>({ 0, 0, 0 });\n-\t\tsharedStats_->yHistogram.fill(0);\n+\t\tstats->sum_ = RGB<uint64_t>({ 0, 0, 0 });\n+\t\tstats->yHistogram.fill(0);\n \t\tfor (const auto &s : stats_) {\n-\t\t\tsharedStats_->sum_ += s.sum_;\n+\t\t\tstats->sum_ += s.sum_;\n \t\t\tfor (unsigned int j = 0; j < SwIspStats::kYHistogramSize; j++)\n-\t\t\t\tsharedStats_->yHistogram[j] += s.yHistogram[j];\n+\t\t\t\tstats->yHistogram[j] += s.yHistogram[j];\n \t\t}\n \n-\t\tsharedStats_->sum_ >>= sumShift_;\n+\t\tstats->sum_ >>= sumShift_;\n \t}\n \n-\tsharedStats_->valid = valid;\n+\tstats->valid = valid;\n \tstatsReady.emit(frame, statsBufferId);\n }\n \n","prefixes":["RFC","v4","14/17"]}