From patchwork Mon Jun 29 16:29:28 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: 27084 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 263BFC3261 for ; Mon, 29 Jun 2026 16:30:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E8B1165F2E; Mon, 29 Jun 2026 18:30:30 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="il+3Cpp9"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D162965F20 for ; Mon, 29 Jun 2026 18:30:21 +0200 (CEST) Received: from pb-laptop.local (185.221.140.128.nat.pool.zt.hu [185.221.140.128]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A1CC38D4; Mon, 29 Jun 2026 18:29:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1782750578; bh=yVAj9Bv4E+3KPxNZWyQfWEEa281jmw3Oasae8yqgqI4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=il+3Cpp9CIgXuBBPscfBzoXei1GKhEITcDdnsq2D7SR56aNbHqTeLvWJ19SwFuon3 /ZDUMstWMr/frqX8VgX9ihZZ4GGluTVx7/Hv1oHc/tZwKrGW1z7GU89CRDiWGr4Oq0 LpCB69dPyXzJP4tJ0qZ08P5Ep9gsdU7xWv7fju9M= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Cc: Laurent Pinchart Subject: [RFC PATCH v1 05/54] libcamera: pipeline: virtual: Make copy of request's buffer map Date: Mon, 29 Jun 2026 18:29:28 +0200 Message-ID: <20260629163017.863145-6-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260629163017.863145-1-barnabas.pocze@ideasonboard.com> References: <20260629163017.863145-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 Reviewed-by: Laurent Pinchart --- 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)