Add public and QPA APIs for adapting existing OpenGL contexts
For now only xcb on GLX is supported. Other platforms will follow later. Add also some missing documentation for the platform OpenGL context factory functions. [ChangeLog] QOpenGLContext is now able to adopt existing native contexts. Task-number: QTBUG-37552 Change-Id: I5dd959f102df178f646b2df5989203b5dc6de376 Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
This commit is contained in:
parent
787692a09e
commit
af1e32426c
@ -479,6 +479,64 @@ void QOpenGLContext::setScreen(QScreen *screen)
|
||||
d->screen = QGuiApplication::primaryScreen();
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the native handles for this context. When create() is called and a
|
||||
native handle is set, configuration settings, like format(), are ignored
|
||||
since this QOpenGLContext will wrap an already created native context
|
||||
instead of creating a new one from scratch.
|
||||
|
||||
On some platforms the native context handle is not sufficient and other
|
||||
related handles (for example, for a window or display) have to be provided
|
||||
in addition. Therefore \a handle is variant containing a platform-specific
|
||||
value type. These classes can be found in the QtPlatformHeaders module.
|
||||
|
||||
When create() is called with native handles set, the handles' ownership are
|
||||
not taken, meaning that destroy() will not destroy the native context.
|
||||
|
||||
\note Some frameworks track the current context and surfaces internally.
|
||||
Making the adopted QOpenGLContext current via Qt will have no effect on such
|
||||
other frameworks' internal state. Therefore a subsequent makeCurrent done
|
||||
via the other framework may have no effect. It is therefore advisable to
|
||||
make explicit calls to make no context and surface current to reset the
|
||||
other frameworks' internal state after performing OpenGL operations via Qt.
|
||||
|
||||
\note Using foreign contexts with Qt windows and Qt contexts with windows
|
||||
and surfaces created by other frameworks may give unexpected results,
|
||||
depending on the platform, due to potential mismatches in context and window
|
||||
pixel formats. To make sure this does not happen, avoid making contexts and
|
||||
surfaces from different frameworks current together. Instead, prefer
|
||||
approaches based on context sharing where OpenGL resources like textures are
|
||||
accessible both from Qt's and the foreign framework's contexts.
|
||||
|
||||
\since 5.4
|
||||
\sa nativeHandle()
|
||||
*/
|
||||
void QOpenGLContext::setNativeHandle(const QVariant &handle)
|
||||
{
|
||||
Q_D(QOpenGLContext);
|
||||
d->nativeHandle = handle;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the native handle for the context.
|
||||
|
||||
This function provides access to the QOpenGLContext's underlying native
|
||||
context. The returned variant contains a platform-specific value type. These
|
||||
classes can be found in the module QtPlatformHeaders.
|
||||
|
||||
On platforms where retrieving the native handle is not supported, or if
|
||||
neither create() nor setNativeHandle() was called, a null variant is
|
||||
returned.
|
||||
|
||||
\since 5.4
|
||||
\sa setNativeHandle()
|
||||
*/
|
||||
QVariant QOpenGLContext::nativeHandle() const
|
||||
{
|
||||
Q_D(const QOpenGLContext);
|
||||
return d->nativeHandle;
|
||||
}
|
||||
|
||||
/*!
|
||||
Attempts to create the OpenGL context with the current configuration.
|
||||
|
||||
@ -500,7 +558,8 @@ void QOpenGLContext::setScreen(QScreen *screen)
|
||||
*/
|
||||
bool QOpenGLContext::create()
|
||||
{
|
||||
destroy();
|
||||
if (isValid())
|
||||
destroy();
|
||||
|
||||
Q_D(QOpenGLContext);
|
||||
d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformOpenGLContext(this);
|
||||
@ -550,6 +609,7 @@ void QOpenGLContext::destroy()
|
||||
d->versionFunctionsBackend.clear();
|
||||
delete d->textureFunctions;
|
||||
d->textureFunctions = 0;
|
||||
d->nativeHandle = QVariant();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -64,6 +64,7 @@
|
||||
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qpair.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -153,6 +154,7 @@ public:
|
||||
void setFormat(const QSurfaceFormat &format);
|
||||
void setShareContext(QOpenGLContext *shareContext);
|
||||
void setScreen(QScreen *screen);
|
||||
void setNativeHandle(const QVariant &handle);
|
||||
|
||||
bool create();
|
||||
bool isValid() const;
|
||||
@ -161,6 +163,7 @@ public:
|
||||
QOpenGLContext *shareContext() const;
|
||||
QOpenGLContextGroup *shareGroup() const;
|
||||
QScreen *screen() const;
|
||||
QVariant nativeHandle() const;
|
||||
|
||||
GLuint defaultFramebufferObject() const;
|
||||
|
||||
@ -242,4 +245,4 @@ QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
#endif // QGUIGLCONTEXT_H
|
||||
#endif // QOPENGLCONTEXT_H
|
||||
|
@ -242,6 +242,8 @@ public:
|
||||
|
||||
QPaintEngineEx *active_engine;
|
||||
|
||||
QVariant nativeHandle;
|
||||
|
||||
static QOpenGLContext *setCurrentContext(QOpenGLContext *context);
|
||||
|
||||
static void setGlobalShareContext(QOpenGLContext *context);
|
||||
|
@ -271,13 +271,32 @@ QPlatformPixmap *QPlatformIntegration::createPlatformPixmap(QPlatformPixmap::Pix
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
/*!
|
||||
Factory function for QPlatformOpenGLContext. The \a context parameter is a pointer to
|
||||
the context for which a platform-specific context backend needs to be
|
||||
created. Configuration settings like the format, share context and screen have to be
|
||||
taken from this QOpenGLContext and the resulting platform context is expected to be
|
||||
backed by a native context that fulfills these criteria.
|
||||
|
||||
If the context has native handles set, no new native context is expected to be created.
|
||||
Instead, the provided handles have to be used. In this case the ownership of the handle
|
||||
must not be taken and the platform implementation is not allowed to destroy the native
|
||||
context. Configuration parameters like the format are also to be ignored. Instead, the
|
||||
platform implementation is responsible for querying the configuriation from the provided
|
||||
native context.
|
||||
|
||||
Returns a pointer to a QPlatformOpenGLContext instance or \c NULL if the context could
|
||||
not be created.
|
||||
|
||||
\sa QOpenGLContext
|
||||
*/
|
||||
QPlatformOpenGLContext *QPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
|
||||
{
|
||||
Q_UNUSED(context);
|
||||
qWarning("This plugin does not support createPlatformOpenGLContext!");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
/*!
|
||||
Factory function for QPlatformSharedGraphicsCache. This function will return 0 if the platform
|
||||
|
51
src/platformheaders/doc/qtplatformheaders.qdocconf
Normal file
51
src/platformheaders/doc/qtplatformheaders.qdocconf
Normal file
@ -0,0 +1,51 @@
|
||||
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
|
||||
|
||||
# Name of the project which must match the outputdir. Determines the .index file
|
||||
project = QtPlatformHeaders
|
||||
|
||||
# Directories in which to search for files to document and images.
|
||||
# By default set to the root directory of the project for sources
|
||||
# and headers and qdoc will therefore generate output for each file.
|
||||
# Images should be placed in <rootdir>/dic/images and examples in
|
||||
# <rootdir>/examples.
|
||||
# Paths are relative to the location of this file.
|
||||
|
||||
headerdirs += ..
|
||||
sourcedirs += ..
|
||||
exampledirs += ..
|
||||
imagedirs += images
|
||||
|
||||
depends += qtdoc qtcore qtgui qtwidgets
|
||||
|
||||
examplesinstallpath = platformheaders
|
||||
|
||||
# The following parameters are for creating a qhp file, the qhelpgenerator
|
||||
# program can convert the qhp file into a qch file which can be opened in
|
||||
# Qt Assistant and/or Qt Creator.
|
||||
|
||||
# Defines the name of the project. You cannot use operators (+, =, -) in
|
||||
# the name. Properties for this project are set using a qhp.<projectname>.property
|
||||
# format.
|
||||
qhp.projects = QtPlatformHeaders
|
||||
|
||||
# Sets the name of the output qhp file.
|
||||
qhp.QtPlatformHeaders.file = qtplatformheaders.qhp
|
||||
|
||||
# Namespace for the output file. This namespace is used to distinguish between
|
||||
# different documentation files in Creator/Assistant.
|
||||
qhp.QtPlatformHeaders.namespace = org.qt-project.qtplatformheaders.$QT_VERSION_TAG
|
||||
|
||||
# Title for the package, will be the main title for the package in
|
||||
# Assistant/Creator.
|
||||
qhp.QtPlatformHeaders.indexTitle = Qt Platform Headers
|
||||
|
||||
# Only update the name of the project for the next variables.
|
||||
qhp.QtPlatformHeaders.virtualFolder = qtplatformheaders
|
||||
qhp.QtPlatformHeaders.subprojects = classes
|
||||
qhp.QtPlatformHeaders.subprojects.classes.title = C++ Classes
|
||||
qhp.QtPlatformHeaders.subprojects.classes.indexTitle = Qt Platform Headers C++ Classes
|
||||
qhp.QtPlatformHeaders.subprojects.classes.selectors = class fake:headerfile
|
||||
qhp.QtPlatformHeaders.subprojects.classes.sortPages = true
|
||||
|
||||
navigation.landingpage = "Qt Platform Headers"
|
||||
navigation.cppclassespage = "Qt Platform Headers C++ Classes"
|
68
src/platformheaders/doc/src/qtplatformheaders.qdoc
Normal file
68
src/platformheaders/doc/src/qtplatformheaders.qdoc
Normal file
@ -0,0 +1,68 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:FDL$
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: http://www.gnu.org/copyleft/fdl.html.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*!
|
||||
\module QtPlatformHeaders
|
||||
\title Qt Platform Headers C++ Classes
|
||||
\ingroup modules
|
||||
|
||||
\brief The Qt Platform Headers module offers header-only inline classes that
|
||||
encapsulate platform-specific information that is tied to a given runtime
|
||||
configuration of a platform plugin.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\page qtplatformheaders-index.html
|
||||
\title Qt Platform Headers
|
||||
|
||||
\brief The Qt Platform Headers module offers header-only inline classes that
|
||||
encapsulate platform-specific information that is tied to a given runtime
|
||||
configuration of a platform plugin.
|
||||
|
||||
Some applications may need to interface Qt with other frameworks. This often
|
||||
means using graphics contexts or other types of native handles created by
|
||||
one framework with another. For example, on some platforms, QOpenGLContext
|
||||
offers the ability to wrap an existing native OpenGL context, instead of
|
||||
creating a new one. This existing native context can be created by some
|
||||
other third-party code.
|
||||
|
||||
The type of such native handles is highly platform specific and in some
|
||||
cases the platform plugin will need more information to adopt a handle, just
|
||||
the handle in itself will not be sufficient. Therefore the public API
|
||||
consists of functions taking or returning a QVariant that contains a
|
||||
platform-specific value type. See for example
|
||||
QOpenGLContext::setNativeHandle() and QOpenGLContext::nativeHandle(). When
|
||||
running on Linux/X11, using the xcb platform plugin and the GLX windowing
|
||||
system interface, the variant contains a QGLXNativeContext. On other
|
||||
platforms a different class will be used. These classes are all placed in
|
||||
the Qt Platform Headers module.
|
||||
|
||||
\note Similar to the other QPA APIs, there are no binary compatibility
|
||||
guarantees for these classes, meaning that an application using these
|
||||
classes is only guaranteed to work with the Qt version it was developed
|
||||
against. Unlike QPA however, source compatibility is guaranteed.
|
||||
*/
|
1
src/platformheaders/nativecontexts/nativecontexts.pri
Normal file
1
src/platformheaders/nativecontexts/nativecontexts.pri
Normal file
@ -0,0 +1 @@
|
||||
HEADERS += $$PWD/qglxnativecontext.h
|
82
src/platformheaders/nativecontexts/qglxnativecontext.h
Normal file
82
src/platformheaders/nativecontexts/qglxnativecontext.h
Normal file
@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 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 QGLXNATIVECONTEXT_H
|
||||
#define QGLXNATIVECONTEXT_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct QGLXNativeContext
|
||||
{
|
||||
QGLXNativeContext()
|
||||
: m_context(0),
|
||||
m_display(0),
|
||||
m_window(0),
|
||||
m_visualId(0)
|
||||
{ }
|
||||
|
||||
QGLXNativeContext(GLXContext ctx, Display *dpy = 0, Window wnd = 0, VisualID vid = 0)
|
||||
: m_context(ctx),
|
||||
m_display(dpy),
|
||||
m_window(wnd),
|
||||
m_visualId(vid)
|
||||
{ }
|
||||
|
||||
GLXContext context() const { return m_context; }
|
||||
Display *display() const { return m_display; }
|
||||
Window window() const { return m_window; }
|
||||
VisualID visualId() const { return m_visualId; }
|
||||
|
||||
private:
|
||||
GLXContext m_context;
|
||||
Display *m_display;
|
||||
Window m_window;
|
||||
VisualID m_visualId;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QGLXNativeContext)
|
||||
|
||||
#endif // QGLXNATIVECONTEXT_H
|
83
src/platformheaders/nativecontexts/qglxnativecontext.qdoc
Normal file
83
src/platformheaders/nativecontexts/qglxnativecontext.qdoc
Normal file
@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:FDL$
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: http://www.gnu.org/copyleft/fdl.html.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*!
|
||||
\class QGLXNativeContext
|
||||
\inmodule QtPlatformHeaders
|
||||
\since 5.4
|
||||
|
||||
\brief A class encapsulating a GLXContext and related native handles.
|
||||
|
||||
\note Only context() is guaranteed to be valid. The other handles may be all \c 0. They are
|
||||
useful however when QOpenGLContext::setNativeHandle() is used to adopt a legacy context
|
||||
created by glXCreateContext. To adopt such a context, either the Window or VisualID
|
||||
that had been used to create the context needs to be known, otherwise the adoption will
|
||||
fail. For modern contexts created with an FBConfig, these are not necessary, the
|
||||
GLXContext itself is sufficient. The Display is optional.
|
||||
|
||||
\note As of Qt 5.4 there is no binary compatibility guarantee for this class, meaning
|
||||
that an application using it is only guaranteed to work with the Qt version it was
|
||||
developed against.
|
||||
|
||||
\sa QOpenGLContext::setNativeHandle(), QOpenGLContext::nativeHandle()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn GLXContext QGLXNativeContext::context() const
|
||||
|
||||
\return the GLXContext.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn Display *QGLXNativeContext::display() const
|
||||
|
||||
\return a pointer to the X11 display or \c NULL if not available.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn Window QGLXNativeContext::window() const
|
||||
|
||||
\return the X11 Window or \c 0 if not available.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn VisualID QGLXNativeContext::visualId() const
|
||||
|
||||
\return the X11 visual ID or \c 0 if not available.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QGLXNativeContext::QGLXNativeContext()
|
||||
|
||||
Construct a new instance with no handles.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QGLXNativeContext::QGLXNativeContext(GLXContext ctx, Display *dpy = 0, Window wnd = 0, VisualID vid = 0)
|
||||
|
||||
Constructs a new instance with the provided \a ctx, \a dpy, \a wnd, \a vid handles.
|
||||
*/
|
11
src/platformheaders/platformheaders.pro
Normal file
11
src/platformheaders/platformheaders.pro
Normal file
@ -0,0 +1,11 @@
|
||||
# Only headers here, no library is wanted.
|
||||
TEMPLATE = subdirs
|
||||
VERSION = $$MODULE_VERSION
|
||||
MODULE_INCNAME = QtPlatformHeaders
|
||||
|
||||
include(nativecontexts/nativecontexts.pri)
|
||||
|
||||
QMAKE_DOCS = $$PWD/doc/qtplatformheaders.qdocconf
|
||||
|
||||
load(qt_module_headers)
|
||||
load(qt_docs)
|
@ -250,7 +250,7 @@ XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *f
|
||||
return visualInfo;
|
||||
}
|
||||
|
||||
void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config, GLXContext)
|
||||
void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config)
|
||||
{
|
||||
int redSize = 0;
|
||||
int greenSize = 0;
|
||||
@ -262,8 +262,6 @@ void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display,
|
||||
int sampleCount = 0;
|
||||
int stereo = 0;
|
||||
|
||||
XVisualInfo *vi = glXGetVisualFromFBConfig(display,config);
|
||||
XFree(vi);
|
||||
glXGetFBConfigAttrib(display, config, GLX_RED_SIZE, &redSize);
|
||||
glXGetFBConfigAttrib(display, config, GLX_GREEN_SIZE, &greenSize);
|
||||
glXGetFBConfigAttrib(display, config, GLX_BLUE_SIZE, &blueSize);
|
||||
@ -287,6 +285,41 @@ void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display,
|
||||
format->setStereo(stereo);
|
||||
}
|
||||
|
||||
void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo)
|
||||
{
|
||||
int redSize = 0;
|
||||
int greenSize = 0;
|
||||
int blueSize = 0;
|
||||
int alphaSize = 0;
|
||||
int depthSize = 0;
|
||||
int stencilSize = 0;
|
||||
int sampleBuffers = 0;
|
||||
int sampleCount = 0;
|
||||
int stereo = 0;
|
||||
|
||||
glXGetConfig(display, visualInfo, GLX_RED_SIZE, &redSize);
|
||||
glXGetConfig(display, visualInfo, GLX_GREEN_SIZE, &greenSize);
|
||||
glXGetConfig(display, visualInfo, GLX_BLUE_SIZE, &blueSize);
|
||||
glXGetConfig(display, visualInfo, GLX_ALPHA_SIZE, &alphaSize);
|
||||
glXGetConfig(display, visualInfo, GLX_DEPTH_SIZE, &depthSize);
|
||||
glXGetConfig(display, visualInfo, GLX_STENCIL_SIZE, &stencilSize);
|
||||
glXGetConfig(display, visualInfo, GLX_SAMPLES_ARB, &sampleBuffers);
|
||||
glXGetConfig(display, visualInfo, GLX_STEREO, &stereo);
|
||||
|
||||
format->setRedBufferSize(redSize);
|
||||
format->setGreenBufferSize(greenSize);
|
||||
format->setBlueBufferSize(blueSize);
|
||||
format->setAlphaBufferSize(alphaSize);
|
||||
format->setDepthBufferSize(depthSize);
|
||||
format->setStencilBufferSize(stencilSize);
|
||||
if (sampleBuffers) {
|
||||
glXGetConfig(display, visualInfo, GLX_SAMPLES_ARB, &sampleCount);
|
||||
format->setSamples(sampleCount);
|
||||
}
|
||||
|
||||
format->setStereo(stereo);
|
||||
}
|
||||
|
||||
QSurfaceFormat qglx_reduceSurfaceFormat(const QSurfaceFormat &format, bool *reduced)
|
||||
{
|
||||
QSurfaceFormat retFormat = format;
|
||||
|
@ -50,7 +50,8 @@
|
||||
|
||||
XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format);
|
||||
GLXFBConfig qglx_findConfig(Display *display, int screen, const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT);
|
||||
void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config, GLXContext context = 0);
|
||||
void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config);
|
||||
void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo);
|
||||
QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT);
|
||||
QSurfaceFormat qglx_reduceSurfaceFormat(const QSurfaceFormat &format, bool *reduced);
|
||||
|
||||
|
@ -179,7 +179,7 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL
|
||||
|
||||
// Get the basic surface format details
|
||||
if (d->context)
|
||||
qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config, d->context);
|
||||
qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config);
|
||||
|
||||
// Create a temporary window so that we can make the new context current
|
||||
d->window = createDummyWindow(x11, config);
|
||||
|
@ -54,6 +54,7 @@
|
||||
|
||||
#include "qglxintegration.h"
|
||||
#include <QtPlatformSupport/private/qglxconvenience_p.h>
|
||||
#include <QtPlatformHeaders/QGLXNativeContext>
|
||||
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
|
||||
#include <dlfcn.h>
|
||||
@ -83,31 +84,31 @@ typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXC
|
||||
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
|
||||
#endif
|
||||
|
||||
static Window createDummyWindow(QXcbScreen *screen, XVisualInfo *visualInfo)
|
||||
static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin)
|
||||
{
|
||||
Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(screen), screen->root(), visualInfo->visual, AllocNone);
|
||||
Colormap cmap = XCreateColormap(dpy, rootWin, visualInfo->visual, AllocNone);
|
||||
XSetWindowAttributes a;
|
||||
a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(screen), screen->screenNumber());
|
||||
a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(screen), screen->screenNumber());
|
||||
a.background_pixel = WhitePixel(dpy, screenNumber);
|
||||
a.border_pixel = BlackPixel(dpy, screenNumber);
|
||||
a.colormap = cmap;
|
||||
|
||||
Window window = XCreateWindow(DISPLAY_FROM_XCB(screen), screen->root(),
|
||||
Window window = XCreateWindow(dpy, rootWin,
|
||||
0, 0, 100, 100,
|
||||
0, visualInfo->depth, InputOutput, visualInfo->visual,
|
||||
CWBackPixel|CWBorderPixel|CWColormap, &a);
|
||||
#ifndef QT_NO_DEBUG
|
||||
XStoreName(DISPLAY_FROM_XCB(screen), window, "Qt GLX dummy window");
|
||||
XStoreName(dpy, window, "Qt GLX dummy window");
|
||||
#endif
|
||||
XFreeColormap(DISPLAY_FROM_XCB(screen), cmap);
|
||||
XFreeColormap(dpy, cmap);
|
||||
return window;
|
||||
}
|
||||
|
||||
static Window createDummyWindow(QXcbScreen *screen, GLXFBConfig config)
|
||||
static Window createDummyWindow(Display *dpy, GLXFBConfig config, int screenNumber, Window rootWin)
|
||||
{
|
||||
XVisualInfo *visualInfo = glXGetVisualFromFBConfig(DISPLAY_FROM_XCB(screen), config);
|
||||
XVisualInfo *visualInfo = glXGetVisualFromFBConfig(dpy, config);
|
||||
if (!visualInfo)
|
||||
qFatal("Could not initialize GLX");
|
||||
Window window = createDummyWindow(screen, visualInfo);
|
||||
Window window = createDummyWindow(dpy, visualInfo, screenNumber, rootWin);
|
||||
XFree(visualInfo);
|
||||
return window;
|
||||
}
|
||||
@ -160,7 +161,8 @@ static void updateFormatFromContext(QSurfaceFormat &format)
|
||||
}
|
||||
}
|
||||
|
||||
QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share)
|
||||
QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share,
|
||||
const QVariant &nativeHandle)
|
||||
: QPlatformOpenGLContext()
|
||||
, m_screen(screen)
|
||||
, m_context(0)
|
||||
@ -168,6 +170,15 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
|
||||
, m_format(format)
|
||||
, m_isPBufferCurrent(false)
|
||||
, m_swapInterval(-1)
|
||||
, m_ownsContext(nativeHandle.isNull())
|
||||
{
|
||||
if (nativeHandle.isNull())
|
||||
init(screen, share);
|
||||
else
|
||||
init(screen, share, nativeHandle);
|
||||
}
|
||||
|
||||
void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
|
||||
{
|
||||
if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
|
||||
m_format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
@ -195,7 +206,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
|
||||
&& (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) {
|
||||
// Try to create an OpenGL context for each known OpenGL version in descending
|
||||
// order from the requested version.
|
||||
const int requestedVersion = format.majorVersion() * 10 + qMin(format.minorVersion(), 9);
|
||||
const int requestedVersion = m_format.majorVersion() * 10 + qMin(m_format.minorVersion(), 9);
|
||||
|
||||
QVector<int> glVersions;
|
||||
if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
|
||||
@ -282,10 +293,10 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
|
||||
|
||||
// Get the basic surface format details
|
||||
if (m_context)
|
||||
qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config, m_context);
|
||||
qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config);
|
||||
|
||||
// Create a temporary window so that we can make the new context current
|
||||
window = createDummyWindow(screen, config);
|
||||
window = createDummyWindow(DISPLAY_FROM_XCB(screen), config, screen->screenNumber(), screen->root());
|
||||
} else {
|
||||
// requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
|
||||
if (m_format.renderableType() == QSurfaceFormat::OpenGLES)
|
||||
@ -303,7 +314,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
|
||||
}
|
||||
|
||||
// Create a temporary window so that we can make the new context current
|
||||
window = createDummyWindow(screen, visualInfo);
|
||||
window = createDummyWindow(DISPLAY_FROM_XCB(screen), visualInfo, screen->screenNumber(), screen->root());
|
||||
XFree(visualInfo);
|
||||
}
|
||||
|
||||
@ -320,9 +331,123 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
|
||||
XDestroyWindow(DISPLAY_FROM_XCB(screen), window);
|
||||
}
|
||||
|
||||
void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle)
|
||||
{
|
||||
if (!nativeHandle.canConvert<QGLXNativeContext>()) {
|
||||
qWarning("QGLXContext: Requires a QGLXNativeContext");
|
||||
return;
|
||||
}
|
||||
QGLXNativeContext handle = nativeHandle.value<QGLXNativeContext>();
|
||||
GLXContext context = handle.context();
|
||||
if (!context) {
|
||||
qWarning("QGLXContext: No GLXContext given");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the provided Display, if available. If not, use our own. It may still work.
|
||||
Display *dpy = handle.display();
|
||||
if (!dpy)
|
||||
dpy = DISPLAY_FROM_XCB(screen);
|
||||
|
||||
// Legacy contexts created using glXCreateContext are created using a visual
|
||||
// and the FBConfig cannot be queried. The only way to adapt these contexts
|
||||
// is to figure out the visual id.
|
||||
XVisualInfo *vinfo = 0;
|
||||
// If the VisualID is provided use it.
|
||||
VisualID vid = handle.visualId();
|
||||
if (!vid) {
|
||||
// In the absence of the VisualID figure it out from the window.
|
||||
Window wnd = handle.window();
|
||||
if (wnd) {
|
||||
XWindowAttributes attrs;
|
||||
XGetWindowAttributes(dpy, wnd, &attrs);
|
||||
vid = XVisualIDFromVisual(attrs.visual);
|
||||
}
|
||||
}
|
||||
if (vid) {
|
||||
XVisualInfo v;
|
||||
v.screen = screen->screenNumber();
|
||||
v.visualid = vid;
|
||||
int n = 0;
|
||||
vinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, &v, &n);
|
||||
if (n < 1) {
|
||||
XFree(vinfo);
|
||||
vinfo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// For contexts created with an FBConfig using the modern functions providing the
|
||||
// visual or window is not mandatory. Just query the config from the context.
|
||||
GLXFBConfig config = 0;
|
||||
if (!vinfo) {
|
||||
int configId = 0;
|
||||
if (glXQueryContext(dpy, context, GLX_FBCONFIG_ID, &configId) != Success) {
|
||||
qWarning("QGLXContext: Failed to query config from the provided context");
|
||||
return;
|
||||
}
|
||||
|
||||
GLXFBConfig *configs;
|
||||
int numConfigs = 0;
|
||||
static const int attribs[] = { GLX_FBCONFIG_ID, configId, None };
|
||||
configs = glXChooseFBConfig(dpy, screen->screenNumber(), attribs, &numConfigs);
|
||||
if (!configs || numConfigs < 1) {
|
||||
qWarning("QGLXContext: Failed to find config");
|
||||
return;
|
||||
}
|
||||
if (configs && numConfigs > 1) // this is suspicious so warn but let it continue
|
||||
qWarning("QGLXContext: Multiple configs for FBConfig ID %d", configId);
|
||||
|
||||
config = configs[0];
|
||||
}
|
||||
|
||||
Q_ASSERT(vinfo || config);
|
||||
|
||||
int screenNumber = DefaultScreen(dpy);
|
||||
Window window;
|
||||
if (vinfo)
|
||||
window = createDummyWindow(dpy, vinfo, screenNumber, RootWindow(dpy, screenNumber));
|
||||
else
|
||||
window = createDummyWindow(dpy, config, screenNumber, RootWindow(dpy, screenNumber));
|
||||
if (!window) {
|
||||
qWarning("QGLXContext: Failed to create dummy window");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update OpenGL version and buffer sizes in our format.
|
||||
if (!glXMakeCurrent(dpy, window, context)) {
|
||||
qWarning("QGLXContext: Failed to make provided context current");
|
||||
return;
|
||||
}
|
||||
m_format = QSurfaceFormat();
|
||||
m_format.setRenderableType(QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL
|
||||
? QSurfaceFormat::OpenGL : QSurfaceFormat::OpenGLES);
|
||||
updateFormatFromContext(m_format);
|
||||
if (vinfo)
|
||||
qglx_surfaceFormatFromVisualInfo(&m_format, dpy, vinfo);
|
||||
else
|
||||
qglx_surfaceFormatFromGLXFBConfig(&m_format, dpy, config);
|
||||
glXMakeCurrent(dpy, 0, 0);
|
||||
XDestroyWindow(dpy, window);
|
||||
|
||||
if (vinfo)
|
||||
XFree(vinfo);
|
||||
|
||||
// Success. Store the context. From this point on isValid() is true.
|
||||
m_context = context;
|
||||
|
||||
if (share)
|
||||
m_shareContext = static_cast<const QGLXContext*>(share)->glxContext();
|
||||
}
|
||||
|
||||
QGLXContext::~QGLXContext()
|
||||
{
|
||||
glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context);
|
||||
if (m_ownsContext)
|
||||
glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context);
|
||||
}
|
||||
|
||||
QVariant QGLXContext::nativeHandle() const
|
||||
{
|
||||
return QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(m_context));
|
||||
}
|
||||
|
||||
bool QGLXContext::makeCurrent(QPlatformSurface *surface)
|
||||
|
@ -58,7 +58,8 @@ QT_BEGIN_NAMESPACE
|
||||
class QGLXContext : public QPlatformOpenGLContext
|
||||
{
|
||||
public:
|
||||
QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share);
|
||||
QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share,
|
||||
const QVariant &nativeHandle);
|
||||
~QGLXContext();
|
||||
|
||||
bool makeCurrent(QPlatformSurface *surface);
|
||||
@ -72,16 +73,22 @@ public:
|
||||
|
||||
GLXContext glxContext() const { return m_context; }
|
||||
|
||||
QVariant nativeHandle() const;
|
||||
|
||||
static bool supportsThreading();
|
||||
static void queryDummyContext();
|
||||
|
||||
private:
|
||||
void init(QXcbScreen *screen, QPlatformOpenGLContext *share);
|
||||
void init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle);
|
||||
|
||||
QXcbScreen *m_screen;
|
||||
GLXContext m_context;
|
||||
GLXContext m_shareContext;
|
||||
QSurfaceFormat m_format;
|
||||
bool m_isPBufferCurrent;
|
||||
int m_swapInterval;
|
||||
bool m_ownsContext;
|
||||
static bool m_queriedDummyContext;
|
||||
static bool m_supportsThreading;
|
||||
};
|
||||
|
@ -233,7 +233,10 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont
|
||||
{
|
||||
QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle());
|
||||
#if defined(XCB_USE_GLX)
|
||||
return new QGLXContext(screen, context->format(), context->shareHandle());
|
||||
QGLXContext *platformContext = new QGLXContext(screen, context->format(),
|
||||
context->shareHandle(), context->nativeHandle());
|
||||
context->setNativeHandle(platformContext->nativeHandle());
|
||||
return platformContext;
|
||||
#elif defined(XCB_USE_EGL)
|
||||
return new QEGLXcbPlatformContext(context->format(), context->shareHandle(),
|
||||
screen->connection()->egl_display(), screen->connection());
|
||||
|
@ -95,6 +95,10 @@ src_platformsupport.subdir = $$PWD/platformsupport
|
||||
src_platformsupport.target = sub-platformsupport
|
||||
src_platformsupport.depends = src_corelib src_gui src_network
|
||||
|
||||
src_platformheaders.subdir = $$PWD/platformheaders
|
||||
src_platformheaders.target = sub-platformheaders
|
||||
src_platformheaders.depends = src_corelib src_gui
|
||||
|
||||
src_widgets.subdir = $$PWD/widgets
|
||||
src_widgets.target = sub-widgets
|
||||
src_widgets.depends = src_corelib src_gui src_tools_uic
|
||||
@ -141,9 +145,9 @@ contains(QT_CONFIG, concurrent):SUBDIRS += src_concurrent
|
||||
SUBDIRS += src_angle
|
||||
src_gui.depends += src_angle
|
||||
}
|
||||
SUBDIRS += src_gui src_platformsupport
|
||||
SUBDIRS += src_gui src_platformsupport src_platformheaders
|
||||
contains(QT_CONFIG, opengl(es2)?):SUBDIRS += src_openglextensions
|
||||
src_plugins.depends += src_gui src_platformsupport
|
||||
src_plugins.depends += src_gui src_platformsupport src_platformheaders
|
||||
!contains(QT_CONFIG, no-widgets) {
|
||||
SUBDIRS += src_tools_uic src_widgets
|
||||
TOOLS += src_tools_uic
|
||||
|
@ -11,6 +11,7 @@
|
||||
"QtDBus" => "$basedir/src/dbus",
|
||||
"QtConcurrent" => "$basedir/src/concurrent",
|
||||
"QtPlatformSupport" => "$basedir/src/platformsupport",
|
||||
"QtPlatformHeaders" => "$basedir/src/platformheaders",
|
||||
"QtANGLE/KHR" => "!$basedir/src/3rdparty/angle/include/KHR",
|
||||
"QtANGLE/GLES2" => "!$basedir/src/3rdparty/angle/include/GLES2",
|
||||
"QtANGLE/EGL" => "!$basedir/src/3rdparty/angle/include/EGL",
|
||||
|
@ -10,3 +10,5 @@ QT += gui-private core-private testlib
|
||||
SOURCES += tst_qopengl.cpp
|
||||
|
||||
win32-msvc2010:contains(QT_CONFIG, angle):CONFIG += insignificant_test # QTBUG-31611
|
||||
|
||||
linux:contains(QT_CONFIG, xcb-glx):contains(QT_CONFIG, xcb-xlib): DEFINES += USE_GLX
|
||||
|
@ -51,12 +51,19 @@
|
||||
#include <QtGui/QGenericMatrix>
|
||||
#include <QtGui/QMatrix4x4>
|
||||
#include <QtGui/private/qopengltextureblitter_p.h>
|
||||
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include <QSignalSpy>
|
||||
|
||||
#ifdef USE_GLX
|
||||
// Must be included last due to the X11 types
|
||||
#include <QtPlatformHeaders/QGLXNativeContext>
|
||||
#endif
|
||||
|
||||
class tst_QOpenGL : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -85,6 +92,10 @@ private slots:
|
||||
void textureblitterPartOriginTopLeftSourceRectTransform();
|
||||
void textureblitterFullTargetRectTransform();
|
||||
void textureblitterPartTargetRectTransform();
|
||||
|
||||
#ifdef USE_GLX
|
||||
void glxContextWrap();
|
||||
#endif
|
||||
};
|
||||
|
||||
struct SharedResourceTracker
|
||||
@ -970,6 +981,45 @@ void tst_QOpenGL::textureblitterPartTargetRectTransform()
|
||||
QCOMPARE(targetBottomRight, expectedBottomRight);
|
||||
}
|
||||
|
||||
#ifdef USE_GLX
|
||||
void tst_QOpenGL::glxContextWrap()
|
||||
{
|
||||
QWindow *window = new QWindow;
|
||||
window->setSurfaceType(QWindow::OpenGLSurface);
|
||||
window->setGeometry(0, 0, 10, 10);
|
||||
window->show();
|
||||
QTest::qWaitForWindowExposed(window);
|
||||
|
||||
QPlatformNativeInterface *nativeIf = QGuiApplicationPrivate::instance()->platformIntegration()->nativeInterface();
|
||||
QVERIFY(nativeIf);
|
||||
|
||||
// Fetch a GLXContext.
|
||||
QOpenGLContext *ctx0 = new QOpenGLContext;
|
||||
ctx0->setFormat(window->format());
|
||||
QVERIFY(ctx0->create());
|
||||
QVariant v = ctx0->nativeHandle();
|
||||
QVERIFY(!v.isNull());
|
||||
QVERIFY(v.canConvert<QGLXNativeContext>());
|
||||
GLXContext context = v.value<QGLXNativeContext>().context();
|
||||
QVERIFY(context);
|
||||
|
||||
// Then create another QOpenGLContext wrapping it.
|
||||
QOpenGLContext *ctx = new QOpenGLContext;
|
||||
ctx->setNativeHandle(QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(context)));
|
||||
QVERIFY(ctx->create());
|
||||
QVERIFY(ctx->nativeHandle().value<QGLXNativeContext>().context() == context);
|
||||
QVERIFY(nativeIf->nativeResourceForContext(QByteArrayLiteral("glxcontext"), ctx) == (void *) context);
|
||||
|
||||
QVERIFY(ctx->makeCurrent(window));
|
||||
ctx->doneCurrent();
|
||||
|
||||
delete ctx;
|
||||
delete ctx0;
|
||||
|
||||
delete window;
|
||||
}
|
||||
#endif // USE_GLX
|
||||
|
||||
QTEST_MAIN(tst_QOpenGL)
|
||||
|
||||
#include "tst_qopengl.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user