Mattias Engdeg?rd wrote:
monitor refresh m m m m m m m m
game frame update 1 2 3 4 5 6
player sees 111111111122222333333333344444555556
object position /\ ^ /\ ^ ^
In this example, frames 1 and 3 are shown twice as long as frames 2, 4 and 5.
Imagine you have an object moving with constant speed on the screen. To
maintain the illusion of constant speed, the time points for each frame
should be the midpoint of the interval during which the frame is seen by
the player (marked by ^ and /). Of course, these have to be known in
advance when rendering a frame (in order to draw the object at the right
place), but then you must know where you are in relation to the vertical
And even then, I’m not 100% sure that motion will be perceived as
completely smooth, since the users sees the object occupying some
positions for a longer time than others.
The thing is, we’re doing our best. Synchronizing to the monitor refresh
would mean slowing down to something like half of the refresh rate (we’d
update every other frame). So you’d suck, but you’d suck evenly. If you
update as fast as you can, of course making the game logic run on its
own clock, you sometimes have a frame that stays on screen longer, but
the object will be advance by a larger increment on the next frame to
compensate, in such a way that you barely see it.
You know what? I’m in Canada and we have 60 Hz AC current. VCRs are
synchronized at a 30 fps rate, but the movies that play on them were
made with a 24 fps sampling rate. They use frame doubling and NOBODY
cares or notice. In Europe, you only have one doubled frame per second,
but here, 25% of the frames in the movie are displayed twice! And it
looks just fine.
I was told that XFree86 queues drawing requests at retrace to the
accelerator, but for operations that are done in software, the
synchronization too bad to help (the problem I described) and/or
software PIO transfers are so slow that they take more time than the
vertical refresh allows for.
This is great news. That would imply that we could replace
XShmPutImage(Shared XImage to Window); XSync();
XShmPutImage(Shared XImage to Pixmap); XCopyArea(Pixmap to Window); XSync();
and get triple-buffering at (almost) no extra charge!
Well, not exactly. You don’t have tearing/shearing, but you get a slow
framerate in exchange because you do one more copy than what is needed.
I think that with XFree86 4.0, XShmPutImage is done through the
accelerator on AGP cards (not on PCI), but I’m not sure.
The thing with PCI is the physically contiguous memory requirement. I’ll
try to find a way to get contiguous memory. :-)–