Added QOffscreenSurface class.

Inherits QSurface and allows to use OpenGL from an arbitrary thread.
Platform plugins can implement QPlatformOffscreenSurface, otherwise an
invisible QWindow is used by QOffscreenSurface.
This patch includes an implementation of QOffscreenSurface for XCB
and EglFS platform plugins using pbuffers.

Change-Id: I57b4fc1db417331f34826dcfa754b7698782fde4
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
This commit is contained in:
Yoann Lopes 2013-02-08 20:05:34 +01:00 committed by The Qt Project
parent f8fdeb68b6
commit c7a51f1858
22 changed files with 996 additions and 48 deletions

6
dist/changes-5.1.0 vendored
View File

@ -29,7 +29,7 @@ General Improvements
Third party components
----------------------
-
-
****************************************************************************
@ -72,7 +72,9 @@ QtCore
QtGui
-----
-
- QOffscreenSurface
* New class for rendering graphics using OpenGL in an arbitrary thread
without needing to use a hidden QWindow.
QtNetwork

View File

@ -24,6 +24,7 @@ HEADERS += \
kernel/qplatformthemefactory_p.h \
kernel/qplatformthemeplugin.h \
kernel/qplatformwindow.h \
kernel/qplatformoffscreensurface.h \
kernel/qplatformwindow_p.h \
kernel/qplatformcursor.h \
kernel/qplatformclipboard.h \
@ -34,6 +35,7 @@ HEADERS += \
kernel/qguiapplication_p.h \
kernel/qwindow_p.h \
kernel/qwindow.h \
kernel/qoffscreensurface.h \
kernel/qplatformsurface.h \
kernel/qsurface.h \
kernel/qclipboard.h \
@ -81,6 +83,7 @@ SOURCES += \
kernel/qplatformthemefactory.cpp \
kernel/qplatformthemeplugin.cpp \
kernel/qplatformwindow.cpp \
kernel/qplatformoffscreensurface.cpp \
kernel/qplatformcursor.cpp \
kernel/qplatformclipboard.cpp \
kernel/qplatformnativeinterface.cpp \
@ -88,6 +91,7 @@ SOURCES += \
kernel/qsurfaceformat.cpp \
kernel/qguiapplication.cpp \
kernel/qwindow.cpp \
kernel/qoffscreensurface.cpp \
kernel/qplatformsurface.cpp \
kernel/qsurface.cpp \
kernel/qclipboard.cpp \

View File

@ -0,0 +1,345 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module 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 "qoffscreensurface.h"
#include "qguiapplication_p.h"
#include "qscreen.h"
#include "qplatformintegration.h"
#include "qplatformoffscreensurface.h"
#include "qwindow.h"
#include "qplatformwindow.h"
QT_BEGIN_NAMESPACE
/*!
\class QOffscreenSurface
\inmodule QtGui
\since 5.1
\brief The QOffscreenSurface class represents an offscreen surface in the underlying platform.
QOffscreenSurface is intended to be used with QOpenGLContext to allow rendering with OpenGL in
an arbitrary thread without the need to create a QWindow.
Even though the surface is renderable, the surface's pixels are not accessible.
QOffscreenSurface should only be used to create OpenGL resources such as textures
or framebuffer objects.
An application will typically use QOffscreenSurface to perform some time-consuming tasks in a
separate thread in order to avoid stalling the main rendering thread. Resources created in the
QOffscreenSurface's context can be shared with the main OpenGL context. Some common use cases
are asynchronous texture uploads or rendering into a QOpenGLFramebufferObject.
How the offscreen surface is implemented depends on the underlying platform, but it will
typically use a pixel buffer (pbuffer). If the platform doesn't implement or support
offscreen surfaces, QOffscreenSurface will use an invisible QWindow internally.
*/
class Q_GUI_EXPORT QOffscreenSurfacePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QOffscreenSurface)
public:
QOffscreenSurfacePrivate()
: QObjectPrivate()
, surfaceType(QSurface::OpenGLSurface)
, platformOffscreenSurface(0)
, offscreenWindow(0)
, screen(0)
, size(1, 1)
{
}
~QOffscreenSurfacePrivate()
{
}
QSurface::SurfaceType surfaceType;
QPlatformOffscreenSurface *platformOffscreenSurface;
QWindow *offscreenWindow;
QSurfaceFormat requestedFormat;
QScreen *screen;
QSize size;
};
/*!
Creates an offscreen surface for the \a targetScreen.
The underlying platform surface is not created until create() is called.
\sa setScreen(), create()
*/
QOffscreenSurface::QOffscreenSurface(QScreen *targetScreen)
: QObject(*new QOffscreenSurfacePrivate(), 0)
, QSurface(Offscreen)
{
Q_D(QOffscreenSurface);
d->screen = targetScreen;
if (!d->screen)
d->screen = QGuiApplication::primaryScreen();
//if your applications aborts here, then chances are your creating a QOffscreenSurface before
//the screen list is populated.
Q_ASSERT(d->screen);
connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*)));
}
/*!
Destroys the offscreen surface.
*/
QOffscreenSurface::~QOffscreenSurface()
{
destroy();
}
/*!
Returns the surface type of the offscreen surface.
The surface type of an offscreen surface is always QSurface::OpenGLSurface.
*/
QOffscreenSurface::SurfaceType QOffscreenSurface::surfaceType() const
{
Q_D(const QOffscreenSurface);
return d->surfaceType;
}
/*!
Allocates the platform resources associated with the offscreen surface.
It is at this point that the surface format set using setFormat() gets resolved
into an actual native surface.
Call destroy() to free the platform resources if necessary.
\sa destroy()
*/
void QOffscreenSurface::create()
{
Q_D(QOffscreenSurface);
if (!d->platformOffscreenSurface && !d->offscreenWindow) {
d->platformOffscreenSurface = QGuiApplicationPrivate::platformIntegration()->createPlatformOffscreenSurface(this);
// No platform offscreen surface, fallback to an invisible window
if (!d->platformOffscreenSurface) {
d->offscreenWindow = new QWindow(d->screen);
d->offscreenWindow->setSurfaceType(QWindow::OpenGLSurface);
d->offscreenWindow->setFormat(d->requestedFormat);
d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height());
d->offscreenWindow->create();
}
}
}
/*!
Releases the native platform resources associated with this offscreen surface.
\sa create()
*/
void QOffscreenSurface::destroy()
{
Q_D(QOffscreenSurface);
delete d->platformOffscreenSurface;
d->platformOffscreenSurface = 0;
if (d->offscreenWindow) {
d->offscreenWindow->destroy();
delete d->offscreenWindow;
d->offscreenWindow = 0;
}
}
/*!
Returns \c true if this offscreen surface is valid; otherwise returns \c false.
The offscreen surface is valid if the platform resources have been successfuly allocated.
\sa create()
*/
bool QOffscreenSurface::isValid() const
{
Q_D(const QOffscreenSurface);
return (d->platformOffscreenSurface && d->platformOffscreenSurface->isValid())
|| (d->offscreenWindow && d->offscreenWindow->handle());
}
/*!
Sets the offscreen surface \a format.
The surface format will be resolved in the create() function. Calling
this function after create() will not re-resolve the surface format of the native surface.
\sa create(), destroy()
*/
void QOffscreenSurface::setFormat(const QSurfaceFormat &format)
{
Q_D(QOffscreenSurface);
d->requestedFormat = format;
}
/*!
Returns the requested surfaceformat of this offscreen surface.
If the requested format was not supported by the platform implementation,
the requestedFormat will differ from the actual offscreen surface format.
This is the value set with setFormat().
\sa setFormat(), format()
*/
QSurfaceFormat QOffscreenSurface::requestedFormat() const
{
Q_D(const QOffscreenSurface);
return d->requestedFormat;
}
/*!
Returns the actual format of this offscreen surface.
After the offscreen surface has been created, this function will return the actual
surface format of the surface. It might differ from the requested format if the requested
format could not be fulfilled by the platform.
\sa create(), requestedFormat()
*/
QSurfaceFormat QOffscreenSurface::format() const
{
Q_D(const QOffscreenSurface);
if (d->platformOffscreenSurface)
return d->platformOffscreenSurface->format();
if (d->offscreenWindow)
return d->offscreenWindow->format();
return d->requestedFormat;
}
/*!
Returns the size of the offscreen surface.
*/
QSize QOffscreenSurface::size() const
{
Q_D(const QOffscreenSurface);
return d->size;
}
/*!
Returns the screen to which the offscreen surface is connected.
\sa setScreen()
*/
QScreen *QOffscreenSurface::screen() const
{
Q_D(const QOffscreenSurface);
return d->screen;
}
/*!
Sets the screen to which the offscreen surface is connected.
If the offscreen surface has been created, it will be recreated on the \a newScreen.
\sa screen()
*/
void QOffscreenSurface::setScreen(QScreen *newScreen)
{
Q_D(QOffscreenSurface);
if (!newScreen)
newScreen = QGuiApplication::primaryScreen();
if (newScreen != d->screen) {
const bool wasCreated = d->platformOffscreenSurface != 0 || d->offscreenWindow != 0;
if (wasCreated)
destroy();
if (d->screen)
disconnect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*)));
d->screen = newScreen;
if (newScreen) {
connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*)));
if (wasCreated)
create();
}
emit screenChanged(newScreen);
}
}
/*!
Called when the offscreen surface's screen is destroyed.
\internal
*/
void QOffscreenSurface::screenDestroyed(QObject *object)
{
Q_D(QOffscreenSurface);
if (object == static_cast<QObject *>(d->screen))
setScreen(0);
}
/*!
\fn QOffscreenSurface::screenChanged(QScreen *screen)
This signal is emitted when an offscreen surface's \a screen changes, either
by being set explicitly with setScreen(), or automatically when
the window's screen is removed.
*/
/*!
Returns the platform offscreen surface corresponding to the offscreen surface.
\internal
*/
QPlatformOffscreenSurface *QOffscreenSurface::handle() const
{
Q_D(const QOffscreenSurface);
return d->platformOffscreenSurface;
}
/*!
Returns the platform surface corresponding to the offscreen surface.
\internal
*/
QPlatformSurface *QOffscreenSurface::surfaceHandle() const
{
Q_D(const QOffscreenSurface);
if (d->offscreenWindow)
return d->offscreenWindow->handle();
return d->platformOffscreenSurface;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module 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 QOFFSCREENSURFACE_H
#define QOFFSCREENSURFACE_H
#include <QtCore/QObject>
#include <QtGui/qsurface.h>
QT_BEGIN_NAMESPACE
class QOffscreenSurfacePrivate;
class QScreen;
class QPlatformOffscreenSurface;
class Q_GUI_EXPORT QOffscreenSurface : public QObject, public QSurface
{
Q_OBJECT
Q_DECLARE_PRIVATE(QOffscreenSurface)
public:
explicit QOffscreenSurface(QScreen *screen = 0);
virtual ~QOffscreenSurface();
SurfaceType surfaceType() const;
void create();
void destroy();
bool isValid() const;
void setFormat(const QSurfaceFormat &format);
QSurfaceFormat format() const;
QSurfaceFormat requestedFormat() const;
QSize size() const;
QScreen *screen() const;
void setScreen(QScreen *screen);
QPlatformOffscreenSurface *handle() const;
Q_SIGNALS:
void screenChanged(QScreen *screen);
private Q_SLOTS:
void screenDestroyed(QObject *screen);
private:
QPlatformSurface *surfaceHandle() const;
Q_DISABLE_COPY(QOffscreenSurface)
};
QT_END_NAMESPACE
#endif // QOFFSCREENSURFACE_H

View File

@ -360,4 +360,15 @@ class QPlatformTheme *QPlatformIntegration::createPlatformTheme(const QString &n
return new QPlatformTheme;
}
/*!
Factory function for QOffscreenSurface. An offscreen surface will typically be implemented with a
pixel buffer (pbuffer). If the platform doesn't support offscreen surfaces, an invisible window
will be used by QOffscreenSurface instead.
*/
QPlatformOffscreenSurface *QPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
Q_UNUSED(surface)
return 0;
}
QT_END_NAMESPACE

View File

@ -75,6 +75,8 @@ class QPlatformDialogHelper;
class QPlatformSharedGraphicsCache;
class QPlatformServices;
class QKeyEvent;
class QPlatformOffscreenSurface;
class QOffscreenSurface;
class Q_GUI_EXPORT QPlatformIntegration
{
@ -146,6 +148,8 @@ public:
virtual QStringList themeNames() const;
virtual QPlatformTheme *createPlatformTheme(const QString &name) const;
virtual QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const;
protected:
void screenAdded(QPlatformScreen *screen);
};

View File

@ -0,0 +1,93 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module 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 "qplatformoffscreensurface.h"
#include "qoffscreensurface.h"
#include "qscreen.h"
QT_BEGIN_NAMESPACE
class QPlatformOffscreenSurfacePrivate
{
public:
};
QPlatformOffscreenSurface::QPlatformOffscreenSurface(QOffscreenSurface *offscreenSurface)
: QPlatformSurface(offscreenSurface)
, d_ptr(new QPlatformOffscreenSurfacePrivate)
{
}
QPlatformOffscreenSurface::~QPlatformOffscreenSurface()
{
}
QOffscreenSurface *QPlatformOffscreenSurface::offscreenSurface() const
{
return static_cast<QOffscreenSurface*>(m_surface);
}
/*!
Returns the platform screen handle corresponding to this QPlatformOffscreenSurface.
*/
QPlatformScreen *QPlatformOffscreenSurface::screen() const
{
return offscreenSurface()->screen()->handle();
}
/*!
Returns the actual surface format of the offscreen surface.
*/
QSurfaceFormat QPlatformOffscreenSurface::format() const
{
return QSurfaceFormat();
}
/*!
Returns \c true if the platform offscreen surface has been allocated.
*/
bool QPlatformOffscreenSurface::isValid() const
{
return false;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,85 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module 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 QPLATFORMOFFSCREENSURFACE_H
#define QPLATFORMOFFSCREENSURFACE_H
//
// W A R N I N G
// -------------
//
// This file is part of the QPA API and is not meant to be used
// in applications. Usage of this API may make your code
// source and binary incompatible with future versions of Qt.
//
#include "qplatformsurface.h"
#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
class QOffscreenSurface;
class QPlatformScreen;
class QPlatformOffscreenSurfacePrivate;
class Q_GUI_EXPORT QPlatformOffscreenSurface : public QPlatformSurface
{
Q_DECLARE_PRIVATE(QPlatformOffscreenSurface)
public:
explicit QPlatformOffscreenSurface(QOffscreenSurface *offscreenSurface);
virtual ~QPlatformOffscreenSurface();
QOffscreenSurface *offscreenSurface() const;
QPlatformScreen *screen() const;
virtual QSurfaceFormat format() const;
virtual bool isValid() const;
protected:
QScopedPointer<QPlatformOffscreenSurfacePrivate> d_ptr;
private:
Q_DISABLE_COPY(QPlatformOffscreenSurface)
};
QT_END_NAMESPACE
#endif // QPLATFORMOFFSCREENSURFACE_H

View File

@ -72,6 +72,7 @@ private:
QSurface *m_surface;
friend class QPlatformWindow;
friend class QPlatformOffscreenSurface;
};
QT_END_NAMESPACE

View File

@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE
The SurfaceClass enum describes the actual subclass of the surface.
\value Window The surface is an instance of QWindow.
\value Offscreen The surface is an instance of QOffscreenSurface.
*/

View File

@ -58,7 +58,8 @@ class Q_GUI_EXPORT QSurface
{
public:
enum SurfaceClass {
Window
Window,
Offscreen
};
enum SurfaceType {

View File

@ -1,10 +1,12 @@
contains(QT_CONFIG,egl) {
HEADERS += \
$$PWD/qeglconvenience_p.h \
$$PWD/qeglplatformcontext_p.h
$$PWD/qeglplatformcontext_p.h \
$$PWD/qeglpbuffer_p.h
SOURCES += \
$$PWD/qeglconvenience.cpp \
$$PWD/qeglplatformcontext.cpp
$$PWD/qeglplatformcontext.cpp \
$$PWD/qeglpbuffer.cpp
contains(QT_CONFIG,xlib) {
HEADERS += \

View File

@ -0,0 +1,76 @@
/****************************************************************************
**
** 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 <QtGui/QOffscreenSurface>
#include "qeglpbuffer_p.h"
#include "qeglconvenience_p.h"
QT_BEGIN_NAMESPACE
QEGLPbuffer::QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface)
: QPlatformOffscreenSurface(offscreenSurface)
, m_format(format)
, m_display(display)
, m_pbuffer(EGL_NO_SURFACE)
{
EGLConfig config = q_configFromGLFormat(m_display, m_format, false, EGL_PBUFFER_BIT);
if (config) {
const EGLint attributes[] = {
EGL_WIDTH, offscreenSurface->size().width(),
EGL_HEIGHT, offscreenSurface->size().height(),
EGL_LARGEST_PBUFFER, EGL_FALSE,
EGL_NONE
};
m_pbuffer = eglCreatePbufferSurface(m_display, config, attributes);
if (m_pbuffer != EGL_NO_SURFACE)
m_format = q_glFormatFromConfig(m_display, config);
}
}
QEGLPbuffer::~QEGLPbuffer()
{
eglDestroySurface(m_display, m_pbuffer);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,69 @@
/****************************************************************************
**
** 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 QEGLPBUFFER_H
#define QEGLPBUFFER_H
#include <EGL/egl.h>
#include <qpa/qplatformoffscreensurface.h>
QT_BEGIN_NAMESPACE
class QEGLPbuffer : public QPlatformOffscreenSurface
{
public:
QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface);
~QEGLPbuffer();
QSurfaceFormat format() const { return m_format; }
bool isValid() const { return m_pbuffer != EGL_NO_SURFACE; }
EGLSurface pbuffer() const { return m_pbuffer; }
private:
QSurfaceFormat m_format;
EGLDisplay m_display;
EGLSurface m_pbuffer;
};
QT_END_NAMESPACE
#endif // QEGLPBUFFER_H

View File

@ -45,6 +45,8 @@
#include "qeglfshooks.h"
#include "qeglfsintegration.h"
#include <QtPlatformSupport/private/qeglpbuffer_p.h>
#include <QtGui/QSurface>
#include <QtDebug>
QT_BEGIN_NAMESPACE
@ -62,16 +64,20 @@ bool QEglFSContext::makeCurrent(QPlatformSurface *surface)
EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
return window->surface();
if (surface->surface()->surfaceClass() == QSurface::Window)
return static_cast<QEglFSWindow *>(surface)->surface();
else
return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
void QEglFSContext::swapBuffers(QPlatformSurface *surface)
{
QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
// draw the cursor
if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->cursor()))
cursor->paintOnScreen();
if (surface->surface()->surfaceClass() == QSurface::Window) {
QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
// draw the cursor
if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->cursor()))
cursor->paintOnScreen();
}
QEGLPlatformContext::swapBuffers(surface);
}

View File

@ -51,6 +51,7 @@
#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
#include <QtPlatformSupport/private/qeglpbuffer_p.h>
#if !defined(QT_NO_EVDEV)
#include <QtPlatformSupport/private/qevdevmousemanager_p.h>
@ -62,6 +63,7 @@
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
#include <QtGui/QOffscreenSurface>
#include <qpa/qplatformcursor.h>
#include "qeglfscontext.h"
@ -154,6 +156,12 @@ QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLCo
return new QEglFSContext(hooks->surfaceFormatFor(context->format()), context->shareHandle(), mDisplay);
}
QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
QEglFSScreen *screen = static_cast<QEglFSScreen *>(surface->screen()->handle());
return new QEGLPbuffer(screen->display(), hooks->surfaceFormatFor(surface->requestedFormat()), surface);
}
QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const
{
return mFontDb;

View File

@ -61,6 +61,7 @@ public:
QPlatformWindow *createPlatformWindow(QWindow *window) const;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const;
QPlatformNativeInterface *nativeInterface() const;
QPlatformFontDatabase *fontDatabase() const;

View File

@ -50,6 +50,7 @@
#include <GL/glx.h>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOffscreenSurface>
#include "qglxintegration.h"
#include <QtPlatformSupport/private/qglxconvenience_p.h>
@ -270,6 +271,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
, m_screen(screen)
, m_context(0)
, m_format(format)
, m_isPBufferCurrent(false)
{
m_shareContext = 0;
if (share)
@ -390,19 +392,35 @@ bool QGLXContext::makeCurrent(QPlatformSurface *surface)
{
Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), glxDrawable, m_context);
QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass();
if (surfaceClass == QSurface::Window) {
m_isPBufferCurrent = false;
QXcbWindow *window = static_cast<QXcbWindow *>(surface);
return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), window->xcb_window(), m_context);
} else if (surfaceClass == QSurface::Offscreen) {
m_isPBufferCurrent = true;
QGLXPbuffer *pbuffer = static_cast<QGLXPbuffer *>(surface);
return glXMakeContextCurrent(DISPLAY_FROM_XCB(m_screen), pbuffer->pbuffer(), pbuffer->pbuffer(), m_context);
}
return false;
}
void QGLXContext::doneCurrent()
{
glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0);
if (m_isPBufferCurrent)
glXMakeContextCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0, 0);
else
glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0);
m_isPBufferCurrent = false;
}
void QGLXContext::swapBuffers(QPlatformSurface *surface)
{
GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
GLXDrawable glxDrawable = 0;
if (surface->surface()->surfaceClass() == QSurface::Offscreen)
glxDrawable = static_cast<QGLXPbuffer *>(surface)->pbuffer();
else
glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), glxDrawable);
}
@ -454,4 +472,36 @@ bool QGLXContext::isValid() const
return m_context != 0;
}
QGLXPbuffer::QGLXPbuffer(QOffscreenSurface *offscreenSurface)
: QPlatformOffscreenSurface(offscreenSurface)
, m_format(offscreenSurface->requestedFormat())
, m_screen(static_cast<QXcbScreen *>(offscreenSurface->screen()->handle()))
, m_pbuffer(0)
{
GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), m_format);
if (config) {
const int attributes[] = {
GLX_PBUFFER_WIDTH, offscreenSurface->size().width(),
GLX_PBUFFER_HEIGHT, offscreenSurface->size().height(),
GLX_LARGEST_PBUFFER, False,
GLX_PRESERVED_CONTENTS, False,
GLX_NONE
};
m_pbuffer = glXCreatePbuffer(DISPLAY_FROM_XCB(m_screen), config, attributes);
if (m_pbuffer)
m_format = qglx_surfaceFormatFromGLXFBConfig(DISPLAY_FROM_XCB(m_screen), config);
}
}
QGLXPbuffer::~QGLXPbuffer()
{
if (m_pbuffer)
glXDestroyPbuffer(DISPLAY_FROM_XCB(m_screen), m_pbuffer);
}
QT_END_NAMESPACE

View File

@ -46,6 +46,7 @@
#include "qxcbscreen.h"
#include <qpa/qplatformopenglcontext.h>
#include <qpa/qplatformoffscreensurface.h>
#include <QtGui/QSurfaceFormat>
#include <QtCore/QMutex>
@ -89,6 +90,25 @@ private:
GLXContext m_context;
GLXContext m_shareContext;
QSurfaceFormat m_format;
bool m_isPBufferCurrent;
};
class QGLXPbuffer : public QPlatformOffscreenSurface
{
public:
explicit QGLXPbuffer(QOffscreenSurface *offscreenSurface);
~QGLXPbuffer();
QSurfaceFormat format() const { return m_format; }
bool isValid() const { return m_pbuffer != 0; }
GLXPbuffer pbuffer() const { return m_pbuffer; }
private:
QSurfaceFormat m_format;
QXcbScreen *m_screen;
GLXPbuffer m_pbuffer;
};
QT_END_NAMESPACE

View File

@ -78,10 +78,12 @@
#elif defined(XCB_USE_EGL)
#include "qxcbeglsurface.h"
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
#include <QtPlatformSupport/private/qeglpbuffer_p.h>
#endif
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
#include <QtGui/QOffscreenSurface>
#ifndef QT_NO_ACCESSIBILITY
#include <qpa/qplatformaccessibility.h>
#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
@ -168,7 +170,10 @@ public:
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
return static_cast<QXcbWindow *>(surface)->eglSurface()->surface();
if (surface->surface()->surfaceClass() == QSurface::Window)
return static_cast<QXcbWindow *>(surface)->eglSurface()->surface();
else
return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
private:
@ -205,6 +210,20 @@ QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *wind
return new QXcbBackingStore(window);
}
QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
#if defined(XCB_USE_GLX)
return new QGLXPbuffer(surface);
#elif defined(XCB_USE_EGL)
QXcbScreen *screen = static_cast<QXcbScreen *>(surface->screen()->handle());
return new QEGLPbuffer(screen->connection()->egl_display(), surface->requestedFormat(), surface);
#else
Q_UNUSED(surface);
qWarning("QXcbIntegration: Cannot create platform offscreen surface, neither GLX nor EGL are enabled");
return 0;
#endif
}
bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {

View File

@ -68,6 +68,8 @@ public:
#endif
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const;
bool hasCapability(Capability cap) const;
QAbstractEventDispatcher *guiThreadEventDispatcher() const;

View File

@ -47,6 +47,7 @@
#include <QtGui/QPainter>
#include <QtGui/QScreen>
#include <QtGui/QWindow>
#include <QtGui/QOffscreenSurface>
#include <QtTest/QtTest>
@ -57,12 +58,18 @@ class tst_QOpenGL : public QObject
Q_OBJECT
private slots:
void sharedResourceCleanup_data();
void sharedResourceCleanup();
void multiGroupSharedResourceCleanup_data();
void multiGroupSharedResourceCleanup();
void multiGroupSharedResourceCleanupCustom_data();
void multiGroupSharedResourceCleanupCustom();
void fboSimpleRendering_data();
void fboSimpleRendering();
void fboRendering_data();
void fboRendering();
void fboHandleNulledAfterContextDestroyed();
void openGLPaintDevice_data();
void openGLPaintDevice();
void aboutToBeDestroyed();
void QTBUG15621_triangulatingStrokerDivZero();
@ -129,16 +136,43 @@ struct SharedResource : public QOpenGLSharedResource
SharedResourceTracker *tracker;
};
static QSurface *createSurface(int surfaceClass)
{
if (surfaceClass == int(QSurface::Window)) {
QWindow *window = new QWindow;
window->setSurfaceType(QWindow::OpenGLSurface);
window->setGeometry(0, 0, 10, 10);
window->create();
return window;
} else if (surfaceClass == int(QSurface::Offscreen)) {
QOffscreenSurface *offscreenSurface = new QOffscreenSurface;
offscreenSurface->create();
return offscreenSurface;
}
return 0;
}
static void common_data()
{
QTest::addColumn<int>("surfaceClass");
QTest::newRow("Using QWindow") << int(QSurface::Window);
QTest::newRow("Using QOffscreenSurface") << int(QSurface::Offscreen);
}
void tst_QOpenGL::sharedResourceCleanup_data()
{
common_data();
}
void tst_QOpenGL::sharedResourceCleanup()
{
QWindow window;
window.setSurfaceType(QWindow::OpenGLSurface);
window.setGeometry(0, 0, 10, 10);
window.create();
QFETCH(int, surfaceClass);
QScopedPointer<QSurface> surface(createSurface(surfaceClass));
QOpenGLContext *ctx = new QOpenGLContext;
ctx->create();
ctx->makeCurrent(&window);
ctx->makeCurrent(surface.data());
SharedResourceTracker tracker;
SharedResource *resource = new SharedResource(&tracker);
@ -165,7 +199,7 @@ void tst_QOpenGL::sharedResourceCleanup()
QCOMPARE(tracker.freeResourceCalls, 0);
QCOMPARE(tracker.destructorCalls, 0);
ctx2->makeCurrent(&window);
ctx2->makeCurrent(surface.data());
// freeResource() should now have been called
QCOMPARE(tracker.invalidateResourceCalls, 0);
@ -192,17 +226,20 @@ void tst_QOpenGL::sharedResourceCleanup()
QCOMPARE(tracker.destructorCalls, 1);
}
void tst_QOpenGL::multiGroupSharedResourceCleanup_data()
{
common_data();
}
void tst_QOpenGL::multiGroupSharedResourceCleanup()
{
QWindow window;
window.setSurfaceType(QWindow::OpenGLSurface);
window.setGeometry(0, 0, 10, 10);
window.create();
QFETCH(int, surfaceClass);
QScopedPointer<QSurface> surface(createSurface(surfaceClass));
for (int i = 0; i < 10; ++i) {
QOpenGLContext *gl = new QOpenGLContext();
gl->create();
gl->makeCurrent(&window);
gl->makeCurrent(surface.data());
{
// Cause QOpenGLMultiGroupSharedResource instantiation.
QOpenGLFunctions func(gl);
@ -214,16 +251,19 @@ void tst_QOpenGL::multiGroupSharedResourceCleanup()
// Shouldn't crash when application exits.
}
void tst_QOpenGL::multiGroupSharedResourceCleanupCustom_data()
{
common_data();
}
void tst_QOpenGL::multiGroupSharedResourceCleanupCustom()
{
QWindow window;
window.setSurfaceType(QWindow::OpenGLSurface);
window.setGeometry(0, 0, 10, 10);
window.create();
QFETCH(int, surfaceClass);
QScopedPointer<QSurface> surface(createSurface(surfaceClass));
QOpenGLContext *ctx = new QOpenGLContext();
ctx->create();
ctx->makeCurrent(&window);
ctx->makeCurrent(surface.data());
QOpenGLMultiGroupSharedResource multiGroupSharedResource;
SharedResource *resource = multiGroupSharedResource.value<SharedResource>(ctx);
@ -350,17 +390,20 @@ void qt_opengl_check_test_pattern(const QImage& img)
QFUZZY_COMPARE_PIXELS(img.pixel(192, 64), QColor(Qt::green).rgb());
}
void tst_QOpenGL::fboSimpleRendering_data()
{
common_data();
}
void tst_QOpenGL::fboSimpleRendering()
{
QWindow window;
window.setSurfaceType(QWindow::OpenGLSurface);
window.setGeometry(0, 0, 10, 10);
window.create();
QFETCH(int, surfaceClass);
QScopedPointer<QSurface> surface(createSurface(surfaceClass));
QOpenGLContext ctx;
ctx.create();
ctx.makeCurrent(&window);
ctx.makeCurrent(surface.data());
if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects())
QSKIP("QOpenGLFramebufferObject not supported on this platform");
@ -386,6 +429,11 @@ void tst_QOpenGL::fboSimpleRendering()
delete fbo;
}
void tst_QOpenGL::fboRendering_data()
{
common_data();
}
// NOTE: This tests that CombinedDepthStencil attachment works by assuming the
// GL2 engine is being used and is implemented the same way as it was when
// this autotest was written. If this is not the case, there may be some
@ -397,14 +445,13 @@ void tst_QOpenGL::fboRendering()
QSKIP("QTBUG-22617");
#endif
QWindow window;
window.setSurfaceType(QWindow::OpenGLSurface);
window.setGeometry(0, 0, 10, 10);
window.create();
QFETCH(int, surfaceClass);
QScopedPointer<QSurface> surface(createSurface(surfaceClass));
QOpenGLContext ctx;
ctx.create();
ctx.makeCurrent(&window);
ctx.makeCurrent(surface.data());
if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects())
QSKIP("QOpenGLFramebufferObject not supported on this platform");
@ -461,16 +508,19 @@ void tst_QOpenGL::fboHandleNulledAfterContextDestroyed()
QCOMPARE(fbo->handle(), 0U);
}
void tst_QOpenGL::openGLPaintDevice_data()
{
common_data();
}
void tst_QOpenGL::openGLPaintDevice()
{
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(__x86_64__)
QSKIP("QTBUG-22617");
#endif
QWindow window;
window.setSurfaceType(QWindow::OpenGLSurface);
window.setGeometry(0, 0, 128, 128);
window.create();
QFETCH(int, surfaceClass);
QScopedPointer<QSurface> surface(createSurface(surfaceClass));
QOpenGLContext ctx;
ctx.create();
@ -478,7 +528,7 @@ void tst_QOpenGL::openGLPaintDevice()
QSurfaceFormat format = ctx.format();
if (format.majorVersion() < 2)
QSKIP("This test requires at least OpenGL 2.0");
ctx.makeCurrent(&window);
ctx.makeCurrent(surface.data());
QImage image(128, 128, QImage::Format_RGB32);
QPainter p(&image);