From patchwork Thu Jun 18 12:38:30 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 26977 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 21C02C3301 for ; Thu, 18 Jun 2026 12:39:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 59DCA62C7B; Thu, 18 Jun 2026 14:39:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="E/N9uqwD"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F07C3656C7 for ; Thu, 18 Jun 2026 14:38:50 +0200 (CEST) Received: from pb-laptop.local (185.182.214.63.nat.pool.zt.hu [185.182.214.63]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 112412F8 for ; Thu, 18 Jun 2026 14:38:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1781786296; bh=YdnQKEA4cjCE/QtSQXKKRRDTNSOgXYSvz9IHtLgnY1w=; h=From:To:Subject:Date:In-Reply-To:References:From; b=E/N9uqwDG8GestQHW7c/RvE+Ug1nnPjmyVzq6ZrXvt968qNbu57cR2Wvaz5a57bPU xKlZ5/uUUs9k0ZIGpMLk+C6eb9syUEsaZgstTSQkQ+Q3jvcgsnKGM4wk2jVQf6Itvr tg76arcOTxMSGNeh31z5Sg8mP6WvmDEf3g4phKUc= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v1 13/27] libcamera: pipeline: virtual: Make copy of request'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 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" The change that moved frame generation to a separate thread introduced a race condition. After the last buffer of a request is completed, the loop in `VirtualCameraData::processRequest()` will reference the buffer map in the loop condition. This is problematic because concurrently the request will be completed, then reused or destroyed. This was mostly hidden by the fact that most application use `ReuseBuffers`, so the buffer map nodes do not change. Fix that by making a copy of the (stream, buffer) pairs locally. Fixes: 6c251ae3ef0e ("libcamera: pipeline: virtual: Move image generation to separate thread") Signed-off-by: Barnabás Pőcze --- src/libcamera/pipeline/virtual/virtual.cpp | 40 +++++++++++++--------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp index 81d2dddab8..a7cd76e226 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -130,33 +130,39 @@ VirtualCameraData::VirtualCameraData(PipelineHandler *pipe, void VirtualCameraData::processRequest(Request *request) { + std::array, kMaxStream> buffers; + size_t bufferCount = 0; + for (const auto &[stream, buffer] : request->buffers()) { bool found = false; - /* map buffer and fill test patterns */ for (auto &streamConfig : streamConfigs_) { if (stream == &streamConfig.stream) { - FrameMetadata &fmd = buffer->_d()->metadata(); - - fmd.status = FrameMetadata::Status::FrameSuccess; - fmd.sequence = streamConfig.seq++; - fmd.timestamp = currentTimestamp(); - - Span planes = buffer->planes(); - for (const auto [i, p] : utils::enumerate(planes)) - fmd.planes()[i].bytesused = p.length; - + buffers[bufferCount++] = { &streamConfig, buffer }; found = true; - - if (streamConfig.frameGenerator->generateFrame( - stream->configuration().size, buffer)) - fmd.status = FrameMetadata::Status::FrameError; - - bufferCompleted.emit(buffer); break; } } ASSERT(found); } + + for (size_t i = 0; i < bufferCount; i++) { + const auto &[stream, buffer] = buffers[i]; + FrameMetadata &fmd = buffer->_d()->metadata(); + + fmd.status = FrameMetadata::Status::FrameSuccess; + fmd.sequence = stream->seq++; + fmd.timestamp = currentTimestamp(); + + Span planes = buffer->planes(); + for (const auto [j, p] : utils::enumerate(planes)) + fmd.planes()[j].bytesused = p.length; + + if (stream->frameGenerator->generateFrame(stream->stream.configuration().size, + buffer)) + fmd.status = FrameMetadata::Status::FrameError; + + bufferCompleted.emit(buffer); + } } VirtualCameraConfiguration::VirtualCameraConfiguration(VirtualCameraData *data)