[{"id":38320,"web_url":"https://patchwork.libcamera.org/comment/38320/","msgid":"<854imx6o3m.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-03-03T13:26:21","subject":"Re: [PATCH v4 3/4] software_isp: debayer_cpu: Add multi-threading\n\tsupport","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Hi Hans,\n\nthank you for the update.\n\nHans de Goede <johannes.goede@oss.qualcomm.com> writes:\n\n> Add CPU soft ISP multi-threading support.\n>\n> Benchmark results for the Arduino Uno-Q with a weak CPU which is good for\n> performance testing, all numbers with an IMX219 running at\n> 3280x2464 -> 3272x2464:\n>\n> 1 thread : 147ms / frame, ~6.5 fps\n> 2 threads:  80ms / frame, ~12.5 fps\n> 3 threads:  65ms / frame, ~15 fps\n>\n> Adding a 4th thread does not improve performance.\n>\n> Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>\n> ---\n> Changes in v4:\n> - Document \"software_isp\", \"threads\" option in runtime_configuration.rst\n> - Add an use constants for min/max/default number of threads\n>\n> Changes in v3:\n> - Adjust for DebayerCpuThread now inheriting from Thread\n> - Use for (auto &thread : threads_)\n>\n> Changes in v2:\n> - Adjust to use the new DebayerCpuThread class introduced in the v2 patch-series\n> - Re-use threads instead of starting new threads every frame\n> ---\n>  Documentation/runtime_configuration.rst    |  1 +\n>  src/libcamera/software_isp/debayer_cpu.cpp | 45 ++++++++++++++++++++--\n>  src/libcamera/software_isp/debayer_cpu.h   | 10 +++++\n>  3 files changed, 53 insertions(+), 3 deletions(-)\n>\n> diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst\n> index e99ef2fb9..07d1a9123 100644\n> --- a/Documentation/runtime_configuration.rst\n> +++ b/Documentation/runtime_configuration.rst\n> @@ -51,6 +51,7 @@ file structure:\n>        measure:\n>          skip: # non-negative integer, frames to skip initially\n>          number: # non-negative integer, frames to measure\n> +      threads: # integer >= 1, number of render threads to use, default 2\n\nIn addition to being added to this overview, the option should be\ndocumented in \"List of variables and configuration options\" later in the\nfile.  The limits on the value range can be described there.\n\n>  Configuration file example\n>  --------------------------\n> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n> index d57d640df..f7c3e1751 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n> @@ -76,6 +76,7 @@ DebayerCpuThread::DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex\n>  \t  debayer_(debayer), threadIndex_(threadIndex),\n>  \t  enableInputMemcpy_(enableInputMemcpy)\n>  {\n> +\tmoveToThread(this);\n>  }\n>  \n>  /**\n> @@ -107,8 +108,10 @@ DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats, const GlobalConfigurat\n>  \tbool enableInputMemcpy =\n>  \t\tconfiguration.option<bool>({ \"software_isp\", \"copy_input_buffer\" }).value_or(true);\n>  \n> -\t/* Just one thread object for now, which will be called inline rather than async */\n> -\tthreads_.resize(1);\n> +\tunsigned int threadCount =\n> +\t\tconfiguration.option<unsigned int>({ \"software_isp\", \"threads\" }).value_or(kDefaultThreads);\n> +\tthreadCount = std::clamp(threadCount, kMinThreads, kMaxThreads);\n\nShould there be an INFO log message in case the specified number of\nthreads gets changed due to the clamping?\n\n> +\tthreads_.resize(threadCount);\n>  \n>  \tfor (unsigned int i = 0; i < threads_.size(); i++)\n>  \t\tthreads_[i] = std::make_unique<DebayerCpuThread>(this, i, enableInputMemcpy);\n> @@ -746,6 +749,11 @@ void DebayerCpuThread::process(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>  \t\tprocess2(frame, src, dst);\n>  \telse\n>  \t\tprocess4(frame, src, dst);\n> +\n> +\tdebayer_->workPendingMutex_.lock();\n> +\tdebayer_->workPending_ &= ~(1 << threadIndex_);\n> +\tdebayer_->workPendingMutex_.unlock();\n> +\tdebayer_->workPendingCv_.notify_one();\n>  }\n>  \n>  void DebayerCpuThread::process2(uint32_t frame, const uint8_t *src, uint8_t *dst)\n> @@ -985,7 +993,21 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>  \n>  \tstats_->startFrame(frame);\n>  \n> -\tthreads_[0]->process(frame, in.planes()[0].data(), out.planes()[0].data());\n> +\tworkPendingMutex_.lock();\n> +\tworkPending_ = (1 << threads_.size()) - 1;\n> +\tworkPendingMutex_.unlock();\n> +\n> +\tfor (auto &thread : threads_)\n> +\t\tthread->invokeMethod(&DebayerCpuThread::process,\n> +\t\t\t\t     ConnectionTypeQueued, frame,\n> +\t\t\t\t     in.planes()[0].data(), out.planes()[0].data());\n> +\n> +\t{\n> +\t\tMutexLocker locker(workPendingMutex_);\n> +\t\tworkPendingCv_.wait(locker, [&]() LIBCAMERA_TSA_REQUIRES(workPendingMutex_) {\n> +\t\t\treturn workPending_ == 0;\n> +\t\t});\n> +\t}\n>  \n>  \tmetadata.planes()[0].bytesused = out.planes()[0].size();\n>  \n> @@ -1004,6 +1026,23 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>  \tinputBufferReady.emit(input);\n>  }\n>  \n> +int DebayerCpu::start()\n> +{\n> +\tfor (auto &thread : threads_)\n> +\t\tthread->start();\n> +\n> +\treturn 0;\n> +}\n> +\n> +void DebayerCpu::stop()\n> +{\n> +\tfor (auto &thread : threads_)\n> +\t\tthread->exit();\n> +\n> +\tfor (auto &thread : threads_)\n> +\t\tthread->wait();\n> +}\n> +\n>  SizeRange DebayerCpu::sizes(PixelFormat inputFormat, const Size &inputSize)\n>  {\n>  \tSize patternSize = this->patternSize(inputFormat);\n> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n> index 780576090..11280c0a1 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.h\n> +++ b/src/libcamera/software_isp/debayer_cpu.h\n> @@ -16,6 +16,7 @@\n>  #include <vector>\n>  \n>  #include <libcamera/base/object.h>\n> +#include <libcamera/base/mutex.h>\n>  \n>  #include \"libcamera/internal/bayer_format.h\"\n>  #include \"libcamera/internal/global_configuration.h\"\n> @@ -41,6 +42,8 @@ public:\n>  \tstd::tuple<unsigned int, unsigned int>\n>  \tstrideAndFrameSize(const PixelFormat &outputFormat, const Size &size);\n>  \tvoid process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams &params);\n> +\tint start();\n> +\tvoid stop();\n>  \tSizeRange sizes(PixelFormat inputFormat, const Size &inputSize);\n>  \tconst SharedFD &getStatsFD() { return stats_->getStatsFD(); }\n>  \n> @@ -144,6 +147,13 @@ private:\n>  \tstd::unique_ptr<SwStatsCpu> stats_;\n>  \tunsigned int xShift_; /* Offset of 0/1 applied to window_.x */\n>  \n> +\tstatic constexpr unsigned int kMinThreads = 1;\n> +\tstatic constexpr unsigned int kMaxThreads = 8;\n> +\tstatic constexpr unsigned int kDefaultThreads = 2;\n> +\n> +\tunsigned int workPending_ LIBCAMERA_TSA_GUARDED_BY(workPendingMutex_);\n> +\tMutex workPendingMutex_;\n> +\tConditionVariable workPendingCv_;\n>  \tstd::vector<std::unique_ptr<DebayerCpuThread>>threads_;\n>  };","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 D43B4BE086\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  3 Mar 2026 13:26:31 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AEFAC62385;\n\tTue,  3 Mar 2026 14:26:30 +0100 (CET)","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 BFF4462010\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  3 Mar 2026 14:26:28 +0100 (CET)","from mail-wr1-f69.google.com (mail-wr1-f69.google.com\n\t[209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-103-GaDLI7zjPVOupuuLcks5Qw-1; Tue, 03 Mar 2026 08:26:26 -0500","by mail-wr1-f69.google.com with SMTP id\n\tffacd0b85a97d-439b484ee04so1352874f8f.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 03 Mar 2026 05:26:25 -0800 (PST)","from mzamazal-thinkpadp1gen7.tpbc.csb\n\t(ip-77-48-47-2.net.vodafone.cz. [77.48.47.2])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-439bb686a32sm10459790f8f.13.2026.03.03.05.26.22\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 03 Mar 2026 05:26:22 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"EcSiD3eG\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1772544387;\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\tin-reply-to:in-reply-to:references:references;\n\tbh=dsjZWTnn5EWAoy92dCDVW0I4S8aFAX8FYdL5V/tj9mU=;\n\tb=EcSiD3eGf0Pl1R9d12m50OtbFg3Wlnwf1rKe641z/uImjEC/cql2mzG6HujeEgJFmf4if3\n\tLvQISXC7mB3Dg3JG0J8OXcg+e8lN86nFhK4yeyIjXdwMPzF92qQj8lBqSD7yfq/p0yNx8c\n\thZxXogkjC/Ojg8fWFmuG8o0sjFCC0W0=","X-MC-Unique":"GaDLI7zjPVOupuuLcks5Qw-1","X-Mimecast-MFC-AGG-ID":"GaDLI7zjPVOupuuLcks5Qw_1772544385","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1772544384; x=1773149184;\n\th=mime-version:user-agent:message-id:date:references:in-reply-to\n\t:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject\n\t:date:message-id:reply-to;\n\tbh=dsjZWTnn5EWAoy92dCDVW0I4S8aFAX8FYdL5V/tj9mU=;\n\tb=xAb8lWh+YhWPKftyARdVJLTXDexftnc4CCY/MQ2D+v1zwqnLHCeZ10ENHrYLj/pVsc\n\tMRIANw16trJ88i5s4qnXeSOJXxMBacIkH1V28HCdUZsIBaPAX8LdmYeoKg+LJiiMVszO\n\tB+NYJZzyMJJ3k9qfnGr/Eak7VN1LfbMSbQeTZyineqr65wkJOPN5CHiYebcirIKnTeaP\n\tYO3XMSMXwpGTy+JHfdIBLxuyphv9mx7pzC1AgHvMTzocpqNM08ltAqtktGtco/GUmgmr\n\tVBBPXzf4VpRU4cmZcrMQOCZL4lh9+rYy8FbGX3zrbC9RDElwIGC86OoDqYang4HHlBjg\n\tvspg==","X-Gm-Message-State":"AOJu0Yx1RMC2sG3tW37kvuDuT1WVpXXVyKgEEBI9f2AbVx5dCZ0YGU7A\n\tyvvh9fdRCqPFPsEbHCGmFrrjYfGG5Dw3Gp+WAvAad/lLzbowaSrjJZjTBK+f0R9hY4NXyV/ebpH\n\tWeslN6zYdjKCX6ZMXhJVpvx+bdbM6oUyK/f+wgRHAPKbkZFIUkExx5N4TMxRxIF60z0ht9qdKFp\n\t5XYoQS2R7QJlufZsAcTXrYva9XG45RMXSU6fnjSF9BwaUuwX6TNxYYEbTwWtg=","X-Gm-Gg":"ATEYQzzWo4WMxiiOMftzMW794bgLB9t2ZtThdSnpm3cX5OXcm8Crcrdz1TVP/E/UnC0\n\t9uaGbC5RAh/DdKVCfqpEZnleQf+dBOxcEVropZR1eIsLqyTVPN24zoW/TnlarxNQVeiBw7HmFbT\n\t2mpc1CbaoWAWvMpwY9+D1g8ElbK3asYsNkYGxJ+tUxiW65Fu4w9yRLgaIWIPAcmXoIIczDA8eJw\n\ttDkTN8hxqhoGrPJGi8FO7oBQa5psgsZ4QXZ4zLLVA5H9J4p9VoR29CvsnJ6eJY60MDicgmZnOiG\n\tH5DYyYVrAmq3Jrv0tspCM98hDu6+GlUTYMnvdLA3l5tn2DM7C1e9ChetgLDG9iljG+/otKRrbs5\n\t5JskGUruAGxVBzrJfFCd1yAOjXfcraAkDRCMjZN0QZPt5C+DHSupkP9DdPlMbjzS84/rVOnqRFU\n\tM=","X-Received":["by 2002:a05:6000:288b:b0:439:c4d1:8755 with SMTP id\n\tffacd0b85a97d-439c4d18bcdmr1078155f8f.9.1772544384361; \n\tTue, 03 Mar 2026 05:26:24 -0800 (PST)","by 2002:a05:6000:288b:b0:439:c4d1:8755 with SMTP id\n\tffacd0b85a97d-439c4d18bcdmr1078095f8f.9.1772544383784; \n\tTue, 03 Mar 2026 05:26:23 -0800 (PST)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"Hans de Goede <johannes.goede@oss.qualcomm.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v4 3/4] software_isp: debayer_cpu: Add multi-threading\n\tsupport","In-Reply-To":"<20260303111741.17417-4-johannes.goede@oss.qualcomm.com> (Hans\n\tde Goede's message of \"Tue, 3 Mar 2026 12:17:40 +0100\")","References":"<20260303111741.17417-1-johannes.goede@oss.qualcomm.com>\n\t<20260303111741.17417-4-johannes.goede@oss.qualcomm.com>","Date":"Tue, 03 Mar 2026 14:26:21 +0100","Message-ID":"<854imx6o3m.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"hd55D7q116-2tz9S0zlqIqh4oqbcF1KZGMZlZVlaNKc_1772544385","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain","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>"}},{"id":38321,"web_url":"https://patchwork.libcamera.org/comment/38321/","msgid":"<0bc1ea57-175d-4ee2-bec7-dfd2779706f1@oss.qualcomm.com>","date":"2026-03-03T14:03:00","subject":"Re: [PATCH v4 3/4] software_isp: debayer_cpu: Add multi-threading\n\tsupport","submitter":{"id":242,"url":"https://patchwork.libcamera.org/api/people/242/","name":"Hans de Goede","email":"johannes.goede@oss.qualcomm.com"},"content":"Hi,\n\nOn 3-Mar-26 14:26, Milan Zamazal wrote:\n> Hi Hans,\n> \n> thank you for the update.\n> \n> Hans de Goede <johannes.goede@oss.qualcomm.com> writes:\n> \n>> Add CPU soft ISP multi-threading support.\n>>\n>> Benchmark results for the Arduino Uno-Q with a weak CPU which is good for\n>> performance testing, all numbers with an IMX219 running at\n>> 3280x2464 -> 3272x2464:\n>>\n>> 1 thread : 147ms / frame, ~6.5 fps\n>> 2 threads:  80ms / frame, ~12.5 fps\n>> 3 threads:  65ms / frame, ~15 fps\n>>\n>> Adding a 4th thread does not improve performance.\n>>\n>> Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>\n>> ---\n>> Changes in v4:\n>> - Document \"software_isp\", \"threads\" option in runtime_configuration.rst\n>> - Add an use constants for min/max/default number of threads\n>>\n>> Changes in v3:\n>> - Adjust for DebayerCpuThread now inheriting from Thread\n>> - Use for (auto &thread : threads_)\n>>\n>> Changes in v2:\n>> - Adjust to use the new DebayerCpuThread class introduced in the v2 patch-series\n>> - Re-use threads instead of starting new threads every frame\n>> ---\n>>  Documentation/runtime_configuration.rst    |  1 +\n>>  src/libcamera/software_isp/debayer_cpu.cpp | 45 ++++++++++++++++++++--\n>>  src/libcamera/software_isp/debayer_cpu.h   | 10 +++++\n>>  3 files changed, 53 insertions(+), 3 deletions(-)\n>>\n>> diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst\n>> index e99ef2fb9..07d1a9123 100644\n>> --- a/Documentation/runtime_configuration.rst\n>> +++ b/Documentation/runtime_configuration.rst\n>> @@ -51,6 +51,7 @@ file structure:\n>>        measure:\n>>          skip: # non-negative integer, frames to skip initially\n>>          number: # non-negative integer, frames to measure\n>> +      threads: # integer >= 1, number of render threads to use, default 2\n> \n> In addition to being added to this overview, the option should be\n> documented in \"List of variables and configuration options\" later in the\n> file.  The limits on the value range can be described there.\n\nAck, will fix for v5.\n\n>>  Configuration file example\n>>  --------------------------\n>> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n>> index d57d640df..f7c3e1751 100644\n>> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n>> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n>> @@ -76,6 +76,7 @@ DebayerCpuThread::DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex\n>>  \t  debayer_(debayer), threadIndex_(threadIndex),\n>>  \t  enableInputMemcpy_(enableInputMemcpy)\n>>  {\n>> +\tmoveToThread(this);\n>>  }\n>>  \n>>  /**\n>> @@ -107,8 +108,10 @@ DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats, const GlobalConfigurat\n>>  \tbool enableInputMemcpy =\n>>  \t\tconfiguration.option<bool>({ \"software_isp\", \"copy_input_buffer\" }).value_or(true);\n>>  \n>> -\t/* Just one thread object for now, which will be called inline rather than async */\n>> -\tthreads_.resize(1);\n>> +\tunsigned int threadCount =\n>> +\t\tconfiguration.option<unsigned int>({ \"software_isp\", \"threads\" }).value_or(kDefaultThreads);\n>> +\tthreadCount = std::clamp(threadCount, kMinThreads, kMaxThreads);\n> \n> Should there be an INFO log message in case the specified number of\n> threads gets changed due to the clamping?\n\nI did consider that when writing this, but I consider it unnecessary verbose,\nunnecessary complication of the code to add this.\n\nStill I can add it if you wish. If you let me know if you want an Info message\nor ok with omitting it then I'll prepare a v5 addressing your other comment.\n\nRegards,\n\nHans\n\n\n\n\n> \n>> +\tthreads_.resize(threadCount);\n>>  \n>>  \tfor (unsigned int i = 0; i < threads_.size(); i++)\n>>  \t\tthreads_[i] = std::make_unique<DebayerCpuThread>(this, i, enableInputMemcpy);\n>> @@ -746,6 +749,11 @@ void DebayerCpuThread::process(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>>  \t\tprocess2(frame, src, dst);\n>>  \telse\n>>  \t\tprocess4(frame, src, dst);\n>> +\n>> +\tdebayer_->workPendingMutex_.lock();\n>> +\tdebayer_->workPending_ &= ~(1 << threadIndex_);\n>> +\tdebayer_->workPendingMutex_.unlock();\n>> +\tdebayer_->workPendingCv_.notify_one();\n>>  }\n>>  \n>>  void DebayerCpuThread::process2(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>> @@ -985,7 +993,21 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>>  \n>>  \tstats_->startFrame(frame);\n>>  \n>> -\tthreads_[0]->process(frame, in.planes()[0].data(), out.planes()[0].data());\n>> +\tworkPendingMutex_.lock();\n>> +\tworkPending_ = (1 << threads_.size()) - 1;\n>> +\tworkPendingMutex_.unlock();\n>> +\n>> +\tfor (auto &thread : threads_)\n>> +\t\tthread->invokeMethod(&DebayerCpuThread::process,\n>> +\t\t\t\t     ConnectionTypeQueued, frame,\n>> +\t\t\t\t     in.planes()[0].data(), out.planes()[0].data());\n>> +\n>> +\t{\n>> +\t\tMutexLocker locker(workPendingMutex_);\n>> +\t\tworkPendingCv_.wait(locker, [&]() LIBCAMERA_TSA_REQUIRES(workPendingMutex_) {\n>> +\t\t\treturn workPending_ == 0;\n>> +\t\t});\n>> +\t}\n>>  \n>>  \tmetadata.planes()[0].bytesused = out.planes()[0].size();\n>>  \n>> @@ -1004,6 +1026,23 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>>  \tinputBufferReady.emit(input);\n>>  }\n>>  \n>> +int DebayerCpu::start()\n>> +{\n>> +\tfor (auto &thread : threads_)\n>> +\t\tthread->start();\n>> +\n>> +\treturn 0;\n>> +}\n>> +\n>> +void DebayerCpu::stop()\n>> +{\n>> +\tfor (auto &thread : threads_)\n>> +\t\tthread->exit();\n>> +\n>> +\tfor (auto &thread : threads_)\n>> +\t\tthread->wait();\n>> +}\n>> +\n>>  SizeRange DebayerCpu::sizes(PixelFormat inputFormat, const Size &inputSize)\n>>  {\n>>  \tSize patternSize = this->patternSize(inputFormat);\n>> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n>> index 780576090..11280c0a1 100644\n>> --- a/src/libcamera/software_isp/debayer_cpu.h\n>> +++ b/src/libcamera/software_isp/debayer_cpu.h\n>> @@ -16,6 +16,7 @@\n>>  #include <vector>\n>>  \n>>  #include <libcamera/base/object.h>\n>> +#include <libcamera/base/mutex.h>\n>>  \n>>  #include \"libcamera/internal/bayer_format.h\"\n>>  #include \"libcamera/internal/global_configuration.h\"\n>> @@ -41,6 +42,8 @@ public:\n>>  \tstd::tuple<unsigned int, unsigned int>\n>>  \tstrideAndFrameSize(const PixelFormat &outputFormat, const Size &size);\n>>  \tvoid process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams &params);\n>> +\tint start();\n>> +\tvoid stop();\n>>  \tSizeRange sizes(PixelFormat inputFormat, const Size &inputSize);\n>>  \tconst SharedFD &getStatsFD() { return stats_->getStatsFD(); }\n>>  \n>> @@ -144,6 +147,13 @@ private:\n>>  \tstd::unique_ptr<SwStatsCpu> stats_;\n>>  \tunsigned int xShift_; /* Offset of 0/1 applied to window_.x */\n>>  \n>> +\tstatic constexpr unsigned int kMinThreads = 1;\n>> +\tstatic constexpr unsigned int kMaxThreads = 8;\n>> +\tstatic constexpr unsigned int kDefaultThreads = 2;\n>> +\n>> +\tunsigned int workPending_ LIBCAMERA_TSA_GUARDED_BY(workPendingMutex_);\n>> +\tMutex workPendingMutex_;\n>> +\tConditionVariable workPendingCv_;\n>>  \tstd::vector<std::unique_ptr<DebayerCpuThread>>threads_;\n>>  };\n>","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 CE09EC0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  3 Mar 2026 14:03:16 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 135B562385;\n\tTue,  3 Mar 2026 15:03:16 +0100 (CET)","from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com\n\t[205.220.180.131])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7DD5762010\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  3 Mar 2026 15:03:13 +0100 (CET)","from pps.filterd (m0279873.ppops.net [127.0.0.1])\n\tby mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id\n\t6239moYX2307603 for <libcamera-devel@lists.libcamera.org>;\n\tTue, 3 Mar 2026 14:03:12 GMT","from mail-ot1-f72.google.com (mail-ot1-f72.google.com\n\t[209.85.210.72])\n\tby mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4cnvtu8u5g-1\n\t(version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT)\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 03 Mar 2026 14:03:12 +0000 (GMT)","by mail-ot1-f72.google.com with SMTP id\n\t46e09a7af769-7d4bd83e456so68260270a34.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 03 Mar 2026 06:03:11 -0800 (PST)","from ?IPV6:2001:1c00:c32:7800:5bfa:a036:83f0:f9ec?\n\t(2001-1c00-0c32-7800-5bfa-a036-83f0-f9ec.cable.dynamic.v6.ziggo.nl.\n\t[2001:1c00:c32:7800:5bfa:a036:83f0:f9ec])\n\tby smtp.gmail.com with ESMTPSA id\n\t4fb4d7f45d1cf-66005566561sm3050515a12.30.2026.03.03.06.03.09\n\t(version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n\tTue, 03 Mar 2026 06:03:09 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=qualcomm.com header.i=@qualcomm.com\n\theader.b=\"Xoq66/NZ\"; dkim=pass (2048-bit key;\n\tunprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com\n\theader.b=\"hN4h+bm3\"; dkim-atps=neutral","DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h=\n\tcc:content-transfer-encoding:content-type:date:from:in-reply-to\n\t:message-id:mime-version:references:subject:to; s=qcppdkim1; bh=\n\tyMPWY0mM0mTOv/L/nz/6Trggnr4dwBVEnXNVVOiMyz8=; b=Xoq66/NZh3oVY3k+\n\tKuCiJPe5z1aWz9zNV11QIW2WElApJ1F1u4+RGb0iQyFrRh+o3PzSRlSYr1QOkqgx\n\trTeL7HwYEDa1eAHWFasgpPO/uBw9hsyQzeA80GI38ExUBfcP951hNrA9a20gMiOZ\n\tsrlggPTNB7AfORpjhK7QDxr5AC+q9Hsksr9IgT5wtZ4DQV/OZfJZaPVITEV1Tdoa\n\tmSiQKg7FVLPz5NvbU0kxc8qiUCzNpXlF23uMEXvVUQ0BFz2Xqgk1zvLS+YHqWGhO\n\tXTVNtbnKV6y8mz1UBOVk/3L314OjNUO4dddRW2iGQw0TILYNvPZ57h2qoQoYDnJz\n\tL0qzGA==","v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=oss.qualcomm.com; s=google; t=1772546591; x=1773151391;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:in-reply-to:content-language:references\n\t:cc:to:subject:from:user-agent:mime-version:date:message-id:from:to\n\t:cc:subject:date:message-id:reply-to;\n\tbh=yMPWY0mM0mTOv/L/nz/6Trggnr4dwBVEnXNVVOiMyz8=;\n\tb=hN4h+bm33SZtDDCF8xJ0eZsE3Cn2vr047aY+0ga5r/CigtgXHJL/+WYBu51Mk+fWyI\n\thfEuEI1/IXbpiI0qobtxFfVfRJSG86PIzqDHBWYAhHpJO9QYeMrQ1nG3oOnopks3D94o\n\tZtwKt9zmo1mfCRfTQkA9LnCD/JNmeqrt3Dy87vwDlV08LjC9cyQ38nhgd3B7u1CGEfTY\n\taqLfu0Pq00Qr5wWNBdq9oCukTBOj92GO/6p0pc1sdUX2tY9mjWkjjibkO8XkK4MoOBh9\n\tXpFS+R+jJf3cQAIxv/qhoyXYHF4L4R1XWuk6ccYTYejy5c6Ne7jQ9PNlT/AXHPNvLjjR\n\tlLxA=="],"X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1772546591; x=1773151391;\n\th=content-transfer-encoding:in-reply-to:content-language:references\n\t:cc:to:subject:from:user-agent:mime-version:date:message-id:x-gm-gg\n\t:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;\n\tbh=yMPWY0mM0mTOv/L/nz/6Trggnr4dwBVEnXNVVOiMyz8=;\n\tb=KszEDynU0HQ6smAdTPQw3OgIvzdKGlCDro/ZOj6h5UXeJKVjj8rteYNPptHoV/RHZh\n\tj1iSHIqkq/VIGZG1gjaw72SWYTyo7D8CK735wt+SqAJ07S2Rg35HahcXT/9jX2THwMop\n\tgD5dVB09RNsKC+Vg7akxX1LxGScadHPZiU5tNa3wLqj1Ry9JWb4OL4FlxCIFyzM/R6wq\n\tJCw527D28OS5hIJFd+6DaDTSJ2YTs9uZqMLRpjZkaexYhqWsAl7eFnSsGgTJZRUHCdtX\n\tOuzZbGxs1zjBHS+1jBeOidgX0wVrE7BqulIPYK4rUhSV88oGXH+7260q3nND0a+l4l+M\n\tdQaA==","X-Gm-Message-State":"AOJu0YxX828XvcrxOBKOYqoPTsg2x8bxqPV4+l8U92YizTf6e6+1Zrpp\n\tUlxyRDnRMh4a8gn61SXj8yKBvhsM9Gtm6pjsym+LaW8l0T68FxzTZ6C5PMaj90o/2MZlOJu+0FC\n\t2JH41OyOZ7ELo/1LsOhyVWDq9tIXXvyIre/li/7e71SWXpsNmJFRAYVJiqFcarrVhMp6+A/WEW3\n\t8F","X-Gm-Gg":"ATEYQzxh9AXMvrKdSulI6vwrjHpssISeap8CuyMWkN4/PqI7/v3pmEDkZW4xKYTj4XX\n\tdl+Pqm6CiirCahIsacgFYkj/pjFNfFX5AnOZXdCVFpLqvISxqr5mgpgqrzZUb+qEY6EG2OKnGIa\n\tLaLv1siY+X7Zu/QmkPknwYeV1n6xkP68D1B3+sfhNJ6B2b6HmV5rZyF9O1TIO1/kOYmdheb3e45\n\tQdYUOFhm8Ei9bwYWSHMcmLgHe/1gTtPPv3ilIR3WMEvdFSXiSdUbyRxCHv4C2vcXpNciy0T/KKM\n\tgAy4CNpnG9chFiM5mCTCSr+OCUr1NNIsOZVhCmDLg7JYwqVlaQHYokvd4u4XBvxgH2uFRQC5A6N\n\t3ZpB6UL9cyQQYShjo0+Z1kicVtBPjA3Cz5tF9bc0nysBmxA8a579hA4DAVPOWh+kWDpPGdAQWv/\n\tGEN4jzPH8PXZzSDfRdRm6b0VAF22444ioiKdKeSlvajmZ5bCm6YyDS2xfkIdfoI+G5TOQ8khF+X\n\tcpt+TNMY0GwVDOR","X-Received":["by 2002:a05:6830:6f86:b0:7c6:cf19:1df1 with SMTP id\n\t46e09a7af769-7d591c0ab7emr8585622a34.30.1772546591093; \n\tTue, 03 Mar 2026 06:03:11 -0800 (PST)","by 2002:a05:6830:6f86:b0:7c6:cf19:1df1 with SMTP id\n\t46e09a7af769-7d591c0ab7emr8585587a34.30.1772546590514; \n\tTue, 03 Mar 2026 06:03:10 -0800 (PST)"],"Message-ID":"<0bc1ea57-175d-4ee2-bec7-dfd2779706f1@oss.qualcomm.com>","Date":"Tue, 3 Mar 2026 15:03:00 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","From":"Hans de Goede <johannes.goede@oss.qualcomm.com>","Subject":"Re: [PATCH v4 3/4] software_isp: debayer_cpu: Add multi-threading\n\tsupport","To":"Milan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20260303111741.17417-1-johannes.goede@oss.qualcomm.com>\n\t<20260303111741.17417-4-johannes.goede@oss.qualcomm.com>\n\t<854imx6o3m.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","Content-Language":"en-US, nl","In-Reply-To":"<854imx6o3m.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"7bit","X-Proofpoint-GUID":"IWTE5a-3zNrFQfMQMmPIu0-mzHGkGF-8","X-Proofpoint-ORIG-GUID":"IWTE5a-3zNrFQfMQMmPIu0-mzHGkGF-8","X-Authority-Analysis":"v=2.4 cv=A75h/qWG c=1 sm=1 tr=0 ts=69a6ea20 cx=c_pps\n\ta=+3WqYijBVYhDct2f5Fivkw==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10\n\ta=Yq5XynenixoA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22\n\ta=u7WPNUs3qKkmUXheDGA7:22 a=rJkE3RaqiGZ5pbrm-msn:22 a=EUspDBNiAAAA:8\n\ta=NARXSNKdXS6s_1JLEMkA:9 a=QEXdDO2ut3YA:10 a=eYe2g0i6gJ5uXG_o6N4q:22","X-Proofpoint-Spam-Details-Enc":"AW1haW4tMjYwMzAzMDExMSBTYWx0ZWRfX5aSQ4txdd2f+\n\tJv4E3WtRCF7AuGkdxtxoxDd/2jdc2td4xJXDBufNO2YsZJehJf3mtL9bmg5r233lrIAmRrignKx\n\tLb1W+fc0UxTa8Tiyp20igmSU68gc8E1HWwag3c9lkVnJiXErL/zjy+47mK8M4jHglw1v0aoBwkw\n\tjEOtlO1Uhm9fGiQ/Z0EwhOPpDODRMiMV8dcb2FjreYkywWMJoRoOdVM+uMJN0K5HTrVYf2UiLzP\n\tIKXr7lJSWLl/g3a2mXEFyKuHmxcNynF2K0LS4Dfg9MMV6kBIPofnHMv8Nu9D/joglZj7tyWX1jC\n\tP+aDidaL+41t217d9AVHqLigDj56moNDj2iaUkpaq6AnDAkyLg81PDzPjeG/DIAPyjscjIhELYh\n\txP0sh2axnLTyU57ZTEohlMaMqgymCg1z8J1ptuIeW/XfvIL1x+3q9dBx+bKPlJUJY1GFobU4W2W\n\t2P6KYbcSk6p5LCtZLwA==","X-Proofpoint-Virus-Version":"vendor=baseguard\n\tengine=ICAP:2.0.293, Aquarius:18.0.1121, Hydra:6.1.51,\n\tFMLib:17.12.100.49\n\tdefinitions=2026-03-02_05,2026-03-03_01,2025-10-01_01","X-Proofpoint-Spam-Details":"rule=outbound_notspam policy=outbound score=0\n\timpostorscore=0 spamscore=0 lowpriorityscore=0 suspectscore=0\n\tphishscore=0\n\tadultscore=0 clxscore=1015 bulkscore=0 malwarescore=0\n\tpriorityscore=1501\n\tclassifier=typeunknown authscore=0 authtc= authcc= route=outbound\n\tadjust=0\n\treason=mlx scancount=1 engine=8.22.0-2602130000\n\tdefinitions=main-2603030111","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>"}},{"id":38322,"web_url":"https://patchwork.libcamera.org/comment/38322/","msgid":"<85zf4p55mo.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-03-03T14:50:39","subject":"Re: [PATCH v4 3/4] software_isp: debayer_cpu: Add multi-threading\n\tsupport","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Hans de Goede <johannes.goede@oss.qualcomm.com> writes:\n\n> Hi,\n>\n> On 3-Mar-26 14:26, Milan Zamazal wrote:\n>> Hi Hans,\n>> \n>> thank you for the update.\n>> \n>> Hans de Goede <johannes.goede@oss.qualcomm.com> writes:\n>> \n>>> Add CPU soft ISP multi-threading support.\n>>>\n>>> Benchmark results for the Arduino Uno-Q with a weak CPU which is good for\n>>> performance testing, all numbers with an IMX219 running at\n>>> 3280x2464 -> 3272x2464:\n>>>\n>>> 1 thread : 147ms / frame, ~6.5 fps\n>>> 2 threads:  80ms / frame, ~12.5 fps\n>>> 3 threads:  65ms / frame, ~15 fps\n>>>\n>>> Adding a 4th thread does not improve performance.\n>>>\n>>> Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>\n>>> ---\n>>> Changes in v4:\n>>> - Document \"software_isp\", \"threads\" option in runtime_configuration.rst\n>>> - Add an use constants for min/max/default number of threads\n>>>\n>>> Changes in v3:\n>>> - Adjust for DebayerCpuThread now inheriting from Thread\n>>> - Use for (auto &thread : threads_)\n>>>\n>>> Changes in v2:\n>>> - Adjust to use the new DebayerCpuThread class introduced in the v2 patch-series\n>>> - Re-use threads instead of starting new threads every frame\n>>> ---\n>>>  Documentation/runtime_configuration.rst    |  1 +\n>>>  src/libcamera/software_isp/debayer_cpu.cpp | 45 ++++++++++++++++++++--\n>>>  src/libcamera/software_isp/debayer_cpu.h   | 10 +++++\n>>>  3 files changed, 53 insertions(+), 3 deletions(-)\n>>>\n>>> diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst\n>>> index e99ef2fb9..07d1a9123 100644\n>>> --- a/Documentation/runtime_configuration.rst\n>>> +++ b/Documentation/runtime_configuration.rst\n>>> @@ -51,6 +51,7 @@ file structure:\n>>>        measure:\n>>>          skip: # non-negative integer, frames to skip initially\n>>>          number: # non-negative integer, frames to measure\n>>> +      threads: # integer >= 1, number of render threads to use, default 2\n>> \n>> In addition to being added to this overview, the option should be\n>> documented in \"List of variables and configuration options\" later in the\n>> file.  The limits on the value range can be described there.\n>\n> Ack, will fix for v5.\n>\n>>>  Configuration file example\n>>>  --------------------------\n>>> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n>>> index d57d640df..f7c3e1751 100644\n>>> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n>>> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n>>> @@ -76,6 +76,7 @@ DebayerCpuThread::DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex\n>>>  \t  debayer_(debayer), threadIndex_(threadIndex),\n>>>  \t  enableInputMemcpy_(enableInputMemcpy)\n>>>  {\n>>> +\tmoveToThread(this);\n>>>  }\n>>>  \n>>>  /**\n>>> @@ -107,8 +108,10 @@ DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats, const GlobalConfigurat\n>>>  \tbool enableInputMemcpy =\n>>>  \t\tconfiguration.option<bool>({ \"software_isp\", \"copy_input_buffer\" }).value_or(true);\n>>>  \n>>> -\t/* Just one thread object for now, which will be called inline rather than async */\n>>> -\tthreads_.resize(1);\n>>> +\tunsigned int threadCount =\n>>> +\t\tconfiguration.option<unsigned int>({ \"software_isp\", \"threads\" }).value_or(kDefaultThreads);\n>>> +\tthreadCount = std::clamp(threadCount, kMinThreads, kMaxThreads);\n>> \n>> Should there be an INFO log message in case the specified number of\n>> threads gets changed due to the clamping?\n>\n> I did consider that when writing this, but I consider it unnecessary verbose,\n> unnecessary complication of the code to add this.\n>\n> Still I can add it if you wish. If you let me know if you want an Info message\n> or ok with omitting it then I'll prepare a v5 addressing your other comment.\n\nI'm OK with omitting the log message if the clamping is clearly\ndocumented in the option description.\n\n> Regards,\n>\n> Hans\n>\n>\n>\n>\n>> \n>>> +\tthreads_.resize(threadCount);\n>>>  \n>>>  \tfor (unsigned int i = 0; i < threads_.size(); i++)\n>>>  \t\tthreads_[i] = std::make_unique<DebayerCpuThread>(this, i, enableInputMemcpy);\n>>> @@ -746,6 +749,11 @@ void DebayerCpuThread::process(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>>>  \t\tprocess2(frame, src, dst);\n>>>  \telse\n>>>  \t\tprocess4(frame, src, dst);\n>>> +\n>>> +\tdebayer_->workPendingMutex_.lock();\n>>> +\tdebayer_->workPending_ &= ~(1 << threadIndex_);\n>>> +\tdebayer_->workPendingMutex_.unlock();\n>>> +\tdebayer_->workPendingCv_.notify_one();\n>>>  }\n>>>  \n>>>  void DebayerCpuThread::process2(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>>> @@ -985,7 +993,21 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>>>  \n>>>  \tstats_->startFrame(frame);\n>>>  \n>>> -\tthreads_[0]->process(frame, in.planes()[0].data(), out.planes()[0].data());\n>>> +\tworkPendingMutex_.lock();\n>>> +\tworkPending_ = (1 << threads_.size()) - 1;\n>>> +\tworkPendingMutex_.unlock();\n>>> +\n>>> +\tfor (auto &thread : threads_)\n>>> +\t\tthread->invokeMethod(&DebayerCpuThread::process,\n>>> +\t\t\t\t     ConnectionTypeQueued, frame,\n>>> +\t\t\t\t     in.planes()[0].data(), out.planes()[0].data());\n>>> +\n>>> +\t{\n>>> +\t\tMutexLocker locker(workPendingMutex_);\n>>> +\t\tworkPendingCv_.wait(locker, [&]() LIBCAMERA_TSA_REQUIRES(workPendingMutex_) {\n>>> +\t\t\treturn workPending_ == 0;\n>>> +\t\t});\n>>> +\t}\n>>>  \n>>>  \tmetadata.planes()[0].bytesused = out.planes()[0].size();\n>>>  \n>>> @@ -1004,6 +1026,23 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>>>  \tinputBufferReady.emit(input);\n>>>  }\n>>>  \n>>> +int DebayerCpu::start()\n>>> +{\n>>> +\tfor (auto &thread : threads_)\n>>> +\t\tthread->start();\n>>> +\n>>> +\treturn 0;\n>>> +}\n>>> +\n>>> +void DebayerCpu::stop()\n>>> +{\n>>> +\tfor (auto &thread : threads_)\n>>> +\t\tthread->exit();\n>>> +\n>>> +\tfor (auto &thread : threads_)\n>>> +\t\tthread->wait();\n>>> +}\n>>> +\n>>>  SizeRange DebayerCpu::sizes(PixelFormat inputFormat, const Size &inputSize)\n>>>  {\n>>>  \tSize patternSize = this->patternSize(inputFormat);\n>>> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n>>> index 780576090..11280c0a1 100644\n>>> --- a/src/libcamera/software_isp/debayer_cpu.h\n>>> +++ b/src/libcamera/software_isp/debayer_cpu.h\n>>> @@ -16,6 +16,7 @@\n>>>  #include <vector>\n>>>  \n>>>  #include <libcamera/base/object.h>\n>>> +#include <libcamera/base/mutex.h>\n>>>  \n>>>  #include \"libcamera/internal/bayer_format.h\"\n>>>  #include \"libcamera/internal/global_configuration.h\"\n>>> @@ -41,6 +42,8 @@ public:\n>>>  \tstd::tuple<unsigned int, unsigned int>\n>>>  \tstrideAndFrameSize(const PixelFormat &outputFormat, const Size &size);\n>>>  \tvoid process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams &params);\n>>> +\tint start();\n>>> +\tvoid stop();\n>>>  \tSizeRange sizes(PixelFormat inputFormat, const Size &inputSize);\n>>>  \tconst SharedFD &getStatsFD() { return stats_->getStatsFD(); }\n>>>  \n>>> @@ -144,6 +147,13 @@ private:\n>>>  \tstd::unique_ptr<SwStatsCpu> stats_;\n>>>  \tunsigned int xShift_; /* Offset of 0/1 applied to window_.x */\n>>>  \n>>> +\tstatic constexpr unsigned int kMinThreads = 1;\n>>> +\tstatic constexpr unsigned int kMaxThreads = 8;\n>>> +\tstatic constexpr unsigned int kDefaultThreads = 2;\n>>> +\n>>> +\tunsigned int workPending_ LIBCAMERA_TSA_GUARDED_BY(workPendingMutex_);\n>>> +\tMutex workPendingMutex_;\n>>> +\tConditionVariable workPendingCv_;\n>>>  \tstd::vector<std::unique_ptr<DebayerCpuThread>>threads_;\n>>>  };\n>>","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 DA90DBE086\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  3 Mar 2026 14:50:49 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1A37762388;\n\tTue,  3 Mar 2026 15:50:49 +0100 (CET)","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 E7B9162010\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  3 Mar 2026 15:50:46 +0100 (CET)","from mail-wr1-f70.google.com (mail-wr1-f70.google.com\n\t[209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-531-93S3XgLENmCmphiPthyPEw-1; Tue, 03 Mar 2026 09:50:44 -0500","by mail-wr1-f70.google.com with SMTP id\n\tffacd0b85a97d-439a85832c0so2309074f8f.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 03 Mar 2026 06:50:43 -0800 (PST)","from mzamazal-thinkpadp1gen7.tpbc.csb\n\t(ip-77-48-47-2.net.vodafone.cz. [77.48.47.2])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-439ab6ebe56sm24499884f8f.15.2026.03.03.06.50.40\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 03 Mar 2026 06:50:40 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"SO5eCztQ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1772549445;\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\tin-reply-to:in-reply-to:references:references;\n\tbh=1EJXLFa93C6mqDYIFloTr3fW/RoeuP0Nw6irwaXU120=;\n\tb=SO5eCztQIhuvkH8m+sKsBJIjx9lpHt5Oer2Y/dWMLtkn18YrtHWJKvBiSKrX8gGWf4jdkk\n\t7TeeKUwLh9P9mUgYuZdOi25qhrd4TO6csx1ntotwTSFq/nc8Vld2gKFnX3iRwyzE7k/yOi\n\tVhBXgDW/+4dTzsL/gLBOOZYuotwTX3Y=","X-MC-Unique":"93S3XgLENmCmphiPthyPEw-1","X-Mimecast-MFC-AGG-ID":"93S3XgLENmCmphiPthyPEw_1772549443","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1772549442; x=1773154242;\n\th=mime-version:user-agent:message-id:date:references:in-reply-to\n\t:subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject\n\t:date:message-id:reply-to;\n\tbh=1EJXLFa93C6mqDYIFloTr3fW/RoeuP0Nw6irwaXU120=;\n\tb=ZPNjIp2p72mpy+N7zJrW7fmZw3xG7G/t0BgcW/UU7rRqg3Pfi6f87/sD8EbtjBFxPu\n\tqgyytyXImkys1c2DxwzkOSeB1jg/O8BetaU9LB+myTPoJFGSSpYJDv4mZj08spjujugo\n\t8tWpiOvDMfIQLKwOy8dvKhoHtTKyn8bexPy/LhvwhLjzEOp0Tb0f4xzeSD0mKeFG9/LC\n\tF7b/8oukc9wes2xP8DtTdAQOggZuRFCg//oEQliOZTDvKdPDamAm9973UgIZzmBw9fcn\n\tIWg4NLy9pEEXM6OyqJL9SMU7L7ffXLD+ayzpzK4bz7l1nKLbUPNDVng8+Kem1lseSedl\n\tnqlA==","X-Gm-Message-State":"AOJu0YxdwkpeM9ccoGT+HfDD7vKDTHQr736MMkdkuy6FovrO6Sm19CPt\n\tcsX5qPpVYVEF0HIUgc3JMQ0Z4Ev4bxYD7s7Q1t8RZ1anHHLGa1DB1A/lDjUmxfnDkIx43GfEiyZ\n\t9eUCtZ/Bk7EpiZyT4R3EZnaor6hC7/9lA6uRkXHG2SdYS7mkGCweiX6UwNsEI3cfWNAW0c5skf0\n\t0l/PmrFh6MzFFAbEEwyY2/SYy8+cpIpF7tA3bicOQg0nxQtB1SNCa0GJ9uMXE=","X-Gm-Gg":"ATEYQzxoelGSQuPpe8ut4839HS3LpYqDSyNQSlF9wR6asbNu/JYHvoN/Z/6ljo0zRxj\n\tJQWAeS2A3uZ+srwuLCfCT+tLgu5vXGRGh0pl/rejGcU4YYKZXMSwoQQ0ulgu8+4G8W6DswNfuPJ\n\trm6HdjTlT/Eax6OW1dXXggcRcUsG8xJkw4PCrs2eGnZNHv3ZO55Tj1B0PHAom2Ovg6HoOUjDq0N\n\tyY7TxC75+P0V4YzKeo1iuF4wBVHWTcJbXbkBNqkW+Xja3tAaFnw6SqNJPY0NjqdhWcCUzn3uIPh\n\t/XmtWmAsKTo6+3idcZkj4+IAAdd6H8X2wu3LXxiih46brLEIEpBKHaL/7YztV/Dgp4L5nrn+jOq\n\tbMuT6U8GJbRCevP9EtOLK6yMMytMu+u9Avr+CA7D/CWgql4ecuwbtb+wbgkIchtTQSrqFzIBF+R\n\tc=","X-Received":["by 2002:a05:6000:2502:b0:439:abcd:b2f6 with SMTP id\n\tffacd0b85a97d-439abcdb576mr20165207f8f.27.1772549442308; \n\tTue, 03 Mar 2026 06:50:42 -0800 (PST)","by 2002:a05:6000:2502:b0:439:abcd:b2f6 with SMTP id\n\tffacd0b85a97d-439abcdb576mr20165155f8f.27.1772549441779; \n\tTue, 03 Mar 2026 06:50:41 -0800 (PST)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"Hans de Goede <johannes.goede@oss.qualcomm.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v4 3/4] software_isp: debayer_cpu: Add multi-threading\n\tsupport","In-Reply-To":"<0bc1ea57-175d-4ee2-bec7-dfd2779706f1@oss.qualcomm.com> (Hans de\n\tGoede's message of \"Tue, 3 Mar 2026 15:03:00 +0100\")","References":"<20260303111741.17417-1-johannes.goede@oss.qualcomm.com>\n\t<20260303111741.17417-4-johannes.goede@oss.qualcomm.com>\n\t<854imx6o3m.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>\n\t<0bc1ea57-175d-4ee2-bec7-dfd2779706f1@oss.qualcomm.com>","Date":"Tue, 03 Mar 2026 15:50:39 +0100","Message-ID":"<85zf4p55mo.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"LBYi29yrvLTjXMomR5SSDUo4UandHv_0WLi23Eyb97Y_1772549443","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain","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>"}}]