[PATCH v3 12/16] libcamera: delayed_controls: Ignore delayed request, if there is a newer one

Jacopo Mondi jacopo.mondi at ideasonboard.com
Thu Mar 21 12:54:11 CET 2024


Hi Stefan

On Tue, Mar 19, 2024 at 01:05:13PM +0100, Stefan Klug wrote:
> Assume for frame 10 a ExposureTime=42 is queued. We have a delay of 2.  After
> receiving stats for frame 8, the isp tries to queue for frame 9.  As it's too
> lae for that frame, delayed controls schedules the update for frame 11. But as
> frame 10 was already queued, the request should be discarded.

I think this use case is the main reason for the whole delayed control
rework, isn't it ?

So please let's try to first clarify if it is valid. Let's expand the
above text:

> Assume for frame 10 a ExposureTime=42 is queued. We have a delay of 2.  After

At what time is the request queued ? During the exposure of which
frame ?

> receiving stats for frame 8, the isp tries to queue for frame 9.  As it's too

s/isp/IPA ? Otherwise I can't make a sense out of this phrase.

If so, frame 8 has been processed by the ISP. If frame 8 has been
processed, it means (at best) frame 9 is already exposing. Whatever
settings we apply at this time, they will get realized at (10 +
max_delay).

> lae for that frame, delayed controls schedules the update for frame 11. But as

Why frame 11 ?

> frame 10 was already queued, the request should be discarded.

frame 10 is queued to what ? To the ISP ?

Let's calrify this use case first then let's discuss the changes to
delayed controls.

Thanks
  j

> ---
>  include/libcamera/internal/delayed_controls.h |  2 +
>  src/libcamera/delayed_controls.cpp            | 19 +++++-
>  test/delayed_controls.cpp                     | 66 +++++++++++++++++++
>  3 files changed, 86 insertions(+), 1 deletion(-)
>
> diff --git a/include/libcamera/internal/delayed_controls.h b/include/libcamera/internal/delayed_controls.h
> index e2decbcc..91c9415a 100644
> --- a/include/libcamera/internal/delayed_controls.h
> +++ b/include/libcamera/internal/delayed_controls.h
> @@ -67,6 +67,8 @@ private:
>  		{
>  			return std::array<Info, listSize>::operator[](index % listSize);
>  		}
> +
> +		unsigned int largestValidIndex;
>  	};
>
>  	bool controlsAreQueued(unsigned int frame, const ControlList &controls);
> diff --git a/src/libcamera/delayed_controls.cpp b/src/libcamera/delayed_controls.cpp
> index 3fd5a0f7..7f2bb479 100644
> --- a/src/libcamera/delayed_controls.cpp
> +++ b/src/libcamera/delayed_controls.cpp
> @@ -151,6 +151,7 @@ void DelayedControls::reset(ControlList *controls)
>  		 * to be written to to device on startup.
>  		 */
>  		values_[id][0] = Info(ctrl.second, 0, false);
> +		values_[id].largestValidIndex = 0;
>  	}
>
>  	/* Propagate initial state */
> @@ -304,18 +305,34 @@ bool DelayedControls::push(const ControlList &controls, std::optional<uint32_t>
>  			continue;
>  		}
>
> -		Info &info = values_[id][updateIndex];
> +		ControlRingBuffer &ring = values_[id];
> +		Info &info = ring[updateIndex];
>  		/*
>  		 * Update the control only if the already existing value stems from a
>  		 * request with a sequence number smaller or equal to the current one
>  		 */
>  		if (info.sourceSequence <= sequence) {
>  			info = Info(control.second, sequence);
> +			if (updateIndex > ring.largestValidIndex)
> +				ring.largestValidIndex = updateIndex;
>
>  			LOG(DelayedControls, Debug)
>  				<< "Queuing " << id->name()
>  				<< " to " << info.toString()
>  				<< " at index " << updateIndex;
> +
> +			/* fill up the next indices with the new information */
> +			unsigned int i = updateIndex + 1;
> +			while (i <= ring.largestValidIndex) {
> +				LOG(DelayedControls, Error) << "update " << i;
> +				Info &next = ring[i];
> +				if (next.sourceSequence <= sequence)
> +					next = info;
> +				else
> +					break;
> +
> +				i++;
> +			}
>  		} else {
>  			LOG(DelayedControls, Warning)
>  				<< "Skipped update " << id->name()
> diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp
> index 481334e7..7d671a0e 100644
> --- a/test/delayed_controls.cpp
> +++ b/test/delayed_controls.cpp
> @@ -271,6 +271,68 @@ protected:
>  		return TestPass;
>  	}
>
> +	int updateTooLateMustSometimesBeIgnored()
> +	{
> +		std::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {
> +			{ V4L2_CID_BRIGHTNESS, { 2, false } },
> +		};
> +		std::unique_ptr<DelayedControls> delayed =
> +			std::make_unique<DelayedControls>(dev_.get(), delays);
> +		ControlList ctrls;
> +
> +		/* Reset control to value that will be first in test. */
> +		int32_t initial = 4;
> +		ctrls.set(V4L2_CID_BRIGHTNESS, initial);
> +		dev_->setControls(&ctrls);
> +		delayed->reset();
> +
> +		int32_t expected = 10;
> +
> +		delayed->push({}, 0);
> +		delayed->push({}, 1);
> +		ctrls.set(V4L2_CID_BRIGHTNESS, expected);
> +		delayed->push(ctrls, 2);
> +		delayed->applyControls(0); /* puts 10 on the bus */
> +
> +		/*
> +		 * Post an update for frame 1. It's too late to fulfill that request,
> +		 * delayed controls will therefore try to delay it to frame 3. But as
> +		 * frame 2 is already queued, the update must be dropped.
> +		 */
> +		ctrls.set(V4L2_CID_BRIGHTNESS, 20);
> +		delayed->push(ctrls, 1);
> +		delayed->applyControls(1);
> +		delayed->applyControls(2);
> +		delayed->applyControls(3);
> +
> +		int frame = 3;
> +
> +		ControlList result = delayed->get(frame);
> +		int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();
> +		ControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS });
> +		int32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get<int32_t>();
> +
> +		if (brightness != expected) {
> +			cerr << "Failed " << __func__
> +			     << " frame " << frame
> +			     << " expected " << expected
> +			     << " got " << brightness
> +			     << endl;
> +			return TestFail;
> +		}
> +
> +		if (brightnessV4L != expected) {
> +			cerr << "Failed " << __func__
> +			     << " frame " << frame
> +			     << " expected V4L " << expected
> +			     << " got " << brightnessV4L
> +			     << endl;
> +			return TestFail;
> +		}
> +
> +		return TestPass;
> +	}
> +
>  	int updateTooLateGetsDelayed()
>  	{
>  		std::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {
> @@ -503,6 +565,10 @@ protected:
>  		if (ret)
>  			failed = true;
>
> +		ret = updateTooLateMustSometimesBeIgnored();
> +		if (ret)
> +			failed = true;
> +
>  		ret = updateTooLateGetsDelayed();
>  		if (ret)
>  			failed = true;
> --
> 2.40.1
>


More information about the libcamera-devel mailing list