[{"id":16046,"web_url":"https://patchwork.libcamera.org/comment/16046/","msgid":"<YGKgNqEYE3SZLuVk@pendragon.ideasonboard.com>","date":"2021-03-30T03:51:18","subject":"Re: [libcamera-devel] [PATCH v3 4/5] ipa: ipu3: Add support for\n\tIPU3 AWB algorithm","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jean-Michel,\n\nThank you for the patch.\n\nOn Mon, Mar 29, 2021 at 09:18:25PM +0200, Jean-Michel Hautbois wrote:\n> Inherit from the Algorithm class to implement basic AWB functions.\n> \n> Once AWB is done, a color temperature is estimated and a default CCM matrice\n\ns/matrice/matrix/\n\n> is used (yet to be tuned).\n\nSee 3/5. The same applies below.\n\n> Implement a basic \"grey-world\" AWB algorithm just for demonstration purpose.\n> \n> BDS output size is passed by the pipeline handler to the IPA.\n\n\"The BDS ...\"\n\n> The best grid is then calculated to maximize the number of pixels taken\n> into account in each cells.\n> As commented in the source code, it can be improved, as ithas (at least)\n\ns/ithas/it has/\n\n> one limitation: if a cell is big (say 128 pixels wide) and indicated as\n> saturated, it won't be taken into account at all.\n> Maybe is it possible to have a smaller one, at the cost of a few pixels\n\nA similar what ?\n\n> to lose. In which case we can center the grid using the x_start and\n\ns/to lose. In which case/to lose, in which case/\n\n> y_start parameters.\n>\n> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>\n> ---\n>  src/ipa/ipu3/ipu3.cpp     |  74 +++++++++++-\n>  src/ipa/ipu3/ipu3_awb.cpp | 233 ++++++++++++++++++++++++++++++++++++++\n>  src/ipa/ipu3/ipu3_awb.h   |  44 +++++++\n>  src/ipa/ipu3/meson.build  |   1 +\n>  4 files changed, 346 insertions(+), 6 deletions(-)\n>  create mode 100644 src/ipa/ipu3/ipu3_awb.cpp\n>  create mode 100644 src/ipa/ipu3/ipu3_awb.h\n> \n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> index 07dbc24a..cc741d69 100644\n> --- a/src/ipa/ipu3/ipu3.cpp\n> +++ b/src/ipa/ipu3/ipu3.cpp\n> @@ -21,6 +21,11 @@\n>  #include \"libcamera/internal/buffer.h\"\n>  #include \"libcamera/internal/log.h\"\n>  \n> +#include \"ipu3_awb.h\"\n> +\n> +static const uint32_t kMaxCellWidthPerSet = 160;\n> +static const uint32_t kMaxCellHeightPerSet = 80;\n\ns/const/constexpr/\n\n> +\n>  namespace libcamera {\n>  \n>  LOG_DEFINE_CATEGORY(IPAIPU3)\n> @@ -62,8 +67,12 @@ private:\n>  \tuint32_t minGain_;\n>  \tuint32_t maxGain_;\n>  \n> +\t/* Interface to the AWB algorithm */\n> +\tstd::unique_ptr<ipa::IPU3Awb> awbAlgo_;\n\nBlank line.\n\n>  \t/* Local parameter storage */\n> -\tipu3_uapi_params params_;\n> +\tstruct ipu3_uapi_params params_;\n\nThe struct should have been in the previous patch. But as that part of\nthe previous patch should be moved here, that doesn't matter much.\n\n> +\n> +\tstruct ipu3_uapi_grid_config bdsGrid_;\n>  };\n>  \n>  int IPAIPU3::start()\n> @@ -73,6 +82,51 @@ int IPAIPU3::start()\n>  \treturn 0;\n>  }\n>  \n> +/* This method calculates a grid for the AWB algorithm in the IPU3 firmware.\n> + * Its input it the BDS output size calculated in the imgU.\n\ns/it the/is the/\n\n> + * It is limited for now to the simplest method: find the lesser error\n> + * with the width/height and respective log2 width/height of the cells.\n> + * \\todo smaller cells are better so adapt x_start to lose a bit but have\n> + * a better average resolution. If a cell is saturated, it might make a big difference. */\n\nI'm afraid I don't understand this :-(\n\nPlease reflow this text, and write the comment as\n\n/*\n * ...\n * ...\n */\n\n> +void IPAIPU3::calculateBdsGrid(const Size &bdsOutputSize)\n\nThis function isn't used in this patch, and not even declared in the\nclass. This will break bisection.\n\n> +{\n> +\tstd::vector<uint32_t> log2WidthVector = { 3, 4, 5, 6, 7 };\n> +\tstd::vector<uint32_t> log2HeightVector = { 3, 4, 5, 6, 7 };\n> +\tuint32_t minError = std::numeric_limits<uint32_t>::max();\n> +\tuint32_t bestWidth = 0;\n> +\tuint32_t bestHeight = 0;\n> +\tuint32_t bestLog2Width = 0;\n> +\tuint32_t bestLog2Height = 0;\n> +\tbdsGrid_ = {};\n> +\n> +\tfor (uint32_t i = 0; i < log2WidthVector.size(); ++i) {\n\nThe i variable is only used to index log2WidthVector, you can thus use a\nrange-based loop. Or even better, you can write\n\n\tfor (unsigned int widthShift = 3; widthShift <= 7; ++widthShift) {\n\n> +\t\tuint32_t width = std::min(kMaxCellWidthPerSet, bdsOutputSize.width >> log2WidthVector[i]);\n\nLine length, and below too.\n\n> +\t\twidth = width << log2WidthVector[i];\n> +\t\tfor (uint32_t j = 0; j < log2HeightVector.size(); ++j) {\n\nSame here.\n\n> +\t\t\tint32_t height = std::min(kMaxCellHeightPerSet, bdsOutputSize.height >> log2HeightVector[j]);\n> +\t\t\theight = height << log2HeightVector[j];\n> +\t\t\tuint32_t error = std::abs((int)(width - bdsOutputSize.width)) + std::abs((int)(height - bdsOutputSize.height));\n\nC++-style casts, and below too.\n\n> +\n> +\t\t\tif (error > minError)\n> +\t\t\t\tcontinue;\n> +\n> +\t\t\tminError = error;\n> +\t\t\tbestWidth = width;\n> +\t\t\tbestHeight = height;\n> +\t\t\tbestLog2Width = log2WidthVector[i];\n> +\t\t\tbestLog2Height = log2HeightVector[j];\n> +\t\t}\n> +\t}\n> +\n> +\tbdsGrid_.width = bestWidth >> bestLog2Width;\n> +\tbdsGrid_.block_width_log2 = bestLog2Width;\n> +\tbdsGrid_.height = bestHeight >> bestLog2Height;\n> +\tbdsGrid_.block_height_log2 = bestLog2Height;\n\nBlank line.\n\n> +\tLOG(IPAIPU3, Debug) << \"Best grid found is: (\"\n> +\t\t\t    << (int)bdsGrid_.width << \" << \" << (int)bdsGrid_.block_width_log2 << \") x (\"\n> +\t\t\t    << (int)bdsGrid_.height << \"<<\" << (int)bdsGrid_.block_height_log2 << \")\";\n> +}\n> +\n>  void IPAIPU3::configure(const std::map<uint32_t, ControlInfoMap> &entityControls,\n>  \t\t\t[[maybe_unused]] const Size &bdsOutputSize)\n\nYou now make use of this parameter.\n\n>  {\n> @@ -103,6 +157,9 @@ void IPAIPU3::configure(const std::map<uint32_t, ControlInfoMap> &entityControls\n>  \n>  \tparams_ = {};\n>  \n> +\tawbAlgo_ = std::make_unique<ipa::IPU3Awb>();\n> +\tawbAlgo_->initialise(params_, bdsOutputSize, bdsGrid_);\n> +\n>  \tsetControls(0);\n>  }\n>  \n> @@ -175,10 +232,9 @@ void IPAIPU3::processControls([[maybe_unused]] unsigned int frame,\n>  \n>  void IPAIPU3::fillParams(unsigned int frame, ipu3_uapi_params *params)\n>  {\n> -\t/* Prepare parameters buffer. */\n> -\tmemset(params, 0, sizeof(*params));\n> +\tawbAlgo_->updateWbParameters(params_, 1.0);\n>  \n> -\t/* \\todo Fill in parameters buffer. */\n> +\t*params = params_;\n>  \n>  \tipa::ipu3::IPU3Action op;\n>  \top.op = ipa::ipu3::ActionParamFilled;\n> @@ -191,8 +247,14 @@ void IPAIPU3::parseStatistics(unsigned int frame,\n>  {\n>  \tControlList ctrls(controls::controls);\n>  \n> -\t/* \\todo React to statistics and update internal state machine. */\n> -\t/* \\todo Add meta-data information to ctrls. */\n> +\tif (!stats->stats_3a_status.awb_en) {\n> +\t\tLOG(IPAIPU3, Error) << \"AWB stats are not enabled\";\n\nSounds like something for the awb algorithm to complain about.\n\n> +\t} else {\n> +\t\tagcAlgo_->process(stats, exposure_, gain_);\n\nThere's no agcAlgo_ in this patch, it comes in 5/5.\n\nI'll stop the review of this series here, and resume in v4.\n\n> +\t\tawbAlgo_->calculateWBGains(stats);\n> +\t\tif (agcAlgo_->updateControls())\n> +\t\t\tsetControls(frame);\n> +\t}\n>  \n>  \tipa::ipu3::IPU3Action op;\n>  \top.op = ipa::ipu3::ActionMetadataReady;\n> diff --git a/src/ipa/ipu3/ipu3_awb.cpp b/src/ipa/ipu3/ipu3_awb.cpp\n> new file mode 100644\n> index 00000000..c63eb08f\n> --- /dev/null\n> +++ b/src/ipa/ipu3/ipu3_awb.cpp\n> @@ -0,0 +1,233 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Ideas On Board\n> + *\n> + * ipu3_awb.cpp - AWB control algorithm\n> + */\n> +#include \"ipu3_awb.h\"\n> +\n> +#include <cmath>\n> +#include <numeric>\n> +#include <unordered_map>\n> +\n> +#include \"libcamera/internal/log.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +LOG_DEFINE_CATEGORY(IPU3Awb)\n> +\n> +static const struct ipu3_uapi_bnr_static_config imguCssBnrDefaults = {\n> +\t.wb_gains = { 16, 16, 16, 16 },\n> +\t.wb_gains_thr = { 255, 255, 255, 255 },\n> +\t.thr_coeffs = { 1700, 0, 31, 31, 0, 16 },\n> +\t.thr_ctrl_shd = { 26, 26, 26, 26 },\n> +\t.opt_center{ -648, 0, -366, 0 },\n> +\t.lut = {\n> +\t\t{ 17, 23, 28, 32, 36, 39, 42, 45,\n> +\t\t  48, 51, 53, 55, 58, 60, 62, 64,\n> +\t\t  66, 68, 70, 72, 73, 75, 77, 78,\n> +\t\t  80, 82, 83, 85, 86, 88, 89, 90 } },\n> +\t.bp_ctrl = { 20, 0, 1, 40, 0, 6, 0, 6, 0 },\n> +\t.dn_detect_ctrl{ 9, 3, 4, 0, 8, 0, 1, 1, 1, 1, 0 },\n> +\t.column_size = 1296,\n> +\t.opt_center_sqr = { 419904, 133956 },\n> +};\n> +\n> +/* settings for Auto White Balance */\n> +static const struct ipu3_uapi_awb_config_s imguCssAwbDefaults = {\n> +\t.rgbs_thr_gr = 8191,\n> +\t.rgbs_thr_r = 8191,\n> +\t.rgbs_thr_gb = 8191,\n> +\t.rgbs_thr_b = 8191 | IPU3_UAPI_AWB_RGBS_THR_B_EN | IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT,\n> +\t.grid = {\n> +\t\t.width = 160,\n> +\t\t.height = 36,\n> +\t\t.block_width_log2 = 3,\n> +\t\t.block_height_log2 = 4,\n> +\t\t.height_per_slice = 1, /* Overridden by kernel. */\n> +\t\t.x_start = 0,\n> +\t\t.y_start = 0,\n> +\t\t.x_end = 0,\n> +\t\t.y_end = 0,\n> +\t},\n> +};\n> +\n> +static const struct ipu3_uapi_ccm_mat_config imguCssCcmDefault = {\n> +\t8191, 0, 0, 0,\n> +\t0, 8191, 0, 0,\n> +\t0, 0, 8191, 0\n> +};\n> +\n> +IPU3Awb::IPU3Awb()\n> +\t: Algorithm()\n> +{\n> +}\n> +\n> +IPU3Awb::~IPU3Awb()\n> +{\n> +}\n> +\n> +void IPU3Awb::initialise(ipu3_uapi_params &params, const Size &bdsOutputSize, struct ipu3_uapi_grid_config &bdsGrid)\n> +{\n> +\tparams.use.acc_awb = 1;\n> +\tparams.acc_param.awb.config = imguCssAwbDefaults;\n> +\n> +\tawbGrid_ = bdsGrid;\n> +\tparams.acc_param.awb.config.grid = awbGrid_;\n> +\n> +\tparams.use.obgrid = 0;\n> +\tparams.obgrid_param.gr = 20;\n> +\tparams.obgrid_param.r = 28;\n> +\tparams.obgrid_param.b = 28;\n> +\tparams.obgrid_param.gb = 20;\n> +\n> +\tparams.use.acc_bnr = 1;\n> +\tparams.acc_param.bnr = imguCssBnrDefaults;\n> +\tparams.acc_param.bnr.opt_center.x_reset = -1 * (bdsOutputSize.width / 2);\n> +\tparams.acc_param.bnr.opt_center.y_reset = -1 * (bdsOutputSize.height / 2);\n> +\tparams.acc_param.bnr.column_size = bdsOutputSize.width;\n> +\tparams.acc_param.bnr.opt_center_sqr.x_sqr_reset = params.acc_param.bnr.opt_center.x_reset * params.acc_param.bnr.opt_center.x_reset;\n> +\tparams.acc_param.bnr.opt_center_sqr.y_sqr_reset = params.acc_param.bnr.opt_center.y_reset * params.acc_param.bnr.opt_center.y_reset;\n> +\n> +\tparams.use.acc_ccm = 1;\n> +\tparams.acc_param.ccm = imguCssCcmDefault;\n> +\n> +\tparams.use.acc_gamma = 1;\n> +\tparams.acc_param.gamma.gc_ctrl.enable = 1;\n> +\n> +\tparams.use.acc_green_disparity = 0;\n> +\tparams.acc_param.green_disparity.gd_black = 2440;\n> +\tparams.acc_param.green_disparity.gd_red = 4;\n> +\tparams.acc_param.green_disparity.gd_blue = 4;\n> +\tparams.acc_param.green_disparity.gd_green = 4;\n> +\tparams.acc_param.green_disparity.gd_shading = 24;\n> +\tparams.acc_param.green_disparity.gd_support = 2;\n> +\tparams.acc_param.green_disparity.gd_clip = 1;\n> +\tparams.acc_param.green_disparity.gd_central_weight = 5;\n> +\n> +\tparams.use.acc_cds = 1;\n> +\tparams.acc_param.cds.csc_en = 1;\n> +\tparams.acc_param.cds.uv_bin_output = 0;\n> +\tparams.acc_param.cds.ds_c00 = 0;\n> +\tparams.acc_param.cds.ds_c01 = 1;\n> +\tparams.acc_param.cds.ds_c02 = 1;\n> +\tparams.acc_param.cds.ds_c03 = 0;\n> +\tparams.acc_param.cds.ds_c10 = 0;\n> +\tparams.acc_param.cds.ds_c11 = 1;\n> +\tparams.acc_param.cds.ds_c12 = 1;\n> +\tparams.acc_param.cds.ds_c13 = 0;\n> +\tparams.acc_param.cds.ds_nf = 2;\n> +\n> +\twbGains_[0] = 16;\n> +\twbGains_[1] = 4096;\n> +\twbGains_[2] = 4096;\n> +\twbGains_[3] = 16;\n> +\n> +\tframe_count_ = 0;\n> +}\n> +\n> +uint32_t IPU3Awb::estimateCCT(uint8_t red, uint8_t green, uint8_t blue)\n> +{\n> +\tdouble X = (-0.14282) * (red) + (1.54924) * (green) + (-0.95641) * (blue);\n> +\tdouble Y = (-0.32466) * (red) + (1.57837) * (green) + (-0.73191) * (blue);\n> +\tdouble Z = (-0.68202) * (red) + (0.77073) * (green) + (0.56332) * (blue);\n> +\n> +\tdouble x = X / (X + Y + Z);\n> +\tdouble y = Y / (X + Y + Z);\n> +\n> +\tdouble n = (x - 0.3320) / (0.1858 - y);\n> +\treturn static_cast<uint32_t>(449 * n * n * n + 3525 * n * n + 6823.3 * n + 5520.33);\n> +}\n> +\n> +double meanValue(std::vector<uint32_t> colorValues)\n> +{\n> +\tuint32_t count = 0;\n> +\tuint32_t hist[256] = { 0 };\n> +\tfor (uint32_t const &val : colorValues) {\n> +\t\thist[val]++;\n> +\t\tcount++;\n> +\t}\n> +\n> +\tdouble mean = 0.0;\n> +\tfor (uint32_t i = 0; i < 256; i++) {\n> +\t\tmean += hist[i] * i;\n> +\t}\n> +\treturn mean /= count;\n> +}\n> +\n> +void IPU3Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)\n> +{\n> +\tstd::vector<uint32_t> redValues, greenValues, blueValues;\n> +\tconst struct ipu3_uapi_grid_config statsAwbGrid = stats->stats_4a_config.awb_config.grid;\n> +\tRectangle awbRegion = { statsAwbGrid.x_start,\n> +\t\t\t\tstatsAwbGrid.y_start,\n> +\t\t\t\tstatic_cast<unsigned int>(statsAwbGrid.x_end - statsAwbGrid.x_start) + 1,\n> +\t\t\t\tstatic_cast<unsigned int>(statsAwbGrid.y_end - statsAwbGrid.y_start) + 1 };\n> +\n> +\tPoint topleft = awbRegion.topLeft();\n> +\tuint32_t startY = (topleft.y >> awbGrid_.block_height_log2) * awbGrid_.width << awbGrid_.block_width_log2;\n> +\tuint32_t startX = (topleft.x >> awbGrid_.block_width_log2) << awbGrid_.block_width_log2;\n> +\tuint32_t endX = (startX + (awbRegion.size().width >> awbGrid_.block_width_log2)) << awbGrid_.block_width_log2;\n> +\tuint32_t count = 0;\n> +\tuint32_t i, j;\n> +\n> +\tawbCounted_ = 0;\n> +\tfor (j = (topleft.y >> awbGrid_.block_height_log2);\n> +\t     j < (topleft.y >> awbGrid_.block_height_log2) + (awbRegion.size().height >> awbGrid_.block_height_log2);\n> +\t     j++) {\n> +\t\tfor (i = startX + startY; i < endX + startY; i += 8) {\n> +\t\t\tif (stats->awb_raw_buffer.meta_data[i + 4 + j * awbGrid_.width] == 0) {\n> +\t\t\t\tgreenValues.push_back(stats->awb_raw_buffer.meta_data[i + j * awbGrid_.width]);\n> +\t\t\t\tredValues.push_back(stats->awb_raw_buffer.meta_data[i + 1 + j * awbGrid_.width]);\n> +\t\t\t\tblueValues.push_back(stats->awb_raw_buffer.meta_data[i + 2 + j * awbGrid_.width]);\n> +\t\t\t\tgreenValues.push_back(stats->awb_raw_buffer.meta_data[i + 3 + j * awbGrid_.width]);\n> +\t\t\t\tawbCounted_++;\n> +\t\t\t}\n> +\t\t\tcount++;\n> +\t\t}\n> +\t}\n> +\n> +\tdouble rMean = meanValue(redValues);\n> +\tdouble bMean = meanValue(blueValues);\n> +\tdouble gMean = meanValue(greenValues);\n> +\n> +\tdouble rGain = gMean / rMean;\n> +\tdouble bGain = gMean / bMean;\n> +\n> +\twbGains_[0] = 16;\n> +\twbGains_[1] = 4096 * rGain;\n> +\twbGains_[2] = 4096 * bGain;\n> +\twbGains_[3] = 16;\n> +\n> +\tframe_count_++;\n> +\n> +\tcct_ = estimateCCT(rMean, gMean, bMean);\n> +}\n> +\n> +void IPU3Awb::updateWbParameters(ipu3_uapi_params &params, double agcGamma)\n> +{\n> +\tif ((wbGains_[0] == 0) || (wbGains_[1] == 0) || (wbGains_[2] == 0) || (wbGains_[3] == 0)) {\n> +\t\tLOG(IPU3Awb, Error) << \"Gains can't be 0, check the stats\";\n> +\t} else {\n> +\t\tparams.acc_param.bnr.wb_gains.gr = wbGains_[0];\n> +\t\tparams.acc_param.bnr.wb_gains.r = wbGains_[1];\n> +\t\tparams.acc_param.bnr.wb_gains.b = wbGains_[2];\n> +\t\tparams.acc_param.bnr.wb_gains.gb = wbGains_[3];\n> +\n> +\t\tLOG(IPU3Awb, Debug) << \"Color temperature estimated: \" << cct_\n> +\t\t\t\t    << \" and gamma calculated: \" << agcGamma;\n> +\t\tparams.acc_param.ccm = imguCssCcmDefault;\n> +\n> +\t\tfor (uint32_t i = 0; i < 256; i++) {\n> +\t\t\tdouble j = i / 255.0;\n> +\t\t\tdouble gamma = std::pow(j, 1.0 / agcGamma);\n> +\t\t\tparams.acc_param.gamma.gc_lut.lut[i] = gamma * 8191;\n> +\t\t}\n> +\t}\n> +}\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/ipu3/ipu3_awb.h b/src/ipa/ipu3/ipu3_awb.h\n> new file mode 100644\n> index 00000000..a14401a0\n> --- /dev/null\n> +++ b/src/ipa/ipu3/ipu3_awb.h\n> @@ -0,0 +1,44 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Ideas On Board\n> + *\n> + * ipu3_awb.h - IPU3 AWB control algorithm\n> + */\n> +#ifndef __LIBCAMERA_IPU3_AWB_H__\n> +#define __LIBCAMERA_IPU3_AWB_H__\n> +\n> +#include <linux/intel-ipu3.h>\n> +\n> +#include <libcamera/geometry.h>\n> +\n> +#include \"libipa/algorithm.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +class IPU3Awb : public Algorithm\n> +{\n> +public:\n> +\tIPU3Awb();\n> +\t~IPU3Awb();\n> +\n> +\tvoid initialise(ipu3_uapi_params &params, const Size &bdsOutputSize, struct ipu3_uapi_grid_config &bdsGrid);\n> +\tvoid calculateWBGains(const ipu3_uapi_stats_3a *stats);\n> +\tvoid updateWbParameters(ipu3_uapi_params &params, double agcGamma);\n> +\n> +private:\n> +\tuint32_t estimateCCT(uint8_t red, uint8_t green, uint8_t blue);\n> +\n> +\t/* WB calculated gains */\n> +\tuint16_t wbGains_[4];\n> +\tuint32_t cct_;\n> +\tuint32_t awbCounted_;\n> +\tstruct ipu3_uapi_grid_config awbGrid_;\n> +\tuint32_t frame_count_;\n> +};\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera*/\n> +#endif /* __LIBCAMERA_IPU3_AWB_H__ */\n> diff --git a/src/ipa/ipu3/meson.build b/src/ipa/ipu3/meson.build\n> index 52d98c8e..07a864c8 100644\n> --- a/src/ipa/ipu3/meson.build\n> +++ b/src/ipa/ipu3/meson.build\n> @@ -4,6 +4,7 @@ ipa_name = 'ipa_ipu3'\n>  \n>  ipu3_ipa_sources = files([\n>    'ipu3.cpp',\n> +  'ipu3_awb.cpp',\n>  ])\n>  \n>  mod = shared_module(ipa_name,","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 78088C32F0\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 30 Mar 2021 03:52:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E188C602D7;\n\tTue, 30 Mar 2021 05:52:04 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3E337602D7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 30 Mar 2021 05:52:03 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8A091292;\n\tTue, 30 Mar 2021 05:52:02 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"URbSmWEB\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1617076322;\n\tbh=ISTNzrPvG64n5vfh1FrNukBv7JjIrFjewtdGESzrigQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=URbSmWEB6qwib65WV4t4zL9g+ue+3YA7IS8QtTHGYlOPCJ0/BM4M9sD77dYsX34B3\n\tgqESG/kLRzGd61eajUZsfN+T+ZsItDPegskB73RJvYV/gKIPlGdw79S/eNvCY3PnGv\n\trPDtrrYTVtuG7GdJPiFkPBy0oA9xGD4pYv0oE0tA=","Date":"Tue, 30 Mar 2021 06:51:18 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>","Message-ID":"<YGKgNqEYE3SZLuVk@pendragon.ideasonboard.com>","References":"<20210329191826.77817-1-jeanmichel.hautbois@ideasonboard.com>\n\t<20210329191826.77817-5-jeanmichel.hautbois@ideasonboard.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210329191826.77817-5-jeanmichel.hautbois@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v3 4/5] ipa: ipu3: Add support for\n\tIPU3 AWB algorithm","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>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]