aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorChris Adams <christopher.adams@nokia.com>2011-12-07 16:39:50 +1000
committerQt by Nokia <qt-info@nokia.com>2011-12-20 05:40:23 +0100
commitf217b776c8a41ea93e3b25a4009573bb94344ac2 (patch)
treedca0a36019a741ea61e5c11ee298fac32c5fc79c /doc
parent6efca58ab943bbd8c91c8f12ad47484677e2cf60 (diff)
Update the performance-tips documentation
Improvements to the JavaScript integration in QML means that developers must be aware of some different performance related concerns. This commit also adds some performance tips for other elements and use-cases in QML. Change-Id: Ia72f8c7ab275d3ff879fa195d59ecab102ca1f86 Reviewed-by: Alan Alpert <alan.alpert@nokia.com> Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'doc')
-rw-r--r--doc/src/declarative/qdeclarativeperformance.qdoc694
1 files changed, 645 insertions, 49 deletions
diff --git a/doc/src/declarative/qdeclarativeperformance.qdoc b/doc/src/declarative/qdeclarativeperformance.qdoc
index 12b345a3ff..a2e72ce156 100644
--- a/doc/src/declarative/qdeclarativeperformance.qdoc
+++ b/doc/src/declarative/qdeclarativeperformance.qdoc
@@ -30,17 +30,471 @@
\inqmlmodule QtQuick 2
\title QML Performance
-\section1 Opaque Items
+\tableofcontents
-Items hidden behind an opaque item incur a cost. If an item will be enitrely
-obscured by an opaque item, set its opacity to 0. One common example of
-this is when a "details" page is shown over the main application view.
+\section1 Timing Considerations
-\section1 Clipping
+As an application developer, you must strive to allow the rendering engine
+to achieve a consistent 60 frames-per-second refresh rate. 60 FPS means
+that there is approximately 16 milliseconds between each frame in which
+processing can be done, which includes the processing required to upload
+the draw primitives to the graphics hardware.
-\i clip is set to false by default. Enable clipping only when necessary.
+In practice, this means that the application developer should use asynchronous,
+event driven programming wherever possible, should use worker threads to do
+significant processing, should never manually spin the event loop, and should
+never spend more than a couple of milliseconds per frame within blocking functions.
+Failure to do so will result in skipped frames, which has a drastic effect on the
+user experience.
-\section1 Anchors vs. Binding
+\section1 Profiling
+
+The most important tip is: use the QML profiler included with Qt Creator. Knowing
+where time is spent in an application will allow you to focus on problem areas which
+actually exist, rather than problem areas which potentially exist. See the Qt Creator
+manual for more information on how to use the QML profiling tool.
+
+Determining which bindings are being run the most often, or which functions your
+application is spending the most time in, will allow you to decide whether you need
+to optimize the problem areas, or redesign some implementation details of your
+application so that the performance is improved. Attempting to optimize code without
+profiling is likely to result in very minor rather than significant performance
+improvements.
+
+\section1 JavaScript
+
+Most QML applications will have a large amount of JavaScript code in them, in the
+form of dynamic functions, signal handlers, and property binding expressions.
+This is not generally a problem (in fact, due to some optimizations in the QML engine
+(bindings compiler, etc) it can for some use-cases be faster than calling a C++ function)
+however care must be taken to ensure that unnecessary processing isn't triggered
+accidentally.
+
+\section2 Type-Conversion
+
+One major cost of using JavaScript is that in most cases when a property from a QML
+element is accessed, a JavaScript object with an external resource containing the
+underlying C++ data (or a reference to it) is created. In most cases, this is fairly
+inexpensive, but in others it can be quite expensive. One example of where it is
+expensive is assigning a C++ QVariantMap Q_PROPERTY to a QML "variant" property.
+Lists can also be expensive, although sequences of specific types (QList of int,
+qreal, bool, QString, and QUrl) should be inexpensive; other list types involve an
+expensive conversion cost (creating a new JavaScript Array, and adding new elements
+one by one, with per-element conversion from C++ type instance to JavaScript value).
+
+Converting between some basic property types (such as "string" and "url" properties)
+can also be expensive. Using the closest matching property type will avoid unnecessary
+conversion.
+
+If you must expose a QVariantMap to QML, use a "var" property rather than a "variant"
+property. In general, "property var" should be considered to be superior to
+"property variant" for every use-case in QtQuick 2.0 (note that "property variant"
+is marked as obsolete in the QtQuick 2.0 documentation), as it allows a true JavaScript
+reference to be stored (which can reduce the number of conversions required in certain
+expressions).
+
+\section2 Resolving Properties
+
+Property resolution takes time. While in some cases the result of a lookup can be
+cached and reused, it is always best to avoid doing unnecessary work altogether, if
+possible.
+
+In the following example, we have a block of code which is run often (in this case, it
+is the contents of an explicit loop; but it could be a commonly-evaluated binding expression,
+for example) and in it, we resolve the element with the "rect" id and its "color" property
+multiple times:
+
+\qml
+// bad.qml
+import QtQuick 2.0
+
+Item {
+ width: 400
+ height: 200
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "blue"
+ }
+
+ function printValue(which, value) {
+ console.log(which + " = " + value);
+ }
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ for (var i = 0; i < 1000; ++i) {
+ printValue("red", rect.color.r);
+ printValue("green", rect.color.g);
+ printValue("blue", rect.color.b);
+ printValue("alpha", rect.color.a);
+ }
+ var t1 = new Date();
+ console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
+ }
+}
+\endqml
+
+We could instead resolve the common base just once in the block:
+
+\qml
+// good.qml
+import QtQuick 2.0
+
+Item {
+ width: 400
+ height: 200
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "blue"
+ }
+
+ function printValue(which, value) {
+ console.log(which + " = " + value);
+ }
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ for (var i = 0; i < 1000; ++i) {
+ var rectColor = rect.color; // resolve the common base.
+ printValue("red", rectColor.r);
+ printValue("green", rectColor.g);
+ printValue("blue", rectColor.b);
+ printValue("alpha", rectColor.a);
+ }
+ var t1 = new Date();
+ console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
+
+ }
+}
+\endqml
+
+Just this simple change results in a significant performance improvement.
+
+\section2 Property Bindings
+
+A property binding expression will be re-evaluated if any of the properties
+it references are changed. As such, binding expressions should be kept as
+simple as possible.
+
+If you have a loop where you do some processing, but only the final result
+of the processing is important, it is often better to update a temporary
+accumulator which you afterwards assign to the property you need to update,
+rather than incrementally updating the property itself, in order to avoid
+triggering re-evaluation of binding expressions during the intermediate
+stages of accumulation.
+
+The following contrived example illustrates this point:
+
+\qml
+// bad.qml
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 200
+ height: 200
+ property int accumulatedValue: 0
+
+ Text {
+ anchors.fill: parent
+ text: root.accumulatedValue.toString()
+ onTextChanged: console.log("text binding re-evaluated")
+ }
+
+ Component.onCompleted: {
+ var someData = [ 1, 2, 3, 4, 5, 20 ];
+ for (var i = 0; i < someData.length; ++i) {
+ accumulatedValue = accumulatedValue + someData[i];
+ }
+ }
+}
+\endqml
+
+The loop in the onCompleted handler causes the "text" property binding to
+be re-evaluated six times (which then results in any other property bindings
+which rely on the text value, as well as the onTextChanged signal handler,
+to be re-evaluated each time, and lays out the text for display each time).
+This is clearly unnecessary in this case, since we really only care about
+the final value of the accumulation.
+
+It could be rewritten as follows:
+
+\qml
+// good.qml
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 200
+ height: 200
+ property int accumulatedValue: 0
+
+ Text {
+ anchors.fill: parent
+ text: root.accumulatedValue.toString()
+ onTextChanged: console.log("text binding re-evaluated")
+ }
+
+ Component.onCompleted: {
+ var someData = [ 1, 2, 3, 4, 5, 20 ];
+ var temp = accumulatedValue;
+ for (var i = 0; i < someData.length; ++i) {
+ temp = temp + someData[i];
+ }
+ accumulatedValue = temp;
+ }
+}
+\endqml
+
+\section2 Sequence tips
+
+As mentioned earlier, some sequence types are fast (eg, QList<int>, QList<qreal>,
+QList<bool>, QList<QString>, QStringList and QList<QUrl>) while others will be
+much slower. Aside from using these types wherever possible instead of slower types,
+there are some other performance-related semantics you need to be aware of to achieve
+the best performance.
+
+Firstly, there are two different implementations for sequence types: one for where
+the sequence is a Q_PROPERTY of a QObject (we'll call this a reference sequence),
+and another for where the sequence is returned from a Q_INVOKABLE function of a
+QObject (we'll call this a copy sequence).
+
+A reference sequence is read and written via QMetaObject::property() and thus is read
+and written as a QVariant. This means that changing the value of any element in the
+sequence from JavaScript will result in three steps occurring: the complete sequence
+will be read from the QObject (as a QVariant, but then cast to a sequence of the correct
+type); the element at the specified index will be changed in that sequence; and the
+complete sequence will be written back to the QObject (as a QVariant).
+
+A copy sequence is far simpler as the actual sequence is stored in the JavaScript
+object's resource data, so no read/modify/write cycle occurs (instead, the resource
+data is modified directly).
+
+Therefore, writes to elements of a reference sequence will be much slower than writes
+to elements of a copy sequence. In fact, writing to a single element of an N-element
+reference sequence is equivalent in cost to assigning a N-element copy sequence to that
+reference sequence, so you're usually better off modifying a temporary copy sequence
+and then assigning the result to a reference sequence, during computation.
+
+Assume the existence (and prior registration into the "Qt.example 1.0" namespace) of the
+following C++ type:
+
+\code
+class SequenceTypeExample : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY (QList<qreal> qrealListProperty READ qrealListProperty WRITE setQrealListProperty NOTIFY qrealListPropertyChanged)
+
+public:
+ SequenceTypeExample() : QQuickItem() { m_list << 1.1 << 2.2 << 3.3; }
+ ~SequenceTypeExample() {}
+
+ QList<qreal> qrealListProperty() const { return m_list; }
+ void setQrealListProperty(const QList<qreal> &list) { m_list = list; emit qrealListPropertyChanged(); }
+
+signals:
+ void qrealListPropertyChanged();
+
+private:
+ QList<qreal> m_list;
+};
+\endcode
+
+The following example writes to elements of a reference sequence in a
+tight loop, resulting in bad performance:
+
+\qml
+// bad.qml
+import QtQuick 2.0
+import Qt.example 1.0
+
+SequenceTypeExample {
+ id: root
+ width: 200
+ height: 200
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ qrealListProperty.length = 100;
+ for (var i = 0; i < 500; ++i) {
+ for (var j = 0; j < 100; ++j) {
+ qrealListProperty[j] = j;
+ }
+ }
+ var t1 = new Date();
+ console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
+ }
+}
+\endqml
+
+The QObject property read and write in the inner loop caused by the
+\c{"qrealListProperty[j] = j"} expression makes this code very suboptimal. Instead,
+something functionally equivalent but much faster would be:
+
+\qml
+// good.qml
+import QtQuick 2.0
+import Qt.example 1.0
+
+SequenceTypeExample {
+ id: root
+ width: 200
+ height: 200
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ var someData = [1.1, 2.2, 3.3]
+ someData.length = 100;
+ for (var i = 0; i < 500; ++i) {
+ for (var j = 0; j < 100; ++j) {
+ someData[j] = j;
+ }
+ qrealListProperty = someData;
+ }
+ var t1 = new Date();
+ console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
+ }
+}
+\endqml
+
+Secondly, a change signal for the property is emitted if any element in it changes.
+If you have many bindings to a particular element in a sequence property, it is better
+to create a dynamic property which is bound to that element, and use that dynamic
+property as the symbol in the binding expressions instead of the sequence element,
+as it will only cause re-evaluation of bindings if its value changes.
+
+This is an unusual use-case which most clients should never hit, but is worth being
+aware of, in case you find yourself doing something like this:
+
+\qml
+// bad.qml
+import QtQuick 2.0
+import Qt.example 1.0
+
+SequenceTypeExample {
+ id: root
+
+ property int firstBinding: qrealListProperty[1] + 10;
+ property int secondBinding: qrealListProperty[1] + 20;
+ property int thirdBinding: qrealListProperty[1] + 30;
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ for (var i = 0; i < 1000; ++i) {
+ qrealListProperty[2] = i;
+ }
+ var t1 = new Date();
+ console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
+ }
+}
+\endqml
+
+Note that even though only the element at index 2 is modified in the loop, the three
+bindings will all be re-evaluated since the granularity of the change signal is that
+the entire property has changed. As such, adding an intermediate binding can
+sometimes be beneficial:
+
+\qml
+// good.qml
+import QtQuick 2.0
+import Qt.example 1.0
+
+SequenceTypeExample {
+ id: root
+
+ property int intermediateBinding: qrealListProperty[1]
+ property int firstBinding: intermediateBinding + 10;
+ property int secondBinding: intermediateBinding + 20;
+ property int thirdBinding: intermediateBinding + 30;
+
+ Component.onCompleted: {
+ var t0 = new Date();
+ for (var i = 0; i < 1000; ++i) {
+ qrealListProperty[2] = i;
+ }
+ var t1 = new Date();
+ console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
+ }
+}
+\endqml
+
+In the above example, only the intermediate binding will be re-evaluated each time,
+resulting in a significant performance increase.
+
+\section2 Value-Type tips
+
+Value-type properties (font, color, vector3d, etc) have similar QObject property
+and change notification semantics to sequence type properties. As such, the tips
+given above for sequences are also applicable for value-type properties. While
+they are usually less of a problem with value-types (since the number of
+sub-properties of a value-type is usually far less than the number of elements
+in a sequence), any increase in the number of bindings being re-evaluated needlessly
+will have a negative impact on performance.
+
+\section2 Other JavaScript Objects
+
+Different JavaScript engines provide different optimizations. The JavaScript engine
+which QtQuick 2 uses is optimized for object instantiation and property lookup, but
+the optimizations which it provides relies on certain criteria. If your application
+does not meet the criteria, the JavaScript engine falls back to a "slow-path" mode
+with much worse performance. As such, always try to ensure you meet the following
+criteria:
+
+\list
+\o Avoid using eval() if at all possible
+\o Do not delete properties of objects
+\o Try to maintain property-assignment order in different constructor functions
+\endlist
+
+\section1 Common Interface Elements
+
+\section2 Text Elements
+
+Calculating text layouts can be a slow operation. Consider using the \c PlainText
+format instead of \c StyledText wherever possible, as this reduces the amount of work
+required of the layout engine. If you cannot use \c PlainText (as you need to embed
+images, or use tags to specify ranges of characters to have certain formatting (bold,
+italic, etc) as opposed to the entire text) then you should use \c StyledText.
+
+You should only use \c AutoText if the text might be (but probably isn't)
+\c StyledText as this mode will incur a parsing cost. The \c RichText mode should
+not be used, as \c StyledText provides almost all of its features at a fraction of
+its cost.
+
+\section2 Images
+
+Images are a vital part of any user interface. Unfortunately, they are also a big
+source of problems due to the time it takes to load them, the amount of memory they
+consume, and the way in which they are used.
+
+\section3 Asynchronous Loading
+
+Images are often quite large, and so it is wise to ensure that loading an image doesn't
+block the UI thread. Set the "asynchronous" property of the QML Image element to
+\c true to enable asynchronous loading of images from the local file system (remote
+images are always loaded asynchronously) where this would not result in a negative impact
+upon the aesthetics of the user interface.
+
+Image elements with the "asynchronous" property set to \c true will load images in
+a low-priority worker thread.
+
+\section3 Explicit Source Size
+
+If your application loads a large image but displays it in a small-sized element, set
+the "sourceSize" property to the size of the element being rendered to ensure that the
+smaller-scaled version of the image is kept in memory, rather than the large one.
+
+Beware that changing the sourceSize will cause the image to be reloaded.
+
+\section3 Avoid Run-time Composition
+
+Also remember that you can avoid doing composition work at run-time by providing the
+pre-composed image resource with your application (e.g., providing elements with shadow
+effects).
+
+\section2 Position Elements With Anchors
It is more efficient to use anchors rather than bindings to position items
relative to each other. Consider this use of bindings to position rect2
@@ -79,67 +533,209 @@ Rectangle {
}
\endcode
-\section1 Images
+\section1 Models and Views
+
+Most applications will have at least one model feeding data to a view. There are
+some semantics which application developers need to be aware of, in order to achieve
+maximal performance.
+
+\section2 Custom C++ Models
+
+It is often desirable to write your own custom model in C++ for use with a view in
+QML. While the optimal implementation of any such model will depend heavily on the
+use-case it must fulfil, some general guidelines are as follows:
+
+\list
+\o Be as asynchronous as possible
+\o Do all processing in a (low priority) worker thread
+\o Batch up backend operations so that (potentially slow) I/O and IPC is minimised
+\o Use a sliding slice window to cache results, whose parameters are determined with the help of profiling
+\endlist
-Images consume a great deal of memory and may also be costly to load. In order
-to deal with large images efficiently it is recommended that the Image::sourceSize
-property be set to a size no greater than that necessary to render it. Beware that
-changing the sourceSize will cause the image to be reloaded.
+It is important to note that using a low-priority worker thread is recommended to
+minimise the risk of starving the GUI thread (which could result in worse perceived
+performance). Also, remember that synchronisation and locking mechanisms can be a
+significant cause of slow performance, and so care should be taken to avoid
+unnecessary locking.
-Images on the local filesystem are usually loaded synchronously. This is usually
-the desired behavior for user interface elements, however for large images that
-do not necessarily need to be visible immediately, set the Image::asynchronous
-property to true. This will load the image in a low priority thread.
+\section2 ListModel
-\section1 View Delegates
+QML provides a ListModel element which can be used to feed data to a ListView.
+It should suffice for most use-cases and be relatively performant so long as
+it is used correctly.
-Delegates must be created quickly as the view is flicked. There are two important
-aspects to maintaining a smooth view:
+\section3 Populate Within A Worker Thread
+ListModel elements can be populated in a (low priority) worker thread in JavaScript. The
+developer must explicitly call "sync()" on the ListModel from within the WorkerScript to
+have the changes synchronised to the main thread. See the WorkerScript documentation
+for more information.
+
+\section3 Don't Use Dynamic Roles
+
+The ListModel element in QtQuick 2.0 is much more performant than in QtQuick 1.0. The
+performance improvements mainly come from assumptions about the type of roles within each
+element in a given model - if the type doesn't change, the caching performance improves
+dramatically. If the type can change dynamically from element to element, this optimization
+becomes impossible, and the performance of the model will be an order of magnitude worse.
+
+Therefore, dynamic typing is disabled by default; the developer must specifically set
+the boolean "dynamicRoles" property of the model to enable dynamic typing (and suffer
+the attendant performance degradation). We recommend that you do not use dynamic typing
+if it is possible to redesign your application to avoid it.
+
+\section2 Views
+
+View delegates should be kept as simple as possible. Have just enough QML in the delegate
+to display the necessary information. Any additional functionality which is not immediately
+required (e.g., if it displays more information when clicked) should not be created until
+needed (see the upcoming section on lazy initialisation).
+
+The following list is a good summary of things to keep in mind when designing a delegate:
\list
-\o Small delegates - keep the amount of QML to a minimum. Have just enough
-QML in the delegate to display the necessary information. Any additional functionality
-that is only needed when the delegate is clicked, for example, should be created by
-a Loader as needed.
-\o Fast data access - ensure the data model is as fast as possible.
+\o The fewer elements that are in a delegate, the faster they can be created, and thus
+ the faster the view can be scrolled.
+\o Keep the number of bindings in a delegate to a minimum; in particular, use anchors
+ rather than bindings for relative positioning within a delegate.
+\o Set a cacheBuffer to allow asynchronous creation of delegates outside the visible area.
+ Be mindful that this creates additional delegates and therefore the size of the
+ cacheBuffer must be balanced against additional memory usage.
+\o Avoid using ShaderEffect elements within delegates.
+\o Never enable clipping on a delegate.
\endlist
-\section1 Image resources over composition
+\section1 Visual Effects
+
+QtQuick 2 includes several features which allow developers and designers to create
+exceptionally appealing user interfaces. Fluidity and dynamic transitions as well
+as visual effects can be used to great effect in an application, but some care must
+be taken when using some of the features in QML as they can have performance implications.
+
+\section2 Animations
+
+In general, animating a property will cause any bindings which reference that property
+to be re-evaluated. Usually, this is what is desired but in other cases it may be better
+to disable the binding prior to performing the animation, and then reassign the binding
+once the animation has completed.
+
+Avoid running JavaScript during animation. For example, running a complex JavaScript
+expression for each frame of an x property animation should be avoided.
-If possible, provide a single image resource, rather than using composition
-of a number of elements. For example, a frame with a shadow could be created using
-a Rectangle placed over an Image providing the shadow. It is more efficient to
-provide an image that includes the frame and the shadow.
+Developers should be especially careful using script animations, as these are run in the main
+thread (and therefore can cause frames to be skipped if they take too long to complete).
-\section1 Limit JavaScript
+\section2 Particles
-Avoid running JavaScript during animation. For example, running a complex
-JavaScript expression for each frame of an x property animation.
+The QtQuick 2.0 Particles module allows beautiful particle effects to be integrated
+seamlessly into user interfaces. However every platform has different graphics hardware
+capabilities, and the Particles module is unable to limit parameters to what your hardware
+can gracefully support. The more particles you attempt to render (and the larger they are),
+the faster your graphics hardware will need to be in order to render at 60 FPS. Affecting
+more particles requires a faster CPU. It is therefore important to test all
+particle effects on your target platform carefully, to calibrate the number and size of
+particles you can render at 60 FPS.
-\section1 Loading later
+It should be noted that a particle system can be disabled when not in use
+(e.g., on a non-visible element) to avoid doing unnecessary simulation.
-Startup time is influenced by the amount of QML that must be loaded. Breaking your
-application into components which can be loaded when needed will allow faster startup time.
-This allows better runtime memory management by unloading the components when no
-longer needed.
+See the \l{Qt Quick Particle System Performance Guide} for more in-depth information.
-This may be achieved by using either \l Loader or creating components
+\section2 Shaders
+
+Shaders written in GLSL allow for complex transformations and visual effects to be written,
+however they should be used with care. Using a ShaderEffectSource causes a scene to
+prerendered into an FBO before it can be drawn. This extra overhead is quite expensive.
+
+A ShaderEffect element can imply a ShaderEffectSource (and the indirect rendering costs
+associated with that) and also involves uploading a vertex and fragment shader program
+(which is then compiled into a GLSL shader). Each fragment shader runs once for every
+pixel of the scene, and so these should be kept as simple as possible.
+
+\section1 Controlling Element Lifetime
+
+By partitioning an application into simple, modular components, each contained in a single
+QML file, you can achieve faster application startup time and better control over memory
+usage, and reduce the number of active-but-invisible elements in your application.
+
+\section2 Lazy Initialisation
+
+The QML engine does some tricky things to try to ensure that loading and initialisation of
+components doesn't cause frames to be skipped, however there is no better way to reduce
+startup time than to avoid doing work you don't need to do, and delaying the work until
+it is necessary. This may be achieved by using either \l Loader or creating components
\l {Dynamic Object Management in QML}{dynamically}.
-\section1 Property Types
+\section3 Using Loader
-When possible use a specific type, rather than variant, when declaring properties.
+The Loader is an element which allows dynamic loading and unloading of components.
-\code
-Item {
- property variant foo: 10
- property real bar: 10
+\list
+\o Using the "active" property of a Loader, initialisation can be delayed until required.
+\o Using the overloaded version of the "setSource()" function, initial property values can
+ be supplied.
+\o Setting the Loader \l {Loader::asynchronous}{asynchronous} property to true may also
+ improve fluidity while a component is instantiated.
+\endlist
- x: foo * 2
- y: bar *3
-}
-\endcode
+\section3 Using Dynamic Creation
+
+Developers can use the Qt.createComponent() function to create a component dynamically at
+runtime from within JavaScript, and then call createObject() to instantiate it. Depending
+on the ownership semantics specified in the call, the developer may have to delete the
+created object manually. See \l {Dynamic Object Management in QML} for more information.
+
+\section2 Destroy Unused Elements
+
+Elements which are invisible because they are a child of a non-visible element (e.g., the
+second tab in a tab-widget, while the first tab is shown) should be initialised lazily in
+most cases, and deleted when no longer in use, to avoid the ongoing cost of leaving them
+active (e.g., rendering, animations, property binding evaluation, etc).
+
+An item loaded with a Loader element may be released by resetting the "source" or
+"sourceComponent" property of the Loader, while other items may be explicitly
+released by calling destroy() on them. In some cases, it may be necessary to
+leave the item active, in which case it should be made invisible at the very least.
+
+See the upcoming section on Rendering for more information on active but invisible elements.
+
+\section1 Rendering
+
+The scene graph used for rendering in QtQuick 2.0 allows highly dynamic, animated user
+interfaces to be rendered fluidly at 60 FPS. There are some things which can
+dramatically decrease rendering performance, however, and developers should be careful
+to avoid these pitfalls wherever possible.
+
+\section2 Clipping
+
+Clipping is disabled by default, and should only be enabled when required.
+
+Clipping is a visual effect, NOT an optimization. It increases (rather than reduces)
+complexity for the renderer. If clipping is enabled, an item will clip its own painting,
+as well as the painting of its children, to its bounding rectangle. This stops the renderer
+from being able to reorder the drawing order of elements freely, resulting in a sub-optimal
+best-case scene graph traversal.
+
+Clipping inside a delegate is especially bad and should be avoided at all costs.
+
+\section2 Over-drawing and Invisible Elements
+
+If you have elements which are totally covered by other (opaque) elements, it is best to
+set their "visible" property to \c false or they will be needlessly drawn.
+
+Similarly, elements which are invisible (e.g., the second tab in a tab widget, while the
+first tab is shown) but need to be initialised at startup time (e.g., if the cost of
+instantiating the second tab takes too long to be able to do it only when the tab is
+activated), should have their "visible" property set to \c false, in order to avoid the
+cost of drawing them (although as previously explained, they will still incur the cost of
+any animations or bindings evaluation since they are still active).
+
+\section2 Manual Layouts
+
+The scene graph renderer is able to batch up certain operations to minimise the number of
+OpenGL state changes required. However, this optimization is only possible for the
+built-in layout elements provided by QtQuick 2.0, and cannot be applied to manual layouts.
-bar is faster than foo.
+Therefore, application developers should use the Row, Column, Grid, GridView and ListView
+elements instead of manual layouts wherever possible.
*/