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_milliseconds()
147 return SDL_GetTicks();
150 int timer_get_microseconds()
152 return SDL_GetTicks() * 1000;
156 // 1 means always return true
157 // 2 and above actually check the time
158 int timestamp_ticker = 2;
160 void timestamp_reset()
162 timestamp_ticker = 2;
165 // Restrict all time values between 0 and MAX_TIME
166 // so we don't have to use UINTs to calculate rollover.
167 // For debugging & testing, you could set this to
168 // something like 1 minute (6000).
169 #define MAX_TIME (INT_MAX/2)
171 void timestamp_inc(float frametime)
173 timestamp_ticker += (int)(frametime*TIMESTAMP_FREQUENCY);
175 if ( timestamp_ticker > MAX_TIME ) {
176 timestamp_ticker = 2; // Roll!
179 if (timestamp_ticker < 2 ) {
180 mprintf(("Whoa!!! timestamp_ticker < 2 -- resetting to 2!!!\n"));
181 timestamp_ticker = 2;
185 int timestamp(int delta_ms )
188 if (delta_ms < 0 ) return 0;
189 if (delta_ms == 0 ) return 1;
190 t2 = timestamp_ticker + delta_ms;
191 if ( t2 > MAX_TIME ) {
193 t2 = delta_ms - (MAX_TIME-timestamp_ticker);
195 if (t2 < 2 ) t2 = 2; // hack??
199 // Returns milliseconds until timestamp will elapse.
200 // Negative value gives milliseconds ago that timestamp elapsed.
201 int timestamp_until(int stamp)
204 // HACK!! This doesn't handle rollover!
205 // (Will it ever happen?)
207 return stamp - timestamp_ticker;
212 delta = stamp - timestamp_ticker;
215 if (delta > UINT_MAX/2)
216 delta = UINT_MAX - delta + 1;
217 else if (delta < - ( (int) (UINT_MAX/2)))
218 delta = UINT_MAX + delta + 1;
224 // alternate timestamp functions. The way these work is you call xtimestamp() to get the
225 // current counter value, and then call
228 return timestamp_ticker;
231 int timestamp_has_time_elapsed(int stamp, int time)
239 if (t <= timestamp_ticker)
240 return 1; // if we are unlucky enough to have it wrap on us, this will assume time has elapsed.
245 // timing functions -------------------------------------------------------------------------------
247 #define MAX_TIMING_EVENTS 15
252 typedef struct timing {
254 int microseconds_total;
260 timing Timing_events[MAX_TIMING_EVENTS];
261 int Timing_event_count = 0;
265 // lookup a timing event
266 int timing_event_lookup(char *event_name)
274 if(event_name == NULL){
278 // look through all events
279 for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
280 if(!SDL_strcasecmp(Timing_events[idx].name, event_name)){
289 // start timing frame stuff
290 void timing_frame_start()
298 Timing_event_count = 0;
299 Timing_frame.start = timer_get_microseconds();
300 for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
301 Timing_events[idx].microseconds_total = 0;
302 SDL_strlcpy(Timing_events[idx].name, "", sizeof(Timing_events[0].name));
303 Timing_events[idx].ref_count = 0;
308 // done timing the frame
309 void timing_frame_stop()
317 stop_time = timer_get_microseconds();
320 Timing_frame.microseconds_total = stop_time - Timing_frame.start;
324 // get the total frame time in microseconds
325 int timing_frame_total()
330 return Timing_frame.microseconds_total;
334 // time an individual event
335 void timing_event_start(char *event_name)
343 if(event_name == NULL){
347 // try and find the event
348 event = timing_event_lookup(event_name);
350 // if we already have one
352 SDL_assert(Timing_events[event].ref_count == 0);
353 Timing_events[event].start = timer_get_microseconds();
354 Timing_events[event].ref_count++;
356 // if we need to add a new one
358 if(Timing_event_count < MAX_TIMING_EVENTS){
359 SDL_strlcpy(Timing_events[Timing_event_count].name, event_name, sizeof(Timing_events[0].name));
360 Timing_events[Timing_event_count].start = timer_get_microseconds();
361 Timing_events[Timing_event_count++].ref_count++;
367 // stop timing an event
368 void timing_event_stop(char *event_name)
376 if(event_name == NULL){
380 // try and find the event
381 event = timing_event_lookup(event_name);
383 // if we already have one
385 SDL_assert(Timing_events[event].ref_count == 1);
386 Timing_events[event].microseconds_total += timer_get_microseconds() - Timing_events[event].start;
387 Timing_events[event].ref_count--;
392 // get the total time for an event in microseconds
393 int timing_event_total(char *event_name)
401 if(event_name == NULL){
405 // try and find the event
406 event = timing_event_lookup(event_name);
411 return Timing_events[event].microseconds_total;
415 // get the percentage of total frametime for the event (0.0 to 1.0)
416 float timing_event_pct(char *event_name)
424 if(event_name == NULL){
428 // try and find the event
429 event = timing_event_lookup(event_name);
434 return (float)((double)Timing_events[event].microseconds_total / (double)Timing_frame.microseconds_total);
439 void timing_display(int x, int y)
446 gr_set_color_fast(&Color_bright_blue);
449 gr_printf(x, y, "Total time %f\n", (float)timing_frame_total() / 1000000.0f);
452 // each event percentage
453 for(idx=0; idx<Timing_event_count; idx++){
454 gr_printf(x, y, "%s : %f\n", Timing_events[idx].name, timing_event_pct(Timing_events[idx].name));