diff options
34 files changed, 499 insertions, 679 deletions
diff --git a/examples/quick/quickwidgets/CMakeLists.txt b/examples/quick/quickwidgets/CMakeLists.txt index e0537e1e01..f205e23600 100644 --- a/examples/quick/quickwidgets/CMakeLists.txt +++ b/examples/quick/quickwidgets/CMakeLists.txt @@ -1,2 +1,2 @@ qt_internal_add_example(quickwidget) -qt_internal_add_example(qquickviewcomparison) +qt_internal_add_example(qquickwidgetversuswindow_opengl) diff --git a/examples/quick/quickwidgets/qquickviewcomparison/CMakeLists.txt b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/CMakeLists.txt index 2ac77c313c..c49bb915ec 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/CMakeLists.txt +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(qquickviewcomparison LANGUAGES CXX) +project(qquickwidgetversuswindow_opengl LANGUAGES CXX) set(CMAKE_AUTOMOC ON) @@ -7,23 +7,22 @@ if(NOT DEFINED INSTALL_EXAMPLESDIR) set(INSTALL_EXAMPLESDIR "examples") endif() -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/quickwidgets/qquickviewcomparison") +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/quickwidgets/qquickwidgetversuswindow_opengl") find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick QuickWidgets ShaderTools Widgets) -qt_add_executable(qquickviewcomparison +qt_add_executable(qquickwidgetversuswindow_opengl fbitem.cpp fbitem.h logo.cpp logo.h main.cpp mainwindow.cpp mainwindow.h ) -set_target_properties(qquickviewcomparison PROPERTIES +set_target_properties(qquickwidgetversuswindow_opengl PROPERTIES WIN32_EXECUTABLE TRUE MACOSX_BUNDLE TRUE ) - -target_link_libraries(qquickviewcomparison PUBLIC +target_link_libraries(qquickwidgetversuswindow_opengl PUBLIC Qt::Core Qt::Gui Qt::Quick @@ -31,24 +30,24 @@ target_link_libraries(qquickviewcomparison PUBLIC Qt::Widgets ) -qt_add_qml_module(qquickviewcomparison +qt_add_qml_module(qquickwidgetversuswindow_opengl URI fbitem VERSION 1.0 QML_FILES test.qml - RESOURCE_PREFIX /qquickviewcomparison + RESOURCE_PREFIX /qquickwidgetversuswindow_opengl NO_RESOURCE_TARGET_PATH ) -qt6_add_shaders(qquickviewcomparison "shaders" +qt6_add_shaders(qquickwidgetversuswindow_opengl "shaders" PRECOMPILE OPTIMIZED PREFIX - "/qquickviewcomparison" + "/qquickwidgetversuswindow_opengl" FILES "wobble.frag" ) -install(TARGETS qquickviewcomparison +install(TARGETS qquickwidgetversuswindow_opengl RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" diff --git a/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/doc/images/qquickwidgetversuswindow-opengl-example.jpg b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/doc/images/qquickwidgetversuswindow-opengl-example.jpg Binary files differnew file mode 100644 index 0000000000..584ac4ed69 --- /dev/null +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/doc/images/qquickwidgetversuswindow-opengl-example.jpg diff --git a/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/doc/src/qquickwidgetversuswindow_opengl.qdoc b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/doc/src/qquickwidgetversuswindow_opengl.qdoc new file mode 100644 index 0000000000..97ad7ddd8b --- /dev/null +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/doc/src/qquickwidgetversuswindow_opengl.qdoc @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \title QQuickWidget - QQuickView Comparison Example + \example quickwidgets/qquickwidgetversuswindow_opengl + \brief Demonstrates the benefits of QQuickWidget over a QQuickView embedded as a native window. + \image qquickwidgetversuswindow-opengl-example.jpg + + The example allows showing the same Qt Quick scene within the same + QWidget-based user interface using two different approaches: one is using a + QQuickView and using it as a child window and + QWidget::createWindowContainer(). The other is using QQuickWidget which + acts as a true QWidget and supports, among others, better clipping and + stacking, as is expected from a true QWidget. + + The Qt Quick scene also uses direct OpenGL rendering, proving that with + QQuickWidget the rendering still happens using the accelerated 3D API. The + implication of this is that the example is tied to OpenGL and will not work + with other graphics APIs (Vulkan, Metal, Direct 3D). + + Clicking on the Show Overlay checkbox demonstrates a widget stacking case + that is not rendering as expected when embedding a native window, while + QQuickWidget makes it render as expected. + + Multisample antialiasing can also be exercised. When enabling it via the + corresponding checkbox, QQuickWidget will internally render into a + multisample renderbuffer, which is then resolved into a regular, + non-multisample 2D texture after each render pass, thus enabling + multisampling for the Qt Quick content without affecting the rest of the + QWidget UI. With QQuickView the native window will request multisampling + for its corresponding window surface, bringing similar results, if + supported by the platform. + + The Qt Quick scene is interactive: typing into the text field is possible + regardless of which embedding technology is used. QQuickWidget takes care + of forwarding input events to the underlying Qt Quick scene automatically. +*/ diff --git a/examples/quick/quickwidgets/qquickviewcomparison/fbitem.cpp b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/fbitem.cpp index 139fcbae5c..139fcbae5c 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/fbitem.cpp +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/fbitem.cpp diff --git a/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/fbitem.h index 573cfd7866..573cfd7866 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/fbitem.h diff --git a/examples/quick/quickwidgets/qquickviewcomparison/logo.cpp b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/logo.cpp index b11c326034..b11c326034 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/logo.cpp +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/logo.cpp diff --git a/examples/quick/quickwidgets/qquickviewcomparison/logo.h b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/logo.h index 7e58bbb7b7..7e58bbb7b7 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/logo.h +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/logo.h diff --git a/examples/quick/quickwidgets/qquickviewcomparison/main.cpp b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/main.cpp index c0a26eefba..c0a26eefba 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/main.cpp +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/main.cpp diff --git a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/mainwindow.cpp index b393937809..27d320892e 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/mainwindow.cpp @@ -158,7 +158,7 @@ void MainWindow::updateView() ? m_currentRootObject->property("currentText").toString() : QStringLiteral("Hello Qt"); - QUrl source("qrc:qquickviewcomparison/test.qml"); + QUrl source("qrc:qquickwidgetversuswindow_opengl/test.qml"); if (m_state == UseWindow) { auto *quickView = new QQuickView; diff --git a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.h b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/mainwindow.h index d182b70960..d182b70960 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.h +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/mainwindow.h diff --git a/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.pro b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/qquickwidgetversuswindow_opengl.pro index 7809c20b3a..42930b1ecd 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.pro +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/qquickwidgetversuswindow_opengl.pro @@ -1,5 +1,5 @@ TEMPLATE = app -TARGET = qquickviewcomparison +TARGET = qquickwidgetversuswindow_opengl CONFIG += qmltypes QML_IMPORT_NAME = fbitem @@ -16,9 +16,9 @@ HEADERS += mainwindow.h \ logo.h \ fbitem.h -RESOURCES += qquickviewcomparison.qrc +RESOURCES += qquickwidgetversuswindow_opengl.qrc OTHER_FILES += test.qml -target.path = $$[QT_INSTALL_EXAMPLES]/quick/quickwidgets/qquickviewcomparison +target.path = $$[QT_INSTALL_EXAMPLES]/quick/quickwidgets/qquickwidgetversuswindow_opengl INSTALLS += target diff --git a/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.qrc b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/qquickwidgetversuswindow_opengl.qrc index e545c993c0..4650ef97e8 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.qrc +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/qquickwidgetversuswindow_opengl.qrc @@ -1,5 +1,5 @@ <RCC> - <qresource prefix="/qquickviewcomparison"> + <qresource prefix="/qquickwidgetversuswindow_opengl"> <file>test.qml</file> <file>wobble.frag.qsb</file> </qresource> diff --git a/examples/quick/quickwidgets/qquickviewcomparison/test.qml b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/test.qml index 8224320509..8224320509 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/test.qml +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/test.qml diff --git a/examples/quick/quickwidgets/qquickviewcomparison/wobble.frag b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/wobble.frag index 9fddf1a162..9fddf1a162 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/wobble.frag +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/wobble.frag diff --git a/examples/quick/quickwidgets/qquickviewcomparison/wobble.frag.qsb b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/wobble.frag.qsb Binary files differindex ab764e8326..ab764e8326 100644 --- a/examples/quick/quickwidgets/qquickviewcomparison/wobble.frag.qsb +++ b/examples/quick/quickwidgets/qquickwidgetversuswindow_opengl/wobble.frag.qsb diff --git a/examples/quick/quickwidgets/quickwidget/CMakeLists.txt b/examples/quick/quickwidgets/quickwidget/CMakeLists.txt index f3cd7688c3..c8121d81a4 100644 --- a/examples/quick/quickwidgets/quickwidget/CMakeLists.txt +++ b/examples/quick/quickwidgets/quickwidget/CMakeLists.txt @@ -12,7 +12,6 @@ set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/quickwidgets/quickwidget") find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick QuickWidgets Widgets) qt_add_executable(quickwidget - fbitem.cpp fbitem.h main.cpp ) @@ -33,9 +32,7 @@ qt_add_qml_module(quickwidget URI QuickWidgetExample VERSION 1.0 QML_FILES - customgl.qml rotatingsquare.qml - rotatingsquaretab.qml RESOURCE_PREFIX /quickwidget NO_RESOURCE_TARGET_PATH ) diff --git a/examples/quick/quickwidgets/quickwidget/customgl.qml b/examples/quick/quickwidgets/quickwidget/customgl.qml deleted file mode 100644 index 577f006bd7..0000000000 --- a/examples/quick/quickwidgets/quickwidget/customgl.qml +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QuickWidgetExample 1.0 - -Rectangle { - color: "lightGray" - - FbItem { - anchors.fill: parent - anchors.margins: 10 - } - - Text { - anchors.left: parent.left - anchors.bottom: parent.bottom - anchors.margins: 15 - text: "QQuickFramebufferObject with animated clear color" - color: "white" - } -} diff --git a/examples/quick/quickwidgets/quickwidget/fbitem.cpp b/examples/quick/quickwidgets/quickwidget/fbitem.cpp deleted file mode 100644 index 3e98168dcf..0000000000 --- a/examples/quick/quickwidgets/quickwidget/fbitem.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "fbitem.h" -#include <QOpenGLFramebufferObject> -#include <QOpenGLContext> -#include <QOpenGLFunctions> -#include <QtCore/QDebug> - -#if QT_CONFIG(opengl) -class FbRenderer : public QQuickFramebufferObject::Renderer -{ -public: - FbRenderer() { } - - // The lifetime of the FBO and this class depends on how QQuickWidget - // manages the scenegraph and context when it comes to showing and hiding - // the widget. The actual behavior is proven by the debug prints. - ~FbRenderer() override { - qDebug("FbRenderer destroyed"); - } - - void render() override { - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - f->glClearColor(c, 0, 0, 1); - f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - c += 0.01f * dir; - if (c >= 1.0f || c <= 0.0f) - dir *= -1; - update(); - } - - QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override { - qDebug() << "Creating FBO" << size; - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - return new QOpenGLFramebufferObject(size, format); - } - -private: - float c = 0; - int dir = 1; -}; -#endif - -QQuickFramebufferObject::Renderer *FbItem::createRenderer() const -{ -#if QT_CONFIG(opengl) - return new FbRenderer; -#else - return nullptr; -#endif -} diff --git a/examples/quick/quickwidgets/quickwidget/fbitem.h b/examples/quick/quickwidgets/quickwidget/fbitem.h deleted file mode 100644 index eb5ec1f1d0..0000000000 --- a/examples/quick/quickwidgets/quickwidget/fbitem.h +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef FBITEM_H -#define FBITEM_H - -#include <QtQuick/QQuickFramebufferObject> - -class FbItem : public QQuickFramebufferObject -{ - Q_OBJECT - QML_ELEMENT -public: - Renderer *createRenderer() const override; -}; - -#endif diff --git a/examples/quick/quickwidgets/quickwidget/main.cpp b/examples/quick/quickwidgets/quickwidget/main.cpp index 191adcc451..5d1bc38aa7 100644 --- a/examples/quick/quickwidgets/quickwidget/main.cpp +++ b/examples/quick/quickwidgets/quickwidget/main.cpp @@ -48,14 +48,18 @@ ** ****************************************************************************/ +#include <QApplication> +#include <QCommandLineParser> #include <QQuickWidget> #include <QQuickItem> #include <QQmlError> -#include <QtWidgets> -#include "fbitem.h" - -static bool optMultipleSample = false; -static bool optCoreProfile = false; +#include <QMdiArea> +#include <QLCDNumber> +#include <QFileDialog> +#include <QStatusBar> +#include <QMainWindow> +#include <QMenuBar> +#include <QPushButton> class MainWindow : public QMainWindow { Q_OBJECT @@ -74,14 +78,12 @@ private: QQuickWidget *m_quickWidget; }; +static bool optMultipleSample = false; + MainWindow::MainWindow() : m_quickWidget(new QQuickWidget) { QSurfaceFormat format; - if (optCoreProfile) { - format.setVersion(4, 4); - format.setProfile(QSurfaceFormat::CoreProfile); - } if (optMultipleSample) format.setSamples(4); m_quickWidget->setFormat(format); @@ -120,23 +122,45 @@ MainWindow::MainWindow() void MainWindow::createQuickWidgetsInTabs(QMdiArea *mdiArea) { - QTabWidget *tabWidget = new QTabWidget; + // A QQuickWidget should work like any other widget when it comes to being + // in layouts, in tab widgets, MDI areas, etc. It can also be freely + // reparented and made top-level. + QTabWidget *tabWidget = new QTabWidget; const QSize size(400, 400); - - QQuickWidget *w = new QQuickWidget; - w->resize(size); - w->setResizeMode(QQuickWidget::SizeRootObjectToView); - w->setSource(QUrl("qrc:quickwidget/rotatingsquaretab.qml")); - - tabWidget->addTab(w, tr("Plain Quick content")); - - w = new QQuickWidget; - w->resize(size); - w->setResizeMode(QQuickWidget::SizeRootObjectToView); - w->setSource(QUrl("qrc:quickwidget/customgl.qml")); - - tabWidget->addTab(w, tr("Custom OpenGL drawing")); + const QString msgToTopLevel = QLatin1String("Break out to top-level window"); + const QString msgFromTopLevel = QLatin1String("Move back under tab widget"); + + static const int N = 4; + static const QColor colorTab[N] = { Qt::green, Qt::blue, Qt::yellow, Qt::magenta }; + for (int i = 0; i < N; ++i) { + QQuickWidget *widget = new QQuickWidget; + widget->resize(size); + widget->setResizeMode(QQuickWidget::SizeRootObjectToView); + QObject::connect(widget, &QQuickWidget::statusChanged, widget, [widget, i] { + if (widget->status() == QQuickWidget::Ready) { + if (QQuickItem *rootItem = widget->rootObject()) { + rootItem->setProperty("rectColor", colorTab[i]); + } + } + }); + widget->setSource(QUrl("qrc:quickwidget/rotatingsquare.qml")); + widget->setWindowTitle(QString::asprintf("Tab %d", i + 1)); + QPushButton *btn = new QPushButton(msgToTopLevel, widget); + connect(btn, &QPushButton::clicked, widget, [=] { + if (widget->parent()) { + widget->setAttribute(Qt::WA_DeleteOnClose, true); + widget->setParent(nullptr); + widget->show(); + btn->setText(msgFromTopLevel); + } else { + widget->setAttribute(Qt::WA_DeleteOnClose, false); + tabWidget->addTab(widget, widget->windowTitle()); + btn->setText(msgToTopLevel); + } + }); + tabWidget->addTab(widget, QString::asprintf("Tab %d", i + 1)); + } mdiArea->addSubWindow(tabWidget); tabWidget->show(); @@ -197,25 +221,20 @@ int main(int argc, char **argv) { QApplication app(argc, argv); - // this example and QQuickWidget are only functional when rendering with OpenGL - QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); - QCoreApplication::setApplicationName("Qt QQuickWidget Example"); QCoreApplication::setOrganizationName("QtProject"); QCoreApplication::setApplicationVersion(QT_VERSION_STR); + QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::applicationName()); parser.addHelpOption(); parser.addVersionOption(); QCommandLineOption multipleSampleOption("multisample", "Multisampling"); parser.addOption(multipleSampleOption); - QCommandLineOption coreProfileOption("coreprofile", "Use core profile"); - parser.addOption(coreProfileOption); parser.process(app); optMultipleSample = parser.isSet(multipleSampleOption); - optCoreProfile = parser.isSet(coreProfileOption); MainWindow mainWindow; mainWindow.show(); diff --git a/examples/quick/quickwidgets/quickwidget/quickwidget.pro b/examples/quick/quickwidgets/quickwidget/quickwidget.pro index b824c520f5..9c31ac28f3 100644 --- a/examples/quick/quickwidgets/quickwidget/quickwidget.pro +++ b/examples/quick/quickwidgets/quickwidget/quickwidget.pro @@ -7,8 +7,7 @@ CONFIG += qmltypes QML_IMPORT_NAME = QuickWidgetExample QML_IMPORT_MAJOR_VERSION = 1 -SOURCES += main.cpp fbitem.cpp -HEADERS += fbitem.h +SOURCES += main.cpp RESOURCES += quickwidget.qrc diff --git a/examples/quick/quickwidgets/quickwidget/quickwidget.qrc b/examples/quick/quickwidgets/quickwidget/quickwidget.qrc index 85a49b75ca..c073b7b80d 100644 --- a/examples/quick/quickwidgets/quickwidget/quickwidget.qrc +++ b/examples/quick/quickwidgets/quickwidget/quickwidget.qrc @@ -1,7 +1,5 @@ <RCC> <qresource prefix="/quickwidget"> <file>rotatingsquare.qml</file> - <file>rotatingsquaretab.qml</file> - <file>customgl.qml</file> </qresource> </RCC> diff --git a/examples/quick/quickwidgets/quickwidget/rotatingsquare.qml b/examples/quick/quickwidgets/quickwidget/rotatingsquare.qml index 5d3bb72fbe..08b769d80f 100644 --- a/examples/quick/quickwidgets/quickwidget/rotatingsquare.qml +++ b/examples/quick/quickwidgets/quickwidget/rotatingsquare.qml @@ -48,10 +48,11 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.8 Rectangle { id: root + property color rectColor: "red" Rectangle { property int d: 100 @@ -59,13 +60,35 @@ Rectangle { width: d height: d anchors.centerIn: parent - color: "red" + color: root.rectColor NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } } Text { + id: text anchors.centerIn: parent - text: "Qt Quick running in a widget" + property string api + Connections { + target: text.GraphicsInfo + function onApiChanged() { + var api = text.GraphicsInfo.api; + if (api === GraphicsInfo.Software) + text.api = "Software"; + else if (api === GraphicsInfo.OpenGL) + text.api = "OpenGL on QRhi"; + else if (api === GraphicsInfo.Direct3D11) + text.api = "D3D11 on QRhi"; + else if (api === GraphicsInfo.Vulkan) + text.api = "Vulkan on QRhi"; + else if (api === GraphicsInfo.Metal) + text.api = "Metal on QRhi"; + else if (api === GraphicsInfo.Null) + text.api = "Null on QRhi"; + else + text.api = "Unknown API"; + } + } + text: "Qt Quick running in a widget\nGraphicsInfo.api says: " + api } function performLayerBasedGrab(fn) { diff --git a/examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml b/examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml deleted file mode 100644 index 116a8f8729..0000000000 --- a/examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 - -Rectangle { - gradient: Gradient { - GradientStop { position: 0; color: "steelblue" } - GradientStop { position: 1; color: "black" } - } - - Rectangle { - property int d: 100 - id: square - width: d - height: d - anchors.centerIn: parent - color: "green" - NumberAnimation on rotation { from: 360; to: 0; duration: 4000; loops: Animation.Infinite; } - } - - Text { - anchors.centerIn: parent - text: "Qt Quick running in a tab widget" - color: "purple" - font.bold: true - font.pointSize: 14 - } -} diff --git a/examples/quick/quickwidgets/quickwidgets.pro b/examples/quick/quickwidgets/quickwidgets.pro index be932f33d0..14d1893776 100644 --- a/examples/quick/quickwidgets/quickwidgets.pro +++ b/examples/quick/quickwidgets/quickwidgets.pro @@ -1,3 +1,3 @@ TEMPLATE = subdirs SUBDIRS = quickwidget \ - qquickviewcomparison + qquickwidgetversuswindow_opengl diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index 5d29408b06..2c5e3e184c 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -157,7 +157,8 @@ QQuickRenderControlPrivate::QQuickRenderControlPrivate(QQuickRenderControl *rend ownRhi(true), cb(nullptr), offscreenSurface(nullptr), - sampleCount(1) + sampleCount(1), + frameStatus(NotRecordingFrame) { if (!sg) { qAddPostRoutine(cleanup); @@ -428,6 +429,7 @@ void QQuickRenderControl::invalidate() // also essential to allow a subsequent initialize() to succeed. d->rc->invalidate(); + d->frameStatus = QQuickRenderControlPrivate::NotRecordingFrame; d->initialized = false; } @@ -635,7 +637,23 @@ void QQuickRenderControl::beginFrame() emit d->window->beforeFrameBegin(); - d->rhi->beginOffscreenFrame(&d->cb); + QRhi::FrameOpResult result = d->rhi->beginOffscreenFrame(&d->cb); + + switch (result) { + case QRhi::FrameOpSuccess: + case QRhi::FrameOpSwapChainOutOfDate: + d->frameStatus = QQuickRenderControlPrivate::RecordingFrame; + break; + case QRhi::FrameOpError: + d->frameStatus = QQuickRenderControlPrivate::ErrorInBeginFrame; + break; + case QRhi::FrameOpDeviceLost: + d->frameStatus = QQuickRenderControlPrivate::DeviceLostInBeginFrame; + break; + default: + d->frameStatus = QQuickRenderControlPrivate::NotRecordingFrame; + break; + } } /*! @@ -658,6 +676,7 @@ void QQuickRenderControl::endFrame() d->rhi->endOffscreenFrame(); d->cb = nullptr; + d->frameStatus = QQuickRenderControlPrivate::NotRecordingFrame; emit d->window->afterFrameEnd(); } diff --git a/src/quick/items/qquickrendercontrol_p.h b/src/quick/items/qquickrendercontrol_p.h index acf84c8a23..f6588072a4 100644 --- a/src/quick/items/qquickrendercontrol_p.h +++ b/src/quick/items/qquickrendercontrol_p.h @@ -65,6 +65,13 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRenderControlPrivate : public QObjectPrivate public: Q_DECLARE_PUBLIC(QQuickRenderControl) + enum FrameStatus { + NotRecordingFrame, + RecordingFrame, + DeviceLostInBeginFrame, + ErrorInBeginFrame + }; + QQuickRenderControlPrivate(QQuickRenderControl *renderControl); static QQuickRenderControlPrivate *get(QQuickRenderControl *renderControl) { @@ -96,6 +103,7 @@ public: QRhiCommandBuffer *cb; QOffscreenSurface *offscreenSurface; int sampleCount; + FrameStatus frameStatus; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp index 6c29a866d7..f56db5568d 100644 --- a/src/quick/scenegraph/qsgrhisupport.cpp +++ b/src/quick/scenegraph/qsgrhisupport.cpp @@ -455,9 +455,9 @@ const void *QSGRhiSupport::rifResource(QSGRendererInterface::Resource res, } } -int QSGRhiSupport::chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi) +int QSGRhiSupport::chooseSampleCount(int samples, QRhi *rhi) { - int msaaSampleCount = qMax(QSurfaceFormat::defaultFormat().samples(), window->requestedFormat().samples()); + int msaaSampleCount = samples; if (qEnvironmentVariableIsSet("QSG_SAMPLES")) msaaSampleCount = qEnvironmentVariableIntValue("QSG_SAMPLES"); msaaSampleCount = qMax(1, msaaSampleCount); @@ -480,6 +480,11 @@ int QSGRhiSupport::chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi) return msaaSampleCount; } +int QSGRhiSupport::chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi) +{ + return chooseSampleCount(qMax(QSurfaceFormat::defaultFormat().samples(), window->requestedFormat().samples()), rhi); +} + // must be called on the main thread QOffscreenSurface *QSGRhiSupport::maybeCreateOffscreenSurface(QWindow *window) { diff --git a/src/quick/scenegraph/qsgrhisupport_p.h b/src/quick/scenegraph/qsgrhisupport_p.h index 101941875e..e7267c5826 100644 --- a/src/quick/scenegraph/qsgrhisupport_p.h +++ b/src/quick/scenegraph/qsgrhisupport_p.h @@ -92,6 +92,7 @@ class Q_QUICK_PRIVATE_EXPORT QSGRhiSupport public: static QSGRhiSupport *instance_internal(); static QSGRhiSupport *instance(); + static int chooseSampleCount(int samples, QRhi *rhi); static int chooseSampleCountForWindowWithRhi(QWindow *window, QRhi *rhi); static QImage grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src = nullptr); static void checkEnvQSgInfo(); diff --git a/src/quickwidgets/CMakeLists.txt b/src/quickwidgets/CMakeLists.txt index 4b6ebc0ad3..f9aaef9533 100644 --- a/src/quickwidgets/CMakeLists.txt +++ b/src/quickwidgets/CMakeLists.txt @@ -38,11 +38,3 @@ qt_internal_extend_target(QuickWidgets CONDITION QT_FEATURE_accessibility qaccessiblequickwidget.cpp qaccessiblequickwidget_p.h qaccessiblequickwidgetfactory.cpp qaccessiblequickwidgetfactory_p.h ) - -## Scopes: -##################################################################### - -qt_internal_extend_target(QuickWidgets CONDITION QT_FEATURE_opengl - LIBRARIES - Qt::OpenGLPrivate -) diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 95c1be879c..6d586f8828 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -40,6 +40,7 @@ #include "qquickwidget.h" #include "qquickwidget_p.h" #include "qaccessiblequickwidgetfactory_p.h" +#include <QtWidgets/private/qwidgetrepaintmanager_p.h> #include "private/qquickwindow_p.h" #include "private/qquickitem_p.h" @@ -60,14 +61,6 @@ #include <QtGui/private/qguiapplication_p.h> #include <QtGui/qpa/qplatformintegration.h> -#if QT_CONFIG(opengl) -#include <private/qopenglcontext_p.h> -#include <private/qopenglextensions_p.h> -#include <QOpenGLFramebufferObject> -#include <QOpenGLContext> -#include <QOpenGLFunctions> -#include <QtOpenGL/qpa/qplatformbackingstoreopenglsupport.h> -#endif #include <QtGui/QPainter> #include <QtQuick/QSGRendererInterface> @@ -212,17 +205,12 @@ void QQuickWidgetPrivate::init(QQmlEngine* e) useSoftwareRenderer = true; if (!useSoftwareRenderer) { -#if QT_CONFIG(opengl) - if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)) + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering)) setRenderToTexture(); else -#endif qWarning("QQuickWidget is not supported on this platform."); } - if (QSGRhiSupport::instance()->rhiBackend() != QRhi::OpenGLES2) - qWarning("QQuickWidget is only supported on OpenGL. Use QQuickWindow::setGraphicsApi() to override the default."); - engine = e; if (!engine.isNull() && !engine.data()->incubationController()) @@ -248,38 +236,24 @@ void QQuickWidgetPrivate::ensureEngine() const void QQuickWidgetPrivate::invalidateRenderControl() { -#if QT_CONFIG(opengl) - if (!useSoftwareRenderer) { - if (!context) // this is not an error, could be called before creating the context, or multiple times - return; - - bool success = context->makeCurrent(offscreenSurface); - if (!success) { - qWarning("QQuickWidget::invalidateRenderControl could not make context current"); - return; - } + if (!useSoftwareRenderer && rhi) { + // For the user's own OpenGL code connected to some QQuickWindow signals. + rhi->makeThreadLocalNativeContextCurrent(); } -#endif renderControl->invalidate(); - - // Many things can happen inside the above invalidate() call, including a - // change of current context. Restore if needed since some code will rely - // on the fact that this function makes and leaves the context current. -#if QT_CONFIG(opengl) - if (!useSoftwareRenderer && context) { - if (QOpenGLContext::currentContext() != context) - context->makeCurrent(offscreenSurface); - } -#endif } void QQuickWidgetPrivate::handleWindowChange() { Q_Q(QQuickWidget); - if (offscreenWindow->isPersistentSceneGraph() && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) + if (offscreenWindow->isPersistentSceneGraph() + && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts) + && rhiConfig().api() == QPlatformBackingStoreRhiConfig::OpenGL) + { return; + } // In case of !isPersistentSceneGraph or when we need a new context due to // the need to share resources with the new window's context, we must both @@ -298,21 +272,19 @@ void QQuickWidgetPrivate::handleWindowChange() QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate())); execute(); - if (!useSoftwareRenderer) - destroyContext(); } QQuickWidgetPrivate::QQuickWidgetPrivate() : root(nullptr) , component(nullptr) , offscreenWindow(nullptr) - , offscreenSurface(nullptr) , renderControl(nullptr) -#if QT_CONFIG(opengl) - , fbo(nullptr) - , resolvedFbo(nullptr) - , context(nullptr) -#endif + , rhi(nullptr) + , outputTexture(nullptr) + , depthStencil(nullptr) + , msaaBuffer(nullptr) + , rt(nullptr) + , rtRp(nullptr) , resizeMode(QQuickWidget::SizeViewToRootObject) , initialSize(0,0) , eventPending(false) @@ -321,28 +293,18 @@ QQuickWidgetPrivate::QQuickWidgetPrivate() , requestedSamples(0) , useSoftwareRenderer(false) , forceFullUpdate(false) + , deviceLost(false) { } -QQuickWidgetPrivate::~QQuickWidgetPrivate() +void QQuickWidgetPrivate::destroy() { + Q_Q(QQuickWidget); invalidateRenderControl(); - - if (useSoftwareRenderer) { - delete renderControl; - delete offscreenWindow; - } else { -#if QT_CONFIG(opengl) - // context and offscreenSurface are current at this stage, if the context was created. - Q_ASSERT(!context || (QOpenGLContext::currentContext() == context && context->surface() == offscreenSurface)); - delete resolvedFbo; - delete fbo; - delete offscreenWindow; - delete renderControl; - - destroyContext(); -#endif - } + q->destroyFramebufferObject(); + delete offscreenWindow; + delete renderControl; + offscreenRenderer.reset(); } void QQuickWidgetPrivate::execute() @@ -382,35 +344,36 @@ void QQuickWidgetPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeom void QQuickWidgetPrivate::render(bool needsSync) { + Q_Q(QQuickWidget); if (!useSoftwareRenderer) { -#if QT_CONFIG(opengl) + if (deviceLost) { + deviceLost = false; + initializeWithRhi(); + q->createFramebufferObject(); + } + + if (!rhi) + return; + // createFramebufferObject() bails out when the size is empty. In this case // we cannot render either. - if (!fbo) + if (!outputTexture) return; - Q_ASSERT(context); - - bool current = context->makeCurrent(offscreenSurface); - - if (!current && !context->isValid()) { - renderControl->invalidate(); - current = context->create() && context->makeCurrent(offscreenSurface); - if (current) { - offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromOpenGLContext(context)); - renderControl->initialize(); - } + renderControl->beginFrame(); + QQuickRenderControlPrivate::FrameStatus frameStatus = QQuickRenderControlPrivate::get(renderControl)->frameStatus; + if (frameStatus == QQuickRenderControlPrivate::DeviceLostInBeginFrame) { + // graphics resources controlled by us must be released + invalidateRenderControl(); + // skip this round and hope that the tlw's repaint manager will manage to reinitialize + deviceLost = true; + return; } - - if (!current) { - qWarning("QQuickWidget: Cannot render due to failing makeCurrent()"); + if (frameStatus != QQuickRenderControlPrivate::RecordingFrame) { + qWarning("QQuickWidget: Failed to begin recording a frame"); return; } - QOpenGLContextPrivate::get(context)->defaultFboRedirect = fbo->handle(); - - renderControl->beginFrame(); - if (needsSync) { renderControl->polishItems(); renderControl->sync(); @@ -419,17 +382,6 @@ void QQuickWidgetPrivate::render(bool needsSync) renderControl->render(); renderControl->endFrame(); - - context->makeCurrent(offscreenSurface); - if (resolvedFbo) { - QRect rect(QPoint(0, 0), fbo->size()); - QOpenGLFramebufferObject::blitFramebuffer(resolvedFbo, rect, fbo, rect); - } - - static_cast<QOpenGLExtensions *>(context->functions())->flushShared(); - - QOpenGLContextPrivate::get(context)->defaultFboRedirect = 0; -#endif } else { //Software Renderer if (needsSync) { @@ -461,14 +413,9 @@ void QQuickWidgetPrivate::renderSceneGraph() if (!q->isVisible() || fakeHidden) return; - if (!useSoftwareRenderer) { -#if QT_CONFIG(opengl) - if (!context) { - qWarning("QQuickWidget: Attempted to render scene with no context"); - return; - } -#endif - Q_ASSERT(offscreenSurface); + if (!useSoftwareRenderer && !rhi) { + qWarning("QQuickWidget: Attempted to render scene with no rhi"); + return; } render(true); @@ -488,25 +435,35 @@ void QQuickWidgetPrivate::renderSceneGraph() QImage QQuickWidgetPrivate::grabFramebuffer() { - if (!useSoftwareRenderer) { -#if QT_CONFIG(opengl) - if (!context) - return QImage(); - - context->makeCurrent(offscreenSurface); -#endif + if (!useSoftwareRenderer && !rhi) + return QImage(); + + // grabWindow() does not work for the rhi case, we are in control of the + // render target, and so it is up to us to read it back. When the software + // renderer is in use, just call grabWindow(). + + if (outputTexture) { + render(true); + QRhiCommandBuffer *cb = nullptr; + rhi->beginOffscreenFrame(&cb); + QRhiResourceUpdateBatch *resUpd = rhi->nextResourceUpdateBatch(); + QRhiReadbackResult readResult; + resUpd->readBackTexture(QRhiReadbackDescription(outputTexture), &readResult); + cb->resourceUpdate(resUpd); + rhi->endOffscreenFrame(); + if (!readResult.data.isEmpty()) { + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); + if (rhi->isYUpInFramebuffer()) + return wrapperImage.mirrored(); + else + return wrapperImage.copy(); + } + return QImage(); } - - // grabWindow() does not work for the OpenGL + render control case, so we - // prefer the FBO's toImage() if available. When the software renderer - // is in use, however, there will be no FBO and we fall back to grabWindow() - // instead. - return -#if QT_CONFIG(opengl) - fbo != nullptr ? fbo->toImage() : -#endif - offscreenWindow->grabWindow(); + return offscreenWindow->grabWindow(); } // Intentionally not overriding the QQuickWindow's focusObject. @@ -568,10 +525,10 @@ QImage QQuickWidgetPrivate::grabFramebuffer() However, the above mentioned advantages come at the expense of performance: \list - \li Unlike QQuickWindow and QQuickView, QQuickWidget requires rendering into OpenGL - framebuffer objects, which needs to be enforced by calling - QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL) at startup. - This will naturally carry a minor performance hit. + \li Unlike QQuickWindow and QQuickView, QQuickWidget involves at least one + additional render pass targeting an offscreen color buffer, typically a 2D + texture, followed by drawing a texture quad. This means increased load + especially for the fragment processing of the GPU. \li Using QQuickWidget disables the \l{threaded_render_loop}{threaded render loop} on all platforms. This means that some of the benefits of threaded rendering, for example @@ -583,6 +540,24 @@ QImage QQuickWidgetPrivate::grabFramebuffer() entire purpose of QQuickWidget is to render Quick scenes without a separate native window, hence making it a native widget should always be avoided. + \section1 Graphics API Support + + QQuickWidget is functional with all the 3D graphics APIs supported by Qt + Quick, as well as the \c software backend. Other backends, for example + OpenVG, are not compatible however and attempting to construct a + QQuickWidget will lead to problems. + + Overriding the platform's default graphics API is done the same way as with + QQuickWindow and QQuickView: either by calling + QQuickWindow::setGraphicsApi() early on before constructing the first + QQuickWidget, or by setting the \c{QSG_RHI_BACKEND} environment variable. + + \note One top-level window can only use one single graphics API for + rendering. For example, attempting to place a QQuickWidget using Vulkan and + a QOpenGLWidget in the widget hierarchy of the same top-level window, + problems will occur and one of the widgets will not be rendering as + expected. + \section1 Scene Graph and Context Persistency QQuickWidget honors QQuickWindow::isPersistentSceneGraph(), meaning that @@ -592,20 +567,19 @@ QImage QQuickWidgetPrivate::grabFramebuffer() related resources be released whenever the widget becomes hidden. By default persistency is enabled, just like with QQuickWindow. - When running with the OpenGL backend of the scene graph, QQuickWindow - offers the possibility to disable persistent OpenGL contexts as well. This - setting is currently ignored by QQuickWidget and the context is always - persistent. The OpenGL context is thus not destroyed when hiding the - widget. The context is destroyed only when the widget is destroyed or when - the widget gets reparented into another top-level widget's child hierarchy. - However, some applications, in particular those that have their own - graphics resources due to performing custom OpenGL rendering in the Qt - Quick scene, may wish to disable the latter since they may not be prepared - to handle the loss of the context when moving a QQuickWidget into another - window. Such applications can set the - QCoreApplication::AA_ShareOpenGLContexts attribute. For a discussion on the - details of resource initialization and cleanup, refer to the QOpenGLWidget - documentation. + When running with the OpenGL, QQuickWindow offers the possibility to + disable persistent OpenGL contexts as well. This setting is currently + ignored by QQuickWidget and the context is always persistent. The OpenGL + context is thus not destroyed when hiding the widget. The context is + destroyed only when the widget is destroyed or when the widget gets + reparented into another top-level widget's child hierarchy. However, some + applications, in particular those that have their own graphics resources + due to performing custom OpenGL rendering in the Qt Quick scene, may wish + to disable the latter since they may not be prepared to handle the loss of + the context when moving a QQuickWidget into another window. Such + applications can set the QCoreApplication::AA_ShareOpenGLContexts + attribute. For a discussion on the details of resource initialization and + cleanup, refer to the QOpenGLWidget documentation. \note QQuickWidget offers less fine-grained control over its internal OpenGL context than QOpenGLWidget, and there are subtle differences, most @@ -633,13 +607,6 @@ QImage QQuickWidgetPrivate::grabFramebuffer() Qt::WA_TranslucentBackground on the top-level window, request an alpha channel, and change the Qt Quick Scenegraph's clear color to Qt::transparent via setClearColor(). - \section1 Support when not using OpenGL - - In addition to OpenGL, the \c software backend of Qt Quick also supports - QQuickWidget. Other backends, for example OpenVG, are not - compatible however and attempting to construct a QQuickWidget will lead to - problems. - \section1 Tab Key Handling On press of the \c[TAB] key, the item inside the QQuickWidget gets focus. If @@ -706,6 +673,13 @@ QQuickWidget::~QQuickWidget() Q_D(QQuickWidget); delete d->root; d->root = nullptr; + + // NB! resetting graphics resources must be done from this destructor, + // *not* from the private class' destructor. This is due to how destruction + // works and due to the QWidget dtor (for toplevels) destroying the repaint + // manager and rhi before the (QObject) private gets destroyed. Hence must + // do it here early on. + d->destroy(); } /*! @@ -1010,7 +984,7 @@ void QQuickWidgetPrivate::handleContextCreationFailure(const QSurfaceFormat &) QString translatedMessage; QString untranslatedMessage; - QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String("OpenGL"), &translatedMessage, &untranslatedMessage); + QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String("QRhi"), &translatedMessage, &untranslatedMessage); static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError); const bool signalConnected = q->isSignalConnected(errorSignal); @@ -1025,72 +999,90 @@ void QQuickWidgetPrivate::handleContextCreationFailure(const QSurfaceFormat &) qFatal("%s", qPrintable(untranslatedMessage)); } +static inline QPlatformBackingStoreRhiConfig::Api graphicsApiToBackingStoreRhiApi(QSGRendererInterface::GraphicsApi api) +{ + switch (api) { + case QSGRendererInterface::OpenGL: + return QPlatformBackingStoreRhiConfig::OpenGL; + case QSGRendererInterface::Vulkan: + return QPlatformBackingStoreRhiConfig::Vulkan; + case QSGRendererInterface::Direct3D11: + return QPlatformBackingStoreRhiConfig::D3D11; + case QSGRendererInterface::Metal: + return QPlatformBackingStoreRhiConfig::Metal; + default: + return QPlatformBackingStoreRhiConfig::Null; + } +} + // Never called by Software Rendering backend -void QQuickWidgetPrivate::createContext() +void QQuickWidgetPrivate::initializeWithRhi() { -#if QT_CONFIG(opengl) Q_Q(QQuickWidget); + QWidgetPrivate *tlwd = QWidgetPrivate::get(q->window()); + // when reparenting, the rhi may suddenly be different + if (rhi) { + QRhi *tlwRhi = nullptr; + if (QWidgetRepaintManager *repaintManager = tlwd->maybeRepaintManager()) + tlwRhi = repaintManager->rhi(); + if (tlwRhi && rhi != tlwRhi) + rhi = nullptr; + } + // On hide-show we may invalidate() (when !isPersistentSceneGraph) but our // context is kept. We may need to initialize() again, though. - const bool reinit = context && !offscreenWindow->isSceneGraphInitialized(); + const bool onlyNeedsSgInit = rhi && !offscreenWindow->isSceneGraphInitialized(); - if (!reinit) { - if (context) + if (!onlyNeedsSgInit) { + if (rhi) return; - context = new QOpenGLContext; - context->setFormat(offscreenWindow->requestedFormat()); - context->setScreen(q->screen()); - QOpenGLContext *shareContext = qt_gl_global_share_context(); - if (!shareContext) - shareContext = QWidgetPrivate::get(q->window())->shareContext(); - if (shareContext) { - context->setShareContext(shareContext); - context->setScreen(shareContext->screen()); - } - if (!context->create()) { - delete context; - context = nullptr; - handleContextCreationFailure(offscreenWindow->requestedFormat()); - return; + if (QWidgetRepaintManager *repaintManager = tlwd->maybeRepaintManager()) + rhi = repaintManager->rhi(); + + if (!rhi) { + // The widget (and its parent chain, if any) may not be shown at + // all, yet one may still want to use it for grabs. This is + // ridiculous of course because the rendering infrastructure is + // tied to the top-level widget that initializes upon expose, but + // it has to be supported. + offscreenRenderer.setConfig(rhiConfig()); + offscreenRenderer.setFormat(q->format()); + // no window passed in, so no swapchain, but we get a functional QRhi which we own + if (offscreenRenderer.create()) + rhi = offscreenRenderer.rhi(); } - offscreenSurface = new QOffscreenSurface; - // Pass the context's format(), which, now that the underlying platform context is created, - // contains a QSurfaceFormat representing the _actual_ format of the underlying - // configuration. This is essential to get a surface that is compatible with the context. - offscreenSurface->setFormat(context->format()); - offscreenSurface->setScreen(context->screen()); - offscreenSurface->create(); + // Could be that something else already initialized the window with some + // other graphics API for the QRhi, that's not good. + if (rhi && rhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()))) { + qWarning("The top-level window is not using the expected graphics API for composition, " + "'%s' is not compatible with this QQuickWidget", + rhi->backendName()); + rhi = nullptr; + } } - if (context->makeCurrent(offscreenSurface)) { + if (rhi) { if (!offscreenWindow->isSceneGraphInitialized()) { - offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromOpenGLContext(context)); + offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi)); +#if QT_CONFIG(vulkan) + if (QWindow *w = q->window()->windowHandle()) + offscreenWindow->setVulkanInstance(w->vulkanInstance()); +#endif renderControl->initialize(); } - } else -#endif - qWarning("QQuickWidget: Failed to make context current"); -} - -// Never called by Software Rendering backend -void QQuickWidgetPrivate::destroyContext() -{ -#if QT_CONFIG(opengl) - delete context; - context = nullptr; -#endif - delete offscreenSurface; - offscreenSurface = nullptr; + } else { + qWarning("QQuickWidget: Failed to get a QRhi from the top-level widget's window"); + } } void QQuickWidget::createFramebufferObject() { Q_D(QQuickWidget); - // Could come from Show -> createContext -> sceneGraphInitialized in which case the size may + // Could come from Show -> initializeWithRhi -> sceneGraphInitialized in which case the size may // still be invalid on some platforms. Bail out. A resize will come later on. if (size().isEmpty()) return; @@ -1109,82 +1101,85 @@ void QQuickWidget::createFramebufferObject() return; } -#if QT_CONFIG(opengl) - if (!d->context) { - qWarning("QQuickWidget: Attempted to create FBO with no context"); - return; - } - - QOpenGLContext *shareWindowContext = QWidgetPrivate::get(window())->shareContext(); - if (shareWindowContext && d->context->shareContext() != shareWindowContext && !qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) { - d->context->setShareContext(shareWindowContext); - d->context->setScreen(shareWindowContext->screen()); - if (!d->context->create()) - qWarning("QQuickWidget: Failed to recreate context"); - // The screen may be different so we must recreate the offscreen surface too. - // Unlike QOpenGLContext, QOffscreenSurface's create() does not recreate so have to destroy() first. - d->offscreenSurface->destroy(); - d->offscreenSurface->setScreen(d->context->screen()); - d->offscreenSurface->create(); - } - - bool current = d->context->makeCurrent(d->offscreenSurface); - if (!current) { - qWarning("QQuickWidget: Failed to make context current when creating FBO"); + if (!d->rhi) { + qWarning("QQuickWidget: Attempted to create output texture with no QRhi"); return; } int samples = d->requestedSamples; - if (!QOpenGLExtensions(d->context).hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) + if (d->rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) + samples = QSGRhiSupport::chooseSampleCount(samples, d->rhi); + else samples = 0; - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - format.setSamples(samples); - - // The default framebuffer for normal windows have sRGB support on OS X which leads to the Qt Quick text item - // utilizing sRGB blending. To get identical results with QQuickWidget we have to have our framebuffer backed - // by an sRGB texture. -#ifdef Q_OS_MACOS - if (d->context->hasExtension("GL_ARB_framebuffer_sRGB") - && d->context->hasExtension("GL_EXT_texture_sRGB") - && d->context->hasExtension("GL_EXT_texture_sRGB_decode")) { - format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT); - } -#endif - const QSize fboSize = size() * devicePixelRatio(); - // Could be a simple hide - show, in which case the previous fbo is just fine. - if (!d->fbo || d->fbo->size() != fboSize) { - delete d->fbo; - d->fbo = new QOpenGLFramebufferObject(fboSize, format); + // Could be a simple hide - show, in which case the previous texture is just fine. + if (!d->outputTexture) { + d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget); + if (!d->outputTexture->create()) { + qWarning("QQuickWidget: failed to create output texture of size %dx%d", + fboSize.width(), fboSize.height()); + } } - - // When compositing in the backingstore, sampling the sRGB texture would perform an - // sRGB-linear conversion which is not what we want when the final framebuffer (the window's) - // is sRGB too. Disable the conversion. -#ifdef Q_OS_MACOS - if (format.internalTextureFormat() == GL_SRGB8_ALPHA8_EXT) { - QOpenGLFunctions *funcs = d->context->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, d->fbo->texture()); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); + if (!d->depthStencil) { + d->depthStencil = d->rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, fboSize, samples); + if (!d->depthStencil->create()) { + qWarning("QQuickWidget: failed to create depth/stencil buffer of size %dx%d and sample count %d", + fboSize.width(), fboSize.height(), samples); + } + } + if (samples > 1 && !d->msaaBuffer) { + d->msaaBuffer = d->rhi->newRenderBuffer(QRhiRenderBuffer::Color, fboSize, samples); + if (!d->msaaBuffer->create()) { + qWarning("QQuickWidget: failed to create multisample renderbuffer of size %dx%d and sample count %d", + fboSize.width(), fboSize.height(), samples); + } + } + if (!d->rt) { + QRhiTextureRenderTargetDescription rtDesc; + QRhiColorAttachment colorAtt; + if (samples <= 1) { + colorAtt.setTexture(d->outputTexture); + } else { + colorAtt.setRenderBuffer(d->msaaBuffer); + colorAtt.setResolveTexture(d->outputTexture); + } + rtDesc.setColorAttachments({ colorAtt }); + rtDesc.setDepthStencilBuffer(d->depthStencil); + d->rt = d->rhi->newTextureRenderTarget(rtDesc); + d->rtRp = d->rt->newCompatibleRenderPassDescriptor(); + d->rt->setRenderPassDescriptor(d->rtRp); + d->rt->create(); + } + if (d->outputTexture->pixelSize() != fboSize) { + d->outputTexture->setPixelSize(fboSize); + if (!d->outputTexture->create()) { + qWarning("QQuickWidget: failed to create resized output texture of size %dx%d", + fboSize.width(), fboSize.height()); + } + d->depthStencil->setPixelSize(fboSize); + if (!d->depthStencil->create()) { + qWarning("QQuickWidget: failed to create resized depth/stencil buffer of size %dx%d", + fboSize.width(), fboSize.height()); + } + if (d->msaaBuffer) { + d->msaaBuffer->setPixelSize(fboSize); + if (!d->msaaBuffer->create()) { + qWarning("QQuickWidget: failed to create resized multisample renderbuffer of size %dx%d", + fboSize.width(), fboSize.height()); + } + } } -#endif - GLuint textureId = d->fbo->texture(); - d->offscreenWindow->setRenderTarget( QQuickRenderTarget::fromOpenGLTexture(textureId, fboSize, samples)); + d->offscreenWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(d->rt)); d->renderControl->setSamples(samples); - if (samples > 0) - d->resolvedFbo = new QOpenGLFramebufferObject(fboSize); - // Sanity check: The window must not have an underlying platform window. // Having one would mean create() was called and platforms that only support // a single native window were in trouble. Q_ASSERT(!d->offscreenWindow->handle()); -#endif } void QQuickWidget::destroyFramebufferObject() @@ -1196,12 +1191,16 @@ void QQuickWidget::destroyFramebufferObject() return; } -#if QT_CONFIG(opengl) - delete d->fbo; - d->fbo = nullptr; - delete d->resolvedFbo; - d->resolvedFbo = nullptr; -#endif + delete d->rt; + d->rt = nullptr; + delete d->rtRp; + d->rtRp = nullptr; + delete d->depthStencil; + d->depthStencil = nullptr; + delete d->msaaBuffer; + d->msaaBuffer = nullptr; + delete d->outputTexture; + d->outputTexture = nullptr; } QQuickWidget::ResizeMode QQuickWidget::resizeMode() const @@ -1279,8 +1278,17 @@ void QQuickWidgetPrivate::setRootObject(QObject *obj) } } -#if QT_CONFIG(opengl) -GLuint QQuickWidgetPrivate::textureId() const +QPlatformBackingStoreRhiConfig QQuickWidgetPrivate::rhiConfig() const +{ + if (useSoftwareRenderer) + return {}; + + QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi())); + config.setDebugLayer(QSGRhiSupport::instance()->isDebugLayerRequested()); + return config; +} + +QRhiTexture *QQuickWidgetPrivate::texture() const { Q_Q(const QQuickWidget); if (!q->isWindow() && q->internalWinId()) { @@ -1288,8 +1296,7 @@ GLuint QQuickWidgetPrivate::textureId() const << "Consider setting Qt::AA_DontCreateNativeWidgetSiblings"; return 0; } - return resolvedFbo ? resolvedFbo->texture() - : (fbo ? fbo->texture() : 0); + return outputTexture; } QPlatformTextureList::Flags QQuickWidgetPrivate::textureListFlags() @@ -1298,7 +1305,6 @@ QPlatformTextureList::Flags QQuickWidgetPrivate::textureListFlags() flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending; return flags; } -#endif /*! \internal @@ -1388,13 +1394,12 @@ void QQuickWidget::resizeEvent(QResizeEvent *e) createFramebufferObject(); } } else { -#if QT_CONFIG(opengl) - if (d->context) { + if (d->rhi) { // Bail out when receiving a resize after scenegraph invalidation. This can happen // during hide - resize - show sequences and also during application exit. - if (!d->fbo && !d->offscreenWindow->isSceneGraphInitialized()) + if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized()) return; - if (!d->fbo || d->fbo->size() != size() * devicePixelRatio()) { + if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) { needsSync = true; createFramebufferObject(); } @@ -1402,14 +1407,13 @@ void QQuickWidget::resizeEvent(QResizeEvent *e) // This will result in a scenegraphInitialized() signal which // is connected to createFramebufferObject(). needsSync = true; - d->createContext(); + d->initializeWithRhi(); } - if (!d->context) { - qWarning("QQuickWidget::resizeEvent() no OpenGL context"); + if (!d->rhi) { + qWarning("QQuickWidget::resizeEvent() no QRhi"); return; } -#endif } d->render(needsSync); @@ -1493,7 +1497,7 @@ void QQuickWidget::showEvent(QShowEvent *) bool shouldTriggerUpdate = true; if (!d->useSoftwareRenderer) { - d->createContext(); + d->initializeWithRhi(); if (d->offscreenWindow->isSceneGraphInitialized()) { shouldTriggerUpdate = false; @@ -1657,26 +1661,22 @@ bool QQuickWidget::event(QEvent *e) return eventResult; } + case QEvent::WindowAboutToChangeInternal: + d->invalidateRenderControl(); + d->rhi = nullptr; + break; + case QEvent::WindowChangeInternal: d->handleWindowChange(); break; - case QEvent::ScreenChangeInternal: { + case QEvent::ScreenChangeInternal: + { QScreen *newScreen = screen(); if (d->offscreenWindow) d->offscreenWindow->setScreen(newScreen); - if (d->offscreenSurface) - d->offscreenSurface->setScreen(newScreen); -#if QT_CONFIG(opengl) - if (d->context) - d->context->setScreen(newScreen); -#endif - if (d->useSoftwareRenderer -#if QT_CONFIG(opengl) - || d->fbo -#endif - ) { + if (d->useSoftwareRenderer || d->outputTexture) { // This will check the size taking the devicePixelRatio into account // and recreate if needed. createFramebufferObject(); @@ -1898,10 +1898,6 @@ void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject) emit window->focusObjectChanged(focusObject); } -#if QT_CONFIG(opengl) -Q_CONSTRUCTOR_FUNCTION(qt_registerDefaultPlatformBackingStoreOpenGLSupport); -#endif - QT_END_NAMESPACE #include "moc_qquickwidget.cpp" diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h index d42fafec8d..a489f8c8cb 100644 --- a/src/quickwidgets/qquickwidget_p.h +++ b/src/quickwidgets/qquickwidget_p.h @@ -53,6 +53,8 @@ #include "qquickwidget.h" #include <private/qwidget_p.h> +#include <private/qrhi_p.h> +#include <private/qbackingstorerhisupport_p.h> #include <QtCore/qurl.h> #include <QtCore/qelapsedtimer.h> @@ -71,9 +73,6 @@ class QQmlError; class QQuickItem; class QQmlComponent; class QQuickRenderControl; -class QOpenGLContext; -class QOffscreenSurface; -class QOpenGLFramebufferObject; class QQuickWidgetPrivate : public QWidgetPrivate, @@ -85,8 +84,8 @@ public: static const QQuickWidgetPrivate* get(const QQuickWidget *view) { return view->d_func(); } QQuickWidgetPrivate(); - ~QQuickWidgetPrivate(); + void destroy(); void execute(); void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry) override; void initResize(); @@ -96,17 +95,13 @@ public: void setRootObject(QObject *); void render(bool needsSync); void renderSceneGraph(); - void createContext(); - void destroyContext(); + void initializeWithRhi(); void handleContextCreationFailure(const QSurfaceFormat &format); -#if QT_CONFIG(opengl) - GLuint textureId() const override; + QPlatformBackingStoreRhiConfig rhiConfig() const override; + QRhiTexture *texture() const override; QPlatformTextureList::Flags textureListFlags() override; QImage grabFramebuffer() override; -#else - QImage grabFramebuffer(); -#endif void init(QQmlEngine* e = 0); void initOffscreenWindow(); @@ -124,14 +119,14 @@ public: QQmlComponent *component; QBasicTimer resizetimer; QQuickWindow *offscreenWindow; - QOffscreenSurface *offscreenSurface; QQuickRenderControl *renderControl; -#if QT_CONFIG(opengl) - QOpenGLFramebufferObject *fbo; - QOpenGLFramebufferObject *resolvedFbo; - QOpenGLContext *context; -#endif + QRhi *rhi; + QRhiTexture *outputTexture; + QRhiRenderBuffer *depthStencil; + QRhiRenderBuffer *msaaBuffer; + QRhiTextureRenderTarget *rt; + QRhiRenderPassDescriptor *rtRp; QQuickWidget::ResizeMode resizeMode; QSize initialSize; @@ -148,6 +143,9 @@ public: QImage softwareImage; QRegion updateRegion; bool forceFullUpdate; + bool deviceLost; + + QBackingStoreRhiSupport offscreenRenderer; }; class QQuickWidgetOffscreenWindow: public QQuickWindow diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp index a63ebde084..f6a91d8534 100644 --- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -127,6 +127,7 @@ public: tst_qquickwidget(); private slots: + void initTestCase(); void showHide(); void reparentAfterShow(); void changeGeometry(); @@ -165,6 +166,20 @@ tst_qquickwidget::tst_qquickwidget() QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi); } +void tst_qquickwidget::initTestCase() +{ + QQmlDataTest::initTestCase(); + + // ### QTBUG-101884 Skip this test in the QEMU configs in the CI. That runs + // with the offscreen plugin and the software backend of Qt Quick. Until + // some of the test cases are investigated, skip the whole test. + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + { + QSKIP("Skipping due to using a an offscreen platform / software rendering"); + } +} + void tst_qquickwidget::showHide() { QWidget window; @@ -380,8 +395,6 @@ void tst_qquickwidget::engine() void tst_qquickwidget::readback() { - QWidget window; - QScopedPointer<QQuickWidget> view(new QQuickWidget); view->setSource(testFileUrl("rectangle.qml")); |