Patch Detail
Show a patch.
GET /api/patches/19752/?format=api
{ "id": 19752, "url": "https://patchwork.libcamera.org/api/patches/19752/?format=api", "web_url": "https://patchwork.libcamera.org/patch/19752/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20240319120517.362082-13-stefan.klug@ideasonboard.com>", "date": "2024-03-19T12:05:13", "name": "[v3,12/16] libcamera: delayed_controls: Ignore delayed request, if there is a newer one", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "f662aa4853abfc4209fe87eaa914aed444356869", "submitter": { "id": 184, "url": "https://patchwork.libcamera.org/api/people/184/?format=api", "name": "Stefan Klug", "email": "stefan.klug@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/19752/mbox/", "series": [ { "id": 4230, "url": "https://patchwork.libcamera.org/api/series/4230/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4230", "date": "2024-03-19T12:05:01", "name": "Preparation for per-frame-controls and initial tests", "version": 3, "mbox": "https://patchwork.libcamera.org/series/4230/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/19752/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/19752/checks/", "tags": {}, "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 7EF4EC32C8\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 19 Mar 2024 12:05:45 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2C54162D6B;\n\tTue, 19 Mar 2024 13:05:45 +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 7B75262D2F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 19 Mar 2024 13:05:30 +0100 (CET)", "from jasper.fritz.box (unknown\n\t[IPv6:2a00:6020:448c:6c00:1478:344b:8fcb:baf5])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C997715EE;\n\tTue, 19 Mar 2024 13:05:03 +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=\"hLF9ZMOk\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1710849903;\n\tbh=e65H+BR9HKWcZ4SGv9EqEiTMDJzzWQA55nciN3BBRyQ=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=hLF9ZMOk7NV69QuCM1cTurHVtwFF4Ep8LU8GhYAKvz69cBil9vLNH/vcDe9bONMWk\n\tx2NjdcxDQHU9Vn43XTUR8neqttp4mQ7zH7Zh7oE04H+Rxc6rVYiW0qTjP7i46gS78v\n\tOOXd5ByPFZgo7YFj0vsMB3hDw6WP075G01GMSlow=", "From": "Stefan Klug <stefan.klug@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Stefan Klug <stefan.klug@ideasonboard.com>", "Subject": "[PATCH v3 12/16] libcamera: delayed_controls: Ignore delayed\n\trequest, 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", "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>" }, "content": "Assume for frame 10 a ExposureTime=42 is queued. We have a delay of 2. After\nreceiving stats for frame 8, the isp tries to queue for frame 9. As it's too\nlae for that frame, delayed controls schedules the update for frame 11. But as\nframe 10 was already queued, the request should be discarded.\n---\n include/libcamera/internal/delayed_controls.h | 2 +\n src/libcamera/delayed_controls.cpp | 19 +++++-\n test/delayed_controls.cpp | 66 +++++++++++++++++++\n 3 files changed, 86 insertions(+), 1 deletion(-)", "diff": "diff --git a/include/libcamera/internal/delayed_controls.h b/include/libcamera/internal/delayed_controls.h\nindex e2decbcc..91c9415a 100644\n--- a/include/libcamera/internal/delayed_controls.h\n+++ b/include/libcamera/internal/delayed_controls.h\n@@ -67,6 +67,8 @@ private:\n \t\t{\n \t\t\treturn std::array<Info, listSize>::operator[](index % listSize);\n \t\t}\n+\n+\t\tunsigned int largestValidIndex;\n \t};\n \n \tbool controlsAreQueued(unsigned int frame, const ControlList &controls);\ndiff --git a/src/libcamera/delayed_controls.cpp b/src/libcamera/delayed_controls.cpp\nindex 3fd5a0f7..7f2bb479 100644\n--- a/src/libcamera/delayed_controls.cpp\n+++ b/src/libcamera/delayed_controls.cpp\n@@ -151,6 +151,7 @@ void DelayedControls::reset(ControlList *controls)\n \t\t * to be written to to device on startup.\n \t\t */\n \t\tvalues_[id][0] = Info(ctrl.second, 0, false);\n+\t\tvalues_[id].largestValidIndex = 0;\n \t}\n \n \t/* Propagate initial state */\n@@ -304,18 +305,34 @@ bool DelayedControls::push(const ControlList &controls, std::optional<uint32_t>\n \t\t\tcontinue;\n \t\t}\n \n-\t\tInfo &info = values_[id][updateIndex];\n+\t\tControlRingBuffer &ring = values_[id];\n+\t\tInfo &info = ring[updateIndex];\n \t\t/*\n \t\t * Update the control only if the already existing value stems from a\n \t\t * request with a sequence number smaller or equal to the current one\n \t\t */\n \t\tif (info.sourceSequence <= sequence) {\n \t\t\tinfo = Info(control.second, sequence);\n+\t\t\tif (updateIndex > ring.largestValidIndex)\n+\t\t\t\tring.largestValidIndex = updateIndex;\n \n \t\t\tLOG(DelayedControls, Debug)\n \t\t\t\t<< \"Queuing \" << id->name()\n \t\t\t\t<< \" to \" << info.toString()\n \t\t\t\t<< \" at index \" << updateIndex;\n+\n+\t\t\t/* fill up the next indices with the new information */\n+\t\t\tunsigned int i = updateIndex + 1;\n+\t\t\twhile (i <= ring.largestValidIndex) {\n+\t\t\t\tLOG(DelayedControls, Error) << \"update \" << i;\n+\t\t\t\tInfo &next = ring[i];\n+\t\t\t\tif (next.sourceSequence <= sequence)\n+\t\t\t\t\tnext = info;\n+\t\t\t\telse\n+\t\t\t\t\tbreak;\n+\n+\t\t\t\ti++;\n+\t\t\t}\n \t\t} else {\n \t\t\tLOG(DelayedControls, Warning)\n \t\t\t\t<< \"Skipped update \" << id->name()\ndiff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\nindex 481334e7..7d671a0e 100644\n--- a/test/delayed_controls.cpp\n+++ b/test/delayed_controls.cpp\n@@ -271,6 +271,68 @@ protected:\n \t\treturn TestPass;\n \t}\n \n+\tint updateTooLateMustSometimesBeIgnored()\n+\t{\n+\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n+\t\t\t{ V4L2_CID_BRIGHTNESS, { 2, false } },\n+\t\t};\n+\t\tstd::unique_ptr<DelayedControls> delayed =\n+\t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n+\t\tControlList ctrls;\n+\n+\t\t/* Reset control to value that will be first in test. */\n+\t\tint32_t initial = 4;\n+\t\tctrls.set(V4L2_CID_BRIGHTNESS, initial);\n+\t\tdev_->setControls(&ctrls);\n+\t\tdelayed->reset();\n+\n+\t\tint32_t expected = 10;\n+\n+\t\tdelayed->push({}, 0);\n+\t\tdelayed->push({}, 1);\n+\t\tctrls.set(V4L2_CID_BRIGHTNESS, expected);\n+\t\tdelayed->push(ctrls, 2);\n+\t\tdelayed->applyControls(0); /* puts 10 on the bus */\n+\n+\t\t/*\n+\t\t * Post an update for frame 1. It's too late to fulfill that request,\n+\t\t * delayed controls will therefore try to delay it to frame 3. But as\n+\t\t * frame 2 is already queued, the update must be dropped.\n+\t\t */\n+\t\tctrls.set(V4L2_CID_BRIGHTNESS, 20);\n+\t\tdelayed->push(ctrls, 1);\n+\t\tdelayed->applyControls(1);\n+\t\tdelayed->applyControls(2);\n+\t\tdelayed->applyControls(3);\n+\n+\t\tint frame = 3;\n+\n+\t\tControlList result = delayed->get(frame);\n+\t\tint32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n+\t\tControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS });\n+\t\tint32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n+\n+\t\tif (brightness != expected) {\n+\t\t\tcerr << \"Failed \" << __func__\n+\t\t\t << \" frame \" << frame\n+\t\t\t << \" expected \" << expected\n+\t\t\t << \" got \" << brightness\n+\t\t\t << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\tif (brightnessV4L != expected) {\n+\t\t\tcerr << \"Failed \" << __func__\n+\t\t\t << \" frame \" << frame\n+\t\t\t << \" expected V4L \" << expected\n+\t\t\t << \" got \" << brightnessV4L\n+\t\t\t << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\treturn TestPass;\n+\t}\n+\n \tint updateTooLateGetsDelayed()\n \t{\n \t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n@@ -503,6 +565,10 @@ protected:\n \t\tif (ret)\n \t\t\tfailed = true;\n \n+\t\tret = updateTooLateMustSometimesBeIgnored();\n+\t\tif (ret)\n+\t\t\tfailed = true;\n+\n \t\tret = updateTooLateGetsDelayed();\n \t\tif (ret)\n \t\t\tfailed = true;\n", "prefixes": [ "v3", "12/16" ] }