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:
virtual bool filterConfig(EGLConfig config) const;
private:
QSurfaceFormat m_format;
EGLDisplay m_display;
EGLint m_surfaceType;

View File

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

View File

@ -47,13 +47,15 @@
#include <EGL/egl.h>
#include <qpa/qplatformoffscreensurface.h>
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
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; }

View File

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

View File

@ -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<EGLint> m_contextAttrs;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QEGLPlatformContext::Flags)
QT_END_NAMESPACE
#endif //QEGLPLATFORMCONTEXT_H

View File

@ -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)
{
}

View File

@ -34,6 +34,7 @@
#include "qeglfsdeviceintegration.h"
#include "qeglfsintegration.h"
#include "qeglfscursor.h"
#include "qeglfswindow.h"
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QGuiApplication>
#include <private/qguiapplication_p.h>
@ -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

View File

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

View File

@ -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<QEglFSScreen *>(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();
}

View File

@ -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<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();
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<QEglFSScreen *>(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<QEglFSScreen *>(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)

View File

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