Details
-
Epic
-
Resolution: Done
-
P1: Critical
-
None
-
None
Description
In order to achieve fast startup times, and continued smoothness as they run, applications need to be able to instantiate new QML elements - anything from delegates to new tabs etc. - while still maintaining a constant, high frame rate. It is expected that a significant portion of most applications will be lazily loaded and there must not be ugly pausing or skipping in animations or transitions while this is happening.
There are two main stages to creating a QML object tree - compiling the QML file into an internal bytecode form, and running the compiled code to produce the element tree. Currently, both stages occur synchronously (excluding any asynchronicity introduced by network operations) on the main application thread.
Compilation
It is reasonable to expect that QML file compilation can be made to run in a (single) separate thread. To maintain the current behaviour, and to ensure that the initial minimal subset of an application is compiled as quickly as possible, the compilation must appear to be synchronous and blocking by default. Only if a special asynchronous flag is set should local compilation be threaded. The C++ API should only need a minor alteration to support this, as compilation that involves a remote resource is already non-blocking today and consequently all the appropriate progress notification signals exist. Even the case involving remote resources should see a performance improvement as even though it behaves in a non-blocking fashion today, as all the work is still being done on the main thread there will be skips and pauses.
Execution
There are too many assumptions in Qt, QML and 3rdparty frameworks like V8 to realistically be able to execute the QML bytecode in a separate thread. It is possible that in the future this might become possible, but it is not an achievable short term goal. Rather than execute QML bytecode in a separate thread, we will try and make the bytecode execution pre-emptible. This should allow us to execute the bytecode across several frames using a degenerative form of "cooperative multitasking". The current thought is that, each frame, the QML 2 scenegraph will indicate to the engine that it has an X ms timeslice in which to execute instantiation code which it will try hard not to exceed. As the time taken in non-engine C++ and JavaScript code cannot be arbitrarily preempted, it is possible that the allocated timeslice maybe overrun, but hopefully it will be good enoughTM.
QML API
It is probably unnecessary to expose much new API to QML to allow applications to effectively utilise this new behaviour. At the very least, the Loader element should gain an asynchronous property that will enable support. Loaded components that involve a network resource should be asynchronous by default.
It is not clear how imperative QML APIs like Qt.createComponent() or Qt.createQmlObject() should be extended. One interesting idea is to not extend the API at all, but instead allow them to be used from within a WorkerScript which would automatically enable non-blocking behaviour. This has the added benefit of encouraging people to use WorkerScript, and encouraging the QML developers to make WorkerScript easier to use.
Implementation Backlog
Add separate-thread support to QDeclarativeDataLoader- Remove QDeclarativeEngine thread dependencies from QDeclarativeCompiler
QDeclarativeScriptData is initialised in loader threadEngine's meta type hash is modified in loader thread, and read in main threadReview instances of QDeclarativeCleanupImported libraries are loaded in the loader thread. Add another plugin interface and deprecate the one with initializeEngine().- Make QDeclarativeEnginePrivate::Locker class skip locking when possible.
Implement QDeclarativeEnginePrivate::deleteInEngineThread
Add API to QDeclarativeComponent to enable asynchronous loadingRefactor execution to bypass non-root QDeclarativeComponents and remove recursionAllow execution to start at any point given starting stateAdd preemption check to instruction processingAdd API to allow the engine to be accept preemption requests.Allow nested executions to hook into an existing asynchronous executionEnsure that cancellations or deletions mid-run don't cause crashesImplement an optimal incubation controller for scenegraphAdd JavaScript API for asynchronous loadingDocumentation- Autotest
Attachments
Issue Links
- is required for
-
QTBUG-25005 Critical issues for Qt5 Beta 1
- Closed
For Gerrit Dashboard: QTBUG-21151 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
5676,3 | Asynchronous component instantiation | master | qt/qtdeclarative | Status: MERGED | -1 | 0 |
5776,1 | QDeclarativeIncubator doc | master | qt/qtdeclarative | Status: MERGED | -1 | 0 |
5780,1 | QDeclarativeIncubationController docs | master | qt/qtdeclarative | Status: MERGED | -1 | 0 |
5822,1 | Remove unnecessary members | master | qt/qtdeclarative | Status: MERGED | -1 | 0 |
5827,1 | Improve QDeclarativeIncubator JS API | master | qt/qtdeclarative | Status: MERGED | -1 | 0 |
5828,1 | Add a QSGCanvas incubation controller | master | qt/qtdeclarative | Status: MERGED | -1 | 0 |
5911,2 | QDeclarativeIncubator::clear() and autotests | master | qt/qtdeclarative | Status: MERGED | -1 | 0 |
5940,1 | QDeclarativeIncubator autotests | master | qt/qtdeclarative | Status: MERGED | +2 | 0 |