[{"id":38301,"web_url":"https://patchwork.libcamera.org/comment/38301/","msgid":"<855x7lc7sv.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-02-25T12:43:44","subject":"Re: [PATCH v3 2/4] software_isp: debayer_cpu: Add DebayerCpuThread\n\tclass","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> Add a DebayerCpuThreadclass and use this in the inner render loop.\n> This contains data which needs to be separate per thread.\n>\n> This is a preparation patch for making DebayerCpu support multi-threading.\n>\n> Benchmarking on the Arduino Uno-Q with a weak CPU which is good for\n> performance testing, shows 146-147ms per 3272x2464 frame both before and\n> after this change, with things maybe being 0.5 ms slower after this change.\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 v3:\n> - Use std::unique_ptr for the DebayerCpuThread pointers\n> - Document new DebayerCpuThread class\n> - Make DebayerCpuThread inherit from both Thread and Object\n>\n> Changes in v2:\n> - Replace the DebayerCpuThreadData struct from v1 with a DebayerCpuThread\n>   class, derived from Object to allow calling invokeMethod for thread re-use\n>   in followup patches\n> - As part of this also move a bunch of methods which primarily deal with\n>   per thread data: setupInputMemcpy(), shiftLinePointers(), memcpyNextLine(),\n>   process*() to the new DebayerCpuThread class\n> ---\n>  src/libcamera/software_isp/debayer_cpu.cpp | 244 +++++++++++++++------\n>  src/libcamera/software_isp/debayer_cpu.h   |  20 +-\n>  2 files changed, 188 insertions(+), 76 deletions(-)\n>\n> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n> index e7b01210..36b7881b 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n> @@ -18,6 +18,8 @@\n>  \n>  #include <linux/dma-buf.h>\n>  \n> +#include <libcamera/base/thread.h>\n> +\n>  #include <libcamera/formats.h>\n>  \n>  #include \"libcamera/internal/bayer_format.h\"\n> @@ -27,6 +29,52 @@\n>  \n>  namespace libcamera {\n>  \n> +/**\n> + * \\brief Class representing one CPU debayering thread\n> + *\n> + * Implementation for CPU based debayering threads.\n> + */\n> +class DebayerCpuThread : public Thread, public Object\n> +{\n> +public:\n> +\tDebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex,\n> +\t\t\t bool enableInputMemcpy);\n> +\n> +\tvoid configure(unsigned int yStart, unsigned int yEnd);\n> +\tvoid process(uint32_t frame, const uint8_t *src, uint8_t *dst);\n> +\n> +private:\n> +\tvoid setupInputMemcpy(const uint8_t *linePointers[]);\n> +\tvoid shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src);\n> +\tvoid memcpyNextLine(const uint8_t *linePointers[]);\n> +\tvoid process2(uint32_t frame, const uint8_t *src, uint8_t *dst);\n> +\tvoid process4(uint32_t frame, const uint8_t *src, uint8_t *dst);\n> +\n> +\tDebayerCpu *debayer_;\n> +\tunsigned int threadIndex_;\n> +\tunsigned int yStart_;\n> +\tunsigned int yEnd_;\n> +\tunsigned int lineBufferLength_;\n> +\tunsigned int lineBufferPadding_;\n> +\tunsigned int lineBufferIndex_;\n> +\tstd::vector<uint8_t> lineBuffers_[DebayerCpu::kMaxLineBuffers];\n> +\tbool enableInputMemcpy_;\n> +};\n> +\n> +/**\n> + * \\brief Construct a DebayerCpuThread object\n> + * \\param[in] debayer pointer back to the DebayerCpuObject this thread belongs to\n> + * \\param[in] threadIndex 0 .. n thread-index value for the thread\n> + * \\param[in] enableInputMemcpy when set copy input data to a heap buffer before use\n> + */\n> +DebayerCpuThread::DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex,\n> +\t\t\t\t   bool enableInputMemcpy)\n> +\t: Thread(\"DebayerCpu:\" + std::to_string(threadIndex)),\n> +\t  debayer_(debayer), threadIndex_(threadIndex),\n> +\t  enableInputMemcpy_(enableInputMemcpy)\n> +{\n> +}\n> +\n>  /**\n>   * \\class DebayerCpu\n>   * \\brief Class for debayering on the CPU\n> @@ -53,8 +101,14 @@ DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats, const GlobalConfigurat\n>  \t * \\todo Make memcpy automatic based on runtime detection of platform\n>  \t * capabilities.\n>  \t */\n> -\tenableInputMemcpy_ =\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> +\n> +\tfor (unsigned int i = 0; i < threads_.size(); i++)\n> +\t\tthreads_[i] = std::make_unique<DebayerCpuThread>(this, i, enableInputMemcpy);\n>  }\n>  \n>  DebayerCpu::~DebayerCpu() = default;\n> @@ -484,7 +538,7 @@ int DebayerCpu::configure(const StreamConfiguration &inputCfg,\n>  \tif (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0)\n>  \t\treturn -EINVAL;\n>  \n> -\tif (stats_->configure(inputCfg) != 0)\n> +\tif (stats_->configure(inputCfg, threads_.size()) != 0)\n>  \t\treturn -EINVAL;\n>  \n>  \tconst Size &statsPatternSize = stats_->patternSize();\n> @@ -548,17 +602,43 @@ int DebayerCpu::configure(const StreamConfiguration &inputCfg,\n>  \t */\n>  \tstats_->setWindow(Rectangle(window_.size()));\n>  \n> +\tunsigned int yStart = 0;\n> +\tunsigned int linesPerThread = (window_.height / threads_.size()) &\n> +\t\t\t\t      ~(inputConfig_.patternSize.height - 1);\n> +\tunsigned int i;\n> +\n> +\tfor (i = 0; i < (threads_.size() - 1); i++) {\n> +\t\tthreads_[i]->configure(yStart, yStart + linesPerThread);\n> +\t\tyStart += linesPerThread;\n> +\t}\n> +\tthreads_[i]->configure(yStart, window_.height);\n> +\n> +\treturn 0;\n> +}\n> +\n> +/**\n> + * \\brief Configure thread to process a specific part of the image\n> + * \\param[in] yStart y coordinate of first line to process\n> + * \\param[in] yEnd y coordinate of the line at which to stop processing\n> + *\n> + * Configure the thread to process lines yStart - (yEnd - 1).\n> + */\n> +void DebayerCpuThread::configure(unsigned int yStart, unsigned int yEnd)\n> +{\n> +\tDebayer::DebayerInputConfig &inputConfig = debayer_->inputConfig_;\n> +\n> +\tyStart_ = yStart;\n> +\tyEnd_ = yEnd;\n> +\n>  \t/* pad with patternSize.Width on both left and right side */\n> -\tlineBufferPadding_ = inputConfig_.patternSize.width * inputConfig_.bpp / 8;\n> -\tlineBufferLength_ = window_.width * inputConfig_.bpp / 8 +\n> +\tlineBufferPadding_ = inputConfig.patternSize.width * inputConfig.bpp / 8;\n> +\tlineBufferLength_ = debayer_->window_.width * inputConfig.bpp / 8 +\n>  \t\t\t    2 * lineBufferPadding_;\n>  \n>  \tif (enableInputMemcpy_) {\n> -\t\tfor (unsigned int i = 0; i <= inputConfig_.patternSize.height; i++)\n> +\t\tfor (unsigned int i = 0; i <= inputConfig.patternSize.height; i++)\n>  \t\t\tlineBuffers_[i].resize(lineBufferLength_);\n>  \t}\n> -\n> -\treturn 0;\n>  }\n>  \n>  /*\n> @@ -599,9 +679,9 @@ DebayerCpu::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size\n>  \treturn std::make_tuple(stride, stride * size.height);\n>  }\n>  \n> -void DebayerCpu::setupInputMemcpy(const uint8_t *linePointers[])\n> +void DebayerCpuThread::setupInputMemcpy(const uint8_t *linePointers[])\n>  {\n> -\tconst unsigned int patternHeight = inputConfig_.patternSize.height;\n> +\tconst unsigned int patternHeight = debayer_->inputConfig_.patternSize.height;\n>  \n>  \tif (!enableInputMemcpy_)\n>  \t\treturn;\n> @@ -617,20 +697,20 @@ void DebayerCpu::setupInputMemcpy(const uint8_t *linePointers[])\n>  \tlineBufferIndex_ = patternHeight;\n>  }\n>  \n> -void DebayerCpu::shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src)\n> +void DebayerCpuThread::shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src)\n>  {\n> -\tconst unsigned int patternHeight = inputConfig_.patternSize.height;\n> +\tconst unsigned int patternHeight = debayer_->inputConfig_.patternSize.height;\n>  \n>  \tfor (unsigned int i = 0; i < patternHeight; i++)\n>  \t\tlinePointers[i] = linePointers[i + 1];\n>  \n> -\tlinePointers[patternHeight] = src +\n> -\t\t\t\t      (patternHeight / 2) * (int)inputConfig_.stride;\n> +\tlinePointers[patternHeight] =\n> +\t\tsrc + (patternHeight / 2) * (int)debayer_->inputConfig_.stride;\n>  }\n>  \n> -void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])\n> +void DebayerCpuThread::memcpyNextLine(const uint8_t *linePointers[])\n>  {\n> -\tconst unsigned int patternHeight = inputConfig_.patternSize.height;\n> +\tconst unsigned int patternHeight = debayer_->inputConfig_.patternSize.height;\n>  \n>  \tif (!enableInputMemcpy_)\n>  \t\treturn;\n> @@ -643,23 +723,48 @@ void DebayerCpu::memcpyNextLine(const uint8_t *linePointers[])\n>  \tlineBufferIndex_ = (lineBufferIndex_ + 1) % (patternHeight + 1);\n>  }\n>  \n> -void DebayerCpu::process2(uint32_t frame, const uint8_t *src, uint8_t *dst)\n> +/**\n> + * \\brief Process part of the image assigned to this debayer thread\n> + * \\param[in] frame The frame number\n> + * \\param[in] src The source buffer\n> + * \\param[in] dst The destination buffer\n> + */\n> +void DebayerCpuThread::process(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>  {\n> -\tunsigned int yEnd = window_.height;\n> +\tRectangle &window = debayer_->window_;\n> +\n> +\t/* Adjust src to top left corner of the window */\n> +\tsrc += (window.y + yStart_) * debayer_->inputConfig_.stride +\n> +\t       window.x * debayer_->inputConfig_.bpp / 8;\n> +\t/* Adjust dst for yStart_ */\n> +\tdst += yStart_ * debayer_->outputConfig_.stride;\n> +\n> +\tif (debayer_->inputConfig_.patternSize.height == 2)\n> +\t\tprocess2(frame, src, dst);\n> +\telse\n> +\t\tprocess4(frame, src, dst);\n> +}\n> +\n> +void DebayerCpuThread::process2(uint32_t frame, const uint8_t *src, uint8_t *dst)\n> +{\n> +\tunsigned int outputStride = debayer_->outputConfig_.stride;\n> +\tunsigned int inputStride = debayer_->inputConfig_.stride;\n> +\tRectangle &window = debayer_->window_;\n> +\tunsigned int yEnd = yEnd_;\n>  \t/* Holds [0] previous- [1] current- [2] next-line */\n>  \tconst uint8_t *linePointers[3];\n>  \n> -\t/* Adjust src to top left corner of the window */\n> -\tsrc += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8;\n> -\n>  \t/* [x] becomes [x - 1] after initial shiftLinePointers() call */\n> -\tif (window_.y) {\n> -\t\tlinePointers[1] = src - inputConfig_.stride; /* previous-line */\n> +\tif (window.y + yStart_) {\n> +\t\tlinePointers[1] = src - inputStride; /* previous-line */\n>  \t\tlinePointers[2] = src;\n>  \t} else {\n> -\t\t/* window_.y == 0, use the next line as prev line */\n> -\t\tlinePointers[1] = src + inputConfig_.stride;\n> +\t\t/* Top line, use the next line as prev line */\n> +\t\tlinePointers[1] = src + inputStride;\n>  \t\tlinePointers[2] = src;\n> +\t}\n> +\n> +\tif (window.y == 0 && yEnd_ == window.height) {\n>  \t\t/*\n>  \t\t * Last 2 lines also need special handling.\n>  \t\t * (And configure() ensures that yEnd >= 2.)\n> @@ -669,83 +774,93 @@ void DebayerCpu::process2(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>  \n>  \tsetupInputMemcpy(linePointers);\n>  \n> -\tfor (unsigned int y = 0; y < yEnd; y += 2) {\n> +\t/*\n> +\t * Note y is the line-number *inside* the window, since stats_' window\n> +\t * is the stats window inside/relative to the debayer window. IOW for\n> +\t * single thread rendering y goes from 0 to window.height.\n> +\t */\n> +\tfor (unsigned int y = yStart_; y < yEnd; y += 2) {\n>  \t\tshiftLinePointers(linePointers, src);\n>  \t\tmemcpyNextLine(linePointers);\n> -\t\tstats_->processLine0(frame, y, linePointers);\n> -\t\t(this->*debayer0_)(dst, linePointers);\n> -\t\tsrc += inputConfig_.stride;\n> -\t\tdst += outputConfig_.stride;\n> +\t\tdebayer_->stats_->processLine0(frame, y, linePointers, threadIndex_);\n> +\t\tdebayer_->debayer0(dst, linePointers);\n> +\t\tsrc += inputStride;\n> +\t\tdst += outputStride;\n>  \n>  \t\tshiftLinePointers(linePointers, src);\n>  \t\tmemcpyNextLine(linePointers);\n> -\t\t(this->*debayer1_)(dst, linePointers);\n> -\t\tsrc += inputConfig_.stride;\n> -\t\tdst += outputConfig_.stride;\n> +\t\tdebayer_->debayer1(dst, linePointers);\n> +\t\tsrc += inputStride;\n> +\t\tdst += outputStride;\n>  \t}\n>  \n> -\tif (window_.y == 0) {\n> +\tif (window.y == 0 && yEnd_ == window.height) {\n>  \t\tshiftLinePointers(linePointers, src);\n>  \t\tmemcpyNextLine(linePointers);\n> -\t\tstats_->processLine0(frame, yEnd, linePointers);\n> -\t\t(this->*debayer0_)(dst, linePointers);\n> -\t\tsrc += inputConfig_.stride;\n> -\t\tdst += outputConfig_.stride;\n> +\t\tdebayer_->stats_->processLine0(frame, yEnd, linePointers, threadIndex_);\n> +\t\tdebayer_->debayer0(dst, linePointers);\n> +\t\tsrc += inputStride;\n> +\t\tdst += outputStride;\n>  \n>  \t\tshiftLinePointers(linePointers, src);\n>  \t\t/* next line may point outside of src, use prev. */\n>  \t\tlinePointers[2] = linePointers[0];\n> -\t\t(this->*debayer1_)(dst, linePointers);\n> -\t\tsrc += inputConfig_.stride;\n> -\t\tdst += outputConfig_.stride;\n> +\t\tdebayer_->debayer1(dst, linePointers);\n> +\t\tsrc += inputStride;\n> +\t\tdst += outputStride;\n>  \t}\n>  }\n>  \n> -void DebayerCpu::process4(uint32_t frame, const uint8_t *src, uint8_t *dst)\n> +void DebayerCpuThread::process4(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>  {\n> +\tunsigned int outputStride = debayer_->outputConfig_.stride;\n> +\tunsigned int inputStride = debayer_->inputConfig_.stride;\n> +\n>  \t/*\n>  \t * This holds pointers to [0] 2-lines-up [1] 1-line-up [2] current-line\n>  \t * [3] 1-line-down [4] 2-lines-down.\n>  \t */\n>  \tconst uint8_t *linePointers[5];\n>  \n> -\t/* Adjust src to top left corner of the window */\n> -\tsrc += window_.y * inputConfig_.stride + window_.x * inputConfig_.bpp / 8;\n> -\n>  \t/* [x] becomes [x - 1] after initial shiftLinePointers() call */\n> -\tlinePointers[1] = src - 2 * inputConfig_.stride;\n> -\tlinePointers[2] = src - inputConfig_.stride;\n> +\tlinePointers[1] = src - 2 * inputStride;\n> +\tlinePointers[2] = src - inputStride;\n>  \tlinePointers[3] = src;\n> -\tlinePointers[4] = src + inputConfig_.stride;\n> +\tlinePointers[4] = src + inputStride;\n>  \n>  \tsetupInputMemcpy(linePointers);\n>  \n> -\tfor (unsigned int y = 0; y < window_.height; y += 4) {\n> +\t/*\n> +\t * Note y is the line-number *inside* the window, since stats_' window\n> +\t * is the stats window inside/relative to the debayer window. IOW for\n> +\t * single thread rendering y goes from 0 to window.height.\n> +\t */\n> +\tfor (unsigned int y = yStart_; y < yEnd_; y += 4) {\n>  \t\tshiftLinePointers(linePointers, src);\n>  \t\tmemcpyNextLine(linePointers);\n> -\t\tstats_->processLine0(frame, y, linePointers);\n> -\t\t(this->*debayer0_)(dst, linePointers);\n> -\t\tsrc += inputConfig_.stride;\n> -\t\tdst += outputConfig_.stride;\n> +\t\tdebayer_->stats_->processLine0(frame, y, linePointers, threadIndex_);\n> +\t\tdebayer_->debayer0(dst, linePointers);\n> +\t\tsrc += inputStride;\n> +\t\tdst += outputStride;\n>  \n>  \t\tshiftLinePointers(linePointers, src);\n>  \t\tmemcpyNextLine(linePointers);\n> -\t\t(this->*debayer1_)(dst, linePointers);\n> -\t\tsrc += inputConfig_.stride;\n> -\t\tdst += outputConfig_.stride;\n> +\t\tdebayer_->debayer1(dst, linePointers);\n> +\t\tsrc += inputStride;\n> +\t\tdst += outputStride;\n>  \n>  \t\tshiftLinePointers(linePointers, src);\n>  \t\tmemcpyNextLine(linePointers);\n> -\t\tstats_->processLine2(frame, y, linePointers);\n> -\t\t(this->*debayer2_)(dst, linePointers);\n> -\t\tsrc += inputConfig_.stride;\n> -\t\tdst += outputConfig_.stride;\n> +\t\tdebayer_->stats_->processLine2(frame, y, linePointers, threadIndex_);\n> +\t\tdebayer_->debayer2(dst, linePointers);\n> +\t\tsrc += inputStride;\n> +\t\tdst += outputStride;\n>  \n>  \t\tshiftLinePointers(linePointers, src);\n>  \t\tmemcpyNextLine(linePointers);\n> -\t\t(this->*debayer3_)(dst, linePointers);\n> -\t\tsrc += inputConfig_.stride;\n> -\t\tdst += outputConfig_.stride;\n> +\t\tdebayer_->debayer3(dst, linePointers);\n> +\t\tsrc += inputStride;\n> +\t\tdst += outputStride;\n>  \t}\n>  }\n>  \n> @@ -867,10 +982,7 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>  \n>  \tstats_->startFrame(frame);\n>  \n> -\tif (inputConfig_.patternSize.height == 2)\n> -\t\tprocess2(frame, in.planes()[0].data(), out.planes()[0].data());\n> -\telse\n> -\t\tprocess4(frame, in.planes()[0].data(), out.planes()[0].data());\n> +\tthreads_[0]->process(frame, in.planes()[0].data(), out.planes()[0].data());\n>  \n>  \tmetadata.planes()[0].bytesused = out.planes()[0].size();\n>  \n> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n> index 7a651746..1074bc9c 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.h\n> +++ b/src/libcamera/software_isp/debayer_cpu.h\n> @@ -26,6 +26,7 @@\n>  \n>  namespace libcamera {\n>  \n> +class DebayerCpuThread;\n>  class DebayerCpu : public Debayer\n>  {\n>  public:\n> @@ -44,6 +45,8 @@ public:\n>  \tconst SharedFD &getStatsFD() { return stats_->getStatsFD(); }\n>  \n>  private:\n> +\tfriend class DebayerCpuThread;\n> +\n>  \t/**\n>  \t * \\brief Called to debayer 1 line of Bayer input data to output format\n>  \t * \\param[out] dst Pointer to the start of the output line to write\n> @@ -74,6 +77,11 @@ private:\n>  \t */\n>  \tusing debayerFn = void (DebayerCpu::*)(uint8_t *dst, const uint8_t *src[]);\n>  \n> +\tvoid debayer0(uint8_t *dst, const uint8_t *src[]) { (this->*debayer0_)(dst, src); }\n> +\tvoid debayer1(uint8_t *dst, const uint8_t *src[]) { (this->*debayer1_)(dst, src); }\n> +\tvoid debayer2(uint8_t *dst, const uint8_t *src[]) { (this->*debayer2_)(dst, src); }\n> +\tvoid debayer3(uint8_t *dst, const uint8_t *src[]) { (this->*debayer3_)(dst, src); }\n> +\n>  \t/* 8-bit raw bayer format */\n>  \ttemplate<bool addAlphaByte, bool ccmEnabled>\n>  \tvoid debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);\n> @@ -105,11 +113,6 @@ private:\n>  \tint setDebayerFunctions(PixelFormat inputFormat,\n>  \t\t\t\tPixelFormat outputFormat,\n>  \t\t\t\tbool ccmEnabled);\n> -\tvoid setupInputMemcpy(const uint8_t *linePointers[]);\n> -\tvoid shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src);\n> -\tvoid memcpyNextLine(const uint8_t *linePointers[]);\n> -\tvoid process2(uint32_t frame, const uint8_t *src, uint8_t *dst);\n> -\tvoid process4(uint32_t frame, const uint8_t *src, uint8_t *dst);\n>  \tvoid updateGammaTable(const DebayerParams &params);\n>  \tvoid updateLookupTables(const DebayerParams &params);\n>  \n> @@ -142,12 +145,9 @@ private:\n>  \tdebayerFn debayer3_;\n>  \tRectangle window_;\n>  \tstd::unique_ptr<SwStatsCpu> stats_;\n> -\tstd::vector<uint8_t> lineBuffers_[kMaxLineBuffers];\n> -\tunsigned int lineBufferLength_;\n> -\tunsigned int lineBufferPadding_;\n> -\tunsigned int lineBufferIndex_;\n>  \tunsigned int xShift_; /* Offset of 0/1 applied to window_.x */\n> -\tbool enableInputMemcpy_;\n> +\n> +\tstd::vector<std::unique_ptr<DebayerCpuThread>>threads_;\n>  };\n>  \n>  } /* namespace libcamera */","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 388A2C0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Feb 2026 12:43:54 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2ECC2622AE;\n\tWed, 25 Feb 2026 13:43:53 +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 0C93D61FA0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Feb 2026 13:43:51 +0100 (CET)","from mail-wm1-f69.google.com (mail-wm1-f69.google.com\n\t[209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-670-qjrdsUaANua5KabK221pXw-1; Wed, 25 Feb 2026 07:43:49 -0500","by mail-wm1-f69.google.com with SMTP id\n\t5b1f17b1804b1-4837b6f6b93so49299705e9.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Feb 2026 04:43:49 -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-43970d3ff27sm35511572f8f.22.2026.02.25.04.43.45\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 25 Feb 2026 04:43:45 -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=\"L/SEqeId\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1772023430;\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=BJrTFOXAF+vPipvVYXJ1baF0T9GhJhSIyI9GVAoRmOA=;\n\tb=L/SEqeIdcLR/VBLgFDrLyQptZkscmMScyoRdV0GaZ++Es9ld+foZVe6xySDn1EbRmUaxgX\n\tN1U7g+nlnwwZHuZYbBrmZczm9/ozN0RwLx04ZK85Gm5pCLyXS/cr/J5G+MWYmFt5mwhOmy\n\tTuYmsIJdoBvWeKLXikP9zERiv8SgHEA=","X-MC-Unique":"qjrdsUaANua5KabK221pXw-1","X-Mimecast-MFC-AGG-ID":"qjrdsUaANua5KabK221pXw_1772023428","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1772023428; x=1772628228;\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=BJrTFOXAF+vPipvVYXJ1baF0T9GhJhSIyI9GVAoRmOA=;\n\tb=cuox/OIJ+1PczxWbQpyxjO41N41ZQ2Lh2p3vE1yXiKg41ihZSdbTMxu7ZA36fM0z1k\n\t2CiVSfPBKUQXSxF2NPku7WcOJccXWW/14tNH4oZBcWbLG8/27WYGp1hikv8akh9DUExs\n\tBs2gkXGZm9IlhYavYpbkePvOswG+UJAKLzQmL5mKeY/OE0tSACUFDEFcOrrpZU0l+CMw\n\tbAE9T/aG1ROdITZTdRY1is75E7jJ0+L26HXRB7O2xRpc4/Oe4QP3O/DIegvJNWK8vJ8P\n\tHqsfp2CyXbgTpsYuhk+dblCnldPUCP7bTSeOmPbGF2PTpUMsT4FiU2YVrW7YKj322nXK\n\tFEtw==","X-Gm-Message-State":"AOJu0Yz3Do1vcwO0lHWnPImeikAHtA2WK4lk55YL9Wj1BwNG28oI++wu\n\t5NAhdZuno76cqW+VPFwpW0HJ49H32zjf9Giw04aPSJ8cBJYs/yeLzKCN4Q4XKTqrKgOohgD7WXF\n\tih6eSyKBI3ifa0tZbi/B7U45FScvJ/f7XZAWl3hlQJ8kRSC18tDypuZoHK1dkjOUT3zdKP3Vpfu\n\tTQuDx3XjF1c459s6G7gok5VQeyXMEYcXPtOmBLslb3k/WDAwUygUHr7p+Oj74=","X-Gm-Gg":"ATEYQzzyycuzEkrUrNashpcHajSTHthvf3YGRyEtpbbRcxgLGh/ACpzuoc+t+nCxeeq\n\taz+ScNvfReNlTG49nbfoiTjxKWM8DWGUETiQ11AzP8SCo3Zdk9kvv5W4W3ybtIpV0LFmdndeSMJ\n\tNPFgWO/kIevx7dFPJdAJrsTXYdStnCMjqZ/IDnlKNNDQe+XcLBOarfLSSVyHsomDWHZxjTbVKlr\n\tcGQOgwvIyi2mSyU1lZquMRMuoR90vsNF0kfZnQY5EtclMUXZh4GMxcjg5UnZE+0jKkKgJJzh4YF\n\tKwUeqPGRgLNidVNqsBVZd+Qmo4mXGP+n8AFDqPg8LcSaVG3RU3WE4MGFJ3GyaA6S8RWezyx7DkO\n\trTQOimPiXmtMsM008eO1l6OyZJUbpd3uAMkR0qRqAcP5Rcy6KD13CzKgzhjLV9fYNkzUviZfF1M\n\tA=","X-Received":["by 2002:a05:600c:6091:b0:483:badb:618b with SMTP id\n\t5b1f17b1804b1-483c219fbb1mr4441495e9.24.1772023427723; \n\tWed, 25 Feb 2026 04:43:47 -0800 (PST)","by 2002:a05:600c:6091:b0:483:badb:618b with SMTP id\n\t5b1f17b1804b1-483c219fbb1mr4440895e9.24.1772023426967; \n\tWed, 25 Feb 2026 04:43:46 -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 v3 2/4] software_isp: debayer_cpu: Add DebayerCpuThread\n\tclass","In-Reply-To":"<20260224193745.106186-3-johannes.goede@oss.qualcomm.com> (Hans\n\tde Goede's message of \"Tue, 24 Feb 2026 20:37:43 +0100\")","References":"<20260224193745.106186-1-johannes.goede@oss.qualcomm.com>\n\t<20260224193745.106186-3-johannes.goede@oss.qualcomm.com>","Date":"Wed, 25 Feb 2026 13:43:44 +0100","Message-ID":"<855x7lc7sv.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":"t-dlrYGBXaUEo9S4kmY54rGMKKjfVn6-G9t6uwaP55s_1772023428","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>"}}]