diff options
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 19 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qmlcontext.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper_p.h | 3 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 4 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper.cpp | 47 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper_p.h | 2 | ||||
-rw-r--r-- | src/qml/qmldirparser/qqmldirparser_p.h | 24 | ||||
-rw-r--r-- | src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc | 588 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgbasicinternalimagenode.cpp | 4 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgthreadedrenderloop.cpp | 10 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgthreadedrenderloop_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qml/ecmascripttests/TestExpectations | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml | 14 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 50 |
18 files changed, 449 insertions, 340 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index e0d259bd0c..61e37ffd25 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1061,6 +1061,7 @@ bool Codegen::visit(Expression *ast) TailCallBlocker blockTailCalls(this); statement(ast->left); blockTailCalls.unblock(); + clearExprResultName(); // The name only holds for the left part accept(ast->right); return false; } @@ -2520,7 +2521,7 @@ bool Codegen::visit(ObjectPattern *ast) { RegisterScope innerScope(this); - Reference value = expression(p->initializer); + Reference value = expression(p->initializer, name); if (hasError) return false; value.loadInAccumulator(); @@ -2962,7 +2963,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, // already defined return leaveContext(); - _context->name = name; + _context->name = name.isEmpty() ? currentExpr().result().name : name; _module->functions.append(_context); _context->functionIndex = _module->functions.count() - 1; diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index ad86483132..958dd16816 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -196,8 +196,9 @@ public: codegen = cg; } - Reference() : + Reference(const QString &name = QString()) : constant(0), + name(name), isArgOrEval(false), isReadonly(false), isReferenceToConst(false), @@ -414,6 +415,11 @@ protected: bool _trueBlockFollowsCondition = false; public: + explicit Result(const QString &name) + : _result(name) + , _requested(ex) + {} + explicit Result(const Reference &lrvalue) : _result(lrvalue) , _requested(ex) @@ -472,6 +478,10 @@ protected: void setResult(Reference &&result) { _result = std::move(result); } + + void clearResultName() { + _result.name.clear(); + } }; void enterContext(AST::Node *node); @@ -519,12 +529,12 @@ protected: const BytecodeGenerator::Label *iffalse, bool trueBlockFollowsCondition); - inline Reference expression(AST::ExpressionNode *ast) + inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString()) { if (!ast || hasError) return Reference(); - pushExpr(); + pushExpr(name); ast->accept(this); return popResult(); } @@ -712,6 +722,7 @@ protected: inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); } inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); } inline Reference exprResult() const { return m_expressions.back().result(); } + inline void clearExprResultName() { m_expressions.back().clearResultName(); } inline bool exprAccept(Format f) { return m_expressions.back().accept(f); } @@ -719,7 +730,7 @@ protected: inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(expr)); } inline void pushExpr(const Result &expr) { m_expressions.push_back(expr); } - inline void pushExpr() { m_expressions.emplace_back(); } + inline void pushExpr(const QString &name = QString()) { m_expressions.emplace_back(name); } inline Result popExpr() { diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 03dc5f6d3c..4fd5e133f7 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -120,7 +120,7 @@ struct Lookup { } indexedLookup; struct { Heap::InternalClass *ic; - Heap::QObjectWrapper *staticQObject; + Heap::InternalClass *qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper QQmlPropertyCache *propertyCache; QQmlPropertyData *propertyData; } qobjectLookup; diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 0c5226d46c..6aa0130188 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -293,7 +293,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject))); const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = propertyData; @@ -326,7 +325,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = propertyData; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 6fed538fa8..63b6435112 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -870,7 +870,6 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E } lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = property; diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 2558ede401..5543c4d5a6 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -233,8 +233,7 @@ inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionE if (!o || o->internalClass != lookup->qobjectLookup.ic) return revertLookup(); - const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject : - static_cast<const Heap::QObjectWrapper *>(o); + const Heap::QObjectWrapper *This = static_cast<const Heap::QObjectWrapper *>(o); QObject *qobj = This->object(); if (QQmlData::wasDeleted(qobj)) return QV4::Encode::undefined(); diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 0c947b541b..71b0b11c97 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -1773,10 +1773,6 @@ PropertyDefinition: PropertyName T_COLON AssignmentExpression_In; /. case $rule_number: { AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Expression); - if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) { - if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName)) - f->name = driver->newStringRef(sym(1).PropertyName->asString()); - } if (auto *c = asAnonymousClassDefinition(sym(3).Expression)) { if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName)) c->name = driver->newStringRef(sym(1).PropertyName->asString()); diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 42cf723284..6bd66464b5 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -606,9 +606,12 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) { - QObject *mutableObj = const_cast<QObject *>(obj); - return qmlAttachedPropertiesObject( - mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create); + // We don't need a concrete object to resolve the function. As T is a C++ type, it and all its + // super types should be registered as CppType (or not at all). We only need the object and its + // QML engine to resolve composite types. Therefore, the function is actually a static property + // of the C++ type system and we can cache it here for improved performance on further lookups. + static const auto func = qmlAttachedPropertiesFunction(nullptr, &T::staticMetaObject); + return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create); } Q_QML_EXPORT void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor); diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 24c5aecc00..c5fa4a04ec 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -459,16 +459,16 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, if (!includeEnums || !name->startsWithUpper()) { QQmlData *ddata = QQmlData::get(qobjectSingleton, false); if (ddata && ddata->propertyCache) { - ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); if (property) { - lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject()); + ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); + lookup->qobjectLookup.qmlTypeIc = This->internalClass(); + lookup->qobjectLookup.ic = val->objectValue()->internalClass(); lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = property; - lookup->getter = QV4::QObjectWrapper::lookupGetter; - return lookup->getter(lookup, engine, *This); + lookup->getter = QQmlTypeWrapper::lookupSingletonProperty; + return lookup->getter(lookup, engine, *object); } // Fall through to base implementation } @@ -488,6 +488,43 @@ bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine return Object::virtualResolveLookupSetter(object, engine, lookup, value); } +ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + const auto revertLookup = [l, engine, &object]() { + l->qobjectLookup.propertyCache->release(); + l->qobjectLookup.propertyCache = nullptr; + l->getter = Lookup::getterGeneric; + return Lookup::getterGeneric(l, engine, object); + }; + + // we can safely cast to a QV4::Object here. If object is something else, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc) + return revertLookup(); + + Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o); + + QQmlType type = This->type(); + if (!type.isValid()) + return revertLookup(); + + if (!type.isSingleton()) + return revertLookup(); + + QQmlEngine *e = engine->qmlEngine(); + QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); + siinfo->init(e); + + QObject *qobjectSingleton = siinfo->qobjectApi(e); + if (!qobjectSingleton) + return revertLookup(); + + Scope scope(engine); + ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton)); + return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); +} + void Heap::QQmlScopedEnumWrapper::destroy() { QQmlType::derefHandle(typePrivate); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 44e82dec2b..5f3cb2523f 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -114,6 +114,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); + static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base); + protected: static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h index cff9cb11a4..f7a91c8b81 100644 --- a/src/qml/qmldirparser/qqmldirparser_p.h +++ b/src/qml/qmldirparser/qqmldirparser_p.h @@ -76,12 +76,24 @@ public: QString typeNamespace() const; void setTypeNamespace(const QString &s); + static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName) + { + if (fileName.startsWith(QLatin1Char('/')) || fileName.contains(QLatin1Char(':'))) { + qWarning() << item << typeName + << "is specified with non-relative URL" << fileName << "in a qmldir file." + << "URLs in qmldir files should be relative to the qmldir file's directory."; + } + } + struct Plugin { Plugin() {} Plugin(const QString &name, const QString &path) - : name(name), path(path) {} + : name(name), path(path) + { + checkNonRelative("Plugin", name, path); + } QString name; QString path; @@ -93,7 +105,10 @@ public: Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion) : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion), - internal(false), singleton(false) {} + internal(false), singleton(false) + { + checkNonRelative("Component", typeName, fileName); + } QString typeName; QString fileName; @@ -108,7 +123,10 @@ public: Script() {} Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion) - : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {} + : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) + { + checkNonRelative("Script", nameSpace, fileName); + } QString nameSpace; QString fileName; diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc index b0e45fadae..8edc5cb0b6 100644 --- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc @@ -31,72 +31,68 @@ \section1 Scene Graph Adaptations in Qt Quick -Originally Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) for parsing -the scene graph and rendering the results to a render target. From Qt 5.8 onwards -Qt Quick also supports rendering in software and with Direct3D 12. +Originally, Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) to parse the scene graph +and render the results to a render target. From Qt 5.8 onwards, Qt Quick also supports rendering in +software and with Direct3D 12. -\section1 Switching Between the Adaptation Used by the Application +\target Switching Between the Adaptation Used by the Application +\section1 Switch Between Adaptations in Your Application -The default rendering backend is still OpenGL, or - in Qt builds with disabled OpenGL support - -the software renderer. This 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 +The default rendering backend is still OpenGL, but in Qt builds with OpenGL support disabled, the +default is the software renderer. You can override this in one of two ways: \list + \li Use an environment variable - Set the \c{QT_QUICK_BACKEND} or the legacy + \c{QMLSCENE_DEVICE} environment variable before launching applications. + \li Use a C++ API - Call QQuickWindow::setSceneGraphBackend() early on in the application's + main() function. +\endlist -\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. - -\li OpenVG - Requested by the string \c{"openvg"} or the enum value QSGRendererInterface::OpenVG. +The following backends are supported: +\list + \li OpenGL - Request with the \c{""} string or the QSGRendererInterface::OpenGL enum value. + \li Software - Request with the \c{"software"} string or the QSGRendererInterface::Software + enum value. + \li Direct3D 12 - Request with the \c{"d3d12"} string or the QSGRendererInterface::Direct3D12 + enum value. + \li OpenVG - Request with the \c{"openvg"} string or the QSGRendererInterface::OpenVG enum + value. \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. +To find out which backend is in use, you can enable basic scene graph information logging via the +\c{QSG_INFO} environment variable or the \c{qt.scenegraph.general} logging category. This results +in some information being printed onto the debug output, during application startup. -\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. +\note Typically, adaptations other than OpenGL come with a set of limitations as they are unlikely + to provide a feature set that's 100% compatible with OpenGL. However, these adaptations may + provide their own specific advantages in certain areas. For more information on the various + adaptations, refer to the sections below. \section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation -The default adaptation capable of providing the full Qt Quick 2 feature -set is the OpenGL adaptation. All of the details of the OpenGL -adaptation can are available here: -\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation} +The OpenGL adaptation is the default adaptation, which is capable of providing the full Qt Quick 2 +feature set. For more details, see +\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}. \section1 Software Adaptation -The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that -uses the raster paint engine to render the contents of the scene graph. The -details for this adaptation are available here: -\l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation} +The Software adaptation is an alternative renderer for \l{Qt Quick} 2 that uses the raster paint +engine to render the contents of the scene graph. For more details, see +\l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation}. \section1 Direct3D 12 (experimental) -The Direct3D 12 adaptation is an alternative renderer for \l {Qt Quick} 2 when -running on Windows 10, both for Win32 and UWP applications. The details for -this adaptation are available here: -\l{qtquick-visualcanvas-adaptations-d3d12.html}{Direct3D 12 Adaptation} +The Direct3D 12 adaptation is an alternative renderer for \l{Qt Quick} 2 when running on Windows +10, both for Win32 and UWP applications. For more details, see +\l{qtquick-visualcanvas-adaptations-d3d12.html}{Direct3D 12 Adaptation}. \section1 OpenVG -The OpenVG adaptation is an alternative renderer for \l {Qt Quick} 2 that will -renderer the contents of the scene graph using OpenVG commands to provide -hardware-acclerated 2D vector and raster graphics. The details for this -adaptation are available here: -\l{qtquick-visualcanvas-adaptations-openvg.html}{OpenVG Adaptation} +The OpenVG adaptation is an alternative renderer for \l{Qt Quick} 2 that renders the contents of +the scene graph using OpenVG commands to provide hardware-accelerated 2D vector and raster +graphics. For more details, see +\l{qtquick-visualcanvas-adaptations-openvg.html}{OpenVG Adaptation}. */ @@ -104,47 +100,44 @@ adaptation are available here: \title Qt Quick Software Adaptation \page qtquick-visualcanvas-adaptations-software.html -The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that -uses the Raster paint engine to render the contents of the scene graph instead -of OpenGL. As a result of not using OpenGL to render the scene graph, some -features and optimizations are no longer available. Most Qt Quick 2 -applications will run without modification though any attempts to use -unsupported features will be ignored. By using the Software adaptation it is -possible to run Qt Quick 2 applications on hardware and platforms that do not -have OpenGL support. - -The Software adaptation was previously known as the Qt Quick 2D Renderer. -However, unlike the 2D Renderer, the new, integrated version supports partial -updates. This means that the full update of the window or screen contents is -now avoided, and only the changed areas get flushed. This can significantly -improve performance for many applications. +The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that uses the Raster paint +engine to render the contents of the scene graph, instead of OpenGL. Consequently, some features +and optimizations are not available. Most Qt Quick 2 applications can run without any modification, +but any attempts to use unsupported features are ignored. By using the Software adaptation, it is +possible to run Qt Quick 2 applications on hardware and platforms that do not have OpenGL support. + +The Software adaptation was previously known as the Qt Quick 2D Renderer. However, unlike the 2D +Renderer, this new, integrated version supports partial updates. This means that a full update +of the window or screen contents is now avoided; only the changed areas are flushed. Partial +updates can significantly improve performance for many applications. \section2 Shader Effects -ShaderEffect components in QtQuick 2 can not be rendered by the Software adptation. + +ShaderEffect components in QtQuick 2 cannot be rendered by the Software adaptation. \section2 Qt Graphical Effects Module -\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use -graphical effects from this module, then you should not hide the source -item so that the original item can still be rendered. + +\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use graphical effects +from this module, then you should not hide the source item so that the original item can still be +rendered. \section2 Particle Effects -It is not possible to render particle effects with the Software adaptation. Whenever -possible, remove particles completely from the scene. Otherwise they will still -require some processing, even though they are not visible. + +It is not possible to render particle effects with the Software adaptation. Whenever possible, +remove particles completely from the scene. Otherwise, they will still require some processing, +even though they are not visible. \section2 Rendering Text -The text rendering with the Software adaptation is based on software -rasterization and does not respond as well to transformations such as scaling -as when using OpenGL. The quality is similar to choosing \l [QML] {Text::renderType} -{Text.NativeRendering} with \l [QML] {Text} items. -\section2 Qt Multimedia VideoOutput -The VideoOutput item of the Qt Multimedia module is not supported with the software -adaptation. This is because VideoOutput uses the QVideoRendererControl item which -requires custom QSGGeometryNode behavior that is only present in the default OpenGL -adaptation. +The text rendering with the Software adaptation is based on software rasterization and does not +respond as well to transformations such as scaling, compared to when using OpenGL. The quality is +similar to choosing \l [QML] {Text::renderType}{Text.NativeRendering} with \l [QML] {Text} items. +\section2 Qt Multimedia VideoOutput +The Qt Multimedia module's VideoOutput item is not supported with the Software adaptation. This +is because VideoOutput uses the QVideoRendererControl item which requires custom QSGGeometryNode +behavior, which is only present in the default OpenGL adaptation. */ @@ -152,251 +145,228 @@ adaptation. \title Qt Quick Direct3D 12 Adaptation \page qtquick-visualcanvas-adaptations-d3d12.html -The Direct3D 12 adaptation for Windows 10 (both Win32 (\c windows platform -plugin) and UWP (\c winrt platform plugin)) is shipped as a dynamically loaded -plugin. It will not be functional on earlier Windows versions. The building of -the plugin is enabled automatically whenever the necessary D3D and DXGI -develpoment files are present. In practice this currently means Visual Studio -2015 and newer. +The Direct3D 12 adaptation for Windows 10, both in Win32 (\c windows platform plugin) and in UWP +(\c winrt platform plugin), is shipped as a dynamically loaded plugin. This adaptation doesn't work +on earlier Windows versions. Building this plugin is enabled automatically, whenever the necessary +D3D and DXGI develpoment files are present. In practice, this currently means Visual Studio 2015 +and newer. -The adaptation is available both in normal, OpenGL-enabled Qt builds and also -when Qt was configured with \c{-no-opengl}. However, it is never the default, -meaning the user or the application has to explicitly request it by setting the -\c{QT_QUICK_BACKEND} environment variable to \c{d3d12} or by calling -QQuickWindow::setSceneGraphBackend(). +The adaptation is available both in normal, OpenGL-enabled Qt builds, and also when Qt is +configured with \c{-no-opengl}. However, it's never the default, meaning that the user or the +application has to explicitly request it by setting the \c{QT_QUICK_BACKEND} environment variable +to \c{d3d12} or by calling QQuickWindow::setSceneGraphBackend(). \section2 Motivation -This experimental adaptation is the first Qt Quick backend focusing on a -modern, lower-level graphics API in combination with a windowing system -interface different from the traditional approaches used in combination with -OpenGL. - -It also allows better integration with Windows, Direct3D being the primary -vendor-supported solution. This means that there are fewer problems anticipated -with drivers, operations like window resizes, and special events like graphics -device loss caused by device resets or graphics driver updates. - -Performance-wise the general expectation is a somewhat lower CPU usage compared -to OpenGL due to lower driver overhead, and a higher GPU utilization with less -wasted idle time. The backend does not heavily utilize threads yet, which means -there are opportunities for further improvements in the future, for example to -further optimize image loading. - -The D3D12 backend also introduces support for pre-compiled shaders. All the -backend's own shaders (used by the built-in materials on which the Rectangle, -Image, Text, etc. QML types are built) are compiled to D3D shader bytecode when -compiling Qt. Applications using ShaderEffect items can chose to ship bytecode -either in regular files or via the Qt resource system, or use HLSL source -strings. Unlike OpenGL, the compilation for the latter is properly threaded, -meaning shader compilation will not block the application and its user +This experimental adaptation is the first Qt Quick backend that focuses on a modern, lower-level +graphics API in combination with a windowing system interface that's different from the traditional +approaches used in combination with OpenGL. + +This adaptation also allows better integration with Windows, as Direct3D is the primary +vendor-supported solution. Consequently, there are fewer problems anticipated with drivers, +operations like window resizes, and special events like graphics device loss caused by device +resets or graphics driver updates. + +Performance-wise, the general expectation is a somewhat lower CPU usage compared to OpenGL, due to +lower driver overhead, and a higher GPU utilization with less idle time wastage. The backend +doesn't heavily utilize threads yet, which means there are opportunities for further improvements +in the future, for example to further optimize image loading. + +The D3D12 backend also introduces support for pre-compiled shaders. All the backend's own shaders +(used by the built-in materials on which the Rectangle, Image, Text, and other QML types are built +with) are compiled to D3D shader bytecode when you compile Qt. Applications using ShaderEffect +items can choose to ship bytecode either in regular files, via the Qt resource system, or use +High Level Shading Language for DirectX (HLSL) source strings. Unlike OpenGL, the compilation for +HLSL is properly threaded, meaning shader compilation won't block the application and its user interface. \section2 Graphics Adapters -The plugin does not necessarily require hardware acceleration. Using WARP, the -Direct3D software rasterizer, is also an option. By default the first adapter -providing hardware acceleration is chosen. To override this, in order to use -another graphics adapter or to force the usage of the software rasterizer, set -the environment variable \c{QT_D3D_ADAPTER_INDEX} to the index of the adapter. -The discovered adapters are printed at startup when \c{QSG_INFO} or the logging -category \c{qt.scenegraph.general} is enabled. +The plugin does not necessarily require hardware acceleration. You can also use WARP, the Direct3D +software rasterizer. By default, the first adapter providing hardware acceleration is chosen. To +override this and use another graphics adapter or to force the use of the software rasterizer, set +the \c{QT_D3D_ADAPTER_INDEX} environment variable to the index of the adapter. The adapters +discovered are printed at startup when \c{QSG_INFO} or the \c{qt.scenegraph.general} logging +category is enabled. \section2 Troubleshooting -When encountering issues, always set the \c{QSG_INFO} and \c{QT_D3D_DEBUG} -environment variables to 1 in order to get debug and warning messages printed -on the debug output. The latter enables the Direct3D debug layer. Note that the -debug layer should not be enabled in production use since it can significantly -impact performance (CPU load) due to increased API overhead. +If you encounter issues, always set the \c{QSG_INFO} and \c{QT_D3D_DEBUG} environment variables +to \c 1, to get debug and warning messages printed on the debug output. \c{QT_D3D_DEBUG} enables +the Direct3D debug layer. + +\note The debug layer shouldn't be enabled in production use, since it can significantly impact +performance (CPU load) due to increased API overhead. \section2 Render Loops -By default the D3D12 adaptation uses a single-threaded render loop similar to -OpenGL's \c windows render loop. There is also a threaded variant available, that -can be requested by setting the \c{QSG_RENDER_LOOP} environment variable to \c -threaded. However, due to conceptual limitations in DXGI, the windowing system -interface, the threaded loop is prone to deadlocks when multiple QQuickWindow -or QQuickView instances are shown. Therefore the default is the single-threaded -loop for the time being. This means that with the D3D12 backend applications -are expected to move their work from the main (GUI) thread out to worker -threads, instead of expecting Qt to keep the GUI thread responsive and suitable -for heavy, blocking operations. - -See the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph page} for more -information on render loops and -\l{https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx#multithreading_and_dxgi}{the -MSDN page for DXGI} regarding the issues with multithreading. +By default, the D3D12 adaptation uses a single-threaded render loop similar to OpenGL's \c windows +render loop. A threaded variant is also available, that you can request by setting the +\c{QSG_RENDER_LOOP} environment variable to \c threaded. However, due to conceptual limitations in +DXGI, the windowing system interface, the threaded loop is prone to deadlocks when multiple +QQuickWindow or QQuickView instances are shown. Consequently, for the time being, the default is +the single-threaded loop. This means that with the D3D12 backend, applications are expected to move +their work from the main (GUI) thread out to worker threads, instead of expecting Qt to keep the +GUI thread responsive and suitable for heavy, blocking operations. + +For more information see \l{qtquick-visualcanvas-scenegraph.html}{Qt Quick Scene Graph} for +details on render loops and +\l{https://docs.microsoft.com/en-us/windows/desktop/direct3darticles/dxgi-best-practices#multithreading-and-dxgi}{Multithreading and DXGI} +regarding the issues with multithreading. \section2 Renderer -The scenegraph renderer in the D3D12 adaptation does not currently perform any -batching. This is less of an issue, unlike OpenGL, because state changes are -not presenting any problems in the first place. The simpler renderer logic can -also lead to lower CPU overhead in some cases. The trade-offs between the -various approaches are currently under research. +The scene graph renderer in the D3D12 adaptation currently doesn't perform any batching. This is +less of an issue, unlike OpenGL, because state changes don't present any problems in the first +place. The simpler renderer logic can also lead to lower CPU overhead in some cases. The trade-offs +between the various approaches are currently under research. \section2 Shader Effects -The ShaderEffect QML type is fully functional with the D3D12 adaptation as well. -However, the interpretation of the fragmentShader and vertexShader properties is -different than with OpenGL. +The ShaderEffect QML type is fully functional with the D3D12 adaptation as well. However, the +interpretation of the fragmentShader and vertexShader properties is different than with OpenGL. -With D3D12, these strings can either be an URL for a local file or a file in -the resource system, or a HLSL source string. The former indicates that the -file in question contains pre-compiled D3D shader bytecode generated by the -\c fxc tool, or, alternatively, HLSL source code. The type of the file is detected -automatically. This means that the D3D12 backend supports all options from -GraphicsInfo.shaderCompilationType and GraphicsInfo.shaderSourceType. +With D3D12, these strings can either be a URL for a local file, a file in the resource system, +or an HLSL source string. Using a URL for a local file or a file in the resource system +indicates that the file in question contains pre-compiled D3D shader bytecode generated by the +\c fxc tool, or, alternatively, HLSL source code. The type of file is detected automatically. +This means that the D3D12 backend supports all options from GraphicsInfo.shaderCompilationType +and GraphicsInfo.shaderSourceType. -Unlike OpenGL, there is a QFileSelector with the extra selector \c hlsl used -whenever opening a file. This allows easy creation of ShaderEffect items that -are functional across both backends, for example by placing the GLSL source -code into \c{shaders/effect.frag}, the HLSL source code or - preferably - -pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing -\c{fragmentShader: "qrc:shaders/effect.frag"} in QML. - -See the ShaderEffect documentation for more details. +Unlike OpenGL, whenever you open a file, there is a QFileSelector with the extra \c hlsl selector +used. This provides easy creation of ShaderEffect items that are functional across both backends, +for example by placing the GLSL source code into \c{shaders/effect.frag}, the HLSL source code or +- preferably - pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing +\c{fragmentShader: "qrc:shaders/effect.frag"} in QML. For more details, see ShaderEffect. \section2 Multisample Render Targets -The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow -or QQuickView (or set via QSurfaceFormat::setDefaultFormat()), with two -exceptions: QSurfaceFormat::samples() and QSurfaceFormat::alphaBufferSize() are -still taken into account. When the samples value is greater than 1, multisample -offscreen render targets will be created with the specified sample count and a -quality of the maximum supported quality level. The backend automatically -performs resolving into the non-multisample swapchain buffers after each frame. +The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow or QQuickView, or +set via QSurfaceFormat::setDefaultFormat(), with two exceptions: QSurfaceFormat::samples() and +QSurfaceFormat::alphaBufferSize() are still taken into account. When the sample value is greater +than 1, multisample offscreen render targets will be created with the specified sample count at +the maximum supported quality level. The backend automatically performs resolving into the +non-multisample swapchain buffers after each frame. \section2 Semi-transparent Windows -When the alpha channel is enabled either via -QQuickWindow::setDefaultAlphaBuffer() or by setting alphaBufferSize to a -non-zero value in the window's QSurfaceFormat or in the global format managed -by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a -swapchain for composition and go through DirectComposition since the flip model -swapchain (which is mandatory) would not support transparency otherwise. +When the alpha channel is enabled either via QQuickWindow::setDefaultAlphaBuffer() or by setting +alphaBufferSize to a non-zero value in the window's QSurfaceFormat or in the global format managed +by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a swapchain for composition +and go through DirectComposition. This is necessary, because the mandatory flip model swapchain +wouldn't support transparency otherwise. -It is therefore important not to unneccessarily request an alpha channel. When -the alphaBufferSize is 0 or the default -1, all these extra steps can be -avoided and the traditional window-based swapchain is sufficient. +Therefore, it's important not to unneccessarily request an alpha channel. When the alphaBufferSize +is 0 or the default -1, all these extra steps can be avoided and the traditional window-based +swapchain is sufficient. -This is not relevant on WinRT because there the backend always uses a -composition swapchain which is associated with the ISwapChainPanel that backs -QWindow on that platform. +On WinRT, this isn't relevant because the backend there always uses a composition swapchain which +is associated with the ISwapChainPanel that backs QWindow on that platform. \section2 Mipmaps -Mipmap generation is supported and handled transparently to the applications -via a built-in compute shader, but is experimental and only supports -power-of-two images at the moment. Textures of other size will work too, but -this involves a QImage-based scaling on the CPU first. Therefore avoid enabling -mipmapping for NPOT images whenever possible. +Mipmap generation is supported and handled transparently to the applications via a built-in compute +shader. However, at the moment, this feature is experimental and only supports power-of-two images. +Textures of other size will work too, but this involves a QImage-based scaling on the CPU first. +Therefore, avoid enabling mipmapping for Non-Power-Of-Two (NPOT) images whenever possible. \section2 Image Formats -When creating textures via the C++ scenegraph APIs like -QQuickWindow::createTextureFromImage(), 32-bit formats will not involve any -conversion, they will map directly to the corresponding \c{R8G8B8A8_UNORM} or -\c{B8G8R8A8_UNORM} format. Everything else will trigger a QImage-based format -conversion on the CPU first. +When creating textures via C++ scene graph APIs like QQuickWindow::createTextureFromImage(), 32-bit +formats won't involve any conversion, they'll map directly to the corresponding \c{R8G8B8A8_UNORM} +or \c{B8G8R8A8_UNORM} format. Everything else will trigger a QImage-based format conversion on the +CPU first. \section2 Unsupported Features -Particles and some other OpenGL-dependent utilities, like -QQuickFramebufferObject, are not currently supported. +Particles and some other OpenGL-dependent utilities, like QQuickFramebufferObject, are currently +not supported. -Like with the \l{qtquick-visualcanvas-adaptations-software.html}{Software -adaptation}, text is always rendered using the native method. Distance -field-based text rendering is not currently implemented. +Like with \l{qtquick-visualcanvas-adaptations-software.html}{Software adaptation}, text is always +rendered using the native method. Distance field-based text rendering is currently not implemented. -The shader sources in the \l {Qt Graphical Effects} module have not been ported -to any format other than the OpenGL 2.0 compatible one, meaning the QML types -provided by that module are not currently functional with the D3D12 backend. +The shader sources in the \l {Qt Graphical Effects} module have not been ported to any format other +than the OpenGL 2.0 compatible one, meaning that the QML types provided by that module are currently +not functional with the D3D12 backend. -Texture atlases are not currently in use. +Texture atlases are currently not in use. -The renderer may lack support for certain minor features, for example drawing -points and lines with a width other than 1. +The renderer may lack support for certain minor features, such as drawing points and lines with a +width other than 1. -Custom Qt Quick items using custom scenegraph nodes can be problematic. -Materials are inherently tied to the graphics API. Therefore only items using -the utility rectangle and image nodes are functional across all adaptations. +Custom Qt Quick items using custom scene graph nodes can be problematic because materials are +inherently tied to the graphics API. Therefore, only items that use the utility rectangle and image +nodes are functional across all adaptations. -QQuickWidget and its underlying OpenGL-based compositing architecture is not -supported. If mixing with QWidget-based user interfaces is desired, use -QWidget::createWindowContainer() to embed the native window of the QQuickWindow -or QQuickView. +QQuickWidget and its underlying OpenGL-based compositing architecture is not supported. If you need +to mix with QWidget-based user interfaces, use QWidget::createWindowContainer() to embed the native +window of the QQuickWindow or QQuickView. -Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with -the D3D12 adaptation at the moment. +Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with the D3D12 adaptation +at the moment. \section2 Related APIs -To integrate custom Direct3D 12 rendering, use QSGRenderNode in combination -with QSGRendererInterface. This approach does not rely on OpenGL contexts or -API specifics like framebuffers, and allows exposing the graphics device and -command buffer from the adaptation. It is not necessarily suitable for easy -integration of all types of content, in particular true 3D, so it will likely -get complemented by an alternative to QQuickFramebufferObject in future -releases. +To integrate custom Direct3D 12 rendering, use QSGRenderNode in combination with +QSGRendererInterface. This approach doesn't rely on OpenGL contexts or API specifics like +framebuffers, and allows exposing the graphics device and command buffer from the adaptation. It's +not necessarily suitable for easy integration of all types of content, in particular true 3D, so +it'll likely get complemented by an alternative to QQuickFramebufferObject in future releases. -To perform runtime decisions based on the adaptation in use, use -QSGRendererInterface from C++ and GraphicsInfo from QML. They can also be used -to check the level of shader support (shading language, compilation approach). +To perform runtime decisions based on the adaptation, use QSGRendererInterface from C++ and +GraphicsInfo from QML. They can also be used to check the level of shader support: shading +language, compilation approach, and so on. -When creating custom items, use the new QSGRectangleNode and QSGImageNode -classes. These replace the now deprecated QSGSimpleRectNode and -QSGSimpleTextureNode. Unlike their predecessors, the new classes are -interfaces, and implementations are created via the factory functions -QQuickWindow::createRectangleNode() and QQuickWindow::createImageNode(). +When creating custom items, use the new QSGRectangleNode and QSGImageNode classes. These replace +the now deprecated QSGSimpleRectNode and QSGSimpleTextureNode. Unlike their predecessors, these new +classes are interfaces, and implementations are created via the QQuickWindow::createRectangleNode() +and QQuickWindow::createImageNode() factory functions. \section2 Advanced Configuration -The D3D12 adaptation can keep multiple frames in flight, similarly to modern -game engines. This is somewhat different from the traditional render - swap - -wait for vsync model and allows better GPU utilization at the expense of higher -resource usage. This means that the renderer will be a number of frames ahead -of what is displayed on the screen. +The D3D12 adaptation can keep multiple frames in flight, similar to modern game engines. This is +somewhat different from the traditional "render - swap - wait for vsync" model and allows for +better GPU utilization at the expense of higher resource use. This means that the renderer will +be a number of frames ahead of what is displayed on the screen. -For a discussion of flip model swap chains and the typical configuration -parameters, refer to -\l{https://software.intel.com/en-us/articles/sample-application-for-direct3d-12-flip-model-swap-chains}{this -article}. +For a discussion of flip model swap chains and the typical configuration parameters, refer to +\l{https://software.intel.com/en-us/articles/sample-application-for-direct3d-12-flip-model-swap-chains} +{Sample Application for Direct3D 12 Flip Model Swap Chains}. -Vertical synchronization is always enabled, meaning Present() is invoked with -an interval of 1. +Vertical synchronization is always enabled, meaning Present() is invoked with an interval of 1. The configuration can be changed by setting the following environment variables: -\list - -\li \c{QT_D3D_BUFFER_COUNT} - The number of swap chain buffers in range 2 - 4. -The default value is 3. - -\li \c{QT_D3D_FRAME_COUNT} - The number of frames prepared without blocking in -range 1 - 4. Note that Present will start blocking after queuing 3 frames -(regardless of \c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use. -Note that every additional frame increases GPU resource usage since geometry -and constant buffer data will have to be duplicated, and involves more -bookkeeping on the CPU side. The default value is 2. - -\li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY} - When set to a value between 1 -and 16, the frame latency is set to the specified value. This changes the limit -for Present() and will trigger a wait for an available swap chain buffer when -beginning each frame. Refer to the article above for a detailed discussion. -This is considered experimental for now and the default value is 0 (disabled). - -\li \c{QT_D3D_BLOCKING_PRESENT} - When set to a non-zero value, there will be -CPU-side wait for the GPU to finish its work after each call to Present. This -effectively kills all parallelism but makes the behavior resemble the -traditional swap-blocks-for-vsync model, and can therefore be useful in some -special cases. This is not the same as setting the frame count to 1 because -that still avoids blocking after Present, and may block only when starting to -prepare the next frame (or may not block at all depending on the time gap -between the frames). By default blocking present is disabled. - -\endlist +\table + \header + \li Environment variable + \li Description + \row + \li \c{QT_D3D_BUFFER_COUNT} + \li The number of swap chain buffers in range 2 - 4. The default value is 3. + \row + \li \c{QT_D3D_FRAME_COUNT} + \li The number of frames prepared without blocking in range 1 - 4. The default value is 2. + Present() starts blocking after queuing 3 frames (regardless of + \c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use. Every additional frame + increases GPU resource usage since geometry and constant buffer data needs to be + duplicated, and involves more bookkeeping on the CPU side. + \row + \li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY} + \li The frame latency in range 1 - 16. The default value is 0 (disabled). + Changes the limit for Present() and triggers a wait for an available swap chain buffer + when beginning each frame. For a detailed discussion, see the article linked above. + \note Currently, this behavior is experimental. + \row + \li \c{QT_D3D_BLOCKING_PRESENT} + \li The time the CPU should wait, a non-zero value, for the GPU to finish its work after + each call to Present(). The default value is 0 (disabled). This behavior effectively + kills all parallelism but makes the behavior resemble the traditional + swap-blocks-for-vsync model, which can be useful in some special cases. However, this + behavior is not the same as setting the frame count to 1 because that still avoids + blocking after Present(), and may only block when starting to prepare the next frame + (or may not block at all depending on the time gap between the frames). +\endtable */ @@ -404,68 +374,72 @@ between the frames). By default blocking present is disabled. \title Qt Quick OpenVG Adaptation \page qtquick-visualcanvas-adaptations-openvg.html -The OpenVG adaptation is an alternative renderer for \l {Qt Quick} 2 that will -renderer the contents of the scene graph using OpenVG commands to provide -hardware-acclerated 2D vector and raster graphics. Much like the Software -adaptation, some features and optimizations are no longer available. Most -Qt Quick 2 applications will run without modification though any attempts to -use unsupported features will be ignored. +The OpenVG adaptation is an alternative renderer for \l{Qt Quick} 2 that renders the contents of +the scene graph using OpenVG commands to provide hardware accelerated 2D vector and raster +graphics. Much like the \l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation}, +some features and optimizations are no longer available. Most Qt Quick 2 applications will run +without modification though any attempts to use unsupported features will be ignored. \section2 EGL Requirement -Unlike the defualt OpenGL Renderer, there is no built in support for acquiring -an OpenVG context. This means that the renderer has the responsbility of -requesting and managing the the current context. To do this EGL has to be used -directly in the OpenVG renderer. This means that the OpenVG renderer is only -usable with platform plugins that support creating QWindows with support for -QSurfaceFormat::OpenVG. From this window, the renderer can get an EGLSurface -which can be used with an EGLContext to render OpenVG content. + +Unlike the default OpenGL Renderer, there is no built-in support to acquire an OpenVG context. +This means that the renderer is responsible for requesting and managing the the current context. +To do this, you use EGL directly in the OpenVG renderer. Consequently, the OpenVG renderer can only +be used with platform plugins that support creating QWindows with support for +QSurfaceFormat::OpenVG. From this window, the renderer can get an EGLSurface which can then be used +with an EGLContext to render OpenVG content. \section2 Renderer -The OpenVG Renderer works by using the OpenVG API to send commands and data to -a Vector GPU which will render the scenegraph in an accelerated manner, offloading -graphics rendering from the CPU. Many operations like the rendering of rectangles -and fonts glyphs ideal for OpenVG because these can be represented as paths which -are stroked and filled. Rendering scenegraph items that would typically involve -textures are handled in the OpenVG renderer by using VGImage. In addition when -rendering to offscreen surfaces (like when using Layers), the scene subtree is -rendered to a VGImage which can be reused in the scene. + +The OpenVG Renderer uses the OpenVG API to send commands and data to a Vector GPU that renders the +scene graph in an accelerated manner, offloading graphics rendering from the CPU. Many operations +like the rendering of rectangles and font glyphs are ideal for OpenVG because they can be +represented as paths which are stroked and filled. Rendering scene graph items that would typically +involve textures are handled in the OpenVG renderer using VGImage. Additionally, when you render +to offscreen surfaces (like with Layers), the scene subtree is rendered to a VGImage which can be +reused in the scene. \section2 Render Loop -The OpenVG Renderer mirrors the behavior of the Basic render loop and will execute -all OpenVG commands in a single thread. -See the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph page} for more -information on render loops +The OpenVG Renderer mirrors the behavior of the Basic render loop and it runs all OpenVG commands +in a single thread. + +For more information on render loops, see +\l{qtquick-visualcanvas-scenegraph.html}{Qt Quick Scene Graph}. \section2 Shader Effects -ShaderEffect components in QtQuick 2 can not be rendered by the OpenVG adaptation. -While it is possible to user ShaderEffectSource and QML Item Layers (which are both -offscreen surfaces), it is not actually possible to apply shader effects to them -via the ShaderEffect item. This is because OpenVG lacks an API for applying per -vertex and per fragment shader operations. It may be possible however to take -advantage of Image Filter operations in the OpenVG API to get similar effects to -what is provided by ShaderEffects in custom items. To integrate custom OpenVG -rendering, use QSGRenderNode in combination with QSGRendererInterface. + +ShaderEffect components in QtQuick 2 can't be rendered by the OpenVG adaptation. While it's +possible to use ShaderEffectSource and QML Item Layers (which are both offscreen surfaces), it's +not possible to apply shader effects to them via the ShaderEffect item. This is because OpenVG +lacks an API for applying per vertex and per fragment shader operations. However, you may be able +to take advantage of Image Filter operations in the OpenVG API to get effects that are similar to +what ShaderEffects provides in custom items. To integrate custom OpenVG rendering, use +QSGRenderNode in combination with QSGRendererInterface. \section2 Qt Graphical Effects Module -\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use -graphical effects from this module, then you should not hide the source -item so that the original item can still be rendered. + +\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use graphical effects +from this module, then you shouldn't hide the source item so that the original item can still be +rendered. \section2 Particle Effects -It is not possible to render particle effects with the OpenVG adaptation. Whenever -possible, remove particles completely from the scene. Otherwise they will still -require some processing, even though they are not visible. + +It's not possible to render particle effects with the OpenVG adaptation. Whenever possible, remove +particles completely from the scene. Otherwise they'll still require some processing, even though +they are not visible. \section2 Rendering Text -The text rendering with the OpenVG adaptation is based on rendering the glpyh -paths, and does not use the distance fields technique used by the OpenGL backend. + +Text rendering with the OpenVG adaptation is based on rendering the glyph paths, and doesn't use +the distance fields technique, unlike with the OpenGL backend. \section2 Perspective Transforms -The OpenVG API does not allow paths to be transformed with non-affine transforms, -while it is possible with Qt Quick. This means that rendering components using -paths like Rectangles and Text, when applying perspective transforms the OpenVG -backend will first render to a VGImage before applying transformations. This uses -more memory at runtime and is a slower path so avoid doing this if necessary. + +The OpenVG API doesn't allow paths to be transformed with non-affine transforms, but it's +possible with Qt Quick. Consquently, when you render components using paths like Rectangles and +Text while applying perspective transforms, the OpenVG backend first renders to a VGImage before +applying transformations. This behavior uses more memory at runtime and takes more time; avoid it +if possible. */ diff --git a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp index c434563c90..d8efda1ecc 100644 --- a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp +++ b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp @@ -258,7 +258,7 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect, xs[1].tx = innerSourceRect.left(); xs += 2; } - if (innerTargetRect.width() != 0) { + if (innerTargetRect.width() != 0 && hTiles > 0) { xs[0].x = innerTargetRect.left(); xs[0].tx = innerSourceRect.x() + (subSourceRect.left() - floorLeft) * innerSourceRect.width(); ++xs; @@ -299,7 +299,7 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect, ys[1].ty = innerSourceRect.top(); ys += 2; } - if (innerTargetRect.height() != 0) { + if (innerTargetRect.height() != 0 && vTiles > 0) { ys[0].y = innerTargetRect.top(); ys[0].ty = innerSourceRect.y() + (subSourceRect.top() - floorTop) * innerSourceRect.height(); ++ys; diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index c18ba4226c..232ef77324 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -770,12 +770,15 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop() QSGThreadedRenderLoop::~QSGThreadedRenderLoop() { + qDeleteAll(pendingRenderContexts); delete sg; } QSGRenderContext *QSGThreadedRenderLoop::createRenderContext(QSGContext *sg) const { - return sg->createRenderContext(); + auto context = sg->createRenderContext(); + pendingRenderContexts.insert(context); + return context; } void QSGThreadedRenderLoop::maybePostPolishRequest(Window *w) @@ -935,7 +938,10 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) Window win; win.window = window; win.actualWindowFormat = window->format(); - win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context); + auto renderContext = QQuickWindowPrivate::get(window)->context; + // The thread assumes ownership, so we don't need to delete it later. + pendingRenderContexts.remove(renderContext); + win.thread = new QSGRenderThread(this, renderContext); win.updateDuringSync = false; win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt m_windows << win; diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h index 32bfcb7148..b8fae8e8da 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h +++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h @@ -124,6 +124,9 @@ private: QSGContext *sg; + // Set of contexts that have been created but are now owned by + // a rendering thread yet, as the window has never been exposed. + mutable QSet<QSGRenderContext*> pendingRenderContexts; QAnimationDriver *m_animation_driver; QList<Window> m_windows; diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index cf7bf3d8ba..a5246c8792 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -714,8 +714,6 @@ language/statements/generators/yield-identifier-non-strict.js sloppyFails language/statements/let/block-local-closure-set-before-initialization.js fails language/statements/let/function-local-closure-set-before-initialization.js fails language/statements/let/global-closure-set-before-initialization.js fails -language/statements/throw/S12.13_A2_T6.js strictFails -language/statements/try/S12.14_A18_T6.js strictFails language/statements/try/scope-catch-block-lex-open.js fails language/statements/variable/binding-resolution.js sloppyFails language/statements/with/unscopables-inc-dec.js sloppyFails diff --git a/tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml b/tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml new file mode 100644 index 0000000000..3166ab647d --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml @@ -0,0 +1,14 @@ +import QtQml 2.0 +import Test.Singletons 1.0 + +QtObject { + property Component singletonAccessor : Component { + QtObject { + property var singletonHolder; + property int result: singletonHolder.testVar + } + } + + property int firstLookup: singletonAccessor.createObject(this, { singletonHolder: CppSingleton1 }).result; + property int secondLookup: singletonAccessor.createObject(this, { singletonHolder: CppSingleton2 }).result; +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 09b271c5f1..43cf8192a5 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -369,6 +369,7 @@ private slots: void intMinDividedByMinusOne(); void undefinedPropertiesInObjectWrapper(); void hugeRegexpQuantifiers(); + void singletonTypeWrapperLookup(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -8986,6 +8987,55 @@ void tst_qqmlecmascript::hugeRegexpQuantifiers() QVERIFY(value.isRegExp()); } +struct CppSingleton1 : public QObject +{ + Q_OBJECT + Q_PROPERTY(int testVar MEMBER testVar CONSTANT) +public: + const int testVar = 0; +}; + +struct CppSingleton2 : public QObject +{ + Q_OBJECT + Q_PROPERTY(int testVar MEMBER testVar CONSTANT) +public: + const int testVar = 1; +}; + +void tst_qqmlecmascript::singletonTypeWrapperLookup() +{ + QQmlEngine engine; + + auto singletonTypeId1 = qmlRegisterSingletonType<CppSingleton1>("Test.Singletons", 1, 0, "CppSingleton1", + [](QQmlEngine *, QJSEngine *) -> QObject * { + return new CppSingleton1; + }); + + auto singletonTypeId2 = qmlRegisterSingletonType<CppSingleton2>("Test.Singletons", 1, 0, "CppSingleton2", + [](QQmlEngine *, QJSEngine *) -> QObject * { + return new CppSingleton2; + }); + + auto cleanup = qScopeGuard([&]() { + qmlUnregisterType(singletonTypeId1); + qmlUnregisterType(singletonTypeId2); + }); + + QQmlComponent component(&engine, testFileUrl("SingletonLookupTest.qml")); + QScopedPointer<QObject> test(component.create()); + QVERIFY2(!test.isNull(), qPrintable(component.errorString())); + + auto singleton1 = engine.singletonInstance<CppSingleton1*>(singletonTypeId1); + QVERIFY(singleton1); + + auto singleton2 = engine.singletonInstance<CppSingleton2*>(singletonTypeId2); + QVERIFY(singleton2); + + QCOMPARE(test->property("firstLookup").toInt(), singleton1->testVar); + QCOMPARE(test->property("secondLookup").toInt(), singleton2->testVar); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" |