1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qquick3dparticlesystemlogging_p.h" |
5 | #include <float.h> // FLT_MAX |
6 | |
7 | QT_BEGIN_NAMESPACE |
8 | |
9 | /*! |
10 | \qmltype ParticleSystem3DLogging |
11 | \inherits QtObject |
12 | \inqmlmodule QtQuick3D.Particles3D |
13 | \brief Provides information of the particle system. |
14 | \since 6.2 |
15 | |
16 | The \c ParticleSystem3DLogging type provides information about particle system statistics. |
17 | This element cannot be created directly, but can be retrieved from a \l ParticleSystem3D. |
18 | */ |
19 | |
20 | QQuick3DParticleSystemLogging::QQuick3DParticleSystemLogging(QObject *parent) |
21 | : QObject(parent) |
22 | { |
23 | } |
24 | |
25 | /*! |
26 | \qmlproperty int ParticleSystem3DLogging::loggingInterval |
27 | |
28 | This property defines in milliseconds how often the logging data is updated. |
29 | Longer update time increases the accuracy of \l {ParticleSystem3DLogging::time}{time} and |
30 | \l {ParticleSystem3DLogging::timeAverage}{timeAverage}, while shorter update times keep |
31 | the data more up to date. |
32 | |
33 | The default value is \c 1000. |
34 | */ |
35 | |
36 | int QQuick3DParticleSystemLogging::loggingInterval() const |
37 | { |
38 | return m_loggingInterval; |
39 | } |
40 | |
41 | void QQuick3DParticleSystemLogging::setLoggingInterval(int interval) |
42 | { |
43 | if (m_loggingInterval == interval) |
44 | return; |
45 | |
46 | m_loggingInterval = interval; |
47 | Q_EMIT loggingIntervalChanged(); |
48 | } |
49 | |
50 | /*! |
51 | \qmlproperty int ParticleSystem3DLogging::updates |
52 | \readonly |
53 | |
54 | This property holds the amount of particle system updates since the last logging. |
55 | When \a loggingInterval is 1000 (default), this can be considered to match the fps. |
56 | */ |
57 | int QQuick3DParticleSystemLogging::updates() const |
58 | { |
59 | return m_updates; |
60 | } |
61 | |
62 | /*! |
63 | \qmlproperty int ParticleSystem3DLogging::particlesMax |
64 | \readonly |
65 | |
66 | This property holds the maximum amount of particles in this system. |
67 | Maximum amount is the sum of system particles \l {Particle3D::maxAmount}{maxAmount} properties. |
68 | */ |
69 | int QQuick3DParticleSystemLogging::particlesMax() const |
70 | { |
71 | return m_particlesMax; |
72 | } |
73 | |
74 | /*! |
75 | \qmlproperty int ParticleSystem3DLogging::particlesUsed |
76 | \readonly |
77 | |
78 | This property holds the amount of particles currently in use in this system. |
79 | This value should be close to \l particlesMax at some point of particle system |
80 | animation. If it is much smaller, consider decreasing \l {Particle3D::maxAmount}{maxAmount} values. |
81 | If it reaches \l particlesMax, particles are used effectively but it can also mean that |
82 | particles are reused before they reach the end of their \l {ParticleEmitter3D::lifeSpan}{lifeSpan}. |
83 | In this case, consider increasing the \l {Particle3D::maxAmount}{maxAmount} values. |
84 | */ |
85 | int QQuick3DParticleSystemLogging::particlesUsed() const |
86 | { |
87 | return m_particlesUsed; |
88 | } |
89 | |
90 | /*! |
91 | \qmlproperty real ParticleSystem3DLogging::time |
92 | \readonly |
93 | |
94 | This property holds the time in milliseconds used for emitting and animating particles |
95 | in each frame. |
96 | */ |
97 | float QQuick3DParticleSystemLogging::time() const |
98 | { |
99 | return m_time; |
100 | } |
101 | |
102 | /*! |
103 | \qmlproperty real ParticleSystem3DLogging::timeAverage |
104 | \readonly |
105 | |
106 | This property holds the average time in milliseconds used for emitting and animating |
107 | particles in each frame. Average is calculated from the middle 50% of the past |
108 | max 100 logging updates. So when \l loggingInterval is 1000, this represents an |
109 | average \l time in past 100 seconds. This can be used for measuring the performance |
110 | of current particle system. |
111 | */ |
112 | float QQuick3DParticleSystemLogging::timeAverage() const |
113 | { |
114 | return m_timeAverage; |
115 | } |
116 | |
117 | /*! |
118 | \qmlproperty real ParticleSystem3DLogging::timeDeviation |
119 | \since 6.3 |
120 | \readonly |
121 | |
122 | This property holds the deviation of the average times in milliseconds. |
123 | The value is the difference between maximum and minimum values of middle 50% |
124 | of the results, also called interquartile range (IQR). |
125 | Bigger deviation means that the times fluctuate more so \l timeAverage |
126 | can be considered to be less accurate. |
127 | */ |
128 | float QQuick3DParticleSystemLogging::timeDeviation() const |
129 | { |
130 | return m_timeDeviation; |
131 | } |
132 | |
133 | void QQuick3DParticleSystemLogging::updateTimes(qint64 time) |
134 | { |
135 | m_time = float(time / 1000000.0) / m_updates; |
136 | |
137 | m_totalTimesList.append(t: m_time); |
138 | |
139 | // Keep max amount of times stored and remove the oldest values |
140 | const int MAX_TIMES = 100; |
141 | if (m_totalTimesList.size() > MAX_TIMES) |
142 | m_totalTimesList.removeFirst(); |
143 | |
144 | auto sortedTimes = m_totalTimesList; |
145 | std::sort(first: sortedTimes.begin(), last: sortedTimes.end()); |
146 | |
147 | // Calculate average from stored times. |
148 | // Only take into account the middle 50% of the values. |
149 | // This gives us interquartile range (IQR) and the average time among IQR. |
150 | if (sortedTimes.size() > 5) { |
151 | // Skip 25%, count 50%, so maxItem at 75% |
152 | const int skipAmount = roundf(x: 0.25f * float(sortedTimes.size())); |
153 | const int maxItem = sortedTimes.size() - skipAmount; |
154 | int countAmount = 0; |
155 | double totalTime = 0.0; |
156 | float maxTime = 0.0f; |
157 | float minTime = FLT_MAX; |
158 | for (int i = skipAmount; i < maxItem; i++) { |
159 | const float time = sortedTimes.at(i); |
160 | totalTime += time; |
161 | minTime = std::min(a: minTime, b: time); |
162 | maxTime = std::max(a: maxTime, b: time); |
163 | countAmount++; |
164 | } |
165 | m_timeAverage = float(totalTime / countAmount); |
166 | m_timeDeviation = maxTime - minTime; |
167 | Q_EMIT timeAverageChanged(); |
168 | Q_EMIT timeDeviationChanged(); |
169 | } |
170 | Q_EMIT timeChanged(); |
171 | } |
172 | |
173 | void QQuick3DParticleSystemLogging::resetData() |
174 | { |
175 | m_updates = 0; |
176 | m_particlesMax = 0; |
177 | m_particlesUsed = 0; |
178 | m_time = 0.0f; |
179 | m_timeAverage = 0.0f; |
180 | m_timeDeviation = 0.0f; |
181 | m_totalTimesList.clear(); |
182 | Q_EMIT updatesChanged(); |
183 | Q_EMIT particlesMaxChanged(); |
184 | Q_EMIT particlesUsedChanged(); |
185 | Q_EMIT timeChanged(); |
186 | Q_EMIT timeAverageChanged(); |
187 | Q_EMIT timeDeviationChanged(); |
188 | } |
189 | |
190 | QT_END_NAMESPACE |
191 | |