[PATCH] winmm: Default to 1ms resolution like we used to
Myah Caron
qsniyg at protonmail.com
Fri Aug 14 17:44:40 CDT 2020
‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Friday, August 14, 2020 1:49 PM, Arkadiusz Hiler <ahiler at codeweavers.com> wrote:
> Wine's winmm is built on an 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 our assumption.
>
> This patch introduces a proper timeGetTime() that uses QueryPerformanceCounter().
> timeGetTime() is now also used instead of GetTickCount() internally by winmm.
>
> The research 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 | 44 +++++++++++++++++++++++++++++++++----------
> dlls/winmm/winmm.c | 12 ++++++------
> dlls/winmm/winmm.spec | 2 +-
> 3 files changed, 41 insertions(+), 17 deletions(-)
>
> diff --git a/dlls/winmm/time.c b/dlls/winmm/time.c
> index 22c89852a2..4d802703f1 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 periods) 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,26 @@ 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;
> - if (!QueryPerformanceCounter(&now))
> - WARN("QueryPerformanceCounter should not fail!\\n");
>
>
> - return now.QuadPart/10000;
> +}
>
> -
>
Sorry I'm a bit new so I'm not quite sure what the rules are regarding TRACEs, but would adding a TRACE here be an issue? I think it might be helpful for future debugging if there are any other issues with it.
> /**************************************************************************
>
> - timeSetEvent [WINMM.@]
>
>
>
> */
> @@ -272,7 +296,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
More information about the wine-devel
mailing list