aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qv4codegen.cpp5
-rw-r--r--src/qml/compiler/qv4codegen_p.h19
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp1
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h3
-rw-r--r--src/qml/parser/qqmljs.g4
-rw-r--r--src/qml/qml/qqml.h9
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp47
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h2
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h24
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc588
-rw-r--r--src/quick/scenegraph/qsgbasicinternalimagenode.cpp4
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp10
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h3
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp50
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"