Allegro 4 timing problem

You can talk about almost anything that you want to on this board.

Moderator: Moderators

Post Reply
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Allegro 4 timing problem

Post by Zepper »

Using vsync() gives a smooth scrolling, but with a timer, things are not good. I set up a volatile int frame_counter to be incremented 3606 times per minute (or 3600 if exactly 60hz). On screen refresh (bitmap blitting), I check the state of frame_counter in a while(0 == frame_counter) loop, waiting for a tick. Then, the blit occurs and the frame_counter=0. I suspect this is the error, but any help on it? As I said, the scrolling seems to gasp.

Code: Select all

//the following is a sketch only
volatile int frame_counter=0;

void gfx_timer_clock(void)
{
   frame_counter++;
}
END_OF_FUNCTION(gfx_timer_clock)  //however, this statement doesn't seem to be REALLY necessary.

void blit_to_screen(BITMAP *bmp)
{
   blit(bmp,screen, ... );  //parameters don't matter.
   while(0 == frame_counter) {
      Sleep(0); //it doesn't impact in the timer as you would might imagine...
   }
   frame_counter = 0;

   //using an old_frame_counter to compare with frame_counter gives the exact same bad effect.
   //it just don't reset the counter.
}

void gfx_timer_init(void)
{
   install_timer();
   LOCK_FUNCTION(gfx_timer_clock);
   LOCK_VARIABLE(frame_counter);
   install_int_ex(gfx_timer_clock,BPM_TO_TIMER(3606));
}
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Allegro 4 timing problem

Post by Dwedit »

Windows Vista/7/8/10 easy vsync wait:

HDC dc = GetDC(NULL);
GetPixel(dc, 0, 0);
ReleaseDC(NULL, dc);
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Allegro 4 timing problem

Post by rainwarrior »

volatile is not generally sufficient for signalling between threads. There are a big long digression on this in this thread. Would recommend using a semaphore instead of that busy loop, but there is probably a better way to really just block until vsync and not have to do any signalling like this.
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Allegro 4 timing problem

Post by pubby »

If it's C++, just use <chrono> and <thread>.
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Allegro 4 timing problem

Post by Dwedit »

Actually getting a true interruption in the main thread is hard to do on modern Windows systems, but it is still possible. There's SetThreadContext, which lets you move the program counter and change the registers. This can be called from a secondary thread.
Some libraries won't let you make certain kinds of calls from a secondary thread.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Allegro 4 timing problem

Post by Zepper »

Dwedit wrote:Windows Vista/7/8/10 easy vsync wait:

HDC dc = GetDC(NULL);
GetPixel(dc, 0, 0);
ReleaseDC(NULL, dc);
It worked as well as Allegro's vsync(). Is this safe to be called 60 times per second?
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Allegro 4 timing problem

Post by Dwedit »

Only works on Vista or Later with Desktop Window Manager (Aero) enabled. Otherwise it doesn't do any waits. Should be safe to use otherwise. The vsync wait is a side-effect and is undocumented.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
Sour
Posts: 891
Joined: Sun Feb 07, 2016 6:16 pm

Re: Allegro 4 timing problem

Post by Sour »

There is nothing preventing that code from incrementing frame_counter 2+ times before the other thread sets it back to 0. Although relatively unlikely due to the ~16ms delay between calls to gfx_timer_clock. This means you could potentially skip displaying frames. It doesn't help that sleep() on Windows is not precise - there is no guarantee it will return after the time specified, it could take several milliseconds more.

Also, have you checked to ensure the Allegro timer is reliably ticking 3606 times per second?

volatile pretty much only tells the compiler to keep the variable outside of a register to force it to be read from memory on each access, but it wouldn't stop the code from doing the increment and the "= 0" statements at the exact time in 2 threads - the result of which is hard to predict, it could be 2, 1 or 0.
Instead of volatile, I would use std::atomic<int> if you can, and also change "frame_counter = 0" to be "frame_counter--", which will should help avoid skipped numbers (although it's hard to know exactly since I'm not sure when/how blit_to_screen is called)

P.S: All of this assumes that gfx_timer_clock runs in a completely different thread than blit_to_screen - if the timer is triggered via Windows Messages and everything is on the main message thread, you can ignore everything I just said.
Post Reply