From: David O. <da...@ga...> - 2001-01-17 03:03:49
|
On 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. I've done a quick proof-of-concept hack in the Utah-GLX GLX driver.=20 It currently affects only the Mach64 and Matrox MGA drivers (as=20 that's the only supported cards I have, at least in Linux boxen), and=20 it could use some more work. I'm not even sure the vidsync init/exit=20 code is in the right place! *heh* It's not sexy, nice, efficient or anything, but It Works For Me (TM),=20 and makes my OpenGL 2D scrolling smoother than anything I've ever=20 seen before; consoles and arcade machines included. :-) (Well, most=20 of the time at least - see the TODO list.) What the patch does is basically adding an extra flush operation,=20 followed by a vertical retrace sync just before the back->front=20 buffer blit. This eliminates all flickering, tearing and similar=20 artifacts on the two cards I've tried, and should work for any=20 resolution regardless of refresh rate or frame rate, as long as the=20 card can perform the back->front blit faster than the raster sweep.=20 (If the blit is too slow, there's nothing to do - the raster *will*=20 pass the blit somewhere on the screen, causing tearing, no matter=20 when the blit is started.) The code change is in the xxxGLXDirectSwapBuffers() functions, and=20 adds =09xxxDmaFlush(); =09vidsync_wait(); right before the old code =09xxxBackToFront( frontbuf, &vp->backBuffer ); =09xxxDmaFlush(); where xxx is mga, mach64 or whatever, depending on which driver we're=20 looking at. The first DmaFlush() makes sure we have no blits (ie triangles)=20 buffered up when we do the actual retrace sync, as that would result=20 in the problem I had with my first hack; there's plenty of work left,=20 which is performed *before* the actual "flip blit" starts. This extra=20 flush prevents that, resulting in the flip blit starting very soon=20 after the start of the vertical retrace. The next two lines are from the original SwapBuffers code; they queue=20 up a blit from the back buffer to the front buffer, and then makes=20 sure the card gets started right away. (For some reason I'm not sure=20 about, just moving the DmaFlush() up results in a black screen or=20 window, at least on the Mach64...) The patch is against Utah-GLX 0.10 pre1, but should be trivial to=20 apply manually to any other version. TODO: =09* Add a timer check, a phase locked loop and a tolerance =09 argument to vidsync_wait(). This will eliminate the occasional =09 frame drop this version does. =09 The problem is that the retrace sync has to be implemented by =09 polling a bit that's set while in the retrace period - which =09 can last just a fraction of a millisecond, depending on the =09 resolution! Not even SCHED_FIFO with the lowlatency patch seem =09 to be capable of not missing retraces - an RTLinux kernel =09 driver would probably be required. =09 Looking at the performance counter, accepting times =09 sufficiently close to the estimated time of the next retrace =09 would reduce the risk of missing a retrace, and make things =09 more flexible and configurable. Actually doing the retrace =09 bit poll, adjusting the PLL every now and then will ensure =09 that we stay in hard sync with the refresh rate. =09* Just DmaFlush()ing before the vidsync_wait() is probably not =09 totally safe, or even correct, as it appears that there =09 *could* be blits running while we return from that call. One =09 should probably wait for the DMA and rendering to finish as =09 well, before syncing with the retrace. =09* Add some interface to enable/disable retrace sync, preferably =09 on some way that fits into the GLX protocol and the GL libs. =09* Triple buffering would allow the card and the application to =09 keep pumping polygons all the time, rather than wasting time =09 waiting for the vertical retrace after every frame. This =09 should be possible to implement even when the flip is done =09 using a blit, but it would require the GLX driver to keep an =09 eye on the watch (performance counter or something) to know =09 when to throw the flip blit in. That far, no serious issues, =09 except that it's a rather ugly design. =09 The *real* problem is putting that flip blit in the right =09 place in the command FIFO, so that it'll be performed at the =09 exact right moment. No major problem if the GPU has a flag =09 or command for that (you could approximate a bit early, and =09 then have the GPU poll for retrace for a short while), but =09 if it *doesn't*... nightmare! =09 Basically, triple buffering (and asynchronous but retrace =09 synced flips in general, actually) requires hardware =09 pageflipping to be done Right, efficiently and reliably. My =09 flush-sync-blit-flush hack is about as fun as it gets without =09 that. (Meanwhile, XFree86 4.0.1 + DRI has both h/w =09 pageflipping and retrace sync, right...?) //David =2E- M A I A -------------------------------------------------. | Multimedia Application Integration Architecture | | A Free/Open Source Plugin API for Professional Multimedia | `----------------------> http://www.linuxaudiodev.com/maia -' =2E- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter | `--------------------------------------> da...@li... -' =00 |