#125202 - RavenWorks - Thu Apr 12, 2007 2:05 am
I'm currently working on a 2D game, that renders some elements on quads using the 3D hardware. I'm finding there's a one-frame delay between the graphics done on the 2D hardware and those done on the 3D hardware, but before you answer, I'm already buffering all the 2D elements until the next vblank (so they'll go through at the same time as the 3D instructions do).
I've got a little pseudocode writeup of the way I'm doing things here: http://img.ravenworks.ca/3D2D.txt
There's also a table that outlines what SHOULD be happening based on my understanding of these things, but the 3D still seems to be one frame behind.
Any ideas?
#125261 - masscat - Thu Apr 12, 2007 12:47 pm
EDIT: ignore this post as it is not correct :)
The 3D buffer swap command does not take affect until the following Vblank (see gbatek).
This leads to the following using your current program flow, hence the one frame delay:
Code: |
|--------|--------|----------|------------|
| 2D RAM | 2D OAM | 3D queue | 3D display |
--------|-------|--------|--------|----------|------------|
| START | -- | -- | -- | -- |
FRAME 1 |-------|--------|--------|----------|------------|
| END | 1 | -- | 1 | -- |
--------|-------|--------|--------|----------|------------|
--------|-------|--------|--------|----------|------------|
| START | 1 | 1 | 1 | -- |
FRAME 2 |-------|--------|--------|----------|------------|
| END | 2 | 1 | 2 | -- |
--------|-------|--------|--------|----------|------------|
--------|-------|--------|--------|----------|------------|
| START | 2 | 2 | 2 | 1 |
FRAME 3 |-------|--------|--------|----------|------------|
| END | 3 | 2 | 3 | 1 |
--------|-------|--------|--------|----------|------------|
|
So the control of your program should be something like:
Code: |
Some time before vblank:
{
Do game logic.
Update 2D RAM.
Issue 3D commands and swap command.
}
Vblank:
{
(hardware prepares to display 3D commands issued)
Copy 2D RAM to OAM
}
|
The importance difference is that on entering Vblank the 3D already has the display for the next frame.
If you want to trigger off of vblank you could do something like:
Code: |
Vblank:
{
copy 2D ram[oldest] to OAM.
2D ram[oldest] = 2D ram[old].
do game logic.
issue 3D commands and swap.
update 2D ram[old].
}
|
But this would lead to a one frame delay from user input to screen update.
Last edited by masscat on Thu Apr 12, 2007 6:11 pm; edited 1 time in total
#125262 - RavenWorks - Thu Apr 12, 2007 1:00 pm
Do you mean, the 3D refuses to start rendering until a vblank, but it ALSO takes a full vblank interval to *finish* rendering? (I assumed the rendering finished between the vblank interrupt and the drawing of the first scanline..)
I still don't understand the difference between my example and your first example... the "some time before vblank" for me is the end of the previous vblank function call.
Thanks! :)
#125325 - masscat - Thu Apr 12, 2007 5:52 pm
Apologies, I buggered up my timings. And the two versions are the same.
#125330 - RavenWorks - Thu Apr 12, 2007 6:06 pm
OK, so, that means that there's still no-one who can explain this delay, then ;)
This means either I'm imagining it, or I'm deviating from my plan in some way I haven't noticed, or just no-one *else* has noticed it yet? (I'm beginning to wonder if it's even worth worrying about..)
I think I'm going to make a really simple example with one shape occluding another, to prove whether or not this delay exists, then post the source..
#125342 - DekuTree64 - Thu Apr 12, 2007 6:50 pm
The swap command will only be processed at the moment of VBlank starting, so if you wait until you're already into the VBlank interrupt handler, it's too late.
Getting 100% guaranteed synchronization (such as for 2 screen 3D) is really tricky, because there's a small period of time just before VBlank starts where all bets are off.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#125346 - RavenWorks - Thu Apr 12, 2007 6:55 pm
I know it's too late if I wait until I'm in the handler -- that's why I delay all my 2D graphics until the next frame also. The thing to note about my program is that (other than copying the last frame's 2D buffer to live 2D OAM), the vblank is basically just my cue that it's alright to start preparing for the NEXT frame, not that frame. Unless you think that my vblank-triggered game logic is taking so long that I wind up past scanline 185 by the time it's done? (which is a possibility, honestly..)
edit: maybe I should clarify, I want to know why there's STILL a delay, even though I'm already delaying my 2D until the next vblank trigger to line up with the 3D update..
#125360 - DekuTree64 - Thu Apr 12, 2007 7:56 pm
Wait, so you're doing your entire game logic in the VBlank handler? That can cause weirdness if it runs over, or total destruction if you have nested interrupts enabled. Generally you want your game loop to still function properly regardless of how long it takes to run (for example, loading a level can take a long time and still be considered one game loop).
I generally go with the style of do game logic -> set flag -> wait for VBlank. Then the VBlank handler checks the flag to decide if it should update the display. That way VBlank interrupts will still be firing off in the meantime to take care of any other processing that needs to be done, but the video is still synchronized to the game loop.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#125364 - RavenWorks - Thu Apr 12, 2007 8:51 pm
Well, what I'm actually doing is, the vblank sets a flag for the main{while(1){ }} to catch, and the while(1) is where the logic actually gets executed. But it happens immediately after the (very short) vblank handler, so I just left it there in the pseudocode for simplicity's sake ;P So, yeah, that wasn't quite accurate, but in fact I *used* to do it like that (before I realised it would mess up my other interrupts), and I still had this problem.
#125680 - RavenWorks - Mon Apr 16, 2007 12:20 am
*awkward cough*
So, umm...
after a bit of testing, I've realised it was a logic problem. XP
Sorry to have wasted everyone's time ^^;; Thanks anyway.