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 ----------------------------------------------------------*/ |
| 2 | static volatile unsigned int fps; |
| 3 | static volatile unsigned int frame_count; |
| 4 | static volatile unsigned int actual_tic; |
| 5 | |
| 6 | /*--- Ticker (timer : game logic)------------------------------------------*/ |
| 7 | void wait_proc() |
| 8 | { |
| 9 | actual_tic++; |
| 10 | } |
| 11 | END_OF_FUNCTION(wait_proc); |
| 12 | |
| 13 | /*--- Fps proc (timer : calculate FPS) ------------------------------------*/ |
| 14 | void fps_proc() |
| 15 | { |
| 16 | fps = frame_count; |
| 17 | frame_count = 0; |
| 18 | } |
| 19 | END_OF_FUNCTION(fps_proc); |
The main loop:
| 1 | void 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 | } |
vsync ?
yes what the hell is this ?
http://www.allegro.cc/forums/thread/585737
vsync ?
A J: No, because like i said:
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?
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.
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 | |
| 3 | volatile int speed_counter=0; |
| 4 | volatile int fps=0; |
| 5 | volatile int frames=0; |
| 6 | BITMAP* bbuffer; |
| 7 | |
| 8 | void increment_speed_counter() |
| 9 | { |
| 10 | speed_counter++; |
| 11 | } |
| 12 | END_OF_FUNCTION(increment_speed_counter); |
| 13 | |
| 14 | void update_fps() |
| 15 | { |
| 16 | fps=frames; |
| 17 | frames=0; |
| 18 | } |
| 19 | END_OF_FUNCTION(update_fps); |
| 20 | |
| 21 | void 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 | |
| 37 | int 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 | } |
| 60 | END_OF_MAIN() |
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).
Assuming windows, what happens if you use the software directx driver or GDI, GFX_DIRECTX_SOFT/GFX_DIRECTX_GDI
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 ?
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
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?
Strangely enough, what you're asking is the first result of a search on the word "Timer", posted by "Kitty Cat".
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...
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.
I have the same problem.
so does it mean that i can't run my timer accurate and give some cpu-cycles to the system at once?
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
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 | |
| 6 | typedef struct N_TIME |
| 7 | { |
| 8 | |
| 9 | time_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 | |
| 25 | N_TIME; |
| 26 | |
| 27 | |
| 28 | |
| 29 | /* |
| 30 | * Init or restart from zero any N_TIME HiTimer |
| 31 | */ |
| 32 | |
| 33 | void start_HiTimer( N_TIME *timer ); |
| 34 | |
| 35 | |
| 36 | |
| 37 | /* |
| 38 | * Poll any N_TIME HiTimer, returning usec |
| 39 | */ |
| 40 | |
| 41 | time_t get_usec( N_TIME *timer ); |
| 42 | |
| 43 | |
| 44 | |
| 45 | /* |
| 46 | * Poll any N_TIME HiTimer, returning usec |
| 47 | */ |
| 48 | |
| 49 | time_t get_msec( N_TIME *timer ); |
| 50 | |
| 51 | |
| 52 | |
| 53 | /* |
| 54 | * Poll any N_TIME HiTimer, returning usec |
| 55 | */ |
| 56 | |
| 57 | |
| 58 | time_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 | |
| 9 | void 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 | |
| 34 | time_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 | |
| 73 | time_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 | |
| 109 | time_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(...) */ |