Game loops and Vertical Blank interupts
Moderator: BigEvilCorporation
-
- Interested
- Posts: 33
- Joined: Tue Feb 23, 2016 4:45 pm
Game loops and Vertical Blank interupts
I'm vaugely hacking around Gunstar Heroes, and one thing that's confusing me (actually lots of things are, but one at a time ) is how it's managing it's game loop.
My understanding is that usually you'd do init and then game loop in the entry point, and wait on the vblank for end of frame. Meanwhile in the vblank interupt you'd do a few things you need correct timing for (dma'ing palettes?) and very little else. Poking around the Sonic 1 disassembly it seems to basically do this.
GH however appears to do all it's logic in the vblank interupt. There is a loop at the end of the entry point, but it's mostly just idling (I managed to get from boot to halfway into a level before it did anything other than nop, and seems to be some kind of loading routine). Is this normal for a MD game? I would have thought that doing so much work in the vblank would make it super hard to do the things you'd normally do in a vblank at the correct time.
My understanding is that usually you'd do init and then game loop in the entry point, and wait on the vblank for end of frame. Meanwhile in the vblank interupt you'd do a few things you need correct timing for (dma'ing palettes?) and very little else. Poking around the Sonic 1 disassembly it seems to basically do this.
GH however appears to do all it's logic in the vblank interupt. There is a loop at the end of the entry point, but it's mostly just idling (I managed to get from boot to halfway into a level before it did anything other than nop, and seems to be some kind of loading routine). Is this normal for a MD game? I would have thought that doing so much work in the vblank would make it super hard to do the things you'd normally do in a vblank at the correct time.
Re: Game loops and Vertical Blank interupts
As long as you do vblank duty at the beginning of the exception (or interrupt as is called on others cpus) this method works too. Super Mario Bros (NES) works just like this.
The problem is that while you are answering a video exception you can't acknowledge another one, making it a sub-optimal solution. If there is a slow down one consequence will be that music will be delayed and therefore distorted, and curiously that makes a more big impact on the player that video delay for the same period.
If the game can ensure that will be no slow down (frame lost), there is no difference whatsoever.
The problem is that while you are answering a video exception you can't acknowledge another one, making it a sub-optimal solution. If there is a slow down one consequence will be that music will be delayed and therefore distorted, and curiously that makes a more big impact on the player that video delay for the same period.
If the game can ensure that will be no slow down (frame lost), there is no difference whatsoever.
HELP. Spanish TVs are brain washing people to be hostile to me.
-
- Interested
- Posts: 33
- Joined: Tue Feb 23, 2016 4:45 pm
Re: Game loops and Vertical Blank interupts
Hmm, I guess that makes sense. Wouldn't this make it really had to do h-blank effects as well? Because now the vblank code is still running and hblanks can't interupt it to do fancy scanline effects (and from what I can tell, Gunstar Heroes has a lot of hblank effects).
Re: Game loops and Vertical Blank interupts
Yes: vertical exception have more priority than the horizontal, in consequence vertical code will mask horizontal exception code, but still you can use the horizontal counter to keep track of the current line to make those effects.
That's in theory, I haven't dissect Gunstar Heroes code.
That's in theory, I haven't dissect Gunstar Heroes code.
HELP. Spanish TVs are brain washing people to be hostile to me.
-
- Interested
- Posts: 33
- Joined: Tue Feb 23, 2016 4:45 pm
Re: Game loops and Vertical Blank interupts
Ok, that makes sense, thanks!
I still don't know why they wouldn't do it a more 'normal' way, as there doesn't seem to be an advantage to it. Maybe I'll find out when i've taken it apart a bit more.
I still don't know why they wouldn't do it a more 'normal' way, as there doesn't seem to be an advantage to it. Maybe I'll find out when i've taken it apart a bit more.
Re: Game loops and Vertical Blank interupts
Then you have Sonic 3D doing part of the game loop in the main thread and part in the vblank interrupt. And the latter was doing the logic for every object on screen. It took a while to figure out how the heck the two were connected.
I honestly prefer the vblank interrupt to just set a flag and nothing else. The vsync subroutine in the main thread can then see it and resume work. If I ever really need to time something strictly to vblank I'll add that to the interrupt (maybe to setup raster effects reliably just in case the game slows down?), but so far vsync alone has been enough.
I honestly prefer the vblank interrupt to just set a flag and nothing else. The vsync subroutine in the main thread can then see it and resume work. If I ever really need to time something strictly to vblank I'll add that to the interrupt (maybe to setup raster effects reliably just in case the game slows down?), but so far vsync alone has been enough.
Sik is pronounced as "seek", not as "sick".
-
- Interested
- Posts: 33
- Joined: Tue Feb 23, 2016 4:45 pm
Re: Game loops and Vertical Blank interupts
Yeah, I don't have much experience with MD programming, but in my mind interupts should do the smallest amount of work possible and finish as quickly as possible.
Having said that - I wonder if what GH is doing is using the main thread as a background loading loop? It seems to be idle until memory addresses get poked with load requests. That way the vblank can do important logic, then yield and let the rest of the frame be filled with low-priority streaming. If the streaming is taking too long, the vblank will still kick in and run the next frame. Plausible?
Having said that - I wonder if what GH is doing is using the main thread as a background loading loop? It seems to be idle until memory addresses get poked with load requests. That way the vblank can do important logic, then yield and let the rest of the frame be filled with low-priority streaming. If the streaming is taking too long, the vblank will still kick in and run the next frame. Plausible?
-
- Very interested
- Posts: 2440
- Joined: Tue Dec 05, 2006 1:37 pm
- Location: Estonia, Rapla City
- Contact:
Re: Game loops and Vertical Blank interupts
I poll for VBL bit in the VDP in main loop and I also set a flag in the frame interrupt. If main loop sees that the flag is set after all game logic it can assume slowdown has happened and act upon it, when flag isn't set the logic ended before frame did.
Mida sa loed ? Nagunii aru ei saa
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen
Re: Game loops and Vertical Blank interupts
Actually is a pretty good dam idea... no, it's very close to necessary IF you are building a continuous level loading game, for other types of games it involves more problems than solutions.OrangyTang wrote: ↑Wed Apr 04, 2018 3:45 pmHaving said that - I wonder if what GH is doing is using the main thread as a background loading loop? It seems to be idle until memory addresses get poked with load requests. That way the vblank can do important logic, then yield and let the rest of the frame be filled with low-priority streaming. If the streaming is taking too long, the vblank will still kick in and run the next frame. Plausible?
Let's recapitulate: exceptions/interruptions allows the programmer to avoid uninterrupted polling along all the code. Then, if you are making a game that follows those rules:
- Game loads into ram continuously the level. So in ram we have a few screens around (or forward) the main character. The farthest is the one is loading.
- Having the level in ram let's you modify it. If you think a bit: you have to chose between the ability to modify it or double scroll direction.
- Only forward scroll, although it's not strictly necessary, helps simplifying things.
- Level is compressed in big chunks, like for example screens, that provides much better compression which is a winner since big levels take a lot of it.
So in the main/start/reset you basically have a procedure to decompress a level which have not to do pulling at all, neither has to be synchronized at a frame level with the game. And in the vertical exception all the remaining things. Half way to a current sand box really.
Plainly this approach is not useful at all for a more conventional game that loads the level only at the start, but other ways it rocks.
Other way to see it is that what makes it so impressive is that you don't need to compress the level in little chucks, probably columns, and accommodate this time inside a frame, but you can do it asynchronously in really big chunks without impact on the frame rate.
That's completely correct within a operative system: just fill the buffer and quit the interrupt as quickly as possible.OrangyTang wrote: ↑Wed Apr 04, 2018 3:45 pmYeah, I don't have much experience with MD programming, but in my mind interupts should do the smallest amount of work possible and finish as quickly as possible.
But in a MD you can do what ever you want: there is no other program to be taken care of.
HELP. Spanish TVs are brain washing people to be hostile to me.
-
- Interested
- Posts: 33
- Joined: Tue Feb 23, 2016 4:45 pm
Re: Game loops and Vertical Blank interupts
Yeah, the more I think about it, the more it makes sense to be a background loading system. Especially as the main thread loop has what looks suspiciously like a decode routine and a whole bunch of vram copy routines.
I suspect GH uses it more for boss loading (it has a lot of bosses in quick succession) rather than level streaming, but we'll see what shakes out.
I suspect GH uses it more for boss loading (it has a lot of bosses in quick succession) rather than level streaming, but we'll see what shakes out.
Re: Game loops and Vertical Blank interupts
Transferring data to the video chip during display period is possible but very slow, unwise because cpu is blocked for much more time than the same data along vblank. For a single value is ok, but for buffer I think is unlikely Treasure did this mistake.
Another potential target to decompress "in the background" is the spawn array which has to be pretty large for this game.
Another potential target to decompress "in the background" is the spawn array which has to be pretty large for this game.
HELP. Spanish TVs are brain washing people to be hostile to me.
Re: Game loops and Vertical Blank interupts
I think I have found a solution to get the best of both words, works but I'm still developing it:
That's the traditional model, stop and load:
That's the continuous loading model:
That's the continuous loading model with HINT's available:
So yes, with a bit of work is possible to obtain HINT's too.
That's the traditional model, stop and load:
Code: Select all
reset:
jsr initialization
jmp gameLoop /* MUST be synchronized to frame*/
vertException:
movem.l %d?/%a?, -(%sp)
jsr doDMAThings
movem.l (%sp)+,%d?/%a?
rte
Code: Select all
reset:
jsr initialization
jmp backgroundTasks
vertException:
movem.l %d?/%a?, -(%sp)
jsr doDMAThings
jsr gameLoop /* No HINT available*/
movem.l (%sp)+,%d?/%a?
rte
Code: Select all
reset:
jsr initialization
jmp backgroundTasks
vertException:
movem.l %d?/%a?, -(%sp)
jsr doDMAThings
movem.l (%sp)+,%d?/%a?
* Copy SR
subq.l #2, %sp
move.w 2(%sp), -(%sp)
* Insert new return address
move.l #Frame, 2(%sp)
* It returns from exception but jumps to 'Frame', another 'rts' will jump to what was actually doing
rte
Frame:
move %sr, -(%sp)
movem.l %d?/%a?, -(%sp)
jsr gameLoop
movem.l (%sp)+,%d?/%a?
move (%sp)+, %sr
rts
HELP. Spanish TVs are brain washing people to be hostile to me.
-
- Very interested
- Posts: 3131
- Joined: Thu Nov 30, 2006 9:46 pm
- Location: France - Sevres
- Contact:
Re: Game loops and Vertical Blank interupts
Why you just don't change interrupt mask level directly in SR register before jumping to gameloop ?
Re: Game loops and Vertical Blank interupts
As mentioned before the problem is during the vertical exception you can receive horizontal ones, because them are of lower priority.
So in the 3rd example what is done is to return from exception but to a custom code, it only saves/restores SR content to preserve flags.
This is kind of a trick (or bad practice if you want): the final example returns from exception but only half.
Also with this trick enables you to receive vertical exceptions during gameLoop to synchronize things like sound. (Also notice the example lacks a variable so synchronize this last part.)
Basically you got 3 "threads":
- Vertical non-interruptible by h/v-ints, to do DMA work
- GameLoop interruptible by h/v-ints, synchronized after Vertical "thread"
- Background: decompress work and alike, completely unsynchronized (unless you code it)
So in the 3rd example what is done is to return from exception but to a custom code, it only saves/restores SR content to preserve flags.
This is kind of a trick (or bad practice if you want): the final example returns from exception but only half.
Also with this trick enables you to receive vertical exceptions during gameLoop to synchronize things like sound. (Also notice the example lacks a variable so synchronize this last part.)
Basically you got 3 "threads":
- Vertical non-interruptible by h/v-ints, to do DMA work
- GameLoop interruptible by h/v-ints, synchronized after Vertical "thread"
- Background: decompress work and alike, completely unsynchronized (unless you code it)
HELP. Spanish TVs are brain washing people to be hostile to me.
-
- Very interested
- Posts: 3131
- Joined: Thu Nov 30, 2006 9:46 pm
- Location: France - Sevres
- Contact:
Re: Game loops and Vertical Blank interupts
Yeah i understand but just lowering interrupt mask level in SR register right after doDMAstuff and before jumping to gameloop should be enough to produce the same result, you can read/write SR register... or i'm missing something ?