fe2e89b5a3cf938a85f91850126d554e1e812e44
[profile/ivi/qtdeclarative.git] / doc / src / declarative / qdeclarativeperformance.qdoc
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the documentation of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:FDL$
10 ** GNU Free Documentation License
11 ** Alternatively, this file may be used under the terms of the GNU Free
12 ** Documentation License version 1.3 as published by the Free Software
13 ** Foundation and appearing in the file included in the packaging of
14 ** this file.
15 **
16 ** Other Usage
17 ** Alternatively, this file may be used in accordance with the terms
18 ** and conditions contained in a signed written agreement between you
19 ** and Nokia.
20 **
21 **
22 **
23 **
24 ** $QT_END_LICENSE$
25 **
26 ****************************************************************************/
27
28 /*!
29 \page qtquick2-performance.html
30 \inqmlmodule QtQuick 2
31 \title QML Performance
32
33 \tableofcontents
34
35 \section1 Timing Considerations
36
37 As an application developer, you must strive to allow the rendering engine
38 to achieve a consistent 60 frames-per-second refresh rate.  60 FPS means
39 that there is approximately 16 milliseconds between each frame in which
40 processing can be done, which includes the processing required to upload
41 the draw primitives to the graphics hardware.
42
43 In practice, this means that the application developer should use asynchronous,
44 event driven programming wherever possible, should use worker threads to do
45 significant processing, should never manually spin the event loop, and should
46 never spend more than a couple of milliseconds per frame within blocking functions.
47 Failure to do so will result in skipped frames, which has a drastic effect on the
48 user experience.
49
50 \section1 Profiling
51
52 The most important tip is: use the QML profiler included with Qt Creator.  Knowing
53 where time is spent in an application will allow you to focus on problem areas which
54 actually exist, rather than problem areas which potentially exist.  See the Qt Creator
55 manual for more information on how to use the QML profiling tool.
56
57 Determining which bindings are being run the most often, or which functions your
58 application is spending the most time in, will allow you to decide whether you need
59 to optimize the problem areas, or redesign some implementation details of your
60 application so that the performance is improved.  Attempting to optimize code without
61 profiling is likely to result in very minor rather than significant performance
62 improvements.
63
64 \section1 JavaScript
65
66 Most QML applications will have a large amount of JavaScript code in them, in the
67 form of dynamic functions, signal handlers, and property binding expressions.
68 This is not generally a problem (in fact, due to some optimizations in the QML engine
69 (bindings compiler, etc) it can for some use-cases be faster than calling a C++ function)
70 however care must be taken to ensure that unnecessary processing isn't triggered
71 accidentally.
72
73 \section2 Type-Conversion
74
75 One major cost of using JavaScript is that in most cases when a property from a QML
76 element is accessed, a JavaScript object with an external resource containing the
77 underlying C++ data (or a reference to it) is created.  In most cases, this is fairly
78 inexpensive, but in others it can be quite expensive.  One example of where it is
79 expensive is assigning a C++ QVariantMap Q_PROPERTY to a QML "variant" property.
80 Lists can also be expensive, although sequences of specific types (QList of int,
81 qreal, bool, QString, and QUrl) should be inexpensive; other list types involve an
82 expensive conversion cost (creating a new JavaScript Array, and adding new elements
83 one by one, with per-element conversion from C++ type instance to JavaScript value).
84
85 Converting between some basic property types (such as "string" and "url" properties)
86 can also be expensive.  Using the closest matching property type will avoid unnecessary
87 conversion.
88
89 If you must expose a QVariantMap to QML, use a "var" property rather than a "variant"
90 property.  In general, "property var" should be considered to be superior to
91 "property variant" for every use-case in QtQuick 2.0 (note that "property variant"
92 is marked as obsolete in the QtQuick 2.0 documentation), as it allows a true JavaScript
93 reference to be stored (which can reduce the number of conversions required in certain
94 expressions).
95
96 \section2 Resolving Properties
97
98 Property resolution takes time.  While in some cases the result of a lookup can be
99 cached and reused, it is always best to avoid doing unnecessary work altogether, if
100 possible.
101
102 In the following example, we have a block of code which is run often (in this case, it
103 is the contents of an explicit loop; but it could be a commonly-evaluated binding expression,
104 for example) and in it, we resolve the element with the "rect" id and its "color" property
105 multiple times:
106
107 \qml
108 // bad.qml
109 import QtQuick 2.0
110
111 Item {
112     width: 400
113     height: 200
114     Rectangle {
115         id: rect
116         anchors.fill: parent
117         color: "blue"
118     }
119
120     function printValue(which, value) {
121         console.log(which + " = " + value);
122     }
123
124     Component.onCompleted: {
125         var t0 = new Date();
126         for (var i = 0; i < 1000; ++i) {
127             printValue("red", rect.color.r);
128             printValue("green", rect.color.g);
129             printValue("blue", rect.color.b);
130             printValue("alpha", rect.color.a);
131         }
132         var t1 = new Date();
133         console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
134     }
135 }
136 \endqml
137
138 We could instead resolve the common base just once in the block:
139
140 \qml
141 // good.qml
142 import QtQuick 2.0
143
144 Item {
145     width: 400
146     height: 200
147     Rectangle {
148         id: rect
149         anchors.fill: parent
150         color: "blue"
151     }
152
153     function printValue(which, value) {
154         console.log(which + " = " + value);
155     }
156
157     Component.onCompleted: {
158         var t0 = new Date();
159         for (var i = 0; i < 1000; ++i) {
160             var rectColor = rect.color; // resolve the common base.
161             printValue("red", rectColor.r);
162             printValue("green", rectColor.g);
163             printValue("blue", rectColor.b);
164             printValue("alpha", rectColor.a);
165         }
166         var t1 = new Date();
167         console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
168
169     }
170 }
171 \endqml
172
173 Just this simple change results in a significant performance improvement.
174
175 \section2 Property Bindings
176
177 A property binding expression will be re-evaluated if any of the properties
178 it references are changed.  As such, binding expressions should be kept as
179 simple as possible.
180
181 If you have a loop where you do some processing, but only the final result
182 of the processing is important, it is often better to update a temporary
183 accumulator which you afterwards assign to the property you need to update,
184 rather than incrementally updating the property itself, in order to avoid
185 triggering re-evaluation of binding expressions during the intermediate
186 stages of accumulation.
187
188 The following contrived example illustrates this point:
189
190 \qml
191 // bad.qml
192 import QtQuick 2.0
193
194 Item {
195     id: root
196     width: 200
197     height: 200
198     property int accumulatedValue: 0
199
200     Text {
201         anchors.fill: parent
202         text: root.accumulatedValue.toString()
203         onTextChanged: console.log("text binding re-evaluated")
204     }
205
206     Component.onCompleted: {
207         var someData = [ 1, 2, 3, 4, 5, 20 ];
208         for (var i = 0; i < someData.length; ++i) {
209             accumulatedValue = accumulatedValue + someData[i];
210         }
211     }
212 }
213 \endqml
214
215 The loop in the onCompleted handler causes the "text" property binding to
216 be re-evaluated six times (which then results in any other property bindings
217 which rely on the text value, as well as the onTextChanged signal handler,
218 to be re-evaluated each time, and lays out the text for display each time).
219 This is clearly unnecessary in this case, since we really only care about
220 the final value of the accumulation.
221
222 It could be rewritten as follows:
223
224 \qml
225 // good.qml
226 import QtQuick 2.0
227
228 Item {
229     id: root
230     width: 200
231     height: 200
232     property int accumulatedValue: 0
233
234     Text {
235         anchors.fill: parent
236         text: root.accumulatedValue.toString()
237         onTextChanged: console.log("text binding re-evaluated")
238     }
239
240     Component.onCompleted: {
241         var someData = [ 1, 2, 3, 4, 5, 20 ];
242         var temp = accumulatedValue;
243         for (var i = 0; i < someData.length; ++i) {
244             temp = temp + someData[i];
245         }
246         accumulatedValue = temp;
247     }
248 }
249 \endqml
250
251 \section2 Sequence tips
252
253 As mentioned earlier, some sequence types are fast (eg, QList<int>, QList<qreal>,
254 QList<bool>, QList<QString>, QStringList and QList<QUrl>) while others will be
255 much slower.  Aside from using these types wherever possible instead of slower types,
256 there are some other performance-related semantics you need to be aware of to achieve
257 the best performance.
258
259 Firstly, there are two different implementations for sequence types: one for where
260 the sequence is a Q_PROPERTY of a QObject (we'll call this a reference sequence),
261 and another for where the sequence is returned from a Q_INVOKABLE function of a
262 QObject (we'll call this a copy sequence).
263
264 A reference sequence is read and written via QMetaObject::property() and thus is read
265 and written as a QVariant.  This means that changing the value of any element in the
266 sequence from JavaScript will result in three steps occurring: the complete sequence
267 will be read from the QObject (as a QVariant, but then cast to a sequence of the correct
268 type); the element at the specified index will be changed in that sequence; and the
269 complete sequence will be written back to the QObject (as a QVariant).
270
271 A copy sequence is far simpler as the actual sequence is stored in the JavaScript
272 object's resource data, so no read/modify/write cycle occurs (instead, the resource
273 data is modified directly).
274
275 Therefore, writes to elements of a reference sequence will be much slower than writes
276 to elements of a copy sequence.  In fact, writing to a single element of an N-element
277 reference sequence is equivalent in cost to assigning a N-element copy sequence to that
278 reference sequence, so you're usually better off modifying a temporary copy sequence
279 and then assigning the result to a reference sequence, during computation.
280
281 Assume the existence (and prior registration into the "Qt.example 1.0" namespace) of the
282 following C++ type:
283
284 \code
285 class SequenceTypeExample : public QQuickItem
286 {
287     Q_OBJECT
288     Q_PROPERTY (QList<qreal> qrealListProperty READ qrealListProperty WRITE setQrealListProperty NOTIFY qrealListPropertyChanged)
289
290 public:
291     SequenceTypeExample() : QQuickItem() { m_list << 1.1 << 2.2 << 3.3; }
292     ~SequenceTypeExample() {}
293
294     QList<qreal> qrealListProperty() const { return m_list; }
295     void setQrealListProperty(const QList<qreal> &list) { m_list = list; emit qrealListPropertyChanged(); }
296
297 signals:
298     void qrealListPropertyChanged();
299
300 private:
301     QList<qreal> m_list;
302 };
303 \endcode
304
305 The following example writes to elements of a reference sequence in a
306 tight loop, resulting in bad performance:
307
308 \qml
309 // bad.qml
310 import QtQuick 2.0
311 import Qt.example 1.0
312
313 SequenceTypeExample {
314     id: root
315     width: 200
316     height: 200
317
318     Component.onCompleted: {
319         var t0 = new Date();
320         qrealListProperty.length = 100;
321         for (var i = 0; i < 500; ++i) {
322             for (var j = 0; j < 100; ++j) {
323                 qrealListProperty[j] = j;
324             }
325         }
326         var t1 = new Date();
327         console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
328     }
329 }
330 \endqml
331
332 The QObject property read and write in the inner loop caused by the
333 \c{"qrealListProperty[j] = j"} expression makes this code very suboptimal.  Instead,
334 something functionally equivalent but much faster would be:
335
336 \qml
337 // good.qml
338 import QtQuick 2.0
339 import Qt.example 1.0
340
341 SequenceTypeExample {
342     id: root
343     width: 200
344     height: 200
345
346     Component.onCompleted: {
347         var t0 = new Date();
348         var someData = [1.1, 2.2, 3.3]
349         someData.length = 100;
350         for (var i = 0; i < 500; ++i) {
351             for (var j = 0; j < 100; ++j) {
352                 someData[j] = j;
353             }
354             qrealListProperty = someData;
355         }
356         var t1 = new Date();
357         console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
358     }
359 }
360 \endqml
361
362 Secondly, a change signal for the property is emitted if any element in it changes.
363 If you have many bindings to a particular element in a sequence property, it is better
364 to create a dynamic property which is bound to that element, and use that dynamic
365 property as the symbol in the binding expressions instead of the sequence element,
366 as it will only cause re-evaluation of bindings if its value changes.
367
368 This is an unusual use-case which most clients should never hit, but is worth being
369 aware of, in case you find yourself doing something like this:
370
371 \qml
372 // bad.qml
373 import QtQuick 2.0
374 import Qt.example 1.0
375
376 SequenceTypeExample {
377     id: root
378
379     property int firstBinding: qrealListProperty[1] + 10;
380     property int secondBinding: qrealListProperty[1] + 20;
381     property int thirdBinding: qrealListProperty[1] + 30;
382
383     Component.onCompleted: {
384         var t0 = new Date();
385         for (var i = 0; i < 1000; ++i) {
386             qrealListProperty[2] = i;
387         }
388         var t1 = new Date();
389         console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
390     }
391 }
392 \endqml
393
394 Note that even though only the element at index 2 is modified in the loop, the three
395 bindings will all be re-evaluated since the granularity of the change signal is that
396 the entire property has changed.  As such, adding an intermediate binding can
397 sometimes be beneficial:
398
399 \qml
400 // good.qml
401 import QtQuick 2.0
402 import Qt.example 1.0
403
404 SequenceTypeExample {
405     id: root
406
407     property int intermediateBinding: qrealListProperty[1]
408     property int firstBinding: intermediateBinding + 10;
409     property int secondBinding: intermediateBinding + 20;
410     property int thirdBinding: intermediateBinding + 30;
411
412     Component.onCompleted: {
413         var t0 = new Date();
414         for (var i = 0; i < 1000; ++i) {
415             qrealListProperty[2] = i;
416         }
417         var t1 = new Date();
418         console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
419     }
420 }
421 \endqml
422
423 In the above example, only the intermediate binding will be re-evaluated each time,
424 resulting in a significant performance increase.
425
426 \section2 Value-Type tips
427
428 Value-type properties (font, color, vector3d, etc) have similar QObject property
429 and change notification semantics to sequence type properties.  As such, the tips
430 given above for sequences are also applicable for value-type properties.  While
431 they are usually less of a problem with value-types (since the number of
432 sub-properties of a value-type is usually far less than the number of elements
433 in a sequence), any increase in the number of bindings being re-evaluated needlessly
434 will have a negative impact on performance.
435
436 \section2 Other JavaScript Objects
437
438 Different JavaScript engines provide different optimizations.  The JavaScript engine
439 which QtQuick 2 uses is optimized for object instantiation and property lookup, but
440 the optimizations which it provides relies on certain criteria.  If your application
441 does not meet the criteria, the JavaScript engine falls back to a "slow-path" mode
442 with much worse performance.  As such, always try to ensure you meet the following
443 criteria:
444
445 \list
446 \o Avoid using eval() if at all possible
447 \o Do not delete properties of objects
448 \o Try to maintain property-assignment order in different constructor functions
449 \endlist
450
451 \section1 Common Interface Elements
452
453 \section2 Text Elements
454
455 Calculating text layouts can be a slow operation.  Consider using the \c PlainText
456 format instead of \c StyledText wherever possible, as this reduces the amount of work
457 required of the layout engine.  If you cannot use \c PlainText (as you need to embed
458 images, or use tags to specify ranges of characters to have certain formatting (bold,
459 italic, etc) as opposed to the entire text) then you should use \c StyledText.
460
461 You should only use \c AutoText if the text might be (but probably isn't)
462 \c StyledText as this mode will incur a parsing cost.  The \c RichText mode should
463 not be used, as \c StyledText provides almost all of its features at a fraction of
464 its cost.
465
466 \section2 Images
467
468 Images are a vital part of any user interface.  Unfortunately, they are also a big
469 source of problems due to the time it takes to load them, the amount of memory they
470 consume, and the way in which they are used.
471
472 \section3 Asynchronous Loading
473
474 Images are often quite large, and so it is wise to ensure that loading an image doesn't
475 block the UI thread.  Set the "asynchronous" property of the QML Image element to
476 \c true to enable asynchronous loading of images from the local file system (remote
477 images are always loaded asynchronously) where this would not result in a negative impact
478 upon the aesthetics of the user interface.
479
480 Image elements with the "asynchronous" property set to \c true will load images in
481 a low-priority worker thread.
482
483 \section3 Explicit Source Size
484
485 If your application loads a large image but displays it in a small-sized element, set
486 the "sourceSize" property to the size of the element being rendered to ensure that the
487 smaller-scaled version of the image is kept in memory, rather than the large one.
488
489 Beware that changing the sourceSize will cause the image to be reloaded.
490
491 \section3 Avoid Run-time Composition
492
493 Also remember that you can avoid doing composition work at run-time by providing the
494 pre-composed image resource with your application (e.g., providing elements with shadow
495 effects).
496
497 \section2 Position Elements With Anchors
498
499 It is more efficient to use anchors rather than bindings to position items
500 relative to each other.  Consider this use of bindings to position rect2
501 relative to rect1:
502
503 \code
504 Rectangle {
505     id: rect1
506     x: 20
507     width: 200; height: 200
508 }
509 Rectangle {
510     id: rect2
511     x: rect1.x
512     y: rect1.y + rect1.height
513     width: rect1.width - 20
514     height: 200
515 }
516 \endcode
517
518 This is achieved more efficiently using anchors:
519
520 \code
521 Rectangle {
522     id: rect1
523     x: 20
524     width: 200; height: 200
525 }
526 Rectangle {
527     id: rect2
528     height: 200
529     anchors.left: rect1.left
530     anchors.top: rect1.bottom
531     anchors.right: rect1.right
532     anchors.rightMargin: 20
533 }
534 \endcode
535
536 \section1 Models and Views
537
538 Most applications will have at least one model feeding data to a view.  There are
539 some semantics which application developers need to be aware of, in order to achieve
540 maximal performance.
541
542 \section2 Custom C++ Models
543
544 It is often desirable to write your own custom model in C++ for use with a view in
545 QML.  While the optimal implementation of any such model will depend heavily on the
546 use-case it must fulfil, some general guidelines are as follows:
547
548 \list
549 \o Be as asynchronous as possible
550 \o Do all processing in a (low priority) worker thread
551 \o Batch up backend operations so that (potentially slow) I/O and IPC is minimised
552 \o Use a sliding slice window to cache results, whose parameters are determined with the help of profiling
553 \endlist
554
555 It is important to note that using a low-priority worker thread is recommended to
556 minimise the risk of starving the GUI thread (which could result in worse perceived
557 performance).  Also, remember that synchronisation and locking mechanisms can be a
558 significant cause of slow performance, and so care should be taken to avoid
559 unnecessary locking.
560
561 \section2 ListModel
562
563 QML provides a ListModel element which can be used to feed data to a ListView.
564 It should suffice for most use-cases and be relatively performant so long as
565 it is used correctly.
566
567 \section3 Populate Within A Worker Thread
568
569 ListModel elements can be populated in a (low priority) worker thread in JavaScript.  The
570 developer must explicitly call "sync()" on the ListModel from within the WorkerScript to
571 have the changes synchronised to the main thread.  See the WorkerScript documentation
572 for more information.
573
574 \section3 Don't Use Dynamic Roles
575
576 The ListModel element in QtQuick 2.0 is much more performant than in QtQuick 1.0.  The
577 performance improvements mainly come from assumptions about the type of roles within each
578 element in a given model - if the type doesn't change, the caching performance improves
579 dramatically.  If the type can change dynamically from element to element, this optimization
580 becomes impossible, and the performance of the model will be an order of magnitude worse.
581
582 Therefore, dynamic typing is disabled by default; the developer must specifically set
583 the boolean "dynamicRoles" property of the model to enable dynamic typing (and suffer
584 the attendant performance degradation).  We recommend that you do not use dynamic typing
585 if it is possible to redesign your application to avoid it.
586
587 \section2 Views
588
589 View delegates should be kept as simple as possible.  Have just enough QML in the delegate
590 to display the necessary information.  Any additional functionality which is not immediately
591 required (e.g., if it displays more information when clicked) should not be created until
592 needed (see the upcoming section on lazy initialisation).
593
594 The following list is a good summary of things to keep in mind when designing a delegate:
595 \list
596 \o The fewer elements that are in a delegate, the faster they can be created, and thus
597    the faster the view can be scrolled.
598 \o Keep the number of bindings in a delegate to a minimum; in particular, use anchors
599    rather than bindings for relative positioning within a delegate.
600 \o Set a cacheBuffer to allow asynchronous creation of delegates outside the visible area.
601    Be mindful that this creates additional delegates and therefore the size of the
602    cacheBuffer must be balanced against additional memory usage.
603 \o Avoid using ShaderEffect elements within delegates.
604 \o Never enable clipping on a delegate.
605 \endlist
606
607 \section1 Visual Effects
608
609 QtQuick 2 includes several features which allow developers and designers to create
610 exceptionally appealing user interfaces.  Fluidity and dynamic transitions as well
611 as visual effects can be used to great effect in an application, but some care must
612 be taken when using some of the features in QML as they can have performance implications.
613
614 \section2 Animations
615
616 In general, animating a property will cause any bindings which reference that property
617 to be re-evaluated.  Usually, this is what is desired but in other cases it may be better
618 to disable the binding prior to performing the animation, and then reassign the binding
619 once the animation has completed.
620
621 Avoid running JavaScript during animation.  For example, running a complex JavaScript
622 expression for each frame of an x property animation should be avoided.
623
624 Developers should be especially careful using script animations, as these are run in the main
625 thread (and therefore can cause frames to be skipped if they take too long to complete).
626
627 \section2 Particles
628
629 The QtQuick 2.0 Particles module allows beautiful particle effects to be integrated
630 seamlessly into user interfaces.  However every platform has different graphics hardware
631 capabilities, and the Particles module is unable to limit parameters to what your hardware
632 can gracefully support.  The more particles you attempt to render (and the larger they are),
633 the faster your graphics hardware will need to be in order to render at 60 FPS.  Affecting
634 more particles requires a faster CPU.  It is therefore important to test all
635 particle effects on your target platform carefully, to calibrate the number and size of
636 particles you can render at 60 FPS.
637
638 It should be noted that a particle system can be disabled when not in use
639 (e.g., on a non-visible element) to avoid doing unnecessary simulation.
640
641 See the \l{Qt Quick Particle System Performance Guide} for more in-depth information.
642
643 \section2 Shaders
644
645 Shaders written in GLSL allow for complex transformations and visual effects to be written,
646 however they should be used with care.  Using a ShaderEffectSource causes a scene to
647 prerendered into an FBO before it can be drawn.  This extra overhead is quite expensive.
648
649 A ShaderEffect element can imply a ShaderEffectSource (and the indirect rendering costs
650 associated with that) and also involves uploading a vertex and fragment shader program
651 (which is then compiled into a GLSL shader).  Each fragment shader runs once for every
652 pixel of the scene, and so these should be kept as simple as possible.
653
654 \section1 Controlling Element Lifetime
655
656 By partitioning an application into simple, modular components, each contained in a single
657 QML file, you can achieve faster application startup time and better control over memory
658 usage, and reduce the number of active-but-invisible elements in your application.
659
660 \section2 Lazy Initialisation
661
662 The QML engine does some tricky things to try to ensure that loading and initialisation of
663 components doesn't cause frames to be skipped, however there is no better way to reduce
664 startup time than to avoid doing work you don't need to do, and delaying the work until
665 it is necessary.  This may be achieved by using either \l Loader or creating components
666 \l {Dynamic Object Management in QML}{dynamically}.
667
668 \section3 Using Loader
669
670 The Loader is an element which allows dynamic loading and unloading of components.
671
672 \list
673 \o Using the "active" property of a Loader, initialisation can be delayed until required.
674 \o Using the overloaded version of the "setSource()" function, initial property values can
675    be supplied.
676 \o Setting the Loader \l {Loader::asynchronous}{asynchronous} property to true may also
677    improve fluidity while a component is instantiated.
678 \endlist
679
680 \section3 Using Dynamic Creation
681
682 Developers can use the Qt.createComponent() function to create a component dynamically at
683 runtime from within JavaScript, and then call createObject() to instantiate it.  Depending
684 on the ownership semantics specified in the call, the developer may have to delete the
685 created object manually.  See \l {Dynamic Object Management in QML} for more information.
686
687 \section2 Destroy Unused Elements
688
689 Elements which are invisible because they are a child of a non-visible element (e.g., the
690 second tab in a tab-widget, while the first tab is shown) should be initialised lazily in
691 most cases, and deleted when no longer in use, to avoid the ongoing cost of leaving them
692 active (e.g., rendering, animations, property binding evaluation, etc).
693
694 An item loaded with a Loader element may be released by resetting the "source" or
695 "sourceComponent" property of the Loader, while other items may be explicitly
696 released by calling destroy() on them.  In some cases, it may be necessary to
697 leave the item active, in which case it should be made invisible at the very least.
698
699 See the upcoming section on Rendering for more information on active but invisible elements.
700
701 \section1 Rendering
702
703 The scene graph used for rendering in QtQuick 2.0 allows highly dynamic, animated user
704 interfaces to be rendered fluidly at 60 FPS.  There are some things which can
705 dramatically decrease rendering performance, however, and developers should be careful
706 to avoid these pitfalls wherever possible.
707
708 \section2 Clipping
709
710 Clipping is disabled by default, and should only be enabled when required.
711
712 Clipping is a visual effect, NOT an optimization.  It increases (rather than reduces)
713 complexity for the renderer.  If clipping is enabled, an item will clip its own painting,
714 as well as the painting of its children, to its bounding rectangle.  This stops the renderer
715 from being able to reorder the drawing order of elements freely, resulting in a sub-optimal
716 best-case scene graph traversal.
717
718 Clipping inside a delegate is especially bad and should be avoided at all costs.
719
720 \section2 Over-drawing and Invisible Elements
721
722 If you have elements which are totally covered by other (opaque) elements, it is best to
723 set their "visible" property to \c false or they will be needlessly drawn.
724
725 Similarly, elements which are invisible (e.g., the second tab in a tab widget, while the
726 first tab is shown) but need to be initialised at startup time (e.g., if the cost of
727 instantiating the second tab takes too long to be able to do it only when the tab is
728 activated), should have their "visible" property set to \c false, in order to avoid the
729 cost of drawing them (although as previously explained, they will still incur the cost of
730 any animations or bindings evaluation since they are still active).
731
732 \section2 Manual Layouts
733
734 The scene graph renderer is able to batch up certain operations to minimise the number of
735 OpenGL state changes required.  However, this optimization is only possible for the
736 built-in layout elements provided by QtQuick 2.0, and cannot be applied to manual layouts.
737
738 Therefore, application developers should use the Row, Column, Grid, GridView and ListView
739 elements instead of manual layouts wherever possible.
740
741 */