From af85a5c96533b66df15af277ccae2431f6e8decf Mon Sep 17 00:00:00 2001 From: Thomas Senyk Date: Wed, 14 Dec 2022 08:20:36 +0100 Subject: [PATCH] Add QEGLContext::invalidateContext QEGLContext::invalidateContext will mark that egl context is invalide and trigger SceneGraph to destroy it, create a new one and re-create and re-upload all resources (e.g. textures) associated with the current state of the SceneGraph In addition this change also improves QEglFSWindow::invalidateSurface() and QEglFSContext::eglSurfaceForPlatformSurface(..) Where QEglFSWindow::invalidateSurface() will now destroy the corresponding EGLSurface via eglDestroySurface, including "unbinding" it from the current thread via eglMakeCurrent and un-setting the screen's EGLSurface in case it's the same resource. QEglFSContext::eglSurfaceForPlatformSurface(..) will now call QEglFSWindow::resetSurface() in case of getting a EGL_NO_SURFACE from the QEglFSWindow (which happens if above invalidateSurface() was called before) - therefor re-creating the resource if it was destoyed via QEglFSWindow::invalidateSurface() Change-Id: I37badd1fc11e993c395fb1502e9bd27ebe18b821 Reviewed-by: Laszlo Agocs (cherry picked from commit 17a59f661398bf56aeaba4187f55d07eea09c578) Reviewed-by: Qt Cherry-pick Bot --- src/gui/kernel/qopenglcontext_platform.h | 2 ++ .../platform/egl/qeglplatformcontext_p.h | 6 ++++- .../platform/unix/qunixnativeinterface.cpp | 16 ++++++++++++ .../platforms/eglfs/api/qeglfscontext.cpp | 15 ++++++++--- .../platforms/eglfs/api/qeglfswindow.cpp | 25 ++++++++++++++++++- 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/gui/kernel/qopenglcontext_platform.h b/src/gui/kernel/qopenglcontext_platform.h index fe36478a653..1f84cf6ce3c 100644 --- a/src/gui/kernel/qopenglcontext_platform.h +++ b/src/gui/kernel/qopenglcontext_platform.h @@ -79,6 +79,8 @@ struct Q_GUI_EXPORT QEGLContext virtual EGLContext nativeContext() const = 0; virtual EGLConfig config() const = 0; virtual EGLDisplay display() const = 0; + + virtual void invalidateContext() = 0; }; #endif diff --git a/src/gui/opengl/platform/egl/qeglplatformcontext_p.h b/src/gui/opengl/platform/egl/qeglplatformcontext_p.h index 556fbabee4f..b1e9c4b4c26 100644 --- a/src/gui/opengl/platform/egl/qeglplatformcontext_p.h +++ b/src/gui/opengl/platform/egl/qeglplatformcontext_p.h @@ -69,12 +69,14 @@ public: QSurfaceFormat format() const override; bool isSharing() const override { return m_shareContext != EGL_NO_CONTEXT; } - bool isValid() const override { return m_eglContext != EGL_NO_CONTEXT; } + bool isValid() const override { return m_eglContext != EGL_NO_CONTEXT && !m_markedInvalid; } EGLContext nativeContext() const override { return eglContext(); } EGLConfig config() const override { return eglConfig(); } EGLDisplay display() const override { return eglDisplay(); } + virtual void invalidateContext() override { m_markedInvalid = true; } + EGLContext eglContext() const; EGLDisplay eglDisplay() const; EGLConfig eglConfig() const; @@ -102,6 +104,8 @@ private: Flags m_flags; bool m_ownsContext = false; QList m_contextAttrs; + + bool m_markedInvalid = false; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QEGLPlatformContext::Flags) diff --git a/src/gui/platform/unix/qunixnativeinterface.cpp b/src/gui/platform/unix/qunixnativeinterface.cpp index 1cca97b34c8..1f891de0f50 100644 --- a/src/gui/platform/unix/qunixnativeinterface.cpp +++ b/src/gui/platform/unix/qunixnativeinterface.cpp @@ -123,6 +123,22 @@ QOpenGLContext *QNativeInterface::QGLXContext::fromNative(GLXContext visualBased \return the EGLDisplay associated with the underlying EGLContext. */ + +/*! + \fn void QNativeInterface::QEGLContext::invalidateContext() + \since 6.5 + \brief Marks the context as invalid + + If this context is used by the Qt Quick scenegraph, this will trigger the + SceneGraph to destroy this context and create a new one. + + Similarly to QPlatformWindow::invalidateSurface(), + this function can only be expected to have an effect on certain platforms, + such as eglfs. + + \sa QOpenGLContext::isValid(), QPlatformWindow::invalidateSurface() +*/ + QT_DEFINE_NATIVE_INTERFACE(QEGLContext); QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QEGLIntegration); diff --git a/src/plugins/platforms/eglfs/api/qeglfscontext.cpp b/src/plugins/platforms/eglfs/api/qeglfscontext.cpp index a17b567b24a..9c10c1a998c 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfscontext.cpp @@ -22,10 +22,19 @@ QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContex EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { - if (surface->surface()->surfaceClass() == QSurface::Window) - return static_cast(surface)->surface(); - else + if (surface->surface()->surfaceClass() == QSurface::Window) { + + QEglFSWindow *w = static_cast(surface); + EGLSurface s = w->surface(); + if (s == EGL_NO_SURFACE) { + w->resetSurface(); + s = w->surface(); + } + return s; + + } else { return static_cast(surface)->pbuffer(); + } } EGLSurface QEglFSContext::createTemporaryOffscreenSurface() diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp index bbd0b8ed685..1a31f97d7b8 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp @@ -22,6 +22,8 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(qLcEglDevDebug) + QEglFSWindow::QEglFSWindow(QWindow *w) : QPlatformWindow(w), #ifndef QT_NO_OPENGL @@ -162,8 +164,29 @@ void QEglFSWindow::destroy() void QEglFSWindow::invalidateSurface() { if (m_surface != EGL_NO_SURFACE) { - eglDestroySurface(screen()->display(), m_surface); + qCDebug(qLcEglDevDebug) << Q_FUNC_INFO << " about to destroy EGLSurface: " << m_surface; + + bool ok = eglDestroySurface(screen()->display(), m_surface); + + if (!ok) { + qCWarning(qLcEglDevDebug, "QEglFSWindow::invalidateSurface() eglDestroySurface failed!" + " Follow-up errors or memory leaks are possible." + " eglGetError(): %x", eglGetError()); + } + + if (eglGetCurrentSurface(EGL_READ) == m_surface || + eglGetCurrentSurface(EGL_DRAW) == m_surface) { + bool ok = eglMakeCurrent(eglGetCurrentDisplay(), EGL_NO_DISPLAY, EGL_NO_DISPLAY, EGL_NO_CONTEXT); + qCDebug(qLcEglDevDebug) << Q_FUNC_INFO << " due to eglDestroySurface on *currently* bound surface" + << "we just called eglMakeCurrent(..,0,0,0)! It returned: " << ok; + } + + if (screen()->primarySurface() == m_surface) + screen()->setPrimarySurface(EGL_NO_SURFACE); + + m_surface = EGL_NO_SURFACE; + m_flags = m_flags & ~Created; } qt_egl_device_integration()->destroyNativeWindow(m_window); m_window = 0;