Discussion in 'General Discussions' started by notaz, Nov 24, 2011.
I redraw always every frame.
The fps in the demonstration video of foxblock are at most 40.
I'm fully redrawing every frame; now I'm using vsync to avoid problems but without vsync I noticed flickering (always in the bottom part of the screen) even with double/triple buffering. I don't understand how this can happen because I never do an SDL_Flip() before a frame is fully drawn, and I running at about 60 fps - due to rounding errors etc it may have fluctuated a bit, but I don't think it would ever draw two complete frames in one 16ms time window, which would be needed to get it to draw to front buffer.
With vsync off and doublebuffer also off, I do get some tearing (upper part and lower part of the screen are not the same frame), but I don't get visible flicker. With vsync on and doublebuffer off, the tearing is more noticeable and I do see some flicker. I guess that's because there is only a front buffer and when it waits for vsync, it becomes more likely that the new frame drawing interferes with the old frame display.
With vsync off and doublebuffer on, there is a small amount of flicker - I have no idea how this can happen. Only with both vsync and doublebuffer on I get things completely flicker-free.
For the sparrow3d problems: if you're running at 40fps that means there are 3 actual vsyncs happening every 2 frame flips. That's probably not a good idea. I think it's best to use 60fps or integer fractions of it (30fps, 20fps), and use vsync + doublebuffer.
Probably what's happening is your buffer positioning is out of sync and when you think you're writing to a backbuffer you're actually writing to the frontbuffer. You don't have to draw two complete frames in one 16ms period for this to happen, you just to gradually drift outside of the period.
At any rate, is there a good reason to leave vsync off?
I don't think there is any good reason to not wait for vsync - I initially left it off because that's the default, the flicker was not very noticeable, and the code I had to time the frames was not very good, which meant that enabling vsync caused it to drop frames for no good reason. So it seemed to be better to just leave it disabled, but then I started noticing the flicker, enabled vsync and improved the frame timing code.
But I still don't see how I can get flicker with triple buffers, even with vsync off. If I'm drawing on buffer N, then the display should be using either buffer N-2 %3 or buffer N-1 %3 (if vsync is on it should always be N-1 %3, otherwise it can be a mix between N-2 %3 and N-1 %3). Right?
Then there is either a bug in your code (you don't update your internal screen pointers from one you get form SDL_Flip() ), or old version of SDL that had some bugs with this.
It's not hard to think of such case:
- Your timing code takes some time reference, let's say it's 0ms
- Kernel had some work to do (write out to SD or whatever), your game has no control for 30ms
- You get control back and call SDL_Flip() to send a buffer you got ready before kernel became busy, pointer to buffer  with that frame makes it way to hardware. At the same time LCD/dispc has just started redrawing buffer  so hardware is not using your new pointer, puts it into a shadow register for next frame. SDL_Flip() gives you a pointer to buffer .
- Your timing code sees 30ms passed, so it needs to do another frame, you do it (let's say the scene is simple and takes < 1ms), call SDL_Flip() and get a pointer to .
- Now is let's say your timing code calculates 30-16 = 14, which means it needs to sleep 2ms to limit to 60fps, let's say it does that but LCD update will only progress for maybe 30% of screen over all this, and you start redrawing  which it's still displaying..
I don't know if your timing code is like that but maybe that can give you an idea how things like that happen.
Of course if someone wants to do a properly timed sample that demonstrates that I'm wrong and it's SDL's fault, please go ahead, but with such severe problems as in Ziz's video I'm pretty sure it's a problem in his code (or SDL version there is old).
Wait... After SDL_Flip I have to get the screen pointer again e.g. with SDL_GetVideoSurface? This is new to me. I thought the pointer stays valid the whole time.
Edit: Other idea. I have in fact no idea about the implementation details of SDL. But if I would write such a library like SDL, I would let the SDL_Surface pointer as it is at the flip, but change the pixels-pointer. Could it be, that this is the actual implementation? Because I cache this pixels-pointer and don't reload it after flip. ^^'
Yes, only screen SDL_Surface's ->pixels pointer changes after flip, so you only need to re-read that. This part is not pandora specific.
Interesting... I wonder, what that means for my PC's SDL Implementation. No Double buffering support? Because there it worked always like a charm. I thought at least the PC's SDL implementation is almost feature complete... I implemented the change and gave it my testing monkey foxblock for his pandora. Let's see.
Edit: My test monkey finished his work: It works now and it is 20% faster! Thanks for the explanation of SDL, notaz. ^^'
Thanks for the explanation, notaz! What I didn't realize was that after an SDL_Flip(), the hardware can still be displaying buffer 0, showing buffer 1 only in the next frame. I assumed it would switch buffers mid-frame. So if you do an SDL_Flip() twice in a row while displaying buffer 0, does it continue showing buffer 0, and in the next frame it then immediately shows buffer 2 (skipping buffer 1)?
I also did not realise this... I don't think it has ever been specifically pointed out in anything I've read either.
This is possible something one realises with hacking around with the source?
Probably whatever PC environment you used it in doesn't let you write directly to the framebuffer. So the hardware framebuffer/backbuffer may be getting flipped but the pixels pointer wouldn't point to it, and the SDL_Flip call would still copy the surface to the hardware backbuffer first.
notaz's SDL on the other hand does give direct framebuffer access. But I don't think it's violating anything to let the pixels pointer change, you're supposed to wrap access to it in SDL_LockSurface/SDL_UnlockSurface and you're supposed to read the pointer after this.
It will continue with 0 until it's finished with it and then switch to whatever was sent last, which in this case is 2.
I thought it's obvious for everyone - multiple buffers - multiple pointers?
As for PC version, at least under Linux with X, SDL_DOUBLEBUF is ignored, don't know about windows.
Yes that makes sense if one is double buffering manually but it seems like many of us wrongly assumed that SDL handled the getting of the correct pointer.
Any how it's nice to learn something new, heh!
(highlighting from me)
Yeah, now I know this, too... I just thought locking is enough and cached the pixels-pointer the whole time. Dunno, what I thought by implementing it this way... Obviously not enough.
FYI: My new code now uses real Double Buffering on all targets without using an extra surface, which is blited in the end (except Dingux. Dingux don't support Double buffering)
I guessed so yesterday in a chat with foxblock, why my fucked up Double buffering code worked on my PC. Yeah, I was right in the end. ^^'
I think the latest update to the git has broken sdl. This new file SDL_x11reuse is not referenced in the configure so the link of the resulting sdl failed. But even when adding the file, I can't initialise libSDL anymore. It just hang at the SDL_Init. Or is it just me?
*EDIT*, just tried the "tests" of SDL and they worked. So it's something else, sorry for the false alarm.
You have to regenerate your configure script by running autogen.sh, it's a generated file that doesn't come in the repository.
Oh, ok, thanks.
Thats rather strange.
I have compiled DGEN for Pandora (it's rather slow without notaz's sdl), and I wanted to try it with the optimized SDL:
I used the export SDL_VIDEODRIVER=omapdss command in the run.sh script but with it, dgen does not launch anymore and crashes. the pnd_ut does not give useful information on how to fix it...
Not sure if this could be the culprit, but I use exec dgen to launch the program.
EDIT: the pnd_out says "sdl:cannot initialize graphics" and "main: couldn't initialize graphics!"
Those messages don't come from SDL lib itself so I can't help you.
Separate names with a comma.