]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/timer.cpp
merge in updated platform code
[taylor/freespace2.git] / src / io / timer.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Io/Timer.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Include file for timer stuff
16  *
17  * $Log$
18  * Revision 1.7  2002/06/09 04:41:22  relnev
19  * added copyright header
20  *
21  * Revision 1.6  2002/06/05 08:05:29  relnev
22  * stub/warning removal.
23  *
24  * reworked the sound code.
25  *
26  * Revision 1.5  2002/05/29 21:38:20  relnev
27  * fixed?
28  *
29  * Revision 1.4  2002/05/28 21:36:10  relnev
30  * some more timer junk.
31  *
32  * tried to fix software mode.
33  *
34  * Revision 1.3  2002/05/28 17:26:57  theoddone33
35  * Fill in some timer and palette setting stubs.  Still no display
36  *
37  * Revision 1.2  2002/05/07 03:16:46  theoddone33
38  * The Great Newline Fix
39  *
40  * Revision 1.1.1.1  2002/05/03 03:28:09  root
41  * Initial import.
42  *
43  * 
44  * 4     5/26/99 3:19p Dave
45  * Fixed release build errors.
46  * 
47  * 3     5/17/99 6:03p Dave
48  * Added new timing code. Put in code to allow camera speed zooming.
49  * 
50  * 2     10/07/98 10:53a Dave
51  * Initial checkin.
52  * 
53  * 1     10/07/98 10:49a Dave
54  * 
55  * 14    4/13/98 10:16a John
56  * Switched gettime back to timer_get_milliseconds, which is now thread
57  * safe.
58  * 
59  * 13    4/13/98 10:11a John
60  * Made timer functions thread safe.  Made timer_init be called in all
61  * projects.
62  * 
63  * 12    4/13/98 8:09a John
64  * Made timer_get functions thread safe.
65  * 
66  * 11    12/02/97 3:56p John
67  * fixed a bug with timestamp_until, created one with it rolling over.
68  * 
69  * 10    9/11/97 7:12p Hoffoss
70  * Added more functionality to training sexp handling code.
71  * 
72  * 9     8/29/97 4:49p Allender
73  * added mprintf to check for wrap problems with timestamp ticker
74  * 
75  * 8     8/28/97 1:38p Allender
76  * from John:  changes to timer func to detect early rollever
77  * 
78  * 7     7/29/97 5:30p Lawrance
79  * move gettime() from keyboard module to timer module
80  * 
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.
85  * 
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
88  * them.
89  *
90  * $NoKeywords: $
91  */
92
93
94 #include        "limits.h"
95 #include "pstypes.h"
96 #include "timer.h"
97 #include "2d.h"
98 #include "alphacolors.h"
99
100 #ifndef NDEBUG
101         #define USE_TIMING
102 #endif
103
104 static int Timer_inited = 0;
105
106 void timer_close()
107 {
108         if ( Timer_inited )     {
109                 Timer_inited = 0;
110         }
111 }
112
113 void timer_init()
114 {
115         if ( !Timer_inited )    {
116                 SDL_InitSubSystem(SDL_INIT_TIMER);
117                 
118                 Timer_inited = 1;
119
120                 atexit(timer_close);
121         }
122 }
123
124
125 fix timer_get_fixed_seconds()
126 {
127         Sint64 a = SDL_GetTicks();
128         
129         a *= 65536;
130         return (fix)(a / 1000);
131 }
132
133 fix timer_get_fixed_secondsX()
134 {
135         return timer_get_fixed_seconds();
136 }
137
138 fix timer_get_approx_seconds()
139 {
140         return timer_get_fixed_seconds();
141 }
142
143 int timer_get_milliseconds()
144 {
145         return SDL_GetTicks();
146 }
147
148 int timer_get_microseconds()
149 {
150         return SDL_GetTicks() * 1000;
151 }
152
153 // 0 means invalid,
154 // 1 means always return true
155 // 2 and above actually check the time
156 int timestamp_ticker = 2;
157
158 void timestamp_reset()
159 {
160         timestamp_ticker = 2;
161 }
162
163 // Restrict all time values between 0 and MAX_TIME
164 // so we don't have to use UINTs to calculate rollover.
165 // For debugging & testing, you could set this to 
166 // something like 1 minute (6000).
167 #define MAX_TIME (INT_MAX/2)
168
169 void timestamp_inc(float frametime)
170 {
171         timestamp_ticker += (int)(frametime*TIMESTAMP_FREQUENCY);
172
173         if ( timestamp_ticker > MAX_TIME )      {
174                 timestamp_ticker = 2;           // Roll!
175         }
176
177         if (timestamp_ticker < 2 ) {
178                 mprintf(("Whoa!!!  timestamp_ticker < 2 -- resetting to 2!!!\n"));
179                 timestamp_ticker = 2;
180         }
181 }
182
183 int timestamp(int delta_ms )
184 {
185         int t2;
186         if (delta_ms < 0 ) return 0;
187         if (delta_ms == 0 ) return 1;
188         t2 = timestamp_ticker + delta_ms;
189         if ( t2 > MAX_TIME )    {
190                 // wrap!!!
191                 t2 = delta_ms - (MAX_TIME-timestamp_ticker);
192         }
193         if (t2 < 2 ) t2 = 2;    // hack??
194         return t2;
195 }
196
197 //      Returns milliseconds until timestamp will elapse.
198 //      Negative value gives milliseconds ago that timestamp elapsed.
199 int timestamp_until(int stamp)
200 {
201         // JAS: FIX
202         // HACK!! This doesn't handle rollover!
203         // (Will it ever happen?)
204         
205         return stamp - timestamp_ticker;
206
207 /*
208         uint    delta;
209
210         delta = stamp - timestamp_ticker;
211         
212
213         if (delta > UINT_MAX/2)
214                 delta = UINT_MAX - delta + 1;
215         else if (delta < - ( (int) (UINT_MAX/2)))
216                 delta = UINT_MAX + delta + 1;
217
218         return delta;
219 */
220 }
221
222 // alternate timestamp functions.  The way these work is you call xtimestamp() to get the
223 // current counter value, and then call
224 int timestamp()
225 {
226         return timestamp_ticker;
227 }
228
229 int timestamp_has_time_elapsed(int stamp, int time)
230 {
231         int t;
232
233         if (time <= 0)
234                 return 1;
235
236         t = stamp + time;
237         if (t <= timestamp_ticker)
238                 return 1;  // if we are unlucky enough to have it wrap on us, this will assume time has elapsed.
239
240         return 0;
241 }
242
243 // timing functions -------------------------------------------------------------------------------
244
245 #define MAX_TIMING_EVENTS               15
246
247 // timing struct
248 #ifdef USE_TIMING
249
250 typedef struct timing {
251         char name[64];
252         int microseconds_total;
253         int start;
254         int ref_count;
255 } timing;
256
257 timing Timing_frame;
258 timing Timing_events[MAX_TIMING_EVENTS];
259 int Timing_event_count = 0;
260
261 #endif
262
263 // lookup a timing event
264 int timing_event_lookup(char *event_name)
265 {
266 #ifndef USE_TIMING
267         return -1;
268 #else
269         int idx;
270
271         // sanity
272         if(event_name == NULL){
273                 return -1;
274         }
275
276         // look through all events
277         for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
278                 if(!SDL_strcasecmp(Timing_events[idx].name, event_name)){
279                         return idx;
280                 }
281         }
282
283         return -1;
284 #endif
285 }
286
287 // start timing frame stuff
288 void timing_frame_start()
289 {
290 #ifndef USE_TIMING
291         return;
292 #else
293         int idx;
294
295         // restart the frame
296         Timing_event_count = 0;
297         Timing_frame.start = timer_get_microseconds();
298         for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
299                 Timing_events[idx].microseconds_total = 0;
300                 SDL_strlcpy(Timing_events[idx].name, "", sizeof(Timing_events[0].name));
301                 Timing_events[idx].ref_count = 0;
302         }
303 #endif
304 }
305
306 // done timing the frame
307 void timing_frame_stop()
308 {
309 #ifndef USE_TIMING
310         return;
311 #else   
312         int stop_time;
313
314         // stop time
315         stop_time = timer_get_microseconds();
316
317         // calc times
318         Timing_frame.microseconds_total = stop_time - Timing_frame.start;       
319 #endif
320 }
321
322 // get the total frame time in microseconds
323 int timing_frame_total()
324 {
325 #ifndef USE_TIMING
326         return 0;
327 #else
328         return Timing_frame.microseconds_total;
329 #endif
330 }
331
332 // time an individual event
333 void timing_event_start(char *event_name)
334 {
335 #ifndef USE_TIMING
336         return;
337 #else
338         int event;
339
340         // sanity
341         if(event_name == NULL){
342                 return;
343         }
344
345         // try and find the event
346         event = timing_event_lookup(event_name);
347
348         // if we already have one
349         if(event != -1){
350                 SDL_assert(Timing_events[event].ref_count == 0);
351                 Timing_events[event].start = timer_get_microseconds();
352                 Timing_events[event].ref_count++;
353         }
354         // if we need to add a new one
355         else {
356                 if(Timing_event_count < MAX_TIMING_EVENTS){
357                         SDL_strlcpy(Timing_events[Timing_event_count].name, event_name, sizeof(Timing_events[0].name));
358                         Timing_events[Timing_event_count].start = timer_get_microseconds();
359                         Timing_events[Timing_event_count++].ref_count++;
360                 }
361         }
362 #endif
363 }
364
365 // stop timing an event
366 void timing_event_stop(char *event_name)
367 {
368 #ifndef USE_TIMING
369         return;
370 #else
371         int event;
372
373         // sanity
374         if(event_name == NULL){
375                 return;
376         }
377
378         // try and find the event
379         event = timing_event_lookup(event_name);
380
381         // if we already have one
382         if(event != -1){
383                 SDL_assert(Timing_events[event].ref_count == 1);
384                 Timing_events[event].microseconds_total += timer_get_microseconds() - Timing_events[event].start;
385                 Timing_events[event].ref_count--;
386         }
387 #endif
388 }
389
390 // get the total time for an event in microseconds
391 int timing_event_total(char *event_name)
392 {
393 #ifndef USE_TIMING
394         return -1;
395 #else
396         int event;
397
398         // sanity
399         if(event_name == NULL){
400                 return -1;
401         }
402
403         // try and find the event
404         event = timing_event_lookup(event_name);
405         if(event == -1){
406                 return -1;
407         }
408         
409         return Timing_events[event].microseconds_total;
410 #endif
411 }
412
413 // get the percentage of total frametime for the event (0.0 to 1.0)
414 float timing_event_pct(char *event_name)
415 {
416 #ifndef USE_TIMING
417         return 0.0f;
418 #else
419         int event;
420
421         // sanity
422         if(event_name == NULL){
423                 return -1.0f;
424         }
425
426         // try and find the event
427         event = timing_event_lookup(event_name);
428         if(event == -1){
429                 return -1.0f;
430         }
431
432         return (float)((double)Timing_events[event].microseconds_total / (double)Timing_frame.microseconds_total);
433 #endif
434 }
435
436 // display timing 
437 void timing_display(int x, int y)
438 {
439 #ifndef USE_TIMING
440         return;
441 #else
442         int idx;
443
444         gr_set_color_fast(&Color_bright_blue);
445
446         // total time
447         gr_printf(x, y, "Total time %f\n", (float)timing_frame_total() / 1000000.0f);
448         y += 10;
449
450         // each event percentage
451         for(idx=0; idx<Timing_event_count; idx++){
452                 gr_printf(x, y, "%s : %f\n", Timing_events[idx].name, timing_event_pct(Timing_events[idx].name));
453                 y += 10;
454         }
455 #endif
456 }