| Message ID | 20260729025557.2261274-1-qi.hou@oss.nxp.com |
|---|---|
| State | Accepted |
| Headers | show |
| Series |
|
| Related | show |
2026. 07. 29. 4:55 keltezéssel, qi.hou@oss.nxp.com írta: > From: Qi Hou <qi.hou@nxp.com> > > isAvailable() previously called probeDisplay() to run a full EGL > initialisation sequence and then immediately terminated the display with > eglTerminate(). When SoftwareIsp subsequently created a DebayerEGL > instance, initEGLContext() would call probeDisplay() again, repeating > the full initialisation. > > Fix this by reusing the display obtained during the availability check. > probeDisplay() is promoted to a public static method and isAvailable() > is removed. The eGL constructor now takes the EGLDisplay as a parameter > and stores it directly, so initEGLContext() no longer needs to call > probeDisplay(). DebayerEGL is updated to accept and forward the display > to eGL, and SoftwareIsp calls eGL::probeDisplay() once, passing the > result straight to DebayerEGL when EGL is available. > > Signed-off-by: Qi Hou <qi.hou@nxp.com> > --- Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # intel-ipu6 + ov2740 + mesa 26.1.5 It seems to work, no output with `MESA_DEBUG=1`, and I might have very well missed it, but I couldn't find any obvious prohibition of what is suggested here. > include/libcamera/internal/egl.h | 5 +-- > src/libcamera/egl.cpp | 42 +++++++-------------- > src/libcamera/software_isp/debayer_egl.cpp | 5 ++- > src/libcamera/software_isp/debayer_egl.h | 2 +- > src/libcamera/software_isp/software_isp.cpp | 5 ++- > 5 files changed, 23 insertions(+), 36 deletions(-) > > diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h > index 1e31d490b..7ef1ca0d9 100644 > --- a/include/libcamera/internal/egl.h > +++ b/include/libcamera/internal/egl.h > @@ -99,11 +99,11 @@ private: > class eGL > { > public: > - eGL(); > + eGL(EGLDisplay display); > ~eGL(); > > int initEGLContext(); > - static bool isAvailable(); > + static EGLDisplay probeDisplay(); > > int createInputDMABufTexture2D(eGLImage &eglImage, int fd); > int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); > @@ -137,7 +137,6 @@ private: > EGLContext context_ = EGL_NO_CONTEXT; > EGLSurface surface_ = EGL_NO_SURFACE; > > - static EGLDisplay probeDisplay(); > int compileShader(int shaderType, GLuint &shaderId, Span<const unsigned char> shaderData, > Span<const std::string> shaderEnv); > > diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp > index 7ec7a654d..01e51cda8 100644 > --- a/src/libcamera/egl.cpp > +++ b/src/libcamera/egl.cpp > @@ -64,12 +64,15 @@ LOG_DEFINE_CATEGORY(eGL) > > /** > * \brief Construct an EGL helper > + * \param[in] display The EGL display to use > * > * Creates an eGL instance with uninitialised context. Call initEGLContext() > - * to set up the EGL display, context, and load extension functions. > + * to set up the EGL context, and load extension functions. > */ > -eGL::eGL() > +eGL::eGL(EGLDisplay display) > + : display_(display) > { > + ASSERT(display_ != EGL_NO_DISPLAY); > } > > /** > @@ -299,15 +302,17 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data) > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); > } > > +/** > + * \brief Try to create an EGL display for surfaceless rendering > + * > + * Tries to create an EGL display for surfaceless rendering. > + * > + * \return A EGL display handle if successful, otherwise \a EGL_NO_DISPLAY > + */ > 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); > @@ -325,24 +330,6 @@ EGLDisplay eGL::probeDisplay() > 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 Update a 2D texture already created > * \param[in,out] eglImage EGL image to associate with the texture > @@ -403,9 +390,8 @@ int eGL::initEGLContext() > EGLint numConfigs; > EGLConfig config; > > - display_ = probeDisplay(); > - if (display_ == EGL_NO_DISPLAY) { > - LOG(eGL, Error) << "Unable to probe display"; > + if (!eglBindAPI(EGL_OPENGL_ES_API)) { > + LOG(eGL, Error) << "API bind fail"; > goto fail; > } > > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp > index dd2041219..20b478b1c 100644 > --- a/src/libcamera/software_isp/debayer_egl.cpp > +++ b/src/libcamera/software_isp/debayer_egl.cpp > @@ -40,9 +40,10 @@ namespace libcamera { > * \brief Construct a DebayerEGL object > * \param[in] stats Statistics processing object > * \param[in] cm The camera manager > + * \param[in] display The EGL display to use > */ > -DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) > - : Debayer(cm), stats_(std::move(stats)) > +DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display) > + : Debayer(cm), stats_(std::move(stats)), egl_(display) > { > } > > diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h > index e613639f5..30e51a477 100644 > --- a/src/libcamera/software_isp/debayer_egl.h > +++ b/src/libcamera/software_isp/debayer_egl.h > @@ -40,7 +40,7 @@ class CameraManager; > class DebayerEGL : public Debayer > { > public: > - DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm); > + DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display); > ~DebayerEGL(); > > int configure(const StreamConfiguration &inputCfg, > diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp > index c73a16ce0..c7165771c 100644 > --- a/src/libcamera/software_isp/software_isp.cpp > +++ b/src/libcamera/software_isp/software_isp.cpp > @@ -120,8 +120,9 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, > } > > if (!softISPMode || softISPMode == "gpu") { > - if (eGL::isAvailable()) { > - debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm); > + auto display = eGL::probeDisplay(); > + if (display != EGL_NO_DISPLAY) { > + debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm, display); > } else { > LOG(SoftwareIsp, Info) > << "EGL not available, falling back to CPU debayer";
Hi Qi Hou On Wed, Jul 29, 2026 at 11:55:57AM +0900, qi.hou@oss.nxp.com wrote: > From: Qi Hou <qi.hou@nxp.com> > > isAvailable() previously called probeDisplay() to run a full EGL > initialisation sequence and then immediately terminated the display with > eglTerminate(). When SoftwareIsp subsequently created a DebayerEGL > instance, initEGLContext() would call probeDisplay() again, repeating > the full initialisation. > > Fix this by reusing the display obtained during the availability check. > probeDisplay() is promoted to a public static method and isAvailable() > is removed. The eGL constructor now takes the EGLDisplay as a parameter > and stores it directly, so initEGLContext() no longer needs to call > probeDisplay(). DebayerEGL is updated to accept and forward the display > to eGL, and SoftwareIsp calls eGL::probeDisplay() once, passing the > result straight to DebayerEGL when EGL is available. > > Signed-off-by: Qi Hou <qi.hou@nxp.com> > --- > include/libcamera/internal/egl.h | 5 +-- > src/libcamera/egl.cpp | 42 +++++++-------------- > src/libcamera/software_isp/debayer_egl.cpp | 5 ++- > src/libcamera/software_isp/debayer_egl.h | 2 +- > src/libcamera/software_isp/software_isp.cpp | 5 ++- > 5 files changed, 23 insertions(+), 36 deletions(-) > > diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h > index 1e31d490b..7ef1ca0d9 100644 > --- a/include/libcamera/internal/egl.h > +++ b/include/libcamera/internal/egl.h > @@ -99,11 +99,11 @@ private: > class eGL > { > public: > - eGL(); > + eGL(EGLDisplay display); > ~eGL(); > > int initEGLContext(); > - static bool isAvailable(); > + static EGLDisplay probeDisplay(); > > int createInputDMABufTexture2D(eGLImage &eglImage, int fd); > int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); > @@ -137,7 +137,6 @@ private: > EGLContext context_ = EGL_NO_CONTEXT; > EGLSurface surface_ = EGL_NO_SURFACE; > > - static EGLDisplay probeDisplay(); > int compileShader(int shaderType, GLuint &shaderId, Span<const unsigned char> shaderData, > Span<const std::string> shaderEnv); > > diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp > index 7ec7a654d..01e51cda8 100644 > --- a/src/libcamera/egl.cpp > +++ b/src/libcamera/egl.cpp > @@ -64,12 +64,15 @@ LOG_DEFINE_CATEGORY(eGL) > > /** > * \brief Construct an EGL helper > + * \param[in] display The EGL display to use > * > * Creates an eGL instance with uninitialised context. Call initEGLContext() > - * to set up the EGL display, context, and load extension functions. > + * to set up the EGL context, and load extension functions. > */ > -eGL::eGL() > +eGL::eGL(EGLDisplay display) > + : display_(display) If I'm not mistaken (not an expert of this area) EGLDisplay is a pointer /usr/include/EGL/egl.h:typedef void *EGLDisplay; so we are not concerned about passing it around by value, right ? > { > + ASSERT(display_ != EGL_NO_DISPLAY); > } > > /** > @@ -299,15 +302,17 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data) > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); > } > > +/** > + * \brief Try to create an EGL display for surfaceless rendering > + * > + * Tries to create an EGL display for surfaceless rendering. > + * > + * \return A EGL display handle if successful, otherwise \a EGL_NO_DISPLAY > + */ > 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); > @@ -325,24 +330,6 @@ EGLDisplay eGL::probeDisplay() > 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 Update a 2D texture already created > * \param[in,out] eglImage EGL image to associate with the texture > @@ -403,9 +390,8 @@ int eGL::initEGLContext() > EGLint numConfigs; > EGLConfig config; > > - display_ = probeDisplay(); > - if (display_ == EGL_NO_DISPLAY) { > - LOG(eGL, Error) << "Unable to probe display"; > + if (!eglBindAPI(EGL_OPENGL_ES_API)) { > + LOG(eGL, Error) << "API bind fail"; > goto fail; Should this check remain in probeDisplay() ? If this check fails (in probeDisplay()) you return EGL_NO_DISPLAY and the eGL class constructor now has ASSERT(display_ != EGL_NO_DISPLAY); so if you get here you should be safe ? Or have I missed something ? Thanks j > } > > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp > index dd2041219..20b478b1c 100644 > --- a/src/libcamera/software_isp/debayer_egl.cpp > +++ b/src/libcamera/software_isp/debayer_egl.cpp > @@ -40,9 +40,10 @@ namespace libcamera { > * \brief Construct a DebayerEGL object > * \param[in] stats Statistics processing object > * \param[in] cm The camera manager > + * \param[in] display The EGL display to use > */ > -DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) > - : Debayer(cm), stats_(std::move(stats)) > +DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display) > + : Debayer(cm), stats_(std::move(stats)), egl_(display) > { > } > > diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h > index e613639f5..30e51a477 100644 > --- a/src/libcamera/software_isp/debayer_egl.h > +++ b/src/libcamera/software_isp/debayer_egl.h > @@ -40,7 +40,7 @@ class CameraManager; > class DebayerEGL : public Debayer > { > public: > - DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm); > + DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display); > ~DebayerEGL(); > > int configure(const StreamConfiguration &inputCfg, > diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp > index c73a16ce0..c7165771c 100644 > --- a/src/libcamera/software_isp/software_isp.cpp > +++ b/src/libcamera/software_isp/software_isp.cpp > @@ -120,8 +120,9 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, > } > > if (!softISPMode || softISPMode == "gpu") { > - if (eGL::isAvailable()) { > - debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm); > + auto display = eGL::probeDisplay(); > + if (display != EGL_NO_DISPLAY) { > + debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm, display); > } else { > LOG(SoftwareIsp, Info) > << "EGL not available, falling back to CPU debayer"; > -- > 2.34.1 >
2026. 07. 31. 15:01 keltezéssel, Jacopo Mondi írta: > Hi Qi Hou > > On Wed, Jul 29, 2026 at 11:55:57AM +0900, qi.hou@oss.nxp.com wrote: >> From: Qi Hou <qi.hou@nxp.com> >> >> isAvailable() previously called probeDisplay() to run a full EGL >> initialisation sequence and then immediately terminated the display with >> eglTerminate(). When SoftwareIsp subsequently created a DebayerEGL >> instance, initEGLContext() would call probeDisplay() again, repeating >> the full initialisation. >> >> Fix this by reusing the display obtained during the availability check. >> probeDisplay() is promoted to a public static method and isAvailable() >> is removed. The eGL constructor now takes the EGLDisplay as a parameter >> and stores it directly, so initEGLContext() no longer needs to call >> probeDisplay(). DebayerEGL is updated to accept and forward the display >> to eGL, and SoftwareIsp calls eGL::probeDisplay() once, passing the >> result straight to DebayerEGL when EGL is available. >> >> Signed-off-by: Qi Hou <qi.hou@nxp.com> >> --- >> include/libcamera/internal/egl.h | 5 +-- >> src/libcamera/egl.cpp | 42 +++++++-------------- >> src/libcamera/software_isp/debayer_egl.cpp | 5 ++- >> src/libcamera/software_isp/debayer_egl.h | 2 +- >> src/libcamera/software_isp/software_isp.cpp | 5 ++- >> 5 files changed, 23 insertions(+), 36 deletions(-) >> >> diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h >> index 1e31d490b..7ef1ca0d9 100644 >> --- a/include/libcamera/internal/egl.h >> +++ b/include/libcamera/internal/egl.h >> @@ -99,11 +99,11 @@ private: >> class eGL >> { >> public: >> - eGL(); >> + eGL(EGLDisplay display); >> ~eGL(); >> >> int initEGLContext(); >> - static bool isAvailable(); >> + static EGLDisplay probeDisplay(); >> >> int createInputDMABufTexture2D(eGLImage &eglImage, int fd); >> int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); >> @@ -137,7 +137,6 @@ private: >> EGLContext context_ = EGL_NO_CONTEXT; >> EGLSurface surface_ = EGL_NO_SURFACE; >> >> - static EGLDisplay probeDisplay(); >> int compileShader(int shaderType, GLuint &shaderId, Span<const unsigned char> shaderData, >> Span<const std::string> shaderEnv); >> >> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp >> index 7ec7a654d..01e51cda8 100644 >> --- a/src/libcamera/egl.cpp >> +++ b/src/libcamera/egl.cpp >> @@ -64,12 +64,15 @@ LOG_DEFINE_CATEGORY(eGL) >> >> /** >> * \brief Construct an EGL helper >> + * \param[in] display The EGL display to use >> * >> * Creates an eGL instance with uninitialised context. Call initEGLContext() >> - * to set up the EGL display, context, and load extension functions. >> + * to set up the EGL context, and load extension functions. >> */ >> -eGL::eGL() >> +eGL::eGL(EGLDisplay display) >> + : display_(display) > > If I'm not mistaken (not an expert of this area) EGLDisplay is a > pointer > > /usr/include/EGL/egl.h:typedef void *EGLDisplay; > > so we are not concerned about passing it around by value, right ? > >> { >> + ASSERT(display_ != EGL_NO_DISPLAY); >> } >> >> /** >> @@ -299,15 +302,17 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data) >> glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); >> } >> >> +/** >> + * \brief Try to create an EGL display for surfaceless rendering >> + * >> + * Tries to create an EGL display for surfaceless rendering. >> + * >> + * \return A EGL display handle if successful, otherwise \a EGL_NO_DISPLAY >> + */ >> 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); >> @@ -325,24 +330,6 @@ EGLDisplay eGL::probeDisplay() >> 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 Update a 2D texture already created >> * \param[in,out] eglImage EGL image to associate with the texture >> @@ -403,9 +390,8 @@ int eGL::initEGLContext() >> EGLint numConfigs; >> EGLConfig config; >> >> - display_ = probeDisplay(); >> - if (display_ == EGL_NO_DISPLAY) { >> - LOG(eGL, Error) << "Unable to probe display"; >> + if (!eglBindAPI(EGL_OPENGL_ES_API)) { >> + LOG(eGL, Error) << "API bind fail"; >> goto fail; > > Should this check remain in probeDisplay() ? > > If this check fails (in probeDisplay()) you return EGL_NO_DISPLAY and > the eGL class constructor now has > > ASSERT(display_ != EGL_NO_DISPLAY); > > so if you get here you should be safe ? > > Or have I missed something ? I suggested moving it in the previous version because * it affects per-thread state in the egl library, * the display creation should work without it (as far as I can tell). > > Thanks > j > >> } >> >> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp >> index dd2041219..20b478b1c 100644 >> --- a/src/libcamera/software_isp/debayer_egl.cpp >> +++ b/src/libcamera/software_isp/debayer_egl.cpp >> @@ -40,9 +40,10 @@ namespace libcamera { >> * \brief Construct a DebayerEGL object >> * \param[in] stats Statistics processing object >> * \param[in] cm The camera manager >> + * \param[in] display The EGL display to use >> */ >> -DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) >> - : Debayer(cm), stats_(std::move(stats)) >> +DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display) >> + : Debayer(cm), stats_(std::move(stats)), egl_(display) >> { >> } >> >> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h >> index e613639f5..30e51a477 100644 >> --- a/src/libcamera/software_isp/debayer_egl.h >> +++ b/src/libcamera/software_isp/debayer_egl.h >> @@ -40,7 +40,7 @@ class CameraManager; >> class DebayerEGL : public Debayer >> { >> public: >> - DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm); >> + DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display); >> ~DebayerEGL(); >> >> int configure(const StreamConfiguration &inputCfg, >> diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp >> index c73a16ce0..c7165771c 100644 >> --- a/src/libcamera/software_isp/software_isp.cpp >> +++ b/src/libcamera/software_isp/software_isp.cpp >> @@ -120,8 +120,9 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, >> } >> >> if (!softISPMode || softISPMode == "gpu") { >> - if (eGL::isAvailable()) { >> - debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm); >> + auto display = eGL::probeDisplay(); >> + if (display != EGL_NO_DISPLAY) { >> + debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm, display); >> } else { >> LOG(SoftwareIsp, Info) >> << "EGL not available, falling back to CPU debayer"; >> -- >> 2.34.1 >>
Hi Barnabás On Fri, Jul 31, 2026 at 03:04:23PM +0200, Barnabás Pőcze wrote: > 2026. 07. 31. 15:01 keltezéssel, Jacopo Mondi írta: > > Hi Qi Hou > > > > On Wed, Jul 29, 2026 at 11:55:57AM +0900, qi.hou@oss.nxp.com wrote: > > > From: Qi Hou <qi.hou@nxp.com> > > > > > > isAvailable() previously called probeDisplay() to run a full EGL > > > initialisation sequence and then immediately terminated the display with > > > eglTerminate(). When SoftwareIsp subsequently created a DebayerEGL > > > instance, initEGLContext() would call probeDisplay() again, repeating > > > the full initialisation. > > > > > > Fix this by reusing the display obtained during the availability check. > > > probeDisplay() is promoted to a public static method and isAvailable() > > > is removed. The eGL constructor now takes the EGLDisplay as a parameter > > > and stores it directly, so initEGLContext() no longer needs to call > > > probeDisplay(). DebayerEGL is updated to accept and forward the display > > > to eGL, and SoftwareIsp calls eGL::probeDisplay() once, passing the > > > result straight to DebayerEGL when EGL is available. > > > > > > Signed-off-by: Qi Hou <qi.hou@nxp.com> > > > --- > > > include/libcamera/internal/egl.h | 5 +-- > > > src/libcamera/egl.cpp | 42 +++++++-------------- > > > src/libcamera/software_isp/debayer_egl.cpp | 5 ++- > > > src/libcamera/software_isp/debayer_egl.h | 2 +- > > > src/libcamera/software_isp/software_isp.cpp | 5 ++- > > > 5 files changed, 23 insertions(+), 36 deletions(-) > > > > > > diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h > > > index 1e31d490b..7ef1ca0d9 100644 > > > --- a/include/libcamera/internal/egl.h > > > +++ b/include/libcamera/internal/egl.h > > > @@ -99,11 +99,11 @@ private: > > > class eGL > > > { > > > public: > > > - eGL(); > > > + eGL(EGLDisplay display); > > > ~eGL(); > > > > > > int initEGLContext(); > > > - static bool isAvailable(); > > > + static EGLDisplay probeDisplay(); > > > > > > int createInputDMABufTexture2D(eGLImage &eglImage, int fd); > > > int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); > > > @@ -137,7 +137,6 @@ private: > > > EGLContext context_ = EGL_NO_CONTEXT; > > > EGLSurface surface_ = EGL_NO_SURFACE; > > > > > > - static EGLDisplay probeDisplay(); > > > int compileShader(int shaderType, GLuint &shaderId, Span<const unsigned char> shaderData, > > > Span<const std::string> shaderEnv); > > > > > > diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp > > > index 7ec7a654d..01e51cda8 100644 > > > --- a/src/libcamera/egl.cpp > > > +++ b/src/libcamera/egl.cpp > > > @@ -64,12 +64,15 @@ LOG_DEFINE_CATEGORY(eGL) > > > > > > /** > > > * \brief Construct an EGL helper > > > + * \param[in] display The EGL display to use > > > * > > > * Creates an eGL instance with uninitialised context. Call initEGLContext() > > > - * to set up the EGL display, context, and load extension functions. > > > + * to set up the EGL context, and load extension functions. > > > */ > > > -eGL::eGL() > > > +eGL::eGL(EGLDisplay display) > > > + : display_(display) > > > > If I'm not mistaken (not an expert of this area) EGLDisplay is a > > pointer > > > > /usr/include/EGL/egl.h:typedef void *EGLDisplay; > > > > so we are not concerned about passing it around by value, right ? > > > > > { > > > + ASSERT(display_ != EGL_NO_DISPLAY); > > > } > > > > > > /** > > > @@ -299,15 +302,17 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data) > > > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); > > > } > > > > > > +/** > > > + * \brief Try to create an EGL display for surfaceless rendering > > > + * > > > + * Tries to create an EGL display for surfaceless rendering. > > > + * > > > + * \return A EGL display handle if successful, otherwise \a EGL_NO_DISPLAY > > > + */ > > > 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); > > > @@ -325,24 +330,6 @@ EGLDisplay eGL::probeDisplay() > > > 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 Update a 2D texture already created > > > * \param[in,out] eglImage EGL image to associate with the texture > > > @@ -403,9 +390,8 @@ int eGL::initEGLContext() > > > EGLint numConfigs; > > > EGLConfig config; > > > > > > - display_ = probeDisplay(); > > > - if (display_ == EGL_NO_DISPLAY) { > > > - LOG(eGL, Error) << "Unable to probe display"; > > > + if (!eglBindAPI(EGL_OPENGL_ES_API)) { > > > + LOG(eGL, Error) << "API bind fail"; > > > goto fail; > > > > Should this check remain in probeDisplay() ? > > > > If this check fails (in probeDisplay()) you return EGL_NO_DISPLAY and > > the eGL class constructor now has > > > > ASSERT(display_ != EGL_NO_DISPLAY); > > > > so if you get here you should be safe ? > > > > Or have I missed something ? > > I suggested moving it in the previous version because > * it affects per-thread state in the egl library, > * the display creation should work without it (as far as I can tell). > Ah yes, I just read your comment on v2.. are you happy with me collecting this patch in this form then ? > > > > > Thanks > > j > > > > > } > > > > > > diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp > > > index dd2041219..20b478b1c 100644 > > > --- a/src/libcamera/software_isp/debayer_egl.cpp > > > +++ b/src/libcamera/software_isp/debayer_egl.cpp > > > @@ -40,9 +40,10 @@ namespace libcamera { > > > * \brief Construct a DebayerEGL object > > > * \param[in] stats Statistics processing object > > > * \param[in] cm The camera manager > > > + * \param[in] display The EGL display to use > > > */ > > > -DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) > > > - : Debayer(cm), stats_(std::move(stats)) > > > +DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display) > > > + : Debayer(cm), stats_(std::move(stats)), egl_(display) > > > { > > > } > > > > > > diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h > > > index e613639f5..30e51a477 100644 > > > --- a/src/libcamera/software_isp/debayer_egl.h > > > +++ b/src/libcamera/software_isp/debayer_egl.h > > > @@ -40,7 +40,7 @@ class CameraManager; > > > class DebayerEGL : public Debayer > > > { > > > public: > > > - DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm); > > > + DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display); > > > ~DebayerEGL(); > > > > > > int configure(const StreamConfiguration &inputCfg, > > > diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp > > > index c73a16ce0..c7165771c 100644 > > > --- a/src/libcamera/software_isp/software_isp.cpp > > > +++ b/src/libcamera/software_isp/software_isp.cpp > > > @@ -120,8 +120,9 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, > > > } > > > > > > if (!softISPMode || softISPMode == "gpu") { > > > - if (eGL::isAvailable()) { > > > - debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm); > > > + auto display = eGL::probeDisplay(); > > > + if (display != EGL_NO_DISPLAY) { > > > + debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm, display); > > > } else { > > > LOG(SoftwareIsp, Info) > > > << "EGL not available, falling back to CPU debayer"; > > > -- > > > 2.34.1 > > > >
Hi Jacopo Mondi, Yes, you're right. `EGLDisplay` is `typedef void *EGLDisplay`, passing and storing it by value is the standard EGL idiom. No concern here. Regards, Qi Hou -----Original Message----- From: Jacopo Mondi <jacopo.mondi@ideasonboard.com> Sent: Friday, July 31, 2026 9:02 PM To: Qi Hou (OSS) <qi.hou@oss.nxp.com> Cc: libcamera-devel@lists.libcamera.org; Jared Hu <jared.hu@nxp.com>; Julien Vuillaumier <julien.vuillaumier@nxp.com> Subject: Re: [PATCH v3] libcamera: egl: Pass EGLDisplay to eGL constructor to avoid double init Hi Qi Hou On Wed, Jul 29, 2026 at 11:55:57AM +0900, qi.hou@oss.nxp.com wrote: > From: Qi Hou <qi.hou@nxp.com> > > isAvailable() previously called probeDisplay() to run a full EGL > initialisation sequence and then immediately terminated the display > with eglTerminate(). When SoftwareIsp subsequently created a > DebayerEGL instance, initEGLContext() would call probeDisplay() again, > repeating the full initialisation. > > Fix this by reusing the display obtained during the availability check. > probeDisplay() is promoted to a public static method and isAvailable() > is removed. The eGL constructor now takes the EGLDisplay as a > parameter and stores it directly, so initEGLContext() no longer needs > to call probeDisplay(). DebayerEGL is updated to accept and forward > the display to eGL, and SoftwareIsp calls eGL::probeDisplay() once, > passing the result straight to DebayerEGL when EGL is available. > > Signed-off-by: Qi Hou <qi.hou@nxp.com> > --- > include/libcamera/internal/egl.h | 5 +-- > src/libcamera/egl.cpp | 42 +++++++-------------- > src/libcamera/software_isp/debayer_egl.cpp | 5 ++- > src/libcamera/software_isp/debayer_egl.h | 2 +- > src/libcamera/software_isp/software_isp.cpp | 5 ++- > 5 files changed, 23 insertions(+), 36 deletions(-) > > diff --git a/include/libcamera/internal/egl.h > b/include/libcamera/internal/egl.h > index 1e31d490b..7ef1ca0d9 100644 > --- a/include/libcamera/internal/egl.h > +++ b/include/libcamera/internal/egl.h > @@ -99,11 +99,11 @@ private: > class eGL > { > public: > - eGL(); > + eGL(EGLDisplay display); > ~eGL(); > > int initEGLContext(); > - static bool isAvailable(); > + static EGLDisplay probeDisplay(); > > int createInputDMABufTexture2D(eGLImage &eglImage, int fd); > int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); @@ > -137,7 +137,6 @@ private: > EGLContext context_ = EGL_NO_CONTEXT; > EGLSurface surface_ = EGL_NO_SURFACE; > > - static EGLDisplay probeDisplay(); > int compileShader(int shaderType, GLuint &shaderId, Span<const unsigned char> shaderData, > Span<const std::string> shaderEnv); > > diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp index > 7ec7a654d..01e51cda8 100644 > --- a/src/libcamera/egl.cpp > +++ b/src/libcamera/egl.cpp > @@ -64,12 +64,15 @@ LOG_DEFINE_CATEGORY(eGL) > > /** > * \brief Construct an EGL helper > + * \param[in] display The EGL display to use > * > * Creates an eGL instance with uninitialised context. Call > initEGLContext() > - * to set up the EGL display, context, and load extension functions. > + * to set up the EGL context, and load extension functions. > */ > -eGL::eGL() > +eGL::eGL(EGLDisplay display) > + : display_(display) If I'm not mistaken (not an expert of this area) EGLDisplay is a pointer /usr/include/EGL/egl.h:typedef void *EGLDisplay; so we are not concerned about passing it around by value, right ? > { > + ASSERT(display_ != EGL_NO_DISPLAY); > } > > /** > @@ -299,15 +302,17 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data) > glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); > } > > +/** > + * \brief Try to create an EGL display for surfaceless rendering > + * > + * Tries to create an EGL display for surfaceless rendering. > + * > + * \return A EGL display handle if successful, otherwise \a > +EGL_NO_DISPLAY */ > 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); > @@ -325,24 +330,6 @@ EGLDisplay eGL::probeDisplay() > 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 Update a 2D texture already created > * \param[in,out] eglImage EGL image to associate with the texture @@ > -403,9 +390,8 @@ int eGL::initEGLContext() > EGLint numConfigs; > EGLConfig config; > > - display_ = probeDisplay(); > - if (display_ == EGL_NO_DISPLAY) { > - LOG(eGL, Error) << "Unable to probe display"; > + if (!eglBindAPI(EGL_OPENGL_ES_API)) { > + LOG(eGL, Error) << "API bind fail"; > goto fail; Should this check remain in probeDisplay() ? If this check fails (in probeDisplay()) you return EGL_NO_DISPLAY and the eGL class constructor now has ASSERT(display_ != EGL_NO_DISPLAY); so if you get here you should be safe ? Or have I missed something ? Thanks j > } > > diff --git a/src/libcamera/software_isp/debayer_egl.cpp > b/src/libcamera/software_isp/debayer_egl.cpp > index dd2041219..20b478b1c 100644 > --- a/src/libcamera/software_isp/debayer_egl.cpp > +++ b/src/libcamera/software_isp/debayer_egl.cpp > @@ -40,9 +40,10 @@ namespace libcamera { > * \brief Construct a DebayerEGL object > * \param[in] stats Statistics processing object > * \param[in] cm The camera manager > + * \param[in] display The EGL display to use > */ > -DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) > - : Debayer(cm), stats_(std::move(stats)) > +DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display) > + : Debayer(cm), stats_(std::move(stats)), egl_(display) > { > } > > diff --git a/src/libcamera/software_isp/debayer_egl.h > b/src/libcamera/software_isp/debayer_egl.h > index e613639f5..30e51a477 100644 > --- a/src/libcamera/software_isp/debayer_egl.h > +++ b/src/libcamera/software_isp/debayer_egl.h > @@ -40,7 +40,7 @@ class CameraManager; class DebayerEGL : public > Debayer { > public: > - DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm); > + DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager > +&cm, EGLDisplay display); > ~DebayerEGL(); > > int configure(const StreamConfiguration &inputCfg, diff --git > a/src/libcamera/software_isp/software_isp.cpp > b/src/libcamera/software_isp/software_isp.cpp > index c73a16ce0..c7165771c 100644 > --- a/src/libcamera/software_isp/software_isp.cpp > +++ b/src/libcamera/software_isp/software_isp.cpp > @@ -120,8 +120,9 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, > } > > if (!softISPMode || softISPMode == "gpu") { > - if (eGL::isAvailable()) { > - debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm); > + auto display = eGL::probeDisplay(); > + if (display != EGL_NO_DISPLAY) { > + debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm, > +display); > } else { > LOG(SoftwareIsp, Info) > << "EGL not available, falling back to CPU debayer"; > -- > 2.34.1 >
diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h index 1e31d490b..7ef1ca0d9 100644 --- a/include/libcamera/internal/egl.h +++ b/include/libcamera/internal/egl.h @@ -99,11 +99,11 @@ private: class eGL { public: - eGL(); + eGL(EGLDisplay display); ~eGL(); int initEGLContext(); - static bool isAvailable(); + static EGLDisplay probeDisplay(); int createInputDMABufTexture2D(eGLImage &eglImage, int fd); int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); @@ -137,7 +137,6 @@ private: EGLContext context_ = EGL_NO_CONTEXT; EGLSurface surface_ = EGL_NO_SURFACE; - static EGLDisplay probeDisplay(); int compileShader(int shaderType, GLuint &shaderId, Span<const unsigned char> shaderData, Span<const std::string> shaderEnv); diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp index 7ec7a654d..01e51cda8 100644 --- a/src/libcamera/egl.cpp +++ b/src/libcamera/egl.cpp @@ -64,12 +64,15 @@ LOG_DEFINE_CATEGORY(eGL) /** * \brief Construct an EGL helper + * \param[in] display The EGL display to use * * Creates an eGL instance with uninitialised context. Call initEGLContext() - * to set up the EGL display, context, and load extension functions. + * to set up the EGL context, and load extension functions. */ -eGL::eGL() +eGL::eGL(EGLDisplay display) + : display_(display) { + ASSERT(display_ != EGL_NO_DISPLAY); } /** @@ -299,15 +302,17 @@ void eGL::createTexture2D(eGLImage &eglImage, void *data) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } +/** + * \brief Try to create an EGL display for surfaceless rendering + * + * Tries to create an EGL display for surfaceless rendering. + * + * \return A EGL display handle if successful, otherwise \a EGL_NO_DISPLAY + */ 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); @@ -325,24 +330,6 @@ EGLDisplay eGL::probeDisplay() 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 Update a 2D texture already created * \param[in,out] eglImage EGL image to associate with the texture @@ -403,9 +390,8 @@ int eGL::initEGLContext() EGLint numConfigs; EGLConfig config; - display_ = probeDisplay(); - if (display_ == EGL_NO_DISPLAY) { - LOG(eGL, Error) << "Unable to probe display"; + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + LOG(eGL, Error) << "API bind fail"; goto fail; } diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index dd2041219..20b478b1c 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -40,9 +40,10 @@ namespace libcamera { * \brief Construct a DebayerEGL object * \param[in] stats Statistics processing object * \param[in] cm The camera manager + * \param[in] display The EGL display to use */ -DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm) - : Debayer(cm), stats_(std::move(stats)) +DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display) + : Debayer(cm), stats_(std::move(stats)), egl_(display) { } diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index e613639f5..30e51a477 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -40,7 +40,7 @@ class CameraManager; class DebayerEGL : public Debayer { public: - DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm); + DebayerEGL(std::unique_ptr<SwStatsCpu> stats, const CameraManager &cm, EGLDisplay display); ~DebayerEGL(); int configure(const StreamConfiguration &inputCfg, diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index c73a16ce0..c7165771c 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -120,8 +120,9 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, } if (!softISPMode || softISPMode == "gpu") { - if (eGL::isAvailable()) { - debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm); + auto display = eGL::probeDisplay(); + if (display != EGL_NO_DISPLAY) { + debayer_ = std::make_unique<DebayerEGL>(std::move(stats), cm, display); } else { LOG(SoftwareIsp, Info) << "EGL not available, falling back to CPU debayer";