[{"id":18646,"web_url":"https://patchwork.libcamera.org/comment/18646/","msgid":"<YRHPn3QlS/ni/Gwa@pendragon.ideasonboard.com>","date":"2021-08-10T01:00:15","subject":"Re: [libcamera-devel] [PATCH v3 4/5] libcamera: ipu3: Initialize\n\tcontrols in the IPA","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nThank you for the patch.\n\nOn Mon, Aug 09, 2021 at 05:23:07PM +0200, Jacopo Mondi wrote:\n> All the IPU3 Camera controls are currently initialized by the pipeline\n> handler which initializes them using the camera sensor configuration and\n> platform specific requirements.\n> \n> However, some controls are better initialized by the IPA, which might,\n> in example, cap the exposure times and frame duration to the constraints\n> of its algorithms implementation.\n> \n> Also, moving forward, the IPA should register controls to report its\n> capabilities, in example the ability to enable/disable 3A algorithms on\n> request.\n> \n> Move the existing controls initialization to the IPA, by providing\n> the sensor configuration and its controls to the IPU3IPA::init()\n> function, which initializes controls and returns them to the pipeline\n> through an output parameter.\n> \n> The existing controls initialization has been copied verbatim from the\n> pipeline handler to the IPA, if not a for few line breaks adjustments\n> and the resulting Camera controls values are not changed .\n\ns/ .$/./\n\n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> ---\n>  include/libcamera/ipa/ipu3.mojom     |  5 +-\n>  src/ipa/ipu3/ipu3.cpp                | 71 ++++++++++++++++++++-\n>  src/libcamera/pipeline/ipu3/ipu3.cpp | 95 ++++++++++++----------------\n>  3 files changed, 113 insertions(+), 58 deletions(-)\n> \n> diff --git a/include/libcamera/ipa/ipu3.mojom b/include/libcamera/ipa/ipu3.mojom\n> index 911a3a072464..d561c2244907 100644\n> --- a/include/libcamera/ipa/ipu3.mojom\n> +++ b/include/libcamera/ipa/ipu3.mojom\n> @@ -38,7 +38,10 @@ struct IPAConfigInfo {\n>  };\n>  \n>  interface IPAIPU3Interface {\n> -\tinit(libcamera.IPASettings settings) => (int32 ret);\n> +\tinit(libcamera.IPASettings settings,\n> +\t     libcamera.IPACameraSensorInfo sensorInfo,\n> +\t     libcamera.ControlInfoMap sensorControls)\n> +\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls);\n>  \tstart() => (int32 ret);\n>  \tstop();\n>  \n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> index 71698d36e50f..5e4b2bdc9ace 100644\n> --- a/src/ipa/ipu3/ipu3.cpp\n> +++ b/src/ipa/ipu3/ipu3.cpp\n> @@ -5,8 +5,10 @@\n>   * ipu3.cpp - IPU3 Image Processing Algorithms\n>   */\n>  \n> +#include <array>\n>  #include <stdint.h>\n>  #include <sys/mman.h>\n> +#include <utility>\n>  \n>  #include <linux/intel-ipu3.h>\n>  #include <linux/v4l2-controls.h>\n> @@ -38,7 +40,11 @@ namespace ipa::ipu3 {\n>  class IPAIPU3 : public IPAIPU3Interface\n>  {\n>  public:\n> -\tint init(const IPASettings &settings) override;\n> +\tint init(const IPASettings &settings,\n> +\t\t const IPACameraSensorInfo &sensorInfo,\n> +\t\t const ControlInfoMap &sensorControls,\n> +\t\t ControlInfoMap *ipaControls) override;\n> +\n>  \tint start() override;\n>  \tvoid stop() override {}\n>  \n> @@ -86,14 +92,73 @@ private:\n>  \tstruct ipu3_uapi_grid_config bdsGrid_;\n>  };\n>  \n> -int IPAIPU3::init(const IPASettings &settings)\n> +/**\n> + * Initialize the IPA module and its controls.\n> + *\n> + * This function receives the camera sensor information from the pipeline\n> + * handler, computes the limits of the controls it handles and returns\n> + * them in the \\a ipaControls output parameter.\n> + */\n> +int IPAIPU3::init(const IPASettings &settings,\n> +\t\t  const IPACameraSensorInfo &sensorInfo,\n> +\t\t  const ControlInfoMap &sensorControls,\n> +\t\t  ControlInfoMap *ipaControls)\n>  {\n>  \tcamHelper_ = CameraSensorHelperFactory::create(settings.sensorModel);\n>  \tif (camHelper_ == nullptr) {\n> -\t\tLOG(IPAIPU3, Error) << \"Failed to create camera sensor helper for \" << settings.sensorModel;\n> +\t\tLOG(IPAIPU3, Error) << \"Failed to create camera sensor helper for \"\n> +\t\t\t\t    << settings.sensorModel;\n\nWhile at it, this could become\n\n\t\tLOG(IPAIPU3, Error)\n\t\t\t<< \"Failed to create camera sensor helper for \"\n\t\t\t<< settings.sensorModel;\n\n>  \t\treturn -ENODEV;\n>  \t}\n>  \n> +\t/* Initialize Controls. */\n> +\tControlInfoMap::Map controls{};\n> +\n> +\t/*\n> +\t * Compute exposure time limits.\n> +\t *\n> +\t * Initialize the control using the line length and pixel rate of the\n> +\t * current configuration converted to microseconds. Use the\n> +\t * V4L2_CID_EXPOSURE control to get exposure min, max and default and\n> +\t * convert it from lines to microseconds.\n> +\t */\n> +\tdouble lineDuration = sensorInfo.lineLength / (sensorInfo.pixelRate / 1e6);\n> +\tconst ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;\n> +\tint32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;\n> +\tint32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;\n> +\tint32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;\n> +\tcontrols[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure,\n> +\t\t\t\t\t\t\tdefExposure);\n> +\n> +\t/*\n> +\t * Compute the frame duration limits.\n> +\t *\n> +\t * The frame length is computed assuming a fixed line length combined\n> +\t * with the vertical frame sizes.\n> +\t */\n> +\tconst ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second;\n> +\tuint32_t hblank = v4l2HBlank.def().get<int32_t>();\n> +\tuint32_t lineLength = sensorInfo.outputSize.width + hblank;\n> +\n> +\tconst ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second;\n> +\tstd::array<uint32_t, 3> frameHeights{\n> +\t\tv4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height,\n> +\t\tv4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height,\n> +\t\tv4l2VBlank.def().get<int32_t>() + sensorInfo.outputSize.height,\n> +\t};\n> +\n> +\tstd::array<int64_t, 3> frameDurations;\n> +\tfor (unsigned int i = 0; i < frameHeights.size(); ++i) {\n> +\t\tuint64_t frameSize = lineLength * frameHeights[i];\n> +\t\tframeDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U);\n> +\t}\n> +\n> +\tcontrols[&controls::FrameDurationLimits] = ControlInfo(frameDurations[0],\n> +\t\t\t\t\t\t\t       frameDurations[1],\n> +\t\t\t\t\t\t\t       frameDurations[2]);\n> +\n> +\t*ipaControls = ControlInfoMap(std::move(controls), controls::controls);\n> +\n>  \treturn 0;\n>  }\n>  \n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> index 9c23788e5231..a2d2c887590f 100644\n> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> @@ -88,6 +88,8 @@ public:\n>  \n>  \tstd::queue<Request *> pendingRequests_;\n>  \n> +\tControlInfoMap ipaControls_;\n> +\n>  private:\n>  \tvoid queueFrameAction(unsigned int id,\n>  \t\t\t      const ipa::ipu3::IPU3Action &action);\n> @@ -954,7 +956,6 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data)\n>  \t\treturn ret;\n>  \n>  \tControlInfoMap::Map controls = IPU3Controls;\n> -\tconst ControlInfoMap &sensorControls = sensor->controls();\n>  \tconst std::vector<int32_t> &testPatternModes = sensor->testPatternModes();\n>  \tif (!testPatternModes.empty()) {\n>  \t\tstd::vector<ControlValue> values;\n> @@ -966,58 +967,6 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data)\n>  \t\tcontrols[&controls::draft::TestPatternMode] = ControlInfo(values);\n>  \t}\n>  \n> -\t/*\n> -\t * Compute exposure time limits.\n> -\t *\n> -\t * Initialize the control using the line length and pixel rate of the\n> -\t * current configuration converted to microseconds. Use the\n> -\t * V4L2_CID_EXPOSURE control to get exposure min, max and default and\n> -\t * convert it from lines to microseconds.\n> -\t */\n> -\tdouble lineDuration = sensorInfo.lineLength\n> -\t\t\t    / (sensorInfo.pixelRate / 1e6);\n> -\tconst ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;\n> -\tint32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;\n> -\tint32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;\n> -\tint32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;\n> -\n> -\t/*\n> -\t * \\todo Report the actual exposure time, use the default for the\n> -\t * moment.\n> -\t */\n> -\tdata->exposureTime_ = defExposure;\n> -\n> -\tcontrols[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure,\n> -\t\t\t\t\t\t\tdefExposure);\n> -\n> -\t/*\n> -\t * Compute the frame duration limits.\n> -\t *\n> -\t * The frame length is computed assuming a fixed line length combined\n> -\t * with the vertical frame sizes.\n> -\t */\n> -\tconst ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second;\n> -\tuint32_t hblank = v4l2HBlank.def().get<int32_t>();\n> -\tuint32_t lineLength = sensorInfo.outputSize.width + hblank;\n> -\n> -\tconst ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second;\n> -\tstd::array<uint32_t, 3> frameHeights{\n> -\t\tv4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height,\n> -\t\tv4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height,\n> -\t\tv4l2VBlank.def().get<int32_t>() + sensorInfo.outputSize.height,\n> -\t};\n> -\n> -\tstd::array<int64_t, 3> frameDurations;\n> -\tfor (unsigned int i = 0; i < frameHeights.size(); ++i) {\n> -\t\tuint64_t frameSize = lineLength * frameHeights[i];\n> -\t\tframeDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U);\n> -\t}\n> -\n> -\tcontrols[&controls::FrameDurationLimits] =\n> -\t\tControlInfo(frameDurations[0],\n> -\t\t\t    frameDurations[1],\n> -\t\t\t    frameDurations[2]);\n> -\n>  \t/*\n>  \t * Compute the scaler crop limits.\n>  \t *\n> @@ -1071,6 +1020,21 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data)\n>  \n>  \tcontrols[&controls::ScalerCrop] = ControlInfo(minCrop, maxCrop, maxCrop);\n>  \n> +\t/*\n> +\t * \\todo Report the actual exposure time, use the default for the\n> +\t * moment.\n> +\t */\n> +\tconst auto exposureInfo = data->ipaControls_.find(&controls::ExposureTime);\n> +\tif (exposureInfo == data->ipaControls_.end()) {\n> +\t\tLOG(IPU3, Error) << \"Exposure control not initialized by the IPA\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\tdata->exposureTime_ = exposureInfo->second.def().get<int32_t>();\n> +\n> +\t/* Add the IPA registered controls to list of camera controls. */\n> +\tfor (const auto &ipaControl : data->ipaControls_)\n> +\t\tcontrols[ipaControl.first] = ipaControl.second;\n> +\n>  \tdata->controlInfo_ = ControlInfoMap(std::move(controls),\n>  \t\t\t\t\t    controls::controls);\n>  \n> @@ -1223,8 +1187,31 @@ int IPU3CameraData::loadIPA()\n>  \n>  \tipa_->queueFrameAction.connect(this, &IPU3CameraData::queueFrameAction);\n>  \n> +\t/*\n> +\t * Pass the sensor info to the IPA to initialize controls.\n> +\t *\n> +\t * \\todo Find a way to initialize IPA controls without basing their\n> +\t * limits on a particular sensor mode. We currently pass sensor\n> +\t * information corresponding to the largest sensor resolution, and the\n> +\t * IPA uses this to compute limits for supported controls. There's a\n> +\t * discrepancy between the need to compute IPA control limits at init\n> +\t * time, and the fact that those limits may depend on the sensor mode.\n> +\t * Research is required to find out to handle this issue.\n> +         */\n\nNearly there, wrong indentation on the last line.\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n>  \tCameraSensor *sensor = cio2_.sensor();\n> -\tint ret = ipa_->init(IPASettings{ \"\", sensor->model() });\n> +\tV4L2SubdeviceFormat sensorFormat = {};\n> +\tsensorFormat.size = sensor->resolution();\n> +\tint ret = sensor->setFormat(&sensorFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tIPACameraSensorInfo sensorInfo{};\n> +\tret = sensor->sensorInfo(&sensorInfo);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tret = ipa_->init(IPASettings{ \"\", sensor->model() }, sensorInfo,\n> +\t\t\t sensor->controls(), &ipaControls_);\n>  \tif (ret) {\n>  \t\tLOG(IPU3, Error) << \"Failed to initialise the IPU3 IPA\";\n>  \t\treturn ret;","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 4B5BCC3240\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 10 Aug 2021 01:00:20 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BAD4568826;\n\tTue, 10 Aug 2021 03:00:19 +0200 (CEST)","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 15AC6687EB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 10 Aug 2021 03:00:19 +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 7A8F2466;\n\tTue, 10 Aug 2021 03:00:17 +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=\"kxgnGefz\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1628557217;\n\tbh=zugpxzm9LMfZZiJpCbGlsWmMHXRJO3eJfjcluxk132M=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=kxgnGefzAwPnQTnOI32B2CLih8kawuWvh+T8aHTDRqdDo+R7hhWZsotZgVcNE1Zqo\n\tI10MPUJKHvXiLiDPdaFArgUTkGgy25dwH+MPS0AO9qjjSNkDxjZu/gEf5Z15QBuAYW\n\t2hlBb8BgyadKvDKK6NfUbZDtDsIvH8jSYyBIIYOQ=","Date":"Tue, 10 Aug 2021 04:00:15 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<YRHPn3QlS/ni/Gwa@pendragon.ideasonboard.com>","References":"<20210809152308.31947-1-jacopo@jmondi.org>\n\t<20210809152308.31947-5-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20210809152308.31947-5-jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [PATCH v3 4/5] libcamera: ipu3: Initialize\n\tcontrols in the IPA","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","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]