[{"id":38955,"web_url":"https://patchwork.libcamera.org/comment/38955/","msgid":"<0b8d0434-0f0e-4c33-9b89-6dc6cb263220@nxsw.ie>","date":"2026-05-26T17:48:45","subject":"Re: [PATCH v4 5/5] debayer_egl: Implement dmabuf import for input\n\tbuffers","submitter":{"id":226,"url":"https://patchwork.libcamera.org/api/people/226/","name":"Bryan O'Donoghue","email":"bod.linux@nxsw.ie"},"content":"On 21/05/2026 16:59, Robert Mader wrote:\n> In many cases we can import the GPU-ISP input buffers, dmabufs from v4l2,\n> directly into EGL instead of mapping and uploading - i.e. copying - them.\n> \n> Doing so can have positive effects in multiple areas, including reducing\n> memory bandwidth and CPU usage, as well as avoiding expensive dmabuf syncs\n> and syscalls.\n> \n> The main reason direct imports may not work are the more demanding stride\n> alignment requirements many GPUs have - often 128 or 256 bytes - compared\n> to ISPs - apparently often closer to 32 bytes.\n> \n> Thus we first try to import buffers directly and - if that fails - fall back\n> to the previous upload path. Failing imports should come at low cost as\n> drivers know the limitations and can bail out early, without causing\n> additional IO or context switches.\n> \n> In the future we might be able to request buffers with a matching stride\n> from v4l2 drivers in many cases, making direct import the norm instead\n> of a hit-or-miss. An optional kernel API for that exists, but doesn't\n> seem to be implemented by any driver tested so far.\n> \n> Note that passing around MappedFrameBuffer and DmaSyncer variables ensures\n> we don't do unnecessary mappings and dmabuf syncs.\n> \n> Below are some benchmark results. All where done using postmarketOS edge\n> with updates from 21th May 2026 (Mesa 26.1.1). The mentioned pipelines\n> where run five times each, with the mean value included here, which should\n> be quite representive as the variance was rather small. All devices\n> where using the powersave governor.\n> \n> - FairPhone 5\n> \n> -- Back camera\n> cam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@29 -s width=1920,height=1080 --capture=60\n> Before: 14027 us/frame\n> After: 12122 us/frame\n> \n> - OnePlus 6\n> \n> -- Back camera (imx519)\n> cam -c /base/soc@0/cci@ac4a000/i2c-bus@0/camera@10 -s width=1920,height=1080 --capture=60\n> Before: 30091 us/frame\n> After: 19878 us/frame\n> \n> - Librem 5\n> \n> -- Back camera\n> cam -c /base/soc@0/bus@30800000/i2c@30a50000/camera@2d -s width=1280,height=720 --capture=60\n> Before: 69092 us/frame\n> After: 41250 us/frame\n> \n> - PinePhone\n> \n> -- Front Camera\n> cam -c /base/i2c-csi/front-camera@3c -s width=1280,height=720 --capture=60\n> Before: 173769 us/frame\n> After: 143274 us/frame\n> \n> -- Back camera\n> cam -c /base/i2c-csi/rear-camera@4c -s width=1280,height=720 --capture=60\n> Before: 174833 us/frame\n> After: 144476 us/frame\n> \n> There is one case where performance regresses:\n> \n> - Pixel 3a\n> \n> -- Back camera\n> cam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@1a -s width=1920,height=1080 --capture=60\n> Before: 14257 us/frame\n> After: 15161 us/frame\n> \n> To my knowledge this is likely caused by bad sampling performance from\n> linear buffers. IMO this is a driver issue - if a copy to tiled format\n> makes sampling faster, drivers should do so implicitly (like e.g. v3d\n> already does).\n> \n> Signed-off-by: Robert Mader <robert.mader@collabora.com>\n> ---\n>   src/libcamera/software_isp/debayer_egl.cpp | 45 ++++++++++++++--------\n>   src/libcamera/software_isp/debayer_egl.h   |  2 +-\n>   2 files changed, 30 insertions(+), 17 deletions(-)\n> \n> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> index d15f3cd48..c1075ac39 100644\n> --- a/src/libcamera/software_isp/debayer_egl.cpp\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -500,16 +500,30 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)\n>   \treturn;\n>   }\n> \n> -int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams &params)\n> +int DebayerEGL::debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams &params, std::optional<MappedFrameBuffer> *inMapped, std::optional<DmaSyncer> *inDmaSyncer)\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\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 (eglImageBayerIn_->dmabuf_import_failed_) {\n> +\t\tinMapped->emplace(input, MappedFrameBuffer::MapFlag::Read);\n> +\t\tinDmaSyncer->emplace(input->planes()[0].fd, DmaSyncer::SyncType::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\nI think this reads better as an if/else instea of if(!) followed by \nbase-case.\n\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 +545,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 +562,14 @@ 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) == 0) {\n> +\t\tif (!inMapped)\n> +\t\t\tinMapped.emplace(input, MappedFrameBuffer::MapFlag::Read);\n> +\t\tif (!inDmaSyncer)\n> +\t\t\tinDmaSyncer.emplace(input->planes()[0].fd, DmaSyncer::SyncType::Read);\n> +\t}\n\nPer previous comment I think you should only do processFrame when you \nknow you have valid data _and_ I think you should comment here about the \nopportunistic mapping you are doing.\n\nAll in all I like the direction here though.\n\n> +\tstats_->processFrame(frame, 0, inMapped ? &inMapped.value() : nullptr);\n> +\tinDmaSyncer.reset();\n> \n>   \tegl_.syncOutput();\n>   \tbench_.finishFrame();\n> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h\n> index 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 &params);\n> -\tint debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams &params);\n> +\tint debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams &params, std::optional<MappedFrameBuffer> *mappedInputBuffer, std::optional<DmaSyncer> *inputBufferDmaSyncer);\n> \n>   \t/* Shader program identifiers */\n>   \tGLuint vertexShaderId_ = 0;\n> --\n> 2.54.0\n>","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 58CABBDCBC\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 26 May 2026 17:48:54 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AA04B62FD3;\n\tTue, 26 May 2026 19:48:53 +0200 (CEST)","from mail-4317.protonmail.ch (mail-4317.protonmail.ch\n\t[185.70.43.17])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E245F62FB1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 May 2026 19:48:51 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxsw.ie header.i=@nxsw.ie header.b=\"Zuguc6vm\";\n\tdkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxsw.ie;\n\ts=protonmail; t=1779817729; x=1780076929;\n\tbh=wbMBOdR01KARtPf0u9nJjm2BNqgknyaNxnpYSRaJa6U=;\n\th=Date:To:From:Subject:Message-ID:In-Reply-To:References:\n\tFeedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:\n\tMessage-ID:BIMI-Selector;\n\tb=Zuguc6vmLnW7bhEX2tHypuhsOUKquPHA/TCLMK0C90aCzH5/2UUxBySyW4xbd9XEs\n\t/nBRY9dxIC7oUKgfPK3iIp/BaldVeB9alSmWo0o7kzW7imYw3/eTFQTNo8qAS4iVJv\n\tl2hLD7EIPCbPpGAq1PiDZkNaoLIStGIBjpxGCeUYZhjpvv7HwkdoWDR06BKZtz6Ypt\n\tFC7y3Fct3j5JiJgc14N8WvLnEdGNOWvY3A1k9iHp9scUKmM0ZVAS3acmqH4JYpL4Xr\n\tqm0V8BevC12CmkkFUv0cOSgDK0tGmbP0RW/9HlVGBJgYQ3DTlJ2M4oSZOpxK9Vqvc3\n\twykfa3uwT3Htw==","Date":"Tue, 26 May 2026 17:48:45 +0000","To":"Robert Mader <robert.mader@collabora.com>,\n\tlibcamera-devel@lists.libcamera.org","From":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Subject":"Re: [PATCH v4 5/5] debayer_egl: Implement dmabuf import for input\n\tbuffers","Message-ID":"<0b8d0434-0f0e-4c33-9b89-6dc6cb263220@nxsw.ie>","In-Reply-To":"<20260521155906.120373-6-robert.mader@collabora.com>","References":"<20260521155906.120373-1-robert.mader@collabora.com>\n\t<20260521155906.120373-6-robert.mader@collabora.com>","Feedback-ID":"136405006:user:proton","X-Pm-Message-ID":"6099e3956d77a89ac133abbc8efa7c70283223c8","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","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>"}},{"id":38960,"web_url":"https://patchwork.libcamera.org/comment/38960/","msgid":"<b4198d68-7aa5-446a-b020-0851eba3fdb6@collabora.com>","date":"2026-05-27T08:24:45","subject":"Re: [PATCH v4 5/5] debayer_egl: Implement dmabuf import for input\n\tbuffers","submitter":{"id":140,"url":"https://patchwork.libcamera.org/api/people/140/","name":"Robert Mader","email":"robert.mader@collabora.com"},"content":"On 26.05.26 19:48, Bryan O'Donoghue wrote:\n> On 21/05/2026 16:59, Robert Mader wrote:\n>> ...\n>>\n>> -int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams &params)\n>> +int DebayerEGL::debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams &params, std::optional<MappedFrameBuffer> *inMapped, std::optional<DmaSyncer> *inDmaSyncer)\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\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 (eglImageBayerIn_->dmabuf_import_failed_) {\n>> +\t\tinMapped->emplace(input, MappedFrameBuffer::MapFlag::Read);\n>> +\t\tinDmaSyncer->emplace(input->planes()[0].fd, DmaSyncer::SyncType::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> I think this reads better as an if/else instea of if(!) followed by\n> base-case.\n\nIt's unfortunately a bit tricky if we want to keep the LOG() (which I \nthink we should) - I tried to improve the readability in v5, please let \nme know if you like that better.\n\n>> ...\n>>    \t/* Calculate stats for the whole frame */\n>> -\tstats_->processFrame(frame, 0, &in);\n>> -\tdmaSyncers.clear();\n>> +\tif ((frame % SwStatsCpu::kStatPerNumFrames) == 0) {\n>> +\t\tif (!inMapped)\n>> +\t\t\tinMapped.emplace(input, MappedFrameBuffer::MapFlag::Read);\n>> +\t\tif (!inDmaSyncer)\n>> +\t\t\tinDmaSyncer.emplace(input->planes()[0].fd, DmaSyncer::SyncType::Read);\n>> +\t}\n> Per previous comment I think you should only do processFrame when you\n> know you have valid data _and_ I think you should comment here about the\n> opportunistic mapping you are doing.\nDid that in v5\n> All in all I like the direction here though.\nThanks for the review!","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 1514DC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 May 2026 08:24:56 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2C5D36301A;\n\tWed, 27 May 2026 10:24:55 +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 DD72F62E6A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 May 2026 10:24:52 +0200 (CEST)","by mx.zohomail.com with SMTPS id 1779870287717828.7802700506916;\n\tWed, 27 May 2026 01:24:47 -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=\"EhPAHNTv\"; \n\tdkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1779870289; cv=none; \n\td=zohomail.com; s=zohoarc; \n\tb=RpouDKpAEhKtYq+bmJt8HPlJvY7f19y+FvEy0IqCJNUekSt//brUzJmr9FPKisHEntuvyS6lRxg/Yf2YMpmCrt+NjSytj7a2DPVNZVXlCGhHxLOfZ5TWcT/XId2MII7UoWxsh1WNMXYrzz3A8o9qEGVuUn5lOtf539LoBJCxNJU=","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; \n\ts=zohoarc; t=1779870289;\n\th=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To:Cc;\n\tbh=tLvyPyb88NHvFRrE+8J7ojsurqujwPmu6tiUsFcAkds=; \n\tb=gJP5x1DIgjs/sa7cFk1/pMEhpD7nmELEP/i0t9J4GJ5+PxpZwYRO6HJ7MSp2uWo+R+Yjbg5712IIBF15JRGIkqvm65s7Y/BlmX9w2JIrnpRxATAVfgGq31sHZS74v75xmBs+KomUmn8LlCvRdq+dSIvpMXWWk9v7TOIA7KNlE5s=","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=1779870289;\n\ts=zohomail; d=collabora.com; i=robert.mader@collabora.com;\n\th=Message-ID:Date:Date:MIME-Version:Subject:Subject:To:To:References:From:From:In-Reply-To:Content-Type:Content-Transfer-Encoding:Message-Id:Reply-To:Cc;\n\tbh=tLvyPyb88NHvFRrE+8J7ojsurqujwPmu6tiUsFcAkds=;\n\tb=EhPAHNTviKQbg1O4fhx1Il51iWLWbsu781rxQIWNlkIV1+OrSA9MKuZ10V7cr3vo\n\tpW90q4SU5xOWRhQkY0Lpf9oM5UhGgBQoCKHZfkScJ1ShZujBnnA5+Cz89tCfYHFz85o\n\tdl/zhRd1fwR5yVe7qOk2Pxt+Z+ziCGb0hBgityIs=","Message-ID":"<b4198d68-7aa5-446a-b020-0851eba3fdb6@collabora.com>","Date":"Wed, 27 May 2026 10:24:45 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v4 5/5] debayer_egl: Implement dmabuf import for input\n\tbuffers","To":"Bryan O'Donoghue <bod.linux@nxsw.ie>, libcamera-devel@lists.libcamera.org","References":"<20260521155906.120373-1-robert.mader@collabora.com>\n\t<20260521155906.120373-6-robert.mader@collabora.com>\n\t<0b8d0434-0f0e-4c33-9b89-6dc6cb263220@nxsw.ie>","Content-Language":"en-US, de-DE, en-GB","From":"Robert Mader <robert.mader@collabora.com>","In-Reply-To":"<0b8d0434-0f0e-4c33-9b89-6dc6cb263220@nxsw.ie>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","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>"}}]