[PATCH 2/3] winmm: Default to 1ms resolution like we used to.
Stefan Dösinger
stefandoesinger at gmail.com
Wed Aug 19 01:46:35 CDT 2020
Hi,
I think this patch could be split up into a patch that first replaces the GetTickCount calls and adds a timeGetTime implementation that (still) calls GetTickCount and a second patch that changes timeGetTime to use QueryPerformanceCounter.
That's just an IMHO though, I am fine with including the patch as-is too as it is pretty straightforward.
Cheers,
Stefan
> Am 18.08.2020 um 16:27 schrieb Arkadiusz Hiler <ahiler at codeweavers.com>:
>
> Wine's winmm is built on the assumption that we default to 1ms resolution
> without ever calling timeBeginPeriod(1).
>
> For simplicity timeGetTime() was backed by GetTickCount() which recently has
> changed its implementation and, in worst case scenario, returns a new value
> each ~16ms. This breaks the mentioned assumption.
>
> This patch introduces a proper timeGetTime() that uses QueryPerformanceCounter().
> timeGetTime() is now also used instead of GetTickCount() internally by winmm.
>
> The "observations" comment was updated with the latest findings.
>
> Fixes: cd215bb49bc2 ("kernel32: Use the user shared data to implement GetTickCount().")
> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49564
> Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
> ---
> dlls/winmm/time.c | 47 +++++++++++++++++++++++++++++++++----------
> dlls/winmm/winmm.c | 12 +++++------
> dlls/winmm/winmm.spec | 2 +-
> 3 files changed, 43 insertions(+), 18 deletions(-)
>
> diff --git a/dlls/winmm/time.c b/dlls/winmm/time.c
> index 22c89852a2..9bb948efbd 100644
> --- a/dlls/winmm/time.c
> +++ b/dlls/winmm/time.c
> @@ -74,17 +74,30 @@ static inline void link_timer( WINE_TIMERENTRY *timer )
>
> /*
> * Some observations on the behavior of winmm on Windows.
> - * First, the call to timeBeginPeriod(xx) can never be used
> - * to raise the timer resolution, only lower it.
> + *
> + * First, the call to timeBeginPeriod(xx) can never be used to
> + * lower the timer resolution (i.e. increase the update
> + * interval), only to increase the timer resolution (i.e. lower
> + * the update interval).
> *
> * Second, a brief survey of a variety of Win 2k and Win X
> * machines showed that a 'standard' (aka default) timer
> * resolution was 1 ms (Win9x is documented as being 1). However, one
> * machine had a standard timer resolution of 10 ms.
> *
> - * Further, if we set our default resolution to 1,
> - * the implementation of timeGetTime becomes GetTickCount(),
> - * and we can optimize the code to reduce overhead.
> + * Further, timeBeginPeriod(xx) also affects the resolution of
> + * wait calls such as NtDelayExecution() and
> + * NtWaitForMultipleObjects() which by default round up their
> + * timeout to the nearest multiple of 15.625ms across all Windows
> + * versions. In Wine all of those currently work with sub-1ms
> + * accuracy.
> + *
> + * Effective time resolution is a global value that is the max
> + * of the resolutions (i.e. min of update intervals) requested by
> + * all the processes. A lot of programs seem to do
> + * timeBeginPeriod(1) forcing it onto everyone else.
> + *
> + * Defaulting to 1ms accuracy in winmm should be safe.
> *
> * Additionally, a survey of Event behaviors shows that
> * if we request a Periodic event every 50 ms, then Windows
> @@ -97,6 +110,7 @@ static inline void link_timer( WINE_TIMERENTRY *timer )
> * no delays.
> *
> * Jeremy White, October 2004
> + * Arkadiusz Hiler, August 2020
> */
> #define MMSYSTIME_MININTERVAL (1)
> #define MMSYSTIME_MAXINTERVAL (65535)
> @@ -131,7 +145,7 @@ static int TIME_MMSysTimeCallback(void)
> }
>
> timer = LIST_ENTRY( ptr, WINE_TIMERENTRY, entry );
> - delta_time = timer->dwTriggerTime - GetTickCount();
> + delta_time = timer->dwTriggerTime - timeGetTime();
> if (delta_time > 0) break;
>
> list_remove( &timer->entry );
> @@ -242,16 +256,27 @@ void TIME_MMTimeStop(void)
> */
> MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize)
> {
> -
> if (wSize >= sizeof(*lpTime)) {
> - lpTime->wType = TIME_MS;
> - lpTime->u.ms = GetTickCount();
> -
> + lpTime->wType = TIME_MS;
> + lpTime->u.ms = timeGetTime();
> }
>
> return 0;
> }
>
> +/**************************************************************************
> + * timeGetTime [WINMM.@]
> + */
> +DWORD WINAPI timeGetTime(void)
> +{
> + LARGE_INTEGER now, freq;
> +
> + QueryPerformanceCounter(&now);
> + QueryPerformanceFrequency(&freq);
> +
> + return (now.QuadPart * 1000) / freq.QuadPart;
> +}
> +
> /**************************************************************************
> * timeSetEvent [WINMM.@]
> */
> @@ -272,7 +297,7 @@ MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc,
> return 0;
>
> lpNewTimer->wDelay = wDelay;
> - lpNewTimer->dwTriggerTime = GetTickCount() + wDelay;
> + lpNewTimer->dwTriggerTime = timeGetTime() + wDelay;
>
> /* FIXME - wResol is not respected, although it is not clear
> that we could change our precision meaningfully */
> diff --git a/dlls/winmm/winmm.c b/dlls/winmm/winmm.c
> index 9075a78f34..eea29ea61e 100644
> --- a/dlls/winmm/winmm.c
> +++ b/dlls/winmm/winmm.c
> @@ -1030,7 +1030,7 @@ static DWORD midistream_get_playing_position(WINE_MIDIStream* lpMidiStrm)
> case MSM_STATUS_PAUSED:
> return lpMidiStrm->dwElapsedMS;
> case MSM_STATUS_PLAYING:
> - return GetTickCount() - lpMidiStrm->dwStartTicks;
> + return timeGetTime() - lpMidiStrm->dwStartTicks;
> default:
> FIXME("Unknown playing status %hu\n", lpMidiStrm->status);
> return 0;
> @@ -1080,7 +1080,7 @@ static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWI
> /* FIXME: send out cc64 0 (turn off sustain pedal) on every channel */
> if (lpMidiStrm->status != MSM_STATUS_PLAYING) {
> EnterCriticalSection(&lpMidiStrm->lock);
> - lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwElapsedMS;
> + lpMidiStrm->dwStartTicks = timeGetTime() - lpMidiStrm->dwElapsedMS;
> lpMidiStrm->status = MSM_STATUS_PLAYING;
> LeaveCriticalSection(&lpMidiStrm->lock);
> }
> @@ -1090,7 +1090,7 @@ static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWI
> /* FIXME: send out cc64 0 (turn off sustain pedal) on every channel */
> if (lpMidiStrm->status != MSM_STATUS_PAUSED) {
> EnterCriticalSection(&lpMidiStrm->lock);
> - lpMidiStrm->dwElapsedMS = GetTickCount() - lpMidiStrm->dwStartTicks;
> + lpMidiStrm->dwElapsedMS = timeGetTime() - lpMidiStrm->dwStartTicks;
> lpMidiStrm->status = MSM_STATUS_PAUSED;
> LeaveCriticalSection(&lpMidiStrm->lock);
> }
> @@ -1126,7 +1126,7 @@ static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWI
> case WINE_MSM_HEADER:
> /* sets initial tick count for first MIDIHDR */
> if (!lpMidiStrm->dwStartTicks)
> - lpMidiStrm->dwStartTicks = GetTickCount();
> + lpMidiStrm->dwStartTicks = timeGetTime();
> lpMidiHdr = (LPMIDIHDR)msg->lParam;
> lpData = (LPBYTE)lpMidiHdr->lpData;
> TRACE("Adding %s lpMidiHdr=%p [lpData=0x%p dwBytesRecorded=%u/%u dwFlags=0x%08x size=%lu]\n",
> @@ -1235,8 +1235,8 @@ start_header:
>
> dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->position_usec / 1000;
>
> - TRACE("%u/%u/%u\n", dwToGo, GetTickCount(), me->dwDeltaTime);
> - while (dwToGo - (dwCurrTC = GetTickCount()) <= MAXLONG) {
> + TRACE("%u/%u/%u\n", dwToGo, timeGetTime(), me->dwDeltaTime);
> + while (dwToGo - (dwCurrTC = timeGetTime()) <= MAXLONG) {
> if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) {
> /* got a message, handle it */
> while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
> diff --git a/dlls/winmm/winmm.spec b/dlls/winmm/winmm.spec
> index 9c6ed2dfa8..d7c7379d77 100644
> --- a/dlls/winmm/winmm.spec
> +++ b/dlls/winmm/winmm.spec
> @@ -147,7 +147,7 @@
> @ stdcall timeEndPeriod(long)
> @ stdcall timeGetDevCaps(ptr long)
> @ stdcall timeGetSystemTime(ptr long)
> -@ stdcall timeGetTime() kernel32.GetTickCount
> +@ stdcall timeGetTime()
> @ stdcall timeKillEvent(long)
> @ stdcall timeSetEvent(long long ptr long long)
> @ stdcall waveInAddBuffer(long ptr long)
> --
> 2.28.0
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Message signed with OpenPGP
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20200819/81586f38/attachment-0001.sig>
More information about the wine-devel
mailing list