Show a patch.

GET /api/patches/27084/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 27084,
    "url": "https://patchwork.libcamera.org/api/patches/27084/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/27084/",
    "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": "<20260629163017.863145-6-barnabas.pocze@ideasonboard.com>",
    "date": "2026-06-29T16:29:28",
    "name": "[RFC,v1,05/54] 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/people/216/?format=api",
        "name": "Barnabás Pőcze",
        "email": "barnabas.pocze@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/27084/mbox/",
    "series": [
        {
            "id": 6025,
            "url": "https://patchwork.libcamera.org/api/series/6025/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=6025",
            "date": "2026-06-29T16:29:23",
            "name": "libcamera: Split requests and buffers",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/6025/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/27084/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/27084/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 263BFC3261\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 29 Jun 2026 16:30:45 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E8B1165F2E;\n\tMon, 29 Jun 2026 18:30:30 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D162965F20\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 29 Jun 2026 18:30:21 +0200 (CEST)",
            "from pb-laptop.local (185.221.140.128.nat.pool.zt.hu\n\t[185.221.140.128])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A1CC38D4;\n\tMon, 29 Jun 2026 18:29:38 +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=\"il+3Cpp9\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782750578;\n\tbh=yVAj9Bv4E+3KPxNZWyQfWEEa281jmw3Oasae8yqgqI4=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=il+3Cpp9CIgXuBBPscfBzoXei1GKhEITcDdnsq2D7SR56aNbHqTeLvWJ19SwFuon3\n\t/ZDUMstWMr/frqX8VgX9ihZZ4GGluTVx7/Hv1oHc/tZwKrGW1z7GU89CRDiWGr4Oq0\n\tLpCB69dPyXzJP4tJ0qZ08P5Ep9gsdU7xWv7fju9M=",
        "From": "=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>",
        "Subject": "[RFC PATCH v1 05/54] libcamera: pipeline: virtual: Make copy of\n\trequest'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",
        "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>\nReviewed-by: Laurent Pinchart <laurent.pinchart@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",
        "05/54"
    ]
}