temp/libcamera: upgrade to 0.7.2

See
https://gitlab.freedesktop.org/camera/libcamera/-/releases/v0.7.2

The release notably includes fixes that allow us to start shipping color
correction matrices in tuning files. This commit includes the current
tuning iterations for the imx363 (used e.g. as Pixel 3a rear camera) and
the s5kjn1 (used on e.g. as FairPhone 5 front camera). The later is also
used for the other correspondig cameras on the mentioned devices, as
they improve the quality over the default. This is of course planed to
change in the future.

The GPU-ISP also received major performance improvements, in particular
if the dmabuf direct import path can be used. If that's not the case
some INFO logs are printed, giving hints what needs to be improved in
the V4L2 or GPU drivers.

Finally we can drop all previously backported patches, only keeping two
PinePhone (OG) specific ones around for now. These should probably be
dropped in future releases, giving the poor performance and limited GPU
capabilities (GLES 2.0 only) on that device.

Part-of: <https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/8991>
This commit is contained in:
Robert Mader 2026-07-10 12:41:06 +02:00 committed by The Friendly Meow (merge) Bot
parent 8433274c9a
commit fd540e8017
No known key found for this signature in database
18 changed files with 135 additions and 1145 deletions

View file

@ -1,44 +0,0 @@
From 5a53056f12094b5077453e1393640b979fc40fde Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Tue, 26 May 2026 10:06:38 +0200
Subject: [PATCH 01/13] debayer_egl: Include stats computation into benchmark
The following commit will allow debayering on the GPU and stats
computation on the CPU to happen in parallel, requiring this change in
order to keep the benchmark meaningful.
Do the change first in order to make before/after comparisons simpler.
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit 1556025bae58b9e02625587728af349b987a14fa)
---
src/libcamera/software_isp/debayer_egl.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 8f0c229fd..565aee9f1 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -547,14 +547,14 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
goto error;
}
- bench_.finishFrame();
-
metadata.planes()[0].bytesused = output->planes()[0].length;
/* Calculate stats for the whole frame */
stats_->processFrame(frame, 0, input);
dmaSyncers.clear();
+ bench_.finishFrame();
+
outputBufferReady.emit(output);
inputBufferReady.emit(input);
--
2.54.0

View file

@ -1,7 +1,7 @@
From afbbb6c818ed330a2239c0ebb78d63ffa775c341 Mon Sep 17 00:00:00 2001
From be67f67c4ac44b571d1740c1da10669fe6a5c75b Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Wed, 1 May 2024 18:12:02 +0200
Subject: [PATCH 12/13] libcamera: simple: Enable softISP for the Pinephone
Subject: [PATCH 1/2] libcamera: simple: Enable softISP for the Pinephone
In theory the PP should be able to use the actual HW ISP, however in
practice this does not work well yet - especially as the driver for the
@ -30,5 +30,5 @@ index e26f438d9..24538649c 100644
bool isRaw(const StreamConfiguration &cfg)
--
2.54.0
2.55.0

View file

@ -1,147 +0,0 @@
From e2dcad90def08cd7f2ba34018ce72162ddc957d8 Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Tue, 26 May 2026 10:06:39 +0200
Subject: [PATCH 02/13] debayer_egl: Sync output buffers after processing stats
Instead of waiting for the GPU to finish output buffers *before* computing
stats, do so afterwards. This allows work to happen in parallel on the GPU
and CPU, improving throughput and reducing latency on various devices as
shown below.
On order for this to work well we need to flush all GL commands to the
GPU before doing heavy CPU work - thus add a corresponding function.
Below are some benchmark results. All where done using postmarketOS edge
with updates from 21th May 2026 (Mesa 26.1.1). The mentioned pipelines
where run five times each, with the mean value included here, which should
be quite representive as the variance was rather small. All devices
where using the powersave governor.
Notes:
1. We only expect changes for frames where stats get computed, currently
every fourth frame (see kStatPerNumFrames) - and the improvements indeed
have been observed to increase when computing stats more often.
2. At least the qcom/freedreno devices have been found to be affected by a
performance issue *without* this patch. This issue can be worked
around by calling `glFlush()` directly before `glFinish()` - as done
in v1 of this series - or by running with `GALLIUM_THREAD=0`. The
benchmarks below show the performance gains *with* those workarounds
applied in order to not inflate the impact of this patch. See
https://gitlab.freedesktop.org/mesa/mesa/-/work_items/15516 for more
context.
cam -c /base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a -s width=1920,height=1080 --capture=60
Before: 33596 us/frame
After: 30179 us/frame
cam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@1a -s width=1920,height=1080 --capture=60
Before: 14922 us/frame
After: 14304 us/frame
cam -c /base/soc@0/cci@ac4b000/i2c-bus@1/camera@10 -s width=1920,height=1080 --capture=60
Before: 26106 us/frame
After: 23312 us/frame
cam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@29 -s width=1920,height=1080 --capture=60
Before: 15897 us/frame
After: 14791 us/frame
cam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@10 -s width=1920,height=1080 --capture=60
Before: 25721 us/frame
After: 23625 us/frame
cam -c /base/soc@0/cci@ac4a000/i2c-bus@0/camera@10 -s width=1920,height=1080 --capture=60
Before: 34124 us/frame
After: 29471 us/frame
cam -c /base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a -s width=1920,height=1080 --capture=60
Before: 23707 us/frame
After: 21890 us/frame
cam -c /base/soc@0/bus@30800000/i2c@30a40000/camera@20 -s width=1280,height=720 --capture=60
Before: 91649 us/frame
After: 83233 us/frame
cam -c /base/soc@0/bus@30800000/i2c@30a50000/camera@2d -s width=1280,height=720 --capture=60
Before: 76956 us/frame
After: 69569 us/frame
cam -c /base/i2c-csi/front-camera@3c -s width=1280,height=720 --capture=60
Before: 188500 us/frame
After: 173764 us/frame
cam -c /base/i2c-csi/rear-camera@4c -s width=1280,height=720 --capture=60
Before: 190222 us/frame
After: 177251 us/frame
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit 2bace926b0f4854bc3508a9805d53e47a273e789)
---
include/libcamera/internal/egl.h | 1 +
src/libcamera/egl.cpp | 13 +++++++++++++
src/libcamera/software_isp/debayer_egl.cpp | 3 ++-
3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h
index 0ad2320b1..0ec8ea6ec 100644
--- a/include/libcamera/internal/egl.h
+++ b/include/libcamera/internal/egl.h
@@ -119,6 +119,7 @@ public:
void useProgram(GLuint programId);
void deleteProgram(GLuint programId);
void syncOutput();
+ void flushOutput();
private:
LIBCAMERA_DISABLE_COPY_AND_MOVE(eGL)
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index f65929470..0ababa361 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -98,6 +98,19 @@ void eGL::syncOutput()
glFinish();
}
+/**
+ * \brief Flush the rendering pipeline
+ *
+ * Calls glFlush().
+ *
+ */
+void eGL::flushOutput()
+{
+ ASSERT(tid_ == Thread::currentId());
+
+ glFlush();
+}
+
/**
* \brief Create a DMA-BUF backed 2D texture
* \param[in,out] eglImage EGL image to associate with the DMA-BUF
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 565aee9f1..dd6b64be2 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -516,7 +516,7 @@ int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParam
LOG(eGL, Error) << "Drawing scene fail " << err;
return -ENODEV;
} else {
- egl_.syncOutput();
+ egl_.flushOutput();
}
return 0;
@@ -553,6 +553,7 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
stats_->processFrame(frame, 0, input);
dmaSyncers.clear();
+ egl_.syncOutput();
bench_.finishFrame();
outputBufferReady.emit(output);
--
2.54.0

View file

@ -1,8 +1,7 @@
From c7efef9c313386d530ab6422c0677953f36a2478 Mon Sep 17 00:00:00 2001
From dc471142932b1f2b0bf596c3ae83dba8bd4b4021 Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Mon, 6 May 2024 21:21:57 +0200
Subject: [PATCH 13/13] libcamera: simple: Skip hwISP formats if swISP is
active
Subject: [PATCH 2/2] libcamera: simple: Skip hwISP formats if swISP is active
On devices like the Pinephone libcamera will advertise support for
formats provided by the HW ISP and the SW ISP at the same time. The
@ -31,5 +30,5 @@ index 24538649c..b96b8b529 100644
} else {
config.outputFormats = { pixelFormat };
--
2.54.0
2.55.0

View file

@ -1,122 +0,0 @@
From 7d7f39be4c7583a7f936cd77c7a4f4822f407b06 Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Wed, 27 May 2026 10:15:30 +0200
Subject: [PATCH 03/13] egl: Add GL format parameter to eGLImage constructor
In preparation for the following commits. This requires a minor
reordering in DebayerEGL::start() as the value for the input texture is
only known after initBayerShaders().
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit 6e23162ddcae7fdeb8f41a054dda2e8c19300d98)
---
include/libcamera/internal/egl.h | 6 ++++--
src/libcamera/egl.cpp | 22 +++++++++++++++++++++-
src/libcamera/software_isp/debayer_egl.cpp | 10 +++++-----
3 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h
index 0ec8ea6ec..825240dbb 100644
--- a/include/libcamera/internal/egl.h
+++ b/include/libcamera/internal/egl.h
@@ -51,14 +51,15 @@ class eGLImage
public:
/**
* \brief Construct an eGLImage with explicit stride
+ * \param[in] format Image GL format
* \param[in] width Image width in pixels
* \param[in] height Image height in pixels
* \param[in] stride Row stride in bytes
* \param[in] texture_unit OpenGL texture unit
* \param[in] texture_unit_uniform_id Shader uniform ID
*/
- eGLImage(uint32_t width, uint32_t height, uint32_t stride, GLenum texture_unit, uint32_t texture_unit_uniform_id)
- : width_(width), height_(height), stride_(stride),
+ eGLImage(GLint format, uint32_t width, uint32_t height, uint32_t stride, GLenum texture_unit, uint32_t texture_unit_uniform_id)
+ : format_(format), width_(width), height_(height), stride_(stride),
framesize_(stride * height),
texture_unit_uniform_id_(texture_unit_uniform_id),
texture_unit_(texture_unit)
@@ -79,6 +80,7 @@ public:
glDeleteTextures(1, &texture_);
}
+ GLint format_; /**< Image GL format */
uint32_t width_; /**< Image width in pixels */
uint32_t height_; /**< Image height in pixels */
uint32_t stride_; /**< Row stride in bytes */
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 0ababa361..882bfa656 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -21,6 +21,8 @@
#include <libdrm/drm_fourcc.h>
+#include <GLES3/gl32.h>
+
namespace libcamera {
LOG_DEFINE_CATEGORY(eGL)
@@ -125,13 +127,31 @@ void eGL::flushOutput()
*/
int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
{
+ EGLint drm_format;
+
ASSERT(tid_ == Thread::currentId());
+ switch (eglImage.format_) {
+ case GL_RED:
+ case GL_LUMINANCE:
+ drm_format = DRM_FORMAT_R8;
+ break;
+ case GL_RG:
+ drm_format = DRM_FORMAT_RG88;
+ break;
+ case GL_RGBA:
+ drm_format = DRM_FORMAT_ARGB8888;
+ break;
+ default:
+ LOG(eGL, Error) << "unhandled GL format";
+ return -ENODEV;
+ }
+
// clang-format off
EGLint image_attrs[] = {
EGL_WIDTH, (EGLint)eglImage.width_,
EGL_HEIGHT, (EGLint)eglImage.height_,
- EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
+ EGL_LINUX_DRM_FOURCC_EXT, drm_format,
EGL_DMA_BUF_PLANE0_FD_EXT, fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT, (EGLint)eglImage.stride_,
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index dd6b64be2..741d9d6f1 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -578,14 +578,14 @@ int DebayerEGL::start()
LOG(Debayer, Debug) << "Available fragment shader texture units " << maxTextureImageUnits;
+ if (initBayerShaders(inputPixelFormat_, outputPixelFormat_))
+ return -EINVAL;
+
/* Raw bayer input as texture */
- eglImageBayerIn_ = std::make_unique<eGLImage>(width_, height_, inputConfig_.stride, GL_TEXTURE0, 0);
+ eglImageBayerIn_ = std::make_unique<eGLImage>(glFormat_, width_, height_, inputConfig_.stride, GL_TEXTURE0, 0);
/* Texture we will render to */
- eglImageBayerOut_ = std::make_unique<eGLImage>(outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE1, 1);
-
- if (initBayerShaders(inputPixelFormat_, outputPixelFormat_))
- return -EINVAL;
+ eglImageBayerOut_ = std::make_unique<eGLImage>(GL_RGBA, outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE1, 1);
return 0;
}
--
2.54.0

View file

@ -1,92 +0,0 @@
From 97baff1439fe171fe80b081a021af71fb7617876 Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Wed, 27 May 2026 10:15:31 +0200
Subject: [PATCH 04/13] egl: Remove some parameters from createTexture2D()
And use the values set in the constructor instead, bringing the
function in line with createInputDMABufTexture2D() and
createOutputDMABufTexture2D().
Adopt the value passed into the constructor accordingly, which
previously was never used.
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit fb312741ed936c69d6a773323a2e76d8e645c077)
---
include/libcamera/internal/egl.h | 2 +-
src/libcamera/egl.cpp | 7 ++-----
src/libcamera/software_isp/debayer_egl.cpp | 4 ++--
3 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h
index 825240dbb..bcf09b475 100644
--- a/include/libcamera/internal/egl.h
+++ b/include/libcamera/internal/egl.h
@@ -105,7 +105,7 @@ public:
int createInputDMABufTexture2D(eGLImage &eglImage, int fd);
int createOutputDMABufTexture2D(eGLImage &eglImage, int fd);
- void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data);
+ void createTexture2D(eGLImage &eglImage, void *data);
void pushEnv(std::vector<std::string> &shaderEnv, const char *str);
void makeCurrent();
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 882bfa656..789ffe2c1 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -241,9 +241,6 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)
/**
* \brief Create a 2D texture from a memory buffer
* \param[in,out] eglImage EGL image to associate with the texture
- * \param[in] format OpenGL internal format (e.g., GL_RGB, GL_RGBA)
- * \param[in] width Texture width in pixels
- * \param[in] height Texture height in pixels
* \param[in] data Pointer to pixel data, or nullptr for uninitialised texture
*
* Creates a 2D texture from a CPU-accessible memory buffer. The texture
@@ -251,7 +248,7 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)
* is useful for uploading static data like lookup tables or uniform color
* matrices to the GPU.
*/
-void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data)
+void eGL::createTexture2D(eGLImage &eglImage, void *data)
{
ASSERT(tid_ == Thread::currentId());
@@ -259,7 +256,7 @@ void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint
glBindTexture(GL_TEXTURE_2D, eglImage.texture_);
// Generate texture, bind, associate image to texture, configure, unbind
- glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
+ glTexImage2D(GL_TEXTURE_2D, 0, eglImage.format_, eglImage.width_, eglImage.height_, 0, eglImage.format_, GL_UNSIGNED_BYTE, data);
// Nearest filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 741d9d6f1..3606ec6eb 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -501,7 +501,7 @@ int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParam
egl_.makeCurrent();
/* Create a standard texture input */
- egl_.createTexture2D(*eglImageBayerIn_, glFormat_, inputConfig_.stride / bytesPerPixel_, height_, in.planes()[0].data());
+ egl_.createTexture2D(*eglImageBayerIn_, in.planes()[0].data());
/* Generate the output render framebuffer as render to texture */
egl_.createOutputDMABufTexture2D(*eglImageBayerOut_, out_fd);
@@ -582,7 +582,7 @@ int DebayerEGL::start()
return -EINVAL;
/* Raw bayer input as texture */
- eglImageBayerIn_ = std::make_unique<eGLImage>(glFormat_, width_, height_, inputConfig_.stride, GL_TEXTURE0, 0);
+ eglImageBayerIn_ = std::make_unique<eGLImage>(glFormat_, inputConfig_.stride / bytesPerPixel_, height_, inputConfig_.stride, GL_TEXTURE0, 0);
/* Texture we will render to */
eglImageBayerOut_ = std::make_unique<eGLImage>(GL_RGBA, outputSize_.width, outputSize_.height, outputConfig_.stride, GL_TEXTURE1, 1);
--
2.54.0

View file

@ -1,48 +0,0 @@
From 3f83705c45cfc34d508030194117207306feb850 Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Wed, 27 May 2026 10:15:32 +0200
Subject: [PATCH 05/13] egl: eGLImage: Add flag to remember dmabuf import fails
In preparation of a following commit where we will start trying dmabuf
import for input buffers.
Also turn down error log in order to avoid flodding logs going
forward.
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit 7b5f651f5200df67f8f0cb4331d051711913de6a)
---
include/libcamera/internal/egl.h | 1 +
src/libcamera/egl.cpp | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h
index bcf09b475..57f90d93f 100644
--- a/include/libcamera/internal/egl.h
+++ b/include/libcamera/internal/egl.h
@@ -90,6 +90,7 @@ public:
GLenum texture_unit_; /**< Texture unit associated with this image eg (GL_TEXTURE0) */
GLuint texture_; /**< OpenGL texture object ID */
GLuint fbo_; /**< OpenGL frame buffer object ID */
+ bool dmabuf_import_failed_ = false; /**< Previous image import failed */
private:
LIBCAMERA_DISABLE_COPY_AND_MOVE(eGLImage)
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 789ffe2c1..7689d7983 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -166,7 +166,8 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
NULL, image_attrs);
if (image == EGL_NO_IMAGE_KHR) {
- LOG(eGL, Error) << "eglCreateImageKHR fail";
+ LOG(eGL, Debug) << "eglCreateImageKHR fail";
+ eglImage.dmabuf_import_failed_ = true;
return -ENODEV;
}
--
2.54.0

View file

@ -1,83 +0,0 @@
From 1e02c409a29c5c32360a4e57e57d995321496a9f Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Wed, 27 May 2026 10:15:33 +0200
Subject: [PATCH 06/13] libcamera: swstats_cpu: Take MappedFrameBuffer in
processFrame()
As the only current user - DebayerEGL::process() - already has the buffer
mapped. Currently this shouldn't impact performance as the kernel should
already avoid remapping the dmabuf - i.e. we implicitly benefit from the
fact that the mentioned function holds its mapping during the runtime of
processFrame(). In a following commit DebayerEGL::process() will change
in a way that would make keeping the mapping counter-intuitive. Thus
this change ensures we'll not accidentally start mapping the buffer
twice per frame.
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit a34ee2274e0ea66757b012e104520405b915e058)
---
include/libcamera/internal/software_isp/swstats_cpu.h | 2 +-
src/libcamera/software_isp/debayer_egl.cpp | 2 +-
src/libcamera/software_isp/swstats_cpu.cpp | 11 ++---------
3 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h
index 802370bdb..3faa040b8 100644
--- a/include/libcamera/internal/software_isp/swstats_cpu.h
+++ b/include/libcamera/internal/software_isp/swstats_cpu.h
@@ -56,7 +56,7 @@ public:
void setWindow(const Rectangle &window);
void startFrame(uint32_t frame);
void finishFrame(uint32_t frame, uint32_t bufferId);
- void processFrame(uint32_t frame, uint32_t bufferId, FrameBuffer *input);
+ void processFrame(uint32_t frame, uint32_t bufferId, MappedFrameBuffer &input);
void processLine0(uint32_t frame, unsigned int y, const uint8_t *src[], unsigned int statsBufferIndex = 0)
{
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 3606ec6eb..067333c03 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -550,7 +550,7 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
metadata.planes()[0].bytesused = output->planes()[0].length;
/* Calculate stats for the whole frame */
- stats_->processFrame(frame, 0, input);
+ stats_->processFrame(frame, 0, in);
dmaSyncers.clear();
egl_.syncOutput();
diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp
index 5366e019f..60fcebc40 100644
--- a/src/libcamera/software_isp/swstats_cpu.cpp
+++ b/src/libcamera/software_isp/swstats_cpu.cpp
@@ -537,7 +537,7 @@ void SwStatsCpu::processBayerFrame2(MappedFrameBuffer &in)
*
* This may only be called after a successful setWindow() call.
*/
-void SwStatsCpu::processFrame(uint32_t frame, uint32_t bufferId, FrameBuffer *input)
+void SwStatsCpu::processFrame(uint32_t frame, uint32_t bufferId, MappedFrameBuffer &input)
{
if (frame % kStatPerNumFrames) {
finishFrame(frame, bufferId);
@@ -546,14 +546,7 @@ void SwStatsCpu::processFrame(uint32_t frame, uint32_t bufferId, FrameBuffer *in
bench_.startFrame();
startFrame(frame);
-
- MappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read);
- if (!in.isValid()) {
- LOG(SwStatsCpu, Error) << "mmap-ing buffer(s) failed";
- return;
- }
-
- (this->*processFrame_)(in);
+ (this->*processFrame_)(input);
finishFrame(frame, bufferId);
bench_.finishFrame();
}
--
2.54.0

View file

@ -1,210 +0,0 @@
From 7f354e1d4fa942a7f79f1d34c0b8b2bc86a4c1c5 Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Wed, 27 May 2026 10:15:34 +0200
Subject: [PATCH 07/13] debayer_egl: Implement dmabuf import for input buffers
In many cases we can import the GPU-ISP input buffers, dmabufs from v4l2,
directly into EGL instead of mapping and uploading - i.e. copying - them.
Doing so can have positive effects in multiple areas, including reducing
memory bandwidth and CPU usage, as well as avoiding expensive dmabuf syncs
and syscalls.
The main reason direct imports may not work are the more demanding stride
alignment requirements many GPUs have - often 128 or 256 bytes - compared
to ISPs - apparently often closer to 32 bytes.
Thus we first try to import buffers directly and - if that fails - fall back
to the previous upload path. Failing imports should come at low cost as
drivers know the limitations and can bail out early, without causing
additional IO or context switches.
In the future we might be able to request buffers with a matching stride
from v4l2 drivers in many cases, making direct import the norm instead
of a hit-or-miss. An optional kernel API for that exists, but doesn't
seem to be implemented by any driver tested so far.
Note that passing around MappedFrameBuffer and DmaSyncer variables ensures
we don't do unnecessary mappings and dmabuf syncs.
Below are some benchmark results. All where done using postmarketOS edge
with updates from 21th May 2026 (Mesa 26.1.1). The mentioned pipelines
where run five times each, with the mean value included here, which should
be quite representive as the variance was rather small. All devices
where using the powersave governor.
- FairPhone 5
-- Back camera
cam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@29 -s width=1920,height=1080 --capture=60
Before: 14027 us/frame
After: 12122 us/frame
- OnePlus 6
-- Back camera (imx519)
cam -c /base/soc@0/cci@ac4a000/i2c-bus@0/camera@10 -s width=1920,height=1080 --capture=60
Before: 30091 us/frame
After: 19878 us/frame
- Librem 5
-- Back camera
cam -c /base/soc@0/bus@30800000/i2c@30a50000/camera@2d -s width=1280,height=720 --capture=60
Before: 69092 us/frame
After: 41250 us/frame
- PinePhone
-- Front Camera
cam -c /base/i2c-csi/front-camera@3c -s width=1280,height=720 --capture=60
Before: 173769 us/frame
After: 143274 us/frame
-- Back camera
cam -c /base/i2c-csi/rear-camera@4c -s width=1280,height=720 --capture=60
Before: 174833 us/frame
After: 144476 us/frame
There is one case where performance regresses:
- Pixel 3a
-- Back camera
cam -c /base/soc@0/cci@ac4a000/i2c-bus@1/camera@1a -s width=1920,height=1080 --capture=60
Before: 14257 us/frame
After: 15161 us/frame
To my knowledge this is likely caused by bad sampling performance from
linear buffers. IMO this is a driver issue - if a copy to tiled format
makes sampling faster, drivers should do so implicitly (like e.g. v3d
already does).
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit 93f0db167a8dfb9bc58cb6bbcf91ef6a23462b16)
---
src/libcamera/software_isp/debayer_egl.cpp | 58 ++++++++++++++++------
src/libcamera/software_isp/debayer_egl.h | 2 +-
2 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 067333c03..e0f6dc6da 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -10,6 +10,7 @@
#include "debayer_egl.h"
#include <cmath>
+#include <assert.h>
#include <stdlib.h>
#include <time.h>
@@ -495,16 +496,34 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)
return;
}
-int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams &params)
+int DebayerEGL::debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams &params, std::optional<MappedFrameBuffer> *inMapped, std::optional<DmaSyncer> *inDmaSyncer)
{
+ bool dmabuf_import_succeeded = false;
+
/* eGL context switch */
egl_.makeCurrent();
- /* Create a standard texture input */
- egl_.createTexture2D(*eglImageBayerIn_, in.planes()[0].data());
+ /* Try to create texture for input buffer via dmabuf import */
+ if (!eglImageBayerIn_->dmabuf_import_failed_) {
+ if (egl_.createInputDMABufTexture2D(*eglImageBayerIn_, input->planes()[0].fd.get()) == 0)
+ dmabuf_import_succeeded = true;
+ else
+ LOG(Debayer, Info) << "Importing input buffer with DMABuf import failed, falling back to upload";
+ }
+
+ /* Otherwise create texture for input buffer via upload from CPU */
+ if (!dmabuf_import_succeeded) {
+ inDmaSyncer->emplace(input->planes()[0].fd, DmaSyncer::SyncType::Read);
+ inMapped->emplace(input, MappedFrameBuffer::MapFlag::Read);
+ if (!inMapped->value().isValid()) {
+ LOG(Debayer, Error) << "mmap-ing buffer(s) failed";
+ return -ENODEV;
+ }
+ egl_.createTexture2D(*eglImageBayerIn_, inMapped->value().planes()[0].data());
+ }
/* Generate the output render framebuffer as render to texture */
- egl_.createOutputDMABufTexture2D(*eglImageBayerOut_, out_fd);
+ egl_.createOutputDMABufTexture2D(*eglImageBayerOut_, output->planes()[0].fd.get());
setShaderVariableValues(params);
glViewport(0, 0, width_, height_);
@@ -526,23 +545,16 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
{
bench_.startFrame();
- std::vector<DmaSyncer> dmaSyncers;
-
- dmaSyncBegin(dmaSyncers, input, nullptr);
-
/* Copy metadata from the input buffer */
FrameMetadata &metadata = output->_d()->metadata();
metadata.status = input->metadata().status;
metadata.sequence = input->metadata().sequence;
metadata.timestamp = input->metadata().timestamp;
- MappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read);
- if (!in.isValid()) {
- LOG(Debayer, Error) << "mmap-ing buffer(s) failed";
- goto error;
- }
+ std::optional<MappedFrameBuffer> inMapped;
+ std::optional<DmaSyncer> inDmaSyncer;
- if (debayerGPU(in, output->planes()[0].fd.get(), params)) {
+ if (debayerGPU(input, output, params, &inMapped, &inDmaSyncer)) {
LOG(Debayer, Error) << "debayerGPU failed";
goto error;
}
@@ -550,8 +562,22 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
metadata.planes()[0].bytesused = output->planes()[0].length;
/* Calculate stats for the whole frame */
- stats_->processFrame(frame, 0, in);
- dmaSyncers.clear();
+ if (frame % SwStatsCpu::kStatPerNumFrames) {
+ stats_->finishFrame(frame, 0);
+ } else {
+ if (!inMapped) {
+ /*
+ * The buffer was directly imported into EGL and thus
+ * not mapped for texture upload. Do it now for the
+ * CPU-based stats calculation.
+ */
+ assert(!inDmaSyncer);
+ inDmaSyncer.emplace(input->planes()[0].fd, DmaSyncer::SyncType::Read);
+ inMapped.emplace(input, MappedFrameBuffer::MapFlag::Read);
+ }
+ stats_->processFrame(frame, 0, inMapped.value());
+ }
+ inDmaSyncer.reset();
egl_.syncOutput();
bench_.finishFrame();
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
index fcd281f4c..f2a127b0d 100644
--- a/src/libcamera/software_isp/debayer_egl.h
+++ b/src/libcamera/software_isp/debayer_egl.h
@@ -66,7 +66,7 @@ private:
int initBayerShaders(PixelFormat inputFormat, PixelFormat outputFormat);
int getShaderVariableLocations();
void setShaderVariableValues(const DebayerParams &params);
- int debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams &params);
+ int debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams &params, std::optional<MappedFrameBuffer> *mappedInputBuffer, std::optional<DmaSyncer> *inputBufferDmaSyncer);
/* Shader program identifiers */
GLuint vertexShaderId_ = 0;
--
2.54.0

View file

@ -1,54 +0,0 @@
From 4afcb102d3742f3223e35668e86d0845dedddca2 Mon Sep 17 00:00:00 2001
From: Qi Hou <qi.hou@nxp.com>
Date: Tue, 2 Jun 2026 10:26:01 +0900
Subject: [PATCH 08/13] libcamera: software_isp: debayer_egl: Demote
unsupported format log to Info
DebayerEGL::getInputConfig() logs at Error level when it encounters an
unsupported input format. This function is called during format
enumeration from the simple pipeline handler's tryPipeline(), which
iterates over all pixel formats reported by the video capture device,
including non-Bayer formats such as UYVY and YUYV. The caller already
handles the failure gracefully by checking the return value. Similarly,
DebayerEGL::getOutputConfig() logs at Error level for unsupported
output formats, but is called from strideAndFrameSize() which also
handles failures via the return value.
Demote both log messages from Error to Info for consistency with
DebayerCpu, which uses Info level in getInputConfig() and
getOutputConfig() for the same situation.
Signed-off-by: Qi Hou <qi.hou@nxp.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit 2985ca6ac024ff89a077f088de49f7a69ab40d37)
---
src/libcamera/software_isp/debayer_egl.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index e0f6dc6da..af21ede45 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -74,7 +74,7 @@ int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
return 0;
}
- LOG(Debayer, Error)
+ LOG(Debayer, Info)
<< "Unsupported input format " << inputFormat;
return -EINVAL;
@@ -88,7 +88,7 @@ int DebayerEGL::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &c
return 0;
}
- LOG(Debayer, Error)
+ LOG(Debayer, Info)
<< "Unsupported output format " << outputFormat;
return -EINVAL;
--
2.54.0

View file

@ -1,196 +0,0 @@
From 6fee511f290fd0e950e8064cba99204dc08ed552 Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Wed, 10 Jun 2026 00:53:56 +0200
Subject: [PATCH 09/13] software_isp: debayer_egl: Request input buffer
alignment of 256 bytes
The most common reason dmabuf import with createInputDMABufTexture2D()
fails is that V4L2 drivers use stride alignments that are not sufficient
(too small) for GPUs, preventing the later from directly using input
buffers and forcing us to do relatively expensive uploads (i.e. copies)
of the buffer contents.
Thus let's request a compatible stride alignment from the V4L2 driver,
which may or may not respect the value. From the v4l2_pix_format ->
bytesperline docs:
> Both applications and drivers can set this field to request padding
> bytes at the end of each line. Drivers however may ignore the value
> requested by the application, returning width times bytes per pixel
> or a larger value required by the hardware. That implies applications
> can just set this field to zero to get a reasonable default.
The approach works as follows:
1. Before setting the input format, query into the debayer class for a
preferred stride based on the bayer format and width. For DebayerCpu
this returns 0, i.e. let the V4L2 driver decide, while for DebayerEGL
the "magic" stride alignment of 256 bytes is used, which is known
to work with all known/common GPUs and already used for output
buffers. Right now there doesn't exist any API to query the correct
value - in many cases it is 64 or 128 - however if e.g. a new EGL
extension will provide it in the future, we can easily implement it
in the new function. Alternatively a config value or env var could be
added there if the need arises.
2. Pass the calculated stride to V4L2VideoDevice::setFormat(), which
again sets it as the bytesperline value.
3. The V4L2 driver will update bytesperline with the value it actually
chose to use. Compare the requested and actual strides and log an info
message if the driver did not honor the request, hinting users at what
could be improved about the kernel driver.
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Tested-by: Milan Zamazal <mzamazal@redhat.com> # rpi4+imx219
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit ff5cb4f17b0b9989dd853b4d4320ddb2c59a9c0e)
---
.../libcamera/internal/software_isp/software_isp.h | 1 +
src/libcamera/pipeline/simple/simple.cpp | 12 ++++++++++++
src/libcamera/software_isp/debayer.cpp | 8 ++++++++
src/libcamera/software_isp/debayer.h | 1 +
src/libcamera/software_isp/debayer_egl.cpp | 8 ++++++++
src/libcamera/software_isp/debayer_egl.h | 1 +
src/libcamera/software_isp/software_isp.cpp | 13 +++++++++++++
7 files changed, 44 insertions(+)
diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h
index 585e0d6d9..2a6fbe413 100644
--- a/include/libcamera/internal/software_isp/software_isp.h
+++ b/include/libcamera/internal/software_isp/software_isp.h
@@ -62,6 +62,7 @@ public:
std::tuple<unsigned int, unsigned int>
strideAndFrameSize(const PixelFormat &outputFormat, const Size &size);
+ uint32_t preferredInputStride(const PixelFormat &inputFormat, const Size &size);
int configure(const StreamConfiguration &inputCfg,
const std::vector<std::reference_wrapper<const StreamConfiguration>> &outputCfgs,
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index c6fe12d65..e26f438d9 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -1542,6 +1542,11 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
captureFormat.fourcc = videoFormat;
captureFormat.size = pipeConfig->captureSize;
+ uint32_t requested_bpl = 0;
+ if (data->swIsp_)
+ requested_bpl = data->swIsp_->preferredInputStride(videoFormat.toPixelFormat(), pipeConfig->captureSize);
+ captureFormat.planes[0].bpl = requested_bpl;
+
ret = video->setFormat(&captureFormat);
if (ret)
return ret;
@@ -1561,6 +1566,13 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
return -EINVAL;
}
+ if (requested_bpl && captureFormat.planes[0].bpl != requested_bpl) {
+ LOG(SimplePipeline, Info)
+ << "Input buffer stride ignored by the driver. "
+ << "Requested " << requested_bpl
+ << ", got " << captureFormat.planes[0].bpl;
+ }
+
/* Configure the converter if needed. */
std::vector<std::reference_wrapper<const StreamConfiguration>> outputCfgs;
data->useConversion_ = config->needConversion();
diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp
index 2d7abfb83..56446f55d 100644
--- a/src/libcamera/software_isp/debayer.cpp
+++ b/src/libcamera/software_isp/debayer.cpp
@@ -103,6 +103,14 @@ Debayer::~Debayer()
* there is no valid output config
*/
+/**
+ * \fn uint32_t Debayer::preferredInputStride(const PixelFormat &inputFormat, const Size &size)
+ * Get the preferred input stride in bytes for the given input format and size
+ * \param[in] inputFormat The input format
+ * \param[in] size The input size (width and height in pixels)
+ * \return The preferred input stride in bytes or 0 if there is no preference
+ */
+
/**
* \fn void Debayer::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, DebayerParams params)
* \brief Process the bayer data into the requested format
diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h
index a2a17ec18..28f1b857b 100644
--- a/src/libcamera/software_isp/debayer.h
+++ b/src/libcamera/software_isp/debayer.h
@@ -46,6 +46,7 @@ public:
virtual std::tuple<unsigned int, unsigned int>
strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) = 0;
+ virtual uint32_t preferredInputStride([[maybe_unused]] const PixelFormat &inputFormat, [[maybe_unused]] const Size &size) { return 0; }
virtual void process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams &params) = 0;
virtual int start() { return 0; }
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index af21ede45..264a9315d 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -17,6 +17,7 @@
#include <libcamera/base/utils.h>
#include <libcamera/formats.h>
+#include "libcamera/internal/formats.h"
#include "../glsl_shaders.h"
@@ -373,6 +374,12 @@ DebayerEGL::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size
return std::make_tuple(stride, stride * size.height);
}
+uint32_t DebayerEGL::preferredInputStride(const PixelFormat &inputFormat, const Size &size)
+{
+ const PixelFormatInfo &info = PixelFormatInfo::info(inputFormat);
+ return info.stride(size.width, 0, 256);
+}
+
void DebayerEGL::setShaderVariableValues(const DebayerParams &params)
{
/*
@@ -655,3 +662,4 @@ SizeRange DebayerEGL::sizes(PixelFormat inputFormat, const Size &inputSize)
}
} /* namespace libcamera */
+
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
index f2a127b0d..c7cb009b6 100644
--- a/src/libcamera/software_isp/debayer_egl.h
+++ b/src/libcamera/software_isp/debayer_egl.h
@@ -51,6 +51,7 @@ public:
std::vector<PixelFormat> formats(PixelFormat input) override;
std::tuple<unsigned int, unsigned int> strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) override;
+ uint32_t preferredInputStride(const PixelFormat &inputFormat, const Size &size) override;
void process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, const DebayerParams &params) override;
int start() override;
diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
index d227bd8e3..9c4a59f08 100644
--- a/src/libcamera/software_isp/software_isp.cpp
+++ b/src/libcamera/software_isp/software_isp.cpp
@@ -253,6 +253,19 @@ SoftwareIsp::strideAndFrameSize(const PixelFormat &outputFormat, const Size &siz
return debayer_->strideAndFrameSize(outputFormat, size);
}
+/**
+ * Get the preferred input stride in bytes for the given input format and size
+ * \param[in] inputFormat The input format
+ * \param[in] size The input size (width and height in pixels)
+ * \return The preferred input stride in bytes or 0 if there is no preference
+ */
+uint32_t SoftwareIsp::preferredInputStride(const PixelFormat &inputFormat, const Size &size)
+{
+ ASSERT(debayer_);
+
+ return debayer_->preferredInputStride(inputFormat, size);
+}
+
/**
* \brief Configure the SoftwareIsp object according to the passed in parameters
* \param[in] inputCfg The input configuration
--
2.54.0

View file

@ -1,37 +0,0 @@
From 7faa71ddfaca43b76b25a0a34b255999b44bfe40 Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Tue, 16 Jun 2026 13:20:21 +0200
Subject: [PATCH 10/13] egl: Log the GL-driver
To make it easier to differentiate various drivers. Some examples from running on
a FairPhone5:
INFO eGL egl.cpp:362 EGL: GL_RENDERER: FD643
INFO eGL egl.cpp:362 EGL: GL_RENDERER: llvmpipe (LLVM 22.1.3, 128 bits)
INFO eGL egl.cpp:362 EGL: GL_RENDERER: zink Vulkan 1.3(Turnip Adreno (TM) 643 (MESA_TURNIP))
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Tested-by: Jai Luthra <jai.luthra@ideasonboard.com>
Reviewed-by: Jai Luthra <jai.luthra@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit 51dbd82e5e008d65bce96821d88ed2f6ea6c8e67)
---
src/libcamera/egl.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
index 7689d7983..9318a1b43 100644
--- a/src/libcamera/egl.cpp
+++ b/src/libcamera/egl.cpp
@@ -360,6 +360,7 @@ int eGL::initEGLContext()
makeCurrent();
+ LOG(eGL, Info) << "EGL: GL_RENDERER: " << glGetString(GL_RENDERER);
LOG(eGL, Info) << "EGL: GL_VERSION: " << glGetString(GL_VERSION);
return 0;
--
2.54.0

View file

@ -1,72 +0,0 @@
From dd5347b8d391e93a8a3ae3ded7168d5705619f4a Mon Sep 17 00:00:00 2001
From: Robert Mader <robert.mader@collabora.com>
Date: Mon, 15 Jun 2026 20:11:27 +0200
Subject: [PATCH 11/13] software_isp: debayer_egl: Consider border for scaling
The debayer algorithm produces a sligtly smaller output resolution
compared to the input one, using a border at the edges depending on the
pattern. This wasn't considered when scaling to the final output buffer
size, resulting in garbage pixels at the right - or in case or 90 degree
rotated sensors - the bottom of the image.
Use the native (i.e. unscaled) output size instead - the maximum output
buffer size.
While on it use outputSize_ for better readability and adopt the scaling
comment slightly.
Fixes: f520b29fe9e6 ("libcamera: software_isp: debayer_egl: Add an eGL Debayer class")
Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
(cherry picked from commit 425dd3955db8d77cb8a4c7a75e2d46a50c896879)
---
src/libcamera/software_isp/debayer_egl.cpp | 10 ++++++----
src/libcamera/software_isp/debayer_egl.h | 1 +
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 264a9315d..5fd014d1d 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -323,6 +323,7 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg,
outputPixelFormat_ = outputCfg.pixelFormat;
outputSize_ = outputCfg.size;
+ nativeOutputSize_ = outSizeRange.max;
window_.x = ((inputCfg.size.width - outputCfg.size.width) / 2) &
~(inputConfig_.patternSize.width - 1);
@@ -394,11 +395,12 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)
1.0f / (height_ - 1) };
GLfloat Stride = (GLfloat)width_ / (shaderStridePixels_ / bytesPerPixel_);
/*
- * Scale input to output size, keeping the aspect ratio and preferring
- * cropping over black bars.
+ * Scale the output size from the native size the algorithm produces for
+ * the input size. Keep the aspect ratio and prefer cropping over black
+ * bars.
*/
- GLfloat scale = std::max((GLfloat)window_.width / width_,
- (GLfloat)window_.height / height_);
+ GLfloat scale = std::max((GLfloat)outputSize_.width / nativeOutputSize_.width,
+ (GLfloat)outputSize_.height / nativeOutputSize_.height);
GLfloat trans = -(1.0f - scale);
GLfloat projMatrix[] = {
scale, 0, 0, 0,
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
index c7cb009b6..ef8c49814 100644
--- a/src/libcamera/software_isp/debayer_egl.h
+++ b/src/libcamera/software_isp/debayer_egl.h
@@ -103,6 +103,7 @@ private:
/* Contrast */
GLint contrastExpUniformDataIn_;
+ Size nativeOutputSize_;
Rectangle window_;
std::unique_ptr<SwStatsCpu> stats_;
eGL egl_;
--
2.54.0

View file

@ -1,9 +1,9 @@
# Forked from Alpine for temporary downstream patches
maintainer="Robert Mader <robert.mader@collabora.com>"
pkgname=libcamera
_pkgver=0.7.1
_pkgver=0.7.2
pkgver=9999$_pkgver
pkgrel=1
pkgrel=0
pkgdesc="Linux camera framework"
url="https://libcamera.org/"
arch="all"
@ -57,19 +57,8 @@ _tuning_files="
s5kjn1.yaml
"
source="https://gitlab.freedesktop.org/camera/libcamera/-/archive/v$_pkgver/libcamera-v$_pkgver.tar.gz
0001-debayer_egl-Include-stats-computation-into-benchmark.patch
0002-debayer_egl-Sync-output-buffers-after-processing-sta.patch
0003-egl-Add-GL-format-parameter-to-eGLImage-constructor.patch
0004-egl-Remove-some-parameters-from-createTexture2D.patch
0005-egl-eGLImage-Add-flag-to-remember-dmabuf-import-fail.patch
0006-libcamera-swstats_cpu-Take-MappedFrameBuffer-in-proc.patch
0007-debayer_egl-Implement-dmabuf-import-for-input-buffer.patch
0008-libcamera-software_isp-debayer_egl-Demote-unsupporte.patch
0009-software_isp-debayer_egl-Request-input-buffer-alignm.patch
0010-egl-Log-the-GL-driver.patch
0011-software_isp-debayer_egl-Consider-border-for-scaling.patch
0012-libcamera-simple-Enable-softISP-for-the-Pinephone.patch
0013-libcamera-simple-Skip-hwISP-formats-if-swISP-is-acti.patch
0001-libcamera-simple-Enable-softISP-for-the-Pinephone.patch
0002-libcamera-simple-Skip-hwISP-formats-if-swISP-is-acti.patch
qcam.desktop
$_tuning_files
"
@ -182,28 +171,17 @@ py3() {
}
sha512sums="
0e886021a3bbd668184b581248b9d89a8e909360a7f138237a2c03b41b477cb255bd6daf4932fdebf86c3410b4deccc4c5db93264ed0c6c9969076cdbae8a77b libcamera-v0.7.1.tar.gz
5e936a5041f30c35f120a437a1cec65ab1d2b3ac335500566c291c7891b9ba585e6b7e4d22c54870257d161d23ef8bc5d3a99a512193f47adf41d4ae1683247a 0001-debayer_egl-Include-stats-computation-into-benchmark.patch
a2b110357ca6b26b469e399fc49fb890efcd97ccc18c16bf715be2a2c9159c293e5f9a23d9bab97dc4a19777232340c008e5ef156699f4383fed67c6157e0e1d 0002-debayer_egl-Sync-output-buffers-after-processing-sta.patch
00792bac0ee7aba1c2abdb1152efa86a08a06a1729c2f7aec19e647b4799ad8cac3a61fb0fc92e87f2af7c776811265e4f391ac8466b8b8a327b10dd9fe8a4f1 0003-egl-Add-GL-format-parameter-to-eGLImage-constructor.patch
75c8adb06c23e791464cbdd8ad36607a5bc6d46fa25af7b395f628b933c2a5fbbe1c1896eb6f4cac521aef38a13b67b71659503d344fe728763d7012f78de4d4 0004-egl-Remove-some-parameters-from-createTexture2D.patch
2afb8080916e25be93b6313f7419364ef8d02616b2e3065733ef180ebadf8ae05412c3b9b03017db711ca4460cf1bbe8c240e6502ff3b8797d7c864b0852b7c2 0005-egl-eGLImage-Add-flag-to-remember-dmabuf-import-fail.patch
5eca6b23c73300948e743e56cb4632db774c860a580f242ba20f387353d00879f70067179eeedb1c1c2f240303af51dc63e40573fa2ef03ebca26bfce1e94c69 0006-libcamera-swstats_cpu-Take-MappedFrameBuffer-in-proc.patch
9fc710bc0e177dcd664b1c7773e8c96dcf8bdf64ababf3f357b95d6dda2e8127ff0ee76f3d11ad01942f5a70f85ed94b78c17ef30c5639bd1c1b2b17fcdf17a4 0007-debayer_egl-Implement-dmabuf-import-for-input-buffer.patch
df8bbbb4438821e8c61a812886f0266f54f10b4b4d490efb6564e30010b8b624671f4b257dbda34056e03b369041c1e39c75aac351ddad2c9a4b98113f3feb9b 0008-libcamera-software_isp-debayer_egl-Demote-unsupporte.patch
8b2b8323b44d9ad45fa73862b0d7287ad9eb5f36583fb1bcbbf01ca85e2117883fde034e3314cbcbc3a73504f08c6abbb00a7e54d97f5991b3570e4e3a20925c 0009-software_isp-debayer_egl-Request-input-buffer-alignm.patch
0cc8cb2da2a25f3c5daa4d644e05f3ba6d45717eaea9e3e19cf65ace4d0eba30df9f5c16b351a693c5db4d4c298f5c04e69aa70db1e4e11318b0bb914e90af06 0010-egl-Log-the-GL-driver.patch
ca6dacedbd76a629539d033c028018ab5b858fcc3194787ceeda6b560d4d20dbb9b684f859ac2e40d144a77bcb2cc211c47d639ac6053cfc80cffeff3c5392b8 0011-software_isp-debayer_egl-Consider-border-for-scaling.patch
709a610297f7d3191da404816841183094bf8deeca4f0abec63a59f0ae7b95d02b546bb6315932264f7a0a731f7e3b949eeb5d5078f7399f39b580d4ff11da66 0012-libcamera-simple-Enable-softISP-for-the-Pinephone.patch
4482204e7a5fea2b853b8030e45fac8716b9e3fc84a16f248b778b3f10a85d956698147f04a173956f3bbf4cfdc6c12879fd8f621bd0147ecb9b3b0d2ddc3d6b 0013-libcamera-simple-Skip-hwISP-formats-if-swISP-is-acti.patch
b317cdc96f61682ee0bf26dfb7c4d6441db9a9c5b93ab53528121a8cd44862b3d59cbaa3881bb0837e3e381564c184c7b742124aef4267eea754c6083de353c1 libcamera-v0.7.2.tar.gz
eef5e38efc874f2049d17f08b04d9f21c3e4616f66873358cd2c446e651f78d6952ae25ee13a6ef917e3f85bc7b6a6991152e42c8efd8c7f5bff69829a518826 0001-libcamera-simple-Enable-softISP-for-the-Pinephone.patch
191dfa09cfd08bcdf0d0d07410d17af590cf78b8bc8f8b7587fd2dc1c645a9ca07f2926b5d98381c011319b1f4e1d6195dd0d6dba65fd8c723882e6be0d6117d 0002-libcamera-simple-Skip-hwISP-formats-if-swISP-is-acti.patch
22167a4eceb6d1b40b0b7c45fdf116c71684f5340de7f767535cb8e160ad9d2ae0f00cb3d461f73a344520a48a4641cf46226841d78bee06bfbfd2a91337f754 qcam.desktop
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f hi846.yaml
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f imx355.yaml
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f imx363.yaml
55dab9dcb9b1982143b9d63e4e51138c5bffd7c8f4a8e4e122750b3ad9d475446956bc297d9f564819ade4be75a575d06633a064e14f8ba3ef77986783c5f067 imx355.yaml
285c6d0d712df341c0117c3762ddc139f53f44e6be36c3388d1a62696429175e2916f392163131e21f410c3676f02f5d125f375171f45f8d82ad278aa5076c62 imx363.yaml
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f imx371.yaml
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f imx376.yaml
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f imx519.yaml
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f imx858.yaml
55dab9dcb9b1982143b9d63e4e51138c5bffd7c8f4a8e4e122750b3ad9d475446956bc297d9f564819ade4be75a575d06633a064e14f8ba3ef77986783c5f067 imx858.yaml
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f s5k3l6xx.yaml
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f s5kjn1.yaml
d59020e62520ee622282c85ce7bcdfe453c99becf48cc1005c5f8a4bb8b2511b19c89f38fb3c994e7c6a79d1f84e2ed5f5a09b4c5bdc1dc4a44b071dbccf0d44 s5kjn1.yaml
"

View file

@ -6,6 +6,37 @@ algorithms:
- BlackLevel:
blackLevel: 4096
- Awb:
- Ccm:
# copied from s5kjn1.yaml
ccms:
- ct: 2676
ccm: [ 2.02152, -0.41859, -0.60292,
-0.59481, 2.21509, -0.62029,
-0.44029, -1.16865, 2.60894 ]
- ct: 2710
ccm: [ 2.01597, -0.46478, -0.55119,
-0.59047, 2.14717, -0.55671,
-0.40793, -1.19946, 2.60739 ]
- ct: 2719
ccm: [ 1.99894, -0.41626, -0.58268,
-0.59321, 2.18167, -0.58846,
-0.42518, -1.21384, 2.63903 ]
- ct: 2867
ccm: [ 1.95177, -0.35904, -0.59274,
-0.44282, 1.97362, -0.53079,
-0.49059, -1.35379, 2.84439 ]
- ct: 3474
ccm: [ 1.97712, -0.60854, -0.36858,
-0.47723, 1.91142, -0.43418,
-0.23092, -0.72246, 1.95339 ]
- ct: 3761
ccm: [ 2.29903, -0.94652, -0.35251,
-0.51661, 1.90311, -0.38651,
-0.25114, -0.67501, 1.92615 ]
- ct: 6890
ccm: [ 1.93867, -0.67486, -0.26381,
-0.43049, 2.00702, -0.57652,
-0.15696, -0.51345, 1.67041 ]
- Adjust:
- Agc:
...

View file

@ -6,6 +6,32 @@ algorithms:
- BlackLevel:
blackLevel: 4096
- Awb:
- Ccm:
ccms:
- ct: 2701
ccm: [ 1.66951, -0.35271, -0.31679,
-0.33594, 1.69731, -0.36137,
0.07843, -1.25185, 2.17341 ]
- ct: 2789
ccm: [ 1.74401, -0.44379, -0.30022,
-0.33322, 1.69889, -0.36567,
0.09074, -1.27168, 2.18093 ]
- ct: 3025
ccm: [ 1.71956, -0.37493, -0.34462,
-0.46994, 1.83453, -0.36459,
0.01838, -1.03863, 2.02024 ]
- ct: 4021
ccm: [ 1.65286, -0.42348, -0.22938,
-0.34752, 1.63472, -0.28719,
-0.02119, -0.65164, 1.67283 ]
- ct: 4125
ccm: [ 1.89736, -0.65796, -0.23941,
-0.36603, 1.62015, -0.25412,
0.01202, -0.66114, 1.64912 ]
- ct: 6521
ccm: [ 1.64464, -0.50901, -0.13564,
-0.28189, 1.73169, -0.44979,
-0.02601, -0.51457, 1.54058 ]
- Adjust:
- Agc:
...

View file

@ -6,6 +6,37 @@ algorithms:
- BlackLevel:
blackLevel: 4096
- Awb:
- Ccm:
# copied from s5kjn1.yaml
ccms:
- ct: 2676
ccm: [ 2.02152, -0.41859, -0.60292,
-0.59481, 2.21509, -0.62029,
-0.44029, -1.16865, 2.60894 ]
- ct: 2710
ccm: [ 2.01597, -0.46478, -0.55119,
-0.59047, 2.14717, -0.55671,
-0.40793, -1.19946, 2.60739 ]
- ct: 2719
ccm: [ 1.99894, -0.41626, -0.58268,
-0.59321, 2.18167, -0.58846,
-0.42518, -1.21384, 2.63903 ]
- ct: 2867
ccm: [ 1.95177, -0.35904, -0.59274,
-0.44282, 1.97362, -0.53079,
-0.49059, -1.35379, 2.84439 ]
- ct: 3474
ccm: [ 1.97712, -0.60854, -0.36858,
-0.47723, 1.91142, -0.43418,
-0.23092, -0.72246, 1.95339 ]
- ct: 3761
ccm: [ 2.29903, -0.94652, -0.35251,
-0.51661, 1.90311, -0.38651,
-0.25114, -0.67501, 1.92615 ]
- ct: 6890
ccm: [ 1.93867, -0.67486, -0.26381,
-0.43049, 2.00702, -0.57652,
-0.15696, -0.51345, 1.67041 ]
- Adjust:
- Agc:
...

View file

@ -6,6 +6,36 @@ algorithms:
- BlackLevel:
blackLevel: 4096
- Awb:
- Ccm:
ccms:
- ct: 2676
ccm: [ 2.02152, -0.41859, -0.60292,
-0.59481, 2.21509, -0.62029,
-0.44029, -1.16865, 2.60894 ]
- ct: 2710
ccm: [ 2.01597, -0.46478, -0.55119,
-0.59047, 2.14717, -0.55671,
-0.40793, -1.19946, 2.60739 ]
- ct: 2719
ccm: [ 1.99894, -0.41626, -0.58268,
-0.59321, 2.18167, -0.58846,
-0.42518, -1.21384, 2.63903 ]
- ct: 2867
ccm: [ 1.95177, -0.35904, -0.59274,
-0.44282, 1.97362, -0.53079,
-0.49059, -1.35379, 2.84439 ]
- ct: 3474
ccm: [ 1.97712, -0.60854, -0.36858,
-0.47723, 1.91142, -0.43418,
-0.23092, -0.72246, 1.95339 ]
- ct: 3761
ccm: [ 2.29903, -0.94652, -0.35251,
-0.51661, 1.90311, -0.38651,
-0.25114, -0.67501, 1.92615 ]
- ct: 6890
ccm: [ 1.93867, -0.67486, -0.26381,
-0.43049, 2.00702, -0.57652,
-0.15696, -0.51345, 1.67041 ]
- Adjust:
- Agc:
...