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 <laszlo.agocs@qt.io>
(cherry picked from commit 17a59f661398bf56aeaba4187f55d07eea09c578)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thomas Senyk 2022-12-14 08:20:36 +01:00 committed by Qt Cherry-pick Bot
parent 013a05a937
commit af85a5c965
5 changed files with 59 additions and 5 deletions

View File

@ -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

View File

@ -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<EGLint> m_contextAttrs;
bool m_markedInvalid = false;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QEGLPlatformContext::Flags)

View File

@ -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);

View File

@ -22,10 +22,19 @@ QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContex
EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
if (surface->surface()->surfaceClass() == QSurface::Window)
return static_cast<QEglFSWindow *>(surface)->surface();
else
if (surface->surface()->surfaceClass() == QSurface::Window) {
QEglFSWindow *w = static_cast<QEglFSWindow *>(surface);
EGLSurface s = w->surface();
if (s == EGL_NO_SURFACE) {
w->resetSurface();
s = w->surface();
}
return s;
} else {
return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
}
EGLSurface QEglFSContext::createTemporaryOffscreenSurface()

View File

@ -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;