@@ -103,6 +103,7 @@ public:
~eGL();
int initEGLContext();
+ static bool isAvailable();
int createInputDMABufTexture2D(eGLImage &eglImage, int fd);
int createOutputDMABufTexture2D(eGLImage &eglImage, int fd);
@@ -133,6 +134,7 @@ private:
EGLContext context_ = EGL_NO_CONTEXT;
EGLSurface surface_ = EGL_NO_SURFACE;
+ static EGLDisplay probeDisplay();
int compileShader(int shaderType, GLuint &shaderId, const unsigned char *shaderData,
unsigned int shaderDataLen,
Span<const std::string> shaderEnv);
@@ -267,6 +267,50 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
+EGLDisplay eGL::probeDisplay()
+{
+ EGLDisplay display;
+
+ if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+ LOG(eGL, Info) << "API bind fail";
+ return EGL_NO_DISPLAY;
+ }
+
+ display = eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA,
+ EGL_DEFAULT_DISPLAY,
+ nullptr);
+
+ if (display == EGL_NO_DISPLAY) {
+ LOG(eGL, Info) << "Unable to get EGL display";
+ return EGL_NO_DISPLAY;
+ }
+
+ if (eglInitialize(display, nullptr, nullptr) != EGL_TRUE) {
+ LOG(eGL, Error) << "eglInitialize fail";
+ return EGL_NO_DISPLAY;
+ }
+
+ return display;
+}
+
+/**
+ * \brief Probe whether EGL surfaceless rendering is available
+ *
+ * Checks if an EGL surfaceless display can be obtained and initialised.
+ * The display is immediately terminated so that no resources are leaked.
+ *
+ * \return true if EGL surfaceless rendering is available, false otherwise
+ */
+bool eGL::isAvailable()
+{
+ EGLDisplay display = probeDisplay();
+ if (display == EGL_NO_DISPLAY)
+ return false;
+
+ eglTerminate(display);
+ return true;
+}
+
/**
* \brief Initialise the EGL context
*
@@ -297,21 +341,9 @@ int eGL::initEGLContext()
EGLint numConfigs;
EGLConfig config;
- if (!eglBindAPI(EGL_OPENGL_ES_API)) {
- LOG(eGL, Error) << "API bind fail";
- goto fail;
- }
-
- display_ = eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA,
- EGL_DEFAULT_DISPLAY,
- nullptr);
+ display_ = probeDisplay();
if (display_ == EGL_NO_DISPLAY) {
- LOG(eGL, Error) << "Unable to get EGL display";
- goto fail;
- }
-
- if (eglInitialize(display_, nullptr, nullptr) != EGL_TRUE) {
- LOG(eGL, Error) << "eglInitialize fail";
+ LOG(eGL, Error) << "Unable to probe display";
goto fail;
}
@@ -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 (eGL::isAvailable()) {
+ debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm);
+ } else {
+ LOG(SoftwareIsp, Info)
+ << "EGL not available, falling back to CPU debayer";
+ }
+ }
#endif
if (!debayer_)
When HAVE_DEBAYER_EGL is enabled, the SoftwareIsp constructor unconditionally creates a DebayerEGL instance. If the platform lacks EGL surfaceless support, DebayerEGL::start() fails with -ENODEV after SwStatsCpu ownership has already been moved, making fallback to DebayerCpu impossible. Add a static eGL::isAvailable() method that probes whether EGL surfaceless rendering can be initialised. Extract the common display obtaining logic (eglBindAPI, eglGetPlatformDisplay, eglInitialize) into a private eGL::probeDisplay() helper that is shared by both isAvailable() and initEGLContext(), avoiding code duplication. The SoftwareIsp constructor now calls eGL::isAvailable() before creating DebayerEGL. If EGL is not available, the existing fallback path creates a DebayerCpu instance instead. Signed-off-by: Qi Hou <qi.hou@nxp.com> --- include/libcamera/internal/egl.h | 2 + src/libcamera/egl.cpp | 60 ++++++++++++++++----- src/libcamera/software_isp/software_isp.cpp | 10 +++- 3 files changed, 56 insertions(+), 16 deletions(-)