QEventDispatcherWin32: use SetCoalescableTimer for (Very)Coarse timers
The tolerance can be set per timer, unlike on Linux. Fixes: QTBUG-98316 Change-Id: I5e52dc5b093c43a3b678fffd16b788a30bcb9574 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
be0dc7fbb8
commit
5e2ce03510
@ -336,15 +336,47 @@ static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatch
|
|||||||
return wnd;
|
return wnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calculateNextTimeout(WinTimerInfo *t, quint64 currentTime)
|
static ULONG calculateNextTimeout(WinTimerInfo *t, quint64 currentTime)
|
||||||
{
|
{
|
||||||
uint interval = t->interval;
|
uint interval = t->interval;
|
||||||
if ((interval >= 20000u && t->timerType != Qt::PreciseTimer) || t->timerType == Qt::VeryCoarseTimer) {
|
ULONG tolerance = TIMERV_DEFAULT_COALESCING;
|
||||||
// round the interval, VeryCoarseTimers only have full second accuracy
|
switch (t->timerType) {
|
||||||
interval = ((interval + 500)) / 1000 * 1000;
|
case Qt::PreciseTimer:
|
||||||
|
// high precision timer is based on millisecond precision
|
||||||
|
// so no adjustment is necessary
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qt::CoarseTimer:
|
||||||
|
// this timer has up to 5% coarseness
|
||||||
|
// so our boundaries are 20 ms and 20 s
|
||||||
|
// below 20 ms, 5% inaccuracy is below 1 ms, so we convert to high precision
|
||||||
|
// above 20 s, 5% inaccuracy is above 1 s, so we convert to VeryCoarseTimer
|
||||||
|
if (interval >= 20000) {
|
||||||
|
t->timerType = Qt::VeryCoarseTimer;
|
||||||
|
} else if (interval <= 20) {
|
||||||
|
// no adjustment necessary
|
||||||
|
t->timerType = Qt::PreciseTimer;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
tolerance = interval / 20;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case Qt::VeryCoarseTimer:
|
||||||
|
// the very coarse timer is based on full second precision,
|
||||||
|
// so we round to closest second (but never to zero)
|
||||||
|
tolerance = 1000;
|
||||||
|
if (interval < 1000)
|
||||||
|
interval = 1000;
|
||||||
|
else
|
||||||
|
interval = (interval + 500) / 1000 * 1000;
|
||||||
|
currentTime = currentTime / 1000 * 1000;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->interval = interval;
|
t->interval = interval;
|
||||||
t->timeout = currentTime + interval;
|
t->timeout = currentTime + interval;
|
||||||
|
return tolerance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
|
void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
|
||||||
@ -354,13 +386,13 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
|
|||||||
Q_Q(QEventDispatcherWin32);
|
Q_Q(QEventDispatcherWin32);
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
calculateNextTimeout(t, qt_msectime());
|
ULONG tolerance = calculateNextTimeout(t, qt_msectime());
|
||||||
uint interval = t->interval;
|
uint interval = t->interval;
|
||||||
if (interval == 0u) {
|
if (interval == 0u) {
|
||||||
// optimization for single-shot-zero-timer
|
// optimization for single-shot-zero-timer
|
||||||
QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
|
QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
|
||||||
ok = true;
|
ok = true;
|
||||||
} else if (interval < 20u || t->timerType == Qt::PreciseTimer) {
|
} else if (tolerance == TIMERV_DEFAULT_COALESCING) {
|
||||||
// 3/2016: Although MSDN states timeSetEvent() is deprecated, the function
|
// 3/2016: Although MSDN states timeSetEvent() is deprecated, the function
|
||||||
// is still deemed to be the most reliable precision timer.
|
// is still deemed to be the most reliable precision timer.
|
||||||
t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc, DWORD_PTR(t),
|
t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc, DWORD_PTR(t),
|
||||||
@ -370,8 +402,10 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
|
|||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
// user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
|
// user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
|
||||||
ok = SetTimer(internalHwnd, t->timerId, interval, 0);
|
ok = SetCoalescableTimer(internalHwnd, t->timerId, interval, nullptr, tolerance);
|
||||||
}
|
}
|
||||||
|
if (!ok)
|
||||||
|
ok = SetTimer(internalHwnd, t->timerId, interval, nullptr);
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
|
qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
|
||||||
|
Loading…
Reference in New Issue
Block a user