{"id":26977,"url":"https://patchwork.libcamera.org/api/1.1/patches/26977/?format=json","web_url":"https://patchwork.libcamera.org/patch/26977/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260618123844.656396-14-barnabas.pocze@ideasonboard.com>","date":"2026-06-18T12:38:30","name":"[RFC,v1,13/27] libcamera: pipeline: virtual: Make copy of request's buffer map","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"ced654a7851d72c2d62e36ae310bbba3b8d10554","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/1.1/people/216/?format=json","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/26977/mbox/","series":[{"id":6006,"url":"https://patchwork.libcamera.org/api/1.1/series/6006/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=6006","date":"2026-06-18T12:38:17","name":"Misc. changes before request-buffer split","version":1,"mbox":"https://patchwork.libcamera.org/series/6006/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/26977/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/26977/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 21C02C3301\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 18 Jun 2026 12:39:19 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 59DCA62C7B;\n\tThu, 18 Jun 2026 14:39:13 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F07C3656C7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Jun 2026 14:38:50 +0200 (CEST)","from pb-laptop.local (185.182.214.63.nat.pool.zt.hu\n\t[185.182.214.63])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 112412F8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Jun 2026 14:38:16 +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=\"E/N9uqwD\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1781786296;\n\tbh=YdnQKEA4cjCE/QtSQXKKRRDTNSOgXYSvz9IHtLgnY1w=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=E/N9uqwDG8GestQHW7c/RvE+Ug1nnPjmyVzq6ZrXvt968qNbu57cR2Wvaz5a57bPU\n\txKlZ5/uUUs9k0ZIGpMLk+C6eb9syUEsaZgstTSQkQ+Q3jvcgsnKGM4wk2jVQf6Itvr\n\ttg76arcOTxMSGNeh31z5Sg8mP6WvmDEf3g4phKUc=","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Subject":"[RFC PATCH v1 13/27] libcamera: pipeline: virtual: Make copy of\n\trequest's buffer map","Date":"Thu, 18 Jun 2026 14:38:30 +0200","Message-ID":"<20260618123844.656396-14-barnabas.pocze@ideasonboard.com>","X-Mailer":"git-send-email 2.54.0","In-Reply-To":"<20260618123844.656396-1-barnabas.pocze@ideasonboard.com>","References":"<20260618123844.656396-1-barnabas.pocze@ideasonboard.com>","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":"The change that moved frame generation to a separate thread introduced\na race condition. After the last buffer of a request is completed, the\nloop in `VirtualCameraData::processRequest()` will reference the buffer\nmap in the loop condition. This is problematic because concurrently the\nrequest will be completed, then reused or destroyed. This was mostly\nhidden by the fact that most application use `ReuseBuffers`, so the\nbuffer map nodes 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 | 40 +++++++++++++---------\n 1 file changed, 23 insertions(+), 17 deletions(-)","diff":"diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\nindex 81d2dddab8..a7cd76e226 100644\n--- a/src/libcamera/pipeline/virtual/virtual.cpp\n+++ b/src/libcamera/pipeline/virtual/virtual.cpp\n@@ -130,33 +130,39 @@ 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,\n+\t\t\t\t\t\t\t  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":["RFC","v1","13/27"]}