Some targets allow different modes with regard to when the screen is updated and the actual drawing takes place.
The synchronous mode is default because it is what most programmers expect: When the drawing command returns, it is already or will be executed very shortly. So the visible effect is that everything is drawn immediately. (It is not guaranteed in the strict sense that it is already drawn when the function call returns, but almost.)
The asynchronous mode is (at least on the X) faster, but does
not guarantee that the command is executed immediately. To make sure that
all pending graphics operations are actually done
and the screen is updated, you need to call
ggiFlush(
myvis);
.
(Side note: The screen refresh the X target does every 1/20 s can take about half the execution time of a program. So syncronous mode can really slow things down.)
As it stands now, all operations are guaranteed to be performed in the order given in both modes. Reordering has been discussed but is currently not done.
So the recommendation for all graphics applications is to set the asynchronous mode. It will be far more efficient on some platforms and will never be worse. (If asynchronous mode is not supported by a target, setting it is still allowed, but has no effect.)
How to set up asynchronous mode?
ggiSetInfoFlags(
myvis,GGIFLAG_ASYNC);
switches to asynchronous mode,ggiFlush(
myvis);
updates the screen,ggiSetInfoFlags(
myvis,GGIFLAG_SYNC);
switches to synchronous mode.
It is strongly discouraged to draw to one visual from two (or more) different processes or threads at the same time. While serious damage is unlikely, corrupted graphics output might happen and a big performance penalty is almost guaranteed.
If drawing from two threads is needed, the application is required to synchronise the threads so that not both draw simultanously.
(Side note: Some cards need some sort of paging for accessing their video ram (banked framebuffer). Two threads accessing different parts of the screen would require a page change on each process switch, which could slow them down to a crawl. State information that has to be reloaded to the accellerator engine after every switch would be another example.)
Some tricky spots have to be taken care of if you mix libggi calls and direct access to the frame buffer. While direct access is done immediately, execution of a libggi call might be delayed due to the accellerator architecture, so framebuffer access immediately after an accellerated libggi call could actually be executed before or while the accellerator accesses the frame buffer itself, which worst case could lock the card and give best case wrong pixels on the screen.
To make sure that all pending accellerator commands are executed, you need
to call ggiFlush(
myvis);
between
a (series of) libGGI call(s) and
direct frame buffer access.
(Side note: ggiFlush(
myvis);
does more than just waiting for
the accellerator to finish pending jobs, so there will be another call
introduced for only this purpose. Stay tuned.)