diff options
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 130 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.h | 8 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 3 | ||||
-rw-r--r-- | tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 76 |
4 files changed, 215 insertions, 2 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 6a56a5dc82..a494f5ea5d 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -77,7 +77,9 @@ QT_BEGIN_NAMESPACE extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); -bool QQuickWindowPrivate::defaultAlphaBuffer(0); +bool QQuickWindowPrivate::defaultAlphaBuffer = false; +bool QQuickWindowPrivate::defaultFormatInitialized = false; +QSurfaceFormat QQuickWindowPrivate::defaultFormat; void QQuickWindowPrivate::updateFocusItemTransform() { @@ -457,7 +459,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control) } q->setSurfaceType(QWindow::OpenGLSurface); - q->setFormat(sg->defaultSurfaceFormat()); + q->setFormat(q->defaultFormat()); animationController = new QQuickAnimatorController(); animationController->m_window = q; @@ -3420,6 +3422,130 @@ void QQuickWindow::resetOpenGLState() } /*! + * \brief QQuickWindow::setDefaultFormat + * \since 5.4 + * @brief Sets the global default surface format that is used for all new QQuickWindow instances. + * + * While it is possible to specify a QSurfaceFormat for every QQuickWindow by + * calling the member function setFormat(), windows may also be created from + * QML by using the Window and ApplicationWindow elements. In this case there + * is no C++ code involved in the creation of the window instance, yet + * applications may still wish to set certain surface format values, for + * example to request a given OpenGL version or profile. Such applications can + * call this static functions in main(). \a format will be used for all Quick + * windows created afterwards. + * + * \note The default value for the default format is not necessarily a + * default-constructed QSurfaceFormat. It may already have depth, stencil and alpha + * buffer sizes set. Unless there is a need to change all these sizes, the format should + * first be queried via defaultFormat() and the changes should be applied to that, + * instead of merely starting with default-constructed QSurfaceFormat. + * + * \sa setFormat(), format(), defaultFormat() + */ +void QQuickWindow::setDefaultFormat(const QSurfaceFormat &format) +{ + QQuickWindowPrivate::defaultFormatInitialized = true; + QQuickWindowPrivate::defaultFormat = format; +} + +/*! + * \brief QQuickWindow::defaultFormat + * \since 5.4 + * \return The global default surface format that is used for all QQuickWindow instances. + * \note This function requires a QGuiApplication or QApplication instance. + */ +QSurfaceFormat QQuickWindow::defaultFormat() +{ + if (!QQuickWindowPrivate::defaultFormatInitialized) { + QQuickWindowPrivate::defaultFormatInitialized = true; + QQuickWindowPrivate::defaultFormat = QSGRenderLoop::instance()->sceneGraphContext()->defaultSurfaceFormat(); + } + return QQuickWindowPrivate::defaultFormat; +} + +/*! + * \brief QQuickWindow::glslVersion + * \since 5.4 + * \return The OpenGL Shading Language version for this window. + * + * QML components that need to be usable on different platforms and environments may need + * to deal with different OpenGL versions if they include ShaderEffect items. The source + * code for a given shader may not be compatible with an OpenGL context that targets a + * different OpenGL version or profile, hence it might be necessary to provide multiple + * versions of the shader. This property helps in deciding which shader source should be + * chosen. + * + * The value corresponds to GLSL version declarations, for example an OpenGL 4.2 core + * profile context will result in the value \e{420 core}, while an OpenGL ES 3.0 context + * gives \e{300 es}. For OpenGL (ES) 2 the value will be an empty string since the + * corresponding shading language does not use version declarations. + * + * \note The value does not necessarily indicate that the shader source must target that + * specific version. For example, compatibility profiles and ES 3.x all allow using + * OpenGL 2 style shaders. The most important for reusable components is to check for + * core profiles since these do not accept shaders with the old syntax. + * + * \sa setFormat(), glslIsCoreProfile() + */ +QString QQuickWindow::glslVersion() const +{ + QString ver; + QOpenGLContext *ctx = openglContext(); + if (ctx) { + const QSurfaceFormat fmt = ctx->format(); + if (fmt.renderableType() == QSurfaceFormat::OpenGLES + && fmt.majorVersion() >= 3) { + ver += QLatin1Char(fmt.majorVersion() + '0'); + ver += QLatin1Char(fmt.minorVersion() + '0'); + ver += QLatin1String("0 es"); + } else if (fmt.renderableType() == QSurfaceFormat::OpenGL + && fmt.majorVersion() >= 3) { + if (fmt.version() == qMakePair(3, 0)) { + ver = QStringLiteral("130"); + } else if (fmt.version() == qMakePair(3, 1)) { + ver = QStringLiteral("140"); + } else if (fmt.version() == qMakePair(3, 2)) { + ver = QStringLiteral("150"); + } else { + ver += QLatin1Char(fmt.majorVersion() + '0'); + ver += QLatin1Char(fmt.minorVersion() + '0'); + ver += QLatin1Char('0'); + } + if (fmt.version() >= qMakePair(3, 2)) { + if (fmt.profile() == QSurfaceFormat::CoreProfile) + ver += QStringLiteral(" core"); + else if (fmt.profile() == QSurfaceFormat::CompatibilityProfile) + ver += QStringLiteral(" compatibility"); + } + } + } + return ver; +} + +/*! + * \brief QQuickWindow::glslIsCoreProfile + * \since 5.4 + * \return True if the window is rendering using OpenGL core profile. + * + * This is convenience function to check if the window's OpenGL context is a core profile + * context. It is more efficient to perform the check via this function than parsing the + * string returned from glslVersion(). + * + * Resusable QML components will typically use this function in bindings in order to + * choose between core and non core profile compatible shader sources. + * + * To retrieve more information about the shading language, use glslVersion(). + * + * \sa glslVersion() + */ +bool QQuickWindow::glslIsCoreProfile() const +{ + QOpenGLContext *ctx = openglContext(); + return ctx ? ctx->format().profile() == QSurfaceFormat::CoreProfile : false; +} + +/*! \qmlproperty string Window::title The window's title in the windowing system. diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 2572f31375..1a4adb0785 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -67,6 +67,8 @@ class Q_QUICK_EXPORT QQuickWindow : public QWindow Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(QQuickItem* contentItem READ contentItem CONSTANT) Q_PROPERTY(QQuickItem* activeFocusItem READ activeFocusItem NOTIFY activeFocusItemChanged REVISION 1) + Q_PROPERTY(QString glslVersion READ glslVersion CONSTANT REVISION 2) + Q_PROPERTY(bool glslIsCoreProfile READ glslIsCoreProfile CONSTANT REVISION 2) Q_CLASSINFO("DefaultProperty", "data") Q_DECLARE_PRIVATE(QQuickWindow) public: @@ -136,6 +138,12 @@ public: QOpenGLContext *openglContext() const; + static void setDefaultFormat(const QSurfaceFormat &format); + static QSurfaceFormat defaultFormat(); + + QString glslVersion() const; + bool glslIsCoreProfile() const; + Q_SIGNALS: void frameSwapped(); Q_REVISION(2) void openglContextCreated(QOpenGLContext *context); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 421651b483..872a054666 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -247,6 +247,9 @@ public: QString *untranslatedMessage, bool isEs); + static bool defaultFormatInitialized; + static QSurfaceFormat defaultFormat; + private: static void cleanupNodesOnShutdown(QQuickItem *); }; diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 28945c4cb5..4ec479a924 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -357,6 +357,9 @@ private slots: void contentItemSize(); + void defaultSurfaceFormat(); + void glslVersion(); + private: QTouchDevice *touchDevice; QTouchDevice *touchDeviceWithVelocity; @@ -1741,6 +1744,79 @@ void tst_qquickwindow::contentItemSize() QCOMPARE(QSizeF(rect->width(), rect->height()), size); } +void tst_qquickwindow::defaultSurfaceFormat() +{ + // It is quite difficult to verify anything for real since the resulting format after + // surface/context creation can be anything, depending on the platform and drivers, + // and many options and settings may fail in various configurations, but test at + // least using some harmless settings to check that the global, static format is + // taken into account in the requested format. + + QSurfaceFormat savedDefaultFormat = QQuickWindow::defaultFormat(); + + // Verify that depth and stencil are set, as they should be, unless they are disabled + // via environment variables. + QVERIFY(savedDefaultFormat.depthBufferSize() >= 16); + QVERIFY(savedDefaultFormat.stencilBufferSize() >= 8); + + QSurfaceFormat format = savedDefaultFormat; + format.setSwapInterval(0); + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + format.setProfile(QSurfaceFormat::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + QQuickWindow::setDefaultFormat(format); + + QQuickWindow window; + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + const QSurfaceFormat reqFmt = window.requestedFormat(); + QCOMPARE(format.swapInterval(), reqFmt.swapInterval()); + QCOMPARE(format.redBufferSize(), reqFmt.redBufferSize()); + QCOMPARE(format.greenBufferSize(), reqFmt.greenBufferSize()); + QCOMPARE(format.blueBufferSize(), reqFmt.blueBufferSize()); + QCOMPARE(format.profile(), reqFmt.profile()); + QCOMPARE(int(format.options()), int(reqFmt.options())); + + QQuickWindow::setDefaultFormat(savedDefaultFormat); +} + +void tst_qquickwindow::glslVersion() +{ + QQuickWindow window; + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + // Core profile is never requested by default. + QVERIFY(!window.glslIsCoreProfile()); + + // Get the format from the context, not the window. The actual OpenGL version and + // related settings are associated with the context and are only written back to the + // context's format. + QSurfaceFormat format = window.openglContext()->format(); + + if (format.renderableType() == QSurfaceFormat::OpenGL) { + if (format.majorVersion() == 2) + QCOMPARE(window.glslVersion(), QString()); + else if (format.majorVersion() == 3) + QVERIFY(window.glslVersion().startsWith('3') + || window.glslVersion() == QStringLiteral("130") + || window.glslVersion() == QStringLiteral("140") + || window.glslVersion() == QStringLiteral("150")); + else if (format.majorVersion() == 4) + QVERIFY(window.glslVersion().startsWith('4')); + QVERIFY(!window.glslVersion().contains(QStringLiteral("core"))); + QVERIFY(!window.glslVersion().contains(QStringLiteral("es"))); + } else if (format.renderableType() == QSurfaceFormat::OpenGLES) { + if (format.majorVersion() == 2) + QCOMPARE(window.glslVersion(), QString()); + else + QVERIFY(window.glslVersion().contains(QStringLiteral("es"))); + } +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" |