Problem with timer - blocked to 64 FPS ?!
anto80

Hello all,

I have a problem with timers and i am sure i have done a basic mistake...

I have a timer named 'wait_proc' for the game logic.
I just increases the variable actual_tic (+1) every call.
I want it to be executed 120 times every second.

I want my program to display the game as soon as possible, but I don't need to draw it if nothing in the game logic has changed. So normally the max FPS should be 120.

I have another timer named 'fps_proc' for the fps count, called every second, and which store the number of frames that have been counted this second.

The problem is that the display is 'blocked' to 64 FPS. However it doesnot come from the display performance because if I force the program to draw, even if nothing in the game logic has changed, i get something like 1000 FPS !
Please see the code below, especially the part with the comment "// DONT KNOW WHY IT IS BLOCKED TO 64 FPS"

Thank you in advance ! :)

My timer installation:

  allegro_init();
  install_allegro_gl();

  install_timer();
  install_keyboard();
  install_mouse();

  // Install my timers ///////////////////////////////////////////////////
  LOCK_VARIABLE(fps);
  LOCK_VARIABLE(frame_count);
  LOCK_VARIABLE(actual_tic);
  LOCK_FUNCTION(fps_proc);
  LOCK_FUNCTION(wait_proc);
  install_int(fps_proc, 1000);  
  install_int_ex(wait_proc, BPS_TO_TIMER(120));

Timer code:

1/*--- Timer vars ----------------------------------------------------------*/
2static volatile unsigned int fps;
3static volatile unsigned int frame_count;
4static volatile unsigned int actual_tic;
5 
6/*--- Ticker (timer : game logic)------------------------------------------*/
7void wait_proc()
8{
9 actual_tic++;
10}
11END_OF_FUNCTION(wait_proc);
12 
13/*--- Fps proc (timer : calculate FPS) ------------------------------------*/
14void fps_proc()
15{
16 fps = frame_count;
17 frame_count = 0;
18}
19END_OF_FUNCTION(fps_proc);

The main loop:

1void loop()
2{
3 unsigned int nPrevUpdateTime; // previous update time
4 bool bGameUpdated; // bool tells if we need to redraw
5 
6 actual_tic = 0;
7 nPrevUpdateTime = 0;
8 
9 while (!key[KEY_ESC])
10 {
11 /*--- move all game logic -----------------------------------------*/
12 bGameUpdated = false;
13 while (nPrevUpdateTime != actual_tic)
14 {
15 /* polls */
16 poll_keyboard();
17 
18 /* moves */
19 t++;
20
21 /* objects moves */
22 listEnemies.move();
23 groupe.move();
24 listStars.move();
25 
26 /* timer variable settings */
27 nPrevUpdateTime++;
28 bGameUpdated = true;
29 }
30 // DONT KNOW WHY IT IS BLOCKED TO 64 FPS
31 // if i put 'bGameUpdated = true; ' here, it gives me something like 1000 FPS !
32 
33 
34 /*--- Display start -----------------------------------------------*/
35 if (bGameUpdated)
36 {
37 clear(bmp);
38 
39 /* various drawings */
40
41 textprintf(bmp, font, 0, 0, makecol(255, 255, 255),
42 "FPS%5d logic %d", fps, actual_tic);
43
44 /* blit bmp to screen */
45
46 frame_count++;
47 }
48 }
49}

A J

vsync ?

Frank Drebin

yes what the hell is this ?
http://www.allegro.cc/forums/thread/585737

anto80
A J said:

vsync ?

A J: No, because like i said:

Quote:

if I force the program to draw, even if nothing in the game logic has changed, i get something like 1000 FPS !

Yes Frank, it seems that I'm getting the same problem.
I am using set_gfx_mode in windowed mode too.
Is there any solution for this?

Neil Walker

two things that probably won't make a difference:

1.
>while (nPrevUpdateTime != actual_tic)

Maybe actual_tic has increased beyond nprevupdatetime during a draw loop and doesn't get caught until the next?

I do it like this:
while(actual_tic!=0)
{ ...
actual_tic--;
}

And in the timer handler increment actual_tic

2. Maybe the keyboard_poll is doing something. Try removing it. I don't think there are any platforms at the minute that need keyboard polling.

Frank Drebin

as i pointed out in my post even this program won't get more than 64 fps and i don't see any errors here:

1#include <allegro.h>
2 
3volatile int speed_counter=0;
4volatile int fps=0;
5volatile int frames=0;
6BITMAP* bbuffer;
7 
8void increment_speed_counter()
9{
10 speed_counter++;
11}
12END_OF_FUNCTION(increment_speed_counter);
13 
14void update_fps()
15{
16 fps=frames;
17 frames=0;
18}
19END_OF_FUNCTION(update_fps);
20 
21void init()
22{
23 allegro_init();
24 install_keyboard();
25 set_color_depth(16);
26 set_gfx_mode(GFX_AUTODETECT_FULLSCREEN,640,480,0,0);
27 install_timer();
28 LOCK_VARIABLE(speed_counter);
29 LOCK_VARIABLE(fps);
30 LOCK_VARIABLE(frames);
31 LOCK_FUNCTION(increment_speed_counter);
32 LOCK_FUNCTION(update_fps);
33 install_int_ex(increment_speed_counter,BPS_TO_TIMER(100));
34 install_int_ex(update_fps,BPS_TO_TIMER(1));
35}
36 
37int main()
38{
39 init();
40 
41 bbuffer=create_bitmap(640,480);
42
43 while (!key[KEY_ESC])
44 {
45 while (speed_counter>0)
46 {
47 speed_counter--;
48 }
49 clear_bitmap(bbuffer);
50 textprintf_ex(bbuffer,font,0,0,makecol(255,255,255),-1,"FPS: %i",fps);
51 blit(bbuffer,screen,0,0,0,0,640,480);
52 frames++;
53 while (speed_counter==0) rest(1);
54 }
55 
56 destroy_bitmap(bbuffer);
57
58 return 0;
59}
60END_OF_MAIN()

Kitty Cat

Allegro's timers are not accurate. If you want more accuracy, you'll have to find another method. I've posted my timer class before, which makes it rather simple to keep track in a method similar to Allegro's. It doesn't take any hit for having one or multiple timers since it runs off the system's timing stuff, and on the right platforms it'll use high-accuracy timing.

If you want me to repost it, let me know. I'll even show you how to use it (which as I said, is simple and almost Allegro-like).

Neil Walker

Assuming windows, what happens if you use the software directx driver or GDI, GFX_DIRECTX_SOFT/GFX_DIRECTX_GDI

Epsi

I had this problem when I was coding scripts with "mIRC", a windows software.

Basically it's because the default Windows timer (the one which returns "ticks") has a resolution which is limited to +- 15 ms, wich gives a result of max 65 times per second.

So with my games I could not "loop" a logic with a timer more than 64 times per second.

In this case I don't really understand why, but it seems that Allegro's timer suffers from the same problem...

The solution for me was to use a high resolution timer (check http://www.unb.ca/metrics/software/HRtime.html)

I hope that this can help...

P.S: What this your OS, and what version is it ?

Audric
KittyCat said:

Allegro's timers are not accurate. If you want more accuracy, you'll have to find another method.

Aye, it's a sad world for coders... Last time I managed flawless scrolling (panning) was by using double buffer and vsync() for timer, on DOS, and it could run on anything...
Today, I'd need to code at least 3 different algorithms, none of them would work on my own machine :-/

anto80

I'm running Win XP SP 2.
I'm developping with MSVC 6, with Allegro and Allegro GL.

KittyCat, I don't know what is the Timer class you are talking about. Could you please show me where it is and how to include it, and use it in my prog?

Audric

Strangely enough, what you're asking is the first result of a search on the word "Timer", posted by "Kitty Cat".

Frank Drebin

epsi,
i don't think that the allegro timer is the problem - at least with the code i posted.
if you leave the rest(1) out of the code you'll get far more than 100 fps and if i understood you right this should not happen then...

Epsi

Frank Drebin: no it's exactly the case: rest(1) will rest for 15ms istead of 1 (assuming it uses Windows basic timer), thus limiting you to 64 fps. If you remove it, you get rid of the timer effect and you get "no limit" fps.

Vasco Freitas

I have the same problem. :-/

Frank Drebin

so does it mean that i can't run my timer accurate and give some cpu-cycles to the system at once?

Neil Walker

Richard Phipps has set a link to the windows timer code he uses, haven't a clue what to search for in the site is though, may be if he reads this he might post the link :)

GullRaDriel

QPC,GTOD thread for HighRes Timer.

Here is my wrapper, you can find the full Library Documentation in my sig:

part of common.h

1/*!
2 * Timing Structure
3 */
4 
5 
6typedef struct N_TIME
7 {
8 
9time_t delta;
10 
11#ifndef LINUX
12 LARGE_INTEGER freq;
13 LARGE_INTEGER startTime;
14 LARGE_INTEGER currentTime;
15 
16#else
17 
18 timeval startTime;
19 timeval currentTime;
20 
21#endif
22 
23 }
24 
25N_TIME;
26 
27 
28 
29/*
30 * Init or restart from zero any N_TIME HiTimer
31 */
32 
33void start_HiTimer( N_TIME *timer );
34 
35 
36 
37/*
38 * Poll any N_TIME HiTimer, returning usec
39 */
40 
41time_t get_usec( N_TIME *timer );
42 
43 
44 
45/*
46 * Poll any N_TIME HiTimer, returning usec
47 */
48 
49time_t get_msec( N_TIME *timer );
50 
51 
52 
53/*
54 * Poll any N_TIME HiTimer, returning usec
55 */
56 
57 
58time_t get_sec( N_TIME *timer );

part of common.c:

1/*!\fn start_HiTimer( N_TIME *timer )
2 *
3 *\brief Initialize or restart from zero any N_TIME HiTimer
4 *
5 *\param timer Any N_TIMER *timer you wanna start or reset
6 *
7 */
8 
9void start_HiTimer( N_TIME *timer )
10 {
11 
12 timer -> delta = 0;
13 
14#ifndef LINUX
15 QueryPerformanceFrequency( ( LARGE_INTEGER * ) & timer -> freq );
16 QueryPerformanceCounter( &timer -> startTime );
17#else
18 gettimeofday( &timer -> startTime, 0 );
19#endif
20 
21 } /* init_HiTimer(...) */
22 
23 
24 
25/*!\fn get_usec( N_TIME *timer )
26 *
27 *\brief Poll any N_TIME HiTimer, returning usec, and moving currentTime to startTime
28 *
29 *\param timer Any N_TIMER *timer you wanna poll
30 *
31 *\return The elapsed number of usec for the given N_TIME *timer
32 */
33 
34time_t get_usec( N_TIME *timer )
35 {
36 
37#ifdef WIN32
38 
39 QueryPerformanceCounter( ( LARGE_INTEGER * ) & timer -> currentTime );
40 
41 timer -> delta = 1000000 * ( timer -> currentTime . QuadPart - timer -> startTime . QuadPart ) / timer -> freq . QuadPart ;
42 
43 timer -> startTime = timer -> currentTime ;
44 
45#else
46 
47 gettimeofday( &timer -> currentTime, 0 );
48 
49 timer -> delta = ( timer -> currentTime . tv_sec - timer -> startTime . tv_sec ) * 1000000 +
50 ( timer -> currentTime . tv_usec - timer -> startTime . tv_usec );
51 
52 timer -> startTime . tv_sec = timer -> currentTime . tv_sec ;
53 timer -> startTime . tv_usec = timer -> currentTime . tv_usec ;
54 
55#endif
56 
57 return timer -> delta;
58 
59 } /* get_usec( ... ) */
60 
61 
62 
63 
64/*!\fn get_msec( N_TIME *timer )
65 *
66 *\brief Poll any N_TIME HiTimer, returning msec, and moving currentTime to startTime
67 *
68 *\param timer Any N_TIMER *timer you wanna poll
69 *
70 *\return The elapsed number of msec for the given N_TIME *timer
71 */
72 
73time_t get_msec( N_TIME *timer ){
74 
75#ifdef WIN32
76 
77 QueryPerformanceCounter( ( LARGE_INTEGER * ) & timer -> currentTime );
78 
79 timer -> delta = 1000 * ( timer -> currentTime . QuadPart - timer -> startTime . QuadPart ) / timer -> freq . QuadPart ;
80 
81 timer -> startTime = timer -> currentTime ;
82 
83#else
84 
85 gettimeofday( &timer -> currentTime, 0 );
86 
87 timer -> delta = ( timer -> currentTime . tv_sec - timer -> startTime . tv_sec ) * 1000 +
88 ( timer -> currentTime . tv_usec - timer -> startTime . tv_usec ) / 1000 ;
89 
90 timer -> startTime . tv_sec = timer -> currentTime . tv_sec ;
91 timer -> startTime . tv_usec = timer -> currentTime . tv_usec ;
92 
93#endif
94 
95 return timer -> delta;
96} /* get_msec(...) */
97 
98 
99 
100/*!\fn get_sec( N_TIME *timer )
101 *
102 *\brief Poll any N_TIME HiTimer, returning sec, and moving currentTime to startTime
103 *
104 *\param timer Any N_TIMER *timer you wanna poll
105 *
106 *\return The elapsed number of sec for the given N_TIME *timer
107 */
108 
109time_t get_sec( N_TIME *timer ){
110 
111#ifdef WIN32
112 
113 QueryPerformanceCounter( ( LARGE_INTEGER * ) & timer -> currentTime );
114 
115 timer -> delta = ( timer -> currentTime . QuadPart - timer -> startTime . QuadPart ) / timer -> freq . QuadPart ;
116 
117 timer -> startTime = timer -> currentTime ;
118 
119#else
120 
121 gettimeofday( &timer -> currentTime, 0 );
122 
123 timer -> delta = ( timer -> currentTime . tv_sec - timer -> startTime . tv_sec ) +
124 ( timer -> currentTime . tv_usec - timer -> startTime . tv_usec ) / 1000000 ;
125 
126 timer -> startTime . tv_sec = timer -> currentTime . tv_sec ;
127 timer -> startTime . tv_usec = timer -> currentTime . tv_usec ;
128 
129#endif
130 
131 return timer -> delta;
132 
133}/* get_sec(...) */

Thread #586111. Printed from Allegro.cc