[2/3] debayer_egl: Implement dmabuf import for input buffers
diff mbox series

Message ID 20260503114002.139255-3-robert.mader@collabora.com
State New
Headers show
Series
  • software_isp: Implement DMABuf import for input buffers
Related show

Commit Message

Robert Mader May 3, 2026, 11:40 a.m. UTC
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.

While on it, add some minor code adjustments to make it easier to
follow.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
---
 src/libcamera/software_isp/debayer_egl.cpp | 28 ++++++++++++----------
 src/libcamera/software_isp/debayer_egl.h   |  2 +-
 2 files changed, 17 insertions(+), 13 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 8f0c229fd..624469947 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -495,16 +495,26 @@  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, std::vector<DmaSyncer> &dmaSyncers, const DebayerParams &params)
 {
 	/* 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_, glFormat_, inputConfig_.stride / bytesPerPixel_, height_, input->planes()[0].fd.get()) != 0) {
+		LOG(Debayer, Debug) << "Importing input buffer with DMABuf import failed, falling back to upload";
+
+		dmaSyncBegin(dmaSyncers, input, nullptr);
+		MappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read);
+		if (!in.isValid()) {
+			LOG(Debayer, Error) << "mmap-ing buffer(s) failed";
+			return -ENODEV;
+		}
+		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);
+	egl_.createOutputDMABufTexture2D(*eglImageBayerOut_, output->planes()[0].fd.get());
 
 	setShaderVariableValues(params);
 	glViewport(0, 0, width_, height_);
@@ -528,21 +538,13 @@  void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
 
 	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;
-	}
-
-	if (debayerGPU(in, output->planes()[0].fd.get(), params)) {
+	if (debayerGPU(input, output, dmaSyncers, params)) {
 		LOG(Debayer, Error) << "debayerGPU failed";
 		goto error;
 	}
@@ -552,6 +554,8 @@  void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
 	metadata.planes()[0].bytesused = output->planes()[0].length;
 
 	/* Calculate stats for the whole frame */
+	if (dmaSyncers.empty() && (frame % SwStatsCpu::kStatPerNumFrames) == 0)
+	    dmaSyncBegin(dmaSyncers, input, nullptr);
 	stats_->processFrame(frame, 0, input);
 	dmaSyncers.clear();
 
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
index fcd281f4c..62cb4f7f1 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, std::vector<DmaSyncer> &dmaSyncers, const DebayerParams &params);
 
 	/* Shader program identifiers */
 	GLuint vertexShaderId_ = 0;