#173253 - gusano - Mon Mar 29, 2010 2:04 am
I'm having trouble understanding GFX_FLUSH. Normally what I would do is:
Code: |
Render();
GFX_FLUSH = 0;
.
.
.
swiWaitForVBlank();
|
which to me means that I'll do all my rendering with glBegin()...glEnd(), then with GFX_FLUSH = 0 I ask the hardware to swap buffers... which happens until the next vblank (when swiWaitForVBlank() returns?)...
but from what I've gathered, it seems like the geometry hardware works independent from the CPU... so although I'm calling GFX_FLUSH = 0, the actual render may finish until after the swiWaitForVBlank() call which means that the buffers will swap until 2 vblanks after rendering began.
can anyone please help me understand the rendering process, and what would be the normal way to use GFX_FLUSH in a 60fps game?
essentially I've been trying to achieve texture double buffering... I render using textures in bank C, and while that happens, I copy the next frame's texture into bank D. the next frame, rendering happens from bank D and the next texture is loaded into bank C.. and so on... but my current code causes flicker on the DS hardware... on No$GBA it looks fine... so I think I'm not understanding the big picture...
thanks in advance...
Last edited by gusano on Tue Mar 30, 2010 4:42 am; edited 1 time in total
#173279 - sajiimori - Mon Mar 29, 2010 6:55 pm
I don't know why you're getting flicker.
In Render(), you're uploading commands to the gfx hardware. The gfx hardware processes your commands as you're uploading them, and it stores the results (verts for clipped polys in screen space) to one of its two buffers.
Meanwhile, the gfx hardware is simultaneously drawing the other buffer to the screen, from top to bottom. So there are really 3 things happening in parallel.
If you finish uploading your commands before vblank, but the gfx hardware didn't have enough time to finish processing them before vblank, then you're not running at 60fps -- you need to finish uploading your commands sooner.
But in practice, although there's a gap between when you finish uploading and when the gfx hardware finishes processing, it's not a very large gap, because you can't queue very many commands. In other words, the CPU can't get very far ahead, because anytime the gfx hardware is not fast enough to keep up, the CPU simply stalls.
You should call GFX_FLUSH as soon as you're done sending commands. On a 60fps game, you don't necessarily need to call swiWaitForVBlank, because trying to upload additional commands after a GFX_FLUSH will automatically block the CPU until the buffer swap is completed.
But again, in practice, it shouldn't make much difference whether you call swiWaitForVBlank. You have to finish your frames in 1/60 of a second, and you should always have some extra time left. It doesn't necessarily matter how you spend that time.
#173282 - gusano - Mon Mar 29, 2010 8:13 pm
Would calling something like glPushMatrix() after GFX_FLUSH cause the CPU to stall if it hasn't finished processing commands?
EDIT: I'm looking through my code to check for any graphics commands happening after GFX_FLUSH but before Render()... but most likely I don't have any...
on another note... let me see if I've understood this:
When you start calling gfx commands, the gfx hardware immediately starts processing them... so an actual render begins as soon as I have my first glBegin()...glVertex3v16()... glEnd() block... (or state setting commands like glPushMatrix() or glColorTable())... When GFX_FLUSH is called, the gfx hardware could still be rendering... it'll eventually be done and at some point... then does the back buffer become the front buffer (page flip) or is the back buffer copied to the front buffer?... if it's copied, then is this what VDraw is?
#173283 - sajiimori - Mon Mar 29, 2010 9:09 pm
Yes, glPushMatrix (and gl-just-about-anything) will wait for any pending buffer swaps to complete.
The DS doesn't have any framebuffers. It has vertex buffers. When you upload commands, the hardware projects and clips them, and fills a vertex buffer with the results. Every VDraw, it renders the contents of one of the vertex buffers, from top to bottom, as the scanline moves down the screen.
Even if you don't draw anything new, it keeps rendering the same old polys, every VDraw, because there is no framebuffer.
When you are "rendering", try to think of it more as "uploading". The hardware processes your commands, but your stuff doesn't start rendering until the buffers are swapped. (Meanwhile, the hardware keeps on rendering the contents of the other buffer.)
#173284 - gusano - Mon Mar 29, 2010 9:39 pm
Ok, so I upload my state change and draw commands...
The hardware starts processing those and will fill vertex buffer "A" with the results...
I set GFX_FLUSH = 0;
[Meanwhile, it could still be rendering the contents of vertex buffer "B", am I right?]
Any gl commands called here will stall the cpu...
VDraw starts, so it'll swap buffers and start rendering the contents of vertex buffer "A"... any subsequent gl calls will cause vertex buffer "B" to be updated...
VDraw is done and now VBlank begins...
If I have a custom vblank handler (which I don't), it could do stuff here...
VBlank is done... back to VDraw (now using vertex buffer "B" to render)
.
.
.
is this correct?
How does VRAM fit into all this? What exactly is LCD mode on a vram bank? All I know is, I'm supposed to set it to LCD, then change data, then move back to TEXTURE mode (in my case)...
#173286 - sajiimori - Mon Mar 29, 2010 10:22 pm
I think you've got it down.
VRAM stores textures and palettes, which the gfx hardware uses while rasterizing your polys. The DS has no way to let the gfx hardware access VRAM at the same time as the CPU. So, there's a special mode (LCDC -- I don't know what it stands for) that maps parts of VRAM to an address range, to let the CPU access it. However, that prevents the gfx hardware from reading those parts. If it tries, you get black lines on the screen.
#173287 - gusano - Mon Mar 29, 2010 10:41 pm
Thanks for your help sajimori, I think what I've been getting is not flicker then... it's black lines due to the gfx hardware reading VRAM while it's on LCDC mode... how can I avoid this?
I set the vram banks to LCDC when I'm copying my dynamic texture into my next frame vram buffer... When I started out, I set banks A,B,C,D to LCDC but I was only copying to bank C or D... I think I've already tried only setting bank C or D to LCDC mode... but I'll try again because at this point I've changed my code so many times that I'm not sure what I've tried and what I haven't.... haha
Thanks again!
#173290 - gusano - Tue Mar 30, 2010 3:08 am
Problem solved!!
When I was copying my dynamic textures into banks C or D I was also setting banks A and B to LCDC mode... so I got black lines... I made it so only the bank I'm updating gets set to LCDC (and back to TEXTURE when I'm done updating)... and it worked!
Thanks sajimori!