It is currently Thu Oct 19, 2017 4:11 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: Allegro 4 timing problem
PostPosted: Fri Apr 21, 2017 7:32 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 3064
Location: Brazil
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:
//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));
}


Top
 Profile  
 
PostPosted: Fri Apr 21, 2017 8:00 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3943
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!


Top
 Profile  
 
PostPosted: Fri Apr 21, 2017 8:09 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5718
Location: Canada
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.


Top
 Profile  
 
PostPosted: Fri Apr 21, 2017 11:36 pm 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 197
If it's C++, just use <chrono> and <thread>.


Top
 Profile  
 
PostPosted: Sat Apr 22, 2017 8:53 am 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3943
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!


Top
 Profile  
 
PostPosted: Sat Apr 22, 2017 9:28 am 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 3064
Location: Brazil
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?


Top
 Profile  
 
PostPosted: Sat Apr 22, 2017 10:18 am 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3943
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!


Top
 Profile  
 
PostPosted: Sat Apr 22, 2017 11:19 am 
Offline

Joined: Sun Feb 07, 2016 6:16 pm
Posts: 285
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.


Top
 Profile  
 
PostPosted: Wed Apr 26, 2017 2:21 pm 
Offline

Joined: Wed Apr 26, 2017 2:19 pm
Posts: 2
So does it work or not?


Top
 Profile  
 
PostPosted: Wed Apr 26, 2017 7:06 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 3064
Location: Brazil
Sour wrote:
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.

That's exactly my doubt!
About threads, well... unfortunately, I'm quite primitive in C coding. Never did any Windows programming, nor get interested to learn it (Visual Basic/C++). There are no threads at least in my C code, since Allegro uses an hack/hook in the main() for the WinMain() as a macro END_OF_MAIN().


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group