[{"id":36769,"web_url":"https://patchwork.libcamera.org/comment/36769/","msgid":"<44af9a00-36e2-40b9-8f01-8a218b488ae7@ideasonboard.com>","date":"2025-11-11T12:14:28","subject":"Re: [PATCH] libcamera: delayed_controls: Make VBLANK priority by\n\tdefault","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2025. 11. 02. 20:19 keltezéssel, Jacopo Mondi írta:\n> The DelayedControls class works around a limitation of the V4L2\n> controls API by assigning to controls that modify the limits of\n> other controls a 'priority' flag.\n> \n> 'Priority' controls are written to the device before others\n> to make sure the limits of dependent controls are correctly\n> updated.\n> \n> A typical example of a priority control is VBLANK, whose value changes\n> the limits of the EXPOSURE control. This doesn't apply to a specific\n> hardware platform but to all V4L2 sensors.\n> \n> It's currently up to users of delayed controls to apply to\n> each control the correct flag by populating a ControlParams instance.\n> However, this is error prone, and the RkISP1 pipeline handler\n> wrongly sets the VBLANK priority to false.\n> \n> Instead of simply fixing the RkISP1 implementation, change how the\n> priorty flag is set, by making DelayedControls automatically flag\n> VBLANK as priority.\n> \n> This limits what controls the pipelines can set as priority, but so\n> far only VBLANK needs that flag to be set.\n> \n> Split the ControlParams type into an external one that only associates\n> delays to control ids and an internal one that is populated at class\n> creation time.\n> \n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> ---\n> Tested on rkisp1:\n> delayed_controls.cpp:100 Set a delay of 2 and priority write flag 1 for Vertical Blanking\n> ---\n\nCan we consider this superseded now that https://patchwork.libcamera.org/patch/24948/ is merged?\n\n\nRegards,\nBarnabás Pőcze\n\n\n>   include/libcamera/internal/delayed_controls.h | 14 ++++++---\n>   src/libcamera/delayed_controls.cpp            | 41 +++++++++++++--------------\n>   src/libcamera/pipeline/ipu3/ipu3.cpp          |  6 ++--\n>   src/libcamera/pipeline/mali-c55/mali-c55.cpp  |  6 ++--\n>   src/libcamera/pipeline/rkisp1/rkisp1.cpp      | 10 +++----\n>   src/libcamera/pipeline/simple/simple.cpp      |  6 ++--\n>   test/delayed_controls.cpp                     | 20 ++++++-------\n>   7 files changed, 53 insertions(+), 50 deletions(-)\n> \n> diff --git a/include/libcamera/internal/delayed_controls.h b/include/libcamera/internal/delayed_controls.h\n> index b64d8bba7cf73e10491d13d64bb4b3f7db80681b..c966fbedb1b832bcb50d0931204a011a334e6514 100644\n> --- a/include/libcamera/internal/delayed_controls.h\n> +++ b/include/libcamera/internal/delayed_controls.h\n> @@ -21,13 +21,14 @@ class V4L2Device;\n>   class DelayedControls : public Object\n>   {\n>   public:\n> -\tstruct ControlParams {\n> +\tstruct Controls {\n> +\t\tuint32_t id;\n>   \t\tunsigned int delay;\n> -\t\tbool priorityWrite;\n>   \t};\n>   \n> -\tDelayedControls(V4L2Device *device,\n> -\t\t\tconst std::unordered_map<uint32_t, ControlParams> &controlParams);\n> +\tusing Params = std::vector<Controls>;\n> +\n> +\tDelayedControls(V4L2Device *device, const Params &controlParams);\n>   \n>   \tvoid reset();\n>   \n> @@ -37,6 +38,11 @@ public:\n>   \tvoid applyControls(uint32_t sequence);\n>   \n>   private:\n> +\tstruct ControlParams {\n> +\t\tunsigned int delay;\n> +\t\tbool priorityWrite;\n> +\t};\n> +\n>   \tclass Info : public ControlValue\n>   \t{\n>   \tpublic:\n> diff --git a/src/libcamera/delayed_controls.cpp b/src/libcamera/delayed_controls.cpp\n> index 94d0a575b01b72416bdf05ea595f1c8e0ab6082c..f3092481ed804077dedd2cce0cda72f22d3563f8 100644\n> --- a/src/libcamera/delayed_controls.cpp\n> +++ b/src/libcamera/delayed_controls.cpp\n> @@ -39,40 +39,35 @@ LOG_DEFINE_CATEGORY(DelayedControls)\n>    */\n>   \n>   /**\n> - * \\struct DelayedControls::ControlParams\n> - * \\brief Parameters associated with controls handled by the \\a DelayedControls\n> + * \\struct DelayedControls::Controls\n> + * \\brief Delays associated with controls handled by the \\a DelayedControls\n>    * helper class\n>    *\n> - * \\var ControlParams::delay\n> + * \\var Controls::id\n> + * \\brief The control id\n> + *\n> + * \\var Controls::delay\n>    * \\brief Frame delay from setting the control on a sensor device to when it is\n>    * consumed during framing.\n> - *\n> - * \\var ControlParams::priorityWrite\n> - * \\brief Flag to indicate that this control must be applied ahead of, and\n> - * separately from the other controls.\n> - *\n> - * Typically set for the \\a V4L2_CID_VBLANK control so that the device driver\n> - * does not reject \\a V4L2_CID_EXPOSURE control values that may be outside of\n> - * the existing vertical blanking specified bounds, but are within the new\n> - * blanking bounds.\n> + */\n> +\n> +/**\n> + * \\typedef DelayedControls::Params\n> + * \\brief Vector of DelayedControls::Controls\n>    */\n>   \n>   /**\n>    * \\brief Construct a DelayedControls instance\n>    * \\param[in] device The V4L2 device the controls have to be applied to\n> - * \\param[in] controlParams Map of the numerical V4L2 control ids to their\n> - * associated control parameters.\n> + * \\param[in] controlParams Control ids and delays\n>    *\n> - * The control parameters comprise of delays (in frames) and a priority write\n> - * flag. If this flag is set, the relevant control is written separately from,\n> - * and ahead of the rest of the batched controls.\n> + * The control parameters associate a delay (in frames) to control ids.\n>    *\n>    * Only controls specified in \\a controlParams are handled. If it's desired to\n>    * mix delayed controls and controls that take effect immediately the immediate\n>    * controls must be listed in the \\a controlParams map with a delay value of 0.\n>    */\n> -DelayedControls::DelayedControls(V4L2Device *device,\n> -\t\t\t\t const std::unordered_map<uint32_t, ControlParams> &controlParams)\n> +DelayedControls::DelayedControls(V4L2Device *device, const Params &controlParams)\n>   \t: device_(device), maxDelay_(0)\n>   {\n>   \tconst ControlInfoMap &controls = device_->controls();\n> @@ -82,11 +77,11 @@ DelayedControls::DelayedControls(V4L2Device *device,\n>   \t * device.\n>   \t */\n>   \tfor (auto const &param : controlParams) {\n> -\t\tauto it = controls.find(param.first);\n> +\t\tauto it = controls.find(param.id);\n>   \t\tif (it == controls.end()) {\n>   \t\t\tLOG(DelayedControls, Error)\n>   \t\t\t\t<< \"Delay request for control id \"\n> -\t\t\t\t<< utils::hex(param.first)\n> +\t\t\t\t<< utils::hex(param.id)\n>   \t\t\t\t<< \" but control is not exposed by device \"\n>   \t\t\t\t<< device_->deviceNode();\n>   \t\t\tcontinue;\n> @@ -94,7 +89,9 @@ DelayedControls::DelayedControls(V4L2Device *device,\n>   \n>   \t\tconst ControlId *id = it->first;\n>   \n> -\t\tcontrolParams_[id] = param.second;\n> +\t\tcontrolParams_[id].delay = param.delay;\n> +\t\tif (param.id == V4L2_CID_VBLANK)\n> +\t\t\tcontrolParams_[id].priorityWrite = true;\n>   \n>   \t\tLOG(DelayedControls, Debug)\n>   \t\t\t<< \"Set a delay of \" << controlParams_[id].delay\n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> index d6b7edcb5a7f9fcb4083d4105a193978e265ef67..0d6d2e30065e03defbc47ae45fd67a22f6bff25a 100644\n> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> @@ -1083,9 +1083,9 @@ int PipelineHandlerIPU3::registerCameras()\n>   \t\t\tcontinue;\n>   \n>   \t\tconst CameraSensorProperties::SensorDelays &delays = cio2->sensor()->sensorDelays();\n> -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> -\t\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> -\t\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> +\t\tDelayedControls::Params params = {\n> +\t\t\t{ V4L2_CID_ANALOGUE_GAIN, delays.gainDelay },\n> +\t\t\t{ V4L2_CID_EXPOSURE, delays.exposureDelay },\n>   \t\t};\n>   \n>   \t\tdata->delayedCtrls_ =\n> diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> index 38bdc6138ed167a2c05f43ca30e60ed549fd953c..85f87ab979b23117c47bda4ca9418e4cb50c878d 100644\n> --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> @@ -1607,9 +1607,9 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink)\n>   \t\tdata->properties_ = data->sensor_->properties();\n>   \n>   \t\tconst CameraSensorProperties::SensorDelays &delays = data->sensor_->sensorDelays();\n> -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> -\t\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> -\t\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> +\t\tDelayedControls::Params params = {\n> +\t\t\t{ V4L2_CID_ANALOGUE_GAIN, delays.gainDelay },\n> +\t\t\t{ V4L2_CID_EXPOSURE, delays.exposureDelay },\n>   \t\t};\n>   \n>   \t\tdata->delayedCtrls_ =\n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index ecd13831539fdf5cb79da2ea4b33a353514328ae..525c8be6f19282e96df47ead602b67f6a74a8f96 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> @@ -1345,12 +1345,12 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)\n>   \tscalerMaxCrop_ = Rectangle(data->sensor_->resolution());\n>   \n>   \tconst CameraSensorProperties::SensorDelays &delays = data->sensor_->sensorDelays();\n> -\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> -\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> -\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> -\t\t{ V4L2_CID_VBLANK, { delays.vblankDelay, false } },\n> -\t};\n> +\tDelayedControls::Params params = {\n> +\t\t{ V4L2_CID_ANALOGUE_GAIN, delays.gainDelay },\n> +\t\t{ V4L2_CID_EXPOSURE, delays.exposureDelay },\n> +\t\t{ V4L2_CID_VBLANK, delays.vblankDelay },\n>   \n> +\t};\n>   \tdata->delayedCtrls_ =\n>   \t\tstd::make_unique<DelayedControls>(data->sensor_->device(),\n>   \t\t\t\t\t\t  params);\n> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> index 91715b7f8afd2058c42856ef38144847f81bd7b0..617ffa8eef490a1301920b3f30ab1f13b3ff62ff 100644\n> --- a/src/libcamera/pipeline/simple/simple.cpp\n> +++ b/src/libcamera/pipeline/simple/simple.cpp\n> @@ -553,9 +553,9 @@ SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,\n>   \t\treturn;\n>   \n>   \tconst CameraSensorProperties::SensorDelays &delays = sensor_->sensorDelays();\n> -\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> -\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> -\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> +\tDelayedControls::Params params = {\n> +\t\t{ V4L2_CID_ANALOGUE_GAIN, delays.gainDelay },\n> +\t\t{ V4L2_CID_EXPOSURE, delays.exposureDelay },\n>   \t};\n>   \tdelayedCtrls_ = std::make_unique<DelayedControls>(sensor_->device(), params);\n>   \n> diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> index 7bd30e7aead87f9350f1e0b48203f32804cfeef0..88425abc829a83ab7212775a8cab2165692a0a52 100644\n> --- a/test/delayed_controls.cpp\n> +++ b/test/delayed_controls.cpp\n> @@ -72,8 +72,8 @@ protected:\n>   \n>   \tint singleControlNoDelay()\n>   \t{\n> -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> -\t\t\t{ V4L2_CID_BRIGHTNESS, { 0, false } },\n> +\t\tDelayedControls::Params delays = {\n> +\t\t\t{ V4L2_CID_BRIGHTNESS, 0 },\n>   \t\t};\n>   \t\tstd::unique_ptr<DelayedControls> delayed =\n>   \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> @@ -113,8 +113,8 @@ protected:\n>   \n>   \tint singleControlWithDelay()\n>   \t{\n> -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> -\t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> +\t\tDelayedControls::Params delays = {\n> +\t\t\t{ V4L2_CID_BRIGHTNESS, 1 },\n>   \t\t};\n>   \t\tstd::unique_ptr<DelayedControls> delayed =\n>   \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> @@ -159,9 +159,9 @@ protected:\n>   \t{\n>   \t\tstatic const unsigned int maxDelay = 2;\n>   \n> -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> -\t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> -\t\t\t{ V4L2_CID_CONTRAST, { maxDelay, false } },\n> +\t\tDelayedControls::Params delays = {\n> +\t\t\t{ V4L2_CID_BRIGHTNESS, 1 },\n> +\t\t\t{ V4L2_CID_CONTRAST, maxDelay },\n>   \t\t};\n>   \t\tstd::unique_ptr<DelayedControls> delayed =\n>   \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> @@ -210,9 +210,9 @@ protected:\n>   \t{\n>   \t\tstatic const unsigned int maxDelay = 2;\n>   \n> -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> -\t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> -\t\t\t{ V4L2_CID_CONTRAST, { maxDelay, false } }\n> +\t\tDelayedControls::Params delays = {\n> +\t\t\t{ V4L2_CID_BRIGHTNESS, 1 },\n> +\t\t\t{ V4L2_CID_CONTRAST, maxDelay }\n>   \t\t};\n>   \t\tstd::unique_ptr<DelayedControls> delayed =\n>   \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> \n> ---\n> base-commit: b1f09c013a01a82c739f0e30b71fd8d000ef5655\n> change-id: 20251102-rkisp1-vblank-ba2084646ba7\n> \n> Best regards,","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 2A18FC3263\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 11 Nov 2025 12:14:35 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 78206606D5;\n\tTue, 11 Nov 2025 13:14:34 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 60220606A0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 11 Nov 2025 13:14:32 +0100 (CET)","from [192.168.33.25] (185.221.140.239.nat.pool.zt.hu\n\t[185.221.140.239])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 983EE741;\n\tTue, 11 Nov 2025 13:12:33 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"TwZ923gM\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1762863153;\n\tbh=CPHwGPqEb6TjZnCTrHYirTyG6aHl+U1rCtAIDfFoOz8=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=TwZ923gM7LQLPk/PN+qbHehi1/12d+RrhNyf0hubs+ygGS9sWpvab0W9D5Sez6cl7\n\t7w+toIVFrenRHCOihJuC6ey97iykL/+zFAEm6WdD5INmvMUJPvxV/RupDohNmUL8hC\n\tEjcy6PG1e63pjsHFZx7SeNL7ymshqR7VtzB9jYSI=","Message-ID":"<44af9a00-36e2-40b9-8f01-8a218b488ae7@ideasonboard.com>","Date":"Tue, 11 Nov 2025 13:14:28 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH] libcamera: delayed_controls: Make VBLANK priority by\n\tdefault","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20251102-rkisp1-vblank-v1-1-d2d6458696aa@ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20251102-rkisp1-vblank-v1-1-d2d6458696aa@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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":36770,"web_url":"https://patchwork.libcamera.org/comment/36770/","msgid":"<57gcsphmzokcj6mmt3tcmqwoloqmfljppagzxwj74z7ffzbqca@hei2g5j55hx7>","date":"2025-11-11T12:24:28","subject":"Re: [PATCH] libcamera: delayed_controls: Make VBLANK priority by\n\tdefault","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"On Tue, Nov 11, 2025 at 01:14:28PM +0100, Barnabás Pőcze wrote:\n> Hi\n>\n> 2025. 11. 02. 20:19 keltezéssel, Jacopo Mondi írta:\n> > The DelayedControls class works around a limitation of the V4L2\n> > controls API by assigning to controls that modify the limits of\n> > other controls a 'priority' flag.\n> >\n> > 'Priority' controls are written to the device before others\n> > to make sure the limits of dependent controls are correctly\n> > updated.\n> >\n> > A typical example of a priority control is VBLANK, whose value changes\n> > the limits of the EXPOSURE control. This doesn't apply to a specific\n> > hardware platform but to all V4L2 sensors.\n> >\n> > It's currently up to users of delayed controls to apply to\n> > each control the correct flag by populating a ControlParams instance.\n> > However, this is error prone, and the RkISP1 pipeline handler\n> > wrongly sets the VBLANK priority to false.\n> >\n> > Instead of simply fixing the RkISP1 implementation, change how the\n> > priorty flag is set, by making DelayedControls automatically flag\n> > VBLANK as priority.\n> >\n> > This limits what controls the pipelines can set as priority, but so\n> > far only VBLANK needs that flag to be set.\n> >\n> > Split the ControlParams type into an external one that only associates\n> > delays to control ids and an internal one that is populated at class\n> > creation time.\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > ---\n> > Tested on rkisp1:\n> > delayed_controls.cpp:100 Set a delay of 2 and priority write flag 1 for Vertical Blanking\n> > ---\n>\n> Can we consider this superseded now that https://patchwork.libcamera.org/patch/24948/ is merged?\n\noh yeah, I'll mark at such in patchwork!\n\nThanks\n  j\n\n>\n>\n> Regards,\n> Barnabás Pőcze\n>\n>\n> >   include/libcamera/internal/delayed_controls.h | 14 ++++++---\n> >   src/libcamera/delayed_controls.cpp            | 41 +++++++++++++--------------\n> >   src/libcamera/pipeline/ipu3/ipu3.cpp          |  6 ++--\n> >   src/libcamera/pipeline/mali-c55/mali-c55.cpp  |  6 ++--\n> >   src/libcamera/pipeline/rkisp1/rkisp1.cpp      | 10 +++----\n> >   src/libcamera/pipeline/simple/simple.cpp      |  6 ++--\n> >   test/delayed_controls.cpp                     | 20 ++++++-------\n> >   7 files changed, 53 insertions(+), 50 deletions(-)\n> >\n> > diff --git a/include/libcamera/internal/delayed_controls.h b/include/libcamera/internal/delayed_controls.h\n> > index b64d8bba7cf73e10491d13d64bb4b3f7db80681b..c966fbedb1b832bcb50d0931204a011a334e6514 100644\n> > --- a/include/libcamera/internal/delayed_controls.h\n> > +++ b/include/libcamera/internal/delayed_controls.h\n> > @@ -21,13 +21,14 @@ class V4L2Device;\n> >   class DelayedControls : public Object\n> >   {\n> >   public:\n> > -\tstruct ControlParams {\n> > +\tstruct Controls {\n> > +\t\tuint32_t id;\n> >   \t\tunsigned int delay;\n> > -\t\tbool priorityWrite;\n> >   \t};\n> > -\tDelayedControls(V4L2Device *device,\n> > -\t\t\tconst std::unordered_map<uint32_t, ControlParams> &controlParams);\n> > +\tusing Params = std::vector<Controls>;\n> > +\n> > +\tDelayedControls(V4L2Device *device, const Params &controlParams);\n> >   \tvoid reset();\n> > @@ -37,6 +38,11 @@ public:\n> >   \tvoid applyControls(uint32_t sequence);\n> >   private:\n> > +\tstruct ControlParams {\n> > +\t\tunsigned int delay;\n> > +\t\tbool priorityWrite;\n> > +\t};\n> > +\n> >   \tclass Info : public ControlValue\n> >   \t{\n> >   \tpublic:\n> > diff --git a/src/libcamera/delayed_controls.cpp b/src/libcamera/delayed_controls.cpp\n> > index 94d0a575b01b72416bdf05ea595f1c8e0ab6082c..f3092481ed804077dedd2cce0cda72f22d3563f8 100644\n> > --- a/src/libcamera/delayed_controls.cpp\n> > +++ b/src/libcamera/delayed_controls.cpp\n> > @@ -39,40 +39,35 @@ LOG_DEFINE_CATEGORY(DelayedControls)\n> >    */\n> >   /**\n> > - * \\struct DelayedControls::ControlParams\n> > - * \\brief Parameters associated with controls handled by the \\a DelayedControls\n> > + * \\struct DelayedControls::Controls\n> > + * \\brief Delays associated with controls handled by the \\a DelayedControls\n> >    * helper class\n> >    *\n> > - * \\var ControlParams::delay\n> > + * \\var Controls::id\n> > + * \\brief The control id\n> > + *\n> > + * \\var Controls::delay\n> >    * \\brief Frame delay from setting the control on a sensor device to when it is\n> >    * consumed during framing.\n> > - *\n> > - * \\var ControlParams::priorityWrite\n> > - * \\brief Flag to indicate that this control must be applied ahead of, and\n> > - * separately from the other controls.\n> > - *\n> > - * Typically set for the \\a V4L2_CID_VBLANK control so that the device driver\n> > - * does not reject \\a V4L2_CID_EXPOSURE control values that may be outside of\n> > - * the existing vertical blanking specified bounds, but are within the new\n> > - * blanking bounds.\n> > + */\n> > +\n> > +/**\n> > + * \\typedef DelayedControls::Params\n> > + * \\brief Vector of DelayedControls::Controls\n> >    */\n> >   /**\n> >    * \\brief Construct a DelayedControls instance\n> >    * \\param[in] device The V4L2 device the controls have to be applied to\n> > - * \\param[in] controlParams Map of the numerical V4L2 control ids to their\n> > - * associated control parameters.\n> > + * \\param[in] controlParams Control ids and delays\n> >    *\n> > - * The control parameters comprise of delays (in frames) and a priority write\n> > - * flag. If this flag is set, the relevant control is written separately from,\n> > - * and ahead of the rest of the batched controls.\n> > + * The control parameters associate a delay (in frames) to control ids.\n> >    *\n> >    * Only controls specified in \\a controlParams are handled. If it's desired to\n> >    * mix delayed controls and controls that take effect immediately the immediate\n> >    * controls must be listed in the \\a controlParams map with a delay value of 0.\n> >    */\n> > -DelayedControls::DelayedControls(V4L2Device *device,\n> > -\t\t\t\t const std::unordered_map<uint32_t, ControlParams> &controlParams)\n> > +DelayedControls::DelayedControls(V4L2Device *device, const Params &controlParams)\n> >   \t: device_(device), maxDelay_(0)\n> >   {\n> >   \tconst ControlInfoMap &controls = device_->controls();\n> > @@ -82,11 +77,11 @@ DelayedControls::DelayedControls(V4L2Device *device,\n> >   \t * device.\n> >   \t */\n> >   \tfor (auto const &param : controlParams) {\n> > -\t\tauto it = controls.find(param.first);\n> > +\t\tauto it = controls.find(param.id);\n> >   \t\tif (it == controls.end()) {\n> >   \t\t\tLOG(DelayedControls, Error)\n> >   \t\t\t\t<< \"Delay request for control id \"\n> > -\t\t\t\t<< utils::hex(param.first)\n> > +\t\t\t\t<< utils::hex(param.id)\n> >   \t\t\t\t<< \" but control is not exposed by device \"\n> >   \t\t\t\t<< device_->deviceNode();\n> >   \t\t\tcontinue;\n> > @@ -94,7 +89,9 @@ DelayedControls::DelayedControls(V4L2Device *device,\n> >   \t\tconst ControlId *id = it->first;\n> > -\t\tcontrolParams_[id] = param.second;\n> > +\t\tcontrolParams_[id].delay = param.delay;\n> > +\t\tif (param.id == V4L2_CID_VBLANK)\n> > +\t\t\tcontrolParams_[id].priorityWrite = true;\n> >   \t\tLOG(DelayedControls, Debug)\n> >   \t\t\t<< \"Set a delay of \" << controlParams_[id].delay\n> > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > index d6b7edcb5a7f9fcb4083d4105a193978e265ef67..0d6d2e30065e03defbc47ae45fd67a22f6bff25a 100644\n> > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > @@ -1083,9 +1083,9 @@ int PipelineHandlerIPU3::registerCameras()\n> >   \t\t\tcontinue;\n> >   \t\tconst CameraSensorProperties::SensorDelays &delays = cio2->sensor()->sensorDelays();\n> > -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> > -\t\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> > -\t\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> > +\t\tDelayedControls::Params params = {\n> > +\t\t\t{ V4L2_CID_ANALOGUE_GAIN, delays.gainDelay },\n> > +\t\t\t{ V4L2_CID_EXPOSURE, delays.exposureDelay },\n> >   \t\t};\n> >   \t\tdata->delayedCtrls_ =\n> > diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > index 38bdc6138ed167a2c05f43ca30e60ed549fd953c..85f87ab979b23117c47bda4ca9418e4cb50c878d 100644\n> > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > @@ -1607,9 +1607,9 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink)\n> >   \t\tdata->properties_ = data->sensor_->properties();\n> >   \t\tconst CameraSensorProperties::SensorDelays &delays = data->sensor_->sensorDelays();\n> > -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> > -\t\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> > -\t\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> > +\t\tDelayedControls::Params params = {\n> > +\t\t\t{ V4L2_CID_ANALOGUE_GAIN, delays.gainDelay },\n> > +\t\t\t{ V4L2_CID_EXPOSURE, delays.exposureDelay },\n> >   \t\t};\n> >   \t\tdata->delayedCtrls_ =\n> > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > index ecd13831539fdf5cb79da2ea4b33a353514328ae..525c8be6f19282e96df47ead602b67f6a74a8f96 100644\n> > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > @@ -1345,12 +1345,12 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)\n> >   \tscalerMaxCrop_ = Rectangle(data->sensor_->resolution());\n> >   \tconst CameraSensorProperties::SensorDelays &delays = data->sensor_->sensorDelays();\n> > -\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> > -\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> > -\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> > -\t\t{ V4L2_CID_VBLANK, { delays.vblankDelay, false } },\n> > -\t};\n> > +\tDelayedControls::Params params = {\n> > +\t\t{ V4L2_CID_ANALOGUE_GAIN, delays.gainDelay },\n> > +\t\t{ V4L2_CID_EXPOSURE, delays.exposureDelay },\n> > +\t\t{ V4L2_CID_VBLANK, delays.vblankDelay },\n> > +\t};\n> >   \tdata->delayedCtrls_ =\n> >   \t\tstd::make_unique<DelayedControls>(data->sensor_->device(),\n> >   \t\t\t\t\t\t  params);\n> > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> > index 91715b7f8afd2058c42856ef38144847f81bd7b0..617ffa8eef490a1301920b3f30ab1f13b3ff62ff 100644\n> > --- a/src/libcamera/pipeline/simple/simple.cpp\n> > +++ b/src/libcamera/pipeline/simple/simple.cpp\n> > @@ -553,9 +553,9 @@ SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,\n> >   \t\treturn;\n> >   \tconst CameraSensorProperties::SensorDelays &delays = sensor_->sensorDelays();\n> > -\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> > -\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> > -\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> > +\tDelayedControls::Params params = {\n> > +\t\t{ V4L2_CID_ANALOGUE_GAIN, delays.gainDelay },\n> > +\t\t{ V4L2_CID_EXPOSURE, delays.exposureDelay },\n> >   \t};\n> >   \tdelayedCtrls_ = std::make_unique<DelayedControls>(sensor_->device(), params);\n> > diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> > index 7bd30e7aead87f9350f1e0b48203f32804cfeef0..88425abc829a83ab7212775a8cab2165692a0a52 100644\n> > --- a/test/delayed_controls.cpp\n> > +++ b/test/delayed_controls.cpp\n> > @@ -72,8 +72,8 @@ protected:\n> >   \tint singleControlNoDelay()\n> >   \t{\n> > -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> > -\t\t\t{ V4L2_CID_BRIGHTNESS, { 0, false } },\n> > +\t\tDelayedControls::Params delays = {\n> > +\t\t\t{ V4L2_CID_BRIGHTNESS, 0 },\n> >   \t\t};\n> >   \t\tstd::unique_ptr<DelayedControls> delayed =\n> >   \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> > @@ -113,8 +113,8 @@ protected:\n> >   \tint singleControlWithDelay()\n> >   \t{\n> > -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> > -\t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> > +\t\tDelayedControls::Params delays = {\n> > +\t\t\t{ V4L2_CID_BRIGHTNESS, 1 },\n> >   \t\t};\n> >   \t\tstd::unique_ptr<DelayedControls> delayed =\n> >   \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> > @@ -159,9 +159,9 @@ protected:\n> >   \t{\n> >   \t\tstatic const unsigned int maxDelay = 2;\n> > -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> > -\t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> > -\t\t\t{ V4L2_CID_CONTRAST, { maxDelay, false } },\n> > +\t\tDelayedControls::Params delays = {\n> > +\t\t\t{ V4L2_CID_BRIGHTNESS, 1 },\n> > +\t\t\t{ V4L2_CID_CONTRAST, maxDelay },\n> >   \t\t};\n> >   \t\tstd::unique_ptr<DelayedControls> delayed =\n> >   \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> > @@ -210,9 +210,9 @@ protected:\n> >   \t{\n> >   \t\tstatic const unsigned int maxDelay = 2;\n> > -\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> > -\t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> > -\t\t\t{ V4L2_CID_CONTRAST, { maxDelay, false } }\n> > +\t\tDelayedControls::Params delays = {\n> > +\t\t\t{ V4L2_CID_BRIGHTNESS, 1 },\n> > +\t\t\t{ V4L2_CID_CONTRAST, maxDelay }\n> >   \t\t};\n> >   \t\tstd::unique_ptr<DelayedControls> delayed =\n> >   \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> >\n> > ---\n> > base-commit: b1f09c013a01a82c739f0e30b71fd8d000ef5655\n> > change-id: 20251102-rkisp1-vblank-ba2084646ba7\n> >\n> > Best regards,\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 A8632C3263\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 11 Nov 2025 12:24:34 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 24321606A0;\n\tTue, 11 Nov 2025 13:24:34 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5B8AB606A0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 11 Nov 2025 13:24:32 +0100 (CET)","from ideasonboard.com (mob-5-90-142-135.net.vodafone.it\n\t[5.90.142.135])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7C700741;\n\tTue, 11 Nov 2025 13:22:33 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"ry/4uup+\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1762863753;\n\tbh=rE7HEu4fQgnF2kd9U3t/NRneJSx1tFGowi7CsKWvtRM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=ry/4uup+Klav4e98AWMp67Cusz9YKG+C6o6doFnyqkabbjLZOg2L6hKz0GCrKMhxO\n\tSr+cAZ0WKkXNKSMGKzCgQVpQYc4izfly1FKwVfCMknFpE++CNs5uh6iWvWP0Dbz7YQ\n\tfc1PlpCBhQldFCNWhrrAlIqOoaEE8vodgdmXp5Ts=","Date":"Tue, 11 Nov 2025 13:24:28 +0100","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] libcamera: delayed_controls: Make VBLANK priority by\n\tdefault","Message-ID":"<57gcsphmzokcj6mmt3tcmqwoloqmfljppagzxwj74z7ffzbqca@hei2g5j55hx7>","References":"<20251102-rkisp1-vblank-v1-1-d2d6458696aa@ideasonboard.com>\n\t<44af9a00-36e2-40b9-8f01-8a218b488ae7@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<44af9a00-36e2-40b9-8f01-8a218b488ae7@ideasonboard.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>"}}]