[{"id":38323,"web_url":"https://patchwork.libcamera.org/comment/38323/","msgid":"<85ms0n9asy.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-03-04T09:57:33","subject":"Re: [PATCH v5 3/5] 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\nIn my TI AM69 environment and with CCM, 2 CPU threads are about of the\nsame speed as GPU, and the speed increases almost linearly up to all the\n8 threads.  Nice.\n\n> Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>\n\nReviewed-by: Milan Zamazal <mzamazal@redhat.com>\n\n> ---\n> Changes in v5:\n> - Extend software_isp.threads docs in runtime_configuration.rst\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    |  8 ++++\n>  src/libcamera/software_isp/debayer_cpu.cpp | 45 ++++++++++++++++++++--\n>  src/libcamera/software_isp/debayer_cpu.h   | 10 +++++\n>  3 files changed, 60 insertions(+), 3 deletions(-)\n>\n> diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst\n> index e99ef2fb9..651929a4d 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>  Configuration file example\n>  --------------------------\n> @@ -84,6 +85,7 @@ Configuration file example\n>         measure:\n>           skip: 50\n>           number: 30\n> +       threads: 2\n>  \n>  List of variables and configuration options\n>  -------------------------------------------\n> @@ -167,6 +169,12 @@ software_isp.measure.skip, software_isp.measure.number\n>  \n>     Example `number` value: ``30``\n>  \n> +software_isp.threads\n> +   Number of render threads the software ISP uses when using the CPU.\n> +   This must be between 1 and 8 and the default is 2.\n> +\n> +   Example value: ``2``\n> +\n>  Further details\n>  ---------------\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> +\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 3B07CBE086\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  4 Mar 2026 09:57:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5FF4F6239C;\n\tWed,  4 Mar 2026 10:57:42 +0100 (CET)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F2D6D620FA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  4 Mar 2026 10:57:39 +0100 (CET)","from mail-wm1-f72.google.com (mail-wm1-f72.google.com\n\t[209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-152-dPSE7TIwNvuK6-I0xhQz6g-1; Wed, 04 Mar 2026 04:57:37 -0500","by mail-wm1-f72.google.com with SMTP id\n\t5b1f17b1804b1-4836b7c302fso64953485e9.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 04 Mar 2026 01:57:37 -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-4399c60f764sm43255372f8f.3.2026.03.04.01.57.34\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 04 Mar 2026 01:57:34 -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=\"CxiTS9T4\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1772618258;\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=UHSJt0GHZRPNCgURen7rqIzfp0yChJ9kln9X2q/ZN0s=;\n\tb=CxiTS9T4cYGM+Kact9i9+ZQqiBKn/QC8hbJToDNRtdsxO1GflyoI5BorK7MGe0RavyAqTj\n\tp28dHOGHpMsxiN9zxVxRMJYOXiL3e0dl+Xgc3C+ILRojSME3ntzj/iv5BbSeDWKkhNJlq4\n\tyJpPPqoNfjFodx3nufpPH9urIvkoYEI=","X-MC-Unique":"dPSE7TIwNvuK6-I0xhQz6g-1","X-Mimecast-MFC-AGG-ID":"dPSE7TIwNvuK6-I0xhQz6g_1772618256","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1772618256; x=1773223056;\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=UHSJt0GHZRPNCgURen7rqIzfp0yChJ9kln9X2q/ZN0s=;\n\tb=OyQbHyVF9r+4oC6MdUrsFbFxNZzBNJZpR6jMbFUI35qKzcDKU920ptLIkIArm8FTlN\n\tNRgLV3CnIt9r5rs65n9JRhluBfdDtWd3a6Y8Q5nWB5MiVsUKq5XzWfKJdz2dxZ+Nvjbv\n\tS2jWi0rC2Q68IBQ8T2f3YjhaHBWcc7ZeJ2PcK+YVSYC0t/B8ZUfTaVdHi9R5qU0NLp3X\n\tVV48Jf70gcGpgWbTcnJsxDXEF44uCL3smL+I6+MJpDyGOiDlpzKT7km4SzIL5Q3YBGy5\n\th4gtkBhkvuMqoyJzIF/n7kneov8oYFPCCp1rFIwrmjEOJHPnw/VcStfbv/Rtl53OlG4v\n\tLw4A==","X-Gm-Message-State":"AOJu0YwmKDMpEXzJQWf0MNy4v4mShSd9nhKAMWXQBPEch6T1XgeWKhkW\n\tF1XAhAcx1YnQouzqoy2ka5G2i30NhRxw20N66nZOTcoQBMfHhVGlnigCMnrhKflzimHXSZfLUTL\n\tLAKUqVFNrqXWmlJCksk0RhaYLaNNZiDErnelkWswXqUfVeTPPQatKwmBDFNvXFL3RTCBMGA8ENG\n\tvnmfx+oAZc/xJC0r5+KWtdJtx8eB6FVq6YEnRGqbY2fLkB0p0Ip0PdSn1zpeg=","X-Gm-Gg":"ATEYQzwA5+u84iM9W5/BLicH55MBBhep+G88oqPAVGu/Go+8jkCzT3TmIVsYX0K7BGm\n\tAp4mEaGBcR0hE+ojyWiHrQQ6PVN437m0eJaN56Um6jL5Qr1o1tUvcLTevEU7fCXyOrVrnPToFBW\n\t2lv8VxAWxTUnWdgmzar9kLEzxCVepd8DYgLkqobmAkSY6lQzviKmnbWsGWIzFGp5mKI6wkdeILD\n\t61Yirz2RpJvw7/vu6J+TULz7jZVSUJ3dSChvaP+C1arVF3znK66awjopyPIqe+T/dSWbhwjIH0i\n\tbRxOQBUw6+J+ez3+91fcXjiAZBLWKQ4WHourPhP4sPV2OS1P2tBdnVrTTa8k6+67G5/vxifXPMz\n\taWL/MnIgWbe+SK5eNMzRJGPSc8l1J/WQRe30T4iFKOtZzKDBqZ6NAK2ON3R5Gt77QBzxBuBdnhY\n\tA=","X-Received":["by 2002:a5d:64c8:0:b0:439:c157:2573 with SMTP id\n\tffacd0b85a97d-439c8008125mr2686812f8f.58.1772618255627; \n\tWed, 04 Mar 2026 01:57:35 -0800 (PST)","by 2002:a5d:64c8:0:b0:439:c157:2573 with SMTP id\n\tffacd0b85a97d-439c8008125mr2686765f8f.58.1772618255106; \n\tWed, 04 Mar 2026 01:57:35 -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 v5 3/5] software_isp: debayer_cpu: Add multi-threading\n\tsupport","In-Reply-To":"<20260304075052.11599-4-johannes.goede@oss.qualcomm.com> (Hans\n\tde Goede's message of \"Wed, 4 Mar 2026 08:50:50 +0100\")","References":"<20260304075052.11599-1-johannes.goede@oss.qualcomm.com>\n\t<20260304075052.11599-4-johannes.goede@oss.qualcomm.com>","Date":"Wed, 04 Mar 2026 10:57:33 +0100","Message-ID":"<85ms0n9asy.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":"H9VGk_4DR3rbNJrpbMlcl_R1oZM2jnE5N8fIn2pEIx4_1772618256","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":38334,"web_url":"https://patchwork.libcamera.org/comment/38334/","msgid":"<e5e2ee7a-2e4b-4ad8-ad57-c52f763f7f93@ideasonboard.com>","date":"2026-03-04T13:49:16","subject":"Re: [PATCH v5 3/5] software_isp: debayer_cpu: Add multi-threading\n\tsupport","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2026. 03. 04. 8:50 keltezéssel, Hans de Goede írta:\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 v5:\n> - Extend software_isp.threads docs in runtime_configuration.rst\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    |  8 ++++\n>   src/libcamera/software_isp/debayer_cpu.cpp | 45 ++++++++++++++++++++--\n>   src/libcamera/software_isp/debayer_cpu.h   | 10 +++++\n>   3 files changed, 60 insertions(+), 3 deletions(-)\n> \n> diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst\n> index e99ef2fb9..651929a4d 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>   Configuration file example\n>   --------------------------\n> @@ -84,6 +85,7 @@ Configuration file example\n>          measure:\n>            skip: 50\n>            number: 30\n> +       threads: 2\n>   \n>   List of variables and configuration options\n>   -------------------------------------------\n> @@ -167,6 +169,12 @@ software_isp.measure.skip, software_isp.measure.number\n>   \n>      Example `number` value: ``30``\n>   \n> +software_isp.threads\n> +   Number of render threads the software ISP uses when using the CPU.\n> +   This must be between 1 and 8 and the default is 2.\n> +\n> +   Example value: ``2``\n> +\n>   Further details\n>   ---------------\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> +\tthreads_.resize(threadCount);\n\nI know it has been discussed in the context of an \"INFO\" message, but I would really\nlike at least a \"DEBUG\" message about the number of threads.\n\n\nTested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # ThinkPad X1 Yoga Gen 7 + ov2740\n\n\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 A39C7BE086\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  4 Mar 2026 13:49:20 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 56494623A7;\n\tWed,  4 Mar 2026 14:49:20 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8162B62380\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  4 Mar 2026 14:49:19 +0100 (CET)","from [192.168.33.100] (185.182.214.224.nat.pool.zt.hu\n\t[185.182.214.224])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id ED1A9838;\n\tWed,  4 Mar 2026 14:48:16 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"oA0xFtEH\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1772632097;\n\tbh=PdgOJabitVJTTX/LbO9+egSBkeS2k8oQfEQo93Z+NCw=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=oA0xFtEH9Hup075ezg6US8iJZVXkdLuIfbt6OW4e0D6jaztIzGmzgNwwGf2MtEQmQ\n\tP3jWIKMUqfftI/RRbWFc6XsIvDXrBciqOrsnXdsXRXPkvyU2npi5i6YgU+q5LtwMuO\n\tLtRQLd5LssEeCJfCPOZvdYbLBPWHFmQlu+3YdZDU=","Message-ID":"<e5e2ee7a-2e4b-4ad8-ad57-c52f763f7f93@ideasonboard.com>","Date":"Wed, 4 Mar 2026 14:49:16 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v5 3/5] software_isp: debayer_cpu: Add multi-threading\n\tsupport","To":"Hans de Goede <johannes.goede@oss.qualcomm.com>,\n\tlibcamera-devel@lists.libcamera.org, Milan Zamazal <mzamazal@redhat.com>","References":"<20260304075052.11599-1-johannes.goede@oss.qualcomm.com>\n\t<20260304075052.11599-4-johannes.goede@oss.qualcomm.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260304075052.11599-4-johannes.goede@oss.qualcomm.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]