[{"id":15083,"web_url":"https://patchwork.libcamera.org/comment/15083/","msgid":"<YCQGQx00eW6YOVcv@pendragon.ideasonboard.com>","date":"2021-02-10T16:13:55","subject":"Re: [libcamera-devel] [PATCH 2/2] ipa: raspberrypi: AWB: Fix race\n\tcondition setting manual gains","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi David,\n\nThank you for the patch.\n\nOn Wed, Feb 10, 2021 at 11:17:43AM +0000, David Plowman wrote:\n> Applying the manual_r_ and manual_b_ values is entirely removed from\n> the asynchronous thread where their use constituted a race hazard. The\n> main thread now deals with them entirely, involving the following\n> changes.\n> \n> 1. SetManualGains() applies the new values directly to the\n> \"sync_results\", meaning that Prepare() will jump to the new values\n> immediately (which is a better behaviour).\n> \n> 2. Process() does not restart the asynchronous thread when manual\n> gains are in force.\n> \n> 3. The asynchronous thread might be running when manual gains are set,\n> so we ignore the results produced in this case.\n\nThe code looks right to me,\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nI'd appreciate a review from Naush if possible though.\n\nA possible improvement would be to add a function to check if AWB is\nenabled:\n\nbool Awb::isAutoEnabled() const\n{\n\treturn manual_r_ == 0.0 || manual_b_ == 0.0;\n}\n\nThe rest of the code will be easier to read. This could be done in a v2\nof this patch, or in a separate patch.\n\n> Signed-off-by: David Plowman <david.plowman@raspberrypi.com>\n> ---\n>  src/ipa/raspberrypi/controller/rpi/awb.cpp | 78 ++++++++++------------\n>  1 file changed, 37 insertions(+), 41 deletions(-)\n> \n> diff --git a/src/ipa/raspberrypi/controller/rpi/awb.cpp b/src/ipa/raspberrypi/controller/rpi/awb.cpp\n> index 1c65eda8..46a8ce2a 100644\n> --- a/src/ipa/raspberrypi/controller/rpi/awb.cpp\n> +++ b/src/ipa/raspberrypi/controller/rpi/awb.cpp\n> @@ -193,28 +193,30 @@ void Awb::SetManualGains(double manual_r, double manual_b)\n>  \t// If any of these are 0.0, we swich back to auto.\n>  \tmanual_r_ = manual_r;\n>  \tmanual_b_ = manual_b;\n> +\t// If non-zero, set these values into the sync_results which means that\n> +\t// Prepare() will adopt them immediately.\n> +\tif (manual_r_ != 0.0 && manual_b_ != 0.0) {\n> +\t\tsync_results_.gain_r = prev_sync_results_.gain_r = manual_r_;\n> +\t\tsync_results_.gain_g = prev_sync_results_.gain_g = 1.0;\n> +\t\tsync_results_.gain_b = prev_sync_results_.gain_b = manual_b_;\n> +\t}\n>  }\n>  \n>  void Awb::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n>  \t\t     Metadata *metadata)\n>  {\n> -\t// If fixed colour gains have been set, we should let other algorithms\n> -\t// know by writing it into the image metadata.\n> -\tif (manual_r_ != 0.0 && manual_b_ != 0.0) {\n> -\t\tprev_sync_results_.gain_r = manual_r_;\n> -\t\tprev_sync_results_.gain_g = 1.0;\n> -\t\tprev_sync_results_.gain_b = manual_b_;\n> -\t\t// If we're starting up for the first time, try and\n> -\t\t// \"dead reckon\" the corresponding colour temperature.\n> -\t\tif (first_switch_mode_ && config_.bayes) {\n> -\t\t\tPwl ct_r_inverse = config_.ct_r.Inverse();\n> -\t\t\tPwl ct_b_inverse = config_.ct_b.Inverse();\n> -\t\t\tdouble ct_r = ct_r_inverse.Eval(ct_r_inverse.Domain().Clip(1 / manual_r_));\n> -\t\t\tdouble ct_b = ct_b_inverse.Eval(ct_b_inverse.Domain().Clip(1 / manual_b_));\n> -\t\t\tprev_sync_results_.temperature_K = (ct_r + ct_b) / 2;\n> -\t\t}\n> -\t\tsync_results_ = prev_sync_results_;\n> +\t// On the first mode switch we'll have no meaningful colour\n> +\t// temperature, so try to dead reckon one.\n> +\tif (manual_r_ != 0.0 && manual_b_ != 0.0 &&\n> +\t    first_switch_mode_ && config_.bayes) {\n> +\t\tPwl ct_r_inverse = config_.ct_r.Inverse();\n> +\t\tPwl ct_b_inverse = config_.ct_b.Inverse();\n> +\t\tdouble ct_r = ct_r_inverse.Eval(ct_r_inverse.Domain().Clip(1 / manual_r_));\n> +\t\tdouble ct_b = ct_b_inverse.Eval(ct_b_inverse.Domain().Clip(1 / manual_b_));\n> +\t\tprev_sync_results_.temperature_K = (ct_r + ct_b) / 2;\n> +\t\tsync_results_.temperature_K = prev_sync_results_.temperature_K;\n>  \t}\n> +\t// Let other algorithms know the current white balance values.\n>  \tmetadata->Set(\"awb.status\", prev_sync_results_);\n>  \tfirst_switch_mode_ = false;\n>  }\n> @@ -224,7 +226,10 @@ void Awb::fetchAsyncResults()\n>  \tLOG(RPiAwb, Debug) << \"Fetch AWB results\";\n>  \tasync_finished_ = false;\n>  \tasync_started_ = false;\n> -\tsync_results_ = async_results_;\n> +\t// It's possible manual gains could be set even while the async\n> +\t// thread was running. In this case, we ignore its results.\n> +\tif (manual_r_ == 0.0 || manual_b_ == 0.0)\n> +\t\tsync_results_ = async_results_;\n>  }\n>  \n>  void Awb::restartAsync(StatisticsPtr &stats, double lux)\n> @@ -289,8 +294,10 @@ void Awb::Process(StatisticsPtr &stats, Metadata *image_metadata)\n>  \tif (frame_phase_ < (int)config_.frame_period)\n>  \t\tframe_phase_++;\n>  \tLOG(RPiAwb, Debug) << \"frame_phase \" << frame_phase_;\n> -\tif (frame_phase_ >= (int)config_.frame_period ||\n> -\t    frame_count_ < (int)config_.startup_frames) {\n> +\t// We do not restart the async thread when we have fixed colour gains.\n> +\tif ((manual_r_ == 0.0 || manual_b_ == 0.0) &&\n> +\t    (frame_phase_ >= (int)config_.frame_period ||\n> +\t     frame_count_ < (int)config_.startup_frames)) {\n>  \t\t// Update any settings and any image metadata that we need.\n>  \t\tstruct LuxStatus lux_status = {};\n>  \t\tlux_status.lux = 400; // in case no metadata\n> @@ -614,29 +621,18 @@ void Awb::awbGrey()\n>  \n>  void Awb::doAwb()\n>  {\n> -\tif (manual_r_ != 0.0 && manual_b_ != 0.0) {\n> -\t\tasync_results_.temperature_K = 4500; // don't know what it is\n> -\t\tasync_results_.gain_r = manual_r_;\n> -\t\tasync_results_.gain_g = 1.0;\n> -\t\tasync_results_.gain_b = manual_b_;\n> +\tprepareStats();\n> +\tLOG(RPiAwb, Debug) << \"Valid zones: \" << zones_.size();\n> +\tif (zones_.size() > config_.min_regions) {\n> +\t\tif (config_.bayes)\n> +\t\t\tawbBayes();\n> +\t\telse\n> +\t\t\tawbGrey();\n>  \t\tLOG(RPiAwb, Debug)\n> -\t\t\t<< \"Using manual white balance: gain_r \"\n> -\t\t\t<< async_results_.gain_r << \" gain_b \"\n> -\t\t\t<< async_results_.gain_b;\n> -\t} else {\n> -\t\tprepareStats();\n> -\t\tLOG(RPiAwb, Debug) << \"Valid zones: \" << zones_.size();\n> -\t\tif (zones_.size() > config_.min_regions) {\n> -\t\t\tif (config_.bayes)\n> -\t\t\t\tawbBayes();\n> -\t\t\telse\n> -\t\t\t\tawbGrey();\n> -\t\t\tLOG(RPiAwb, Debug)\n> -\t\t\t\t<< \"CT found is \"\n> -\t\t\t\t<< async_results_.temperature_K\n> -\t\t\t\t<< \" with gains r \" << async_results_.gain_r\n> -\t\t\t\t<< \" and b \" << async_results_.gain_b;\n> -\t\t}\n> +\t\t\t<< \"CT found is \"\n> +\t\t\t<< async_results_.temperature_K\n> +\t\t\t<< \" with gains r \" << async_results_.gain_r\n> +\t\t\t<< \" and b \" << async_results_.gain_b;\n>  \t}\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 29D32BD160\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 10 Feb 2021 16:14:21 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id ABF486162A;\n\tWed, 10 Feb 2021 17:14: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 C5403602FE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 10 Feb 2021 17:14:19 +0100 (CET)","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 33AC731A;\n\tWed, 10 Feb 2021 17:14:19 +0100 (CET)"],"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=\"SmZLOgHB\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1612973659;\n\tbh=Eywp+jXwfA46A5lUz764WwR20JzMrKCwByfMPMrVIJI=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=SmZLOgHB652JGQ3JsGkjTn+Epqt7hTfiJGnWePk4DSE7iFXPD/HM+miFTb56TxUxs\n\tdw8T8WubY6JyY6IVw4JsQWL7DQWtx8oACJpkzzjhSTfl24pkjAUZxG0RsldN+xQw5u\n\tvjb/ghsIDZ8b7W+8x5a47WkKTmKpRI6t52dycuag=","Date":"Wed, 10 Feb 2021 18:13:55 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"David Plowman <david.plowman@raspberrypi.com>","Message-ID":"<YCQGQx00eW6YOVcv@pendragon.ideasonboard.com>","References":"<20210210111743.14374-1-david.plowman@raspberrypi.com>\n\t<20210210111743.14374-3-david.plowman@raspberrypi.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210210111743.14374-3-david.plowman@raspberrypi.com>","Subject":"Re: [libcamera-devel] [PATCH 2/2] ipa: raspberrypi: AWB: Fix race\n\tcondition setting manual gains","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>"}},{"id":15085,"web_url":"https://patchwork.libcamera.org/comment/15085/","msgid":"<CAEmqJPqtLBHHe0srO8=YfgvYmnRoA7-VPtbK+zkv0Z73ky8jcg@mail.gmail.com>","date":"2021-02-10T17:20:10","subject":"Re: [libcamera-devel] [PATCH 2/2] ipa: raspberrypi: AWB: Fix race\n\tcondition setting manual gains","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/people/34/","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"content":"Hi David,\n\nThank you for your work.\n\nOn Wed, 10 Feb 2021 at 11:17, David Plowman <david.plowman@raspberrypi.com>\nwrote:\n\n> Applying the manual_r_ and manual_b_ values is entirely removed from\n> the asynchronous thread where their use constituted a race hazard. The\n> main thread now deals with them entirely, involving the following\n> changes.\n>\n> 1. SetManualGains() applies the new values directly to the\n> \"sync_results\", meaning that Prepare() will jump to the new values\n> immediately (which is a better behaviour).\n>\n> 2. Process() does not restart the asynchronous thread when manual\n> gains are in force.\n>\n> 3. The asynchronous thread might be running when manual gains are set,\n> so we ignore the results produced in this case.\n>\n> Signed-off-by: David Plowman <david.plowman@raspberrypi.com>\n>\n\nI agree with Laurent's suggestion about having a isAutoEnabled() method.\nHowever, either way:\n\nReviewed-by: Naushir Patuck <naush@raspberrypi.com>\n\n\n> ---\n>  src/ipa/raspberrypi/controller/rpi/awb.cpp | 78 ++++++++++------------\n>  1 file changed, 37 insertions(+), 41 deletions(-)\n>\n> diff --git a/src/ipa/raspberrypi/controller/rpi/awb.cpp\n> b/src/ipa/raspberrypi/controller/rpi/awb.cpp\n> index 1c65eda8..46a8ce2a 100644\n> --- a/src/ipa/raspberrypi/controller/rpi/awb.cpp\n> +++ b/src/ipa/raspberrypi/controller/rpi/awb.cpp\n> @@ -193,28 +193,30 @@ void Awb::SetManualGains(double manual_r, double\n> manual_b)\n>         // If any of these are 0.0, we swich back to auto.\n>         manual_r_ = manual_r;\n>         manual_b_ = manual_b;\n> +       // If non-zero, set these values into the sync_results which means\n> that\n> +       // Prepare() will adopt them immediately.\n> +       if (manual_r_ != 0.0 && manual_b_ != 0.0) {\n> +               sync_results_.gain_r = prev_sync_results_.gain_r =\n> manual_r_;\n> +               sync_results_.gain_g = prev_sync_results_.gain_g = 1.0;\n> +               sync_results_.gain_b = prev_sync_results_.gain_b =\n> manual_b_;\n> +       }\n>  }\n>\n>  void Awb::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n>                      Metadata *metadata)\n>  {\n> -       // If fixed colour gains have been set, we should let other\n> algorithms\n> -       // know by writing it into the image metadata.\n> -       if (manual_r_ != 0.0 && manual_b_ != 0.0) {\n> -               prev_sync_results_.gain_r = manual_r_;\n> -               prev_sync_results_.gain_g = 1.0;\n> -               prev_sync_results_.gain_b = manual_b_;\n> -               // If we're starting up for the first time, try and\n> -               // \"dead reckon\" the corresponding colour temperature.\n> -               if (first_switch_mode_ && config_.bayes) {\n> -                       Pwl ct_r_inverse = config_.ct_r.Inverse();\n> -                       Pwl ct_b_inverse = config_.ct_b.Inverse();\n> -                       double ct_r =\n> ct_r_inverse.Eval(ct_r_inverse.Domain().Clip(1 / manual_r_));\n> -                       double ct_b =\n> ct_b_inverse.Eval(ct_b_inverse.Domain().Clip(1 / manual_b_));\n> -                       prev_sync_results_.temperature_K = (ct_r + ct_b) /\n> 2;\n> -               }\n> -               sync_results_ = prev_sync_results_;\n> +       // On the first mode switch we'll have no meaningful colour\n> +       // temperature, so try to dead reckon one.\n> +       if (manual_r_ != 0.0 && manual_b_ != 0.0 &&\n> +           first_switch_mode_ && config_.bayes) {\n> +               Pwl ct_r_inverse = config_.ct_r.Inverse();\n> +               Pwl ct_b_inverse = config_.ct_b.Inverse();\n> +               double ct_r =\n> ct_r_inverse.Eval(ct_r_inverse.Domain().Clip(1 / manual_r_));\n> +               double ct_b =\n> ct_b_inverse.Eval(ct_b_inverse.Domain().Clip(1 / manual_b_));\n> +               prev_sync_results_.temperature_K = (ct_r + ct_b) / 2;\n> +               sync_results_.temperature_K =\n> prev_sync_results_.temperature_K;\n>         }\n> +       // Let other algorithms know the current white balance values.\n>         metadata->Set(\"awb.status\", prev_sync_results_);\n>         first_switch_mode_ = false;\n>  }\n> @@ -224,7 +226,10 @@ void Awb::fetchAsyncResults()\n>         LOG(RPiAwb, Debug) << \"Fetch AWB results\";\n>         async_finished_ = false;\n>         async_started_ = false;\n> -       sync_results_ = async_results_;\n> +       // It's possible manual gains could be set even while the async\n> +       // thread was running. In this case, we ignore its results.\n> +       if (manual_r_ == 0.0 || manual_b_ == 0.0)\n> +               sync_results_ = async_results_;\n>  }\n>\n>  void Awb::restartAsync(StatisticsPtr &stats, double lux)\n> @@ -289,8 +294,10 @@ void Awb::Process(StatisticsPtr &stats, Metadata\n> *image_metadata)\n>         if (frame_phase_ < (int)config_.frame_period)\n>                 frame_phase_++;\n>         LOG(RPiAwb, Debug) << \"frame_phase \" << frame_phase_;\n> -       if (frame_phase_ >= (int)config_.frame_period ||\n> -           frame_count_ < (int)config_.startup_frames) {\n> +       // We do not restart the async thread when we have fixed colour\n> gains.\n> +       if ((manual_r_ == 0.0 || manual_b_ == 0.0) &&\n> +           (frame_phase_ >= (int)config_.frame_period ||\n> +            frame_count_ < (int)config_.startup_frames)) {\n>                 // Update any settings and any image metadata that we need.\n>                 struct LuxStatus lux_status = {};\n>                 lux_status.lux = 400; // in case no metadata\n> @@ -614,29 +621,18 @@ void Awb::awbGrey()\n>\n>  void Awb::doAwb()\n>  {\n> -       if (manual_r_ != 0.0 && manual_b_ != 0.0) {\n> -               async_results_.temperature_K = 4500; // don't know what it\n> is\n> -               async_results_.gain_r = manual_r_;\n> -               async_results_.gain_g = 1.0;\n> -               async_results_.gain_b = manual_b_;\n> +       prepareStats();\n> +       LOG(RPiAwb, Debug) << \"Valid zones: \" << zones_.size();\n> +       if (zones_.size() > config_.min_regions) {\n> +               if (config_.bayes)\n> +                       awbBayes();\n> +               else\n> +                       awbGrey();\n>                 LOG(RPiAwb, Debug)\n> -                       << \"Using manual white balance: gain_r \"\n> -                       << async_results_.gain_r << \" gain_b \"\n> -                       << async_results_.gain_b;\n> -       } else {\n> -               prepareStats();\n> -               LOG(RPiAwb, Debug) << \"Valid zones: \" << zones_.size();\n> -               if (zones_.size() > config_.min_regions) {\n> -                       if (config_.bayes)\n> -                               awbBayes();\n> -                       else\n> -                               awbGrey();\n> -                       LOG(RPiAwb, Debug)\n> -                               << \"CT found is \"\n> -                               << async_results_.temperature_K\n> -                               << \" with gains r \" <<\n> async_results_.gain_r\n> -                               << \" and b \" << async_results_.gain_b;\n> -               }\n> +                       << \"CT found is \"\n> +                       << async_results_.temperature_K\n> +                       << \" with gains r \" << async_results_.gain_r\n> +                       << \" and b \" << async_results_.gain_b;\n>         }\n>  }\n>\n> --\n> 2.20.1\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel\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 1B78CBD160\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 10 Feb 2021 17:20:30 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 763F361634;\n\tWed, 10 Feb 2021 18:20:29 +0100 (CET)","from mail-lf1-x12b.google.com (mail-lf1-x12b.google.com\n\t[IPv6:2a00:1450:4864:20::12b])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id CE1DA602FE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 10 Feb 2021 18:20:27 +0100 (CET)","by mail-lf1-x12b.google.com with SMTP id d3so3973566lfg.10\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 10 Feb 2021 09:20:27 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"A5rXn8RE\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=UJ6duhl4vET7BHoXrWPsOk3rVUYumHVe+EeHYexLYW4=;\n\tb=A5rXn8REcH/kG/wEf10z4DOWbbeQfMihXBKVEMOM+cibqN0nYF7Z1/XZ6drutrwv27\n\tQ1ULD2f7T+mcWtkF4+sqBVFMI9B0E/No0xzk7tUNRpNkPNUFdm263Ez8TKBUMr1fp3U1\n\tmPDf0YoNtdSVm46YgGz4/i4vUNXpzIUcPpdvLdacpqmGETd7ccFYYCKxnnwkQv9sOlpG\n\t0UfJwbt7gfqkGWAh417GJNGhgvzZcpud58Rp1R6afjoiM28cBG1rPMm/QLk2CA1ovf2F\n\trIMMjvk2ZJf6Y9+Q7tzuZaY4a57nKCKn8Ckyk/40EtkhxRs+TLPNjNiMyh3jM5VUUutp\n\tYk8Q==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=UJ6duhl4vET7BHoXrWPsOk3rVUYumHVe+EeHYexLYW4=;\n\tb=re2pU4G3flDsW9GeqQHcwGXt2c0cM92rWMYTsOydH8kEGXBNFAXDfaeYk9ICCAmYyQ\n\t2gg+NEs8nZcn2FaE8gc1ktpElJSSRDeJtrfaHCU0ux+rNqSQpCkI30PV+UEpThHYxq7a\n\twexppRaQX182a5JXBfDaWcKWqjdR3iCRb61G7kXUhDYy5YpiKt+gfYjXPxIea3uBJzA6\n\tar61/lxc8HPDo9FvOowVyllISkC7ztEwQ1Yz2Z0oXhQuF1nh+s6u+e6XAdP0Q639X4zC\n\tcQzPhK0U/5IIPhp7NLLtUUcDGeAKkwCa4KdjAsG1cUrwUfyKFR3nlomb8mLJK3CPLZKn\n\t6LRg==","X-Gm-Message-State":"AOAM531NxkvJPgYh64RcmhgfFYu6fNbsuJB0rNE2TRSb1PsgOLBYQ8MK\n\thc8Db7AMK81HItjif07ibVFvDUlso5YabSNZZXdd/52Q6kMMuA==","X-Google-Smtp-Source":"ABdhPJyfE0ZkKc1zd8h/s6KsZsoqx6ARA146OQoY9EnIhsc78NEgLKKS8SWomBiCfJsdZ5SpH8X2+PjAYkri7xZNcqs=","X-Received":"by 2002:ac2:44c3:: with SMTP id d3mr2159076lfm.375.1612977627112;\n\tWed, 10 Feb 2021 09:20:27 -0800 (PST)","MIME-Version":"1.0","References":"<20210210111743.14374-1-david.plowman@raspberrypi.com>\n\t<20210210111743.14374-3-david.plowman@raspberrypi.com>","In-Reply-To":"<20210210111743.14374-3-david.plowman@raspberrypi.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Wed, 10 Feb 2021 17:20:10 +0000","Message-ID":"<CAEmqJPqtLBHHe0srO8=YfgvYmnRoA7-VPtbK+zkv0Z73ky8jcg@mail.gmail.com>","To":"David Plowman <david.plowman@raspberrypi.com>","Subject":"Re: [libcamera-devel] [PATCH 2/2] ipa: raspberrypi: AWB: Fix race\n\tcondition setting manual gains","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 <libcamera-devel@lists.libcamera.org>","Content-Type":"multipart/mixed;\n\tboundary=\"===============8476793880438085768==\"","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]