libcamera: software_isp: Probe EGL availability before creating DebayerEGL
diff mbox series

Message ID 20260603102534.3059900-1-qi.hou@nxp.com
State New
Headers show
Series
  • libcamera: software_isp: Probe EGL availability before creating DebayerEGL
Related show

Commit Message

Qi Hou June 3, 2026, 10:25 a.m. UTC
When HAVE_DEBAYER_EGL is enabled, the SoftwareIsp constructor
unconditionally creates a DebayerEGL instance. The DebayerEGL
constructor always succeeds because it merely stores pointers without
initialising the EGL context. The actual EGL initialisation is deferred
to DebayerEGL::start(), which calls eGL::initEGLContext(). If the
platform lacks a surfaceless EGL display (e.g. i.MX8MM without Mesa
surfaceless support), eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA)
fails and start() returns -ENODEV. At that point, the SwStatsCpu
ownership has already been moved into the unusable DebayerEGL instance,
making a fallback to DebayerCpu impossible.

Fix this by adding a static DebayerEGL::isEGLAvailable() method that
probes whether EGL surfaceless rendering can be initialised. It
attempts eglGetPlatformDisplay() + eglInitialize() and immediately
calls eglTerminate() to release resources. The SoftwareIsp constructor
now calls this probe before creating DebayerEGL. If EGL is not
available, DebayerEGL is not instantiated and the existing fallback
path naturally creates a DebayerCpu instance instead.

Signed-off-by: Qi Hou <qi.hou@nxp.com>
---
 src/libcamera/software_isp/debayer_egl.cpp  | 28 +++++++++++++++++++++
 src/libcamera/software_isp/debayer_egl.h    |  2 ++
 src/libcamera/software_isp/software_isp.cpp | 10 ++++++--
 3 files changed, 38 insertions(+), 2 deletions(-)

Comments

Laurent Pinchart June 3, 2026, 9:04 p.m. UTC | #1
On Wed, Jun 03, 2026 at 07:25:34PM +0900, Qi Hou wrote:
> When HAVE_DEBAYER_EGL is enabled, the SoftwareIsp constructor
> unconditionally creates a DebayerEGL instance. The DebayerEGL
> constructor always succeeds because it merely stores pointers without
> initialising the EGL context. The actual EGL initialisation is deferred
> to DebayerEGL::start(), which calls eGL::initEGLContext(). If the
> platform lacks a surfaceless EGL display (e.g. i.MX8MM without Mesa
> surfaceless support), eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA)
> fails and start() returns -ENODEV. At that point, the SwStatsCpu
> ownership has already been moved into the unusable DebayerEGL instance,
> making a fallback to DebayerCpu impossible.
> 
> Fix this by adding a static DebayerEGL::isEGLAvailable() method that
> probes whether EGL surfaceless rendering can be initialised. It
> attempts eglGetPlatformDisplay() + eglInitialize() and immediately
> calls eglTerminate() to release resources. The SoftwareIsp constructor
> now calls this probe before creating DebayerEGL. If EGL is not
> available, DebayerEGL is not instantiated and the existing fallback
> path naturally creates a DebayerCpu instance instead.

This duplicates code from eGL::initEGLContext(), which doesn't seem to
be a nice design.

> Signed-off-by: Qi Hou <qi.hou@nxp.com>
> ---
>  src/libcamera/software_isp/debayer_egl.cpp  | 28 +++++++++++++++++++++
>  src/libcamera/software_isp/debayer_egl.h    |  2 ++
>  src/libcamera/software_isp/software_isp.cpp | 10 ++++++--
>  3 files changed, 38 insertions(+), 2 deletions(-)
> 
> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
> index 7b9e02d9..cfe41447 100644
> --- a/src/libcamera/software_isp/debayer_egl.cpp
> +++ b/src/libcamera/software_isp/debayer_egl.cpp
> @@ -33,6 +33,34 @@ namespace libcamera {
>   * Implements an EGL shader based debayering solution.
>   */
>  
> +/**
> + * \brief Probe whether EGL surfaceless rendering is available
> + *
> + * Performs a lightweight check by attempting to obtain an EGL display using
> + * EGL_PLATFORM_SURFACELESS_MESA and initialising it. The display is
> + * immediately released so that no resources are leaked. This allows the
> + * caller to decide at construction time whether to instantiate DebayerEGL
> + * or fall back to DebayerCpu.
> + *
> + * \return true if EGL surfaceless rendering is available, false otherwise
> + */
> +bool DebayerEGL::isEGLAvailable()
> +{
> +	if (!eglBindAPI(EGL_OPENGL_ES_API))
> +		return false;
> +
> +	EGLDisplay display = eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA,
> +						    EGL_DEFAULT_DISPLAY,
> +						    nullptr);
> +	if (display == EGL_NO_DISPLAY)
> +		return false;
> +
> +	EGLBoolean ret = eglInitialize(display, nullptr, nullptr);
> +	eglTerminate(display);
> +
> +	return ret == EGL_TRUE;
> +}
> +
>  /**
>   * \brief Construct a DebayerEGL object
>   * \param[in] stats Statistics processing object
> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
> index 141fb288..945125cd 100644
> --- a/src/libcamera/software_isp/debayer_egl.h
> +++ b/src/libcamera/software_isp/debayer_egl.h
> @@ -39,6 +39,8 @@ class CameraManager;
>  class DebayerEGL : public Debayer
>  {
>  public:
> +	static bool isEGLAvailable();
> +
>  	DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm);
>  	~DebayerEGL();
>  
> diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
> index 781cf02f..403efbdb 100644
> --- a/src/libcamera/software_isp/software_isp.cpp
> +++ b/src/libcamera/software_isp/software_isp.cpp
> @@ -119,8 +119,14 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,
>  		}
>  	}
>  
> -	if (!softISPMode || softISPMode == "gpu")
> -		debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm);
> +	if (!softISPMode || softISPMode == "gpu") {
> +		if (DebayerEGL::isEGLAvailable()) {
> +			debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm);
> +		} else {
> +			LOG(SoftwareIsp, Info)
> +				<< "EGL not available, falling back to CPU debayer";
> +		}
> +	}
>  
>  #endif
>  	if (!debayer_)

Patch
diff mbox series

diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 7b9e02d9..cfe41447 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -33,6 +33,34 @@  namespace libcamera {
  * Implements an EGL shader based debayering solution.
  */
 
+/**
+ * \brief Probe whether EGL surfaceless rendering is available
+ *
+ * Performs a lightweight check by attempting to obtain an EGL display using
+ * EGL_PLATFORM_SURFACELESS_MESA and initialising it. The display is
+ * immediately released so that no resources are leaked. This allows the
+ * caller to decide at construction time whether to instantiate DebayerEGL
+ * or fall back to DebayerCpu.
+ *
+ * \return true if EGL surfaceless rendering is available, false otherwise
+ */
+bool DebayerEGL::isEGLAvailable()
+{
+	if (!eglBindAPI(EGL_OPENGL_ES_API))
+		return false;
+
+	EGLDisplay display = eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA,
+						    EGL_DEFAULT_DISPLAY,
+						    nullptr);
+	if (display == EGL_NO_DISPLAY)
+		return false;
+
+	EGLBoolean ret = eglInitialize(display, nullptr, nullptr);
+	eglTerminate(display);
+
+	return ret == EGL_TRUE;
+}
+
 /**
  * \brief Construct a DebayerEGL object
  * \param[in] stats Statistics processing object
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
index 141fb288..945125cd 100644
--- a/src/libcamera/software_isp/debayer_egl.h
+++ b/src/libcamera/software_isp/debayer_egl.h
@@ -39,6 +39,8 @@  class CameraManager;
 class DebayerEGL : public Debayer
 {
 public:
+	static bool isEGLAvailable();
+
 	DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm);
 	~DebayerEGL();
 
diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
index 781cf02f..403efbdb 100644
--- a/src/libcamera/software_isp/software_isp.cpp
+++ b/src/libcamera/software_isp/software_isp.cpp
@@ -119,8 +119,14 @@  SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,
 		}
 	}
 
-	if (!softISPMode || softISPMode == "gpu")
-		debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm);
+	if (!softISPMode || softISPMode == "gpu") {
+		if (DebayerEGL::isEGLAvailable()) {
+			debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm);
+		} else {
+			LOG(SoftwareIsp, Info)
+				<< "EGL not available, falling back to CPU debayer";
+		}
+	}
 
 #endif
 	if (!debayer_)