From patchwork Tue Mar 3 11:17:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 26244 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id EFCE4C0DA4 for ; Tue, 3 Mar 2026 11:17:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6CFBA62381; Tue, 3 Mar 2026 12:17:52 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=qualcomm.com header.i=@qualcomm.com header.b="fPJ/7AT2"; dkim=pass (2048-bit key; unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="fl96v1et"; dkim-atps=neutral Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E7D7D621CE for ; Tue, 3 Mar 2026 12:17:49 +0100 (CET) Received: from pps.filterd (m0279865.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6239nGFA3349612 for ; Tue, 3 Mar 2026 11:17:48 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=qcppdkim1; bh=Q9h8k+AeUz8 t+HWwjwjc7na33VwWe6woYgARNnc/Hyc=; b=fPJ/7AT2TNsbyqs5hK8otxmwwh7 x8Mwc3Dt4Y/h7mD6Nqk+NSgF0DM34CVcneqxYr2+pqNXFFM8br9NHbBwjlmPHana rAXeJbRBBR1FNFEzWbZMdwpThutbuIutLVGL8d607kU8bOKZaGCSuvV8eVq4syzq nZHdJCGF6Ph9OmtqNbS9HbXMTRtugYg5N3m+tvjg+7hd5uODkYhbKUJtmeJrCZZ4 ZA8ySKj2+Bv/QJ11LTs10IMetvc7StnNGlr0CjioAU9o/qAG2vWmaEtwGJufomCQ t/0dZ+tv/1U/qY+flDYLjxMsHbHgQ/Z0s3cVTPJYP/G9HVw2AkW8sjlJgvw== Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4cnhxsahwt-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 03 Mar 2026 11:17:48 +0000 (GMT) Received: by mail-qk1-f199.google.com with SMTP id af79cd13be357-8cb3b6b37d8so3482211785a.3 for ; Tue, 03 Mar 2026 03:17:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1772536667; x=1773141467; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Q9h8k+AeUz8t+HWwjwjc7na33VwWe6woYgARNnc/Hyc=; b=fl96v1etIJz2cbdNMd8tqB1fw3xfaC3l/TDqQzJ1pB9p9m5Gv+MSg/GlBXYzTwW+XU EP3FXHvr0GTBNsWofIpGg+eieu7dMsxJNQxDzAQlHq3j7PJgmlJewoaAn0decSTvlq0A mPsPmW+8wbb2oYeQKSLO2F9mew6kKGiAezbNeOhrtBlLIH9xcbfofxUMJvmoe2Ybk8vk I8y8f5cFMZDiCKRCK0vt4azPb2A2kZ7MsszRS9HI508+7FjNNdfIWTHsc0pQCcGNCdCE ckqkoVjpJA4fR7uJc+1aPcm8+iP06U2Qlza27o7L3rgTyz/muNWVNwX/p4ijamkVIBHf b8ZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772536667; x=1773141467; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Q9h8k+AeUz8t+HWwjwjc7na33VwWe6woYgARNnc/Hyc=; b=vzb9RoTkNx+1L30386syyc51lz2F6f/znabk8yhpAl5bFG5Q2JLrt6WcgPC8I+bduJ cgiPsZFuivdeGQUEM014FYzFCd0fJwHuz+sYfJE3UWFJ+1g5fg2MTUIZn9kEXCwZRsNS GxOj6F89JChgm6WD2mHTv5zWri6/Eehus9xLj8CCkg+MKOgmXfn3Mnxa6EjsYci1ptmc GaO56y8vnijZ9avPC0wI6BxzWFrv3kAcHx9JxJO/fyus6PVqlJjAluqnPpPa/XBC92Jc IazGuwKcGbx7tCUdZryLwBqFZNDEcjBHXBR51i5yUBCn2Cmc3+UABVVg/Piy7nQ/Mn9v Kx2A== X-Gm-Message-State: AOJu0YwSKWhTgNLM3NxOZyHIx0KtbLWc7hw6hVnOteb/L6yzAydr08rQ xnAw2vFWSJrHvo5VY9HnbEvNjCyGlcM4+trDKD1BSBJDI37ZBFQmcjPsBHA8l09TVBeUq188NJL TlFewAiiiAqM6EkfCzu0NlZp6sX6NToQ+prRKnWmZZaNH9PIPJDkp/i96ABdv/eHdKmQhXq5aiY Tiv7rq707W X-Gm-Gg: ATEYQzxiXPzb6y9vMlkHQ49Bi30tNeusLIrLCmrT5zGul+7+swETCRJH/bamMFyV/23 iZvqV+vSxe1P2AKfjmMimr1B0FUhjMQTiWj+d0Ig8KhS4Rr8VYPU8q5iccr+EP8NKPtHKLqm+oY hGzX6QV4amxarXEaPxZJiDNEIdQYPfa+w4RmFhzRaeXi8H1p/xUFq6wc2UFsQ44jIFgEmorvORP Q+pooc9mFObLJ9PaxRYzNqBMiFrZj+iAimZ9pL6HR6h9ZLkTpJgZv4N3d0N94k5bYpkJQuYJCnV K3j7SCIUWwX3ekSgscG+zOOk0szZm7LPdCkv+h4cTOieMq/+dtXwzXetbd3oENjlzWLT/uggtMt YQemuh1G4mjIN0lde3iaaMqa4AMj0LnQFdm4e+1nVYFeZnFoGZg6i3mE/3owO/igcJtRDx5XlJM zOekw7dFmifxHQ87dbTQb4WRsXxoBZUSv8xw== X-Received: by 2002:a05:620a:2806:b0:8c9:eb6a:1659 with SMTP id af79cd13be357-8cbc8d671b4mr1562242785a.9.1772536667042; Tue, 03 Mar 2026 03:17:47 -0800 (PST) X-Received: by 2002:a05:620a:2806:b0:8c9:eb6a:1659 with SMTP id af79cd13be357-8cbc8d671b4mr1562239885a.9.1772536666515; Tue, 03 Mar 2026 03:17:46 -0800 (PST) Received: from t14s (2001-1c00-0c32-7800-beb3-9058-f5fe-3f2e.cable.dynamic.v6.ziggo.nl. [2001:1c00:c32:7800:beb3:9058:f5fe:3f2e]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-66003479178sm2958144a12.9.2026.03.03.03.17.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2026 03:17:44 -0800 (PST) From: Hans de Goede To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Hans de Goede Subject: [PATCH v4 1/4] software_isp: swstats_cpu: Prepare for multi-threading support Date: Tue, 3 Mar 2026 12:17:38 +0100 Message-ID: <20260303111741.17417-2-johannes.goede@oss.qualcomm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260303111741.17417-1-johannes.goede@oss.qualcomm.com> References: <20260303111741.17417-1-johannes.goede@oss.qualcomm.com> MIME-Version: 1.0 X-Proofpoint-ORIG-GUID: Q5asM91nASRsUa9nAb8bn1KAq6uwS_ze X-Authority-Analysis: v=2.4 cv=dfmNHHXe c=1 sm=1 tr=0 ts=69a6c35c cx=c_pps a=HLyN3IcIa5EE8TELMZ618Q==:117 a=xqWC_Br6kY4A:10 a=Yq5XynenixoA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=Um2Pa8k9VHT-vaBCBUpS:22 a=20KFwNOVAAAA:8 a=EUspDBNiAAAA:8 a=VvikW9XIONpR7lsxkDIA:9 a=bTQJ7kPSJx9SKPbeHEYW:22 X-Proofpoint-GUID: Q5asM91nASRsUa9nAb8bn1KAq6uwS_ze X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMzAzMDA4NiBTYWx0ZWRfXzldDBOH+uFGD vix6WvVJdlOwBS63sycOhVsIX60nCgU9TePsD/a23RGEYKvRnCcQLf0x3E0+n6fOMyI/jxX6d1k c2yYg+50a+ISgg1+TlY6LvuVLZbVkzx/qpWJ2WGqA1SuyO9dOF+qFTuXa9QwtzqZSOcCRXHaYgW Z4tqZpJ5lVqyuSy98SXgr2WKvqd6QHSj6Qu+Y3U3ZhovU38DJzD512wWjDv3eKP6gDY6gjPD6Do VTSsLX/JCpHF0+rH0mwCNexJ0Zvr8BjzU/iEjVtEDCSE2jiNJvFj47QIwtMzkd5RTRKX6dFK3nr v3litK4DjTMdGSkqkiQphbv3q/Km8k067jK0ZRHQR7MRygOe/mf9SJmvXtgEWbyOkGTq53qGciA QzWIaOf4cBZE0PadfeMB0V/Ru2sgPfHxjQIJ7cUbOo4XK7pbng0Y0UDNgrvY0rmQHzNYyCGVdDs 5nEx/2v0j+hKVp8upHw== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293, Aquarius:18.0.1121, Hydra:6.1.51, FMLib:17.12.100.49 definitions=2026-03-02_05,2026-03-03_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 bulkscore=0 impostorscore=0 phishscore=0 clxscore=1015 spamscore=0 adultscore=0 suspectscore=0 lowpriorityscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2602130000 definitions=main-2603030086 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Make the storage used to accumulate the RGB sums and the Y histogram value a vector of SwIspStats objects instead of a single object so that when using multi-threading every thread can use its own storage to collect intermediate stats to avoid cache-line bouncing. Benchmarking with the GPU-ISP which does separate swstats benchmarking, on the Arduino Uno-Q which has a weak CPU which is good for performance testing, shows 20ms to generate stats for a 3272x2464 frame both before and after this change. Reviewed-by: Milan Zamazal Signed-off-by: Hans de Goede --- Changes in v4: - Use const in for (const auto &s : stats_) {} in SwStatsCpu::finishFrame() - Add Milan's Reviewed-by Changes in v3: - Use for (auto &s : stats_) {} Changes in v2: - Move the allocation of the vector of SwIspStats objects to inside the SwStatsCpu class, controlled by a configure() arguments instead of making the caller allocate the objects --- .../internal/software_isp/swstats_cpu.h | 25 ++++----- src/libcamera/software_isp/swstats_cpu.cpp | 54 +++++++++++++------ 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h index 64b3e23f5..feee92f99 100644 --- a/include/libcamera/internal/software_isp/swstats_cpu.h +++ b/include/libcamera/internal/software_isp/swstats_cpu.h @@ -12,6 +12,7 @@ #pragma once #include +#include #include @@ -51,13 +52,13 @@ public: const Size &patternSize() { return patternSize_; } - int configure(const StreamConfiguration &inputCfg); + int configure(const StreamConfiguration &inputCfg, unsigned int statsBufferCount = 1); void setWindow(const Rectangle &window); void startFrame(uint32_t frame); void finishFrame(uint32_t frame, uint32_t bufferId); void processFrame(uint32_t frame, uint32_t bufferId, FrameBuffer *input); - void processLine0(uint32_t frame, unsigned int y, const uint8_t *src[]) + void processLine0(uint32_t frame, unsigned int y, const uint8_t *src[], unsigned int statsBufferIndex = 0) { if (frame % kStatPerNumFrames) return; @@ -66,10 +67,10 @@ public: y >= (window_.y + window_.height)) return; - (this->*stats0_)(src); + (this->*stats0_)(src, stats_[statsBufferIndex]); } - void processLine2(uint32_t frame, unsigned int y, const uint8_t *src[]) + void processLine2(uint32_t frame, unsigned int y, const uint8_t *src[], unsigned int statsBufferIndex = 0) { if (frame % kStatPerNumFrames) return; @@ -78,25 +79,25 @@ public: y >= (window_.y + window_.height)) return; - (this->*stats2_)(src); + (this->*stats2_)(src, stats_[statsBufferIndex]); } Signal statsReady; private: - using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[]); + using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[], SwIspStats &stats); using processFrameFn = void (SwStatsCpu::*)(MappedFrameBuffer &in); int setupStandardBayerOrder(BayerFormat::Order order); /* Bayer 8 bpp unpacked */ - void statsBGGR8Line0(const uint8_t *src[]); + void statsBGGR8Line0(const uint8_t *src[], SwIspStats &stats); /* Bayer 10 bpp unpacked */ - void statsBGGR10Line0(const uint8_t *src[]); + void statsBGGR10Line0(const uint8_t *src[], SwIspStats &stats); /* Bayer 12 bpp unpacked */ - void statsBGGR12Line0(const uint8_t *src[]); + void statsBGGR12Line0(const uint8_t *src[], SwIspStats &stats); /* Bayer 10 bpp packed */ - void statsBGGR10PLine0(const uint8_t *src[]); - void statsGBRG10PLine0(const uint8_t *src[]); + void statsBGGR10PLine0(const uint8_t *src[], SwIspStats &stats); + void statsGBRG10PLine0(const uint8_t *src[], SwIspStats &stats); void processBayerFrame2(MappedFrameBuffer &in); @@ -116,8 +117,8 @@ private: unsigned int xShift_; unsigned int stride_; + std::vector stats_; SharedMemObject sharedStats_; - SwIspStats stats_; Benchmark bench_; }; diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index 1cedcfbc1..ded0dcf1a 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -74,11 +74,12 @@ namespace libcamera { */ /** - * \fn void SwStatsCpu::processLine0(uint32_t frame, unsigned int y, const uint8_t *src[]) + * \fn void SwStatsCpu::processLine0(uint32_t frame, unsigned int y, const uint8_t *src[], unsigned int statsBufferIndex = 0) * \brief Process line 0 * \param[in] frame The frame number * \param[in] y The y coordinate. * \param[in] src The input data. + * \param[in] statsBufferIndex Index of stats buffer to use for multi-threading. * * This function processes line 0 for input formats with * patternSize height == 1. @@ -97,14 +98,18 @@ namespace libcamera { * to the line in plane 0, etc. * * For non Bayer single plane input data only a single src pointer is required. + * + * The statsBufferIndex value must be less than the statsBufferCount value passed + * to configure(). */ /** - * \fn void SwStatsCpu::processLine2(uint32_t frame, unsigned int y, const uint8_t *src[]) + * \fn void SwStatsCpu::processLine2(uint32_t frame, unsigned int y, const uint8_t *src[], unsigned int statsBufferIndex = 0) * \brief Process line 2 and 3 * \param[in] frame The frame number * \param[in] y The y coordinate. * \param[in] src The input data. + * \param[in] statsBufferIndex Index of stats buffer to use for multi-threading. * * This function processes line 2 and 3 for input formats with * patternSize height == 4. @@ -182,14 +187,14 @@ static constexpr unsigned int kBlueYMul = 29; /* 0.114 * 256 */ yVal = r * kRedYMul; \ yVal += g * kGreenYMul; \ yVal += b * kBlueYMul; \ - stats_.yHistogram[yVal * SwIspStats::kYHistogramSize / (256 * 256 * (div))]++; + stats.yHistogram[yVal * SwIspStats::kYHistogramSize / (256 * 256 * (div))]++; #define SWSTATS_FINISH_LINE_STATS() \ - stats_.sum_.r() += sumR; \ - stats_.sum_.g() += sumG; \ - stats_.sum_.b() += sumB; + stats.sum_.r() += sumR; \ + stats.sum_.g() += sumG; \ + stats.sum_.b() += sumB; -void SwStatsCpu::statsBGGR8Line0(const uint8_t *src[]) +void SwStatsCpu::statsBGGR8Line0(const uint8_t *src[], SwIspStats &stats) { const uint8_t *src0 = src[1] + window_.x; const uint8_t *src1 = src[2] + window_.x; @@ -214,7 +219,7 @@ void SwStatsCpu::statsBGGR8Line0(const uint8_t *src[]) SWSTATS_FINISH_LINE_STATS() } -void SwStatsCpu::statsBGGR10Line0(const uint8_t *src[]) +void SwStatsCpu::statsBGGR10Line0(const uint8_t *src[], SwIspStats &stats) { const uint16_t *src0 = (const uint16_t *)src[1] + window_.x; const uint16_t *src1 = (const uint16_t *)src[2] + window_.x; @@ -240,7 +245,7 @@ void SwStatsCpu::statsBGGR10Line0(const uint8_t *src[]) SWSTATS_FINISH_LINE_STATS() } -void SwStatsCpu::statsBGGR12Line0(const uint8_t *src[]) +void SwStatsCpu::statsBGGR12Line0(const uint8_t *src[], SwIspStats &stats) { const uint16_t *src0 = (const uint16_t *)src[1] + window_.x; const uint16_t *src1 = (const uint16_t *)src[2] + window_.x; @@ -266,7 +271,7 @@ void SwStatsCpu::statsBGGR12Line0(const uint8_t *src[]) SWSTATS_FINISH_LINE_STATS() } -void SwStatsCpu::statsBGGR10PLine0(const uint8_t *src[]) +void SwStatsCpu::statsBGGR10PLine0(const uint8_t *src[], SwIspStats &stats) { const uint8_t *src0 = src[1] + window_.x * 5 / 4; const uint8_t *src1 = src[2] + window_.x * 5 / 4; @@ -292,7 +297,7 @@ void SwStatsCpu::statsBGGR10PLine0(const uint8_t *src[]) SWSTATS_FINISH_LINE_STATS() } -void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src[]) +void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src[], SwIspStats &stats) { const uint8_t *src0 = src[1] + window_.x * 5 / 4; const uint8_t *src1 = src[2] + window_.x * 5 / 4; @@ -332,8 +337,10 @@ void SwStatsCpu::startFrame(uint32_t frame) if (window_.width == 0) LOG(SwStatsCpu, Error) << "Calling startFrame() without setWindow()"; - stats_.sum_ = RGB({ 0, 0, 0 }); - stats_.yHistogram.fill(0); + for (auto &s : stats_) { + s.sum_ = RGB({ 0, 0, 0 }); + s.yHistogram.fill(0); + } } /** @@ -345,8 +352,19 @@ void SwStatsCpu::startFrame(uint32_t frame) */ void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId) { - stats_.valid = frame % kStatPerNumFrames == 0; - *sharedStats_ = stats_; + bool valid = frame % kStatPerNumFrames == 0; + + if (valid) { + sharedStats_->sum_ = RGB({ 0, 0, 0 }); + sharedStats_->yHistogram.fill(0); + for (const auto &s : stats_) { + sharedStats_->sum_ += s.sum_; + for (unsigned int j = 0; j < SwIspStats::kYHistogramSize; j++) + sharedStats_->yHistogram[j] += s.yHistogram[j]; + } + } + + sharedStats_->valid = valid; statsReady.emit(frame, bufferId); } @@ -389,12 +407,14 @@ int SwStatsCpu::setupStandardBayerOrder(BayerFormat::Order order) /** * \brief Configure the statistics object for the passed in input format * \param[in] inputCfg The input format + * \param[in] statsBufferCount number of internal stats buffers to use for multi-threading * * \return 0 on success, a negative errno value on failure */ -int SwStatsCpu::configure(const StreamConfiguration &inputCfg) +int SwStatsCpu::configure(const StreamConfiguration &inputCfg, unsigned int statsBufferCount) { stride_ = inputCfg.stride; + stats_.resize(statsBufferCount); BayerFormat bayerFormat = BayerFormat::fromPixelFormat(inputCfg.pixelFormat); @@ -504,7 +524,7 @@ void SwStatsCpu::processBayerFrame2(MappedFrameBuffer &in) /* linePointers[0] is not used by any stats0_ functions */ linePointers[1] = src; linePointers[2] = src + stride_; - (this->*stats0_)(linePointers); + (this->*stats0_)(linePointers, stats_[0]); src += stride_ * 2; } } From patchwork Tue Mar 3 11:17:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 26245 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 90F79C0DA4 for ; Tue, 3 Mar 2026 11:17:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0A98F62395; Tue, 3 Mar 2026 12:17:55 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=qualcomm.com header.i=@qualcomm.com header.b="Lk20aq4u"; dkim=pass (2048-bit key; unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="hWiIpaFe"; dkim-atps=neutral Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3F3A762010 for ; Tue, 3 Mar 2026 12:17:51 +0100 (CET) Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6239n6i5582382 for ; Tue, 3 Mar 2026 11:17:49 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=qcppdkim1; bh=lj7q66a95nk SRrYrRSIi8jiFgvLhiP3E04FCMHJ3vrU=; b=Lk20aq4uSZiFX+hNAbsV99zs454 wgPctORDxtVJUAU+ETssCZppxl8ETBEUkiXfJiU65J7q8Bm4QW6InB4JpMHU3QdB 7LG42SVQ3lDLGGtEo+n6JpM/5fqJwsNE6x0/QSDzPgX3zWbQMhqtYM3OGuuCv9Fr vyVbsiqUfdn7stYith/gajUbVYskEhZCWN1/+fciE5Yn5i11gsnFGU/Rrq8q3O/R /Z6+z9hO2QEESkFEIoxIB0tp24sORUrN67+J/yNhzdo69q1BmfsawLlGVYdNhsxp jtSiA61sy0vsQRsJIQyZ+VYmJcufLt24QG9aH1qgWWaqs9wXfyJWOY66B3w== Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4cnh6uaqcu-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 03 Mar 2026 11:17:49 +0000 (GMT) Received: by mail-qk1-f198.google.com with SMTP id af79cd13be357-8cb4817f3c8so3370792585a.3 for ; Tue, 03 Mar 2026 03:17:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1772536668; x=1773141468; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=lj7q66a95nkSRrYrRSIi8jiFgvLhiP3E04FCMHJ3vrU=; b=hWiIpaFeaZhFT8stLndLn3xaDpl/5LZlPHgICzEc3+QMuRs8H4+H/TjjpjO5K0DRu0 pfNsnI8sSdfj6LpWvrBJyy4p94cPy5bVrUNfh22RofHf/i+JhTpNsHRh3q+LnI4sdm3t FyEV8EnA52JAN7Ts6ZStZZpdN9yi00SUZUX52qo4p957arIKbPoxCOI00q+KMDKN1K6s 3XN7/tPotraSJ2/vYbch/lxGDZ3AQk3TZwumtkyupJPnzBVMarWcSRG7RB86pYTlNvFG WYbzBv4nGXRfXXMeAgOqPKNMDBkkQO8+J4FZqEcvHpfYJ2798VIgjE0L4eUjMEBAhUfI Un6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772536668; x=1773141468; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=lj7q66a95nkSRrYrRSIi8jiFgvLhiP3E04FCMHJ3vrU=; b=PfJGgkMQAX5P73uhi121AUo8/sdCPfmiA+et/dAo48EYGoR6CfnHpN2Xhtw+AhMKHO DbaSOQBuDKMHul5XEfgVkheYJCEKv5gfzURjHqMbe2hMpyf5NPsjFe1Hkdl3xHwP1YL+ 3RY6hJnJ7UlG38ZyOE9XNw5qSZFpTD2x8U8LRQx6Kx47nkLid46usWM1z3+w6IJYJRGn zviRzwTzYJaERSz0DxWS4z3YVm3VPBwPeQW+bwbyo6FNBBqawd1wRyCeFv7NWTsIh23e GsiT+2XjfSuRYsw5UGQXgo30fIBtOZSMRU7pUlBqI77eBD+1RQTW5bnMFjNvUX7g+BK/ oUog== X-Gm-Message-State: AOJu0YxRU5/aAmHWZU8Si7zWSWnnwkd++WlHY5PJilJETDlfKC5IrK8k c4RY5M9qWSMUTYKMumjAK4R7fRlYYgM9/bNi5Ic7USATGukrBPGcobL1qkCm43vTx0BwcK3cx3O JnZQphAKW3PdQP2GMYjiH38vo2fnaiLjCRY8N1gRHB06Ajp1JOZANpvq3Ru3oR/QEi47Ai9dOqc y8r9/6RGhS X-Gm-Gg: ATEYQzy5TNRxR0ihgQ/I1B3tWdaCfLdGMKZqCbEKM1eFHO18lFxlIreUyIFGekY3b1h XZ02RnyvrY53EvzYSKwrZkI86shcc6moQyvJa4Pc0gPP3f5tPjByV5Gp3mI9YT0blNUuKdcAb0G 1N49ydjoxdWM8hYhBFsuDxvK8mNNXggJQdMZvusKdmF6J6ToPioeJ8Lq2qeme9uKUtI0oubpJNF fvtITgWDgA5S39u6cBr4k4GbnnMqbHrKZve3lgnAOscK863j5AxCs2INZR+3Ky/fVMi+Qc8MJtV 3OSkETZa692qtTLZR9ILxxSc5xPj/ucM6SiXFaooWQtkJU2KN8RGAosGlqcCxbkxC4mJ6QC//vY 933UoQBCF+kkqQaxzwvX4+ey25PWgQ0wnqBiYkCGu8C+kagIBcVtmUxVIJhuZ+iY2+xIbgnc0HZ SnEUjNGRCTL59oI7MipD3zmalACUbWaZMVqA== X-Received: by 2002:a05:620a:700a:b0:8cb:4d18:bb53 with SMTP id af79cd13be357-8cbc8e1f501mr1952061385a.64.1772536668084; Tue, 03 Mar 2026 03:17:48 -0800 (PST) X-Received: by 2002:a05:620a:700a:b0:8cb:4d18:bb53 with SMTP id af79cd13be357-8cbc8e1f501mr1952058185a.64.1772536667558; Tue, 03 Mar 2026 03:17:47 -0800 (PST) Received: from t14s (2001-1c00-0c32-7800-beb3-9058-f5fe-3f2e.cable.dynamic.v6.ziggo.nl. [2001:1c00:c32:7800:beb3:9058:f5fe:3f2e]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-66003479178sm2958144a12.9.2026.03.03.03.17.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2026 03:17:46 -0800 (PST) From: Hans de Goede To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Hans de Goede Subject: [PATCH v4 2/4] software_isp: debayer_cpu: Add DebayerCpuThread class Date: Tue, 3 Mar 2026 12:17:39 +0100 Message-ID: <20260303111741.17417-3-johannes.goede@oss.qualcomm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260303111741.17417-1-johannes.goede@oss.qualcomm.com> References: <20260303111741.17417-1-johannes.goede@oss.qualcomm.com> MIME-Version: 1.0 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMzAzMDA4NiBTYWx0ZWRfX1sLEAwt0zE7e cKmCCCFRSQP3/VxBBzVbTkIZ9aQHt6p8nTxpXnv8BPnSiLe/aFVTKHJdHAn8aKYVkf2uSgh7OFt hVO+i5k/z1dMLLXN5abQb3asf1FZctj/1XYPU2qwrDVpwS17yXWOJZXieAyi3gBYUQMeC9QOpwH rLdblRLac1eC4NgWpIyTCl5XW/IDX2jH0J+2Bl4ENgnIgQlNUCIj2seOmjEjze+zLuUKzQdSOfp rZysbMAdv/H4Z4JtSyIqO6fbTrtQiDUr28BUlJYBNXIRtbvfE9aGcUmEbmaD9wfumTD2v4onBf5 Dg+kYB2fMGzS8sAFy95JmdS40TEdYfiM9DEO9aEaXdvNS19WpegpQrgKtFIZkro4R7/TZyfBQfy MBhjvk10A1jJNfXDLsUjsR/lAosaBDeLovGulpqdSXJW03eWvF7QLtA7mlhEpnsTi6IrKNTEZ+p 7ZD+64sTAWL0kDevWyQ== X-Authority-Analysis: v=2.4 cv=MuhfKmae c=1 sm=1 tr=0 ts=69a6c35d cx=c_pps a=qKBjSQ1v91RyAK45QCPf5w==:117 a=xqWC_Br6kY4A:10 a=Yq5XynenixoA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_K5XuSEh1TEqbUxoQ0s3:22 a=20KFwNOVAAAA:8 a=EUspDBNiAAAA:8 a=Ba8D0n3WaO7QZ3tp1_0A:9 a=NFOGd7dJGGMPyQGDc5-O:22 X-Proofpoint-ORIG-GUID: cCJj2DjtPTYTOZouv-8mpLhSTU33ODhO X-Proofpoint-GUID: cCJj2DjtPTYTOZouv-8mpLhSTU33ODhO X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293, Aquarius:18.0.1121, Hydra:6.1.51, FMLib:17.12.100.49 definitions=2026-03-02_05,2026-03-03_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 phishscore=0 bulkscore=0 lowpriorityscore=0 adultscore=0 impostorscore=0 suspectscore=0 malwarescore=0 clxscore=1015 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2602130000 definitions=main-2603030086 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a DebayerCpuThreadclass and use this in the inner render loop. This contains data which needs to be separate per thread. This is a preparation patch for making DebayerCpu support multi-threading. Benchmarking on the Arduino Uno-Q with a weak CPU which is good for performance testing, shows 146-147ms per 3272x2464 frame both before and after this change, with things maybe being 0.5 ms slower after this change. Reviewed-by: Milan Zamazal Signed-off-by: Hans de Goede --- Changes in v4: - Move kMaxLineBuffers constant to DebayerCpuThread class - Add Milan's Reviewed-by Changes in v3: - Use std::unique_ptr for the DebayerCpuThread pointers - Document new DebayerCpuThread class - Make DebayerCpuThread inherit from both Thread and Object Changes in v2: - Replace the DebayerCpuThreadData struct from v1 with a DebayerCpuThread class, derived from Object to allow calling invokeMethod for thread re-use in followup patches - As part of this also move a bunch of methods which primarily deal with per thread data: setupInputMemcpy(), shiftLinePointers(), memcpyNextLine(), process*() to the new DebayerCpuThread class --- src/libcamera/software_isp/debayer_cpu.cpp | 247 +++++++++++++++------ src/libcamera/software_isp/debayer_cpu.h | 23 +- 2 files changed, 191 insertions(+), 79 deletions(-) diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index e7b012105..d57d640df 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -18,6 +18,8 @@ #include +#include + #include #include "libcamera/internal/bayer_format.h" @@ -27,6 +29,55 @@ namespace libcamera { +/** + * \brief Class representing one CPU debayering thread + * + * Implementation for CPU based debayering threads. + */ +class DebayerCpuThread : public Thread, public Object +{ +public: + DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex, + bool enableInputMemcpy); + + void configure(unsigned int yStart, unsigned int yEnd); + void process(uint32_t frame, const uint8_t *src, uint8_t *dst); + +private: + void setupInputMemcpy(const uint8_t *linePointers[]); + void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src); + void memcpyNextLine(const uint8_t *linePointers[]); + void process2(uint32_t frame, const uint8_t *src, uint8_t *dst); + void process4(uint32_t frame, const uint8_t *src, uint8_t *dst); + + /* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */ + static constexpr unsigned int kMaxLineBuffers = 5; + + DebayerCpu *debayer_; + unsigned int threadIndex_; + unsigned int yStart_; + unsigned int yEnd_; + unsigned int lineBufferLength_; + unsigned int lineBufferPadding_; + unsigned int lineBufferIndex_; + std::vector lineBuffers_[kMaxLineBuffers]; + bool enableInputMemcpy_; +}; + +/** + * \brief Construct a DebayerCpuThread object + * \param[in] debayer pointer back to the DebayerCpuObject this thread belongs to + * \param[in] threadIndex 0 .. n thread-index value for the thread + * \param[in] enableInputMemcpy when set copy input data to a heap buffer before use + */ +DebayerCpuThread::DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex, + bool enableInputMemcpy) + : Thread("DebayerCpu:" + std::to_string(threadIndex)), + debayer_(debayer), threadIndex_(threadIndex), + enableInputMemcpy_(enableInputMemcpy) +{ +} + /** * \class DebayerCpu * \brief Class for debayering on the CPU @@ -53,8 +104,14 @@ DebayerCpu::DebayerCpu(std::unique_ptr stats, const GlobalConfigurat * \todo Make memcpy automatic based on runtime detection of platform * capabilities. */ - enableInputMemcpy_ = + bool enableInputMemcpy = configuration.option({ "software_isp", "copy_input_buffer" }).value_or(true); + + /* Just one thread object for now, which will be called inline rather than async */ + threads_.resize(1); + + for (unsigned int i = 0; i < threads_.size(); i++) + threads_[i] = std::make_unique(this, i, enableInputMemcpy); } DebayerCpu::~DebayerCpu() = default; @@ -484,7 +541,7 @@ int DebayerCpu::configure(const StreamConfiguration &inputCfg, if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) return -EINVAL; - if (stats_->configure(inputCfg) != 0) + if (stats_->configure(inputCfg, threads_.size()) != 0) return -EINVAL; const Size &statsPatternSize = stats_->patternSize(); @@ -548,17 +605,43 @@ int DebayerCpu::configure(const StreamConfiguration &inputCfg, */ stats_->setWindow(Rectangle(window_.size())); + unsigned int yStart = 0; + unsigned int linesPerThread = (window_.height / threads_.size()) & + ~(inputConfig_.patternSize.height - 1); + unsigned int i; + + for (i = 0; i < (threads_.size() - 1); i++) { + threads_[i]->configure(yStart, yStart + linesPerThread); + yStart += linesPerThread; + } + threads_[i]->configure(yStart, window_.height); + + return 0; +} + +/** + * \brief Configure thread to process a specific part of the image + * \param[in] yStart y coordinate of first line to process + * \param[in] yEnd y coordinate of the line at which to stop processing + * + * Configure the thread to process lines yStart - (yEnd - 1). + */ +void DebayerCpuThread::configure(unsigned int yStart, unsigned int yEnd) +{ + Debayer::DebayerInputConfig &inputConfig = debayer_->inputConfig_; + + yStart_ = yStart; + yEnd_ = yEnd; + /* pad with patternSize.Width on both left and right side */ - lineBufferPadding_ = inputConfig_.patternSize.width * inputConfig_.bpp / 8; - lineBufferLength_ = window_.width * inputConfig_.bpp / 8 + + lineBufferPadding_ = inputConfig.patternSize.width * inputConfig.bpp / 8; + lineBufferLength_ = debayer_->window_.width * inputConfig.bpp / 8 + 2 * lineBufferPadding_; if (enableInputMemcpy_) { - for (unsigned int i = 0; i <= inputConfig_.patternSize.height; i++) + for (unsigned int i = 0; i <= inputConfig.patternSize.height; i++) lineBuffers_[i].resize(lineBufferLength_); } - - return 0; } /* @@ -599,9 +682,9 @@ DebayerCpu::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size return std::make_tuple(stride, stride * size.height); } -void DebayerCpu::setupInputMemcpy(const uint8_t *linePointers[]) +void DebayerCpuThread::setupInputMemcpy(const uint8_t *linePointers[]) { - const unsigned int patternHeight = inputConfig_.patternSize.height; + const unsigned int patternHeight = debayer_->inputConfig_.patternSize.height; if (!enableInputMemcpy_) return; @@ -617,20 +700,20 @@ void DebayerCpu::setupInputMemcpy(const uint8_t *linePointers[]) lineBufferIndex_ = patternHeight; } -void DebayerCpu::shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src) +void DebayerCpuThread::shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src) { - const unsigned int patternHeight = inputConfig_.patternSize.height; + const unsigned int patternHeight = debayer_->inputConfig_.patternSize.height; for (unsigned int i = 0; i < patternHeight; i++) linePointers[i] = linePointers[i + 1]; - linePointers[patternHeight] = src + - (patternHeight / 2) * (int)inputConfig_.stride; + linePointers[patternHeight] = + src + (patternHeight / 2) * (int)debayer_->inputConfig_.stride; } -void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[]) +void DebayerCpuThread::memcpyNextLine(const uint8_t *linePointers[]) { - const unsigned int patternHeight = inputConfig_.patternSize.height; + const unsigned int patternHeight = debayer_->inputConfig_.patternSize.height; if (!enableInputMemcpy_) return; @@ -643,23 +726,48 @@ void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[]) lineBufferIndex_ = (lineBufferIndex_ + 1) % (patternHeight + 1); } -void DebayerCpu::process2(uint32_t frame, const uint8_t *src, uint8_t *dst) +/** + * \brief Process part of the image assigned to this debayer thread + * \param[in] frame The frame number + * \param[in] src The source buffer + * \param[in] dst The destination buffer + */ +void DebayerCpuThread::process(uint32_t frame, const uint8_t *src, uint8_t *dst) { - unsigned int yEnd = window_.height; + Rectangle &window = debayer_->window_; + + /* Adjust src to top left corner of the window */ + src += (window.y + yStart_) * debayer_->inputConfig_.stride + + window.x * debayer_->inputConfig_.bpp / 8; + /* Adjust dst for yStart_ */ + dst += yStart_ * debayer_->outputConfig_.stride; + + if (debayer_->inputConfig_.patternSize.height == 2) + process2(frame, src, dst); + else + process4(frame, src, dst); +} + +void DebayerCpuThread::process2(uint32_t frame, const uint8_t *src, uint8_t *dst) +{ + unsigned int outputStride = debayer_->outputConfig_.stride; + unsigned int inputStride = debayer_->inputConfig_.stride; + Rectangle &window = debayer_->window_; + unsigned int yEnd = yEnd_; /* Holds [0] previous- [1] current- [2] next-line */ const uint8_t *linePointers[3]; - /* Adjust src to top left corner of the window */ - src += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8; - /* [x] becomes [x - 1] after initial shiftLinePointers() call */ - if (window_.y) { - linePointers[1] = src - inputConfig_.stride; /* previous-line */ + if (window.y + yStart_) { + linePointers[1] = src - inputStride; /* previous-line */ linePointers[2] = src; } else { - /* window_.y == 0, use the next line as prev line */ - linePointers[1] = src + inputConfig_.stride; + /* Top line, use the next line as prev line */ + linePointers[1] = src + inputStride; linePointers[2] = src; + } + + if (window.y == 0 && yEnd_ == window.height) { /* * Last 2 lines also need special handling. * (And configure() ensures that yEnd >= 2.) @@ -669,83 +777,93 @@ void DebayerCpu::process2(uint32_t frame, const uint8_t *src, uint8_t *dst) setupInputMemcpy(linePointers); - for (unsigned int y = 0; y < yEnd; y += 2) { + /* + * Note y is the line-number *inside* the window, since stats_' window + * is the stats window inside/relative to the debayer window. IOW for + * single thread rendering y goes from 0 to window.height. + */ + for (unsigned int y = yStart_; y < yEnd; y += 2) { shiftLinePointers(linePointers, src); memcpyNextLine(linePointers); - stats_->processLine0(frame, y, linePointers); - (this->*debayer0_)(dst, linePointers); - src += inputConfig_.stride; - dst += outputConfig_.stride; + debayer_->stats_->processLine0(frame, y, linePointers, threadIndex_); + debayer_->debayer0(dst, linePointers); + src += inputStride; + dst += outputStride; shiftLinePointers(linePointers, src); memcpyNextLine(linePointers); - (this->*debayer1_)(dst, linePointers); - src += inputConfig_.stride; - dst += outputConfig_.stride; + debayer_->debayer1(dst, linePointers); + src += inputStride; + dst += outputStride; } - if (window_.y == 0) { + if (window.y == 0 && yEnd_ == window.height) { shiftLinePointers(linePointers, src); memcpyNextLine(linePointers); - stats_->processLine0(frame, yEnd, linePointers); - (this->*debayer0_)(dst, linePointers); - src += inputConfig_.stride; - dst += outputConfig_.stride; + debayer_->stats_->processLine0(frame, yEnd, linePointers, threadIndex_); + debayer_->debayer0(dst, linePointers); + src += inputStride; + dst += outputStride; shiftLinePointers(linePointers, src); /* next line may point outside of src, use prev. */ linePointers[2] = linePointers[0]; - (this->*debayer1_)(dst, linePointers); - src += inputConfig_.stride; - dst += outputConfig_.stride; + debayer_->debayer1(dst, linePointers); + src += inputStride; + dst += outputStride; } } -void DebayerCpu::process4(uint32_t frame, const uint8_t *src, uint8_t *dst) +void DebayerCpuThread::process4(uint32_t frame, const uint8_t *src, uint8_t *dst) { + unsigned int outputStride = debayer_->outputConfig_.stride; + unsigned int inputStride = debayer_->inputConfig_.stride; + /* * This holds pointers to [0] 2-lines-up [1] 1-line-up [2] current-line * [3] 1-line-down [4] 2-lines-down. */ const uint8_t *linePointers[5]; - /* Adjust src to top left corner of the window */ - src += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8; - /* [x] becomes [x - 1] after initial shiftLinePointers() call */ - linePointers[1] = src - 2 * inputConfig_.stride; - linePointers[2] = src - inputConfig_.stride; + linePointers[1] = src - 2 * inputStride; + linePointers[2] = src - inputStride; linePointers[3] = src; - linePointers[4] = src + inputConfig_.stride; + linePointers[4] = src + inputStride; setupInputMemcpy(linePointers); - for (unsigned int y = 0; y < window_.height; y += 4) { + /* + * Note y is the line-number *inside* the window, since stats_' window + * is the stats window inside/relative to the debayer window. IOW for + * single thread rendering y goes from 0 to window.height. + */ + for (unsigned int y = yStart_; y < yEnd_; y += 4) { shiftLinePointers(linePointers, src); memcpyNextLine(linePointers); - stats_->processLine0(frame, y, linePointers); - (this->*debayer0_)(dst, linePointers); - src += inputConfig_.stride; - dst += outputConfig_.stride; + debayer_->stats_->processLine0(frame, y, linePointers, threadIndex_); + debayer_->debayer0(dst, linePointers); + src += inputStride; + dst += outputStride; shiftLinePointers(linePointers, src); memcpyNextLine(linePointers); - (this->*debayer1_)(dst, linePointers); - src += inputConfig_.stride; - dst += outputConfig_.stride; + debayer_->debayer1(dst, linePointers); + src += inputStride; + dst += outputStride; shiftLinePointers(linePointers, src); memcpyNextLine(linePointers); - stats_->processLine2(frame, y, linePointers); - (this->*debayer2_)(dst, linePointers); - src += inputConfig_.stride; - dst += outputConfig_.stride; + debayer_->stats_->processLine2(frame, y, linePointers, threadIndex_); + debayer_->debayer2(dst, linePointers); + src += inputStride; + dst += outputStride; shiftLinePointers(linePointers, src); memcpyNextLine(linePointers); - (this->*debayer3_)(dst, linePointers); - src += inputConfig_.stride; - dst += outputConfig_.stride; + debayer_->debayer3(dst, linePointers); + src += inputStride; + dst += outputStride; } } @@ -867,10 +985,7 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output stats_->startFrame(frame); - if (inputConfig_.patternSize.height == 2) - process2(frame, in.planes()[0].data(), out.planes()[0].data()); - else - process4(frame, in.planes()[0].data(), out.planes()[0].data()); + threads_[0]->process(frame, in.planes()[0].data(), out.planes()[0].data()); metadata.planes()[0].bytesused = out.planes()[0].size(); diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 7a6517462..780576090 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -26,6 +26,7 @@ namespace libcamera { +class DebayerCpuThread; class DebayerCpu : public Debayer { public: @@ -44,6 +45,8 @@ public: const SharedFD &getStatsFD() { return stats_->getStatsFD(); } private: + friend class DebayerCpuThread; + /** * \brief Called to debayer 1 line of Bayer input data to output format * \param[out] dst Pointer to the start of the output line to write @@ -74,6 +77,11 @@ private: */ using debayerFn = void (DebayerCpu::*)(uint8_t *dst, const uint8_t *src[]); + void debayer0(uint8_t *dst, const uint8_t *src[]) { (this->*debayer0_)(dst, src); } + void debayer1(uint8_t *dst, const uint8_t *src[]) { (this->*debayer1_)(dst, src); } + void debayer2(uint8_t *dst, const uint8_t *src[]) { (this->*debayer2_)(dst, src); } + void debayer3(uint8_t *dst, const uint8_t *src[]) { (this->*debayer3_)(dst, src); } + /* 8-bit raw bayer format */ template void debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]); @@ -105,17 +113,9 @@ private: int setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputFormat, bool ccmEnabled); - void setupInputMemcpy(const uint8_t *linePointers[]); - void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src); - void memcpyNextLine(const uint8_t *linePointers[]); - void process2(uint32_t frame, const uint8_t *src, uint8_t *dst); - void process4(uint32_t frame, const uint8_t *src, uint8_t *dst); void updateGammaTable(const DebayerParams ¶ms); void updateLookupTables(const DebayerParams ¶ms); - /* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */ - static constexpr unsigned int kMaxLineBuffers = 5; - static constexpr unsigned int kRGBLookupSize = 256; static constexpr unsigned int kGammaLookupSize = 1024; struct CcmColumn { @@ -142,12 +142,9 @@ private: debayerFn debayer3_; Rectangle window_; std::unique_ptr stats_; - std::vector lineBuffers_[kMaxLineBuffers]; - unsigned int lineBufferLength_; - unsigned int lineBufferPadding_; - unsigned int lineBufferIndex_; unsigned int xShift_; /* Offset of 0/1 applied to window_.x */ - bool enableInputMemcpy_; + + std::vector>threads_; }; } /* namespace libcamera */ From patchwork Tue Mar 3 11:17:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 26246 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 8A662C32EA for ; Tue, 3 Mar 2026 11:17:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BD928623A2; Tue, 3 Mar 2026 12:17:55 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=qualcomm.com header.i=@qualcomm.com header.b="pJXKCwHp"; dkim=pass (2048-bit key; unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="LwpMicCV"; dkim-atps=neutral Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3547662395 for ; Tue, 3 Mar 2026 12:17:52 +0100 (CET) Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6239moKV2733596 for ; Tue, 3 Mar 2026 11:17:50 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=qcppdkim1; bh=61zLKSb3u/2 Bf+JVWEk65x3S2OYd22ZVRPj0PFmBxuE=; b=pJXKCwHpTsuNuQtSW3Asgq/Fxm2 NkHLpg83OQp0NZg78EqVzjaBUA3i7ucq7DSLjaE1eZr5E/opZK88iL3IFKMKtjQU j7pBBhIZCwfiGnvrwiub/ShVhfudTwb0Ot1Cynjex3WcUZJL62Z/2v3XubaUfa39 0sf0JVyab1DPfO6yV5+fE/zgqAJS+SnOt6o1Avd5x2dISvuQnmjbVWcK6wuDFt7/ AM4R+VCIni7f3TO6WiOoRnBFtqjAdwAuAqlqf3HhNh/LNKDuCM1qbpsnvl7t2Arr CkW9IDk4xZkpuw7TDRjLkUtkX7djUrW/8PYHQTUrV5hOkpSCvakCSqzY9KA== Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4cnswe129k-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 03 Mar 2026 11:17:50 +0000 (GMT) Received: by mail-qk1-f199.google.com with SMTP id af79cd13be357-8cb3ff05c73so3645742785a.0 for ; Tue, 03 Mar 2026 03:17:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1772536669; x=1773141469; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=61zLKSb3u/2Bf+JVWEk65x3S2OYd22ZVRPj0PFmBxuE=; b=LwpMicCVH4M4BviWWDbSjQU9X9Z3epjOdgkPChjhgY4jg73zp8gJllJnta0d+SFuiG BEkRxPTOI6xkHft94P3wy0MJR9kcekXq/pi2oodew1sMPWibeLTUiSFZQzxQ2BxUSUQV Y7peqIxqfQ0Uw+xr76GCF4fqNGQaIfrGS1zWiZHx4Z/Pssx8TB2ehDuAkA4OzCMVKKWn Vwt5KrgJmHwB5zy3D+KZbMGz0qbiwcSPW4pmgNwNj15hseOicHe4/bo78wonrFMpNA+f P8U5c2gTT+Wx5jHLZYmp/SUzyQyxYjSTaqgfWR6HvlRgO82CgtcPd/a6/UUnSQiswNai Yu0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772536669; x=1773141469; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=61zLKSb3u/2Bf+JVWEk65x3S2OYd22ZVRPj0PFmBxuE=; b=KT8/mhAU4EIKqMjn0nd/OdD2AT2rwZu+b3SUXX2iFpn2ytJnHDDsNSpc7UpcUUnbnP t/gedDMveij3dH90lH6B0Pk9M69886rpGhqE5MniYX2uAsDVqpddWX/ZtKaXLU4lh1k4 DlzPdesDVFyLbvqtnL2WW5XPWO/uRXksL/jLNWEPiK+Udh9BKCpsm8t3ZcUtlXUQ4Gxg Hvrv5XVlaCdc4MVbP04z//GwMkbnTJaq8uYQUXdfujZ6+qMLZZjAqphVFjPuFcjolv4U oqcsmsFtkavjdmssZ9iG+JB+CKtvXWqtRXT8AuEtwLL9jnvRwwWWC91iH52w/XVtlhLQ 9b9A== X-Gm-Message-State: AOJu0Yx0+Wph8b8CoPczeMosApoElvibolqXyNdvHuLgSs5sYB3dcXsR 3N8eDrCJfZ7IdrrsArRFesKib2xGm4Z8/bT3bhCCD9X67jCAKB8vJVrB/P8W+Y96zO5zDjuD5vV TVa3tjjDA2wn7pBT8KXpyPKuePl0152rRzLtr4viEyFp0U1QKx8LtDdpXEK2XGZD0vlrnOEF1SX WN17wyfuZA X-Gm-Gg: ATEYQzyIzHe+ilRDMIIjtIWAzXMbzJ+Zof6B7wI3yi0cn1eNRWflKLs0BsjvohRhDoy DqDGP1QTBNe84dSSSpoPUyTszAGyWuE58GMY2ALmCir/Ci/oAC4P0fNo9hznQTg1smPxmlCXZrt zB1z6aMiOPVocoqopu4ZM/PtKcNDeOtIWqqDt/q1lt/Gl731Sm8i40m9WjczFCLgw9TvzXwyYY+ ANXt56AwWc4N3LMyOjuQKngN0gW8qfZON0waiymonogjJNWaxw0DUBoh48Y6tevun8X0Bu6V3Sc bTkqIDMt2HNtRAVx97GFETxuITFzambnmTkr48LpGUIJzfbXzoD60lF6MiSLcQjv/StXsZlv+Pl I0FT9r5gVs73qZtpKZuMGLruIwl+sR5KsJvisOeuX0oEiXKnpu01AofLdheuBl/vuRbK4FfR2qo IOglny79Ep9dx8iAOB9JGAZxk8aa8GwrANSQ== X-Received: by 2002:a05:620a:25c7:b0:8ca:3c67:891d with SMTP id af79cd13be357-8cbc8f1af5emr1859077585a.54.1772536669088; Tue, 03 Mar 2026 03:17:49 -0800 (PST) X-Received: by 2002:a05:620a:25c7:b0:8ca:3c67:891d with SMTP id af79cd13be357-8cbc8f1af5emr1859074685a.54.1772536668537; Tue, 03 Mar 2026 03:17:48 -0800 (PST) Received: from t14s (2001-1c00-0c32-7800-beb3-9058-f5fe-3f2e.cable.dynamic.v6.ziggo.nl. [2001:1c00:c32:7800:beb3:9058:f5fe:3f2e]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-66003479178sm2958144a12.9.2026.03.03.03.17.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2026 03:17:47 -0800 (PST) From: Hans de Goede To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Hans de Goede Subject: [PATCH v4 3/4] software_isp: debayer_cpu: Add multi-threading support Date: Tue, 3 Mar 2026 12:17:40 +0100 Message-ID: <20260303111741.17417-4-johannes.goede@oss.qualcomm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260303111741.17417-1-johannes.goede@oss.qualcomm.com> References: <20260303111741.17417-1-johannes.goede@oss.qualcomm.com> MIME-Version: 1.0 X-Proofpoint-ORIG-GUID: WPnRoZim_gyi0BujCbYdFpjfD0LbFb00 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMzAzMDA4NiBTYWx0ZWRfX94nF592oVPcr 2p7Ue/HOZiimTJFor5DZYX2GA962AQ+46pwssysULQrblnTjUbhcNsBJ07RWQ2lX6lOSZiMNiRP tAz5a7rF4k7IBtTVbmhw09UiPQ7KDwXH1nev+hEFx6kVeapNoC+4Ki4nFKwjovCKF7/JgO1ZVeA WG8zIy+jGLrh/kbta2o77K2LtuPJ12OlUlFQlsmR4sMkFzHSJj7TlsRen/QPbI+XTH4M6qYBPjd L2YCA7Y55NRuuSarKBXNJxXodZCpI2uy3K/fzvBnmMc/OY1V/XgS1dbK/bepHp/Q6JR6rJxIE/B 2HrBncoSOIuCih27EPdF001CIuL/2sDWIWNhlL/FpL7CYS3/W/3DC/vbR5PlR3O5fsYXiafV7Ss rQhDBIdmcGvMVp4RnZumQkBTz3eHSV1LR8pThcRVuVRZXEMPo9FJi5S3OqnNKvHPKiXndqLtz0v uo7oUikJhGGYyLSseMg== X-Authority-Analysis: v=2.4 cv=TtHrRTXh c=1 sm=1 tr=0 ts=69a6c35e cx=c_pps a=HLyN3IcIa5EE8TELMZ618Q==:117 a=xqWC_Br6kY4A:10 a=Yq5XynenixoA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=eoimf2acIAo5FJnRuUoq:22 a=EUspDBNiAAAA:8 a=wcwPUnDRDUmv0zfwghEA:9 a=bTQJ7kPSJx9SKPbeHEYW:22 X-Proofpoint-GUID: WPnRoZim_gyi0BujCbYdFpjfD0LbFb00 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293, Aquarius:18.0.1121, Hydra:6.1.51, FMLib:17.12.100.49 definitions=2026-03-02_05,2026-03-03_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 malwarescore=0 phishscore=0 suspectscore=0 adultscore=0 priorityscore=1501 spamscore=0 impostorscore=0 bulkscore=0 clxscore=1015 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2602130000 definitions=main-2603030086 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add CPU soft ISP multi-threading support. Benchmark results for the Arduino Uno-Q with a weak CPU which is good for performance testing, all numbers with an IMX219 running at 3280x2464 -> 3272x2464: 1 thread : 147ms / frame, ~6.5 fps 2 threads: 80ms / frame, ~12.5 fps 3 threads: 65ms / frame, ~15 fps Adding a 4th thread does not improve performance. Signed-off-by: Hans de Goede --- Changes in v4: - Document "software_isp", "threads" option in runtime_configuration.rst - Add an use constants for min/max/default number of threads Changes in v3: - Adjust for DebayerCpuThread now inheriting from Thread - Use for (auto &thread : threads_) Changes in v2: - Adjust to use the new DebayerCpuThread class introduced in the v2 patch-series - Re-use threads instead of starting new threads every frame --- Documentation/runtime_configuration.rst | 1 + src/libcamera/software_isp/debayer_cpu.cpp | 45 ++++++++++++++++++++-- src/libcamera/software_isp/debayer_cpu.h | 10 +++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index e99ef2fb9..07d1a9123 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -51,6 +51,7 @@ file structure: measure: skip: # non-negative integer, frames to skip initially number: # non-negative integer, frames to measure + threads: # integer >= 1, number of render threads to use, default 2 Configuration file example -------------------------- diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index d57d640df..f7c3e1751 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -76,6 +76,7 @@ DebayerCpuThread::DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex debayer_(debayer), threadIndex_(threadIndex), enableInputMemcpy_(enableInputMemcpy) { + moveToThread(this); } /** @@ -107,8 +108,10 @@ DebayerCpu::DebayerCpu(std::unique_ptr stats, const GlobalConfigurat bool enableInputMemcpy = configuration.option({ "software_isp", "copy_input_buffer" }).value_or(true); - /* Just one thread object for now, which will be called inline rather than async */ - threads_.resize(1); + unsigned int threadCount = + configuration.option({ "software_isp", "threads" }).value_or(kDefaultThreads); + threadCount = std::clamp(threadCount, kMinThreads, kMaxThreads); + threads_.resize(threadCount); for (unsigned int i = 0; i < threads_.size(); i++) threads_[i] = std::make_unique(this, i, enableInputMemcpy); @@ -746,6 +749,11 @@ void DebayerCpuThread::process(uint32_t frame, const uint8_t *src, uint8_t *dst) process2(frame, src, dst); else process4(frame, src, dst); + + debayer_->workPendingMutex_.lock(); + debayer_->workPending_ &= ~(1 << threadIndex_); + debayer_->workPendingMutex_.unlock(); + debayer_->workPendingCv_.notify_one(); } void DebayerCpuThread::process2(uint32_t frame, const uint8_t *src, uint8_t *dst) @@ -985,7 +993,21 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output stats_->startFrame(frame); - threads_[0]->process(frame, in.planes()[0].data(), out.planes()[0].data()); + workPendingMutex_.lock(); + workPending_ = (1 << threads_.size()) - 1; + workPendingMutex_.unlock(); + + for (auto &thread : threads_) + thread->invokeMethod(&DebayerCpuThread::process, + ConnectionTypeQueued, frame, + in.planes()[0].data(), out.planes()[0].data()); + + { + MutexLocker locker(workPendingMutex_); + workPendingCv_.wait(locker, [&]() LIBCAMERA_TSA_REQUIRES(workPendingMutex_) { + return workPending_ == 0; + }); + } metadata.planes()[0].bytesused = out.planes()[0].size(); @@ -1004,6 +1026,23 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output inputBufferReady.emit(input); } +int DebayerCpu::start() +{ + for (auto &thread : threads_) + thread->start(); + + return 0; +} + +void DebayerCpu::stop() +{ + for (auto &thread : threads_) + thread->exit(); + + for (auto &thread : threads_) + thread->wait(); +} + SizeRange DebayerCpu::sizes(PixelFormat inputFormat, const Size &inputSize) { Size patternSize = this->patternSize(inputFormat); diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 780576090..11280c0a1 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -16,6 +16,7 @@ #include #include +#include #include "libcamera/internal/bayer_format.h" #include "libcamera/internal/global_configuration.h" @@ -41,6 +42,8 @@ public: std::tuple strideAndFrameSize(const PixelFormat &outputFormat, const Size &size); void process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms); + int start(); + void stop(); SizeRange sizes(PixelFormat inputFormat, const Size &inputSize); const SharedFD &getStatsFD() { return stats_->getStatsFD(); } @@ -144,6 +147,13 @@ private: std::unique_ptr stats_; unsigned int xShift_; /* Offset of 0/1 applied to window_.x */ + static constexpr unsigned int kMinThreads = 1; + static constexpr unsigned int kMaxThreads = 8; + static constexpr unsigned int kDefaultThreads = 2; + + unsigned int workPending_ LIBCAMERA_TSA_GUARDED_BY(workPendingMutex_); + Mutex workPendingMutex_; + ConditionVariable workPendingCv_; std::vector>threads_; }; From patchwork Tue Mar 3 11:17:41 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 26247 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 59519C0DA4 for ; Tue, 3 Mar 2026 11:17:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9C6B26239C; Tue, 3 Mar 2026 12:17:56 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=qualcomm.com header.i=@qualcomm.com header.b="MPfQBuog"; dkim=pass (2048-bit key; unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="BZEq/wwx"; dkim-atps=neutral Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0F5216238E for ; Tue, 3 Mar 2026 12:17:52 +0100 (CET) Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6239n5J4582371 for ; Tue, 3 Mar 2026 11:17:51 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=qcppdkim1; bh=8Gvil8HmgAm ctZLXvrxDYw8ceQF1zFMUNkBVOjwGEfg=; b=MPfQBuogKnHaHWjex2Pq8gDiH8q tIzTvJ5q6EsyHyWb+QV9JJsdBgudUrz/q5IFo+SFayrw5JVOtEUXJZCDzuw5jKo0 ML7AKAn8SA//GMo3eAzHUFDIjY4dmim4X6SJC/RkQYBuxmgYcA9E/ua1VSbpG/hf lVJ9/xE6BAq0altuQlyqnSmZgL4Z3X0/soxcDp3fKNDN6ZwYzYdTq2Vdl5e6ztBo G796jQYUMDML8rNui1YH4CPsQiJ82ANZ9D85F6cNXEGtoIfqzQglZcXhBmpz/Dtw w6nFj7O8fs4SWep/e/DEDrcxOJfm2wli5wdNR8sGg0hsQA04JRNshhYjsXQ== Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4cnh6uaqd3-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 03 Mar 2026 11:17:51 +0000 (GMT) Received: by mail-qt1-f199.google.com with SMTP id d75a77b69052e-5033c483b74so54133211cf.2 for ; Tue, 03 Mar 2026 03:17:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1772536670; x=1773141470; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8Gvil8HmgAmctZLXvrxDYw8ceQF1zFMUNkBVOjwGEfg=; b=BZEq/wwxatmlrB481uf5huSmkKJFPGDR5GNASU7zQxCBhyucnO5A2115NSs4dyBb7v Uz7J+WcjmO+xnQMHzPYThe/l7irSUfGkiHibsxg1vsZ3BAAKS0TM2rbdfdr3MpRs2olv W96gUp6tlHbmkBTT/CUjbdY6x52f5RGdAeNiyvh/IvYc0kTo+BwXZQKyuhmvau6R5d8L nZ82QcH5dVYwL98qC2UwIx+KTz9RLxV5fcDStxzhbnxw7NONhKr+JGL0fXat4WjngzZQ AHtlSzA35iBeh1RyD1RmWtiX8ME9LXBq++RAdVjgXuw0fXsj5EaHJj2LNHEMOXG1rnej zEuw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772536670; x=1773141470; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8Gvil8HmgAmctZLXvrxDYw8ceQF1zFMUNkBVOjwGEfg=; b=fC90qVVtHVf80gL5qKXzIbLyRRkKl6iqoduZ0PorEvkLH+AqJcBLq7Czwg5LAw/t1A 27emaNCWJxpoqA4OJqPYtpdZCLOkFEsFkZYAqeaacqsyIIipnQsuRtdnimn34Is5hTpN t7kRu5j0nw8yW784rIx45MaGCJ+JWGOn9mq0TSLJmNwvIZKkefovAHl/+vDCFPJNJYvV njViqeriaNApk5QQ2NL4lDZDyONujElDGL4DJFifvHrXwuVLBk95Ji1LA0+Ib39V0aij 4rZwSRRSg4lrHXbvDoTAor6OEwYQDLoppDIq/bJ/jl2VHVFjeAVcA/Uw76L65vWNjprx g4Ww== X-Gm-Message-State: AOJu0YwG94wSvbI5X26MXhhKivYqYxrTQJOnf/tnvFusk+orvnHUN7tm Ch1tnn2/OHCvcMe6fn+sGurs/qdLGzQt7OVw0tGs6twg4/UWjdLTgqSChuyw3k1dVZrj+SgpdMN 7vtN66wF2KeGqbAbs6mPbI7yjuTdxN9dGl3B3sL/zsQOdvcrngCCWdXJ6fjP0TvO65TiNaztbOw 5R8tO698n3 X-Gm-Gg: ATEYQzz1uzgzgYrFnm8dyET6AJqQ+BaU8Vkcg+ZnCHkcTHOQTqupE/y2XrMTVDD1ynw EjOAuryi6QSvxrFNnLnSYhHK/vHUYCenQiHql3GJEofbXwjwE8punrHly7VnhXC1YrCcoEx1W0G vcHN18h1J+8+e5iiopQM34JNVRJEjuet2rWlfPAJAmCGnwaw3poYbhQn3QG0sRA4IhdnThjFvzc hLY/FgqfzjIzYLbeFHaWhMI9XG8nyzjRlPZKC8nulaFrq+wpK0UrcdzP8ewArrgKQ62NqgjVJl/ 0fpMom/efqLkZrbWeeIrjBG2s1j2gWC7Gs/XqbkvV4x7AJQ190plSXjHNFWCMdawxm3pZyM9tnI nheBgU2RzR7YOxrIk+afo6cCxFz4sN+yG1hB8RPapYkIdUXh6jezHQT5MJTroZeL11FKecaOmil nvIvnUU/eLIflkuV5SXqxFwHkjC94BuHiAJA== X-Received: by 2002:a05:620a:f0e:b0:8b2:e666:70d with SMTP id af79cd13be357-8cbc8e03a3emr1976829485a.43.1772536670070; Tue, 03 Mar 2026 03:17:50 -0800 (PST) X-Received: by 2002:a05:620a:f0e:b0:8b2:e666:70d with SMTP id af79cd13be357-8cbc8e03a3emr1976826585a.43.1772536669622; Tue, 03 Mar 2026 03:17:49 -0800 (PST) Received: from t14s (2001-1c00-0c32-7800-beb3-9058-f5fe-3f2e.cable.dynamic.v6.ziggo.nl. [2001:1c00:c32:7800:beb3:9058:f5fe:3f2e]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-66003479178sm2958144a12.9.2026.03.03.03.17.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2026 03:17:49 -0800 (PST) From: Hans de Goede To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Hans de Goede Subject: [PATCH v4 4/4] software_isp: Log input config from configure() Date: Tue, 3 Mar 2026 12:17:41 +0100 Message-ID: <20260303111741.17417-5-johannes.goede@oss.qualcomm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260303111741.17417-1-johannes.goede@oss.qualcomm.com> References: <20260303111741.17417-1-johannes.goede@oss.qualcomm.com> MIME-Version: 1.0 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMzAzMDA4NiBTYWx0ZWRfX8+JV4HTK+qix IQ/XKUC/sWrSZEQc/KiFYB3v5+sk2bgEpgpiP0kvCCEBgamlAtYTeCyHFlslIEBACQHkoSN/Hk2 pe+t29ryOicK5WIA0xdJmD6F05nmGLHEJ8AX2Dk4J7U6YtizQo3znGbF7Uu4Bux3ezKKNr/zmGX jX9L8775h6RemE3rPoMiMYMr3g+DaGRWy1M2/9H73BXSxM6XFG8LOyOanaD/un57HJn2hTLpQ4Q wA6WtuMoHHMgfNv5dnsRoFAuKJ3dFeYL1wBRC1xOUpyxWgTfcxckeG5AG6SyDH8DP8Kf3UF2QIb 0uR9F6+VuiXibxVM/kDs7p9eRIKEcSEbQzzxfmIRzVEcZxLQrMHhjsIK1V21UOTiAdtVtKByMxJ vXKqcgeCwy/9xAEjUob6NG4eRr8OMvNiKZ5ns5ubuOXlAmJw0ytJyVeKWpuz0xwZ9NnKsLib4Ps F0NDAxyc5XOzbZEXMDQ== X-Authority-Analysis: v=2.4 cv=MuhfKmae c=1 sm=1 tr=0 ts=69a6c35f cx=c_pps a=WeENfcodrlLV9YRTxbY/uA==:117 a=xqWC_Br6kY4A:10 a=Yq5XynenixoA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_K5XuSEh1TEqbUxoQ0s3:22 a=20KFwNOVAAAA:8 a=EUspDBNiAAAA:8 a=mKg8M22OkPar6P-70WAA:9 a=kacYvNCVWA4VmyqE58fU:22 X-Proofpoint-ORIG-GUID: n64Tv9yWasSHCK2RLVsI7F_X4cy4Vi1N X-Proofpoint-GUID: n64Tv9yWasSHCK2RLVsI7F_X4cy4Vi1N X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293, Aquarius:18.0.1121, Hydra:6.1.51, FMLib:17.12.100.49 definitions=2026-03-02_05,2026-03-03_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 phishscore=0 bulkscore=0 lowpriorityscore=0 adultscore=0 impostorscore=0 suspectscore=0 malwarescore=0 clxscore=1015 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2602130000 definitions=main-2603030086 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" As shown by commit 94d32fdc55a3 ("pipeline: simple: Consider output sizes when choosing pipe config"), the extra pixel columns CPU debayering requires on the input side makes resolution selection non trivial. Add logging of the selected input config on a successful configure() so that the logs clearly show which sensor mode has been selected. Reviewed-by: Milan Zamazal Signed-off-by: Hans de Goede --- Changes in v2: - Move from DebayerCpu::configure() to SoftwareIsp::configure() so that the input fmt also gets logged when using the DebayerEgl class --- src/libcamera/software_isp/software_isp.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 562cdba22..4cf5639d9 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -21,6 +21,7 @@ #include #include +#include "libcamera/internal/bayer_format.h" #include "libcamera/internal/framebuffer.h" #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/software_isp/debayer_params.h" @@ -270,7 +271,16 @@ int SoftwareIsp::configure(const StreamConfiguration &inputCfg, if (ret < 0) return ret; - return debayer_->configure(inputCfg, outputCfgs, ccmEnabled_); + ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_); + if (ret < 0) + return ret; + + LOG(SoftwareIsp, Info) + << "Input " << inputCfg.size + << "-" << BayerFormat::fromPixelFormat(inputCfg.pixelFormat) + << " stride " << inputCfg.stride; + + return 0; } /**