diff options
18 files changed, 429 insertions, 51 deletions
diff --git a/examples/quick/quickwidgets/quickwidget/customgl.qml b/examples/quick/quickwidgets/quickwidget/customgl.qml new file mode 100644 index 0000000000..81e33e1ac9 --- /dev/null +++ b/examples/quick/quickwidgets/quickwidget/customgl.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 new file mode 100644 index 0000000000..fc2a4ea7ad --- /dev/null +++ b/examples/quick/quickwidgets/quickwidget/fbitem.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 <QtGui/QOpenGLFramebufferObject> +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLFunctions> +#include <QtCore/QDebug> + +#ifndef QT_NO_OPENGL +class FbRenderer : public QQuickFramebufferObject::Renderer +{ +public: + FbRenderer() : c(0), dir(1) { } + + // 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() { + qDebug("FbRenderer destroyed"); + } + + void render() { + 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) { + qDebug() << "Creating FBO" << size; + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + return new QOpenGLFramebufferObject(size, format); + } + +private: + float c; + int dir; +}; +#endif + +QQuickFramebufferObject::Renderer *FbItem::createRenderer() const +{ +#ifndef QT_NO_OPENGL + return new FbRenderer; +#else + return nullptr; +#endif +} diff --git a/examples/quick/quickwidgets/quickwidget/fbitem.h b/examples/quick/quickwidgets/quickwidget/fbitem.h new file mode 100644 index 0000000000..59280eb3b8 --- /dev/null +++ b/examples/quick/quickwidgets/quickwidget/fbitem.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 +public: + Renderer *createRenderer() const; +}; + +#endif diff --git a/examples/quick/quickwidgets/quickwidget/main.cpp b/examples/quick/quickwidgets/quickwidget/main.cpp index 65258d958e..2f73447a5d 100644 --- a/examples/quick/quickwidgets/quickwidget/main.cpp +++ b/examples/quick/quickwidgets/quickwidget/main.cpp @@ -41,6 +41,7 @@ #include <QQuickWidget> #include <QQmlError> #include <QtWidgets> +#include "fbitem.h" class MainWindow : public QMainWindow { Q_OBJECT @@ -52,6 +53,7 @@ private slots: void sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message); void grabToFile(); void renderToFile(); + void createQuickWidgetsInTabs(QMdiArea *mdiArea); private: QQuickWidget *m_quickWidget; @@ -74,7 +76,7 @@ MainWindow::MainWindow() QLCDNumber *lcd = new QLCDNumber; lcd->display(1337); lcd->setMinimumSize(250,100); - centralWidget ->addSubWindow(lcd); + centralWidget->addSubWindow(lcd); QUrl source("qrc:quickwidget/rotatingsquare.qml"); @@ -86,14 +88,42 @@ MainWindow::MainWindow() m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView ); m_quickWidget->setSource(source); - centralWidget ->addSubWindow(m_quickWidget); + centralWidget->addSubWindow(m_quickWidget); setCentralWidget(centralWidget); QMenu *fileMenu = menuBar()->addMenu(tr("&File")); - fileMenu->addAction(tr("Grab to imFage"), this, &MainWindow::grabToFile); + fileMenu->addAction(tr("Grab to image"), this, &MainWindow::grabToFile); fileMenu->addAction(tr("Render to pixmap"), this, &MainWindow::renderToFile); fileMenu->addAction(tr("Quit"), qApp, &QCoreApplication::quit); + + QMenu *windowMenu = menuBar()->addMenu(tr("&Window")); + windowMenu->addAction(tr("Add tab widget"), this, + [this, centralWidget] { createQuickWidgetsInTabs(centralWidget); }); +} + +void MainWindow::createQuickWidgetsInTabs(QMdiArea *mdiArea) +{ + 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")); + + mdiArea->addSubWindow(tabWidget); + tabWidget->show(); } void MainWindow::quickWidgetStatusChanged(QQuickWidget::Status status) @@ -139,6 +169,8 @@ int main(int argc, char **argv) { QApplication app(argc, argv); + qmlRegisterType<FbItem>("QuickWidgetExample", 1, 0, "FbItem"); + MainWindow mainWindow; mainWindow.show(); diff --git a/examples/quick/quickwidgets/quickwidget/quickwidget.pro b/examples/quick/quickwidgets/quickwidget/quickwidget.pro index 04fb5541a7..5be006f7fa 100644 --- a/examples/quick/quickwidgets/quickwidget/quickwidget.pro +++ b/examples/quick/quickwidgets/quickwidget/quickwidget.pro @@ -3,7 +3,8 @@ QT += core gui quick widgets quickwidgets TARGET = quickwidget TEMPLATE = app -SOURCES += main.cpp +SOURCES += main.cpp fbitem.cpp +HEADERS += fbitem.h RESOURCES += quickwidget.qrc diff --git a/examples/quick/quickwidgets/quickwidget/quickwidget.qrc b/examples/quick/quickwidgets/quickwidget/quickwidget.qrc index c073b7b80d..85a49b75ca 100644 --- a/examples/quick/quickwidgets/quickwidget/quickwidget.qrc +++ b/examples/quick/quickwidgets/quickwidget/quickwidget.qrc @@ -1,5 +1,7 @@ <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/rotatingsquaretab.qml b/examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml new file mode 100644 index 0000000000..51c17b9ffb --- /dev/null +++ b/examples/quick/quickwidgets/quickwidget/rotatingsquaretab.qml @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index e40666864c..d73ce6f09d 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -47,7 +47,6 @@ #include <private/qv4ssa_p.h> #include "qqmlpropertycachecreator_p.h" -#include "qqmlpropertyvalidator_p.h" #define COMPILE_EXCEPTION(token, desc) \ { \ @@ -168,34 +167,6 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() compilationUnit->propertyCaches = std::move(m_propertyCaches); Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->data->nObjects)); - // Add to type registry of composites - if (compilationUnit->propertyCaches.needsVMEMetaObject(qmlUnit->indexOfRootObject)) - engine->registerInternalCompositeType(compilationUnit); - else { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject); - auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); - Q_ASSERT(typeRef); - if (typeRef->compilationUnit) { - compilationUnit->metaTypeId = typeRef->compilationUnit->metaTypeId; - compilationUnit->listMetaTypeId = typeRef->compilationUnit->listMetaTypeId; - } else { - compilationUnit->metaTypeId = typeRef->type->typeId(); - compilationUnit->listMetaTypeId = typeRef->type->qListTypeId(); - } - } - - { - // Sanity check property bindings - QQmlPropertyValidator validator(engine, *imports(), compilationUnit); - QVector<QQmlCompileError> errors = validator.validate(); - if (!errors.isEmpty()) { - for (const QQmlCompileError &error: qAsConst(errors)) - recordError(error); - return nullptr; - } - } - - compilationUnit->updateBindingAndObjectCounters(); if (errors.isEmpty()) return compilationUnit; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index d2587a547c..b05abdc0c8 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -239,8 +239,23 @@ IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjec return *it; } -void CompilationUnit::updateBindingAndObjectCounters() +void CompilationUnit::finalize(QQmlEnginePrivate *engine) { + // Add to type registry of composites + if (propertyCaches.needsVMEMetaObject(data->indexOfRootObject)) + engine->registerInternalCompositeType(this); + else { + const QV4::CompiledData::Object *obj = objectAt(data->indexOfRootObject); + auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); + Q_ASSERT(typeRef); + if (typeRef->compilationUnit) { + metaTypeId = typeRef->compilationUnit->metaTypeId; + listMetaTypeId = typeRef->compilationUnit->listMetaTypeId; + } else { + metaTypeId = typeRef->type->typeId(); + listMetaTypeId = typeRef->type->qListTypeId(); + } + } // Collect some data for instantiation later. int bindingCount = 0; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index b960901402..a9a0ebbf51 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -766,7 +766,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount QHash<int, IdentifierHash<int>> namedObjectsPerComponentCache; IdentifierHash<int> namedObjectsPerComponent(int componentObjectIndex); - void updateBindingAndObjectCounters(); + void finalize(QQmlEnginePrivate *engine); int totalBindingsCount; // Number of bindings used in this type int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 7ba18cd761..190ac29e33 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -49,6 +49,7 @@ #include <private/qqmlprofiler_p.h> #include <private/qqmlmemoryprofiler_p.h> #include <private/qqmltypecompiler_p.h> +#include <private/qqmlpropertyvalidator_p.h> #include <QtCore/qdir.h> #include <QtCore/qfile.h> @@ -445,6 +446,21 @@ void QQmlDataBlob::setError(const QQmlCompileError &error) setError(e); } +void QQmlDataBlob::setError(const QVector<QQmlCompileError> &errors) +{ + QList<QQmlError> finalErrors; + finalErrors.reserve(errors.count()); + for (const QQmlCompileError &error: errors) { + QQmlError e; + e.setColumn(error.location.column); + e.setLine(error.location.line); + e.setDescription(error.description); + e.setUrl(url()); + finalErrors << e; + } + setError(finalErrors); +} + void QQmlDataBlob::setError(const QString &description) { QQmlError e; @@ -2082,6 +2098,20 @@ void QQmlTypeData::done() compile(); if (!isError()) { + QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); + { + // Sanity check property bindings + QQmlPropertyValidator validator(engine, m_importCache, m_compiledData); + QVector<QQmlCompileError> errors = validator.validate(); + if (!errors.isEmpty()) { + setError(errors); + } + } + + m_compiledData->finalize(engine); + } + + if (!isError()) { QQmlType *type = QQmlMetaType::qmlType(finalUrl(), true); if (m_compiledData && m_compiledData->data->flags & QV4::CompiledData::Unit::IsSingleton) { if (!type) { diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 9fd7fb9f51..2030dbf427 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -146,6 +146,7 @@ protected: void setError(const QQmlError &); void setError(const QList<QQmlError> &errors); void setError(const QQmlCompileError &error); + void setError(const QVector<QQmlCompileError> &errors); void setError(const QString &description); void addDependency(QQmlDataBlob *); diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc index d7d2fea281..a1b4650507 100644 --- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc @@ -31,14 +31,46 @@ \section1 Scene Graph Adaptations in Qt Quick -Originally Qt Quick only had one available renderer for parsing the -scene graph and rendering the results to a render target. This renderer -is now the default OpenGL Renderer which supports rendering either using -the OpenGL ES 2.0 or OpenGL 2.0 APIs. The Qt Quick APIs are designed -with the assumption that these two APIs are always available. It is -however possible now to use other graphics API's to render Qt Quick +Originally Qt Quick only had one available renderer for parsing the scene graph +and rendering the results to a render target. This renderer is now the default +OpenGL Renderer which supports rendering either using the OpenGL ES 2.0 or +OpenGL 2.0 (with framebuffer object extensions) APIs. The Qt Quick APIs have +originally been designed with the assumption that OpenGL is always available. +However, it is now possible to use other graphics API's to render Qt Quick scenes using the scene graph APIs. +\section1 Switching between the adaptation used by the application + +The default of the OpenGL, or - in Qt builds with disabled OpenGL support - the +software adaptation, can be overridden either by using an environment variable +or a C++ API. The former consists of setting the \c{QT_QUICK_BACKEND} or the +legacy \c{QMLSCENE_DEVICE} environment variable before launching applications. +The latter is done by calling QQuickWindow::setSceneGraphBackend() early in the +application's main() function. + +The supported backends are the following + +\list + +\li OpenGL - Requested by the string \c{""} or the enum value QSGRendererInterface::OpenGL. + +\li Software - Requested by the string \c{"software"} or the enum value QSGRendererInterface::Software. + +\li Direct3D 12 - Requested by the string \c{"d3d12"} or the enum value QSGRendererInterface::Direct3D12. + +\endlist + +When in doubt which backend is in use, enable basic scenegraph information +logging via the \c{QSG_INFO} environment variable or the +\c{qt.scenegraph.general} logging category. This will result in printing some +information during application startup onto the debug output. + +\note Adaptations other than OpenGL will typically come with a set of +limitations since they are unlikely to provide a feature set 100% compatible +with OpenGL. However, they may provide their own specific advantages in certain +areas. Refer to the sections below for more information on the various +adaptations. + \section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation The default adaptation capable of providing the full Qt Quick 2 feature diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp index eb0e26462a..26efba5b13 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp @@ -149,7 +149,7 @@ void QSGAbstractSoftwareRenderer::buildRenderList() QSGSoftwareRenderListBuilder(this).visitChildren(rootNode()); } -void QSGAbstractSoftwareRenderer::optimizeRenderList() +QRegion QSGAbstractSoftwareRenderer::optimizeRenderList() { // Iterate through the renderlist from front to back // Objective is to update the dirty status and rects. @@ -212,9 +212,13 @@ void QSGAbstractSoftwareRenderer::optimizeRenderList() m_dirtyRegion += node->dirtyRegion(); } + QRegion updateRegion = m_dirtyRegion; + // Empty dirtyRegion m_dirtyRegion = QRegion(); m_obscuredRegion = QRegion(); + + return updateRegion; } void QSGAbstractSoftwareRenderer::setBackgroundColor(const QColor &color) diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h index a2e953f40d..73410b09f5 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h @@ -78,7 +78,7 @@ public: protected: QRegion renderNodes(QPainter *painter); void buildRenderList(); - void optimizeRenderList(); + QRegion optimizeRenderList(); void setBackgroundColor(const QColor &color); void setBackgroundSize(const QSize &size); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp index ea00de7a66..7bf06f8081 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp @@ -45,6 +45,7 @@ #include "qsgsoftwarerenderablenode_p.h" #include <QtGui/QPaintDevice> +#include <QtGui/QBackingStore> #include <QElapsedTimer> Q_LOGGING_CATEGORY(lcRenderer, "qt.scenegraph.softwarecontext.renderer") @@ -53,6 +54,8 @@ QT_BEGIN_NAMESPACE QSGSoftwareRenderer::QSGSoftwareRenderer(QSGRenderContext *context) : QSGAbstractSoftwareRenderer(context) + , m_paintDevice(nullptr) + , m_backingStore(nullptr) { } @@ -63,6 +66,13 @@ QSGSoftwareRenderer::~QSGSoftwareRenderer() void QSGSoftwareRenderer::setCurrentPaintDevice(QPaintDevice *device) { m_paintDevice = device; + m_backingStore = nullptr; +} + +void QSGSoftwareRenderer::setBackingStore(QBackingStore *backingStore) +{ + m_backingStore = backingStore; + m_paintDevice = nullptr; } QRegion QSGSoftwareRenderer::flushRegion() const @@ -82,18 +92,19 @@ void QSGSoftwareRenderer::renderScene(uint) void QSGSoftwareRenderer::render() { - if (!m_paintDevice) + if (!m_paintDevice && !m_backingStore) return; + // If there is a backingstore, set the current paint device + if (m_backingStore) + m_paintDevice = m_backingStore->paintDevice(); + QElapsedTimer renderTimer; setBackgroundColor(clearColor()); setBackgroundSize(QSize(m_paintDevice->width() / m_paintDevice->devicePixelRatio(), m_paintDevice->height() / m_paintDevice->devicePixelRatio())); - QPainter painter(m_paintDevice); - painter.setRenderHint(QPainter::Antialiasing); - // Build Renderlist // The renderlist is created by visiting each node in the tree and when a // renderable node is reach, we find the coorosponding RenderableNode object @@ -113,13 +124,23 @@ void QSGSoftwareRenderer::render() // side effect of this is that additional nodes may need to be marked dirty to // force a repaint. It is also important that any item that needs to be // repainted only paints what is needed, via the use of clip regions. - optimizeRenderList(); + const QRegion updateRegion = optimizeRenderList(); qint64 optimizeRenderListTime = renderTimer.restart(); + // If Rendering to a backingstore, prepare it to be updated + if (m_backingStore != nullptr) + m_backingStore->beginPaint(updateRegion); + + QPainter painter(m_paintDevice); + painter.setRenderHint(QPainter::Antialiasing); + // Render the contents Renderlist m_flushRegion = renderNodes(&painter); qint64 renderTime = renderTimer.elapsed(); + if (m_backingStore != nullptr) + m_backingStore->endPaint(); + qCDebug(lcRenderer) << "render" << m_flushRegion << buildRenderListTime << optimizeRenderListTime << renderTime; } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h index e2b8bcddca..a201e4887e 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE class QPaintDevice; +class QBackingStore; class Q_QUICK_PRIVATE_EXPORT QSGSoftwareRenderer : public QSGAbstractSoftwareRenderer { @@ -64,6 +65,7 @@ public: virtual ~QSGSoftwareRenderer(); void setCurrentPaintDevice(QPaintDevice *device); + void setBackingStore(QBackingStore *backingStore); QRegion flushRegion() const; protected: @@ -72,6 +74,7 @@ protected: private: QPaintDevice* m_paintDevice; + QBackingStore* m_backingStore; QRegion m_flushRegion; }; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp index 5292e1371f..0b111c7b19 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp @@ -156,11 +156,9 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window) //Tell the renderer about the windows backing store auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer); if (softwareRenderer) - softwareRenderer->setCurrentPaintDevice(m_backingStores[window]->paintDevice()); + softwareRenderer->setBackingStore(m_backingStores[window]); - m_backingStores[window]->beginPaint(QRect(0, 0, window->width(), window->height())); cd->renderSceneGraph(window->size()); - m_backingStores[window]->endPaint(); if (profileFrames) renderTime = renderTimer.nsecsElapsed(); |