Triple buffering

For each game render:
Blit into the software-surface
Blit software-surface to hardware-backbuffer
Call flip() to display hardware-backbuffer

There’s just one ‘but’: the flip() call causes program execution to halt until the next vertical retrace, at least, it does under Win32 using DirectX. So,
this still makes the program stop until the flip has actually begun, right? Since I wanted to use triple-buffering to be able to continue game
execution while waiting for a retrace, this solution does not seem to fit my purposes… Could anyone enlighten me?

Basically you just want a flip that synchronizes with vertical retrace,
but doesn’t block the execution of the program, right? You realize that
if this was implemented using OS API calls, it would only work on DirectX,
right?

See ya,
-Sam Lantinga, Software Engineer, Blizzard Entertainment

The whole point of this is, that I have a logic-routine which
may only be updated 15 times per second, and an independant drawing
routine which may be updated as much as possible.

With interpolation? Soooo much smoother! :slight_smile:

Yeah, I’m planning to do simple linear interpolation in my sprite
engine… The first game I’ll create with it is a platform game,
imagine that: Super Mario jumping interpolated when you’ve got a fast
computer :slight_smile: Smooootthhhh…

Oh, yeah…! Have a look at the fast ships flying around in Kobo Deluxe
at the higher levels.

I’ve tested the “frame rate converter” (which uses linear interpolation)
with as low control system frame rates as 5 Hz with incredibly good
results. Indeed, things move in straight lines between “key frames”, but
with the CS rate of 33.3333 Hz of Kobo Deluxe, you couldn’t tell.

I will probably try cubic interpolation, though - just for the h*ll of
it, if nothing else. :slight_smile:

Isn’t the normal

while(logic_time < next_frame_time)
run_logic_frame();

solution sufficient?

Let’s say you’re calling run_logic_frame() at a time and the function
takes just a little bit too long. This leaves you at, say, 0.001
frametime after a vertical blank, causing the flip() routine to wait
almost a full frame before your application gets control again. So you
loose one frame,

Yes. This is the fundamental rule of hard real time programming:

NEVER miss a deadline.

It’s as simple as that, and there’s no way around it. You can do all
sorts of things to minimize the consequences of missing a deadline, but
the inevitable and final truth is that you cannot turn back time. If
you’re late, you’re late.

and worse, your game logic is halted for a full frame!

Yes, but that should only affect future frames - and in fact, not even
that, if you implement the engine properly. You can catch up to get the
next frame right, but the frame you just missed is lost forever.

[…]

If interpolation is used in the drawframe() logics, the game runs
smooth on-screen, while the game logics are only updated 10 times a
second. And the game can already start drawing a new frame while the
flipthread is still waiting for the next vertical blank!

[…]

Ok… so the problem is actually that the logic code is
nondeterministic, to the extent where it’s completion time can
occasionally peak to levels where it would interfere with rendering
performance if executed in the context of the rendering loop.

Now I get why you need to mess with multiple threads at all! :slight_smile:

However, if you want a rock solid solution, well, unsync’ed blit-flips
are problematic, because they cause tearing when used on a single
buffer screen. When used on a h/w pageflipping screen, timing jitter
is introduced, unless there is exactly one blit flip for every real
flip. This would be doable though, and might even solve some
problems.

This is exactly what I’ve got running now: I’m blitting the full
software surface to the hardware backbuffer, then my special
flip-thread takes care of the flip itself. So, it does wait for a
vertical blank with the flip, but control is returned to the main game
thread to continue processing game logics. The next time my program
thinks it should do a flip() again, it just looks whether the flip()
thread is still busy, and if not, it starts it again. The advantage is
obvious: You get vsync’ed flips which do not interfere with the game
logic itself.

Yes, I see. Pretty neat. :slight_smile:

So, are you expecting to get steady full frame rates on any reasonable
hardware…?

Yep, I’m aiming high here :slight_smile:

Well, you should! I’ve seen way too much of this unsmoost scrolling
that have plagued 2D gaming ever since the PC was introduced…

The solution I described above could very
well solve my problems, but it does require the user to have a quite
fast graphics card and good drivers for the sw->hw blits.

Yeah, that’s the major problem, especially on Linux…

I have
implemented the thread-solution into CSDL and it seems to work
beautifully.

Great!

Ofcourse I have to wait with drawing into the software-surface until
the sw->hw blit has finished, but that’s easily solved with a mutex
inbetween the threads. I could use two software-surfaces, ofcourse, but
I honestly do not think that waiting for that blit will have that much
impact, if I’ll have to wait at all, that is.

Well, sw->hw blits usually do take a substantial amount of time, even
if accelerated… So, if the rendering takes the better part of a full
frame to complete, you could very well gain a lot from taking advantage
of the fact that sw rendering and sw->hw blitting can be done at the same
time, if you have two buffers.

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------------> http://www.linuxdj.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |-------------------------------------> http://olofson.net -'On Friday 08 March 2002 18:14, Martijn Melenhorst wrote:

There’s just one ‘but’: the flip() call causes program execution to halt
until the next vertical retrace, at least, it does under Win32 using
DirectX. So, this still makes the program stop until the flip has
actually begun, right? Since I wanted to use triple-buffering to be able
to continue game execution while waiting for a retrace, this solution
does not seem to fit my purposes… Could anyone enlighten me?

Would it be possible to thread this?

That would require SDL’s blitting to be thread-safe, which it isn’t.–
Trick


“There is no magic” - Nakor, magic user

6-3-2002 17:37:20, David Olofson <david.olofson at reologica.se> wrote:

Anyway, I was following the thread about fixed time steps at
http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-
MainLoopTimeSteps&forum=totd&id=-1 while researching the best way to
implement my high-res timer,

Is this a high resolution timer in the sense of something that actually
makes the OS schedule some code to run at regular intervals? (If so,
you’re on the wrong track, IMHO.)

No, it is not the OS that is scheduling the intervals, don’t worry. I’m just using the standard SDL functions to measure time, and fire up events
from that, just like they suggested in that article.

and came to the conclusion that I will not
be able to create screen-refreshrate-independant movement without
triple buffering.

Why? Indeed, triple buffering helps, but double buffering with retrace
sync’ed flipping is sufficient as long as you have enough rendering power.

As I described earlier, you have to wait for a vertical blank on each frame, which can take almost a full frame, if you do not have enough
rendering power. I’d rather use that waiting time, than sitting idle doing nothing, so at least the game-internals do run at the same speed on each
machine. See an earlier message in which I described my game loop for this.

Actually, the only reason why OpenGL usually will do what you want with
only double buffering is that virtually every h/w OpenGL implementation
works with a queue of commands that are executed asynchronously in
relation to your application. (This is possible to do with h/w
accelerated 2D as well, but we all know by now that that’s not something
that’s normally available.)

This is not available with DirectDraw, at least. That’s why I made the blit&flip thread, to make this happen asynchronously.

I’d hate to apply a patch to SDL everytime I update form the
CVS tree, so can anyone help me out here?

Well, I don’t really see why there isn’t an SDL_TRIPLEBUFFER flag or
something. It’s not as generic as it should be, but at least, it would
enable some rendering backends to make better use of the available
resources. As far as I can see, it wouldn’t be much work to implement for
DirectDraw, OpenGL and other targets that support it natively.

As to targets that don’t do h/w pageflipping at all, there’s no point in
implementing triple buffering unless you “flip” by blitting
asynchronously using a separate thread on SMP systems, or using busmaster
DMA.

SDL_TRIPLEBUFFER would be great… I am currently using my quad-buffer & flipthread solution, which works beautifully, but does require a full-
screen blit from software to hardware for each frame. Ofcourse I could expand the solution to use SDL_TRIPLEBUFFER, when it is available, for
computers with less processing-power. I’m ready for it…