Patch Detail
Show a patch.
GET /api/patches/26758/?format=api
{ "id": 26758, "url": "https://patchwork.libcamera.org/api/patches/26758/?format=api", "web_url": "https://patchwork.libcamera.org/patch/26758/", "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": "<20260514150046.503654-1-barnabas.pocze@ideasonboard.com>", "date": "2026-05-14T15:00:46", "name": "[v1] libcamera: pipeline: virtual: Make copy of request's buffer map", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "dd85fed1106e7002220e532351d78c361983fde3", "submitter": { "id": 216, "url": "https://patchwork.libcamera.org/api/people/216/?format=api", "name": "Barnabás Pőcze", "email": "barnabas.pocze@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/26758/mbox/", "series": [ { "id": 5947, "url": "https://patchwork.libcamera.org/api/series/5947/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5947", "date": "2026-05-14T15:00:46", "name": "[v1] libcamera: pipeline: virtual: Make copy of request's buffer map", "version": 1, "mbox": "https://patchwork.libcamera.org/series/5947/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/26758/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/26758/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 72843BDCBC\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 14 May 2026 15:00:53 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7E4F162FE1;\n\tThu, 14 May 2026 17:00:52 +0200 (CEST)", "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 4CE9962FE1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 14 May 2026 17:00:50 +0200 (CEST)", "from pb-laptop.local (185.182.215.166.nat.pool.zt.hu\n\t[185.182.215.166])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EEBDAD7E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 14 May 2026 17:00:40 +0200 (CEST)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Cme7H6gA\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1778770841;\n\tbh=0jeO9HTWQOs7fa80SwCWmYA5AroSHS0PNLBrgnjUFBg=;\n\th=From:To:Subject:Date:From;\n\tb=Cme7H6gAKDKwBrb4yWpl+sZDr68wZY5vhmysYuk3R7+hIprC3qji8jm6amAnx5wqg\n\tOBq0sNZHuZXUZk4lB989b+WejPa8hVdhrYvjdf27Owarl0JMQSAF1XYNPOJUPsZm1F\n\tpopYl/Uy+lBYdKowh3Yv2huGu1zuqHd7cZF0BZ5A=", "From": "=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Subject": "[PATCH v1] libcamera: pipeline: virtual: Make copy of request's\n\tbuffer map", "Date": "Thu, 14 May 2026 17:00:46 +0200", "Message-ID": "<20260514150046.503654-1-barnabas.pocze@ideasonboard.com>", "X-Mailer": "git-send-email 2.54.0", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "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": "A `Request` must not be accessed by a pipeline handler after it has called\n`completeRequest()` as that call essentially transfers the request back\nto the application.\n\nThe change that moved frame generation to a separate thread violated this\nrequirement. After the last buffer of a request is completed, the loop in\n`VirtualCameraData::processRequest()` will reference the buffer map in\nthe loop condition. This is problematic because concurrently the request\nwill be completed, then reused or destroyed. This was mostly hidden by\nthe fact that most application use `ReuseBuffers`, so the buffer map\nnodes do not change.\n\nFix that by making a copy of the (stream, buffer) pairs locally.\n\nFixes: 6c251ae3ef0e (\"libcamera: pipeline: virtual: Move image generation to separate thread\")\nSigned-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n---\n src/libcamera/pipeline/virtual/virtual.cpp | 39 ++++++++++++----------\n 1 file changed, 22 insertions(+), 17 deletions(-)", "diff": "diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\nindex 81d2dddab..6e0cb6478 100644\n--- a/src/libcamera/pipeline/virtual/virtual.cpp\n+++ b/src/libcamera/pipeline/virtual/virtual.cpp\n@@ -130,33 +130,38 @@ VirtualCameraData::VirtualCameraData(PipelineHandler *pipe,\n \n void VirtualCameraData::processRequest(Request *request)\n {\n+\tstd::array<std::pair<StreamConfig *, FrameBuffer *>, kMaxStream> buffers;\n+\tsize_t bufferCount = 0;\n+\n \tfor (const auto &[stream, buffer] : request->buffers()) {\n \t\tbool found = false;\n-\t\t/* map buffer and fill test patterns */\n \t\tfor (auto &streamConfig : streamConfigs_) {\n \t\t\tif (stream == &streamConfig.stream) {\n-\t\t\t\tFrameMetadata &fmd = buffer->_d()->metadata();\n-\n-\t\t\t\tfmd.status = FrameMetadata::Status::FrameSuccess;\n-\t\t\t\tfmd.sequence = streamConfig.seq++;\n-\t\t\t\tfmd.timestamp = currentTimestamp();\n-\n-\t\t\t\tSpan<const FrameBuffer::Plane> planes = buffer->planes();\n-\t\t\t\tfor (const auto [i, p] : utils::enumerate(planes))\n-\t\t\t\t\tfmd.planes()[i].bytesused = p.length;\n-\n+\t\t\t\tbuffers[bufferCount++] = { &streamConfig, buffer };\n \t\t\t\tfound = true;\n-\n-\t\t\t\tif (streamConfig.frameGenerator->generateFrame(\n-\t\t\t\t\t stream->configuration().size, buffer))\n-\t\t\t\t\tfmd.status = FrameMetadata::Status::FrameError;\n-\n-\t\t\t\tbufferCompleted.emit(buffer);\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\n \t\tASSERT(found);\n \t}\n+\n+\tfor (size_t i = 0; i < bufferCount; i++) {\n+\t\tconst auto &[stream, buffer] = buffers[i];\n+\t\tFrameMetadata &fmd = buffer->_d()->metadata();\n+\n+\t\tfmd.status = FrameMetadata::Status::FrameSuccess;\n+\t\tfmd.sequence = stream->seq++;\n+\t\tfmd.timestamp = currentTimestamp();\n+\n+\t\tSpan<const FrameBuffer::Plane> planes = buffer->planes();\n+\t\tfor (const auto [j, p] : utils::enumerate(planes))\n+\t\t\tfmd.planes()[j].bytesused = p.length;\n+\n+\t\tif (stream->frameGenerator->generateFrame(stream->stream.configuration().size, buffer))\n+\t\t\tfmd.status = FrameMetadata::Status::FrameError;\n+\n+\t\tbufferCompleted.emit(buffer);\n+\t}\n }\n \n VirtualCameraConfiguration::VirtualCameraConfiguration(VirtualCameraData *data)\n", "prefixes": [ "v1" ] }