1 /*
2 * Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "KisStrokeSpeedMonitor.h"
20
21 #include <QGlobalStatic>
22 #include <QMutex>
23 #include <QMutexLocker>
24
25 #include <KisRollingMeanAccumulatorWrapper.h>
26 #include "kis_paintop_preset.h"
27 #include "kis_paintop_settings.h"
28
29 #include "kis_config.h"
30 #include "kis_config_notifier.h"
31 #include "KisImageConfigNotifier.h"
32
33
34 Q_GLOBAL_STATIC(KisStrokeSpeedMonitor, s_instance)
35
36
37 struct KisStrokeSpeedMonitor::Private
38 {
39 static const int averageWindow = 10;
40
PrivateKisStrokeSpeedMonitor::Private41 Private()
42 : avgCursorSpeed(averageWindow),
43 avgRenderingSpeed(averageWindow),
44 avgFps(averageWindow)
45 {
46 }
47
48 KisRollingMeanAccumulatorWrapper avgCursorSpeed;
49 KisRollingMeanAccumulatorWrapper avgRenderingSpeed;
50 KisRollingMeanAccumulatorWrapper avgFps;
51
52 qreal cachedAvgCursorSpeed = 0;
53 qreal cachedAvgRenderingSpeed = 0;
54 qreal cachedAvgFps = 0;
55
56 qreal lastCursorSpeed = 0;
57 qreal lastRenderingSpeed = 0;
58 qreal lastFps = 0;
59 bool lastStrokeSaturated = false;
60
61 QByteArray lastPresetMd5;
62 QString lastPresetName;
63 qreal lastPresetSize = 0;
64
65 bool haveStrokeSpeedMeasurement = true;
66
67 QMutex mutex;
68 };
69
KisStrokeSpeedMonitor()70 KisStrokeSpeedMonitor::KisStrokeSpeedMonitor()
71 : m_d(new Private())
72 {
73 connect(KisImageConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetAccumulatedValues()));
74 connect(KisImageConfigNotifier::instance(), SIGNAL(configChanged()), SIGNAL(sigStatsUpdated()));
75 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
76
77 slotConfigChanged();
78 }
79
~KisStrokeSpeedMonitor()80 KisStrokeSpeedMonitor::~KisStrokeSpeedMonitor()
81 {
82 }
83
instance()84 KisStrokeSpeedMonitor *KisStrokeSpeedMonitor::instance()
85 {
86 return s_instance;
87 }
88
haveStrokeSpeedMeasurement() const89 bool KisStrokeSpeedMonitor::haveStrokeSpeedMeasurement() const
90 {
91 return m_d->haveStrokeSpeedMeasurement;
92 }
93
setHaveStrokeSpeedMeasurement(bool value)94 void KisStrokeSpeedMonitor::setHaveStrokeSpeedMeasurement(bool value)
95 {
96 m_d->haveStrokeSpeedMeasurement = value;
97 }
98
resetAccumulatedValues()99 void KisStrokeSpeedMonitor::resetAccumulatedValues()
100 {
101 m_d->avgCursorSpeed.reset(m_d->averageWindow);
102 m_d->avgRenderingSpeed.reset(m_d->averageWindow);
103 m_d->avgFps.reset(m_d->averageWindow);
104 }
105
slotConfigChanged()106 void KisStrokeSpeedMonitor::slotConfigChanged()
107 {
108 KisConfig cfg(true);
109 m_d->haveStrokeSpeedMeasurement = cfg.enableBrushSpeedLogging();
110 resetAccumulatedValues();
111 emit sigStatsUpdated();
112 }
113
notifyStrokeFinished(qreal cursorSpeed,qreal renderingSpeed,qreal fps,KisPaintOpPresetSP preset)114 void KisStrokeSpeedMonitor::notifyStrokeFinished(qreal cursorSpeed, qreal renderingSpeed, qreal fps, KisPaintOpPresetSP preset)
115 {
116 if (qFuzzyCompare(cursorSpeed, 0.0) || qFuzzyCompare(renderingSpeed, 0.0)) return;
117
118 QMutexLocker locker(&m_d->mutex);
119
120 const bool isSamePreset =
121 m_d->lastPresetName == preset->name() &&
122 qFuzzyCompare(m_d->lastPresetSize, preset->settings()->paintOpSize());
123
124 //ENTER_FUNCTION() << ppVar(isSamePreset);
125
126 if (!isSamePreset) {
127 resetAccumulatedValues();
128 m_d->lastPresetName = preset->name();
129 m_d->lastPresetSize = preset->settings()->paintOpSize();
130 }
131
132 m_d->lastCursorSpeed = cursorSpeed;
133 m_d->lastRenderingSpeed = renderingSpeed;
134 m_d->lastFps = fps;
135
136
137 static const qreal saturationSpeedThreshold = 0.30; // cursor speed should be at least 30% higher
138 m_d->lastStrokeSaturated = cursorSpeed / renderingSpeed > (1.0 + saturationSpeedThreshold);
139
140
141 if (m_d->lastStrokeSaturated) {
142 m_d->avgCursorSpeed(cursorSpeed);
143 m_d->avgRenderingSpeed(renderingSpeed);
144 m_d->avgFps(fps);
145
146 m_d->cachedAvgCursorSpeed = m_d->avgCursorSpeed.rollingMean();
147 m_d->cachedAvgRenderingSpeed = m_d->avgRenderingSpeed.rollingMean();
148 m_d->cachedAvgFps = m_d->avgFps.rollingMean();
149 }
150
151 emit sigStatsUpdated();
152
153
154 ENTER_FUNCTION() <<
155 QString(" CS: %1 RS: %2 FPS: %3 %4")
156 .arg(m_d->lastCursorSpeed, 5)
157 .arg(m_d->lastRenderingSpeed, 5)
158 .arg(m_d->lastFps, 5)
159 .arg(m_d->lastStrokeSaturated ? "(saturated)" : "");
160 ENTER_FUNCTION() <<
161 QString("ACS: %1 ARS: %2 AFPS: %3")
162 .arg(m_d->cachedAvgCursorSpeed, 5)
163 .arg(m_d->cachedAvgRenderingSpeed, 5)
164 .arg(m_d->cachedAvgFps, 5);
165 }
166
lastPresetName() const167 QString KisStrokeSpeedMonitor::lastPresetName() const
168 {
169 return m_d->lastPresetName;
170 }
171
lastPresetSize() const172 qreal KisStrokeSpeedMonitor::lastPresetSize() const
173 {
174 return m_d->lastPresetSize;
175 }
176
lastCursorSpeed() const177 qreal KisStrokeSpeedMonitor::lastCursorSpeed() const
178 {
179 return m_d->lastCursorSpeed;
180 }
181
lastRenderingSpeed() const182 qreal KisStrokeSpeedMonitor::lastRenderingSpeed() const
183 {
184 return m_d->lastRenderingSpeed;
185 }
186
lastFps() const187 qreal KisStrokeSpeedMonitor::lastFps() const
188 {
189 return m_d->lastFps;
190 }
191
lastStrokeSaturated() const192 bool KisStrokeSpeedMonitor::lastStrokeSaturated() const
193 {
194 return m_d->lastStrokeSaturated;
195 }
196
avgCursorSpeed() const197 qreal KisStrokeSpeedMonitor::avgCursorSpeed() const
198 {
199 return m_d->cachedAvgCursorSpeed;
200 }
201
avgRenderingSpeed() const202 qreal KisStrokeSpeedMonitor::avgRenderingSpeed() const
203 {
204 return m_d->cachedAvgRenderingSpeed;
205 }
206
avgFps() const207 qreal KisStrokeSpeedMonitor::avgFps() const
208 {
209 return m_d->cachedAvgFps;
210 }
211