[{"id":39173,"web_url":"https://patchwork.libcamera.org/comment/39173/","msgid":"<0fd60302-896b-4b99-90b4-bde29b83544c@ideasonboard.com>","date":"2026-06-18T12:50:05","subject":"Re: [PATCH 29/30] libcamera: software_isp: gpu: Cache output\n\tframebuffers, only recreate when necessary","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2026. 06. 18. 14:22 keltezéssel, Bryan O'Donoghue írta:\n> Once a texture has been created using dma-buf handle, we can switch texture\n> units and ids with our glsl program without re-creating textures.\n> \n> Since we are mapping pages, instead of copying the GPU simply takes the\n> maps it needs and operates on those.\n> \n> Much faster.\n> \n> ➜  libcamera git:(0.7.0-multipass-v4) ✗ grep Bench before.log\n> [15:07:08.009062165] [1195303]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 729270us, 24309 us/frame\n> [15:07:11.686143411] [1195334]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 733995us, 24466 us/frame\n> [15:07:14.980640685] [1195363]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 740157us, 24671 us/frame\n> [15:07:18.163299379] [1195393]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 720094us, 24003 us/frame\n> [15:07:21.366461990] [1195422]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 719166us, 23972 us/frame\n> [15:07:24.718877325] [1195451]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 725425us, 24180 us/frame\n> [15:07:28.924768220] [1195481]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 753400us, 25113 us/frame\n> [15:07:32.336224289] [1195513]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 727160us, 24238 us/frame\n> [15:07:35.638928194] [1195542]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 762408us, 25413 us/frame\n> [15:07:38.868084716] [1195579]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 728991us, 24299 us/frame\n> \n> ➜  libcamera git:(0.7.0-multipass-v4) ✗ grep Bench after.log\n> [16:26:07.109426223] [1202010]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 650120us, 21670 us/frame\n> [16:26:18.925748074] [1202048]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 611062us, 20368 us/frame\n> [16:26:22.712614967] [1202077]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 609333us, 20311 us/frame\n> [16:26:26.551615514] [1202107]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 609791us, 20326 us/frame\n> [16:26:30.085663553] [1202136]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 612838us, 20427 us/frame\n> [16:26:34.945255617] [1202165]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 681918us, 22730 us/frame\n> [16:26:39.031353171] [1202194]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 595551us, 19851 us/frame\n> [16:26:42.610503048] [1202227]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 663929us, 22130 us/frame\n> [16:26:46.100211690] [1202256]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 580685us, 19356 us/frame\n> [16:26:49.394640903] [1202286]  INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 595072us, 19835 us/frame\n> \n> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>\n> ---\n>   .../software_isp/software_isp_pipeline_gpu.cpp  | 17 ++++++++++-------\n>   .../software_isp/software_isp_pipeline_gpu.h    |  2 +-\n>   2 files changed, 11 insertions(+), 8 deletions(-)\n> \n> diff --git a/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp b/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp\n> index 2e5c0e40e..bc5d59575 100644\n> --- a/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp\n> +++ b/src/libcamera/software_isp/software_isp_pipeline_gpu.cpp\n> @@ -263,8 +263,14 @@ int SoftwareIspPipelineGpu::processGPU(FrameBuffer *input, FrameBuffer *output,\n>   \t\tegl_.updateInputTexture2D(*eglImageBayerIn_, inMapped->value().planes()[0].data());\n>   \t}\n>   \n> -\t/* Generate the output render framebuffer as render to texture */\n> -\tegl_.createOutputDMABufTexture2D(*eglImageRGBAOut_, output->planes()[0].fd.get());\n> +\t/* Find an existing eglImage in the cache */\n> +\tauto [output_cache, output_miss] = eglImageRGBAOut_.try_emplace(output);\n> +\tif (output_miss) {\n> +\t\t/* Generate the output render framebuffer as render to texture */\n> +\t\toutput_cache->second = std::make_unique<eGLImage>(GL_RGBA, outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE3, 3);\n> +\t\tegl_.createOutputDMABufTexture2D(*output_cache->second, output->planes()[0].fd.get());\n> +\t}\n> +\teGLImage &eglImageRGBAOut = *output_cache->second;\n>   \n>   \tpipelineResult = gpuIspShaderPassBlcNormalise_.process(*eglImageBayerIn_, *eglImagePingPong_[0], width_, height_, params);\n>   \tif (pipelineResult) {\n> @@ -272,7 +278,7 @@ int SoftwareIspPipelineGpu::processGPU(FrameBuffer *input, FrameBuffer *output,\n>   \t\treturn pipelineResult;\n>   \t}\n>   \n> -\tpipelineResult = gpuIspShaderPassDemosiac_.process(*eglImagePingPong_[0], *eglImageRGBAOut_, width_, height_, params);\n> +\tpipelineResult = gpuIspShaderPassDemosiac_.process(*eglImagePingPong_[0], eglImageRGBAOut, width_, height_, params);\n>   \tif (pipelineResult) {\n>   \t\tLOG(Debayer, Error) << \"Demosiac fail\";\n>   \t\treturn pipelineResult;\n> @@ -371,9 +377,6 @@ int SoftwareIspPipelineGpu::start()\n>   \teglImagePingPong_[0] = std::make_unique<eGLImage>(gpuIspShaderPassDemosiac_.glFormat_, width_, height_, outputConfig_.stride, GL_TEXTURE1, 1);\n>   \teglImagePingPong_[1] = std::make_unique<eGLImage>(gpuIspShaderPassDemosiac_.glFormat_, width_, height_, outputConfig_.stride, GL_TEXTURE2, 2);\n>   \n> -\t/* Texture we will render to */\n> -\teglImageRGBAOut_ = std::make_unique<eGLImage>(GL_RGBA, outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE3, 3);\n> -\n>   \tegl_.createInputTexture2D(*eglImageBayerIn_, NULL);\n>   \tegl_.createOutputTexture2D(*eglImagePingPong_[0]);\n>   \tegl_.createOutputTexture2D(*eglImagePingPong_[1]);\n> @@ -383,7 +386,7 @@ int SoftwareIspPipelineGpu::start()\n>   \n>   void SoftwareIspPipelineGpu::stop()\n>   {\n> -\teglImageRGBAOut_.reset();\n> +\teglImageRGBAOut_.clear();\n>   \teglImagePingPong_[1].reset();\n>   \teglImagePingPong_[0].reset();\n>   \teglImageBayerIn_.reset();\n> diff --git a/src/libcamera/software_isp/software_isp_pipeline_gpu.h b/src/libcamera/software_isp/software_isp_pipeline_gpu.h\n> index b32d4cad3..995e84295 100644\n> --- a/src/libcamera/software_isp/software_isp_pipeline_gpu.h\n> +++ b/src/libcamera/software_isp/software_isp_pipeline_gpu.h\n> @@ -69,7 +69,7 @@ private:\n>   \t/* Pointer to object representing input texture */\n>   \tstd::unique_ptr<eGLImage> eglImageBayerIn_;\n>   \tstd::unique_ptr<eGLImage> eglImagePingPong_[2];\n> -\tstd::unique_ptr<eGLImage> eglImageRGBAOut_;\n> +\tstd::unordered_map<FrameBuffer *, std::unique_ptr<eGLImage>> eglImageRGBAOut_;\n\nThis has to have a hard-limit on the number of entries because technically\neach request may use a different set of buffers, so the size must be limited.\n\nThen it must also handle situation correctly where a `FrameBuffer` is destroyed after request\ncompletion, and a new one is created for a later request that happens to have the same address.\n\nI think something like `V4L2BufferCache` is needed if you want to do caching.\n\n\nRegards,\nBarnabás Pőcze\n\n>   \n>   \tstd::unique_ptr<SwStatsCpu> stats_;\n>   \teGL egl_;","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 2E8FAC3261\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 18 Jun 2026 12:50:11 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CA73662C78;\n\tThu, 18 Jun 2026 14:50:10 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B5C1261754\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Jun 2026 14:50:09 +0200 (CEST)","from [192.168.33.31] (185.182.214.63.nat.pool.zt.hu\n\t[185.182.214.63])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 98DFE3A2;\n\tThu, 18 Jun 2026 14:49:34 +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=\"MWU/I8rW\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1781786974;\n\tbh=DNzN9ovmh60jftAa8Xqqs9Z15dPKDM8L6zrsljWAomI=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=MWU/I8rWxtnwlfRspPSlVb5JxiZCx4RNLuhPVtuZYmVAa795sIhJbANHK1PC6ykQa\n\tYiH54ZQuFqmopUEhjYv1ssWsCiCor9zTSw7S0YCh+ObGefSCsK0PHugHQ9HQCfm8Pm\n\tTqlI1Rte59uR5YyjppjXjsntkwYkjl5tpDjXww4g=","Message-ID":"<0fd60302-896b-4b99-90b4-bde29b83544c@ideasonboard.com>","Date":"Thu, 18 Jun 2026 14:50:05 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH 29/30] libcamera: software_isp: gpu: Cache output\n\tframebuffers, only recreate when necessary","To":"Bryan O'Donoghue <bryan.odonoghue@linaro.org>,\n\tlibcamera-devel@lists.libcamera.org","Cc":"pavel@ucw.cz","References":"<20260618122245.946138-1-bryan.odonoghue@linaro.org>\n\t<20260618122245.946138-30-bryan.odonoghue@linaro.org>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260618122245.946138-30-bryan.odonoghue@linaro.org>","Content-Type":"text/plain; charset=UTF-8; format=flowed","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>"}}]