[{"id":36738,"web_url":"https://patchwork.libcamera.org/comment/36738/","msgid":"<5jwa3bj3trtf2kbvaw3qgvptpiiqflzcmw3szhqypjm2wzn6sd@c5caznestai2>","date":"2025-11-06T17:34:07","subject":"Re: [PATCH v1 18/35] libcamera: delayed_controls: Change semantics\n\tof sequence numbers","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Stefan\n\nOn Fri, Oct 24, 2025 at 10:50:42AM +0200, Stefan Klug wrote:\n> In the context of per frame controls I believe it is easier to think\n> about what needs to be done for a specific sequence number.\n>\n> So (assuming a max sensor delay of 2) the actions would be:\n>\n> - delayedControls.push(n) stores the controls that shall be active on\n>   frame n\n> - delayedControls.get(n) returns these controls again\n> - delayedControls.apply(n) applies the slowest control for frame n and\n>   does a look back on other controls. So when a frameStart for frame n\n> occurs, it is time to call delayedControls.apply(n + maxDelay)\n\nI see this being used as\n\nvoid PipelineHandlerRkISP1::frameStart(uint32_t sequence)\n\n        ...\n\n\tuint32_t sequenceToApply = sequence + data->delayedCtrls_->maxDelay();\n\tdata->delayedCtrls_->applyControls(sequenceToApply);\n\nand you suggest this as a call pattern.\n\nIs this me or this is exactly what was happening before without the\ntrouble of having to query the maxDelay() everytime from the caller\nside ? Or, in other words, do you expect applyControls to be called\nwith anything but 'sequence + maxDelay()' ?\n\n>\n> Changing these semantics on delayed controls doesn't require much code\n> change and has the added benefit that we don't run in to clamping for\n> get() on frames < maxDelay.\n>\n> ToDo: This breaks the delayed controls test at the moment. The tests\n> need to be fixed and other pipelines need to be adjusted accordingly.\n>\n> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> ---\n>  src/libcamera/delayed_controls.cpp       | 15 ++++++++-------\n>  src/libcamera/pipeline/rkisp1/rkisp1.cpp |  5 +++--\n>  test/meson.build                         |  2 +-\n>  3 files changed, 12 insertions(+), 10 deletions(-)\n>\n> diff --git a/src/libcamera/delayed_controls.cpp b/src/libcamera/delayed_controls.cpp\n> index 35a624525b80..8239f3dcf347 100644\n> --- a/src/libcamera/delayed_controls.cpp\n> +++ b/src/libcamera/delayed_controls.cpp\n> @@ -241,7 +241,7 @@ bool DelayedControls::push(uint32_t sequence, const ControlList &controls)\n>   */\n>  ControlList DelayedControls::get(uint32_t sequence)\n>  {\n> -\tunsigned int index = std::max<int>(0, sequence - maxDelay_);\n> +\tunsigned int index = sequence;\n>\n>  \tControlList out(device_->controls());\n>  \tfor (const auto &ctrl : values_) {\n> @@ -267,13 +267,14 @@ ControlList DelayedControls::get(uint32_t sequence)\n>   */\n>\n>  /**\n> - * \\brief Inform DelayedControls of the start of a new frame\n> - * \\param[in] sequence Sequence number of the frame that started\n> + * \\brief Apply controls for a frame\n> + * \\param[in] sequence Sequence number of the frame to apply\n>   *\n> - * Inform the state machine that a new frame has started and of its sequence\n> - * number. Any user of these helpers is responsible to inform the helper about\n> - * the start of any frame. This can be connected with ease to the start of a\n> - * exposure (SOE) V4L2 event.\n> + * Apply controls for the frame \\a sequence. This applies the controls with the\n> + * largest delay. For controls with a smaller delay it does a looks back and\n> + * applies the controls for the previous sequence. So usually this function is\n> + * called in a start of exposure event as applyControls(startedSequence +\n> + * maxDelay)\n>   */\n>  void DelayedControls::applyControls(uint32_t sequence)\n>  {\n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index d937c94e351f..7a4957d7e535 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> @@ -1624,10 +1624,11 @@ void PipelineHandlerRkISP1::frameStart(uint32_t sequence)\n>  \t\treturn;\n>\n>  \tRkISP1CameraData *data = cameraData(activeCamera_);\n> -\tdata->delayedCtrls_->applyControls(sequence);\n> +\tuint32_t sequenceToApply = sequence + data->delayedCtrls_->maxDelay();\n> +\tdata->delayedCtrls_->applyControls(sequenceToApply);\n>\n>  \tif (isRaw_) {\n> -\t\tdata->ipa_->computeParams(sequence + 1, 0);\n> +\t\tdata->ipa_->computeParams(sequenceToApply + 1, 0);\n>  \t}\n>  }\n>\n> diff --git a/test/meson.build b/test/meson.build\n> index 52f04364e4fc..80fb543f2201 100644\n> --- a/test/meson.build\n> +++ b/test/meson.build\n> @@ -53,7 +53,7 @@ internal_tests = [\n>      {'name': 'bayer-format', 'sources': ['bayer-format.cpp']},\n>      {'name': 'byte-stream-buffer', 'sources': ['byte-stream-buffer.cpp']},\n>      {'name': 'camera-sensor', 'sources': ['camera-sensor.cpp']},\n> -    {'name': 'delayed_controls', 'sources': ['delayed_controls.cpp']},\n> +    {'name': 'delayed_controls', 'sources': ['delayed_controls.cpp'], 'should_fail': true},\n>      {'name': 'event', 'sources': ['event.cpp']},\n>      {'name': 'event-dispatcher', 'sources': ['event-dispatcher.cpp']},\n>      {'name': 'event-thread', 'sources': ['event-thread.cpp']},\n> --\n> 2.48.1\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 7DA2BBDE4C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  6 Nov 2025 17:34:17 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7D42660A8B;\n\tThu,  6 Nov 2025 18:34:16 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BC762606E6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  6 Nov 2025 18:34:14 +0100 (CET)","from ideasonboard.com (mob-5-90-141-71.net.vodafone.it\n\t[5.90.141.71])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C75096A6;\n\tThu,  6 Nov 2025 18:32:18 +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=\"QIzRwimn\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1762450339;\n\tbh=rqWDZzUNR81glOga0eW4Duk0voVw1soYvNCZtT17hNs=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=QIzRwimnPjCjeHxVKwXSndoPbVV5gIAbUiZLQIde0xd1VYOtV1V4UP9sty1rdH8Sn\n\trYPX1It65I6c1VRgQsQX6/sylRBJ59ILYjMhOBRahJDK4u1xWQTacJ6xFu7a/GeUHs\n\t3SExo7RiA5Wzz5r2+GukG8TSdUgt4Zpv+FuDK/88=","Date":"Thu, 6 Nov 2025 18:34:07 +0100","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v1 18/35] libcamera: delayed_controls: Change semantics\n\tof sequence numbers","Message-ID":"<5jwa3bj3trtf2kbvaw3qgvptpiiqflzcmw3szhqypjm2wzn6sd@c5caznestai2>","References":"<20251024085130.995967-1-stefan.klug@ideasonboard.com>\n\t<20251024085130.995967-19-stefan.klug@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20251024085130.995967-19-stefan.klug@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>"}},{"id":37285,"web_url":"https://patchwork.libcamera.org/comment/37285/","msgid":"<176542523059.48638.2042446934135907034@localhost>","date":"2025-12-11T03:53:50","subject":"Re: [PATCH v1 18/35] libcamera: delayed_controls: Change semantics\n\tof sequence numbers","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/people/184/","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"content":"Hi Jacopo,\n\nThank you for the review.\n\nQuoting Jacopo Mondi (2025-11-06 18:34:07)\n> Hi Stefan\n> \n> On Fri, Oct 24, 2025 at 10:50:42AM +0200, Stefan Klug wrote:\n> > In the context of per frame controls I believe it is easier to think\n> > about what needs to be done for a specific sequence number.\n> >\n> > So (assuming a max sensor delay of 2) the actions would be:\n> >\n> > - delayedControls.push(n) stores the controls that shall be active on\n> >   frame n\n> > - delayedControls.get(n) returns these controls again\n> > - delayedControls.apply(n) applies the slowest control for frame n and\n> >   does a look back on other controls. So when a frameStart for frame n\n> > occurs, it is time to call delayedControls.apply(n + maxDelay)\n> \n> I see this being used as\n> \n> void PipelineHandlerRkISP1::frameStart(uint32_t sequence)\n> \n>         ...\n> \n>         uint32_t sequenceToApply = sequence + data->delayedCtrls_->maxDelay();\n>         data->delayedCtrls_->applyControls(sequenceToApply);\n> \n> and you suggest this as a call pattern.\n> \n> Is this me or this is exactly what was happening before without the\n> trouble of having to query the maxDelay() everytime from the caller\n> side ? Or, in other words, do you expect applyControls to be called\n> with anything but 'sequence + maxDelay()' ?\n\nYou are right, it is basically the same. But I don't see that as\nadditional trouble. It helps my brain to cope with the sequence of\nevents. If you look at the frameStart() function after applying the\nwhole series, it looks like that:\n\nuint32_t sequenceToApply = sequence + data->delayedCtrls_->maxDelay();\ndata->delayedCtrls_->applyControls(sequenceToApply);\ncomputeParamBuffers(sequenceToApply + 1);\n\nThis code makes it pretty clear, that the lookahead we need to do to prepare\nthe params buffer is the sequenceToApply + 1. So at that point we'd need\nto fetch the maxDelay anyways.\n\nCan you go with that?\n\nBest regards,\nStefan\n\n> \n> >\n> > Changing these semantics on delayed controls doesn't require much code\n> > change and has the added benefit that we don't run in to clamping for\n> > get() on frames < maxDelay.\n> >\n> > ToDo: This breaks the delayed controls test at the moment. The tests\n> > need to be fixed and other pipelines need to be adjusted accordingly.\n> >\n> > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> > ---\n> >  src/libcamera/delayed_controls.cpp       | 15 ++++++++-------\n> >  src/libcamera/pipeline/rkisp1/rkisp1.cpp |  5 +++--\n> >  test/meson.build                         |  2 +-\n> >  3 files changed, 12 insertions(+), 10 deletions(-)\n> >\n> > diff --git a/src/libcamera/delayed_controls.cpp b/src/libcamera/delayed_controls.cpp\n> > index 35a624525b80..8239f3dcf347 100644\n> > --- a/src/libcamera/delayed_controls.cpp\n> > +++ b/src/libcamera/delayed_controls.cpp\n> > @@ -241,7 +241,7 @@ bool DelayedControls::push(uint32_t sequence, const ControlList &controls)\n> >   */\n> >  ControlList DelayedControls::get(uint32_t sequence)\n> >  {\n> > -     unsigned int index = std::max<int>(0, sequence - maxDelay_);\n> > +     unsigned int index = sequence;\n> >\n> >       ControlList out(device_->controls());\n> >       for (const auto &ctrl : values_) {\n> > @@ -267,13 +267,14 @@ ControlList DelayedControls::get(uint32_t sequence)\n> >   */\n> >\n> >  /**\n> > - * \\brief Inform DelayedControls of the start of a new frame\n> > - * \\param[in] sequence Sequence number of the frame that started\n> > + * \\brief Apply controls for a frame\n> > + * \\param[in] sequence Sequence number of the frame to apply\n> >   *\n> > - * Inform the state machine that a new frame has started and of its sequence\n> > - * number. Any user of these helpers is responsible to inform the helper about\n> > - * the start of any frame. This can be connected with ease to the start of a\n> > - * exposure (SOE) V4L2 event.\n> > + * Apply controls for the frame \\a sequence. This applies the controls with the\n> > + * largest delay. For controls with a smaller delay it does a looks back and\n> > + * applies the controls for the previous sequence. So usually this function is\n> > + * called in a start of exposure event as applyControls(startedSequence +\n> > + * maxDelay)\n> >   */\n> >  void DelayedControls::applyControls(uint32_t sequence)\n> >  {\n> > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > index d937c94e351f..7a4957d7e535 100644\n> > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > @@ -1624,10 +1624,11 @@ void PipelineHandlerRkISP1::frameStart(uint32_t sequence)\n> >               return;\n> >\n> >       RkISP1CameraData *data = cameraData(activeCamera_);\n> > -     data->delayedCtrls_->applyControls(sequence);\n> > +     uint32_t sequenceToApply = sequence + data->delayedCtrls_->maxDelay();\n> > +     data->delayedCtrls_->applyControls(sequenceToApply);\n> >\n> >       if (isRaw_) {\n> > -             data->ipa_->computeParams(sequence + 1, 0);\n> > +             data->ipa_->computeParams(sequenceToApply + 1, 0);\n> >       }\n> >  }\n> >\n> > diff --git a/test/meson.build b/test/meson.build\n> > index 52f04364e4fc..80fb543f2201 100644\n> > --- a/test/meson.build\n> > +++ b/test/meson.build\n> > @@ -53,7 +53,7 @@ internal_tests = [\n> >      {'name': 'bayer-format', 'sources': ['bayer-format.cpp']},\n> >      {'name': 'byte-stream-buffer', 'sources': ['byte-stream-buffer.cpp']},\n> >      {'name': 'camera-sensor', 'sources': ['camera-sensor.cpp']},\n> > -    {'name': 'delayed_controls', 'sources': ['delayed_controls.cpp']},\n> > +    {'name': 'delayed_controls', 'sources': ['delayed_controls.cpp'], 'should_fail': true},\n> >      {'name': 'event', 'sources': ['event.cpp']},\n> >      {'name': 'event-dispatcher', 'sources': ['event-dispatcher.cpp']},\n> >      {'name': 'event-thread', 'sources': ['event-thread.cpp']},\n> > --\n> > 2.48.1\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 4FEF0C3257\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 11 Dec 2025 03:54:00 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5D58A61507;\n\tThu, 11 Dec 2025 04:53:59 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 44D60606D5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 11 Dec 2025 04:53:58 +0100 (CET)","from ideasonboard.com (p99249-ipoefx.ipoe.ocn.ne.jp\n\t[153.246.134.248])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 8DF401661; \n\tThu, 11 Dec 2025 04:53:55 +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=\"tk2UqpXc\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1765425236;\n\tbh=gDSvXOttj2YwIEDFBVfzROeGyPbsIqq9O8aZSa9Bojk=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=tk2UqpXc6t6PLN2Iq1WQBelpCaxHi5otcGlpPZ6y2McAuOe2FYxIaWwEM3tZx4kRG\n\ttG1Jmdl0ab9P6FTaI1D6hDf3DTJZpFyOabU9Wnk4RK0EbtWySdv7HWtPxGXMkinsKJ\n\tHdpKjvjreC8eLuK/iD+px6QENeS+r1V/U+HNkHEs=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<5jwa3bj3trtf2kbvaw3qgvptpiiqflzcmw3szhqypjm2wzn6sd@c5caznestai2>","References":"<20251024085130.995967-1-stefan.klug@ideasonboard.com>\n\t<20251024085130.995967-19-stefan.klug@ideasonboard.com>\n\t<5jwa3bj3trtf2kbvaw3qgvptpiiqflzcmw3szhqypjm2wzn6sd@c5caznestai2>","Subject":"Re: [PATCH v1 18/35] libcamera: delayed_controls: Change semantics\n\tof sequence numbers","From":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Date":"Thu, 11 Dec 2025 04:53:50 +0100","Message-ID":"<176542523059.48638.2042446934135907034@localhost>","User-Agent":"alot/0.12.dev8+g2c003385c862.d20250602","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":37853,"web_url":"https://patchwork.libcamera.org/comment/37853/","msgid":"<176907339225.3882822.7268888007097765474@neptunite.rasen.tech>","date":"2026-01-22T09:16:32","subject":"Re: [PATCH v1 18/35] libcamera: delayed_controls: Change semantics\n\tof sequence numbers","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Quoting Stefan Klug (2025-10-24 17:50:42)\n> In the context of per frame controls I believe it is easier to think\n> about what needs to be done for a specific sequence number.\n> \n> So (assuming a max sensor delay of 2) the actions would be:\n> \n> - delayedControls.push(n) stores the controls that shall be active on\n>   frame n\n> - delayedControls.get(n) returns these controls again\n> - delayedControls.apply(n) applies the slowest control for frame n and\n>   does a look back on other controls. So when a frameStart for frame n\n> occurs, it is time to call delayedControls.apply(n + maxDelay)\n> \n> Changing these semantics on delayed controls doesn't require much code\n> change and has the added benefit that we don't run in to clamping for\n> get() on frames < maxDelay.\n> \n> ToDo: This breaks the delayed controls test at the moment. The tests\n> need to be fixed and other pipelines need to be adjusted accordingly.\n> \n> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> ---\n>  src/libcamera/delayed_controls.cpp       | 15 ++++++++-------\n>  src/libcamera/pipeline/rkisp1/rkisp1.cpp |  5 +++--\n>  test/meson.build                         |  2 +-\n>  3 files changed, 12 insertions(+), 10 deletions(-)\n> \n> diff --git a/src/libcamera/delayed_controls.cpp b/src/libcamera/delayed_controls.cpp\n> index 35a624525b80..8239f3dcf347 100644\n> --- a/src/libcamera/delayed_controls.cpp\n> +++ b/src/libcamera/delayed_controls.cpp\n> @@ -241,7 +241,7 @@ bool DelayedControls::push(uint32_t sequence, const ControlList &controls)\n>   */\n>  ControlList DelayedControls::get(uint32_t sequence)\n>  {\n> -       unsigned int index = std::max<int>(0, sequence - maxDelay_);\n> +       unsigned int index = sequence;\n>  \n>         ControlList out(device_->controls());\n>         for (const auto &ctrl : values_) {\n> @@ -267,13 +267,14 @@ ControlList DelayedControls::get(uint32_t sequence)\n>   */\n>  \n>  /**\n> - * \\brief Inform DelayedControls of the start of a new frame\n> - * \\param[in] sequence Sequence number of the frame that started\n> + * \\brief Apply controls for a frame\n> + * \\param[in] sequence Sequence number of the frame to apply\n>   *\n> - * Inform the state machine that a new frame has started and of its sequence\n> - * number. Any user of these helpers is responsible to inform the helper about\n> - * the start of any frame. This can be connected with ease to the start of a\n> - * exposure (SOE) V4L2 event.\n> + * Apply controls for the frame \\a sequence. This applies the controls with the\n> + * largest delay. For controls with a smaller delay it does a looks back and\n> + * applies the controls for the previous sequence. So usually this function is\n> + * called in a start of exposure event as applyControls(startedSequence +\n> + * maxDelay)\n>   */\n>  void DelayedControls::applyControls(uint32_t sequence)\n>  {\n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index d937c94e351f..7a4957d7e535 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> @@ -1624,10 +1624,11 @@ void PipelineHandlerRkISP1::frameStart(uint32_t sequence)\n>                 return;\n>  \n>         RkISP1CameraData *data = cameraData(activeCamera_);\n> -       data->delayedCtrls_->applyControls(sequence);\n> +       uint32_t sequenceToApply = sequence + data->delayedCtrls_->maxDelay();\n> +       data->delayedCtrls_->applyControls(sequenceToApply);\n\nHm, I'm a bit torn between what Jacopo has said (that if it's only ever called\nin this pattern then it should be abstracted away), and yours that it is easier\nto understand this way. In any case we need the sequenceToApply for\ncomputeParams() below, which if you want to abstract you would have to return\nit from applyControls() which is probably even less nice. So I think the\nclearer way is a bit better. Probably more concrete code example documentation\nwould be better though.\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n>  \n>         if (isRaw_) {\n> -               data->ipa_->computeParams(sequence + 1, 0);\n> +               data->ipa_->computeParams(sequenceToApply + 1, 0);\n>         }\n>  }\n>  \n> diff --git a/test/meson.build b/test/meson.build\n> index 52f04364e4fc..80fb543f2201 100644\n> --- a/test/meson.build\n> +++ b/test/meson.build\n> @@ -53,7 +53,7 @@ internal_tests = [\n>      {'name': 'bayer-format', 'sources': ['bayer-format.cpp']},\n>      {'name': 'byte-stream-buffer', 'sources': ['byte-stream-buffer.cpp']},\n>      {'name': 'camera-sensor', 'sources': ['camera-sensor.cpp']},\n> -    {'name': 'delayed_controls', 'sources': ['delayed_controls.cpp']},\n> +    {'name': 'delayed_controls', 'sources': ['delayed_controls.cpp'], 'should_fail': true},\n>      {'name': 'event', 'sources': ['event.cpp']},\n>      {'name': 'event-dispatcher', 'sources': ['event-dispatcher.cpp']},\n>      {'name': 'event-thread', 'sources': ['event-thread.cpp']},\n> -- \n> 2.48.1\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 B4232BDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 22 Jan 2026 09:16:40 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 509E861FEE;\n\tThu, 22 Jan 2026 10:16:40 +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 17ACC61FC4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 22 Jan 2026 10:16:38 +0100 (CET)","from neptunite.rasen.tech (unknown\n\t[IPv6:2404:7a81:160:2100:8816:a947:ebed:2ec7])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 2DF3F2DD;\n\tThu, 22 Jan 2026 10:16:04 +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=\"cfX9wgTQ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1769073365;\n\tbh=dBeC9yxIe2mVBxuwO+NzvO72rgwsJxv3htnT9VY0FaE=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=cfX9wgTQoJuDsVCP1HjOo1kkpUaYcDeVFlJARGli1zMLuMJzwudoCfPQVD2zw26O+\n\tacM0/hTdAtUfyKWmN1y2XvQDQlcuDbzT268tVQbCEjkMyTsd1fvSF7n9T+WIDAa4Ik\n\tNtPX9EL2zrh4TIbFMUyfJR9+RUDl3WsNtq+Pi6mA=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20251024085130.995967-19-stefan.klug@ideasonboard.com>","References":"<20251024085130.995967-1-stefan.klug@ideasonboard.com>\n\t<20251024085130.995967-19-stefan.klug@ideasonboard.com>","Subject":"Re: [PATCH v1 18/35] libcamera: delayed_controls: Change semantics\n\tof sequence numbers","From":"Paul Elder <paul.elder@ideasonboard.com>","Cc":"Stefan Klug <stefan.klug@ideasonboard.com>","To":"Stefan Klug <stefan.klug@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Thu, 22 Jan 2026 18:16:32 +0900","Message-ID":"<176907339225.3882822.7268888007097765474@neptunite.rasen.tech>","User-Agent":"alot/0.0.0","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>"}}]