From patchwork Sun Aug 24 00:48:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bryan O'Donoghue X-Patchwork-Id: 24183 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 67048BEFBE for ; Sun, 24 Aug 2025 00:48:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E60C0692E7; Sun, 24 Aug 2025 02:48:38 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="LNdQHoTC"; dkim-atps=neutral Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E0BDE613BE for ; Sun, 24 Aug 2025 02:48:36 +0200 (CEST) Received: by mail-wr1-x431.google.com with SMTP id ffacd0b85a97d-3c79f0a606fso432792f8f.0 for ; Sat, 23 Aug 2025 17:48:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1755996516; x=1756601316; darn=lists.libcamera.org; h=cc:to:content-transfer-encoding:mime-version:message-id:date :subject:from:from:to:cc:subject:date:message-id:reply-to; bh=xrAbCCxjkzyBtd08rCDydNa0a+sWY+zQ+miNMuHwzUM=; b=LNdQHoTCVIxU49w0m8sc8sw5llaW8Pdm76irfBVTZfw78T5AypQwWk0rPP5HQTp+sq ELzUlWQ0PgdxIRboLkubOZi9Cn8oP1x193zY1MDlgxPsS4pC9p84Tv+o6I4CDbGbIwaV XEipYynhfjdNaC/m89lgdNXHupRPMdfEwD3bUny0AiX6BHh2+w17yR/+Xmq8l2dttxnB sm9gKs4S8hDyNYt8m3ndKTgt463ri02JLpZtn50eFk0LaFeQJmbO27fQowi8TrcsmImN vj4D+wkqudIiUuNOwEID9iMUV8BUIzvKRUsVNx9jpTaloo6d3ohWBU4ADVGrVDWR5kVA uQLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755996516; x=1756601316; h=cc:to:content-transfer-encoding:mime-version:message-id:date :subject:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=xrAbCCxjkzyBtd08rCDydNa0a+sWY+zQ+miNMuHwzUM=; b=PGahws8QiUIVXCz32fo7PZyGH7Urf/3GdZioJfZ+L0PM4NOcFB8qQmrVGpZALXetIl YZX5Ef0KZNR3w+vYILI2kukEfyAFAQnmCx0uX/gPf8d+6upMCwSVMVsp5VYudBuMYhQ8 7+LZvLh+zQ8ADcGjWXgCo6TtzZXhIOezBwaZtxorA4WLJKCIttRdHnLvFYvJTlcE9zEt dLgxox5gRVO9XQzucNrd+BaOkenHlPlVVWm8DfmAU7YUrmsTFLPiwbgOkPYgzgZxudwE sl9fFHcwUHXYnKaPlHNRUwIpsQAWJuQACeI3cUbyI9hmcueETK3ejNiKf2bMh30nFdrN x4tg== X-Gm-Message-State: AOJu0YyoF0Y4kNgUChcciNVyxUXRhKKeujymPdOcFBpv1RyG80468wJn 8fUUQGSYfnkcGvJpUAc88FUK+sAkNsLvjKALzga7m5KjAsic6wJNXWf95jZ3Y7f63oY= X-Gm-Gg: ASbGncv0/As3I/KUvOaQlw2T8DeD1JmhyWsJscpJF3FL+85DpTFJTbxpSX9NI1ip+zy 6Wd2PpcQnvvasgzMPQBcpGnZ/Raj02VCE1wBwBcqiakrFq1NHLmSENeiTtXQKFhOk+tTAqWDVB/ onCJN8BGkw9RRanlI5mNe8pUEUpJzTqtWJAmdVpVD8EUoHUT+KfMeuy6UumZF6JZNOOuwUMXN2v ksoF2kJqp9MGxCGvTHt7LamxGvlINoYGAOZoKMY1TvINDEEwmPDGqwMFi8VLp17qalXdVuJX/5e sdq8c9vKWrPNSw9ioIY84MX5EYDhJ5pSna+kzlOMDF27oKxO0AHrrsodYPUYUQtF/qzBHxZWIey a/BeCUfPVyjMHi2IpS9LlgaIf23KdFpFitGVthdqOJ+8OPyMwM0iCQS+8jE9QKmzPihDadbzWoy FFu0/W4PRDhot6brlho/Dl X-Google-Smtp-Source: AGHT+IEb6zksNQgOweAMLq/w3AHryYeDtVfiJ5mRex6h6HL9biCIDLL1JwgRgAIeDUo+2rJ3YbewXw== X-Received: by 2002:a05:6000:230d:b0:3b9:5002:3b4d with SMTP id ffacd0b85a97d-3c5dbf68962mr4478147f8f.19.1755996516198; Sat, 23 Aug 2025 17:48:36 -0700 (PDT) Received: from [192.168.0.13] (188-141-3-146.dynamic.upc.ie. [188.141.3.146]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b4e1d530esm69347225e9.0.2025.08.23.17.48.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 23 Aug 2025 17:48:35 -0700 (PDT) From: Bryan O'Donoghue Subject: [PATCH v2 00/37] Add GLES 2.0 GPUISP to libcamera Date: Sun, 24 Aug 2025 01:48:12 +0100 Message-Id: <20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org> MIME-Version: 1.0 X-B4-Tracking: v=1; b=H4sIAE1hqmgC/x3MQQrDIBBG4auEWfcHM1EScpXSRYwTO5tUlEpAc vdKl9/ivUZFskqhdWiUpWrRz9nBj4H293ZGgYZuYsPOLDzBW1QDB0ZMXy0JlbEhWOMnPy9htiP 1NmU59Pp/n6/7/gGdM0YYZwAAAA== X-Change-ID: 20250823-b4-v0-5-2-gpuisp-v2-a-d40b3b78d741 To: libcamera-devel@lists.libcamera.org Cc: Bryan O'Donoghue , Hans de Goede , Kieran Bingham , Milan Zamazal X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=11986; i=bryan.odonoghue@linaro.org; h=from:subject:message-id; bh=WMfET/qspFAi8zv6LLfXPrETVmV+9nz5bgrl+xNz/rk=; b=owEBbQKS/ZANAwAKASJxO7Ohjcg6AcsmYgBoqmFcyhld1xKudBhrRvf7m65sRCATcF/gr8ZeB J3GkkyrApyJAjMEAAEKAB0WIQTmk/sqq6Nt4Rerb7QicTuzoY3IOgUCaKphXAAKCRAicTuzoY3I Ol1HD/0S4qlI+5Ece6QMGf/vNfVqqhoW8RTqIw44ROKHbnDnannbtUkb2OrQ4fZfEwPia61hyer LfH6Q97SRaxO2ghFmSwcg0Vl4BALGfKAxDvQN+/WsT2YcP+FmpADW+hXWEl73RRHkc3/X65GA+f TfjARpDYS4zyIO7SPf9Wg6yVP3Et1zIdlZF5uEVskCcae+g0nG0Ww3hMmTDSK/yhfihKvLfbf6x 7aZhIakk9eEkwsRrPa1EC4Dnb5lUIeNaSLURsdQIKnB0peBWSYvDy1idMrQbIf3mWxl9sMSnLVw 9NeKTewwMNSa1eNKsK3fIx8kvNicJCqGBthZRj+FojCDlopvBwDMVtl2A2EJKMgx7pJWMsLIEXw 8YZxt/I5v1wMQbJpMwj8vpBf5iNyRHS6rfe7KFkkdYToJPUHoDe1ccThL2h0vPnDUQ3E7aLoahG OQiRju6jgbEmRMWTvOdF+tEUcaKatSyFcJhlum7xpZGkn+QMJpfmj+uVBaM01q/FMfz76NsnDX0 N2ZSWqcHhMNOYXFkqVra37umxc7/xR/IaGH9kc78PWnpzDq4yPFy7FMGqJuAVzQllBJCUDX9mnt IDt3CDLbvpRDFLhEqfUyMvcVPnUxnHfBm4B2XHGNODrfZBRnWB52JGFFPj3tEo48fax8z2Um9/r zKCGxo22m7z/Huw== X-Developer-Key: i=bryan.odonoghue@linaro.org; a=openpgp; fpr=E693FB2AABA36DE117AB6FB422713BB3A18DC83A 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" v2: This version 2 is an incomplete update with-respect-to previous comment feedback, which ordinarily I would not publish however, given OSSEU is starting on Monday and we have talk about this topic, in addition to some pretty good progress in the interregnum I thought a v2 would be appropriate. - V2 drops use of GBM surface in favour of generating a framebuffer from the dma-buf handle, called render-to-texture. The conversion from GBM surface + memcpy() including the associated cache invalidate has a dramatic effect on GPUISP performance. Some rough stats for a Qualcomm sm8250 "kona" device with an imx517 sensor @ 4048 x 3040 ABRG8888 - debug builds CPUISP + CCM: 2 FPS CPU usage > 100% single core pulls about 9 watts GPUISP v1 + CCM: 14 FPS - power not measured GPUISP v2 + CCM: 30 FPS - sensor linerate - CPU usage ~ 70 % pulling 8 Watts. Milan Zamal has reported a TI AM69 + imx219 - unknown resolution CPUISP 4 FPS GPUISP v2 - 2 or 3 FPS GPUISP v2 - 15 FPS == sensor linerate In other words for these boards we can hit linerate with GPUISP + 3A + CCM. - Drop GBM surface rendering - Drop swapbuffers - Use eglCreateImageKHR to directly render into the output dma-buf buffer eglCreateImageKHR lets you specify the FOURCC of the texture which means we can create the texture in the uncompressed target output pixel format we want. - Fix stride calculation to 256 bytes Laurent and Maxime explained to me about GPU stride alignments being tribal wisdom and that 256 bytes is a good cross-platform value. This helped to get the render-to-texture command right. - A synchronous blocking wait is used to ensure GPU operations have completed. Laurent wants this to be made async. At the moment its not clear to me the eglWaitSyncKHR is really required and in any case doesn't seem to have any performance impact. But this part is still TBD - I've included the sync wait for simplicity and safety. - A Debayer::stop() method has been introduced to ensure we call eglDestroySyncKHR when the eGL context is valid, as opposed to in the callchain of destructors triggering eGL::~eGL(); - stats move constructor call chain dropped - Branabas - Incorporates Milan's area-of-interest constraint for Bayer stats i.e. squashes his v3 update into debayer_egl.cpp directly - Moves ALIGN_TO into a common area to facilitate its reuse in egl.cpp - Rebases on 0.5.2 - There are a number of known checks failing on the CI loop right now Link to v1: https://lists.libcamera.org/pipermail/libcamera-devel/2025-June/050692.html v1: This series introduces a GLES 2.0 GPU ISP to libcamera. We have had extensive discussions, meetings and collaborative discussions about this topic over the last year or so. As an overview we want to start to move as much processing of software_isp into the GPU as possible. This is especially advantageous when we are talking about processing a framebuffer's worth of pixels as quickly as possible. The decision to use GLES 2.0 instead of say Vulcan stems from a desire to support as much in the way of older hardware as possible and the fact we already have upstream GLES 2.0 fragment shaders to do debayer. Generally the approach is - Move the fragment shaders out of qcam and into a common location - Update the existing SoftwareISP Debayer/DebayerCPU pair to facilitate addition of a new class DebayerEGL. - Introduce that class - Then do progressive change of the shaders and DebayerEGL class to make the modifications as transparent as possible in the git log. - Reuse as much of the SoftIPA data-structures and logic as possible. - Consume the data from SoftIPA in the Debayer Shaders so that CPUISP and GPUISP give similar - hopefully the same results but with GPUISP going faster. In order to get untiled and uncompressed pixel data out of the GPU framebuffer we need to tell the GPU how to store the data it is writing to that framebuffer. GPUs can store their framebuffer data in tiled or even compressed formats which is why the naive approach of running your fragment shader and then using glReadPixels(GL_RGBA); will be horrendously slow as glReadPixels must convert from the internal GPU format to the requested output format - an operation that for me takes ~ 10 milliseconds per frame. Instead we get the GPU to store its data as ARGB8888 swap buffers and memcpy() from the swapped buffer to our output frame. Right now this series supports 32 bit output formats only. The memcpy() also entails flushing the cache of the target buffer as per the terms of the dma-buf software contract. This leads us onto the main outstanding TODOs - 24 bit GBM buffer support leading - 24 bit output framebuffer support - Surfaceless GBM and eGL context with no swapbuffer - Render to texture If we render directly to a buffer provided to the GPU the output buffer we will not need to memcpy() to the output buffer nor will we need to invalidate the output buffer cache. - eglCreateImageKHR for the texture upload. This list is of the colour "make it go faster" not "make it work" which is why we are moving to start to submit a v1 for discussion in the full realisation it will have to go through several cycles of review giving us the opportunity to fix: - Doxygen is missing for new classes and methods - Some of the pipelines don't complete in gitlab - 24 bit output seems doable before merge - Render to texture perhaps even too For me on my Qualcomm hardware GPUISP works very well I get 30fps in qcam with about 75% CPU usage versus > 100% - cam goes faster which to me implies a good bit of time is being consumed in qcam itself. The series starts out with fixes and updates from Hans and finishes it out with shader modifications from Milan both of whom along with Kieran, Laurent and Maxime I'd like to thank for being some helpful and patient. Signed-off-by: Bryan O'Donoghue --- Bryan O'Donoghue (28): libcamera: MappedFrameBuffer: Add MappedFrameBuffer::getPlaneFD() libcamera: software_isp: Move useful items from DebayerCpu to Debayer base class libcamera: software_isp: Move Bayer params init from DebayerCpu to Debayer libcamera: software_isp: Move param select code to Debayer base class libcamera: software_isp: Move DMA Sync code to Debayer base class libcamera: software_isp: Move isStandardBayerOrder to base class libcamera: software_isp: Start the ISP thread in configure libcamera: software_isp: Move configure to worker thread libcamera: software_isp: debayer: Make the debayer_ object of type class Debayer not DebayerCpu libcamera: software_isp: debayer: Extend DebayerParams struct to hold a copy of per-frame CCM values libcamera: software_isp: debayer: Introduce a stop() callback to the debayer object libcamera: shaders: Move GL shader programs to src/libcamera/assets/shader utils: gen-shader-headers: Add a utility to generate headers from shaders meson: Automatically generate glsl_shaders.h from specified shader programs libcamera: software_isp: ccm: Populate CCM table to Debayer params structure libcamera: software_isp: lut: Make gain corrected CCM in lut.cpp available in debayer params libcamera: software_isp: gbm: Add in a GBM helper class for GPU surface access libcamera: utils: Move ALIGN_TO from camera_metadata.c to utils.h libcamera: software_isp: egl: Introduce an eGL base helper class libcamera: software_isp: debayer_egl: Add an eGL debayer class libcamera: software_isp: debayer_egl: Make DebayerEGL an environment option libcamera: shaders: Use highp not mediump for float precision libcamera: shaders: Extend debayer shaders to apply RGB gain values on output libcamera: software_isp: Switch on uncalibrated CCM to validate eGLDebayer libcamera: software_isp: Make isStandardBayerOrder static libcamera: software_isp: debayer_cpu: Make getInputConfig and getOutputConfig static libcamera: shaders: Extend bayer shaders to support swapping R and B on output libcamera: software_isp: Add a gpuisp todo list Hans de Goede (5): libcamera: swstats_cpu: Update statsProcessFn() / processLine0() documentation libcamera: swstats_cpu: Drop patternSize_ documentation libcamera: swstats_cpu: Move header to libcamera/internal/software_isp libcamera: software_isp: Move benchmark code to its own class libcamera: swstats_cpu: Add processFrame() method Milan Zamazal (4): libcamera: shaders: Fix neighbouring positions in 8-bit debayering libcamera: software_isp: GPU support for unpacked 10/12-bit formats libcamera: shaders: Rename bayer_8 to bayer_unpacked libcamera: software_isp: Reduce statistics image area include/libcamera/base/utils.h | 3 + include/libcamera/internal/egl.h | 133 +++++ include/libcamera/internal/gbm.h | 39 ++ include/libcamera/internal/mapped_framebuffer.h | 4 + include/libcamera/internal/meson.build | 11 + .../libcamera/internal/shaders}/RGB.frag | 2 +- .../libcamera/internal/shaders}/YUV_2_planes.frag | 2 +- .../libcamera/internal/shaders}/YUV_3_planes.frag | 2 +- .../libcamera/internal/shaders}/YUV_packed.frag | 2 +- .../internal/shaders}/bayer_1x_packed.frag | 62 +- .../libcamera/internal/shaders/bayer_unpacked.frag | 78 ++- .../libcamera/internal/shaders/bayer_unpacked.vert | 8 +- .../libcamera/internal/shaders}/identity.vert | 0 include/libcamera/internal/shaders/meson.build | 10 + .../libcamera/internal/software_isp/benchmark.h | 36 ++ .../internal/software_isp/debayer_params.h | 7 + .../libcamera/internal/software_isp/meson.build | 2 + .../libcamera/internal/software_isp/software_isp.h | 5 +- .../libcamera/internal}/software_isp/swstats_cpu.h | 12 + src/android/metadata/camera_metadata.c | 4 +- src/apps/qcam/assets/shader/shaders.qrc | 16 +- src/apps/qcam/viewfinder_gl.cpp | 70 +-- src/ipa/simple/algorithms/ccm.cpp | 4 +- src/ipa/simple/algorithms/lut.cpp | 1 + src/ipa/simple/data/uncalibrated.yaml | 12 +- src/libcamera/egl.cpp | 408 +++++++++++++ src/libcamera/gbm.cpp | 61 ++ src/libcamera/mapped_framebuffer.cpp | 10 + src/libcamera/meson.build | 34 ++ src/libcamera/software_isp/benchmark.cpp | 93 +++ src/libcamera/software_isp/debayer.cpp | 61 ++ src/libcamera/software_isp/debayer.h | 42 +- src/libcamera/software_isp/debayer_cpu.cpp | 88 +-- src/libcamera/software_isp/debayer_cpu.h | 44 +- src/libcamera/software_isp/debayer_egl.cpp | 628 +++++++++++++++++++++ src/libcamera/software_isp/debayer_egl.h | 171 ++++++ src/libcamera/software_isp/gpuisp-todo.txt | 61 ++ src/libcamera/software_isp/meson.build | 9 + src/libcamera/software_isp/software_isp.cpp | 40 +- src/libcamera/software_isp/swstats_cpu.cpp | 89 ++- utils/gen-shader-header.py | 38 ++ utils/gen-shader-headers.sh | 44 ++ utils/meson.build | 2 + 43 files changed, 2236 insertions(+), 212 deletions(-) --- base-commit: 1bd66f54a6bc928f99e321630f43d200df4d3579 change-id: 20250823-b4-v0-5-2-gpuisp-v2-a-d40b3b78d741 Best regards,