]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/timer.cpp
use SDL hint for timer resolution (not needed; do it anyway)
[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                 SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1");
119
120                 Timer_inited = 1;
121
122                 atexit(timer_close);
123         }
124 }
125
126
127 fix timer_get_fixed_seconds()
128 {
129         Sint64 a = SDL_GetTicks();
130         
131         a *= 65536;
132         return (fix)(a / 1000);
133 }
134
135 fix timer_get_fixed_secondsX()
136 {
137         return timer_get_fixed_seconds();
138 }
139
140 fix timer_get_approx_seconds()
141 {
142         return timer_get_fixed_seconds();
143 }
144
145 int timer_get_milliseconds()
146 {
147         return SDL_GetTicks();
148 }
149
150 int timer_get_microseconds()
151 {
152         return SDL_GetTicks() * 1000;
153 }
154
155 // 0 means invalid,
156 // 1 means always return true
157 // 2 and above actually check the time
158 int timestamp_ticker = 2;
159
160 void timestamp_reset()
161 {
162         timestamp_ticker = 2;
163 }
164
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)
170
171 void timestamp_inc(float frametime)
172 {
173         timestamp_ticker += (int)(frametime*TIMESTAMP_FREQUENCY);
174
175         if ( timestamp_ticker > MAX_TIME )      {
176                 timestamp_ticker = 2;           // Roll!
177         }
178
179         if (timestamp_ticker < 2 ) {
180                 mprintf(("Whoa!!!  timestamp_ticker < 2 -- resetting to 2!!!\n"));
181                 timestamp_ticker = 2;
182         }
183 }
184
185 int timestamp(int delta_ms )
186 {
187         int t2;
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 )    {
192                 // wrap!!!
193                 t2 = delta_ms - (MAX_TIME-timestamp_ticker);
194         }
195         if (t2 < 2 ) t2 = 2;    // hack??
196         return t2;
197 }
198
199 //      Returns milliseconds until timestamp will elapse.
200 //      Negative value gives milliseconds ago that timestamp elapsed.
201 int timestamp_until(int stamp)
202 {
203         // JAS: FIX
204         // HACK!! This doesn't handle rollover!
205         // (Will it ever happen?)
206         
207         return stamp - timestamp_ticker;
208
209 /*
210         uint    delta;
211
212         delta = stamp - timestamp_ticker;
213         
214
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;
219
220         return delta;
221 */
222 }
223
224 // alternate timestamp functions.  The way these work is you call xtimestamp() to get the
225 // current counter value, and then call
226 int timestamp()
227 {
228         return timestamp_ticker;
229 }
230
231 int timestamp_has_time_elapsed(int stamp, int time)
232 {
233         int t;
234
235         if (time <= 0)
236                 return 1;
237
238         t = stamp + 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.
241
242         return 0;
243 }
244
245 // timing functions -------------------------------------------------------------------------------
246
247 #define MAX_TIMING_EVENTS               15
248
249 // timing struct
250 #ifdef USE_TIMING
251
252 typedef struct timing {
253         char name[64];
254         int microseconds_total;
255         int start;
256         int ref_count;
257 } timing;
258
259 timing Timing_frame;
260 timing Timing_events[MAX_TIMING_EVENTS];
261 int Timing_event_count = 0;
262
263 #endif
264
265 // lookup a timing event
266 int timing_event_lookup(char *event_name)
267 {
268 #ifndef USE_TIMING
269         return -1;
270 #else
271         int idx;
272
273         // sanity
274         if(event_name == NULL){
275                 return -1;
276         }
277
278         // look through all events
279         for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
280                 if(!SDL_strcasecmp(Timing_events[idx].name, event_name)){
281                         return idx;
282                 }
283         }
284
285         return -1;
286 #endif
287 }
288
289 // start timing frame stuff
290 void timing_frame_start()
291 {
292 #ifndef USE_TIMING
293         return;
294 #else
295         int idx;
296
297         // restart the frame
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;
304         }
305 #endif
306 }
307
308 // done timing the frame
309 void timing_frame_stop()
310 {
311 #ifndef USE_TIMING
312         return;
313 #else   
314         int stop_time;
315
316         // stop time
317         stop_time = timer_get_microseconds();
318
319         // calc times
320         Timing_frame.microseconds_total = stop_time - Timing_frame.start;       
321 #endif
322 }
323
324 // get the total frame time in microseconds
325 int timing_frame_total()
326 {
327 #ifndef USE_TIMING
328         return 0;
329 #else
330         return Timing_frame.microseconds_total;
331 #endif
332 }
333
334 // time an individual event
335 void timing_event_start(char *event_name)
336 {
337 #ifndef USE_TIMING
338         return;
339 #else
340         int event;
341
342         // sanity
343         if(event_name == NULL){
344                 return;
345         }
346
347         // try and find the event
348         event = timing_event_lookup(event_name);
349
350         // if we already have one
351         if(event != -1){
352                 SDL_assert(Timing_events[event].ref_count == 0);
353                 Timing_events[event].start = timer_get_microseconds();
354                 Timing_events[event].ref_count++;
355         }
356         // if we need to add a new one
357         else {
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++;
362                 }
363         }
364 #endif
365 }
366
367 // stop timing an event
368 void timing_event_stop(char *event_name)
369 {
370 #ifndef USE_TIMING
371         return;
372 #else
373         int event;
374
375         // sanity
376         if(event_name == NULL){
377                 return;
378         }
379
380         // try and find the event
381         event = timing_event_lookup(event_name);
382
383         // if we already have one
384         if(event != -1){
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--;
388         }
389 #endif
390 }
391
392 // get the total time for an event in microseconds
393 int timing_event_total(char *event_name)
394 {
395 #ifndef USE_TIMING
396         return -1;
397 #else
398         int event;
399
400         // sanity
401         if(event_name == NULL){
402                 return -1;
403         }
404
405         // try and find the event
406         event = timing_event_lookup(event_name);
407         if(event == -1){
408                 return -1;
409         }
410         
411         return Timing_events[event].microseconds_total;
412 #endif
413 }
414
415 // get the percentage of total frametime for the event (0.0 to 1.0)
416 float timing_event_pct(char *event_name)
417 {
418 #ifndef USE_TIMING
419         return 0.0f;
420 #else
421         int event;
422
423         // sanity
424         if(event_name == NULL){
425                 return -1.0f;
426         }
427
428         // try and find the event
429         event = timing_event_lookup(event_name);
430         if(event == -1){
431                 return -1.0f;
432         }
433
434         return (float)((double)Timing_events[event].microseconds_total / (double)Timing_frame.microseconds_total);
435 #endif
436 }
437
438 // display timing 
439 void timing_display(int x, int y)
440 {
441 #ifndef USE_TIMING
442         return;
443 #else
444         int idx;
445
446         gr_set_color_fast(&Color_bright_blue);
447
448         // total time
449         gr_printf(x, y, "Total time %f\n", (float)timing_frame_total() / 1000000.0f);
450         y += 10;
451
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));
455                 y += 10;
456         }
457 #endif
458 }