From 22e439141384f49028770d2410fafb18ef8cad1f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 7 Aug 2014 16:45:05 +0200 Subject: Add default format to QSurfaceFormat Add defaultFormat() and setDefaultFormat() statics to QSurfaceFormat. These define the default values for the requestedFormat members of QOpenGLContext, QWindow and QOpenGLWidget (and implicitly QOpenGLWindow, QQuickWindow, etc.) This replaces QQuickWindow::setDefaultFormat() which can now be removed. The main inspiration here is not the convenience (avoiding setFormat() calls for all windows/widgets), but robustness: by setting the format once at the start of the application, all windows and contexts, including the internal share context used by QOpenGLWidget and QQuickWidget, will use the same format, eliminating the possibility of failing due to trying to share between incompatible contexts. Furthermore, since such a functionality is anyway mandatory for QQuickWindow (due to the possibility of creating windows from QML code), extending it to QSurfaceFormat and QOpenGLContext/QWindow is the next logical step. Change-Id: Ie94486adc489d17fecfcebb7050fecedffd2688b Reviewed-by: Gunnar Sletta --- src/gui/kernel/qopenglcontext.cpp | 6 ++++ src/gui/kernel/qopenglcontext_p.h | 1 + src/gui/kernel/qsurfaceformat.cpp | 40 ++++++++++++++++++++++ src/gui/kernel/qsurfaceformat.h | 3 ++ src/gui/kernel/qwindow.cpp | 10 +++++- .../code/doc_gui_widgets_qopenglwidget.cpp | 19 ++++++++++ src/widgets/kernel/qopenglwidget.cpp | 19 ++++++++-- tests/auto/gui/qopengl/tst_qopengl.cpp | 18 ++++++++++ 8 files changed, 112 insertions(+), 4 deletions(-) diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index f6273fc6dd..71a1d1e074 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -489,6 +489,12 @@ QOpenGLContext::QOpenGLContext(QObject *parent) /*! Sets the \a format the OpenGL context should be compatible with. You need to call create() before it takes effect. + + When the format is not explicitly set via this function, the format returned + by QSurfaceFormat::defaultFormat() will be used. This means that when having + multiple contexts, individual calls to this function can be replaced by one + single call to QSurfaceFormat::setDefaultFormat() before creating the first + context. */ void QOpenGLContext::setFormat(const QSurfaceFormat &format) { diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h index 4447df5294..46e1572376 100644 --- a/src/gui/kernel/qopenglcontext_p.h +++ b/src/gui/kernel/qopenglcontext_p.h @@ -211,6 +211,7 @@ public: , workaround_missingPrecisionQualifiers(false) , active_engine(0) { + requestedFormat = QSurfaceFormat::defaultFormat(); } virtual ~QOpenGLContextPrivate() diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index 2b8e611dff..f077abc6a2 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -196,6 +196,9 @@ public: /*! Constructs a default initialized QSurfaceFormat. + + \note By default OpenGL 2.0 is requested since this provides the highest + grade of portability between platforms and OpenGL implementations. */ QSurfaceFormat::QSurfaceFormat() : d(new QSurfaceFormatPrivate) { @@ -730,6 +733,43 @@ int QSurfaceFormat::swapInterval() const return d->swapInterval; } +Q_GLOBAL_STATIC(QSurfaceFormat, qt_default_surface_format) + +/*! + Sets the global default surface \a format. + + This format is used by default in QOpenGLContext, QWindow, QOpenGLWidget and + similar classes. + + It can always be overridden on a per-instance basis by using the class in + question's own setFormat() function. However, it is often more convenient to + set the format for all windows once at the start of the application. It also + guarantees proper behavior in cases where shared contexts are required, + because settings the format via this function guarantees that all contexts + and surfaces, even the ones created internally by Qt, will use the same + format. + + \since 5.4 + \sa defaultFormat() + */ +void QSurfaceFormat::setDefaultFormat(const QSurfaceFormat &format) +{ + *qt_default_surface_format() = format; +} + +/*! + Returns the global default surface format. + + When setDefaultFormat() is not called, this is a default-constructed QSurfaceFormat. + + \since 5.4 + \sa setDefaultFormat() + */ +QSurfaceFormat QSurfaceFormat::defaultFormat() +{ + return *qt_default_surface_format(); +} + /*! Returns \c true if all the options of the two QSurfaceFormat objects \a a and \a b are equal. diff --git a/src/gui/kernel/qsurfaceformat.h b/src/gui/kernel/qsurfaceformat.h index 453beac5cd..05aba2f83c 100644 --- a/src/gui/kernel/qsurfaceformat.h +++ b/src/gui/kernel/qsurfaceformat.h @@ -138,6 +138,9 @@ public: int swapInterval() const; void setSwapInterval(int interval); + static void setDefaultFormat(const QSurfaceFormat &format); + static QSurfaceFormat defaultFormat(); + private: QSurfaceFormatPrivate *d; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 8159b7746e..8c0db2c0c7 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -224,6 +224,8 @@ void QWindowPrivate::init() exit(1); } QGuiApplicationPrivate::window_list.prepend(q); + + requestedFormat = QSurfaceFormat::defaultFormat(); } /*! @@ -672,7 +674,13 @@ void QWindow::setModality(Qt::WindowModality modality) this function after create() has been called will not re-resolve the surface format of the native surface. - \sa create(), destroy() + When the format is not explicitly set via this function, the format returned + by QSurfaceFormat::defaultFormat() will be used. This means that when having + multiple windows, individual calls to this function can be replaced by one + single call to QSurfaceFormat::setDefaultFormat() before creating the first + window. + + \sa create(), destroy(), QSurfaceFormat::setDefaultFormat() */ void QWindow::setFormat(const QSurfaceFormat &format) { diff --git a/src/widgets/doc/snippets/code/doc_gui_widgets_qopenglwidget.cpp b/src/widgets/doc/snippets/code/doc_gui_widgets_qopenglwidget.cpp index 0814b5f30f..921c3fa9f8 100644 --- a/src/widgets/doc/snippets/code/doc_gui_widgets_qopenglwidget.cpp +++ b/src/widgets/doc/snippets/code/doc_gui_widgets_qopenglwidget.cpp @@ -178,3 +178,22 @@ void MyGLWidget::cleanup() doneCurrent(); } //! [5] + +//! [6] +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + format.setVersion(3, 2); + format.setProfile(QSurfaceFormat::CoreProfile); + QSurfaceFormat::setDefaultFormat(format); + + MyWidget widget; + widget.show(); + + return app.exec(); +} +//! [6] diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 33e036ee64..e59057a662 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -107,7 +107,8 @@ QT_BEGIN_NAMESPACE setFormat(). Keep in mind however that having multiple QOpenGLWidget instances in the same window requires that they all use the same format, or at least formats that do not make the contexts - non-sharable. + non-sharable. To overcome this issue, prefer using + QSurfaceFormat::setDefaultFormat() instead of setFormat(). \section1 Painting Techniques @@ -190,7 +191,7 @@ QT_BEGIN_NAMESPACE \snippet code/doc_gui_widgets_qopenglwidget.cpp 0 - Alternatively, the prefixing of each and every OpenGL call can be avoidided by deriving + Alternatively, the prefixing of each and every OpenGL call can be avoided by deriving from QOpenGLFunctions instead: \snippet code/doc_gui_widgets_qopenglwidget.cpp 1 @@ -206,6 +207,12 @@ QT_BEGIN_NAMESPACE \snippet code/doc_gui_widgets_qopenglwidget.cpp 3 + As described above, it is simpler and more robust to set the requested format + globally so that it applies to all windows and contexts during the lifetime of + the application. Below is an example of this: + + \snippet code/doc_gui_widgets_qopenglwidget.cpp 6 + \section1 Relation to QGLWidget The legacy QtOpenGL module (classes prefixed with QGL) provides a widget @@ -392,6 +399,7 @@ public: paintDevice(0), inBackingStorePaint(false) { + requestedFormat = QSurfaceFormat::defaultFormat(); } ~QOpenGLWidgetPrivate() @@ -620,13 +628,18 @@ QOpenGLWidget::~QOpenGLWidget() /*! Sets the requested surface \a format. + When the format is not explicitly set via this function, the format returned by + QSurfaceFormat::defaultFormat() will be used. This means that when having multiple + OpenGL widgets, individual calls to this function can be replaced by one single call to + QSurfaceFormat::setDefaultFormat() before creating the first widget. + \note Requesting an alpha buffer via this function will not lead to the desired results and should be avoided. Instead, use Qt::WA_AlwaysStackOnTop to enable semi-transparent QOpenGLWidget instances with other widgets visible underneath. Keep in mind however that this breaks the stacking order, so it will no longer be possible to have other widgets on top of the QOpenGLWidget. - \sa format(), Qt::WA_AlwaysStackOnTop + \sa format(), Qt::WA_AlwaysStackOnTop, QSurfaceFormat::setDefaultFormat() */ void QOpenGLWidget::setFormat(const QSurfaceFormat &format) { diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp index 6d83defdeb..a5100a57bf 100644 --- a/tests/auto/gui/qopengl/tst_qopengl.cpp +++ b/tests/auto/gui/qopengl/tst_qopengl.cpp @@ -102,6 +102,7 @@ private slots: void textureblitterPartOriginTopLeftSourceRectTransform(); void textureblitterFullTargetRectTransform(); void textureblitterPartTargetRectTransform(); + void defaultSurfaceFormat(); #ifdef USE_GLX void glxContextWrap(); @@ -1110,6 +1111,23 @@ void tst_QOpenGL::textureblitterPartTargetRectTransform() QCOMPARE(targetBottomRight, expectedBottomRight); } +void tst_QOpenGL::defaultSurfaceFormat() +{ + QSurfaceFormat fmt; + QVERIFY(QSurfaceFormat::defaultFormat() == fmt); + + fmt.setDepthBufferSize(16); + QSurfaceFormat::setDefaultFormat(fmt); + QVERIFY(QSurfaceFormat::defaultFormat() == fmt); + QCOMPARE(QSurfaceFormat::defaultFormat().depthBufferSize(), 16); + + QScopedPointer window(new QWindow); + QVERIFY(window->requestedFormat() == fmt); + + QScopedPointer context(new QOpenGLContext); + QVERIFY(context->format() == fmt); +} + #ifdef USE_GLX void tst_QOpenGL::glxContextWrap() { -- cgit v1.2.3