Retrace sync again

I got the impression that retrace sync on flip with double buffering used to
work with X/DGA (at least on XFree86 4.0.1), but this doesn’t seem to be the
case with SDL 1.1.7+… Did something break, or isn’t this supposed to work in
the first place? I’ll try some older versions and other stuff to sort out more
accurately what works and what doesn’t on my machines. I could be mixing things
up…

Further, I’ve failed to get any SDL/OpenGL code to animate without tearing. It
seems that double buffering is indeed done (using hardware blits), but as
there’s no retrace sync, there are very visible artifacts when doing fast
scrolling and the like. Also, the frame rate is way beyond the refresh rate
(like 189 fps on a 80.7 Hz display), which again indicates that no raster sync
is done. This happens on the G400 as well as on the Mach64 Rage Pro, in
windowed mode as well as in full screen mode. Is this possible to fix, and if
so; how, and does it work on the majority of cards?

I’m thinking about some sort of more or less portable solution for targets
that don’t support retrace sync at all. I’ve collected some retrace sync code
for various hardware (from SDL, svgalib, X,…), and it seems that it’s
possible to do it through simple polling/busy-waiting on most hardware, without
interfering with the driver.

The question is; what do I do with this code? It seems that most people seem
to believe retrace sync is too ugly to be in production drivers, with the net
result that Linux can’t do high quality animation. So the only options would
be to put it in some library, or make a “stand alone” library or driver of some
kind.

The idealistic alternative would be to wait until all video cards have commands
and interrupts for all kinds of synchronization. However, some sources indicate
that one might have too wait forever.

Either may, this is really needed for quality animation, especially on
targets that “flip” using blits. (Tearing unavoidable without at least retrace
syncing the blit.) It’s not worth the effort writing a 2D engine with subpixel
accurate rendering for ultra smooth animation or even try to achieve full
frame rate, if there’s no way to avoid tearing and other artifacts introduced
by the display target…

Basically, where do I best spend my limited time in order to fix this?

As things look now, I’d prefer to have it in SDL, but somehow I got the
impression that it has very, very low priority for various reasons. It might
not be an issue for the majority of SDL users/developers, but I consider it a
showstopper. (Well, I have more code to hack, but I’d rather see the real
results than jerking and tearing.)

//David

…- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' ..- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -’

(This has (probably) little to do with SDL, and more to do with
OpenGL and GLX.)

[…]

Further, I’ve failed to get any SDL/OpenGL code to animate without
tearing. It seems that double buffering is indeed done (using
hardware blits), but as there’s no retrace sync, there are very
visible artifacts when doing fast scrolling and the like.

Played some more with it, and yep, this is exactly what happens.
After adding a retrace sync (directly on the VGA port), the tearing
stays in a small area of the screen, moving up and down depending on
the polygon count. (The frame rate exactly matches the refresh rate.)

I’ve tried various ways of getting OpenGL (Utah-GLX on XFree86 3.3.6)
to render the full display into the back buffer before the sync +
flip to eliminate this problem, but everything I’ve tried has little
or no effect. Is there any OpenGL or GLX call that is supposed to do
this on any double buffered target?

As to non-OpenGL on X, fullscreen, the tearing is still there, and
the position (ie delay from the sync point) differs as a function of
the screen size when SDL has to do pixel format converison. When
using the native format of the screen, the tearing goes away,
provided I still do retrace sync myself, and that the resolution is
not too high. That is, it seems that someone is still doing a rather
slow blit somewhere…

Conclusion:
There is no retrace sync on the X target, and since SDL_Flip() causes
various lenghty operations to be performed before the actual blit to
VRAM is performed, it doesn’t help much doing a retrace sync before
calling SDL_Flip().

Next, I’ll try hacking the retrace sync in at the right place, if
possible.

//David

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Friday 12 January 2001 18:06, David Olofson wrote:

Conclusion:
There is no retrace sync on the X target, and since SDL_Flip() causes
various lenghty operations to be performed before the actual blit to
VRAM is performed, it doesn’t help much doing a retrace sync before
calling SDL_Flip().

Next, I’ll try hacking the retrace sync in at the right place, if
possible.

Bear in mind that what you’re doing will be very system-dependent,
as the actual display work is being done in the X server. What you
probably want is some XFree86 extension to synch with vertical retrace
for screen update requests.

See ya!
-Sam Lantinga, Lead Programmer, Loki Entertainment Software

Yes, that would be the right solution in this case. I was thinking
about a more generic solution (ie syncing in some separate library or
driver, regardless of target), but obviously, most targets do all
sorts of stuff before even starting the back->front blit, which means
that such sync attempts are futile - all you get is tearing in a more
or less fixed area of the screen… (It would work with real hardware
pageflipping, though.)

//David

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Saturday 13 January 2001 22:29, Sam Lantinga wrote:

Conclusion:
There is no retrace sync on the X target, and since SDL_Flip()
causes various lenghty operations to be performed before the
actual blit to VRAM is performed, it doesn’t help much doing a
retrace sync before calling SDL_Flip().

Next, I’ll try hacking the retrace sync in at the right place, if
possible.

Bear in mind that what you’re doing will be very system-dependent,
as the actual display work is being done in the X server. What you
probably want is some XFree86 extension to synch with vertical
retrace for screen update requests.

I’ve done a quick proof-of-concept hack in the Utah-GLX GLX driver.
It currently affects only the Mach64 and Matrox MGA drivers (as
that’s the only supported cards I have, at least in Linux boxen), and
it could use some more work. I’m not even sure the vidsync init/exit
code is in the right place! heh

It’s not sexy, nice, efficient or anything, but It Works For Me ™,
and makes my OpenGL 2D scrolling smoother than anything I’ve ever
seen before; consoles and arcade machines included. :slight_smile: (Well, most
of the time at least - see the TODO list.)

What the patch does is basically adding an extra flush operation,
followed by a vertical retrace sync just before the back->front
buffer blit. This eliminates all flickering, tearing and similar
artifacts on the two cards I’ve tried, and should work for any
resolution regardless of refresh rate or frame rate, as long as the
card can perform the back->front blit faster than the raster sweep.
(If the blit is too slow, there’s nothing to do - the raster will
pass the blit somewhere on the screen, causing tearing, no matter
when the blit is started.)

The code change is in the xxxGLXDirectSwapBuffers() functions, and
adds

xxxDmaFlush();
vidsync_wait();

right before the old code

xxxBackToFront( frontbuf, &vp->backBuffer );
xxxDmaFlush();

where xxx is mga, mach64 or whatever, depending on which driver we’re
looking at.

The first DmaFlush() makes sure we have no blits (ie triangles)
buffered up when we do the actual retrace sync, as that would result
in the problem I had with my first hack; there’s plenty of work left,
which is performed before the actual “flip blit” starts. This extra
flush prevents that, resulting in the flip blit starting very soon
after the start of the vertical retrace.

The next two lines are from the original SwapBuffers code; they queue
up a blit from the back buffer to the front buffer, and then makes
sure the card gets started right away. (For some reason I’m not sure
about, just moving the DmaFlush() up results in a black screen or
window, at least on the Mach64…)

The patch is against Utah-GLX 0.10 pre1, but should be trivial to
apply manually to any other version.

TODO:
* Add a timer check, a phase locked loop and a tolerance
argument to vidsync_wait(). This will eliminate the occasional
frame drop this version does.

  The problem is that the retrace sync has to be implemented by
  polling a bit that's set while in the retrace period - which
  can last just a fraction of a millisecond, depending on the
  resolution! Not even SCHED_FIFO with the lowlatency patch seem
  to be capable of not missing retraces - an RTLinux kernel
  driver would probably be required.

  Looking at the performance counter, accepting times
  sufficiently close to the estimated time of the next retrace
  would reduce the risk of missing a retrace, and make things
  more flexible and configurable. Actually doing the retrace
  bit poll, adjusting the PLL every now and then will ensure
  that we stay in hard sync with the refresh rate.

* Just DmaFlush()ing before the vidsync_wait() is probably not
  totally safe, or even correct, as it appears that there
  *could* be blits running while we return from that call. One
  should probably wait for the DMA and rendering to finish as
  well, before syncing with the retrace.

* Add some interface to enable/disable retrace sync, preferably
  on some way that fits into the GLX protocol and the GL libs.

* Triple buffering would allow the card and the application to
  keep pumping polygons all the time, rather than wasting time
  waiting for the vertical retrace after every frame. This
  should be possible to implement even when the flip is done
  using a blit, but it would require the GLX driver to keep an
  eye on the watch (performance counter or something) to know
  when to throw the flip blit in. That far, no serious issues,
  except that it's a rather ugly design.

  The *real* problem is putting that flip blit in the right
  place in the command FIFO, so that it'll be performed at the
  exact right moment. No major problem if the GPU has a flag
  or command for that (you could approximate a bit early, and
  then have the GPU poll for retrace for a short while), but
  if it *doesn't*... nightmare!

  Basically, triple buffering (and asynchronous but retrace
  synced flips in general, actually) requires hardware
  pageflipping to be done Right, efficiently and reliably. My
  flush-sync-blit-flush hack is about as fun as it gets without
  that. (Meanwhile, XFree86 4.0.1 + DRI has both h/w
  pageflipping and retrace sync, right...?)

//David

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -’

-------------- next part --------------
A non-text attachment was scrubbed…
Name: utah-glx-retrace-sync.patch
Type: text/x-c
Size: 3448 bytes
Desc: Retrace synced SwapBuffers for Utah-GLX 0.10-pre1
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20010117/e435cd46/attachment.binOn Saturday 13 January 2001 22:29, Sam Lantinga wrote:

Bear in mind that what you’re doing will be very system-dependent,
as the actual display work is being done in the X server. What you
probably want is some XFree86 extension to synch with vertical
retrace for screen update requests.