temp/libcamera: update downstream patch to merged version
Replace the dmabuf import patch with the two series that it grow into during upstreaming, shipping in the next libcamera release. This will: 1. Improve performance for all devices using the GPU-ISP, including those not able to use dmabuf import. 2. Simplify debugging. 3. Ensure the patches get enough testing before the upstream release. While on it backport some additional patches: 1. A follow-up patch adding the last required step to allow dmabuf import for input buffers to work in almost all cases *if* the V4L2 driver handles custom bytesperline requests for bayer formats. 2. A small logging fix 3. A fix for bad bottom lines of pixels seen on some devices. This is the only patch with visual impact - and a quite desirable one. 4. A patch to log the used driver for easier debugging. This leaves us with only two downstream patches, both specific to the PinePhone (OG). Finally, add a "py3-$pkgname-pyc:pyc" subpackage in order to stay in sync with the upstream package. Part-of: <https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/8650>
This commit is contained in:
parent
1045ec382b
commit
093a6b017b
15 changed files with 1140 additions and 225 deletions
|
|
@ -0,0 +1,44 @@
|
|||
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
|
||||
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
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
|
||||
|
||||
|
|
@ -1,212 +0,0 @@
|
|||
From 08b9cc8401e57b05cd8b73e1dd1d7bf0691a048b Mon Sep 17 00:00:00 2001
|
||||
From: Robert Mader <robert.mader@collabora.com>
|
||||
Date: Fri, 19 Dec 2025 20:31:16 +0100
|
||||
Subject: [PATCH 3/3] RFC: egl: Implement DMABuf import for input buffers
|
||||
|
||||
In many cases we can import the GPU-ISP input buffer, a dmabuf from v4l2,
|
||||
directly into EGL instead of mapping and uploading - i.e. copying - it.
|
||||
This reduces memory bandwith usage and can even slightly improve
|
||||
latency.
|
||||
This main reason this doesn't work in many cases is the stride
|
||||
alignment, as GPUs often have stricter requirements (often 128 or even
|
||||
256 bytes) than hardware ISPs.
|
||||
|
||||
Thus try to import buffer directly and - if that fails - fall back to
|
||||
the previous upload path. To do so, adjust some function parameters and
|
||||
turn down error messages. 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.
|
||||
|
||||
Signed-off-by: Robert Mader <robert.mader@collabora.com>
|
||||
---
|
||||
include/libcamera/internal/egl.h | 4 +--
|
||||
src/libcamera/egl.cpp | 37 +++++++++++++++++-----
|
||||
src/libcamera/software_isp/debayer_egl.cpp | 21 ++++++------
|
||||
src/libcamera/software_isp/debayer_egl.h | 2 +-
|
||||
4 files changed, 44 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h
|
||||
index 0ad2320b1..bb97b0c7c 100644
|
||||
--- a/include/libcamera/internal/egl.h
|
||||
+++ b/include/libcamera/internal/egl.h
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
|
||||
int initEGLContext();
|
||||
|
||||
- int createInputDMABufTexture2D(eGLImage &eglImage, int fd);
|
||||
+ int createInputDMABufTexture2D(eGLImage &eglImage, int fd, GLint format, uint32_t width, uint32_t height);
|
||||
int createOutputDMABufTexture2D(eGLImage &eglImage, int fd);
|
||||
void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data);
|
||||
|
||||
@@ -133,7 +133,7 @@ private:
|
||||
unsigned int shaderDataLen,
|
||||
Span<const std::string> shaderEnv);
|
||||
|
||||
- int createDMABufTexture2D(eGLImage &eglImage, int fd, bool output);
|
||||
+ int createDMABufTexture2D(eGLImage &eglImage, int fd, uint32_t drm_format, uint32_t width, uint32_t height, bool output);
|
||||
|
||||
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
|
||||
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
|
||||
diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp
|
||||
index f65929470..febfd4bba 100644
|
||||
--- a/src/libcamera/egl.cpp
|
||||
+++ b/src/libcamera/egl.cpp
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <libcamera/base/thread.h>
|
||||
|
||||
+#include <GLES3/gl32.h>
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
|
||||
namespace libcamera {
|
||||
@@ -102,6 +103,9 @@ void eGL::syncOutput()
|
||||
* \brief Create a DMA-BUF backed 2D texture
|
||||
* \param[in,out] eglImage EGL image to associate with the DMA-BUF
|
||||
* \param[in] fd DMA-BUF file descriptor
|
||||
+ * \param[in] drm_format the DRM fourcc
|
||||
+ * \param[in] width the buffer width
|
||||
+ * \param[in] height the buffer height
|
||||
* \param[in] output If true, create framebuffer for render target
|
||||
*
|
||||
* Internal implementation for creating DMA-BUF textures. Creates an EGL
|
||||
@@ -110,15 +114,15 @@ void eGL::syncOutput()
|
||||
*
|
||||
* \return 0 on success, or -ENODEV on failure
|
||||
*/
|
||||
-int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
|
||||
+int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, uint32_t drm_format, uint32_t width, uint32_t height, bool output)
|
||||
{
|
||||
ASSERT(tid_ == Thread::currentId());
|
||||
|
||||
// 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_WIDTH, (EGLint)width,
|
||||
+ EGL_HEIGHT, (EGLint)height,
|
||||
+ EGL_LINUX_DRM_FOURCC_EXT, (EGLint)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_,
|
||||
@@ -133,7 +137,7 @@ 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";
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -172,6 +176,9 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
|
||||
* \brief Create an input DMA-BUF backed texture
|
||||
* \param[in,out] eglImage EGL image to associate with the DMA-BUF
|
||||
* \param[in] fd DMA-BUF file descriptor
|
||||
+ * \param[in] format the GL format
|
||||
+ * \param[in] width the buffer width
|
||||
+ * \param[in] height the buffer height
|
||||
*
|
||||
* Creates an EGL image from a DMA-BUF file descriptor and binds it to
|
||||
* a 2D texture for use as an input texture in shaders. The texture is
|
||||
@@ -179,11 +186,25 @@ int eGL::createDMABufTexture2D(eGLImage &eglImage, int fd, bool output)
|
||||
*
|
||||
* \return 0 on success, or -ENODEV on failure
|
||||
*/
|
||||
-int eGL::createInputDMABufTexture2D(eGLImage &eglImage, int fd)
|
||||
+int eGL::createInputDMABufTexture2D(eGLImage &eglImage, int fd, GLint format, uint32_t width, uint32_t height)
|
||||
{
|
||||
+ EGLint drm_format;
|
||||
+
|
||||
ASSERT(tid_ == Thread::currentId());
|
||||
|
||||
- return createDMABufTexture2D(eglImage, fd, false);
|
||||
+ switch (format) {
|
||||
+ case GL_LUMINANCE:
|
||||
+ drm_format = DRM_FORMAT_R8;
|
||||
+ break;
|
||||
+ case GL_RG:
|
||||
+ drm_format = DRM_FORMAT_RG88;
|
||||
+ break;
|
||||
+ default:
|
||||
+ LOG(eGL, Error) << "unhandled GL format";
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ return createDMABufTexture2D(eglImage, fd, drm_format, width, height, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,7 +223,7 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd)
|
||||
{
|
||||
ASSERT(tid_ == Thread::currentId());
|
||||
|
||||
- return createDMABufTexture2D(eglImage, fd, true);
|
||||
+ return createDMABufTexture2D(eglImage, fd, DRM_FORMAT_ARGB8888, eglImage.width_, eglImage.height_, true);
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
|
||||
index 8f0c229fd..f4fc2a6f9 100644
|
||||
--- a/src/libcamera/software_isp/debayer_egl.cpp
|
||||
+++ b/src/libcamera/software_isp/debayer_egl.cpp
|
||||
@@ -495,13 +495,22 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams ¶ms)
|
||||
return;
|
||||
}
|
||||
|
||||
-int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams ¶ms)
|
||||
+int DebayerEGL::debayerGPU(FrameBuffer *input, int out_fd, const DebayerParams ¶ms)
|
||||
{
|
||||
/* eGL context switch */
|
||||
egl_.makeCurrent();
|
||||
|
||||
/* Create a standard texture input */
|
||||
- egl_.createTexture2D(*eglImageBayerIn_, glFormat_, inputConfig_.stride / bytesPerPixel_, height_, in.planes()[0].data());
|
||||
+ if (egl_.createInputDMABufTexture2D(*eglImageBayerIn_, input->planes()[0].fd.get(), glFormat_, inputConfig_.stride / bytesPerPixel_, height_) != 0) {
|
||||
+ MappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read);
|
||||
+ if (!in.isValid()) {
|
||||
+ LOG(Debayer, Error) << "mmap-ing buffer(s) failed";
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ LOG(Debayer, Debug) << "Importing input buffer with DMABuf import failed, falling back to upload";
|
||||
+ egl_.createTexture2D(*eglImageBayerIn_, glFormat_, inputConfig_.stride / bytesPerPixel_, height_, in.planes()[0].data());
|
||||
+ }
|
||||
|
||||
/* Generate the output render framebuffer as render to texture */
|
||||
egl_.createOutputDMABufTexture2D(*eglImageBayerOut_, out_fd);
|
||||
@@ -536,13 +545,7 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
|
||||
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;
|
||||
- }
|
||||
-
|
||||
- if (debayerGPU(in, output->planes()[0].fd.get(), params)) {
|
||||
+ if (debayerGPU(input, output->planes()[0].fd.get(), params)) {
|
||||
LOG(Debayer, Error) << "debayerGPU failed";
|
||||
goto error;
|
||||
}
|
||||
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
|
||||
index fcd281f4c..5a1e4dfe3 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 ¶ms);
|
||||
- int debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams ¶ms);
|
||||
+ int debayerGPU(FrameBuffer *input, int out_fd, const DebayerParams ¶ms);
|
||||
|
||||
/* Shader program identifiers */
|
||||
GLuint vertexShaderId_ = 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
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
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
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
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
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
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
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
|
||||
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
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 ¶ms)
|
||||
return;
|
||||
}
|
||||
|
||||
-int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams ¶ms)
|
||||
+int DebayerEGL::debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, 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 ¶ms);
|
||||
- int debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParams ¶ms);
|
||||
+ int debayerGPU(FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms, std::optional<MappedFrameBuffer> *mappedInputBuffer, std::optional<DmaSyncer> *inputBufferDmaSyncer);
|
||||
|
||||
/* Shader program identifiers */
|
||||
GLuint vertexShaderId_ = 0;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
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
|
||||
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
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 ¶ms) = 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 ¶ms)
|
||||
{
|
||||
/*
|
||||
@@ -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 ¶ms) 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
|
||||
|
||||
37
temp/libcamera/0010-egl-Log-the-GL-driver.patch
Normal file
37
temp/libcamera/0010-egl-Log-the-GL-driver.patch
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
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
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
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 ¶ms)
|
||||
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
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
From ccbfcbaf782fc66fe4600902fb51f043f44bf105 Mon Sep 17 00:00:00 2001
|
||||
From afbbb6c818ed330a2239c0ebb78d63ffa775c341 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 1/3] libcamera: simple: Enable softISP for the Pinephone
|
||||
Subject: [PATCH 12/13] 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
|
||||
|
|
@ -17,7 +17,7 @@ Signed-off-by: Robert Mader <robert.mader@collabora.com>
|
|||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
|
||||
index c6fe12d65..89b86f59c 100644
|
||||
index e26f438d9..24538649c 100644
|
||||
--- a/src/libcamera/pipeline/simple/simple.cpp
|
||||
+++ b/src/libcamera/pipeline/simple/simple.cpp
|
||||
@@ -264,7 +264,7 @@ static const SimplePipelineInfo supportedDevices[] = {
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
From 00e2f3ed19756080d709bd86d46c3c27ec8cea80 Mon Sep 17 00:00:00 2001
|
||||
From c7efef9c313386d530ab6422c0677953f36a2478 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 2/3] libcamera: simple: Skip hwISP formats if swISP is active
|
||||
Subject: [PATCH 13/13] 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
|
||||
|
|
@ -15,7 +16,7 @@ Signed-off-by: Robert Mader <robert.mader@collabora.com>
|
|||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
|
||||
index 89b86f59c..1daee387e 100644
|
||||
index 24538649c..b96b8b529 100644
|
||||
--- a/src/libcamera/pipeline/simple/simple.cpp
|
||||
+++ b/src/libcamera/pipeline/simple/simple.cpp
|
||||
@@ -745,9 +745,7 @@ void SimpleCameraData::tryPipeline(unsigned int code, const Size &size)
|
||||
|
|
@ -3,7 +3,7 @@ maintainer="Robert Mader <robert.mader@collabora.com>"
|
|||
pkgname=libcamera
|
||||
_pkgver=0.7.1
|
||||
pkgver=9999$_pkgver
|
||||
pkgrel=0
|
||||
pkgrel=1
|
||||
pkgdesc="Linux camera framework"
|
||||
url="https://libcamera.org/"
|
||||
arch="all"
|
||||
|
|
@ -42,6 +42,7 @@ subpackages="
|
|||
$pkgname-gstreamer
|
||||
$pkgname-v4l2
|
||||
$pkgname-tools
|
||||
py3-$pkgname-pyc:pyc
|
||||
py3-$pkgname:py3
|
||||
"
|
||||
_tuning_files="
|
||||
|
|
@ -55,9 +56,19 @@ _tuning_files="
|
|||
s5kjn1.yaml
|
||||
"
|
||||
source="https://gitlab.freedesktop.org/camera/libcamera/-/archive/v$_pkgver/libcamera-v$_pkgver.tar.gz
|
||||
0001-libcamera-simple-Enable-softISP-for-the-Pinephone.patch
|
||||
0002-libcamera-simple-Skip-hwISP-formats-if-swISP-is-acti.patch
|
||||
0003-RFC-egl-Implement-DMABuf-import-for-input-buffers.patch
|
||||
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
|
||||
qcam.desktop
|
||||
$_tuning_files
|
||||
"
|
||||
|
|
@ -171,9 +182,19 @@ py3() {
|
|||
|
||||
sha512sums="
|
||||
0e886021a3bbd668184b581248b9d89a8e909360a7f138237a2c03b41b477cb255bd6daf4932fdebf86c3410b4deccc4c5db93264ed0c6c9969076cdbae8a77b libcamera-v0.7.1.tar.gz
|
||||
aa24b1caab3d0e6bca413ff149aafa5233ba8141c2585b1b55c655759dd663612091222135ec5add402e60bf53d58c307f3f3127385efaa11b6cef866e03906e 0001-libcamera-simple-Enable-softISP-for-the-Pinephone.patch
|
||||
cd1559a70dabe8711bb2cc1a8c6dca114e9f5b83088000935845ad90e5d109e2b215f0810f709f5bf00dd76be76e937bad4db49a1c6662135ec1704809a9a62b 0002-libcamera-simple-Skip-hwISP-formats-if-swISP-is-acti.patch
|
||||
6bca235e430e7392f68c94742d1bc1cd19cffe12ac03c8890ffa27b756972df67f5a408f4c806149a6b4f52827881a73d14d7f6a00bab9d4692f5eb9b06478a5 0003-RFC-egl-Implement-DMABuf-import-for-input-buffers.patch
|
||||
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
|
||||
22167a4eceb6d1b40b0b7c45fdf116c71684f5340de7f767535cb8e160ad9d2ae0f00cb3d461f73a344520a48a4641cf46226841d78bee06bfbfd2a91337f754 qcam.desktop
|
||||
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f hi846.yaml
|
||||
2ee566653b17d565d2c0de67cbe6ebad25df5aac6051cad78e6bae52016fa2ca0247e964d735ac776b3e0bd447ead9c4fcb26cd7629228cdba3ceb91b46f378f imx355.yaml
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue