2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Io/Timer.cpp $
15 * Include file for timer stuff
18 * Revision 1.7 2002/06/09 04:41:22 relnev
19 * added copyright header
21 * Revision 1.6 2002/06/05 08:05:29 relnev
22 * stub/warning removal.
24 * reworked the sound code.
26 * Revision 1.5 2002/05/29 21:38:20 relnev
29 * Revision 1.4 2002/05/28 21:36:10 relnev
30 * some more timer junk.
32 * tried to fix software mode.
34 * Revision 1.3 2002/05/28 17:26:57 theoddone33
35 * Fill in some timer and palette setting stubs. Still no display
37 * Revision 1.2 2002/05/07 03:16:46 theoddone33
38 * The Great Newline Fix
40 * Revision 1.1.1.1 2002/05/03 03:28:09 root
44 * 4 5/26/99 3:19p Dave
45 * Fixed release build errors.
47 * 3 5/17/99 6:03p Dave
48 * Added new timing code. Put in code to allow camera speed zooming.
50 * 2 10/07/98 10:53a Dave
53 * 1 10/07/98 10:49a Dave
55 * 14 4/13/98 10:16a John
56 * Switched gettime back to timer_get_milliseconds, which is now thread
59 * 13 4/13/98 10:11a John
60 * Made timer functions thread safe. Made timer_init be called in all
63 * 12 4/13/98 8:09a John
64 * Made timer_get functions thread safe.
66 * 11 12/02/97 3:56p John
67 * fixed a bug with timestamp_until, created one with it rolling over.
69 * 10 9/11/97 7:12p Hoffoss
70 * Added more functionality to training sexp handling code.
72 * 9 8/29/97 4:49p Allender
73 * added mprintf to check for wrap problems with timestamp ticker
75 * 8 8/28/97 1:38p Allender
76 * from John: changes to timer func to detect early rollever
78 * 7 7/29/97 5:30p Lawrance
79 * move gettime() from keyboard module to timer module
81 * 6 7/16/97 4:42p Mike
82 * Make afterburner shake viewer, not ship.
83 * Shake for limited time.
84 * Add timestamp_until() function to timer library.
86 * 5 2/17/97 5:18p John
87 * Added a bunch of RCS headers to a bunch of old files that don't have
98 #include "alphacolors.h"
104 static int Timer_inited = 0;
108 if ( Timer_inited ) {
115 if ( !Timer_inited ) {
116 SDL_InitSubSystem(SDL_INIT_TIMER);
118 SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1");
127 fix timer_get_fixed_seconds()
129 Sint64 a = SDL_GetTicks();
132 return (fix)(a / 1000);
135 fix timer_get_fixed_secondsX()
137 return timer_get_fixed_seconds();
140 fix timer_get_approx_seconds()
142 return timer_get_fixed_seconds();
145 int timer_get_seconds()
147 return SDL_GetTicks() / 1000;
150 int timer_get_milliseconds()
152 return SDL_GetTicks();
155 int timer_get_microseconds()
157 return SDL_GetTicks() * 1000;
161 // 1 means always return true
162 // 2 and above actually check the time
163 int timestamp_ticker = 2;
165 void timestamp_reset()
167 timestamp_ticker = 2;
170 // Restrict all time values between 0 and MAX_TIME
171 // so we don't have to use UINTs to calculate rollover.
172 // For debugging & testing, you could set this to
173 // something like 1 minute (6000).
174 #define MAX_TIME (INT_MAX/2)
176 void timestamp_inc(float frametime)
178 timestamp_ticker += (int)(frametime*TIMESTAMP_FREQUENCY);
180 if ( timestamp_ticker > MAX_TIME ) {
181 timestamp_ticker = 2; // Roll!
184 if (timestamp_ticker < 2 ) {
185 mprintf(("Whoa!!! timestamp_ticker < 2 -- resetting to 2!!!\n"));
186 timestamp_ticker = 2;
190 int timestamp(int delta_ms )
193 if (delta_ms < 0 ) return 0;
194 if (delta_ms == 0 ) return 1;
195 t2 = timestamp_ticker + delta_ms;
196 if ( t2 > MAX_TIME ) {
198 t2 = delta_ms - (MAX_TIME-timestamp_ticker);
200 if (t2 < 2 ) t2 = 2; // hack??
204 // Returns milliseconds until timestamp will elapse.
205 // Negative value gives milliseconds ago that timestamp elapsed.
206 int timestamp_until(int stamp)
209 // HACK!! This doesn't handle rollover!
210 // (Will it ever happen?)
212 return stamp - timestamp_ticker;
217 delta = stamp - timestamp_ticker;
220 if (delta > UINT_MAX/2)
221 delta = UINT_MAX - delta + 1;
222 else if (delta < - ( (int) (UINT_MAX/2)))
223 delta = UINT_MAX + delta + 1;
229 // alternate timestamp functions. The way these work is you call xtimestamp() to get the
230 // current counter value, and then call
233 return timestamp_ticker;
236 int timestamp_has_time_elapsed(int stamp, int time)
244 if (t <= timestamp_ticker)
245 return 1; // if we are unlucky enough to have it wrap on us, this will assume time has elapsed.
250 // timing functions -------------------------------------------------------------------------------
252 #define MAX_TIMING_EVENTS 15
257 typedef struct timing {
259 int microseconds_total;
265 timing Timing_events[MAX_TIMING_EVENTS];
266 int Timing_event_count = 0;
270 // lookup a timing event
271 int timing_event_lookup(char *event_name)
279 if(event_name == NULL){
283 // look through all events
284 for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
285 if(!SDL_strcasecmp(Timing_events[idx].name, event_name)){
294 // start timing frame stuff
295 void timing_frame_start()
303 Timing_event_count = 0;
304 Timing_frame.start = timer_get_microseconds();
305 for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
306 Timing_events[idx].microseconds_total = 0;
307 SDL_strlcpy(Timing_events[idx].name, "", SDL_arraysize(Timing_events[0].name));
308 Timing_events[idx].ref_count = 0;
313 // done timing the frame
314 void timing_frame_stop()
322 stop_time = timer_get_microseconds();
325 Timing_frame.microseconds_total = stop_time - Timing_frame.start;
329 // get the total frame time in microseconds
330 int timing_frame_total()
335 return Timing_frame.microseconds_total;
339 // time an individual event
340 void timing_event_start(char *event_name)
348 if(event_name == NULL){
352 // try and find the event
353 event = timing_event_lookup(event_name);
355 // if we already have one
357 SDL_assert(Timing_events[event].ref_count == 0);
358 Timing_events[event].start = timer_get_microseconds();
359 Timing_events[event].ref_count++;
361 // if we need to add a new one
363 if(Timing_event_count < MAX_TIMING_EVENTS){
364 SDL_strlcpy(Timing_events[Timing_event_count].name, event_name, SDL_arraysize(Timing_events[0].name));
365 Timing_events[Timing_event_count].start = timer_get_microseconds();
366 Timing_events[Timing_event_count++].ref_count++;
372 // stop timing an event
373 void timing_event_stop(char *event_name)
381 if(event_name == NULL){
385 // try and find the event
386 event = timing_event_lookup(event_name);
388 // if we already have one
390 SDL_assert(Timing_events[event].ref_count == 1);
391 Timing_events[event].microseconds_total += timer_get_microseconds() - Timing_events[event].start;
392 Timing_events[event].ref_count--;
397 // get the total time for an event in microseconds
398 int timing_event_total(char *event_name)
406 if(event_name == NULL){
410 // try and find the event
411 event = timing_event_lookup(event_name);
416 return Timing_events[event].microseconds_total;
420 // get the percentage of total frametime for the event (0.0 to 1.0)
421 float timing_event_pct(char *event_name)
429 if(event_name == NULL){
433 // try and find the event
434 event = timing_event_lookup(event_name);
439 return (float)((double)Timing_events[event].microseconds_total / (double)Timing_frame.microseconds_total);
444 void timing_display(int x, int y)
451 gr_set_color_fast(&Color_bright_blue);
454 gr_printf(x, y, "Total time %f\n", (float)timing_frame_total() / 1000000.0f);
457 // each event percentage
458 for(idx=0; idx<Timing_event_count; idx++){
459 gr_printf(x, y, "%s : %f\n", Timing_events[idx].name, timing_event_pct(Timing_events[idx].name));