Merge remote-tracking branch 'origin/5.13' into dev

Conflicts:
	src/qml/jsruntime/qv4value_p.h
	src/qml/qml/qqmlmetatype.cpp
	src/qml/qml/qqmltypewrapper.cpp
	src/quick/items/qquicktableview.cpp

Change-Id: I684f8e01a711580512848bf1253f39b39fcbf4c7
This commit is contained in:
Qt Forward Merge Bot 2019-06-11 01:01:10 +02:00 committed by Ulf Hermann
commit 10e3b24c02
49 changed files with 658 additions and 387 deletions

View File

@ -1073,6 +1073,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;
}
@ -2537,7 +2538,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();
@ -2979,7 +2980,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;

View File

@ -199,8 +199,9 @@ public:
codegen = cg;
}
Reference() :
Reference(const QString &name = QString()) :
constant(0),
name(name),
isArgOrEval(false),
isReadonly(false),
isReferenceToConst(false),
@ -418,6 +419,11 @@ protected:
bool _trueBlockFollowsCondition = false;
public:
explicit Result(const QString &name)
: _result(name)
, _requested(ex)
{}
explicit Result(const Reference &lrvalue)
: _result(lrvalue)
, _requested(ex)
@ -476,6 +482,10 @@ protected:
void setResult(Reference &&result) {
_result = std::move(result);
}
void clearResultName() {
_result.name.clear();
}
};
void enterContext(AST::Node *node);
@ -523,12 +533,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();
}
@ -716,6 +726,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); }
@ -723,7 +734,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()
{

View File

@ -17,7 +17,7 @@ function createSpriteObjects() {
//![local]
component = Qt.createComponent("Sprite.qml");
sprite = component.createObject(appWindow, {"x": 100, "y": 100});
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
@ -32,7 +32,7 @@ function createSpriteObjects() {
//![finishCreation]
function finishCreation() {
if (component.status == Component.Ready) {
sprite = component.createObject(appWindow, {"x": 100, "y": 100});
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");

View File

@ -77,8 +77,13 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
primitiveLookup.type = object.type();
switch (primitiveLookup.type) {
case Value::Undefined_Type:
case Value::Null_Type:
return engine->throwTypeError();
case Value::Null_Type: {
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
const QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString())
.arg(QLatin1String(primitiveLookup.type == Value::Undefined_Type ? "undefined" : "null"));
return engine->throwTypeError(message);
}
case Value::Boolean_Type:
primitiveLookup.proto = engine->booleanPrototype()->d();
break;

View File

@ -120,7 +120,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
} indexedLookup;
struct {
Heap::InternalClass *ic;
Heap::QObjectWrapper *staticQObject;
Heap::InternalClass *qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper
QQmlPropertyCache *propertyCache;
QQmlPropertyData *propertyData;
} qobjectLookup;

View File

@ -292,7 +292,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;
@ -325,7 +324,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;

View File

@ -872,7 +872,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;

View File

@ -231,8 +231,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();

View File

@ -87,12 +87,29 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
{
HeapBasePtr b;
#ifdef __ia64
// Restore bits 49-47 to bits 63-61, undoing the workaround explained in
// setM below.
quint64 _tmp;
_tmp = _val & (7L << 47); // 0x3800000000000
_tmp = (_tmp << 14) | (_val ^ _tmp);
memcpy(&b, &_tmp, 8);
#else
memcpy(&b, &_val, 8);
#endif
return b;
}
QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
{
memcpy(&_val, &b, 8);
#ifdef __ia64
// On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region
// number. Since this implementation is not 64-bit clean, we move bits 63-61
// to bits 49-47 and hope for the best. This is undone in *m(), above.
_val |= ((_val & (7L << 61)) >> 14);
_val &= ((1L << 50)-1);
#endif
}
#elif QT_POINTER_SIZE == 4
QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const

View File

@ -1110,6 +1110,23 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
node->isReadonlyMember = true;
node->readonlyToken = loc(1);
node->typeModifier = stringRef(3);
node->propertyToken = loc(2);
node->typeModifierToken = loc(3);
node->typeToken = loc(5);
node->identifierToken = loc(7);
node->semicolonToken = loc(8);
sym(1).Node = node;
} break;
./
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
/.
@ -1221,6 +1238,34 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
node->isReadonlyMember = true;
node->readonlyToken = loc(1);
node->typeModifier = stringRef(3);
node->propertyToken = loc(2);
node->typeModifierToken = loc(3);
node->typeToken = loc(5);
node->identifierToken = loc(7);
node->semicolonToken = loc(8); // insert a fake ';' before ':'
AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(7));
propertyName->identifierToken = loc(7);
propertyName->next = 0;
AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish());
binding->colonToken = loc(8);
binding->lbracketToken = loc(9);
binding->rbracketToken = loc(11);
node->binding = binding;
sym(1).Node = node;
} break;
./
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
/.
case $rule_number: {
@ -1773,10 +1818,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());

View File

@ -608,9 +608,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);
}
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,

View File

@ -76,7 +76,7 @@ void QQmlApplicationEnginePrivate::init()
&QCoreApplication::exit, Qt::QueuedConnection);
#if QT_CONFIG(translation)
QTranslator* qtTranslator = new QTranslator;
if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
QCoreApplication::installTranslator(qtTranslator);
translators << qtTranslator;
#endif
@ -90,10 +90,10 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile)
if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc"))
return;
QFileInfo fi(rootFile.toLocalFile());
QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile));
QTranslator *translator = new QTranslator;
if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"))) {
if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm"))) {
QCoreApplication::installTranslator(translator);
translators << translator;
} else {
@ -180,6 +180,9 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
\list
\li Connecting Qt.quit() to QCoreApplication::quit()
\li Automatically loads translation files from an i18n directory adjacent to the main QML file.
\list
\li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm.
\endlist
\li Automatically sets an incubation controller if the scene contains a QQuickWindow.
\li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all
QML files and assets.

View File

@ -1206,7 +1206,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
\js
var component = Qt.createComponent("Button.qml");
if (component.status == Component.Ready)
component.createObject(parent, {"x": 100, "y": 100});
component.createObject(parent, {x: 100, y: 100});
\endjs
Dynamically created instances can be deleted with the \c destroy() method.

View File

@ -1193,7 +1193,8 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVe
void QQmlMetaType::unregisterType(int typeIndex)
{
QQmlMetaTypeDataPtr data;
if (const QQmlTypePrivate *d = data->types.value(typeIndex).priv()) {
const QQmlType type = data->types.value(typeIndex);
if (const QQmlTypePrivate *d = type.priv()) {
removeQQmlTypePrivate(data->idToType, d);
removeQQmlTypePrivate(data->nameToType, d);
removeQQmlTypePrivate(data->urlToType, d);
@ -1203,6 +1204,7 @@ void QQmlMetaType::unregisterType(int typeIndex)
module->remove(d);
data->clearPropertyCachesForMinorVersion(typeIndex);
data->types[typeIndex] = QQmlType();
data->undeletableTypes.remove(type);
}
}

View File

@ -454,16 +454,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
}
@ -485,6 +485,39 @@ 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.isQObjectSingleton() && !type.isCompositeSingleton())
return revertLookup();
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
Q_ASSERT(qobjectSingleton);
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);

View File

@ -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);

View File

@ -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;

View File

@ -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 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.
\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
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.
The following backends are supported:
\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.
\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
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 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 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, 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 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.
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 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 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.
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.
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.
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
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.
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, 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
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.
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.
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.
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.
*/

View File

@ -191,7 +191,7 @@ public:
void resetFirstItemPosition(qreal pos = 0.0) override;
void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) override;
void createHighlight() override;
void createHighlight(bool onDestruction = false) override;
void updateHighlight() override;
void resetHighlightPosition() override;
@ -696,9 +696,8 @@ void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int
gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
}
void QQuickGridViewPrivate::createHighlight()
void QQuickGridViewPrivate::createHighlight(bool onDestruction)
{
Q_Q(QQuickGridView);
bool changed = false;
if (highlight) {
if (trackedItem == highlight)
@ -714,6 +713,10 @@ void QQuickGridViewPrivate::createHighlight()
changed = true;
}
if (onDestruction)
return;
Q_Q(QQuickGridView);
if (currentItem) {
QQuickItem *item = createHighlightItem();
if (item) {

View File

@ -162,7 +162,7 @@ QQuickItemView::QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent)
QQuickItemView::~QQuickItemView()
{
Q_D(QQuickItemView);
d->clear();
d->clear(true);
if (d->ownModel)
delete d->model;
delete d->header;
@ -1662,7 +1662,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
releaseItem(oldCurrentItem);
}
void QQuickItemViewPrivate::clear()
void QQuickItemViewPrivate::clear(bool onDestruction)
{
Q_Q(QQuickItemView);
currentChanges.reset();
@ -1683,7 +1683,7 @@ void QQuickItemViewPrivate::clear()
currentItem = nullptr;
if (oldCurrentItem)
emit q->currentItemChanged();
createHighlight();
createHighlight(onDestruction);
trackedItem = nullptr;
if (requestedIndex >= 0) {
@ -2352,15 +2352,16 @@ void QQuickItemView::destroyingItem(QObject *object)
bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
{
Q_Q(QQuickItemView);
if (!item || !model)
if (!item)
return true;
if (trackedItem == item)
trackedItem = nullptr;
item->trackGeometry(false);
QQmlInstanceModel::ReleaseFlags flags = model->release(item->item);
if (item->item) {
if (flags == 0) {
QQmlInstanceModel::ReleaseFlags flags = {};
if (model && item->item) {
flags = model->release(item->item);
if (!flags) {
// item was not destroyed, and we no longer reference it.
QQuickItemPrivate::get(item->item)->setCulled(true);
unrequestedItems.insert(item->item, model->indexOf(item->item, q));

View File

@ -163,7 +163,7 @@ public:
int mapFromModel(int modelIndex) const;
virtual void init();
virtual void clear();
virtual void clear(bool onDestruction=false);
virtual void updateViewport();
void regenerate(bool orientationChanged=false);
@ -327,7 +327,7 @@ protected:
virtual bool hasStickyHeader() const { return false; }
virtual bool hasStickyFooter() const { return false; }
virtual void createHighlight() = 0;
virtual void createHighlight(bool onDestruction = false) = 0;
virtual void updateHighlight() = 0;
virtual void resetHighlightPosition() = 0;
virtual bool movingFromHighlight() { return false; }

View File

@ -81,7 +81,7 @@ public:
FxViewItem *snapItemAt(qreal pos);
void init() override;
void clear() override;
void clear(bool onDestruction) override;
bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) override;
bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) override;
@ -98,7 +98,7 @@ public:
void adjustFirstItem(qreal forwards, qreal backwards, int) override;
void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult) override;
void createHighlight() override;
void createHighlight(bool onDestruction = false) override;
void updateHighlight() override;
void resetHighlightPosition() override;
bool movingFromHighlight() override;
@ -575,7 +575,7 @@ void QQuickListViewPrivate::init()
::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
}
void QQuickListViewPrivate::clear()
void QQuickListViewPrivate::clear(bool onDestruction)
{
for (int i = 0; i < sectionCacheSize; ++i) {
delete sectionCache[i];
@ -587,7 +587,7 @@ void QQuickListViewPrivate::clear()
releaseSectionItem(nextSectionItem);
nextSectionItem = nullptr;
lastVisibleSection = QString();
QQuickItemViewPrivate::clear();
QQuickItemViewPrivate::clear(onDestruction);
}
FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
@ -634,7 +634,7 @@ void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
{
if (!item || !model)
return true;
return QQuickItemViewPrivate::releaseItem(item);
QPointer<QQuickItem> it = item->item;
QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
@ -876,9 +876,8 @@ void QQuickListViewPrivate::updateSizeChangesBeforeVisiblePos(FxViewItem *item,
QQuickItemViewPrivate::updateSizeChangesBeforeVisiblePos(item, removeResult);
}
void QQuickListViewPrivate::createHighlight()
void QQuickListViewPrivate::createHighlight(bool onDestruction)
{
Q_Q(QQuickListView);
bool changed = false;
if (highlight) {
if (trackedItem == highlight)
@ -896,6 +895,10 @@ void QQuickListViewPrivate::createHighlight()
changed = true;
}
if (onDestruction)
return;
Q_Q(QQuickListView);
if (currentItem) {
QQuickItem *item = createHighlightItem();
if (item) {

View File

@ -221,7 +221,7 @@ QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon()
clearSignalMappers(shaderType);
}
void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key::ShaderType shaderType)
void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
{
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
if (signalMappers[shaderType].at(i) == 0)
@ -229,11 +229,12 @@ void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key
const UniformData &d = uniformData[shaderType].at(i);
auto mapper = signalMappers[shaderType].at(i);
void *a = mapper;
QObjectPrivate::disconnect(obj, mapper->signalIndex(), &a);
QObjectPrivate::disconnect(item, mapper->signalIndex(), &a);
if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
QQuickItemPrivate::get(source)->derefWindow();
if (item->window())
QQuickItemPrivate::get(source)->derefWindow();
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
}
}

View File

@ -89,7 +89,7 @@ struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
~QQuickOpenGLShaderEffectCommon();
void disconnectPropertySignals(QObject *item, Key::ShaderType shaderType);
void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
void connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType);
void updateParseLog(bool ignoreAttributes);
void lookThroughShaderCode(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType, const QByteArray &code);

View File

@ -505,7 +505,7 @@ void QQuickOpenGLShaderEffectNode::markDirtyTexture()
Q_EMIT dirtyTexture();
}
void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(const QObject *object)
void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(QObject *object)
{
Q_ASSERT(material());
static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->invalidateTextureProvider(object);

View File

@ -159,7 +159,7 @@ Q_SIGNALS:
private Q_SLOTS:
void markDirtyTexture();
void textureProviderDestroyed(const QObject *object);
void textureProviderDestroyed(QObject *object);
};
QT_END_NAMESPACE

View File

@ -120,16 +120,17 @@ QQuickRepeaterPrivate::~QQuickRepeaterPrivate()
Also, note that Repeater is \l {Item}-based, and can only repeat \l {Item}-derived objects.
For example, it cannot be used to repeat QtObjects:
\code
//bad code
\qml
// bad code:
Item {
Can't repeat QtObject as it doesn't derive from Item.
// Can't repeat QtObject as it doesn't derive from Item.
Repeater {
model: 10
QtObject {}
}
}
\endcode
\endqml
*/
/*!

View File

@ -515,6 +515,20 @@ QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
m_impl = new QQuickGenericShaderEffect(this, this);
}
QQuickShaderEffect::~QQuickShaderEffect()
{
// Delete the implementations now, while they still have have
// valid references back to us.
#if QT_CONFIG(opengl)
auto *glImpl = m_glImpl;
m_glImpl = nullptr;
delete glImpl;
#endif
auto *impl = m_impl;
m_impl = nullptr;
delete impl;
}
/*!
\qmlproperty string QtQuick::ShaderEffect::fragmentShader

View File

@ -92,6 +92,7 @@ public:
Q_ENUM(Status)
QQuickShaderEffect(QQuickItem *parent = nullptr);
~QQuickShaderEffect() override;
QByteArray fragmentShader() const;
void setFragmentShader(const QByteArray &code);

View File

@ -868,6 +868,9 @@ void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
void QQuickTableViewPrivate::forceLayout()
{
if (loadedItems.isEmpty())
return;
clearEdgeSizeCache();
RebuildOptions rebuildOptions = RebuildOption::LayoutOnly;

View File

@ -1403,7 +1403,7 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVar
case Qt::ImAnchorPosition:
return QVariant(d->cursor.anchor() - block.position());
case Qt::ImAbsolutePosition:
return QVariant(d->cursor.anchor());
return QVariant(d->cursor.position());
case Qt::ImTextAfterCursor:
{
int maxLength = argument.isValid() ? argument.toInt() : 1024;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -1314,9 +1314,13 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
void QQuickWidget::showEvent(QShowEvent *)
{
Q_D(QQuickWidget);
bool shouldTriggerUpdate = true;
if (!d->useSoftwareRenderer) {
d->createContext();
if (d->offscreenWindow->openglContext()) {
shouldTriggerUpdate = false;
d->render(true);
// render() may have led to a QQuickWindow::update() call (for
// example, having a scene with a QQuickFramebufferObject::Renderer
@ -1329,11 +1333,12 @@ void QQuickWidget::showEvent(QShowEvent *)
d->updatePending = false;
update();
}
} else {
triggerUpdate();
}
}
if (shouldTriggerUpdate)
triggerUpdate();
// note offscreenWindow is "QQuickOffScreenWindow" instance
d->offscreenWindow->setVisible(true);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())

View File

@ -322,7 +322,7 @@ void tst_QQmlPreview::zoom()
for (auto testZoomFactor : {2.0f, 1.5f, 0.5f}) {
m_client->triggerZoom(testZoomFactor);
verifyZoomFactor(m_process, baseZoomFactor * testZoomFactor);
verifyZoomFactor(m_process, testZoomFactor);
}
m_client->triggerZoom(-1.0f);

View File

@ -712,8 +712,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

Binary file not shown.

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="" sourcelanguage="en">
<context>
<name>loadTranslation</name>
<message>
<source>translate it</source>
<translation>translated</translation>
</message>
</context>
</TS>

View File

@ -0,0 +1,5 @@
import QtQml 2.0
QtObject {
property string translation: qsTr('translate it')
}

View File

@ -50,6 +50,9 @@ private slots:
void application();
void applicationProperties();
void removeObjectsWhenDestroyed();
void loadTranslation_data();
void loadTranslation();
private:
QString buildDir;
QString srcDir;
@ -241,6 +244,30 @@ void tst_qqmlapplicationengine::removeObjectsWhenDestroyed()
QCOMPARE(test->rootObjects().size(), 0);
}
void tst_qqmlapplicationengine::loadTranslation_data()
{
QTest::addColumn<QUrl>("qmlUrl");
QTest::addColumn<QString>("translation");
QTest::newRow("local file") << testFileUrl("loadTranslation.qml")
<< QStringLiteral("translated");
QTest::newRow("qrc") << QUrl(QLatin1String("qrc:///data/loadTranslation.qml"))
<< QStringLiteral("translated");
}
void tst_qqmlapplicationengine::loadTranslation()
{
QFETCH(QUrl, qmlUrl);
QFETCH(QString, translation);
QQmlApplicationEngine test(qmlUrl);
QVERIFY(!test.rootObjects().isEmpty());
QObject *rootObject = test.rootObjects().first();
QVERIFY(rootObject);
QCOMPARE(rootObject->property("translation").toString(), translation);
}
QTEST_MAIN(tst_qqmlapplicationengine)

View File

@ -5,6 +5,9 @@ macx:CONFIG -= app_bundle
SOURCES += tst_qqmlapplicationengine.cpp
TESTDATA += data/*
RESOURCES += tst_qqmlapplicationengine.qrc
include (../../shared/util.pri)
QT += core-private gui-private qml-private network testlib
TRANSLATIONS = data/i18n/qml_ja.ts

View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>data/loadTranslation.qml</file>
<file>data/i18n/qml.qm</file>
</qresource>
</RCC>

View File

@ -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;
}

View File

@ -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);
@ -9007,6 +9008,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([&]() {
QQmlMetaType::unregisterType(singletonTypeId1);
QQmlMetaType::unregisterType(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"

View File

@ -54,6 +54,7 @@ private slots:
void noSubstitutionTemplateLiteral();
void templateLiteral();
void leadingSemicolonInClass();
void templatedReadonlyProperty();
private:
QStringList excludedDirs;
@ -289,6 +290,15 @@ void tst_qqmlparser::leadingSemicolonInClass()
QVERIFY(parser.parseProgram());
}
void tst_qqmlparser::templatedReadonlyProperty()
{
QQmlJS::Engine engine;
QQmlJS::Lexer lexer(&engine);
lexer.setCode(QLatin1String("A { readonly property list<B> listfoo: [ C{} ] }"), 1);
QQmlJS::Parser parser(&engine);
QVERIFY(parser.parse());
}
QTEST_MAIN(tst_qqmlparser)
#include "tst_qqmlparser.moc"

View File

@ -1491,11 +1491,11 @@ void tst_QQuickPathView::undefinedPath()
// QPainterPath warnings are only received if QT_NO_DEBUG is not defined
if (QLibraryInfo::isDebugBuild()) {
QString warning1("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
QTest::ignoreMessage(QtWarningMsg,qPrintable(warning1));
QRegularExpression warning1("^QPainterPath::moveTo:.*ignoring call$");
QTest::ignoreMessage(QtWarningMsg, warning1);
QString warning2("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
QTest::ignoreMessage(QtWarningMsg,qPrintable(warning2));
QRegularExpression warning2("^QPainterPath::lineTo:.*ignoring call$");
QTest::ignoreMessage(QtWarningMsg, warning2);
}
QQmlComponent c(&engine, testFileUrl("undefinedpath.qml"));

View File

@ -564,7 +564,10 @@ bool tst_SceneGraph::isRunningOnOpenGL()
bool retval = false;
QQuickView dummy;
dummy.show();
QTest::qWaitForWindowExposed(&dummy);
if (!QTest::qWaitForWindowExposed(&dummy)) {
[](){ QFAIL("Could not show a QQuickView"); }();
return false;
}
if (dummy.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL)
retval = true;
dummy.hide();

View File

@ -449,9 +449,6 @@ void tst_qquickwidget::reparentToNewWindow()
qqw->setParent(&window2);
qqw->show();
if (QGuiApplication::platformName() == QLatin1String("offscreen"))
QEXPECT_FAIL("", "afterRendering not emitted after reparenting on offscreen", Continue);
QTRY_VERIFY(afterRenderingSpy.size() > 0);
QImage img = qqw->grabFramebuffer();