eglfs: Separate compositor and improve raster window support

Separating the compositor into a separate source file improves the
chances of possible future reuse and paves the way to supporting
multiple GL windows. Tooltips are now working too. Implemented a few
window functions like raise() and lower(). Fixed the qFatal for
multiple GL windows to be raised in non-SDK based Android builds too.

Change-Id: Id94d2fb2a4382766f3d130eebe1e6f397a535852
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
This commit is contained in:
Laszlo Agocs 2013-10-08 14:55:28 +02:00 committed by The Qt Project
parent 8d2c6206fd
commit 80cd06fd9d
10 changed files with 413 additions and 242 deletions

View File

@ -16,7 +16,8 @@ SOURCES += $$PWD/qeglfsintegration.cpp \
$$PWD/qeglfsscreen.cpp \
$$PWD/qeglfshooks_stub.cpp \
$$PWD/qeglfscursor.cpp \
$$PWD/qeglfscontext.cpp
$$PWD/qeglfscontext.cpp \
$$PWD/qeglfscompositor.cpp
HEADERS += $$PWD/qeglfsintegration.h \
$$PWD/qeglfswindow.h \
@ -24,7 +25,8 @@ HEADERS += $$PWD/qeglfsintegration.h \
$$PWD/qeglfsscreen.h \
$$PWD/qeglfscursor.h \
$$PWD/qeglfshooks.h \
$$PWD/qeglfscontext.h
$$PWD/qeglfscontext.h \
$$PWD/qeglfscompositor.h
QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF

View File

@ -40,120 +40,24 @@
****************************************************************************/
#include "qeglfsbackingstore.h"
#include "qeglfscompositor.h"
#include "qeglfscursor.h"
#include "qeglfswindow.h"
#include "qeglfscontext.h"
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLPaintDevice>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QScreen>
QT_BEGIN_NAMESPACE
QEglFSCompositor::QEglFSCompositor()
: m_rootWindow(0)
{
m_updateTimer.setSingleShot(true);
m_updateTimer.setInterval(0);
connect(&m_updateTimer, SIGNAL(timeout()), SLOT(renderAll()));
}
void QEglFSCompositor::schedule(QEglFSWindow *rootWindow)
{
m_rootWindow = rootWindow;
if (!m_updateTimer.isActive())
m_updateTimer.start();
}
void QEglFSCompositor::renderAll()
{
Q_ASSERT(m_rootWindow);
QOpenGLContext *context = QEglFSBackingStore::makeRootCurrent(m_rootWindow);
QEglFSScreen *screen = m_rootWindow->screen();
QList<QEglFSWindow *> windows = screen->windows();
for (int i = 0; i < windows.size(); ++i) {
if (windows.at(i)->backingStore())
render(windows.at(i), m_rootWindow);
}
context->swapBuffers(m_rootWindow->window());
context->doneCurrent();
}
void QEglFSCompositor::render(QEglFSWindow *window, QEglFSWindow *rootWindow)
{
QEglFSBackingStore *rootBackingStore = rootWindow->backingStore();
rootBackingStore->m_program->bind();
const GLfloat textureCoordinates[] = {
0, 0,
1, 0,
1, 1,
0, 1
};
QRectF sr = window->screen()->geometry();
QRect r = window->window()->geometry();
QPoint tl = r.topLeft();
QPoint br = r.bottomRight();
GLfloat x1 = (tl.x() / sr.width()) * 2 - 1;
GLfloat x2 = (br.x() / sr.width()) * 2 - 1;
GLfloat y1 = ((sr.height() - tl.y()) / sr.height()) * 2 - 1;
GLfloat y2 = ((sr.height() - br.y()) / sr.height()) * 2 - 1;
const GLfloat vertexCoordinates[] = {
x1, y1,
x2, y1,
x2, y2,
x1, y2
};
glViewport(0, 0, sr.width(), sr.height());
glEnableVertexAttribArray(rootBackingStore->m_vertexCoordEntry);
glEnableVertexAttribArray(rootBackingStore->m_textureCoordEntry);
glVertexAttribPointer(rootBackingStore->m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinates);
glVertexAttribPointer(rootBackingStore->m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
glBindTexture(GL_TEXTURE_2D, window->backingStore()->m_texture);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
rootBackingStore->m_program->release();
glBindTexture(GL_TEXTURE_2D, 0);
glDisableVertexAttribArray(rootBackingStore->m_vertexCoordEntry);
glDisableVertexAttribArray(rootBackingStore->m_textureCoordEntry);
}
static QEglFSCompositor *compositor = 0;
QEglFSCompositor *QEglFSCompositor::instance()
{
if (!compositor)
compositor = new QEglFSCompositor;
return compositor;
}
QEglFSBackingStore::QEglFSBackingStore(QWindow *window)
: QPlatformBackingStore(window)
, m_window(static_cast<QEglFSWindow *>(window->handle()))
, m_context(0)
, m_texture(0)
, m_program(0)
: QPlatformBackingStore(window),
m_window(static_cast<QEglFSWindow *>(window->handle())),
m_texture(0)
{
m_window->setBackingStore(this);
}
QEglFSBackingStore::~QEglFSBackingStore()
{
delete m_program;
delete m_context;
}
QPaintDevice *QEglFSBackingStore::paintDevice()
{
return &m_image;
@ -186,7 +90,8 @@ void QEglFSBackingStore::updateTexture()
// if the sub-rect is full-width we can pass the image data directly to
// OpenGL instead of copying, since there's no gap between scanlines
if (rect.width() == imageRect.width()) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_image.constScanLine(rect.y()));
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
m_image.constScanLine(rect.y()));
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
m_image.copy(rect).constBits());
@ -207,63 +112,14 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion &region, const QPo
qWarning("QEglBackingStore::flush %p", window);
#endif
m_window->create();
QEglFSWindow *rootWin = m_window->screen()->rootWindow();
if (rootWin) {
makeRootCurrent(rootWin);
updateTexture();
QEglFSCompositor::instance()->schedule(rootWin);
}
}
if (!rootWin)
return;
void QEglFSBackingStore::makeCurrent()
{
Q_ASSERT(m_window->hasNativeWindow());
QWindow *wnd = window();
if (!m_context) {
m_context = new QOpenGLContext;
m_context->setFormat(wnd->requestedFormat());
m_context->setScreen(wnd->screen());
m_context->create();
}
m_context->makeCurrent(wnd);
}
QOpenGLContext *QEglFSBackingStore::makeRootCurrent(QEglFSWindow *rootWin)
{
Q_ASSERT(rootWin->hasNativeWindow() && rootWin->isRasterRoot());
QEglFSBackingStore *rootBackingStore = rootWin->backingStore();
rootBackingStore->makeCurrent();
if (!rootBackingStore->m_program) {
static const char *textureVertexProgram =
"attribute highp vec2 vertexCoordEntry;\n"
"attribute highp vec2 textureCoordEntry;\n"
"varying highp vec2 textureCoord;\n"
"void main() {\n"
" textureCoord = textureCoordEntry;\n"
" gl_Position = vec4(vertexCoordEntry, 0.0, 1.0);\n"
"}\n";
static const char *textureFragmentProgram =
"uniform sampler2D texture;\n"
"varying highp vec2 textureCoord;\n"
"void main() {\n"
" gl_FragColor = texture2D(texture, textureCoord).bgra;\n"
"}\n";
rootBackingStore->m_program = new QOpenGLShaderProgram;
rootBackingStore->m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
rootBackingStore->m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
rootBackingStore->m_program->link();
rootBackingStore->m_vertexCoordEntry = rootBackingStore->m_program->attributeLocation("vertexCoordEntry");
rootBackingStore->m_textureCoordEntry = rootBackingStore->m_program->attributeLocation("textureCoordEntry");
}
return rootBackingStore->m_context;
m_window->create();
rootWin->screen()->rootContext()->makeCurrent(rootWin->window());
updateTexture();
QEglFSCompositor::instance()->schedule(rootWin->screen());
}
void QEglFSBackingStore::beginPaint(const QRegion &rgn)
@ -275,9 +131,14 @@ void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents
{
Q_UNUSED(staticContents);
QEglFSWindow *rootWin = m_window->screen()->rootWindow();
if (!rootWin)
return;
m_image = QImage(size, QImage::Format_RGB32);
m_window->create();
makeRootCurrent(m_window->screen()->rootWindow());
rootWin->screen()->rootContext()->makeCurrent(rootWin->window());
if (m_texture)
glDeleteTextures(1, &m_texture);

View File

@ -46,41 +46,16 @@
#include <QImage>
#include <QRegion>
#include <QTimer>
QT_BEGIN_NAMESPACE
class QOpenGLContext;
class QOpenGLPaintDevice;
class QOpenGLShaderProgram;
class QEglFSWindow;
class QEglFSCompositor : public QObject
{
Q_OBJECT
public:
QEglFSCompositor();
void schedule(QEglFSWindow *rootWindow);
static QEglFSCompositor *instance();
private slots:
void renderAll();
private:
void render(QEglFSWindow *window, QEglFSWindow *rootWindow);
QEglFSWindow *m_rootWindow;
QTimer m_updateTimer;
};
class QEglFSBackingStore : public QPlatformBackingStore
{
public:
QEglFSBackingStore(QWindow *window);
~QEglFSBackingStore();
QPaintDevice *paintDevice();
@ -89,21 +64,15 @@ public:
void flush(QWindow *window, const QRegion &region, const QPoint &offset);
void resize(const QSize &size, const QRegion &staticContents);
uint texture() const { return m_texture; }
private:
void makeCurrent();
static QOpenGLContext *makeRootCurrent(QEglFSWindow *rootWin);
void updateTexture();
QEglFSWindow *m_window;
QOpenGLContext *m_context;
QImage m_image;
uint m_texture;
QRegion m_dirty;
QOpenGLShaderProgram *m_program;
int m_vertexCoordEntry;
int m_textureCoordEntry;
friend class QEglFSCompositor;
};
QT_END_NAMESPACE

View File

@ -0,0 +1,198 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qeglfscompositor.h"
#include "qeglfswindow.h"
#include "qeglfscontext.h"
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLFramebufferObject>
QT_BEGIN_NAMESPACE
static QEglFSCompositor *compositor = 0;
QEglFSCompositor::QEglFSCompositor()
: m_screen(0),
m_program(0)
{
Q_ASSERT(!compositor);
m_updateTimer.setSingleShot(true);
m_updateTimer.setInterval(0);
connect(&m_updateTimer, SIGNAL(timeout()), SLOT(renderAll()));
}
QEglFSCompositor::~QEglFSCompositor()
{
Q_ASSERT(compositor == this);
delete m_program;
compositor = 0;
}
void QEglFSCompositor::schedule(QEglFSScreen *screen)
{
m_screen = screen;
if (!m_updateTimer.isActive())
m_updateTimer.start();
}
void QEglFSCompositor::renderAll()
{
QEglFSWindow *rootWin = m_screen->rootWindow();
if (!rootWin)
return;
Q_ASSERT(rootWin->hasNativeWindow());
QOpenGLContext *context = m_screen->rootContext();
Q_ASSERT(context);
context->makeCurrent(rootWin->window());
ensureProgram();
m_program->bind();
QList<QEglFSWindow *> windows = m_screen->windows();
for (int i = 0; i < windows.size(); ++i) {
QEglFSWindow *window = windows.at(i);
uint texture = window->texture();
if (texture)
render(window, texture, window->isRaster());
}
m_program->release();
context->swapBuffers(rootWin->window());
}
void QEglFSCompositor::ensureProgram()
{
if (!m_program) {
static const char *textureVertexProgram =
"attribute highp vec2 vertexCoordEntry;\n"
"attribute highp vec2 textureCoordEntry;\n"
"varying highp vec2 textureCoord;\n"
"void main() {\n"
" textureCoord = textureCoordEntry;\n"
" gl_Position = vec4(vertexCoordEntry, 0.0, 1.0);\n"
"}\n";
static const char *textureFragmentProgram =
"uniform sampler2D texture;\n"
"varying highp vec2 textureCoord;\n"
"uniform bool isRaster;\n"
"void main() {\n"
" lowp vec4 c = texture2D(texture, textureCoord);\n"
" gl_FragColor = isRaster ? c.bgra : c.rgba;\n"
"}\n";
m_program = new QOpenGLShaderProgram;
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
m_program->link();
m_vertexCoordEntry = m_program->attributeLocation("vertexCoordEntry");
m_textureCoordEntry = m_program->attributeLocation("textureCoordEntry");
m_isRasterEntry = m_program->uniformLocation("isRaster");
}
}
void QEglFSCompositor::render(QEglFSWindow *window, uint texture, bool raster)
{
const GLfloat textureCoordinates[] = {
0, 0,
1, 0,
1, 1,
0, 1
};
QRectF sr = window->screen()->geometry();
QRect r = window->window()->geometry();
QPoint tl = r.topLeft();
QPoint br = r.bottomRight();
GLfloat x1 = (tl.x() / sr.width()) * 2 - 1;
GLfloat x2 = (br.x() / sr.width()) * 2 - 1;
GLfloat y1 = ((sr.height() - tl.y()) / sr.height()) * 2 - 1;
GLfloat y2 = ((sr.height() - br.y()) / sr.height()) * 2 - 1;
if (!raster)
qSwap(y1, y2);
const GLfloat vertexCoordinates[] = {
x1, y1,
x2, y1,
x2, y2,
x1, y2
};
glViewport(0, 0, sr.width(), sr.height());
glEnableVertexAttribArray(m_vertexCoordEntry);
glEnableVertexAttribArray(m_textureCoordEntry);
glVertexAttribPointer(m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinates);
glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
glBindTexture(GL_TEXTURE_2D, texture);
m_program->setUniformValue(m_isRasterEntry, raster);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
glDisableVertexAttribArray(m_vertexCoordEntry);
glDisableVertexAttribArray(m_textureCoordEntry);
}
QEglFSCompositor *QEglFSCompositor::instance()
{
if (!compositor)
compositor = new QEglFSCompositor;
return compositor;
}
void QEglFSCompositor::destroy()
{
delete compositor;
compositor = 0;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,83 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QEGLFSCOMPOSITOR_H
#define QEGLFSCOMPOSITOR_H
#include <QTimer>
QT_BEGIN_NAMESPACE
class QEglFSScreen;
class QEglFSWindow;
class QOpenGLShaderProgram;
class QEglFSCompositor : public QObject
{
Q_OBJECT
public:
void schedule(QEglFSScreen *screen);
static QEglFSCompositor *instance();
static void destroy();
private slots:
void renderAll();
private:
QEglFSCompositor();
~QEglFSCompositor();
void render(QEglFSWindow *window, uint texture, bool raster);
void ensureProgram();
QEglFSScreen *m_screen;
QTimer m_updateTimer;
QOpenGLShaderProgram *m_program;
int m_vertexCoordEntry;
int m_textureCoordEntry;
int m_isRasterEntry;
};
QT_END_NAMESPACE
#endif // QEGLFSCOMPOSITOR_H

View File

@ -43,6 +43,7 @@
#include "qeglfswindow.h"
#include "qeglfsbackingstore.h"
#include "qeglfscompositor.h"
#include "qeglfshooks.h"
#include <QtGui/private/qguiapplication_p.h>
@ -75,8 +76,6 @@
QT_BEGIN_NAMESPACE
static void *eglContextForContext(QOpenGLContext *context);
QEglFSIntegration::QEglFSIntegration()
: mFontDb(new QGenericUnixFontDatabase)
, mServices(new QGenericUnixServices)
@ -108,8 +107,8 @@ QEglFSIntegration::QEglFSIntegration()
QEglFSIntegration::~QEglFSIntegration()
{
QEglFSCompositor::destroy();
delete mScreen;
eglTerminate(mDisplay);
QEglFSHooks::hooks()->platformDestroy();
}
@ -131,9 +130,11 @@ bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) cons
QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
{
QWindowSystemInterface::flushWindowSystemEvents();
QEglFSWindow *w = new QEglFSWindow(window);
w->create();
w->requestActivateWindow();
if (window->type() != Qt::ToolTip)
w->requestActivateWindow();
return w;
}
@ -263,15 +264,6 @@ void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QO
return result;
}
QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource)
{
QByteArray lowerCaseResource = resource.toLower();
if (lowerCaseResource == "get_egl_context")
return NativeResourceForContextFunction(eglContextForContext);
return 0;
}
static void *eglContextForContext(QOpenGLContext *context)
{
Q_ASSERT(context);
@ -283,6 +275,15 @@ static void *eglContextForContext(QOpenGLContext *context)
return handle->eglContext();
}
QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource)
{
QByteArray lowerCaseResource = resource.toLower();
if (lowerCaseResource == "get_egl_context")
return NativeResourceForContextFunction(eglContextForContext);
return 0;
}
EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
{
class Chooser : public QEglConfigChooser {

View File

@ -47,9 +47,10 @@
QT_BEGIN_NAMESPACE
QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
: m_dpy(dpy)
, m_surface(EGL_NO_SURFACE)
, m_cursor(0)
: m_dpy(dpy),
m_surface(EGL_NO_SURFACE),
m_cursor(0),
m_rootContext(0)
{
#ifdef QEGL_EXTRA_DEBUG
qWarning("QEglScreen %p\n", this);
@ -121,10 +122,23 @@ void QEglFSScreen::removeWindow(QEglFSWindow *window)
m_windows.removeOne(window);
}
void QEglFSScreen::moveToTop(QEglFSWindow *window)
{
m_windows.removeOne(window);
m_windows.append(window);
}
void QEglFSScreen::changeWindowIndex(QEglFSWindow *window, int newIdx)
{
int idx = m_windows.indexOf(window);
if (idx != -1 && idx != newIdx)
m_windows.move(idx, newIdx);
}
QEglFSWindow *QEglFSScreen::rootWindow()
{
Q_FOREACH (QEglFSWindow *window, m_windows) {
if (window->isRasterRoot())
if (window->hasNativeWindow())
return window;
}
return 0;

View File

@ -50,9 +50,9 @@
QT_BEGIN_NAMESPACE
class QPlatformOpenGLContext;
class QEglFSCursor;
class QEglFSWindow;
class QOpenGLContext;
class QEglFSScreen : public QPlatformScreen
{
@ -77,7 +77,11 @@ public:
QList<QEglFSWindow *> windows() const { return m_windows; }
void addWindow(QEglFSWindow *window);
void removeWindow(QEglFSWindow *window);
void moveToTop(QEglFSWindow *window);
void changeWindowIndex(QEglFSWindow *window, int newIdx);
QEglFSWindow *rootWindow();
QOpenGLContext *rootContext() { return m_rootContext; }
void setRootContext(QOpenGLContext *context) { m_rootContext = context; }
protected:
void setPrimarySurface(EGLSurface surface);
@ -89,6 +93,7 @@ private:
EGLSurface m_surface;
QEglFSCursor *m_cursor;
QList<QEglFSWindow *> m_windows;
QOpenGLContext *m_rootContext;
};
QT_END_NAMESPACE

View File

@ -42,9 +42,11 @@
#include "qeglfswindow.h"
#include "qeglfshooks.h"
#include "qeglfscursor.h"
#include "qeglfsbackingstore.h"
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
#include <QtGui/QOpenGLContext>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
@ -99,18 +101,21 @@ void QEglFSWindow::create()
if (window()->surfaceType() == QSurface::RasterSurface)
m_flags |= IsRaster;
// Stop if there is already a raster root window backed by a native window and
// surface. Other raster windows will not have their own native window, surface and
// context. Instead, they will be composited onto the root window's surface.
if (screen()->primarySurface() != EGL_NO_SURFACE) {
if (m_flags.testFlag(IsRaster) && screen()->rootWindow()->m_flags.testFlag(IsRaster))
// Stop if there is already a window backed by a native window and surface. Additional
// raster windows will not have their own native window, surface and context. Instead,
// they will be composited onto the root window's surface.
QEglFSScreen *screen = this->screen();
if (screen->primarySurface() != EGL_NO_SURFACE) {
if (m_flags.testFlag(IsRaster) && screen->rootWindow()->m_flags.testFlag(IsRaster))
return;
#ifndef Q_OS_ANDROID
#if !defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)
// We can have either a single OpenGL window or multiple raster windows.
// Other combinations cannot work.
qFatal("EGLFS: OpenGL windows cannot be mixed with others.");
#endif
return;
}
window()->setSurfaceType(QSurface::OpenGLSurface);
@ -118,31 +123,40 @@ void QEglFSWindow::create()
setGeometry(QRect()); // will become fullscreen
QWindowSystemInterface::handleExposeEvent(window(), geometry());
EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
EGLDisplay display = static_cast<QEglFSScreen *>(screen)->display();
QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat());
m_config = QEglFSIntegration::chooseConfig(display, platformFormat);
m_format = q_glFormatFromConfig(display, m_config);
resetSurface();
if (screen()->primarySurface() == EGL_NO_SURFACE) {
screen()->setPrimarySurface(m_surface);
m_flags |= IsRasterRoot;
screen->setPrimarySurface(m_surface);
if (m_flags.testFlag(IsRaster)) {
QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance());
context->setFormat(window()->requestedFormat());
context->setScreen(window()->screen());
context->create();
screen->setRootContext(context);
}
}
void QEglFSWindow::destroy()
{
QEglFSScreen *screen = this->screen();
if (m_flags.testFlag(HasNativeWindow)) {
QEglFSCursor *cursor = static_cast<QEglFSCursor *>(screen()->cursor());
QEglFSCursor *cursor = static_cast<QEglFSCursor *>(screen->cursor());
if (cursor)
cursor->resetResources();
if (screen()->primarySurface() == m_surface)
screen()->setPrimarySurface(EGL_NO_SURFACE);
if (screen->primarySurface() == m_surface)
screen->setPrimarySurface(EGL_NO_SURFACE);
invalidateSurface();
}
m_flags = 0;
screen()->removeWindow(this);
screen->removeWindow(this);
}
// The virtual functions resetSurface and invalidateSurface may get overridden
@ -182,20 +196,15 @@ void QEglFSWindow::setVisible(bool visible)
} else {
screen()->removeWindow(this);
windows = screen()->windows();
// try activating the window below
if (windows.size())
windows.last()->requestActivateWindow();
}
}
// trigger an update
QEglFSWindow *rootWin = screen()->rootWindow();
if (rootWin) {
QWindowSystemInterface::handleExposeEvent(rootWin->window(), rootWin->window()->geometry());
QWindowSystemInterface::flushWindowSystemEvents();
}
QWindowSystemInterface::handleExposeEvent(window(), window()->geometry());
QPlatformWindow::setVisible(visible);
if (visible)
QWindowSystemInterface::flushWindowSystemEvents();
}
void QEglFSWindow::setGeometry(const QRect &r)
@ -230,13 +239,31 @@ WId QEglFSWindow::winId() const
void QEglFSWindow::requestActivateWindow()
{
if (window()->type() != Qt::Desktop) {
// move to the end of the list, to be on top
screen()->removeWindow(this);
screen()->addWindow(this);
}
if (window()->type() != Qt::Desktop)
screen()->moveToTop(this);
QWindowSystemInterface::handleWindowActivated(window());
QWindowSystemInterface::handleExposeEvent(window(), window()->geometry());
}
void QEglFSWindow::raise()
{
if (window()->type() != Qt::Desktop) {
screen()->moveToTop(this);
QWindowSystemInterface::handleExposeEvent(window(), window()->geometry());
}
}
void QEglFSWindow::lower()
{
QList<QEglFSWindow *> windows = screen()->windows();
if (window()->type() != Qt::Desktop && windows.count() > 1) {
int idx = windows.indexOf(this);
if (idx > 0) {
screen()->changeWindowIndex(this, idx - 1);
QWindowSystemInterface::handleExposeEvent(windows.last()->window(), windows.last()->geometry());
}
}
}
EGLSurface QEglFSWindow::surface() const
@ -259,4 +286,12 @@ QEglFSScreen *QEglFSWindow::screen() const
return static_cast<QEglFSScreen *>(QPlatformWindow::screen());
}
uint QEglFSWindow::texture() const
{
if (m_backingStore)
return m_backingStore->texture();
return 0;
}
QT_END_NAMESPACE

View File

@ -62,6 +62,8 @@ public:
WId winId() const;
void setVisible(bool visible);
void requestActivateWindow();
void raise();
void lower();
EGLSurface surface() const;
QSurfaceFormat format() const;
@ -73,11 +75,13 @@ public:
void destroy();
bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); }
bool isRasterRoot() const { return m_flags.testFlag(IsRasterRoot); }
bool isRaster() const { return m_flags.testFlag(IsRaster); }
QEglFSBackingStore *backingStore() { return m_backingStore; }
void setBackingStore(QEglFSBackingStore *backingStore) { m_backingStore = backingStore; }
uint texture() const;
virtual void invalidateSurface();
virtual void resetSurface();
@ -93,9 +97,8 @@ private:
enum Flag {
Created = 0x01,
HasNativeWindow = 0x02,
IsRaster = 0x04,
IsRasterRoot = 0x08
IsRaster = 0x02,
HasNativeWindow = 0x04
};
Q_DECLARE_FLAGS(Flags, Flag);
Flags m_flags;