[{"id":18508,"web_url":"https://patchwork.libcamera.org/comment/18508/","msgid":"<20210803100238.GA2167@pyrite.rasen.tech>","date":"2021-08-03T10:02:38","subject":"Re: [libcamera-devel] [PATCH v2 4/5] libcamera: ipu3: Initialize\n\tcontrols in the IPA","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Wed, Jul 28, 2021 at 06:11:15PM +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> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n>  include/libcamera/ipa/ipu3.mojom     |   9 ++-\n>  src/ipa/ipu3/ipu3.cpp                |  71 +++++++++++++++++--\n>  src/libcamera/pipeline/ipu3/ipu3.cpp | 100 ++++++++++++---------------\n>  3 files changed, 121 insertions(+), 59 deletions(-)\n> \n> diff --git a/include/libcamera/ipa/ipu3.mojom b/include/libcamera/ipa/ipu3.mojom\n> index 911a3a072464..5fb53d0fcc4f 100644\n> --- a/include/libcamera/ipa/ipu3.mojom\n> +++ b/include/libcamera/ipa/ipu3.mojom\n> @@ -30,6 +30,12 @@ struct IPU3Action {\n>  \tlibcamera.ControlList controls;\n>  };\n>  \n> +struct IPAInitInfo {\n> +\tlibcamera.IPASettings settings;\n> +\tlibcamera.IPACameraSensorInfo sensorInfo;\n> +\tlibcamera.ControlInfoMap sensorControls;\n> +};\n> +\n>  struct IPAConfigInfo {\n>  \tlibcamera.IPACameraSensorInfo sensorInfo;\n>  \tmap<uint32, libcamera.ControlInfoMap> entityControls;\n> @@ -38,7 +44,8 @@ struct IPAConfigInfo {\n>  };\n>  \n>  interface IPAIPU3Interface {\n> -\tinit(libcamera.IPASettings settings) => (int32 ret);\n> +\tinit(IPAInitInfo initInfo)\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..7a0c89ecb5fa 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,8 @@ namespace ipa::ipu3 {\n>  class IPAIPU3 : public IPAIPU3Interface\n>  {\n>  public:\n> -\tint init(const IPASettings &settings) override;\n> +\tint init(const IPAInitInfo &initInfo, ControlInfoMap *ipaControls) override;\n> +\n>  \tint start() override;\n>  \tvoid stop() override {}\n>  \n> @@ -86,14 +89,74 @@ 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 IPAInitInfo &initInfo, ControlInfoMap *ipaControls)\n>  {\n> -\tcamHelper_ = CameraSensorHelperFactory::create(settings.sensorModel);\n> +\tconst std::string &sensorModel = initInfo.settings.sensorModel;\n> +\t/* Initialize the camera sensor helper. */\n> +\tcamHelper_ = CameraSensorHelperFactory::create(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    << sensorModel;\n>  \t\treturn -ENODEV;\n>  \t}\n>  \n> +\t/* Initialize Controls. */\n> +\tconst ControlInfoMap &sensorControls = initInfo.sensorControls;\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> +\tconst IPACameraSensorInfo &sensorInfo = initInfo.sensorInfo;\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 048993365b44..91fc1f7dc9b7 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> @@ -940,7 +942,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> @@ -952,58 +953,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> @@ -1057,9 +1006,14 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data)\n>  \n>  \tcontrols[&controls::ScalerCrop] = ControlInfo(minCrop, maxCrop, maxCrop);\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> +\n>  \treturn 0;\n>  }\n>  \n> @@ -1209,13 +1163,51 @@ 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> +         * \\todo Find a way to initialize IPA controls without basing their\n> +         * limits on a particular sensor mode. We currently pass sensor\n> +         * information corresponding to the largest sensor resolution, and the\n> +         * IPA uses this to compute limits for supported controls. There's a\n> +         * discrepancy between the need to compute IPA control limits at init\n> +         * time, and the fact that those limits may depend on the sensor mode.\n> +         * Research is required to find out to handle this issue.\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> +\tipa::ipu3::IPAInitInfo initInfo{\n> +\t\t{ \"\", sensor->model() },\n> +\t\tsensorInfo,\n> +\t\tsensor->controls(),\n> +\t};\n> +\tret = ipa_->init(initInfo, &ipaControls_);\n>  \tif (ret) {\n>  \t\tLOG(IPU3, Error) << \"Failed to initialise the IPU3 IPA\";\n>  \t\treturn ret;\n>  \t}\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 = ipaControls_.find(&controls::ExposureTime);\n> +\tif (exposureInfo == ipaControls_.end()) {\n> +\t\tLOG(IPU3, Error) << \"Exposure control not initializaed by the IPA\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\texposureTime_ = exposureInfo->second.def().get<int32_t>();\n> +\n>  \treturn 0;\n>  }\n>  \n> -- \n> 2.32.0\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 49D95C3235\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  3 Aug 2021 10:02:49 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C647668536;\n\tTue,  3 Aug 2021 12:02:48 +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 A61C66026A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  3 Aug 2021 12:02:46 +0200 (CEST)","from pyrite.rasen.tech (unknown\n\t[IPv6:2400:4051:61:600:2c71:1b79:d06d:5032])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1D8113F0;\n\tTue,  3 Aug 2021 12:02:44 +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=\"kxAYAowk\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1627984966;\n\tbh=6a9BmWz36GW6j6CFihmbmVQDPLr0lf/j/uAWnWcrT2c=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=kxAYAowk8+JsOH7EKDjdOCYgEBRIMKjkVwzAN3CWGD2reuFKDEyj7njE9u3W7OvVD\n\tVuAj1ro4p2aG/qFOjKEzeENVtG12p01fUQNKjjo0qEnyKXjaaHWX1q1b7vfuaTnzzU\n\tipkAFqI+9xS0e0jb++Gt07RMWRIsGaTOVlIKrF3c=","Date":"Tue, 3 Aug 2021 19:02:38 +0900","From":"paul.elder@ideasonboard.com","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<20210803100238.GA2167@pyrite.rasen.tech>","References":"<20210728161116.64489-1-jacopo@jmondi.org>\n\t<20210728161116.64489-5-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20210728161116.64489-5-jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [PATCH v2 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>"}},{"id":18526,"web_url":"https://patchwork.libcamera.org/comment/18526/","msgid":"<YQlzZKx3lOyLd4nO@pendragon.ideasonboard.com>","date":"2021-08-03T16:48:36","subject":"Re: [libcamera-devel] [PATCH v2 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 Wed, Jul 28, 2021 at 06:11:15PM +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> ---\n>  include/libcamera/ipa/ipu3.mojom     |   9 ++-\n>  src/ipa/ipu3/ipu3.cpp                |  71 +++++++++++++++++--\n>  src/libcamera/pipeline/ipu3/ipu3.cpp | 100 ++++++++++++---------------\n>  3 files changed, 121 insertions(+), 59 deletions(-)\n> \n> diff --git a/include/libcamera/ipa/ipu3.mojom b/include/libcamera/ipa/ipu3.mojom\n> index 911a3a072464..5fb53d0fcc4f 100644\n> --- a/include/libcamera/ipa/ipu3.mojom\n> +++ b/include/libcamera/ipa/ipu3.mojom\n> @@ -30,6 +30,12 @@ struct IPU3Action {\n>  \tlibcamera.ControlList controls;\n>  };\n>  \n> +struct IPAInitInfo {\n> +\tlibcamera.IPASettings settings;\n> +\tlibcamera.IPACameraSensorInfo sensorInfo;\n> +\tlibcamera.ControlInfoMap sensorControls;\n> +};\n> +\n>  struct IPAConfigInfo {\n>  \tlibcamera.IPACameraSensorInfo sensorInfo;\n>  \tmap<uint32, libcamera.ControlInfoMap> entityControls;\n> @@ -38,7 +44,8 @@ struct IPAConfigInfo {\n>  };\n>  \n>  interface IPAIPU3Interface {\n> -\tinit(libcamera.IPASettings settings) => (int32 ret);\n> +\tinit(IPAInitInfo initInfo)\n\nBy the way, there's no requirement for functions to take a single\nparameter, so this could also be written\n\n\tinit(libcamera.IPASettings settings,\n\t     libcamera.IPACameraSensorInfo sensorInfo,\n\t     libcamera.ControlInfoMap sensorControls)\n\nif you think the resulting code would be better.\n\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..7a0c89ecb5fa 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,8 @@ namespace ipa::ipu3 {\n>  class IPAIPU3 : public IPAIPU3Interface\n>  {\n>  public:\n> -\tint init(const IPASettings &settings) override;\n> +\tint init(const IPAInitInfo &initInfo, ControlInfoMap *ipaControls) override;\n> +\n>  \tint start() override;\n>  \tvoid stop() override {}\n>  \n> @@ -86,14 +89,74 @@ 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 IPAInitInfo &initInfo, ControlInfoMap *ipaControls)\n>  {\n> -\tcamHelper_ = CameraSensorHelperFactory::create(settings.sensorModel);\n> +\tconst std::string &sensorModel = initInfo.settings.sensorModel;\n\nNitpicking, I'd move this after the comment, it feels weird to have the\ncomment tightly hugged by two lines.\n\n> +\t/* Initialize the camera sensor helper. */\n> +\tcamHelper_ = CameraSensorHelperFactory::create(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    << sensorModel;\n>  \t\treturn -ENODEV;\n>  \t}\n>  \n> +\t/* Initialize Controls. */\n> +\tconst ControlInfoMap &sensorControls = initInfo.sensorControls;\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> +\tconst IPACameraSensorInfo &sensorInfo = initInfo.sensorInfo;\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 048993365b44..91fc1f7dc9b7 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> @@ -940,7 +942,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> @@ -952,58 +953,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> @@ -1057,9 +1006,14 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data)\n>  \n>  \tcontrols[&controls::ScalerCrop] = ControlInfo(minCrop, maxCrop, maxCrop);\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> +\n\nExtra blank line.\n\n>  \treturn 0;\n>  }\n>  \n> @@ -1209,13 +1163,51 @@ 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> +         * \\todo Find a way to initialize IPA controls without basing their\n> +         * limits on a particular sensor mode. We currently pass sensor\n> +         * information corresponding to the largest sensor resolution, and the\n> +         * IPA uses this to compute limits for supported controls. There's a\n> +         * discrepancy between the need to compute IPA control limits at init\n> +         * time, and the fact that those limits may depend on the sensor mode.\n> +         * Research is required to find out to handle this issue.\n\ns/        /\\t/\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\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> +\tipa::ipu3::IPAInitInfo initInfo{\n> +\t\t{ \"\", sensor->model() },\n> +\t\tsensorInfo,\n> +\t\tsensor->controls(),\n> +\t};\n> +\tret = ipa_->init(initInfo, &ipaControls_);\n>  \tif (ret) {\n>  \t\tLOG(IPU3, Error) << \"Failed to initialise the IPU3 IPA\";\n>  \t\treturn ret;\n>  \t}\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 = ipaControls_.find(&controls::ExposureTime);\n> +\tif (exposureInfo == ipaControls_.end()) {\n> +\t\tLOG(IPU3, Error) << \"Exposure control not initializaed by the IPA\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\texposureTime_ = exposureInfo->second.def().get<int32_t>();\n> +\n>  \treturn 0;\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 912B7C3232\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  3 Aug 2021 16:48:50 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id F0981687CE;\n\tTue,  3 Aug 2021 18:48:49 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BD38F6026A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  3 Aug 2021 18:48:48 +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 4E62D3F0;\n\tTue,  3 Aug 2021 18:48:48 +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=\"pF750IuL\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1628009328;\n\tbh=9wuZ6KaCkyadg+tZ4xMXOaOv1KG1U+CKkJYitpargHw=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=pF750IuLG0FQO7DeR/SQ2OE3wdTsxImYgW7jkbOQWyIoRMoTlLrU3qZ+99sJDsZ46\n\tReKVOWJlKZONHkHdevZilZrLeXPjtlsT3+M8Z0qUV3Oan65okmRiabtEtBdsdaywHm\n\t+g/fIV9cjAgW4E10D2vo0pt5YoBKd/onh60Hbf94=","Date":"Tue, 3 Aug 2021 19:48:36 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<YQlzZKx3lOyLd4nO@pendragon.ideasonboard.com>","References":"<20210728161116.64489-1-jacopo@jmondi.org>\n\t<20210728161116.64489-5-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20210728161116.64489-5-jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [PATCH v2 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>"}}]