[WINMM] Improve implementation of timeGetTime, timeBeginPeriod, timeEndPeriod (#2933)
[reactos.git] / dll / win32 / winmm / time.c
index 5da3f2f..832a45b 100644 (file)
@@ -47,6 +47,7 @@ static    LPWINE_TIMERENTRY   TIME_TimersList;
 static    HANDLE                TIME_hKillEvent;
 static    HANDLE                TIME_hWakeEvent;
 static    BOOL                  TIME_TimeToDie = TRUE;
+static    LARGE_INTEGER         TIME_qpcFreq;
 
 /*
  * Some observations on the behavior of winmm on Windows.
@@ -422,7 +423,14 @@ MMRESULT WINAPI timeGetDevCaps(LPTIMECAPS lpCaps, UINT wSize)
 MMRESULT WINAPI timeBeginPeriod(UINT wPeriod)
 {
     if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
-       return TIMERR_NOCANDO;
+        return TIMERR_NOCANDO;
+
+    /*  High resolution timer requested, use QPC */
+    if (wPeriod <= 5 && TIME_qpcFreq.QuadPart == 0)
+    {
+        if (QueryPerformanceFrequency(&TIME_qpcFreq))
+            TIME_qpcFreq.QuadPart /= 1000;
+    }
 
     if (wPeriod > MMSYSTIME_MININTERVAL)
     {
@@ -438,7 +446,11 @@ MMRESULT WINAPI timeBeginPeriod(UINT wPeriod)
 MMRESULT WINAPI timeEndPeriod(UINT wPeriod)
 {
     if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
-       return TIMERR_NOCANDO;
+        return TIMERR_NOCANDO;
+
+    /*  High resolution timer no longer requested, stop using QPC */
+    if (wPeriod <= 5 && TIME_qpcFreq.QuadPart != 0)
+        TIME_qpcFreq.QuadPart = 0;
 
     if (wPeriod > MMSYSTIME_MININTERVAL)
     {
@@ -453,6 +465,7 @@ MMRESULT WINAPI timeEndPeriod(UINT wPeriod)
  */
 DWORD WINAPI timeGetTime(void)
 {
+    LARGE_INTEGER perfCount;
 #if defined(COMMENTOUTPRIORTODELETING)
     DWORD       count;
 
@@ -462,6 +475,12 @@ DWORD WINAPI timeGetTime(void)
     if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
     if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
 #endif
-
+    /* Use QPC if a high-resolution timer was requested (<= 5ms) */
+    if (TIME_qpcFreq.QuadPart != 0)
+    {
+        QueryPerformanceCounter(&perfCount);
+        return (DWORD)(perfCount.QuadPart / TIME_qpcFreq.QuadPart);
+    }
+    /* Otherwise continue using GetTickCount */
     return GetTickCount();
 }