Patch Detail
Show a patch.
GET /api/patches/26805/?format=api
{ "id": 26805, "url": "https://patchwork.libcamera.org/api/patches/26805/?format=api", "web_url": "https://patchwork.libcamera.org/patch/26805/", "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": "<20260527081534.20245-6-robert.mader@collabora.com>", "date": "2026-05-27T08:15:34", "name": "[v5,5/5] debayer_egl: Implement dmabuf import for input buffers", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "3873725e4c9b4962c12e226f273eb2b9b17fba2f", "submitter": { "id": 140, "url": "https://patchwork.libcamera.org/api/people/140/?format=api", "name": "Robert Mader", "email": "robert.mader@collabora.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/26805/mbox/", "series": [ { "id": 5965, "url": "https://patchwork.libcamera.org/api/series/5965/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5965", "date": "2026-05-27T08:15:29", "name": "software_isp: Implement DMABuf import for input buffers", "version": 5, "mbox": "https://patchwork.libcamera.org/series/5965/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/26805/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/26805/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 7C917C328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 May 2026 08:16:15 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 41F3E63030;\n\tWed, 27 May 2026 10:16:15 +0200 (CEST)", "from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com\n\t[136.143.188.112])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A67CA62FD3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 May 2026 10:16:12 +0200 (CEST)", "by mx.zohomail.com with SMTPS id 1779869767189707.2228837095331;\n\tWed, 27 May 2026 01:16:07 -0700 (PDT)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=collabora.com\n\theader.i=robert.mader@collabora.com header.b=\"Xx5ZhvTO\"; \n\tdkim-atps=neutral", "ARC-Seal": "i=1; a=rsa-sha256; t=1779869768; cv=none; \n\td=zohomail.com; s=zohoarc; \n\tb=EJq/gfujxM2c/omsSpXzzvxcO9AZuVhlNV9yYG8a4JKucO72eALlCkhZ+W/PXj+l2PRETzPQfNN+wepxVIt7ZT+7spcbp4l3p+8tmkpfMRWfXsfZ9WrlsAZN/nMjeJRhVzM/5aConX2AROXIaNoeBYHmaLjYntLS4T7C7Si9RPk=", "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; \n\ts=zohoarc; t=1779869768;\n\th=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To;\n\tbh=GLFy6yooih8jdmRuaoK+D5lh6st2WpFO/Mjagn3sRIk=; \n\tb=dC+8EPrMVGjwUtwv1Fl47u2IGWmEyFJjpFMX0PADLqTRGMZn9QiZfpdkghwvOLPVoEqJUtglMiW5G8nhnGLb+fFjIeYc9yM73oQQZ9RysJKTwW0qQ4G6vyfCWFIJ2W2zLE/6rzF/FLim/9xD/Z2GVvxI7zwGkA6vC2hbHbRhaPI=", "ARC-Authentication-Results": "i=1; mx.zohomail.com;\n\tdkim=pass header.i=collabora.com;\n\tspf=pass smtp.mailfrom=robert.mader@collabora.com;\n\tdmarc=pass header.from=<robert.mader@collabora.com>", "DKIM-Signature": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1779869768;\n\ts=zohomail; d=collabora.com; i=robert.mader@collabora.com;\n\th=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-ID:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Message-Id:Reply-To;\n\tbh=GLFy6yooih8jdmRuaoK+D5lh6st2WpFO/Mjagn3sRIk=;\n\tb=Xx5ZhvTOg6f+KrNvkjTCYregm77qUA3ObXbWR23cL1pnhdHDg+0bSj7jKhlRtYXd\n\tmVNMU7tk1khpOI2GkwzoBJ65ZPAKuG+44KgKdDT4qL+L1swRiMa3n/OtA8cXyCKSNkf\n\t1L8sb3SXYPqqE9Oz6/41F/uy4RRx1QLs2rZVQwDo=", "From": "Robert Mader <robert.mader@collabora.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Robert Mader <robert.mader@collabora.com>", "Subject": "[PATCH v5 5/5] debayer_egl: Implement dmabuf import for input\n\tbuffers", "Date": "Wed, 27 May 2026 10:15:34 +0200", "Message-ID": "<20260527081534.20245-6-robert.mader@collabora.com>", "X-Mailer": "git-send-email 2.54.0", "In-Reply-To": "<20260527081534.20245-1-robert.mader@collabora.com>", "References": "<20260527081534.20245-1-robert.mader@collabora.com>", "MIME-Version": "1.0", "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": "In many cases we can import the GPU-ISP input buffers, dmabufs from v4l2,\ndirectly into EGL instead of mapping and uploading - i.e. copying - them.\n\nDoing so can have positive effects in multiple areas, including reducing\nmemory bandwidth and CPU usage, as well as avoiding expensive dmabuf syncs\nand syscalls.\n\nThe main reason direct imports may not work are the more demanding stride\nalignment requirements many GPUs have - often 128 or 256 bytes - compared\nto ISPs - apparently often closer to 32 bytes.\n\nThus we first try to import buffers directly and - if that fails - fall back\nto the previous upload path. Failing imports should come at low cost as\ndrivers know the limitations and can bail out early, without causing\nadditional IO or context switches.\n\nIn the future we might be able to request buffers with a matching stride\nfrom v4l2 drivers in many cases, making direct import the norm instead\nof a hit-or-miss. An optional kernel API for that exists, but doesn't\nseem to be implemented by any driver tested so far.\n\nNote that passing around MappedFrameBuffer and DmaSyncer variables ensures\nwe don't do unnecessary mappings and dmabuf syncs.\n\nBelow are some benchmark results. All where done using postmarketOS edge\nwith updates from 21th May 2026 (Mesa 26.1.1). The mentioned pipelines\nwhere run five times each, with the mean value included here, which should\nbe quite representive as the variance was rather small. All devices\nwhere using the powersave governor.\n\n- FairPhone 5\n\n-- Back camera\ncam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@29 -s width=1920,height=1080 --capture=60\nBefore: 14027 us/frame\nAfter: 12122 us/frame\n\n- OnePlus 6\n\n-- Back camera (imx519)\ncam -c /base/soc@0/cci@ac4a000/i2c-bus@0/camera@10 -s width=1920,height=1080 --capture=60\nBefore: 30091 us/frame\nAfter: 19878 us/frame\n\n- Librem 5\n\n-- Back camera\ncam -c /base/soc@0/bus@30800000/i2c@30a50000/camera@2d -s width=1280,height=720 --capture=60\nBefore: 69092 us/frame\nAfter: 41250 us/frame\n\n- PinePhone\n\n-- Front Camera\ncam -c /base/i2c-csi/front-camera@3c -s width=1280,height=720 --capture=60\nBefore: 173769 us/frame\nAfter: 143274 us/frame\n\n-- Back camera\ncam -c /base/i2c-csi/rear-camera@4c -s width=1280,height=720 --capture=60\nBefore: 174833 us/frame\nAfter: 144476 us/frame\n\nThere is one case where performance regresses:\n\n- Pixel 3a\n\n-- Back camera\ncam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@1a -s width=1920,height=1080 --capture=60\nBefore: 14257 us/frame\nAfter: 15161 us/frame\n\nTo my knowledge this is likely caused by bad sampling performance from\nlinear buffers. IMO this is a driver issue - if a copy to tiled format\nmakes sampling faster, drivers should do so implicitly (like e.g. v3d\nalready does).\n\nSigned-off-by: Robert Mader <robert.mader@collabora.com>\n---\n src/libcamera/software_isp/debayer_egl.cpp | 58 ++++++++++++++++------\n src/libcamera/software_isp/debayer_egl.h | 2 +-\n 2 files changed, 43 insertions(+), 17 deletions(-)", "diff": "diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\nindex d08634640..e83a68a97 100644\n--- a/src/libcamera/software_isp/debayer_egl.cpp\n+++ b/src/libcamera/software_isp/debayer_egl.cpp\n@@ -10,6 +10,7 @@\n #include \"debayer_egl.h\"\n \n #include <algorithm>\n+#include <assert.h>\n #include <memory>\n #include <stdlib.h>\n #include <string>\n@@ -500,16 +501,34 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams ¶ms)\n \treturn;\n }\n \n-int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams ¶ms)\n+int DebayerEGL::debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *inMapped, std::optional<DmaSyncer> *inDmaSyncer)\n {\n+\tbool dmabuf_import_succeeded = false;\n+\n \t/* eGL context switch */\n \tegl_.makeCurrent();\n \n-\t/* Create a standard texture input */\n-\tegl_.createTexture2D(*eglImageBayerIn_, in.planes()[0].data());\n+\t/* Try to create texture for input buffer via dmabuf import */\n+\tif (!eglImageBayerIn_->dmabuf_import_failed_) {\n+\t\tif (egl_.createInputDMABufTexture2D(*eglImageBayerIn_, input->planes()[0].fd.get()) == 0)\n+\t\t\tdmabuf_import_succeeded = true;\n+\t\telse\n+\t\t\tLOG(Debayer, Info) << \"Importing input buffer with DMABuf import failed, falling back to upload\";\n+\t}\n+\n+\t/* Otherwise create texture for input buffer via upload from CPU */\n+\tif (!dmabuf_import_succeeded) {\n+\t\tinDmaSyncer->emplace(input->planes()[0].fd, DmaSyncer::SyncType::Read);\n+\t\tinMapped->emplace(input, MappedFrameBuffer::MapFlag::Read);\n+\t\tif (!inMapped->value().isValid()) {\n+\t\t\tLOG(Debayer, Error) << \"mmap-ing buffer(s) failed\";\n+\t\t\treturn -ENODEV;\n+\t\t}\n+\t\tegl_.createTexture2D(*eglImageBayerIn_, inMapped->value().planes()[0].data());\n+\t}\n \n \t/* Generate the output render framebuffer as render to texture */\n-\tegl_.createOutputDMABufTexture2D(*eglImageBayerOut_, out_fd);\n+\tegl_.createOutputDMABufTexture2D(*eglImageBayerOut_, output->planes()[0].fd.get());\n \n \tsetShaderVariableValues(params);\n \tglViewport(0, 0, width_, height_);\n@@ -531,23 +550,16 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n {\n \tbench_.startFrame();\n \n-\tstd::vector<DmaSyncer> dmaSyncers;\n-\n-\tdmaSyncBegin(dmaSyncers, input, nullptr);\n-\n \t/* Copy metadata from the input buffer */\n \tFrameMetadata &metadata = output->_d()->metadata();\n \tmetadata.status = input->metadata().status;\n \tmetadata.sequence = input->metadata().sequence;\n \tmetadata.timestamp = input->metadata().timestamp;\n \n-\tMappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read);\n-\tif (!in.isValid()) {\n-\t\tLOG(Debayer, Error) << \"mmap-ing buffer(s) failed\";\n-\t\tgoto error;\n-\t}\n+\tstd::optional<MappedFrameBuffer> inMapped;\n+\tstd::optional<DmaSyncer> inDmaSyncer;\n \n-\tif (debayerGPU(in, output->planes()[0].fd.get(), params)) {\n+\tif (debayerGPU(input, output, params, &inMapped, &inDmaSyncer)) {\n \t\tLOG(Debayer, Error) << \"debayerGPU failed\";\n \t\tgoto error;\n \t}\n@@ -555,8 +567,22 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n \tmetadata.planes()[0].bytesused = output->planes()[0].length;\n \n \t/* Calculate stats for the whole frame */\n-\tstats_->processFrame(frame, 0, in);\n-\tdmaSyncers.clear();\n+\tif (frame % SwStatsCpu::kStatPerNumFrames) {\n+\t\tstats_->finishFrame(frame, 0);\n+\t} else {\n+\t\tif (!inMapped) {\n+\t\t\t/*\n+\t\t\t * The buffer was directly imported into EGL and thus\n+\t\t\t * not mapped for texture upload. Do it now for the\n+\t\t\t * CPU-based stats calculation.\n+\t\t\t */\n+\t\t\tassert(!inDmaSyncer);\n+\t\t\tinDmaSyncer.emplace(input->planes()[0].fd, DmaSyncer::SyncType::Read);\n+\t\t\tinMapped.emplace(input, MappedFrameBuffer::MapFlag::Read);\n+\t\t}\n+\t\tstats_->processFrame(frame, 0, inMapped.value());\n+\t}\n+\tinDmaSyncer.reset();\n \n \tegl_.syncOutput();\n \tbench_.finishFrame();\ndiff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h\nindex 141fb288f..875e7cfc5 100644\n--- a/src/libcamera/software_isp/debayer_egl.h\n+++ b/src/libcamera/software_isp/debayer_egl.h\n@@ -65,7 +65,7 @@ private:\n \tint initBayerShaders(PixelFormat inputFormat, PixelFormat outputFormat);\n \tint getShaderVariableLocations();\n \tvoid setShaderVariableValues(const DebayerParams ¶ms);\n-\tint debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams ¶ms);\n+\tint debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *mappedInputBuffer, std::optional<DmaSyncer> *inputBufferDmaSyncer);\n \n \t/* Shader program identifiers */\n \tGLuint vertexShaderId_ = 0;\n", "prefixes": [ "v5", "5/5" ] }