Reputation: 13691
Consider this example:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: appWindow
width: 1024
height: 800
visible: true
Rectangle {
id: rect1
property bool active: true
opacity: active ? 1 : 0
height: 300 * opacity
width: 300 * opacity
Behavior on opacity { NumberAnimation { duration: 1000 } }
MouseArea { anchors.fill: parent; onClicked: parent.active = false }
color: 'cornflowerblue'
}
Rectangle {
id: rect2
property bool active: true
x: 305
opacity: active ? 1 : 0
height: active ? 300 : 0
width: active ? 300 : 0
Behavior on opacity { NumberAnimation { duration: 1000 } }
Behavior on height { NumberAnimation { duration: 1000 } }
Behavior on width { NumberAnimation { duration: 1000 } }
MouseArea { anchors.fill: parent; onClicked: parent.active = false }
color: 'steelblue'
}
}
I have two Rectangle
s with the same observable behavior: when clicked, they fade both in opacity and size.
Internally, it differs in the amount of Animation
s, that are running concurrently - either 1 or 3:
As of now, I mainly use the pattern form rect1
and only in cases where the bindings would get unneccessarily complex rect2
. However I wonder, if the animation system has some magic, that optimizes the animation of a single property, while the binding might be less performant.
In which usecases it is beneficial to use pattern rect1
and when it would be wiser to use the method of rect2
?
EDIT There is also a third option which moves, what possible, to the render thread via OpacityAnimator
. Now I can't bind to the opacity anymore, as it will jump to 0 at the end of the animation.
Rectangle {
id: rect3
property bool active: true
opacity: active ? 1 : 0
height: active ? 300 : 0
x: 610
width: height
Behavior on opacity { OpacityAnimator { duration: 1000 } }
Behavior on height { NumberAnimation { duration: 1000 } }
MouseArea { anchors.fill: parent; onClicked: parent.active = false }
color: 'dodgerblue'
}
EDIT 2 To adress the Answer of Ansh Kumar:
This is an excerpt from the QML Profiler
. You can see, that during the animation of rect2
there are neither bindings nor JavaScript running, unlike during the times where height
and width
are (efficiently) bound to the opacity
in rect1
or the width
is (efficiently) bound to the height
in rect3
.
Further the source of the animations shows little trace of JS
. I couldn't examine it into all it's depths, but it seems, that only a ScriptAction
gets a QQMLScriptString
and the rest has only the cost of converting the input from var
to the right type (if a type is specified by using a concrete animation such as NumberAnimation
).
Further, as far as I can see, there is not a loop per animation involved, but all animations feature some kind of update()
-function or so, that is called (when running/registered) by a single loop (AnimationTimer
). But this is where I am already unsure about.
Now the question remains: Is the implementation of the animations more efficient than the optimized JS environment especially as multiple objects are created and stuff.
Upvotes: 3
Views: 1683
Reputation: 2296
There are two types of bindings in QML: optimized and non-optimized bindings. It is a good idea to keep binding expressions as simple as possible, since the QML engine makes use of an optimized binding expression evaluator which can evaluate simple binding expressions without needing to switch into a full JavaScript execution environment. These optimized bindings are evaluated far more efficiently than more complex (non-optimized) bindings. The basic requirement for optimization of bindings is that the type information of every symbol accessed must be known at compile time.
Bindings are quickest when they know the type of objects and properties they are working with. Animating a property will cause any bindings which reference that property to be re-evaluated. Usually, this is what is desired. The opacity
, height
and width
in rect2
are re-evaluated into a full JavaScript execution environment whereas in rect1
; width
and height
goes through an optimized binding expression evaluator and optimized to give more efficient binding since their type of object is known at compile time. Check binding and also animations for more details.
EDIT
You were right about evaluation being done in C++ environment. I found following informations.
Rendering engine should achieve a consistent 60 frames-per-second refresh rate. 60 FPS means that there is approximately 16 milliseconds (exactly 16.6667 milliseconds) between each frame in which processing can be done, which includes the processing required to upload the draw primitives to the graphics hardware. This shows that the animation is in sync with the vertical refresh, so once every 16.66 ms, and exactly once pr frame.
while (animationIsRunning) {
processEvents();
advanceAnimations();
paintQMLScene();
swapAndBlockForNextVSync();
}
So, in rect1
you have set duration: 1000
and binded height
with opacity
(height: 300 * opacity
) similarly width
with opacity
, so binding should be called around 60 times ? If you see QML profiler
output of statistics
you will find following
As expected number of calls are around 60 (exactly 63). Now if you change duration to 2000, number of calls will be doubled.
Since, 300 * opacity
has to be calculated, so QML
should call JavaScript environment around 60 times (when duration: 1000
)
As expected it was called around 60 times.
What about the NumberAnimation
, is it implemented in JavaScript or C++ ? Definitely, you were right about it being implemented in C++, Here is the link to its declaration . So, in rect1
we have used NumberAnimation
one time and in rect2
we have used it 3 times. So, total of 4 instances of NumberAnimation
should be created.
So, rect1
has a total of around 120 bindings and JavaScript calls whereas in in rect2
there is no binding and JavaScript calls, so animation of rect2
should be faster, but the question is, will there be any significant improvements? Since, free version of QtCreator does not comes with CPU analyzer I was not able to study that part of the question (CPU Usage Qt). If anyone has commercial version of Qt, please update me about my hypothesis. I really think that rect2
is the best for usage as number of calls are reduced.
Upvotes: 2