[{"id":29726,"web_url":"https://patchwork.libcamera.org/comment/29726/","msgid":"<20240601225429.GB6683@pendragon.ideasonboard.com>","date":"2024-06-01T22:54:29","subject":"Re: [PATCH v6 3/5] libcamera: software_isp: Move color mappings out\n\tof debayering","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Milan,\n\nThank you for the patch.\n\nOn Fri, May 31, 2024 at 02:38:38PM +0200, Milan Zamazal wrote:\n> Constructing the color mapping tables is related to stats rather than\n> debayering, where they are applied.  Let's move the corresponding code\n> to stats processing.\n> \n> The same applies to the auxiliary gamma table.  As the gamma value is\n> currently fixed and used in a single place, with the temporary exception\n> mentioned below, there is no need to share it anywhere anymore.\n> \n> It's necessary to initialize SoftwareIsp::debayerParams_ to default\n> values.  These initial values are used for the first two frames, before\n> they are changed based on determined stats.  To avoid sharing the gamma\n> value constant in artificial ways, we use 0.5 directly in the\n> initialization.  This all is not a particularly elegant thing to do,\n> such a code belongs conceptually to the similar code in stats\n> processing, but doing better is left for larger refactoring.\n> \n> This is a preliminary step towards building this functionality on top of\n> libipa/algorithm.h, which should follow.\n> \n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> Reviewed-by: Andrei Konovalov <andrey.konovalov.ynk@gmail.com>\n> ---\n>  .../internal/software_isp/debayer_params.h    | 18 +++----\n>  src/ipa/simple/soft_simple.cpp                | 51 +++++++++++++++----\n>  src/libcamera/software_isp/debayer.cpp        | 29 +++++------\n>  src/libcamera/software_isp/debayer_cpu.cpp    | 43 +++-------------\n>  src/libcamera/software_isp/debayer_cpu.h      | 11 ++--\n>  src/libcamera/software_isp/software_isp.cpp   | 23 +++++++--\n>  6 files changed, 95 insertions(+), 80 deletions(-)\n> \n> diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h\n> index ce1b5945..463d24b3 100644\n> --- a/include/libcamera/internal/software_isp/debayer_params.h\n> +++ b/include/libcamera/internal/software_isp/debayer_params.h\n> @@ -1,6 +1,6 @@\n>  /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>  /*\n> - * Copyright (C) 2023, Red Hat Inc.\n> + * Copyright (C) 2023, 2024 Red Hat Inc.\n>   *\n>   * Authors:\n>   * Hans de Goede <hdegoede@redhat.com>\n> @@ -10,20 +10,20 @@\n>  \n>  #pragma once\n>  \n> +#include <array>\n> +#include <stdint.h>\n> +\n>  namespace libcamera {\n>  \n>  struct DebayerParams {\n>  \tstatic constexpr unsigned int kGain10 = 256;\n> +\tstatic constexpr unsigned int kRGBLookupSize = 256;\n>  \n> -\tunsigned int gainR;\n> -\tunsigned int gainG;\n> -\tunsigned int gainB;\n> +\tusing ColorLookupTable = std::array<uint8_t, kRGBLookupSize>;\n>  \n> -\tfloat gamma;\n> -\t/**\n> -\t * \\brief Level of the black point, 0..255, 0 is no correction.\n> -\t */\n> -\tunsigned int blackLevel;\n> +\tColorLookupTable red;\n> +\tColorLookupTable green;\n> +\tColorLookupTable blue;\n>  };\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n> index f383f994..3388686f 100644\n> --- a/src/ipa/simple/soft_simple.cpp\n> +++ b/src/ipa/simple/soft_simple.cpp\n> @@ -5,6 +5,7 @@\n>   * Simple Software Image Processing Algorithm module\n>   */\n>  \n> +#include <cmath>\n>  #include <numeric>\n>  #include <stdint.h>\n>  #include <sys/mman.h>\n> @@ -84,6 +85,10 @@ private:\n>  \tControlInfoMap sensorInfoMap_;\n>  \tBlackLevel blackLevel_;\n>  \n> +\tstatic constexpr unsigned int kGammaLookupSize = 1024;\n> +\tstd::array<uint8_t, kGammaLookupSize> gammaTable_;\n> +\tint lastBlackLevel_ = -1;\n> +\n>  \tint32_t exposureMin_, exposureMax_;\n>  \tint32_t exposure_;\n>  \tdouble againMin_, againMax_, againMinStep_;\n> @@ -246,7 +251,6 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)\n>  \tif (ignoreUpdates_ > 0)\n>  \t\tblackLevel_.update(histogram);\n>  \tconst uint8_t blackLevel = blackLevel_.get();\n> -\tparams_->blackLevel = blackLevel;\n>  \n>  \t/*\n>  \t * Black level must be subtracted to get the correct AWB ratios,\n> @@ -263,13 +267,42 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)\n>  \t/*\n>  \t * Calculate red and blue gains for AWB.\n>  \t * Clamp max gain at 4.0, this also avoids 0 division.\n> +\t * Gain: 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.\n>  \t */\n> -\tparams_->gainR = sumR <= sumG / 4 ? 1024 : 256 * sumG / sumR;\n> -\tparams_->gainB = sumB <= sumG / 4 ? 1024 : 256 * sumG / sumB;\n> -\n> +\tconst unsigned int gainR = sumR <= sumG / 4 ? 1024 : 256 * sumG / sumR;\n> +\tconst unsigned int gainB = sumB <= sumG / 4 ? 1024 : 256 * sumG / sumB;\n>  \t/* Green gain and gamma values are fixed */\n> -\tparams_->gainG = 256;\n> -\tparams_->gamma = 0.5;\n> +\tconstexpr unsigned int gainG = 256;\n> +\n> +\t/* Update the gamma table if needed */\n> +\tif (blackLevel != lastBlackLevel_) {\n> +\t\tconstexpr float gamma = 0.5;\n> +\t\tconst unsigned int blackIndex = blackLevel * kGammaLookupSize / 256;\n> +\t\tstd::fill(gammaTable_.begin(), gammaTable_.begin() + blackIndex, 0);\n> +\t\tconst float divisor = kGammaLookupSize - blackIndex - 1.0;\n> +\t\tfor (unsigned int i = blackIndex; i < kGammaLookupSize; i++)\n> +\t\t\tgammaTable_[i] = UINT8_MAX *\n> +\t\t\t\t\t std::pow((i - blackIndex) / divisor, gamma);\n> +\n> +\t\tlastBlackLevel_ = blackLevel;\n> +\t}\n> +\n> +\tfor (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {\n> +\t\tconstexpr unsigned int div =\n> +\t\t\tDebayerParams::kRGBLookupSize * DebayerParams::kGain10 /\n> +\t\t\tkGammaLookupSize;\n> +\t\tunsigned int idx;\n> +\n> +\t\t/* Apply gamma after gain! */\n> +\t\tidx = std::min({ i * gainR / div, (kGammaLookupSize - 1) });\n> +\t\tparams_->red[i] = gammaTable_[idx];\n> +\n> +\t\tidx = std::min({ i * gainG / div, (kGammaLookupSize - 1) });\n> +\t\tparams_->green[i] = gammaTable_[idx];\n> +\n> +\t\tidx = std::min({ i * gainB / div, (kGammaLookupSize - 1) });\n> +\t\tparams_->blue[i] = gammaTable_[idx];\n> +\t}\n>  \n>  \tsetIspParams.emit();\n>  \n> @@ -290,7 +323,7 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)\n>  \t * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf\n>  \t */\n>  \tconst unsigned int blackLevelHistIdx =\n> -\t\tparams_->blackLevel / (256 / SwIspStats::kYHistogramSize);\n> +\t\tblackLevel / (256 / SwIspStats::kYHistogramSize);\n>  \tconst unsigned int histogramSize =\n>  \t\tSwIspStats::kYHistogramSize - blackLevelHistIdx;\n>  \tconst unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount;\n> @@ -338,8 +371,8 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)\n>  \n>  \tLOG(IPASoft, Debug) << \"exposureMSV \" << exposureMSV\n>  \t\t\t    << \" exp \" << exposure_ << \" again \" << again_\n> -\t\t\t    << \" gain R/B \" << params_->gainR << \"/\" << params_->gainB\n> -\t\t\t    << \" black level \" << params_->blackLevel;\n> +\t\t\t    << \" gain R/B \" << gainR << \"/\" << gainB\n> +\t\t\t    << \" black level \" << static_cast<unsigned int>(blackLevel);\n>  }\n>  \n>  void IPASoftSimple::updateExposure(double exposureMSV)\n> diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp\n> index efe75ea8..3f3969f7 100644\n> --- a/src/libcamera/software_isp/debayer.cpp\n> +++ b/src/libcamera/software_isp/debayer.cpp\n> @@ -1,7 +1,7 @@\n>  /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>  /*\n>   * Copyright (C) 2023, Linaro Ltd\n> - * Copyright (C) 2023, Red Hat Inc.\n> + * Copyright (C) 2023, 2024 Red Hat Inc.\n>   *\n>   * Authors:\n>   * Hans de Goede <hdegoede@redhat.com>\n> @@ -24,29 +24,28 @@ namespace libcamera {\n>   */\n>  \n>  /**\n> - * \\var DebayerParams::gainR\n> - * \\brief Red gain\n> - *\n> - * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.\n> + * \\var DebayerParams::kRGBLookupSize\n> + * \\brief Size of a color lookup table\n>   */\n>  \n>  /**\n> - * \\var DebayerParams::gainG\n> - * \\brief Green gain\n> - *\n> - * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.\n> + * \\typedef DebayerParams::ColorLookupTable\n> + * \\brief Type of the lookup tables for red, green, blue values\n>   */\n>  \n>  /**\n> - * \\var DebayerParams::gainB\n> - * \\brief Blue gain\n> - *\n> - * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.\n> + * \\var DebayerParams::red\n> + * \\brief Lookup table for red color, mapping input values to output values\n> + */\n> +\n> +/**\n> + * \\var DebayerParams::green\n> + * \\brief Lookup table for green color, mapping input values to output values\n>   */\n>  \n>  /**\n> - * \\var DebayerParams::gamma\n> - * \\brief Gamma correction, 1.0 is no correction\n> + * \\var DebayerParams::blue\n> + * \\brief Lookup table for blue color, mapping input values to output values\n>   */\n>  \n>  /**\n> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n> index 8254bbe9..c038eed4 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n> @@ -11,7 +11,6 @@\n>  \n>  #include \"debayer_cpu.h\"\n>  \n> -#include <math.h>\n>  #include <stdlib.h>\n>  #include <time.h>\n>  \n> @@ -35,7 +34,7 @@ namespace libcamera {\n>   * \\param[in] stats Pointer to the stats object to use\n>   */\n>  DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats)\n> -\t: stats_(std::move(stats)), gammaCorrection_(1.0), blackLevel_(0)\n> +\t: stats_(std::move(stats))\n>  {\n>  \t/*\n>  \t * Reading from uncached buffers may be very slow.\n> @@ -47,9 +46,9 @@ DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats)\n>  \t */\n>  \tenableInputMemcpy_ = true;\n>  \n> -\t/* Initialize gamma to 1.0 curve */\n> -\tfor (unsigned int i = 0; i < kGammaLookupSize; i++)\n> -\t\tgamma_[i] = i / (kGammaLookupSize / kRGBLookupSize);\n> +\t/* Initialize color lookup tables */\n> +\tfor (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++)\n> +\t\tred_[i] = green_[i] = blue_[i] = i;\n>  \n>  \tfor (unsigned int i = 0; i < kMaxLineBuffers; i++)\n>  \t\tlineBuffers_[i] = nullptr;\n> @@ -698,37 +697,9 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams\n>  \t\tclock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);\n>  \t}\n>  \n> -\t/* Apply DebayerParams */\n> -\tif (params.gamma != gammaCorrection_ || params.blackLevel != blackLevel_) {\n> -\t\tconst unsigned int blackIndex =\n> -\t\t\tparams.blackLevel * kGammaLookupSize / 256;\n> -\t\tstd::fill(gamma_.begin(), gamma_.begin() + blackIndex, 0);\n> -\t\tconst float divisor = kGammaLookupSize - blackIndex - 1.0;\n> -\t\tfor (unsigned int i = blackIndex; i < kGammaLookupSize; i++)\n> -\t\t\tgamma_[i] = UINT8_MAX * powf((i - blackIndex) / divisor, params.gamma);\n> -\n> -\t\tgammaCorrection_ = params.gamma;\n> -\t\tblackLevel_ = params.blackLevel;\n> -\t}\n> -\n> -\tif (swapRedBlueGains_)\n> -\t\tstd::swap(params.gainR, params.gainB);\n> -\n> -\tfor (unsigned int i = 0; i < kRGBLookupSize; i++) {\n> -\t\tconstexpr unsigned int div =\n> -\t\t\tkRGBLookupSize * DebayerParams::kGain10 / kGammaLookupSize;\n> -\t\tunsigned int idx;\n> -\n> -\t\t/* Apply gamma after gain! */\n> -\t\tidx = std::min({ i * params.gainR / div, (kGammaLookupSize - 1) });\n> -\t\tred_[i] = gamma_[idx];\n> -\n> -\t\tidx = std::min({ i * params.gainG / div, (kGammaLookupSize - 1) });\n> -\t\tgreen_[i] = gamma_[idx];\n> -\n> -\t\tidx = std::min({ i * params.gainB / div, (kGammaLookupSize - 1) });\n> -\t\tblue_[i] = gamma_[idx];\n> -\t}\n> +\tgreen_ = params.green;\n> +\tred_ = swapRedBlueGains_ ? params.blue : params.red;\n> +\tblue_ = swapRedBlueGains_ ? params.red : params.blue;\n>  \n>  \t/* Copy metadata from the input buffer */\n>  \tFrameMetadata &metadata = output->_d()->metadata();\n> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n> index de216fe3..be7dcdca 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.h\n> +++ b/src/libcamera/software_isp/debayer_cpu.h\n> @@ -122,15 +122,12 @@ private:\n>  \tvoid process2(const uint8_t *src, uint8_t *dst);\n>  \tvoid process4(const uint8_t *src, uint8_t *dst);\n>  \n> -\tstatic constexpr unsigned int kGammaLookupSize = 1024;\n> -\tstatic constexpr unsigned int kRGBLookupSize = 256;\n>  \t/* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */\n>  \tstatic constexpr unsigned int kMaxLineBuffers = 5;\n>  \n> -\tstd::array<uint8_t, kGammaLookupSize> gamma_;\n> -\tstd::array<uint8_t, kRGBLookupSize> red_;\n> -\tstd::array<uint8_t, kRGBLookupSize> green_;\n> -\tstd::array<uint8_t, kRGBLookupSize> blue_;\n> +\tDebayerParams::ColorLookupTable red_;\n> +\tDebayerParams::ColorLookupTable green_;\n> +\tDebayerParams::ColorLookupTable blue_;\n>  \tdebayerFn debayer0_;\n>  \tdebayerFn debayer1_;\n>  \tdebayerFn debayer2_;\n> @@ -146,8 +143,6 @@ private:\n>  \tunsigned int xShift_; /* Offset of 0/1 applied to window_.x */\n>  \tbool enableInputMemcpy_;\n>  \tbool swapRedBlueGains_;\n> -\tfloat gammaCorrection_;\n> -\tunsigned int blackLevel_;\n>  \tunsigned int measuredFrames_;\n>  \tint64_t frameProcessTime_;\n>  \t/* Skip 30 frames for things to stabilize then measure 30 frames */\n> diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp\n> index c9b6be56..ccd703bb 100644\n> --- a/src/libcamera/software_isp/software_isp.cpp\n> +++ b/src/libcamera/software_isp/software_isp.cpp\n> @@ -7,6 +7,8 @@\n>  \n>  #include \"libcamera/internal/software_isp/software_isp.h\"\n>  \n> +#include <cmath>\n> +#include <stdint.h>\n>  #include <sys/mman.h>\n>  #include <sys/types.h>\n>  #include <unistd.h>\n> @@ -18,6 +20,7 @@\n>  #include \"libcamera/internal/framebuffer.h\"\n>  #include \"libcamera/internal/ipa_manager.h\"\n>  #include \"libcamera/internal/mapped_framebuffer.h\"\n> +#include \"libcamera/internal/software_isp/debayer_params.h\"\n>  \n>  #include \"debayer_cpu.h\"\n>  \n> @@ -63,10 +66,24 @@ LOG_DEFINE_CATEGORY(SoftwareIsp)\n>   * handler\n>   */\n>  SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor)\n> -\t: debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10,\n> -\t\t\t  DebayerParams::kGain10, 0.5f, 0 },\n> -\t  dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System)\n> +\t: dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System)\n>  {\n> +\t/*\n> +\t * debayerParams_ must be initialized because the initial value is used for\n> +\t * the first two frames, i.e. until stats processing starts providing its\n> +\t * own parameters.\n> +\t *\n> +\t * \\todo This should be handled in the same place as the related operations.\n\nI would write\n\n\t * \\todo This should be handled in the same place as the related\n\t * operations, in the IPA module.\n\nNo need to resubmit just for this, I can update the comment when\napplying.\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\t */\n> +\tstd::array<uint8_t, 256> gammaTable;\n> +\tfor (unsigned int i = 0; i < 256; i++)\n> +\t\tgammaTable[i] = UINT8_MAX * std::pow(i / 256.0, 0.5);\n> +\tfor (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {\n> +\t\tdebayerParams_.red[i] = gammaTable[i];\n> +\t\tdebayerParams_.green[i] = gammaTable[i];\n> +\t\tdebayerParams_.blue[i] = gammaTable[i];\n> +\t}\n> +\n>  \tif (!dmaHeap_.isValid()) {\n>  \t\tLOG(SoftwareIsp, Error) << \"Failed to create DmaHeap object\";\n>  \t\treturn;","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 53715BD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat,  1 Jun 2024 22:54:46 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5AA17634BA;\n\tSun,  2 Jun 2024 00:54:45 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 85E0061A46\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun,  2 Jun 2024 00:54:43 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 4C5E1675;\n\tSun,  2 Jun 2024 00:54:37 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"FJ6h4dGL\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1717282477;\n\tbh=2Hl/v1Gm3OpPcUP0qODZ9ERBZ0bPzIcAhDv/Iz1m/qU=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=FJ6h4dGLZ0APbKX+ht8qD7YtfgvXZOLZ32pNYjJ8noQ9cMlCGTXwX6eTUiFSVNyCE\n\tVaYWiA5AuhjjWrrJKOM3xntyBGP7AapJS/o3oVPn2cwdlr+qmghm9KundS6D8B11El\n\tEgRVNRHo2qoHSUO514PZ7kN4h+deRVUXDdXBKjK0=","Date":"Sun, 2 Jun 2024 01:54:29 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Milan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>,\n\tAndrei Konovalov <andrey.konovalov.ynk@gmail.com>","Subject":"Re: [PATCH v6 3/5] libcamera: software_isp: Move color mappings out\n\tof debayering","Message-ID":"<20240601225429.GB6683@pendragon.ideasonboard.com>","References":"<20240531123840.713364-1-mzamazal@redhat.com>\n\t<20240531123840.713364-4-mzamazal@redhat.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20240531123840.713364-4-mzamazal@redhat.com>","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":29737,"web_url":"https://patchwork.libcamera.org/comment/29737/","msgid":"<87r0dempjb.fsf@redhat.com>","date":"2024-06-03T07:52:24","subject":"Re: [PATCH v6 3/5] libcamera: software_isp: Move color mappings out\n\tof debayering","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Laurent Pinchart <laurent.pinchart@ideasonboard.com> writes:\n\n> Hi Milan,\n>\n> Thank you for the patch.\n\nHi Laurent,\n\nthank you for review.\n\n> On Fri, May 31, 2024 at 02:38:38PM +0200, Milan Zamazal wrote:\n>> Constructing the color mapping tables is related to stats rather than\n>> debayering, where they are applied.  Let's move the corresponding code\n>> to stats processing.\n>> \n>> The same applies to the auxiliary gamma table.  As the gamma value is\n>> currently fixed and used in a single place, with the temporary exception\n>> mentioned below, there is no need to share it anywhere anymore.\n>> \n>> It's necessary to initialize SoftwareIsp::debayerParams_ to default\n>> values.  These initial values are used for the first two frames, before\n>> they are changed based on determined stats.  To avoid sharing the gamma\n>> value constant in artificial ways, we use 0.5 directly in the\n>> initialization.  This all is not a particularly elegant thing to do,\n>> such a code belongs conceptually to the similar code in stats\n>> processing, but doing better is left for larger refactoring.\n>> \n>> This is a preliminary step towards building this functionality on top of\n>> libipa/algorithm.h, which should follow.\n>> \n>> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n>> Reviewed-by: Andrei Konovalov <andrey.konovalov.ynk@gmail.com>\n>> ---\n>>  .../internal/software_isp/debayer_params.h    | 18 +++----\n>>  src/ipa/simple/soft_simple.cpp                | 51 +++++++++++++++----\n>>  src/libcamera/software_isp/debayer.cpp        | 29 +++++------\n>>  src/libcamera/software_isp/debayer_cpu.cpp    | 43 +++-------------\n>>  src/libcamera/software_isp/debayer_cpu.h      | 11 ++--\n>>  src/libcamera/software_isp/software_isp.cpp   | 23 +++++++--\n>>  6 files changed, 95 insertions(+), 80 deletions(-)\n>> \n>> diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h\n>> index ce1b5945..463d24b3 100644\n>> --- a/include/libcamera/internal/software_isp/debayer_params.h\n>> +++ b/include/libcamera/internal/software_isp/debayer_params.h\n>> @@ -1,6 +1,6 @@\n>>  /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>>  /*\n>> - * Copyright (C) 2023, Red Hat Inc.\n>> + * Copyright (C) 2023, 2024 Red Hat Inc.\n>>   *\n>>   * Authors:\n>>   * Hans de Goede <hdegoede@redhat.com>\n>> @@ -10,20 +10,20 @@\n>>  \n>>  #pragma once\n>>  \n>> +#include <array>\n>> +#include <stdint.h>\n>> +\n>>  namespace libcamera {\n>>  \n>>  struct DebayerParams {\n>>  \tstatic constexpr unsigned int kGain10 = 256;\n>> +\tstatic constexpr unsigned int kRGBLookupSize = 256;\n>>  \n>> -\tunsigned int gainR;\n>> -\tunsigned int gainG;\n>> -\tunsigned int gainB;\n>> +\tusing ColorLookupTable = std::array<uint8_t, kRGBLookupSize>;\n>>  \n>> -\tfloat gamma;\n>> -\t/**\n>> -\t * \\brief Level of the black point, 0..255, 0 is no correction.\n>> -\t */\n>> -\tunsigned int blackLevel;\n>> +\tColorLookupTable red;\n>> +\tColorLookupTable green;\n>> +\tColorLookupTable blue;\n>>  };\n>>  \n>>  } /* namespace libcamera */\n>> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n>> index f383f994..3388686f 100644\n>> --- a/src/ipa/simple/soft_simple.cpp\n>> +++ b/src/ipa/simple/soft_simple.cpp\n>> @@ -5,6 +5,7 @@\n>>   * Simple Software Image Processing Algorithm module\n>>   */\n>>  \n>> +#include <cmath>\n>>  #include <numeric>\n>>  #include <stdint.h>\n>>  #include <sys/mman.h>\n>> @@ -84,6 +85,10 @@ private:\n>>  \tControlInfoMap sensorInfoMap_;\n>>  \tBlackLevel blackLevel_;\n>>  \n>> +\tstatic constexpr unsigned int kGammaLookupSize = 1024;\n>> +\tstd::array<uint8_t, kGammaLookupSize> gammaTable_;\n>> +\tint lastBlackLevel_ = -1;\n>> +\n>>  \tint32_t exposureMin_, exposureMax_;\n>>  \tint32_t exposure_;\n>>  \tdouble againMin_, againMax_, againMinStep_;\n>> @@ -246,7 +251,6 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)\n>>  \tif (ignoreUpdates_ > 0)\n>>  \t\tblackLevel_.update(histogram);\n>>  \tconst uint8_t blackLevel = blackLevel_.get();\n>> -\tparams_->blackLevel = blackLevel;\n>>  \n>>  \t/*\n>>  \t * Black level must be subtracted to get the correct AWB ratios,\n>> @@ -263,13 +267,42 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)\n>>  \t/*\n>>  \t * Calculate red and blue gains for AWB.\n>>  \t * Clamp max gain at 4.0, this also avoids 0 division.\n>> +\t * Gain: 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.\n>>  \t */\n>> -\tparams_->gainR = sumR <= sumG / 4 ? 1024 : 256 * sumG / sumR;\n>> -\tparams_->gainB = sumB <= sumG / 4 ? 1024 : 256 * sumG / sumB;\n>> -\n>> +\tconst unsigned int gainR = sumR <= sumG / 4 ? 1024 : 256 * sumG / sumR;\n>> +\tconst unsigned int gainB = sumB <= sumG / 4 ? 1024 : 256 * sumG / sumB;\n>>  \t/* Green gain and gamma values are fixed */\n>> -\tparams_->gainG = 256;\n>> -\tparams_->gamma = 0.5;\n>> +\tconstexpr unsigned int gainG = 256;\n>> +\n>> +\t/* Update the gamma table if needed */\n>> +\tif (blackLevel != lastBlackLevel_) {\n>> +\t\tconstexpr float gamma = 0.5;\n>> +\t\tconst unsigned int blackIndex = blackLevel * kGammaLookupSize / 256;\n>> +\t\tstd::fill(gammaTable_.begin(), gammaTable_.begin() + blackIndex, 0);\n>> +\t\tconst float divisor = kGammaLookupSize - blackIndex - 1.0;\n>> +\t\tfor (unsigned int i = blackIndex; i < kGammaLookupSize; i++)\n>> +\t\t\tgammaTable_[i] = UINT8_MAX *\n>> +\t\t\t\t\t std::pow((i - blackIndex) / divisor, gamma);\n>> +\n>> +\t\tlastBlackLevel_ = blackLevel;\n>> +\t}\n>> +\n>> +\tfor (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {\n>> +\t\tconstexpr unsigned int div =\n>> +\t\t\tDebayerParams::kRGBLookupSize * DebayerParams::kGain10 /\n>> +\t\t\tkGammaLookupSize;\n>> +\t\tunsigned int idx;\n>> +\n>> +\t\t/* Apply gamma after gain! */\n>> +\t\tidx = std::min({ i * gainR / div, (kGammaLookupSize - 1) });\n>> +\t\tparams_->red[i] = gammaTable_[idx];\n>> +\n>> +\t\tidx = std::min({ i * gainG / div, (kGammaLookupSize - 1) });\n>> +\t\tparams_->green[i] = gammaTable_[idx];\n>> +\n>> +\t\tidx = std::min({ i * gainB / div, (kGammaLookupSize - 1) });\n>> +\t\tparams_->blue[i] = gammaTable_[idx];\n>> +\t}\n>>  \n>>  \tsetIspParams.emit();\n>>  \n>> @@ -290,7 +323,7 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)\n>>  \t * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf\n>>  \t */\n>>  \tconst unsigned int blackLevelHistIdx =\n>> -\t\tparams_->blackLevel / (256 / SwIspStats::kYHistogramSize);\n>> +\t\tblackLevel / (256 / SwIspStats::kYHistogramSize);\n>>  \tconst unsigned int histogramSize =\n>>  \t\tSwIspStats::kYHistogramSize - blackLevelHistIdx;\n>>  \tconst unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount;\n>> @@ -338,8 +371,8 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)\n>>  \n>>  \tLOG(IPASoft, Debug) << \"exposureMSV \" << exposureMSV\n>>  \t\t\t    << \" exp \" << exposure_ << \" again \" << again_\n>> -\t\t\t    << \" gain R/B \" << params_->gainR << \"/\" << params_->gainB\n>> -\t\t\t    << \" black level \" << params_->blackLevel;\n>> +\t\t\t    << \" gain R/B \" << gainR << \"/\" << gainB\n>> +\t\t\t    << \" black level \" << static_cast<unsigned int>(blackLevel);\n>>  }\n>>  \n>>  void IPASoftSimple::updateExposure(double exposureMSV)\n>> diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp\n>> index efe75ea8..3f3969f7 100644\n>> --- a/src/libcamera/software_isp/debayer.cpp\n>> +++ b/src/libcamera/software_isp/debayer.cpp\n>> @@ -1,7 +1,7 @@\n>>  /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>>  /*\n>>   * Copyright (C) 2023, Linaro Ltd\n>> - * Copyright (C) 2023, Red Hat Inc.\n>> + * Copyright (C) 2023, 2024 Red Hat Inc.\n>>   *\n>>   * Authors:\n>>   * Hans de Goede <hdegoede@redhat.com>\n>> @@ -24,29 +24,28 @@ namespace libcamera {\n>>   */\n>>  \n>>  /**\n>> - * \\var DebayerParams::gainR\n>> - * \\brief Red gain\n>> - *\n>> - * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.\n>> + * \\var DebayerParams::kRGBLookupSize\n>> + * \\brief Size of a color lookup table\n>>   */\n>>  \n>>  /**\n>> - * \\var DebayerParams::gainG\n>> - * \\brief Green gain\n>> - *\n>> - * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.\n>> + * \\typedef DebayerParams::ColorLookupTable\n>> + * \\brief Type of the lookup tables for red, green, blue values\n>>   */\n>>  \n>>  /**\n>> - * \\var DebayerParams::gainB\n>> - * \\brief Blue gain\n>> - *\n>> - * 128 = 0.5, 256 = 1.0, 512 = 2.0, etc.\n>> + * \\var DebayerParams::red\n>> + * \\brief Lookup table for red color, mapping input values to output values\n>> + */\n>> +\n>> +/**\n>> + * \\var DebayerParams::green\n>> + * \\brief Lookup table for green color, mapping input values to output values\n>>   */\n>>  \n>>  /**\n>> - * \\var DebayerParams::gamma\n>> - * \\brief Gamma correction, 1.0 is no correction\n>> + * \\var DebayerParams::blue\n>> + * \\brief Lookup table for blue color, mapping input values to output values\n>>   */\n>>  \n>>  /**\n>> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n>> index 8254bbe9..c038eed4 100644\n>> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n>> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n>> @@ -11,7 +11,6 @@\n>>  \n>>  #include \"debayer_cpu.h\"\n>>  \n>> -#include <math.h>\n>>  #include <stdlib.h>\n>>  #include <time.h>\n>>  \n>> @@ -35,7 +34,7 @@ namespace libcamera {\n>>   * \\param[in] stats Pointer to the stats object to use\n>>   */\n>>  DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats)\n>> -\t: stats_(std::move(stats)), gammaCorrection_(1.0), blackLevel_(0)\n>> +\t: stats_(std::move(stats))\n>>  {\n>>  \t/*\n>>  \t * Reading from uncached buffers may be very slow.\n>> @@ -47,9 +46,9 @@ DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats)\n>>  \t */\n>>  \tenableInputMemcpy_ = true;\n>>  \n>> -\t/* Initialize gamma to 1.0 curve */\n>> -\tfor (unsigned int i = 0; i < kGammaLookupSize; i++)\n>> -\t\tgamma_[i] = i / (kGammaLookupSize / kRGBLookupSize);\n>> +\t/* Initialize color lookup tables */\n>> +\tfor (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++)\n>> +\t\tred_[i] = green_[i] = blue_[i] = i;\n>>  \n>>  \tfor (unsigned int i = 0; i < kMaxLineBuffers; i++)\n>>  \t\tlineBuffers_[i] = nullptr;\n>> @@ -698,37 +697,9 @@ void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams\n>>  \t\tclock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime);\n>>  \t}\n>>  \n>> -\t/* Apply DebayerParams */\n>> -\tif (params.gamma != gammaCorrection_ || params.blackLevel != blackLevel_) {\n>> -\t\tconst unsigned int blackIndex =\n>> -\t\t\tparams.blackLevel * kGammaLookupSize / 256;\n>> -\t\tstd::fill(gamma_.begin(), gamma_.begin() + blackIndex, 0);\n>> -\t\tconst float divisor = kGammaLookupSize - blackIndex - 1.0;\n>> -\t\tfor (unsigned int i = blackIndex; i < kGammaLookupSize; i++)\n>> -\t\t\tgamma_[i] = UINT8_MAX * powf((i - blackIndex) / divisor, params.gamma);\n>> -\n>> -\t\tgammaCorrection_ = params.gamma;\n>> -\t\tblackLevel_ = params.blackLevel;\n>> -\t}\n>> -\n>> -\tif (swapRedBlueGains_)\n>> -\t\tstd::swap(params.gainR, params.gainB);\n>> -\n>> -\tfor (unsigned int i = 0; i < kRGBLookupSize; i++) {\n>> -\t\tconstexpr unsigned int div =\n>> -\t\t\tkRGBLookupSize * DebayerParams::kGain10 / kGammaLookupSize;\n>> -\t\tunsigned int idx;\n>> -\n>> -\t\t/* Apply gamma after gain! */\n>> -\t\tidx = std::min({ i * params.gainR / div, (kGammaLookupSize - 1) });\n>> -\t\tred_[i] = gamma_[idx];\n>> -\n>> -\t\tidx = std::min({ i * params.gainG / div, (kGammaLookupSize - 1) });\n>> -\t\tgreen_[i] = gamma_[idx];\n>> -\n>> -\t\tidx = std::min({ i * params.gainB / div, (kGammaLookupSize - 1) });\n>> -\t\tblue_[i] = gamma_[idx];\n>> -\t}\n>> +\tgreen_ = params.green;\n>> +\tred_ = swapRedBlueGains_ ? params.blue : params.red;\n>> +\tblue_ = swapRedBlueGains_ ? params.red : params.blue;\n>>  \n>>  \t/* Copy metadata from the input buffer */\n>>  \tFrameMetadata &metadata = output->_d()->metadata();\n>> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n>> index de216fe3..be7dcdca 100644\n>> --- a/src/libcamera/software_isp/debayer_cpu.h\n>> +++ b/src/libcamera/software_isp/debayer_cpu.h\n>> @@ -122,15 +122,12 @@ private:\n>>  \tvoid process2(const uint8_t *src, uint8_t *dst);\n>>  \tvoid process4(const uint8_t *src, uint8_t *dst);\n>>  \n>> -\tstatic constexpr unsigned int kGammaLookupSize = 1024;\n>> -\tstatic constexpr unsigned int kRGBLookupSize = 256;\n>>  \t/* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */\n>>  \tstatic constexpr unsigned int kMaxLineBuffers = 5;\n>>  \n>> -\tstd::array<uint8_t, kGammaLookupSize> gamma_;\n>> -\tstd::array<uint8_t, kRGBLookupSize> red_;\n>> -\tstd::array<uint8_t, kRGBLookupSize> green_;\n>> -\tstd::array<uint8_t, kRGBLookupSize> blue_;\n>> +\tDebayerParams::ColorLookupTable red_;\n>> +\tDebayerParams::ColorLookupTable green_;\n>> +\tDebayerParams::ColorLookupTable blue_;\n>>  \tdebayerFn debayer0_;\n>>  \tdebayerFn debayer1_;\n>>  \tdebayerFn debayer2_;\n>> @@ -146,8 +143,6 @@ private:\n>>  \tunsigned int xShift_; /* Offset of 0/1 applied to window_.x */\n>>  \tbool enableInputMemcpy_;\n>>  \tbool swapRedBlueGains_;\n>> -\tfloat gammaCorrection_;\n>> -\tunsigned int blackLevel_;\n>>  \tunsigned int measuredFrames_;\n>>  \tint64_t frameProcessTime_;\n>>  \t/* Skip 30 frames for things to stabilize then measure 30 frames */\n>> diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp\n>> index c9b6be56..ccd703bb 100644\n>> --- a/src/libcamera/software_isp/software_isp.cpp\n>> +++ b/src/libcamera/software_isp/software_isp.cpp\n>> @@ -7,6 +7,8 @@\n>>  \n>>  #include \"libcamera/internal/software_isp/software_isp.h\"\n>>  \n>> +#include <cmath>\n>> +#include <stdint.h>\n>>  #include <sys/mman.h>\n>>  #include <sys/types.h>\n>>  #include <unistd.h>\n>> @@ -18,6 +20,7 @@\n>>  #include \"libcamera/internal/framebuffer.h\"\n>>  #include \"libcamera/internal/ipa_manager.h\"\n>>  #include \"libcamera/internal/mapped_framebuffer.h\"\n>> +#include \"libcamera/internal/software_isp/debayer_params.h\"\n>>  \n>>  #include \"debayer_cpu.h\"\n>>  \n>> @@ -63,10 +66,24 @@ LOG_DEFINE_CATEGORY(SoftwareIsp)\n>>   * handler\n>>   */\n>>  SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor)\n>> -\t: debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10,\n>> -\t\t\t  DebayerParams::kGain10, 0.5f, 0 },\n>> -\t  dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System)\n>> +\t: dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System)\n>>  {\n>> +\t/*\n>> +\t * debayerParams_ must be initialized because the initial value is used for\n>> +\t * the first two frames, i.e. until stats processing starts providing its\n>> +\t * own parameters.\n>> +\t *\n>> +\t * \\todo This should be handled in the same place as the related operations.\n>\n> I would write\n>\n> \t * \\todo This should be handled in the same place as the related\n> \t * operations, in the IPA module.\n\nYes, OK.\n\n> No need to resubmit just for this, I can update the comment when\n> applying.\n\nThank you.\n\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>\n>> +\t */\n>> +\tstd::array<uint8_t, 256> gammaTable;\n>> +\tfor (unsigned int i = 0; i < 256; i++)\n>> +\t\tgammaTable[i] = UINT8_MAX * std::pow(i / 256.0, 0.5);\n>> +\tfor (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {\n>> +\t\tdebayerParams_.red[i] = gammaTable[i];\n>> +\t\tdebayerParams_.green[i] = gammaTable[i];\n>> +\t\tdebayerParams_.blue[i] = gammaTable[i];\n>> +\t}\n>> +\n>>  \tif (!dmaHeap_.isValid()) {\n>>  \t\tLOG(SoftwareIsp, Error) << \"Failed to create DmaHeap object\";\n>>  \t\treturn;","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 B87CABD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  3 Jun 2024 07:52:34 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C8FB9634CA;\n\tMon,  3 Jun 2024 09:52:33 +0200 (CEST)","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 5EE3E61A3B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  3 Jun 2024 09:52:31 +0200 (CEST)","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-110-acQIfWI6NY-F50j_yUMoxA-1; Mon, 03 Jun 2024 03:52:27 -0400","by mail-wm1-f69.google.com with SMTP id\n\t5b1f17b1804b1-4212b505781so16783935e9.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 03 Jun 2024 00:52:26 -0700 (PDT)","from nuthatch (ip-77-48-47-2.net.vodafone.cz. [77.48.47.2])\n\tby smtp.gmail.com with ESMTPSA id\n\t5b1f17b1804b1-4212b8b39aesm105938335e9.46.2024.06.03.00.52.24\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 03 Jun 2024 00:52:24 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"L2sveqWU\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1717401150;\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=8f1lbkUbyBq61P5/oGPQv3wCHfx/k+MqK6lVQrm+C+U=;\n\tb=L2sveqWUjqgGuHKrGbzTfDisJw2yXk05ts0earxSRF47LRCzD3C0plxnw0H1DO+ng3nwHp\n\tBO4pve9sWe9peRdg6DYVvqIF4yM5KZ0KTd7l9s+0HhFYvd5HCy+MYeRDGZrRvhl/9CoKRA\n\t034wopiTfbe0yojsfRcd+ZslwXZmVzU=","X-MC-Unique":"acQIfWI6NY-F50j_yUMoxA-1","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1717401146; x=1718005946;\n\th=mime-version:user-agent:message-id:date:references:in-reply-to\n\t:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=8f1lbkUbyBq61P5/oGPQv3wCHfx/k+MqK6lVQrm+C+U=;\n\tb=rqR6rkcEfuzpGNqz7f1xP87rUNdVbKItPatLxHKVmgRTarZ3WJEoDkdtkRI2p9Fyih\n\tF+4o931u1cXSNdkyGppKfV3bypKM6SB3zrvNxHQg64hETgeipx5nFB5MZ7nnf8aBT1m5\n\tAgJvtI9Ijwld9kAugG+GFU9SsOqjMkddY+cU6FXUeNVwV1Jl5VL3TcmpRcQmOLeWXiOX\n\taBaxFKWmhofNirFHtrqBJXVneMp30d0ab5LD/5eSD+c3g+tFKxWZdp6PwN6zyGAHGTCo\n\tETvYx+9h57ijs2nYeMTwgSh24+7WoGoYuRzy1rEGnhhMC/VADEZruUsEeq7exToxCclB\n\tcDyg==","X-Gm-Message-State":"AOJu0YxO4eookrxHNZzAhcEEbKuas/A7fWNlTlnxc6vo7JRweDyqe0ED\n\tgZgo6Wm9ml43kgULWFgp5cZSvRmqHgeDiR6LJzFs2s2zTmzUbQCg9zoHdJN6xIEn5bQDZKlouib\n\tUtPAb0+XQDob0ZyEpn+F6wkdIOO3OUmec57+OFskHD4rNtXvXFaUqoj0UEpZZMRtzVCKBtxg=","X-Received":["by 2002:a05:600c:4705:b0:421:28e6:9934 with SMTP id\n\t5b1f17b1804b1-42128e69fd2mr98092945e9.15.1717401145878; \n\tMon, 03 Jun 2024 00:52:25 -0700 (PDT)","by 2002:a05:600c:4705:b0:421:28e6:9934 with SMTP id\n\t5b1f17b1804b1-42128e69fd2mr98092655e9.15.1717401145243; \n\tMon, 03 Jun 2024 00:52:25 -0700 (PDT)"],"X-Google-Smtp-Source":"AGHT+IGAQHMZakzJH7h7jHZ4B5aNtfm7+x5ZtRZOw9uqDU1u/7+lRfmL/aks2TogZwI4vEyPwiU66g==","From":"Milan Zamazal <mzamazal@redhat.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,  Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>,  Andrei Konovalov\n\t<andrey.konovalov.ynk@gmail.com>","Subject":"Re: [PATCH v6 3/5] libcamera: software_isp: Move color mappings out\n\tof debayering","In-Reply-To":"<20240601225429.GB6683@pendragon.ideasonboard.com> (Laurent\n\tPinchart's message of \"Sun, 2 Jun 2024 01:54:29 +0300\")","References":"<20240531123840.713364-1-mzamazal@redhat.com>\n\t<20240531123840.713364-4-mzamazal@redhat.com>\n\t<20240601225429.GB6683@pendragon.ideasonboard.com>","Date":"Mon, 03 Jun 2024 09:52:24 +0200","Message-ID":"<87r0dempjb.fsf@redhat.com>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","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>"}}]