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 > Screen Tearing / VBlanks

#170934 - scizzorz - Tue Oct 27, 2009 3:32 am

Hello!

I have just recently (1-2 weeks) started programming for my Game Boy Advance and have run into a problem with screen tearing. I'm currently using the HAM library (yes, I know, it's outdated, but it's quite easy to pick up and learn) and there are a few occasions where if I put too much coding into my VBlank method (HAM has a method for starting an interrupt handler - I've been using it for the VBlank interrupt), sprites may have horizontal lines running through them where I can see the background.

I've done some research and learned that a screen refresh takes 280,896 CPU cycles, 197,120 of which are used before the VBlank and 83,776 of which are used during the VBlank. I've also learned that graphics positioning and updating should be done during the VBlank and the other game logic should be done during the screen rendering, but I'm not quite sure how to organize/set up my coding to prevent any screen tearing.

Can anyone help me? I'll give you a cookie or two.

#170937 - Dwedit - Tue Oct 27, 2009 4:32 am

I find an easy way to perform screen updates is to have two sets of variables: One for what we want on the screen, and one for what is on the screen.
Code that runs during the main loop only modifies "what we want".
Code that runs during vblank compares "what we want" with "what we are displaying". If they are different, load new data.

Another thing to do is just have a secondary copy of some stuff in RAM, especially the OAM. For example, make a secondary sprite table in RAM, then copy it to the OAM during vblank. If you are worried about not finishing making your sprite table before the screen period ends (that would cause graphical glitches), use two secondary sprite tables, and use a variable to indicate which table is 100% ready.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#170938 - scizzorz - Tue Oct 27, 2009 4:43 am

Thanks a ton! Quite helpful, but one question:

Quote:
Code that runs during the main loop only modifies "what we want".
Code that runs during vblank compares "what we want" with "what we are displaying". If they are different, load new data.


What exactly is the main loop?
Is that the
Code:
while(1) {
    ...
}
in my main()?

As I have it right now, all of my code is in the VBlank method and nothing is in the while(1) {...} - should I move some from the VBlank? It seems like I tried that before I knew about VBlanks and things moved too fast to be useful...

#170939 - Dwedit - Tue Oct 27, 2009 5:11 am

By main loop, I just meant any non vblank routine code.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#170955 - Exophase - Tue Oct 27, 2009 5:49 pm

I find your glitch of sprites having horizontal lines running through them very strange. The only thing that could cause that is if OAM is modified mid-frame, but for single lines to appear the position would have to change and then get changed back. Or it might just be a glitch associating with writing to OAM during horizontal refresh, or possibly during hblank if the "process OAM during hblank" configuration bit is set. Or is the problem actually that the sprites stop entirely at a certain point?

You do have to make sure to update sprites and whatnot during vblank but you don't have to do game logic during screen rendering, you can do it at any time. Games usually copy to all of OAM and often the palette as well during the vblank handler, as well as submit other periodic tasks like swapping audio buffer pointers, counting ticks, and polling input. Although conventional wisdom dictates that you should keep interrupt routines quick you can actually get away with having a vblank interrupt as long as you need it, if you don't rely on other interrupts (or have a reenterable handler). Just be sure to update the screen stuff as soon after the vblank interrupt fires as possible.

#170961 - Miked0801 - Tue Oct 27, 2009 6:42 pm

Horiztonal lines dropping out of sprites can be caused by too many sprites on a scanline as well.

#170962 - scizzorz - Tue Oct 27, 2009 6:45 pm

Thank you again. I moved my OAM/BG updating/positioning to the start of the VBlank interrupt and it seems to be fixed.

In return, the cookies I promised.
http://www.library.drexel.edu/blogs/thesuggestionbox/Cookies.jpg

#170964 - Dwedit - Tue Oct 27, 2009 8:02 pm

Damn you, my monitor is now damaged from attempting to eat it.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#170965 - scizzorz - Tue Oct 27, 2009 8:09 pm

Haha :) One more quick question - what's a good/the best image/bitmap converter? I've been using mspaint and gfx2gba (packaged with HAM) but I was wondering if there was a better one, perhaps an editor designed specifically for GBA?

Many, many, many thanks to you all!

#170966 - keldon - Tue Oct 27, 2009 8:16 pm

scizzorz wrote:
Haha :) One more quick question - what's a good/the best image/bitmap converter? I've been using mspaint and gfx2gba (packaged with HAM) but I was wondering if there was a better one, perhaps an editor designed specifically for GBA?

Many, many, many thanks to you all!


usenti and grit from www.coranac.com

#170972 - Exophase - Tue Oct 27, 2009 10:16 pm

Miked0801 wrote:
Horiztonal lines dropping out of sprites can be caused by too many sprites on a scanline as well.


Although that's true you'd have to be reeeally pushing things in a pretty deliberate way, that and it could be hard to notice what with all those sprites overlapping each other.

If it happened for more than a few lines the person would have to be changing OAM mid-frame in a pretty deliberate fashion.

#171000 - sverx - Wed Oct 28, 2009 9:38 am

Miked0801 wrote:
Horiztonal lines dropping out of sprites can be caused by too many sprites on a scanline as well.


Wow! Too many sprites? How many can be safely placed on a scanline, in your experience?
Thanks :)

#171014 - Miked0801 - Wed Oct 28, 2009 3:15 pm

You start Double Size mode scaling your 2D sprites and it doesn't take long at all to start seeing dropout. My current game has a few screens where I got bit by this.

Without scaling though, you'd be very hard pressed to run into this issue. I'm not quite sure what's too many. It buried in the docs somewhere, but I don't have it off hand.

#171022 - Exophase - Wed Oct 28, 2009 8:29 pm

From GBATEK:

Quote:
Maximum Number of Sprites per Line
The total available OBJ rendering cycles per line are

1210 (=304*4-6) If "H-Blank Interval Free" bit in DISPCNT register is 0
954 (=240*4-6) If "H-Blank Interval Free" bit in DISPCNT register is 1

The required rendering cycles are (depending on horizontal OBJ size)

Cycles per <n> Pixels OBJ Type OBJ Type Screen Pixel Range
n*1 cycles Normal OBJs 8..64 pixels
10+n*2 cycles Rotation/Scaling OBJs 8..64 pixels (area clipped)
10+n*2 cycles Rotation/Scaling OBJs 16..128 pixels (double size)

Caution:
The maximum number of OBJs per line is also affected by undisplayed (offscreen) OBJs which are having higher priority than displayed OBJs.
To avoid this, move displayed OBJs to the begin of OAM memory (ie. OBJ0 has highest priority, OBJ127 lowest).
Otherwise (in case that the program logic expects OBJs at fixed positions in OAM) at least take care to set the OBJ size of undisplayed OBJs to 8x8 with Rotation/Scaling disabled (this reduces the overload).
Does the above also apply for VERTICALLY OFFSCREEN (or VERTICALLY not on CURRENT LINE) sprites ?


As far as the last sentence is concerned, it wouldn't make any sense for it to apply to anything but the sprites on the current line on a line per line basis. Otherwise you wouldn't see single horizontal lines go missing.

Even with double size rotated sprites you can still display 8 64 wide sprites per line, which is way more than will actually fit so they'd have to be pretty overlapped to begin with. This only applies if OAM processing during hblank is turned off, otherwise the number you can display would be lower. Unless you need sprite-multiplexing you should always have that option off.

With non-rotated 8 wide sprites you can actually display all of them on a single line :B

#171044 - Miked0801 - Thu Oct 29, 2009 3:31 am

Sprite overlapping heavily on some menus...