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.

C/C++ > switch() speed killing?

#18568 - LOst? - Mon Mar 29, 2004 1:01 am

I have a switch() statement that updates the selected background, like most of use have I guess?

Now I wanted to use the UpdateBackground() with the switch() in my Hblank interrupt, but it didn't manage to finish the work before the interrupt time was over making the background flicker in some areas. So I fixed it by taking out the switch() and just updating the bg registers of the background I wanted to do the effect for and that worked.

Now i'm afraid to use switch() for anything, and when am I then to use? goto labels? That's so far away from OOP as I can get.

So, why are switch() so bad?

#18572 - Miked0801 - Mon Mar 29, 2004 1:50 am

They aren't. Most of the time, a switch is changed into an offset table read then PC jump. If your switch is small though, quite often the compiler will change it to a if/else if construct to save space or time. Still, why are you doing a switch statement in HBlank? That's pretty much the last place you want to do conditional checks style code. You should be able to setup a system where the code you want to run is figured out well before you get to the interrupt - perhaps by setting up a function pointer in real time that is later used by the hblank.

#18595 - torne - Mon Mar 29, 2004 1:30 pm

If the case values in a switch are consecutive (or nearly so) then it will almost always compile into a jump table, which is fast (unless there are very few choices, as miked said, but if there are that few then going through the ifs shouldn't be too bad). If your values are not consecutive then it'll make a set of if-else's however many there are.

#18608 - LOst? - Mon Mar 29, 2004 8:52 pm

Miked0801 wrote:
Still, why are you doing a switch statement in HBlank?


I wanted to have the same standard as I use in the main game loop. I call a UpdateBG (&bg1) and I just used the same call in the HBlank and that wasn't a good move.

I have to find and use a better standard for updating sprites and backgrounds so that they will be compatibe with my HBlank bg effect proc.

If crt0.s uses a good way of calling interrupts, maybe I should let the VBlank interrupt take care of all updates of sprites and backgrounds, and lock VBlank so that it can only be called when I want to render the screen. Is that a good way?

Oh yea the question is for Miked0801 because he seems to know much about game designing (since he's professional). But you all may answer the question :P

#18611 - poslundc - Mon Mar 29, 2004 10:12 pm

LOst? wrote:
If crt0.s uses a good way of calling interrupts, maybe I should let the VBlank interrupt take care of all updates of sprites and backgrounds, and lock VBlank so that it can only be called when I want to render the screen. Is that a good way?


crt0.S offers three different ways of calling interrupts, depending on what your needs are. You need to modify crt0.S to select which one you want to use.

None of those ways are better than writing your own interrupt handler, though. (If you want to use the Fast Interrupts mode in crt0.S you may as well just write your own ISR and copy its address to 0x03007FFC. It'll be the same as doing it through crt0.S but you'll save a load and branch instruction.)

When writing your own ISR, check to see if it is a HBlank ISR and if so service that immediately (you've only got 224 cycles to do it in), all other interrupts can wait. Especially if you are also using interrupts to handle VBlank processing, which lasts for almost 84,000 cycles!

If you are doing anything more complicated in HBlank than updating a few registers (in which case you should just use HDMA anyway, which is simpler and more efficient), consider learning assembly and doing it in that. HBlank is just that short.

I don't recommend using interrupts to handle VBlank, although others may disagree. All I would likely use the VBlank interrupt for is if I want to halt the CPU to save batteries and need the interrupt just to get it started again when VBlank arrives.

Quote:
Oh yea the question is for Miked0801 because he seems to know much about game designing (since he's professional). But you all may answer the question :P


Thanks. :P

Dan.

#18617 - Miked0801 - Mon Mar 29, 2004 11:28 pm

Lol - you hurt Dan's feelings :)

For what it's worth, here what we do.

We use VBlank for Sprite OAM copies, palette updates, and reseting of stuff that our HBlank routines fiddle with (scroll windows and register resets, Alpha Blends resets, etc.) We also use VBlank for setting up our HBlank interrupt chains (through a request system so we don't accidently play with hblank while its trying to read a vector. No fun like a 1 in million load half an address and jump bug.) Using VBlank as our base function for updates works well for preventing visual gltiching and the like that is caused by playng with interrupt stuff at run time.

For HBlanks, if we need to do anything real complex, we break the line before we want the effect to happen, do all the setup code, wait for the hblank period to begin in a tight loop, then go to town. We use a vector table that updates a pointer after every function is called to allow an easy way to go from function to function (there is overhead involved in this, but the ease of development I believe outweighs the costs.)

Don't know if I answered your question, but there's some info there none the less :)

#18618 - LOst? - Mon Mar 29, 2004 11:31 pm

poslundc wrote:
LOst? wrote:
If crt0.s uses a good way of calling interrupts, maybe I should let the VBlank interrupt take care of all updates of sprites and backgrounds, and lock VBlank so that it can only be called when I want to render the screen. Is that a good way?


crt0.S offers three different ways of calling interrupts, depending on what your needs are. You need to modify crt0.S to select which one you want to use.

None of those ways are better than writing your own interrupt handler, though. (If you want to use the Fast Interrupts mode in crt0.S you may as well just write your own ISR and copy its address to 0x03007FFC. It'll be the same as doing it through crt0.S but you'll save a load and branch instruction.)

When writing your own ISR, check to see if it is a HBlank ISR and if so service that immediately (you've only got 224 cycles to do it in), all other interrupts can wait. Especially if you are also using interrupts to handle VBlank processing, which lasts for almost 84,000 cycles!

If you are doing anything more complicated in HBlank than updating a few registers (in which case you should just use HDMA anyway, which is simpler and more efficient), consider learning assembly and doing it in that. HBlank is just that short.

I don't recommend using interrupts to handle VBlank, although others may disagree. All I would likely use the VBlank interrupt for is if I want to halt the CPU to save batteries and need the interrupt just to get it started again when VBlank arrives.

Quote:
Oh yea the question is for Miked0801 because he seems to know much about game designing (since he's professional). But you all may answer the question :P


Thanks. :P

Dan.


Yes 84,000 cycles! That's a dream to hear. I will try to make the VBlank handle all the updates of sprites, palettes, and backgrounds. That way I will be able to synchronize them on every frame without doing any mistakes.

And HDMA is something I should learn to use. Still I don't know how it works (I can look it up) and how I would be able to use it fro scroll effects on backgrounds, including the first scanline (which I had to get working with a lot of hacks)

#18627 - tepples - Tue Mar 30, 2004 3:57 am

Getting the first scanline of an HDMA working is easy: just write the first scanline's data manually during Vblank, and then start the HDMA with the source address pointing at the second scanline's data. What "lot of hacks" did you need?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#18648 - LOst? - Tue Mar 30, 2004 11:16 pm

tepples wrote:
Getting the first scanline of an HDMA working is easy: just write the first scanline's data manually during Vblank, and then start the HDMA with the source address pointing at the second scanline's data. What "lot of hacks" did you need?


Code:

void HblankS ()
{
   Vcnt = (u32) REG_VCOUNT;
   Vcnt += 1;

   if (Vcnt > 227)
      Vcnt = 0;

   Vcnt += (screen_y >> bgintshift_y);
   if (Vcnt >= 512)
      Vcnt = 1;
   else if (Vcnt < 0)
      Vcnt = 0;

   bg0.y_scroll = screen_y * lines_y [Vcnt];
   bg0.x_scroll = screen_x * lines_x [Vcnt];

   REG_BG0HOFS = (bg0.x_scroll >> bgintshift_x);
   REG_BG0VOFS = (bg0.y_scroll >> bgintshift_y);

   REG_IF |= INT_HBLANK;
}


That's what I call hacking.

#18650 - LOst? - Tue Mar 30, 2004 11:17 pm

Miked0801 wrote:
Lol - you hurt Dan's feelings :)

For what it's worth, here what we do.

We use VBlank for Sprite OAM copies, palette updates, and reseting of stuff that our HBlank routines fiddle with (scroll windows and register resets, Alpha Blends resets, etc.) We also use VBlank for setting up our HBlank interrupt chains (through a request system so we don't accidently play with hblank while its trying to read a vector. No fun like a 1 in million load half an address and jump bug.) Using VBlank as our base function for updates works well for preventing visual gltiching and the like that is caused by playng with interrupt stuff at run time.

For HBlanks, if we need to do anything real complex, we break the line before we want the effect to happen, do all the setup code, wait for the hblank period to begin in a tight loop, then go to town. We use a vector table that updates a pointer after every function is called to allow an easy way to go from function to function (there is overhead involved in this, but the ease of development I believe outweighs the costs.)

Don't know if I answered your question, but there's some info there none the less :)


Yea that's about it! I want to do that myself. I can see how many professional games are changing the registers every frame so you can't hack it with VisualBoy Advance.