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 <oswald.buddenhagen@theqtcompany.com>
Reviewed-by: Louai Al-Khanji <louai.al-khanji@theqtcompany.com>
This commit is contained in:
Laszlo Agocs 2015-10-13 15:54:18 +02:00
parent b63c3d4d9a
commit 6046458dee
11 changed files with 73 additions and 34 deletions

View File

@ -88,7 +88,6 @@ public:
protected: protected:
virtual bool filterConfig(EGLConfig config) const; virtual bool filterConfig(EGLConfig config) const;
private:
QSurfaceFormat m_format; QSurfaceFormat m_format;
EGLDisplay m_display; EGLDisplay m_display;
EGLint m_surfaceType; EGLint m_surfaceType;

View File

@ -49,13 +49,15 @@ QT_BEGIN_NAMESPACE
and return a new instance of this class. 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) : QPlatformOffscreenSurface(offscreenSurface)
, m_format(format) , m_format(format)
, m_display(display) , m_display(display)
, m_pbuffer(EGL_NO_SURFACE) , 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 // 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 // operations (glReadPixels) are unable to work without a surface since they at some

View File

@ -47,13 +47,15 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#include <qpa/qplatformoffscreensurface.h> #include <qpa/qplatformoffscreensurface.h>
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QEGLPbuffer : public QPlatformOffscreenSurface class QEGLPbuffer : public QPlatformOffscreenSurface
{ {
public: public:
QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface); QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface,
QEGLPlatformContext::Flags flags = 0);
~QEGLPbuffer(); ~QEGLPbuffer();
QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; }

View File

@ -106,11 +106,12 @@ QT_BEGIN_NAMESPACE
#endif #endif
QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, 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_eglDisplay(display)
, m_swapInterval(-1) , m_swapInterval(-1)
, m_swapIntervalEnvChecked(false) , m_swapIntervalEnvChecked(false)
, m_swapIntervalFromEnv(-1) , m_swapIntervalFromEnv(-1)
, m_flags(flags)
{ {
if (nativeHandle.isNull()) { if (nativeHandle.isNull()) {
m_eglConfig = config ? *config : q_configFromGLFormat(display, format); m_eglConfig = config ? *config : q_configFromGLFormat(display, format);
@ -291,7 +292,7 @@ void QEGLPlatformContext::updateFormatFromGL()
// drivers (Mesa) when certain attributes are present (multisampling). // drivers (Mesa) when certain attributes are present (multisampling).
EGLSurface tempSurface = EGL_NO_SURFACE; EGLSurface tempSurface = EGL_NO_SURFACE;
EGLContext tempContext = EGL_NO_CONTEXT; 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(); tempSurface = createTemporaryOffscreenSurface();
EGLBoolean ok = eglMakeCurrent(m_eglDisplay, tempSurface, tempSurface, m_eglContext); EGLBoolean ok = eglMakeCurrent(m_eglDisplay, tempSurface, tempSurface, m_eglContext);

View File

@ -56,8 +56,14 @@ QT_BEGIN_NAMESPACE
class QEGLPlatformContext : public QPlatformOpenGLContext class QEGLPlatformContext : public QPlatformOpenGLContext
{ {
public: public:
enum Flag {
NoSurfaceless = 0x01
};
Q_DECLARE_FLAGS(Flags, Flag)
QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, 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(); ~QEGLPlatformContext();
void initialize() Q_DECL_OVERRIDE; void initialize() Q_DECL_OVERRIDE;
@ -93,10 +99,13 @@ private:
int m_swapInterval; int m_swapInterval;
bool m_swapIntervalEnvChecked; bool m_swapIntervalEnvChecked;
int m_swapIntervalFromEnv; int m_swapIntervalFromEnv;
Flags m_flags;
bool m_ownsContext; bool m_ownsContext;
QVector<EGLint> m_contextAttrs; QVector<EGLint> m_contextAttrs;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(QEGLPlatformContext::Flags)
QT_END_NAMESPACE QT_END_NAMESPACE
#endif //QEGLPLATFORMCONTEXT_H #endif //QEGLPLATFORMCONTEXT_H

View File

@ -44,7 +44,8 @@ QT_BEGIN_NAMESPACE
QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display,
EGLConfig *config, const QVariant &nativeHandle) 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) m_tempWindow(0)
{ {
} }

View File

@ -34,6 +34,7 @@
#include "qeglfsdeviceintegration.h" #include "qeglfsdeviceintegration.h"
#include "qeglfsintegration.h" #include "qeglfsintegration.h"
#include "qeglfscursor.h" #include "qeglfscursor.h"
#include "qeglfswindow.h"
#include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QGuiApplication> #include <QGuiApplication>
#include <private/qguiapplication_p.h> #include <private/qguiapplication_p.h>
@ -175,6 +176,11 @@ EGLNativeDisplayType QEGLDeviceIntegration::platformDisplay() const
return EGL_DEFAULT_DISPLAY; return EGL_DEFAULT_DISPLAY;
} }
EGLDisplay QEGLDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
{
return eglGetDisplay(nativeDisplay);
}
bool QEGLDeviceIntegration::usesDefaultScreen() bool QEGLDeviceIntegration::usesDefaultScreen()
{ {
return true; return true;
@ -238,6 +244,11 @@ qreal QEGLDeviceIntegration::refreshRate() const
return q_refreshRateFromFb(framebuffer); return q_refreshRateFromFb(framebuffer);
} }
EGLint QEGLDeviceIntegration::surfaceType() const
{
return EGL_WINDOW_BIT;
}
QSurfaceFormat QEGLDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const QSurfaceFormat QEGLDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
{ {
QSurfaceFormat format = inputFormat; QSurfaceFormat format = inputFormat;
@ -257,6 +268,11 @@ bool QEGLDeviceIntegration::filterConfig(EGLDisplay, EGLConfig) const
return true; return true;
} }
QEglFSWindow *QEGLDeviceIntegration::createWindow(QWindow *window) const
{
return new QEglFSWindow(window);
}
EGLNativeWindowType QEGLDeviceIntegration::createNativeWindow(QPlatformWindow *platformWindow, EGLNativeWindowType QEGLDeviceIntegration::createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size, const QSize &size,
const QSurfaceFormat &format) const QSurfaceFormat &format)
@ -313,4 +329,9 @@ bool QEGLDeviceIntegration::supportsPBuffers() const
return true; return true;
} }
bool QEGLDeviceIntegration::supportsSurfacelessContexts() const
{
return true;
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -56,6 +56,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QPlatformSurface; class QPlatformSurface;
class QEglFSWindow;
#define QEGLDeviceIntegrationFactoryInterface_iid "org.qt-project.qt.qpa.egl.QEGLDeviceIntegrationFactoryInterface.5.5" #define QEGLDeviceIntegrationFactoryInterface_iid "org.qt-project.qt.qpa.egl.QEGLDeviceIntegrationFactoryInterface.5.5"
@ -67,6 +68,7 @@ public:
virtual void platformInit(); virtual void platformInit();
virtual void platformDestroy(); virtual void platformDestroy();
virtual EGLNativeDisplayType platformDisplay() const; virtual EGLNativeDisplayType platformDisplay() const;
virtual EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay);
virtual bool usesDefaultScreen(); virtual bool usesDefaultScreen();
virtual void screenInit(); virtual void screenInit();
virtual void screenDestroy(); virtual void screenDestroy();
@ -79,6 +81,8 @@ public:
virtual QImage::Format screenFormat() const; virtual QImage::Format screenFormat() const;
virtual qreal refreshRate() const; virtual qreal refreshRate() const;
virtual QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const; virtual QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const;
virtual EGLint surfaceType() const;
virtual QEglFSWindow *createWindow(QWindow *window) const;
virtual EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow, virtual EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size, const QSize &size,
const QSurfaceFormat &format); const QSurfaceFormat &format);
@ -92,6 +96,7 @@ public:
virtual QByteArray fbDeviceName() const; virtual QByteArray fbDeviceName() const;
virtual int framebufferIndex() const; virtual int framebufferIndex() const;
virtual bool supportsPBuffers() const; virtual bool supportsPBuffers() const;
virtual bool supportsSurfacelessContexts() const;
}; };
class Q_EGLFS_EXPORT QEGLDeviceIntegrationPlugin : public QObject class Q_EGLFS_EXPORT QEGLDeviceIntegrationPlugin : public QObject

View File

@ -117,7 +117,7 @@ void QEglFSIntegration::initialize()
{ {
qt_egl_device_integration()->platformInit(); qt_egl_device_integration()->platformInit();
m_display = eglGetDisplay(nativeDisplay()); m_display = qt_egl_device_integration()->createDisplay(nativeDisplay());
if (m_display == EGL_NO_DISPLAY) if (m_display == EGL_NO_DISPLAY)
qFatal("Could not open egl display"); qFatal("Could not open egl display");
@ -179,7 +179,7 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi
QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
{ {
QWindowSystemInterface::flushWindowSystemEvents(); QWindowSystemInterface::flushWindowSystemEvents();
QEglFSWindow *w = new QEglFSWindow(window); QEglFSWindow *w = qt_egl_device_integration()->createWindow(window);
w->create(); w->create();
if (window->type() != Qt::ToolTip) if (window->type() != Qt::ToolTip)
w->requestActivateWindow(); w->requestActivateWindow();
@ -213,10 +213,14 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf
{ {
EGLDisplay dpy = surface->screen() ? static_cast<QEglFSScreen *>(surface->screen()->handle())->display() : display(); EGLDisplay dpy = surface->screen() ? static_cast<QEglFSScreen *>(surface->screen()->handle())->display() : display();
QSurfaceFormat fmt = qt_egl_device_integration()->surfaceFormatFor(surface->requestedFormat()); QSurfaceFormat fmt = qt_egl_device_integration()->surfaceFormatFor(surface->requestedFormat());
if (qt_egl_device_integration()->supportsPBuffers()) if (qt_egl_device_integration()->supportsPBuffers()) {
return new QEGLPbuffer(dpy, fmt, surface); QEGLPlatformContext::Flags flags = 0;
else if (!qt_egl_device_integration()->supportsSurfacelessContexts())
flags |= QEGLPlatformContext::NoSurfaceless;
return new QEGLPbuffer(dpy, fmt, surface, flags);
} else {
return new QEglFSOffscreenWindow(dpy, fmt, surface); return new QEglFSOffscreenWindow(dpy, fmt, surface);
}
// Never return null. Multiple QWindows are not supported by this plugin. // 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 chooser(display);
chooser.setSurfaceType(qt_egl_device_integration()->surfaceType());
chooser.setSurfaceFormat(format); chooser.setSurfaceFormat(format);
return chooser.chooseConfig(); return chooser.chooseConfig();
} }

View File

@ -51,7 +51,7 @@ QEglFSWindow::QEglFSWindow(QWindow *w)
m_backingStore(0), m_backingStore(0),
m_raster(false), m_raster(false),
m_winId(0), m_winId(0),
m_surface(0), m_surface(EGL_NO_SURFACE),
m_window(0), m_window(0),
m_flags(0) m_flags(0)
{ {
@ -120,13 +120,14 @@ void QEglFSWindow::create()
setGeometry(QRect()); // will become fullscreen setGeometry(QRect()); // will become fullscreen
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
EGLDisplay display = static_cast<QEglFSScreen *>(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(); 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); screen->setPrimarySurface(m_surface);
if (isRaster()) { if (isRaster()) {
@ -158,15 +159,10 @@ void QEglFSWindow::destroy()
QOpenGLCompositor::instance()->removeWindow(this); 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() void QEglFSWindow::invalidateSurface()
{ {
if (m_surface != EGL_NO_SURFACE) { if (m_surface != EGL_NO_SURFACE) {
EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display(); eglDestroySurface(screen()->display(), m_surface);
eglDestroySurface(display, m_surface);
m_surface = EGL_NO_SURFACE; m_surface = EGL_NO_SURFACE;
} }
qt_egl_device_integration()->destroyNativeWindow(m_window); qt_egl_device_integration()->destroyNativeWindow(m_window);
@ -175,15 +171,13 @@ void QEglFSWindow::invalidateSurface()
void QEglFSWindow::resetSurface() void QEglFSWindow::resetSurface()
{ {
QEglFSScreen *nativeScreen = static_cast<QEglFSScreen *>(screen()); EGLDisplay display = screen()->display();
EGLDisplay display = nativeScreen->display(); QSurfaceFormat platformFormat = qt_egl_device_integration()->surfaceFormatFor(window()->requestedFormat());
m_window = qt_egl_device_integration()->createNativeWindow(this, nativeScreen->geometry().size(), m_format);
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); 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) void QEglFSWindow::setVisible(bool visible)

View File

@ -89,7 +89,7 @@ public:
const QPlatformTextureList *textures() const Q_DECL_OVERRIDE; const QPlatformTextureList *textures() const Q_DECL_OVERRIDE;
void endCompositing() Q_DECL_OVERRIDE; void endCompositing() Q_DECL_OVERRIDE;
private: protected:
QOpenGLCompositorBackingStore *m_backingStore; QOpenGLCompositorBackingStore *m_backingStore;
bool m_raster; bool m_raster;
WId m_winId; WId m_winId;