From patchwork Tue Mar 19 12:05:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 19752 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 7EF4EC32C8 for ; Tue, 19 Mar 2024 12:05:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2C54162D6B; Tue, 19 Mar 2024 13:05:45 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="hLF9ZMOk"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7B75262D2F for ; Tue, 19 Mar 2024 13:05:30 +0100 (CET) Received: from jasper.fritz.box (unknown [IPv6:2a00:6020:448c:6c00:1478:344b:8fcb:baf5]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C997715EE; Tue, 19 Mar 2024 13:05:03 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1710849903; bh=e65H+BR9HKWcZ4SGv9EqEiTMDJzzWQA55nciN3BBRyQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hLF9ZMOk7NV69QuCM1cTurHVtwFF4Ep8LU8GhYAKvz69cBil9vLNH/vcDe9bONMWk x2NjdcxDQHU9Vn43XTUR8neqttp4mQ7zH7Zh7oE04H+Rxc6rVYiW0qTjP7i46gS78v OOXd5ByPFZgo7YFj0vsMB3hDw6WP075G01GMSlow= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH v3 12/16] libcamera: delayed_controls: Ignore delayed request, if there is a newer one Date: Tue, 19 Mar 2024 13:05:13 +0100 Message-Id: <20240319120517.362082-13-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240319120517.362082-1-stefan.klug@ideasonboard.com> References: <20240319120517.362082-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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. --- 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::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 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 delays = { + { V4L2_CID_BRIGHTNESS, { 2, false } }, + }; + std::unique_ptr delayed = + std::make_unique(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(); + ControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS }); + int32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get(); + + 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 delays = { @@ -503,6 +565,10 @@ protected: if (ret) failed = true; + ret = updateTooLateMustSometimesBeIgnored(); + if (ret) + failed = true; + ret = updateTooLateGetsDelayed(); if (ret) failed = true;