From 6046458dee115841c6f01b2a2e01b41be1bfbdc9 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 13 Oct 2015 15:54:18 +0200 Subject: eglfs: Handle custom platform window implementations better Backends may want to subclass QEglFSWindow and reimplement resetSurface() and similar. Make it possible to do this by moving window creation to the device integration interface, similarly to screens. In addition to customizing the windows, some backends may want to disable the dependency on surfaceless contexts when using offscreen windows (i.e. pbuffer surfaces). Make this possible too. Change-Id: Ic5a426e07f821c7a800217b8799f91770ba6a6d8 Reviewed-by: Oswald Buddenhagen Reviewed-by: Louai Al-Khanji --- .../eglconvenience/qeglconvenience_p.h | 1 - src/platformsupport/eglconvenience/qeglpbuffer.cpp | 6 ++-- src/platformsupport/eglconvenience/qeglpbuffer_p.h | 4 ++- .../eglconvenience/qeglplatformcontext.cpp | 5 ++-- .../eglconvenience/qeglplatformcontext_p.h | 11 ++++++- src/plugins/platforms/eglfs/qeglfscontext.cpp | 3 +- .../platforms/eglfs/qeglfsdeviceintegration.cpp | 21 +++++++++++++ .../platforms/eglfs/qeglfsdeviceintegration.h | 5 ++++ src/plugins/platforms/eglfs/qeglfsintegration.cpp | 15 ++++++---- src/plugins/platforms/eglfs/qeglfswindow.cpp | 34 +++++++++------------- src/plugins/platforms/eglfs/qeglfswindow.h | 2 +- 11 files changed, 73 insertions(+), 34 deletions(-) diff --git a/src/platformsupport/eglconvenience/qeglconvenience_p.h b/src/platformsupport/eglconvenience/qeglconvenience_p.h index 59441d8c9a..ec6f668cba 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience_p.h +++ b/src/platformsupport/eglconvenience/qeglconvenience_p.h @@ -88,7 +88,6 @@ public: protected: virtual bool filterConfig(EGLConfig config) const; -private: QSurfaceFormat m_format; EGLDisplay m_display; EGLint m_surfaceType; diff --git a/src/platformsupport/eglconvenience/qeglpbuffer.cpp b/src/platformsupport/eglconvenience/qeglpbuffer.cpp index 756609a641..d1a31642b2 100644 --- a/src/platformsupport/eglconvenience/qeglpbuffer.cpp +++ b/src/platformsupport/eglconvenience/qeglpbuffer.cpp @@ -49,13 +49,15 @@ QT_BEGIN_NAMESPACE and return a new instance of this class. */ -QEGLPbuffer::QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface) +QEGLPbuffer::QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface, + QEGLPlatformContext::Flags flags) : QPlatformOffscreenSurface(offscreenSurface) , m_format(format) , m_display(display) , m_pbuffer(EGL_NO_SURFACE) { - bool hasSurfaceless = q_hasEglExtension(display, "EGL_KHR_surfaceless_context"); + bool hasSurfaceless = !flags.testFlag(QEGLPlatformContext::NoSurfaceless) + && q_hasEglExtension(display, "EGL_KHR_surfaceless_context"); // Disable surfaceless contexts on Mesa for now. As of 10.6.0 and Intel at least, some // operations (glReadPixels) are unable to work without a surface since they at some diff --git a/src/platformsupport/eglconvenience/qeglpbuffer_p.h b/src/platformsupport/eglconvenience/qeglpbuffer_p.h index 3372c0735d..81fdab8901 100644 --- a/src/platformsupport/eglconvenience/qeglpbuffer_p.h +++ b/src/platformsupport/eglconvenience/qeglpbuffer_p.h @@ -47,13 +47,15 @@ #include #include +#include QT_BEGIN_NAMESPACE class QEGLPbuffer : public QPlatformOffscreenSurface { public: - QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface); + QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface, + QEGLPlatformContext::Flags flags = 0); ~QEGLPbuffer(); QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 2de7fb3b40..acd6197ed5 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -106,11 +106,12 @@ QT_BEGIN_NAMESPACE #endif QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig *config, const QVariant &nativeHandle) + EGLConfig *config, const QVariant &nativeHandle, Flags flags) : m_eglDisplay(display) , m_swapInterval(-1) , m_swapIntervalEnvChecked(false) , m_swapIntervalFromEnv(-1) + , m_flags(flags) { if (nativeHandle.isNull()) { m_eglConfig = config ? *config : q_configFromGLFormat(display, format); @@ -291,7 +292,7 @@ void QEGLPlatformContext::updateFormatFromGL() // drivers (Mesa) when certain attributes are present (multisampling). EGLSurface tempSurface = EGL_NO_SURFACE; EGLContext tempContext = EGL_NO_CONTEXT; - if (!q_hasEglExtension(m_eglDisplay, "EGL_KHR_surfaceless_context")) + if (m_flags.testFlag(NoSurfaceless) || !q_hasEglExtension(m_eglDisplay, "EGL_KHR_surfaceless_context")) tempSurface = createTemporaryOffscreenSurface(); EGLBoolean ok = eglMakeCurrent(m_eglDisplay, tempSurface, tempSurface, m_eglContext); diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h index 2ab7ad28d0..2fa465556b 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h @@ -56,8 +56,14 @@ QT_BEGIN_NAMESPACE class QEGLPlatformContext : public QPlatformOpenGLContext { public: + enum Flag { + NoSurfaceless = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig *config = 0, const QVariant &nativeHandle = QVariant()); + EGLConfig *config = 0, const QVariant &nativeHandle = QVariant(), + Flags flags = 0); ~QEGLPlatformContext(); void initialize() Q_DECL_OVERRIDE; @@ -93,10 +99,13 @@ private: int m_swapInterval; bool m_swapIntervalEnvChecked; int m_swapIntervalFromEnv; + Flags m_flags; bool m_ownsContext; QVector m_contextAttrs; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QEGLPlatformContext::Flags) + QT_END_NAMESPACE #endif //QEGLPLATFORMCONTEXT_H diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp index e2223aba43..6fcdae7ad2 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp @@ -44,7 +44,8 @@ QT_BEGIN_NAMESPACE QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLConfig *config, const QVariant &nativeHandle) - : QEGLPlatformContext(format, share, display, config, nativeHandle), + : QEGLPlatformContext(format, share, display, config, nativeHandle, + qt_egl_device_integration()->supportsSurfacelessContexts() ? Flags(0) : QEGLPlatformContext::NoSurfaceless), m_tempWindow(0) { } diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp index d27c949c8d..0c2aa7ad61 100644 --- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp @@ -34,6 +34,7 @@ #include "qeglfsdeviceintegration.h" #include "qeglfsintegration.h" #include "qeglfscursor.h" +#include "qeglfswindow.h" #include #include #include @@ -175,6 +176,11 @@ EGLNativeDisplayType QEGLDeviceIntegration::platformDisplay() const return EGL_DEFAULT_DISPLAY; } +EGLDisplay QEGLDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay) +{ + return eglGetDisplay(nativeDisplay); +} + bool QEGLDeviceIntegration::usesDefaultScreen() { return true; @@ -238,6 +244,11 @@ qreal QEGLDeviceIntegration::refreshRate() const return q_refreshRateFromFb(framebuffer); } +EGLint QEGLDeviceIntegration::surfaceType() const +{ + return EGL_WINDOW_BIT; +} + QSurfaceFormat QEGLDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const { QSurfaceFormat format = inputFormat; @@ -257,6 +268,11 @@ bool QEGLDeviceIntegration::filterConfig(EGLDisplay, EGLConfig) const return true; } +QEglFSWindow *QEGLDeviceIntegration::createWindow(QWindow *window) const +{ + return new QEglFSWindow(window); +} + EGLNativeWindowType QEGLDeviceIntegration::createNativeWindow(QPlatformWindow *platformWindow, const QSize &size, const QSurfaceFormat &format) @@ -313,4 +329,9 @@ bool QEGLDeviceIntegration::supportsPBuffers() const return true; } +bool QEGLDeviceIntegration::supportsSurfacelessContexts() const +{ + return true; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h index 260fc313f7..d91d67de16 100644 --- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE class QPlatformSurface; +class QEglFSWindow; #define QEGLDeviceIntegrationFactoryInterface_iid "org.qt-project.qt.qpa.egl.QEGLDeviceIntegrationFactoryInterface.5.5" @@ -67,6 +68,7 @@ public: virtual void platformInit(); virtual void platformDestroy(); virtual EGLNativeDisplayType platformDisplay() const; + virtual EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay); virtual bool usesDefaultScreen(); virtual void screenInit(); virtual void screenDestroy(); @@ -79,6 +81,8 @@ public: virtual QImage::Format screenFormat() const; virtual qreal refreshRate() const; virtual QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const; + virtual EGLint surfaceType() const; + virtual QEglFSWindow *createWindow(QWindow *window) const; virtual EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow, const QSize &size, const QSurfaceFormat &format); @@ -92,6 +96,7 @@ public: virtual QByteArray fbDeviceName() const; virtual int framebufferIndex() const; virtual bool supportsPBuffers() const; + virtual bool supportsSurfacelessContexts() const; }; class Q_EGLFS_EXPORT QEGLDeviceIntegrationPlugin : public QObject diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index f0946b9b64..2df06caa6b 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -117,7 +117,7 @@ void QEglFSIntegration::initialize() { qt_egl_device_integration()->platformInit(); - m_display = eglGetDisplay(nativeDisplay()); + m_display = qt_egl_device_integration()->createDisplay(nativeDisplay()); if (m_display == EGL_NO_DISPLAY) qFatal("Could not open egl display"); @@ -179,7 +179,7 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const { QWindowSystemInterface::flushWindowSystemEvents(); - QEglFSWindow *w = new QEglFSWindow(window); + QEglFSWindow *w = qt_egl_device_integration()->createWindow(window); w->create(); if (window->type() != Qt::ToolTip) w->requestActivateWindow(); @@ -213,10 +213,14 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf { EGLDisplay dpy = surface->screen() ? static_cast(surface->screen()->handle())->display() : display(); QSurfaceFormat fmt = qt_egl_device_integration()->surfaceFormatFor(surface->requestedFormat()); - if (qt_egl_device_integration()->supportsPBuffers()) - return new QEGLPbuffer(dpy, fmt, surface); - else + if (qt_egl_device_integration()->supportsPBuffers()) { + QEGLPlatformContext::Flags flags = 0; + if (!qt_egl_device_integration()->supportsSurfacelessContexts()) + flags |= QEGLPlatformContext::NoSurfaceless; + return new QEGLPbuffer(dpy, fmt, surface, flags); + } else { return new QEglFSOffscreenWindow(dpy, fmt, surface); + } // Never return null. Multiple QWindows are not supported by this plugin. } @@ -433,6 +437,7 @@ EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceForm }; Chooser chooser(display); + chooser.setSurfaceType(qt_egl_device_integration()->surfaceType()); chooser.setSurfaceFormat(format); return chooser.chooseConfig(); } diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index c3b9dd6ef0..8301be8c17 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -51,7 +51,7 @@ QEglFSWindow::QEglFSWindow(QWindow *w) m_backingStore(0), m_raster(false), m_winId(0), - m_surface(0), + m_surface(EGL_NO_SURFACE), m_window(0), m_flags(0) { @@ -120,13 +120,14 @@ void QEglFSWindow::create() setGeometry(QRect()); // will become fullscreen QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); - EGLDisplay display = static_cast(screen)->display(); - QSurfaceFormat platformFormat = qt_egl_device_integration()->surfaceFormatFor(window()->requestedFormat()); - m_config = QEglFSIntegration::chooseConfig(display, platformFormat); - m_format = q_glFormatFromConfig(display, m_config, platformFormat); - resetSurface(); + if (m_surface == EGL_NO_SURFACE) { + EGLint error = eglGetError(); + eglTerminate(screen->display()); + qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error); + } + screen->setPrimarySurface(m_surface); if (isRaster()) { @@ -158,15 +159,10 @@ void QEglFSWindow::destroy() QOpenGLCompositor::instance()->removeWindow(this); } -// The virtual functions resetSurface and invalidateSurface may get overridden -// in derived classes, for example in the Android port, to perform the native -// window and surface creation differently. - void QEglFSWindow::invalidateSurface() { if (m_surface != EGL_NO_SURFACE) { - EGLDisplay display = static_cast(screen())->display(); - eglDestroySurface(display, m_surface); + eglDestroySurface(screen()->display(), m_surface); m_surface = EGL_NO_SURFACE; } qt_egl_device_integration()->destroyNativeWindow(m_window); @@ -175,15 +171,13 @@ void QEglFSWindow::invalidateSurface() void QEglFSWindow::resetSurface() { - QEglFSScreen *nativeScreen = static_cast(screen()); - EGLDisplay display = nativeScreen->display(); - m_window = qt_egl_device_integration()->createNativeWindow(this, nativeScreen->geometry().size(), m_format); + EGLDisplay display = screen()->display(); + QSurfaceFormat platformFormat = qt_egl_device_integration()->surfaceFormatFor(window()->requestedFormat()); + + m_config = QEglFSIntegration::chooseConfig(display, platformFormat); + m_format = q_glFormatFromConfig(display, m_config, platformFormat); + m_window = qt_egl_device_integration()->createNativeWindow(this, screen()->geometry().size(), m_format); m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL); - if (m_surface == EGL_NO_SURFACE) { - EGLint error = eglGetError(); - eglTerminate(display); - qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error); - } } void QEglFSWindow::setVisible(bool visible) diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index 53b9e18dc1..806b21de0a 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -89,7 +89,7 @@ public: const QPlatformTextureList *textures() const Q_DECL_OVERRIDE; void endCompositing() Q_DECL_OVERRIDE; -private: +protected: QOpenGLCompositorBackingStore *m_backingStore; bool m_raster; WId m_winId; -- cgit v1.2.3