src/timer/win32/SDL_systimer.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 07 Mar 2006 05:21:32 +0000
changeset 1480 0a2bd6507477
parent 1433 bb6839704ed6
child 1497 420b3f47806d
permissions -rw-r--r--
More Win64 updates
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #define WIN32_LEAN_AND_MEAN
    25 #include <windows.h>
    26 #include <mmsystem.h>
    27 
    28 #include "SDL_timer.h"
    29 #include "../SDL_timer_c.h"
    30 
    31 #ifdef _WIN32_WCE
    32   #error This is WinCE. Please use src/timer/wince/SDL_systimer.c instead.
    33 
    34   /* but if you really want to use this file, use these #defines... */
    35   #define USE_GETTICKCOUNT
    36   #define USE_SETTIMER
    37 #endif
    38 
    39 #define TIME_WRAP_VALUE	(~(DWORD)0)
    40 
    41 /* The first (low-resolution) ticks value of the application */
    42 static DWORD start;
    43 
    44 #ifndef USE_GETTICKCOUNT
    45 /* Store if a high-resolution performance counter exists on the system */
    46 static BOOL hires_timer_available;
    47 /* The first high-resolution ticks value of the application */
    48 static LARGE_INTEGER hires_start_ticks;
    49 /* The number of ticks per second of the high-resolution performance counter */
    50 static LARGE_INTEGER hires_ticks_per_second;
    51 #endif
    52 
    53 void SDL_StartTicks(void)
    54 {
    55 	/* Set first ticks value */
    56 #ifdef USE_GETTICKCOUNT
    57 	start = GetTickCount();
    58 #else
    59 #if 0 /* Apparently there are problems with QPC on Win2K */
    60 	if (QueryPerformanceFrequency(&hires_ticks_per_second) == TRUE)
    61 	{
    62 		hires_timer_available = TRUE;
    63 		QueryPerformanceCounter(&hires_start_ticks);
    64 	}
    65 	else
    66 #endif
    67 	{
    68 		hires_timer_available = FALSE;
    69 		timeBeginPeriod(1);		/* use 1 ms timer precision */
    70 		start = timeGetTime();
    71 	}
    72 #endif
    73 }
    74 
    75 Uint32 SDL_GetTicks(void)
    76 {
    77 	DWORD now, ticks;
    78 #ifndef USE_GETTICKCOUNT
    79 	LARGE_INTEGER hires_now;
    80 #endif
    81 
    82 #ifdef USE_GETTICKCOUNT
    83 	now = GetTickCount();
    84 #else
    85 	if (hires_timer_available)
    86 	{
    87 		QueryPerformanceCounter(&hires_now);
    88 
    89 		hires_now.QuadPart -= hires_start_ticks.QuadPart;
    90 		hires_now.QuadPart *= 1000;
    91 		hires_now.QuadPart /= hires_ticks_per_second.QuadPart;
    92 
    93 		return (DWORD)hires_now.QuadPart;
    94 	}
    95 	else
    96 	{
    97 		now = timeGetTime();
    98 	}
    99 #endif
   100 
   101 	if ( now < start ) {
   102 		ticks = (TIME_WRAP_VALUE-start) + now;
   103 	} else {
   104 		ticks = (now - start);
   105 	}
   106 	return(ticks);
   107 }
   108 
   109 void SDL_Delay(Uint32 ms)
   110 {
   111 	Sleep(ms);
   112 }
   113 
   114 #ifdef USE_SETTIMER
   115 
   116 static UINT WIN_timer;
   117 
   118 int SDL_SYS_TimerInit(void)
   119 {
   120 	return(0);
   121 }
   122 
   123 void SDL_SYS_TimerQuit(void)
   124 {
   125 	return;
   126 }
   127 
   128 /* Forward declaration because this is called by the timer callback */
   129 int SDL_SYS_StartTimer(void);
   130 
   131 static VOID CALLBACK TimerCallbackProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
   132 {
   133 	Uint32 ms;
   134 
   135 	ms = SDL_alarm_callback(SDL_alarm_interval);
   136 	if ( ms != SDL_alarm_interval ) {
   137 		KillTimer(NULL, idEvent);
   138 		if ( ms ) {
   139 			SDL_alarm_interval = ROUND_RESOLUTION(ms);
   140 			SDL_SYS_StartTimer();
   141 		} else {
   142 			SDL_alarm_interval = 0;
   143 		}
   144 	}
   145 }
   146 
   147 int SDL_SYS_StartTimer(void)
   148 {
   149 	int retval;
   150 
   151 	WIN_timer = SetTimer(NULL, 0, SDL_alarm_interval, TimerCallbackProc);
   152 	if ( WIN_timer ) {
   153 		retval = 0;
   154 	} else {
   155 		retval = -1;
   156 	}
   157 	return retval;
   158 }
   159 
   160 void SDL_SYS_StopTimer(void)
   161 {
   162 	if ( WIN_timer ) {
   163 		KillTimer(NULL, WIN_timer);
   164 		WIN_timer = 0;
   165 	}
   166 }
   167 
   168 #else /* !USE_SETTIMER */
   169 
   170 /* Data to handle a single periodic alarm */
   171 static UINT timerID = 0;
   172 
   173 static void CALLBACK HandleAlarm(UINT uID,  UINT uMsg, DWORD_PTR dwUser,
   174 						DWORD_PTR dw1, DWORD_PTR dw2)
   175 {
   176 	SDL_ThreadedTimerCheck();
   177 }
   178 
   179 
   180 int SDL_SYS_TimerInit(void)
   181 {
   182 	MMRESULT result;
   183 
   184 	/* Set timer resolution */
   185 	result = timeBeginPeriod(TIMER_RESOLUTION);
   186 	if ( result != TIMERR_NOERROR ) {
   187 		SDL_SetError("Warning: Can't set %d ms timer resolution",
   188 							TIMER_RESOLUTION);
   189 	}
   190 	/* Allow 10 ms of drift so we don't chew on CPU */
   191 	timerID = timeSetEvent(TIMER_RESOLUTION,1,HandleAlarm,0,TIME_PERIODIC);
   192 	if ( ! timerID ) {
   193 		SDL_SetError("timeSetEvent() failed");
   194 		return(-1);
   195 	}
   196 	return(SDL_SetTimerThreaded(1));
   197 }
   198 
   199 void SDL_SYS_TimerQuit(void)
   200 {
   201 	if ( timerID ) {
   202 		timeKillEvent(timerID);
   203 	}
   204 	timeEndPeriod(TIMER_RESOLUTION);
   205 }
   206 
   207 int SDL_SYS_StartTimer(void)
   208 {
   209 	SDL_SetError("Internal logic error: Win32 uses threaded timer");
   210 	return(-1);
   211 }
   212 
   213 void SDL_SYS_StopTimer(void)
   214 {
   215 	return;
   216 }
   217 
   218 #endif /* USE_SETTIMER */