gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Where should I place the WaitVBlank function?

#58326 - Nacho - Sat Oct 22, 2005 6:27 pm

Hello there! I?m making a simple 3D raster in C (mode 4). I?ve been reading Harbour?s book because I need to learn about timers and found out that in his demo?s main loop he calls the WaitVBlank() function twice: at the beginning and in the end. This has been my game loop so far:

Code:

    while(iFlag) {
      GameMain(&RendCont);      
      WaitVBlank();
        FlipPages();
        FillScreen(); // Erases the back buffer.
    } // End while.


but now I?ve seen Harbour?s code I?m quite confused. What?s the proper scheme to use? Thanks in advance for your help!

--Nacho

#58334 - poslundc - Sat Oct 22, 2005 7:22 pm

I don't know Harbour's book, but the model you are using should work.

The one thing to keep in mind is that if your GameMain() function is still really short (as is often the case when you're just starting out), it might be completing before the VBlank period is over. This means you can hit WaitVBlank() before the next actual rendering cycle has hit... depending on how your WaitVBlank() code functions, if it doesn't recognize that it's still the same VBlank (and that it needs to wait for the next one), it can throw off the timing of your game.

Using interrupts for your VBlank routine inherently handles this. If, on the other hand, you're hanging in a tight loop waiting while (REG_VCOUNT != 160), it's often normal to add the following wait at the end of your VBlank phase:

Code:
while (REG_VCOUNT == 160);


... just to make sure that the above misfire doesn't occur. Perhaps this is what Harbour's book was doing.

Dan.

#58335 - tepples - Sat Oct 22, 2005 7:23 pm

It's probably a 30fps engine.
Code:

while(still_playing))
{
  WaitVblank();
  DoSomeProcessing();
  WaitVblank();
  DoMoreProcessing();
}


_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#58340 - Cearn - Sat Oct 22, 2005 7:42 pm

If memory serves correctly, there are at least three inconsistent (and possibly wrong) versions of WaitVBlank in the book, so it's not surprising that it'd be confusing. Don't consider it your only source for GBA programming; check the FAQ and main site for other/better alternatives.
For the correct Vsync procedure, do what poslundc suggested. Then when you get comfortable with interrupts, switch to VSync with VBlankIntrWait.

#58364 - Nacho - Sat Oct 22, 2005 10:50 pm

Thanks for your replies!

@ poslundc:

poslundc wrote:
... depending on how your WaitVBlank() code functions, if it doesn't recognize that it's still the same VBlank (and that it needs to wait for the next one), it can throw off the timing of your game.


Here?s the code for my VBlank function:

Code:

void
WaitVBlank(void)
{
    while(*g_lpScanlineCounter<160);
} /* End WaitVBlank() */


There?s something I don?t get about this VBlank thing. Does the value inside g_lpScanlineCounter equal 160 during the entire period the screen "pointer" repositions itself back to the top of the screen? I?ve been searching on the Internet for the answer to this question and haven?t found it.

I also found the following solution in the document Cearn suggested:

Code:

void vid_vsync()
{
    while(REG_VCOUNT >= 160);   // wait till VDraw
    while(REG_VCOUNT < 160);    // wait till VBlank
}


Is this solution as effective as the one you propose?

@ tepples: Harbour doesn?t mention anything about being a 30 fps engine. Maybe he made a mistake in his code.

@ Cearn: The document you suggested in very interesting! Thanks a lot! I?ll try the interrupt approach later.

#58370 - poslundc - Sat Oct 22, 2005 11:16 pm

Nacho wrote:
Here?s the code for my VBlank function:

Code:

void
WaitVBlank(void)
{
    while(*g_lpScanlineCounter<160);
} /* End WaitVBlank() */


There?s something I don?t get about this VBlank thing. Does the value inside g_lpScanlineCounter equal 160 during the entire period the screen "pointer" repositions itself back to the top of the screen? I?ve been searching on the Internet for the answer to this question and haven?t found it.


The answers to most of your technical questions can be found at the Cowbite Virtual Hardware Spec and GBATEK. (Cowbite is a bit of an easier read, whereas GBATEK is considered to be the more definitive resource of the two.)

The GBA cycles over a course of 228 scanlines: 160 VDraw followed by 68 VBlank. So at the end of the VBlank phase, REG_VCOUNT will be 227, then roll over to 0 as the next frame's VDraw phase commences.

In the case of your VBlank function, imagine the following timeline:

1. Your game loop function completes, and WaitVBlank is called.
2. WaitVBlank waits until REG_VCOUNT is 160, then returns.
3. Your VBlank routine begins... say it only takes 5 scanlines; REG_VCOUNT is now 165.
4. Your VDraw routine begins again... say it only takes another 10 scanlines. REG_VCOUNT is now 175.
5. WaitVBlank is called... but the VBlank condition you are testing for is still true from the previous frame because your draw routine didn't take long enough for REG_VCOUNT to roll over to 0. And so your code spins out of control.

Quote:
I also found the following solution in the document Cearn suggested:

Code:

void vid_vsync()
{
    while(REG_VCOUNT >= 160);   // wait till VDraw
    while(REG_VCOUNT < 160);    // wait till VBlank
}


Is this solution as effective as the one you propose?


Yes; the order of the timing considerations are shifted but it pretty much amounts to the same thing.

Dan.

#58375 - Nacho - Sat Oct 22, 2005 11:57 pm

Thanks for the links and for the big explanation!

poslundc wrote:

3. Your VBlank routine begins... say it only takes 5 scanlines; REG_VCOUNT is now 165.
4. Your VDraw routine begins again... say it only takes another 10 scanlines. REG_VCOUNT is now 175.


I think I understand your point, but what do you mean by VBlank and VDraw routines? My rendering code (which plots pixels to the backbuffer) is inside GameMain, is that approach correct?

In any case, the GameMain function is quite CPU intensive (lots of matrix computation and pixel plotting going on) and I?m not an optimization guru, so I don?t think the whole function is taking less than the vertical blank period :)

Thanks again for all your help!

--Nacho

#58398 - poslundc - Sun Oct 23, 2005 6:24 am

Nacho wrote:
I think I understand your point, but what do you mean by VBlank and VDraw routines? My rendering code (which plots pixels to the backbuffer) is inside GameMain, is that approach correct?


GBA games are structured around the timing of the hardware. Routines that update the game's state or visual elements that aren't currently being rendered on the screen (such as the back buffer in Mode 4) are typically done while the screen is being rendered, aka VDraw. Routines that actually update what appears on the display are run while the screen is inactive - aka VBlank - to prevent screen artifacts from occurring. It's up to the programmer to make sure that the machine is in the correct state when their code is being run, which is why the main loop of a GBA game cycles around waiting for VBlank to occur.

Dan.

#58416 - Nacho - Sun Oct 23, 2005 1:23 pm

poslundc wrote:
[...] Routines that update the game's state or visual elements that aren't currently being rendered on the screen (such as the back buffer in Mode 4) are typically done while the screen is being rendered, aka VDraw. Routines that actually update what appears on the display are run while the screen is inactive - aka VBlank - to prevent screen artifacts from occurring.


But since I?m working in a double buffered mode, do I need to make the distinction you mention or can I just update and render to the backbuffer all the game?s elements and use the VBlank period to perform page flipping?

--Nacho

#58430 - tepples - Sun Oct 23, 2005 3:47 pm

Nacho wrote:
can I just update and render to the backbuffer all the game?s elements and use the VBlank period to perform page flipping?

Yes. But you'll probably have to install a vblank interrupt handler to count the number of vblanks that your code misses so that you can adjust the game engine's frameskip accordingly.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#58445 - Nacho - Sun Oct 23, 2005 5:43 pm

tepples wrote:
Yes. But you'll probably have to install a vblank interrupt handler to count the number of vblanks that your code misses so that you can adjust the game engine's frameskip accordingly.


Gotcha. That would also solve the framerate issue I?ve been talking about in the other thread. I?ll look into vblank interrupts then. Thanks a lot tepples!

--Nacho