
"Cliff notes" on new X target.

The old X target rendered all primitives in a RAM backbuffer, and
then copied the entire backbuffer periodically using the mansync helper
to the X screen.  This caused a lot of wasted bandwidth.  However, since
the bandwidth was being wasted anyway, LibGGIMISC splitline support was a 
simple hack that added nearly no complexity.

The old Xlib target had no RAM backbuffer and rendered all primitives 
using Xlib calls.  This caused very slow performance when a lot of individual
pixels were being drawn one at a time, and slow performance on operations
which got pixel data back from the visual, since it had to be fetched back
over the wire.  Also, this precluded the use of the directbuffer on the xlib
target.

The new X target in its default mode maintains both a RAM backbuffer on 
the client side, and uses Xlib primitives to draw on the server side.
When a primitive, such as a drawbox, can use an Xlib function, the 
command is dispatched to the X server and the data in the RAM buffer is 
updated using a software renderer.  For operations such as putbox, the
RAM buffer is updated first, and the synced to the X server.  Unlike
the old target, the new target keeps track of a "dirty region" and 
only syncs the area affected since the last time a syncronization occured.
This dirty-region tracking only keeps track of one rectangular dirty area.
A helper library that keeps track of more than one rectangle could be 
implemented to improve performance of display-X and any other similarly  
designed display target.  To be most flexible such a target should take
weighted parameters representing the cost of transferring data (per byte) 
from the backbuffer, and the per-operation cost of initiating such a transfer,
which would alter its strategy as to how many regions are maintained and how
much they overlap.

The old X target's RAM buffer was implemented using the X target's 
drawops hooks -- that is, the RAM buffer was essentially a re-implementation
of display-memory with the extra facilities to sync to the X server
built in.  The new target capitalizes on some improvements made in 
display-memory, and instead it opens and loads a child display-memory visual 
which takes care of finding software renderers for the RAM buffer.  The main 
drawops of the new target dispatch the the X server commands and call the 
child's corresponsing software drawops to ensure consistant state of the RAM 
buffer vs the X window.  This must be done such that any requests to get 
data from the RAM backbuffer are not processed until the RAM backbuffer is 
up to date, and any flushes from the backbuffer are not processed until the
backbuffer is up to date.  There's a lot of locking intracacy to ensure this
level of consistancy.

The basic syncronization operation is accomplished by the flush function,
which is the function loaded on the xpriv "flush" member hook.  The flush hook
function is called:
  1) When the mansync helper decides it is time to refresh the screen.
  2) After a primitive, if the visual in in syncronous rendering mode.
  3) When an expose or graphicsexpose event is sent from the server.
     This means the server has discarded data that was concealed by another 
     window or by the edge of the screen, and the data must be resent from 
     the client.
...in the last case the whole area that must be refreshed is sent again by
the client.  In the first two cases only the dirty area is sent, except when
the application is holding the directbuffer writing resource, in which case 
the whole area must be synced because there is no way for the target
to tell what the user has modified.  Holding the directbuffer write
resource open when the display is in syncronous mode or when also sending
primitives will result in bad perfomance.  There's no reason to do so on
any target, so don't.

Unfortunately some XFree86 drivers are buggy, and when you render an 
accelerated primitive which overlaps an area which is not visible to
the user, the driver fails to update the backing store (it only draws
the clipped primitive using accelarated functions and does not complete the
job by calling the software renderer to update the backing store.)  Most
people will not be affected by this bug, however.

The new X target implements gammamap (DirectColor), unlike the old targets.

The new X target is best used with backing store turned on in the
server.  When backing store is not turned on, primitives which are
clipped to the visual area but still in the virtual area may be slower
then the old target, since data will be sent to the server hoping
it will be stored in the backing store.  Likewise when a full-screen 
flush occurrs the entire virtual area data is sent.  The target could be 
optimized not to send this data when it detects that there is no backing 
store available in the server.

Either the RAM backbuffer or the X primitives can be disabled via
target options, which will cause emulation of the old X (-noaccel) and 
Xlib (-nobuffer) targets, with a coupel of notable exceptions:

The old X and Xlib targets opened a window and drew directly into it.
The old Xlib target did not implement support for ggiSetOrigin.  As
noted above the old X target used a hack that didn't cost much when 
compared to the cost of syncing the backbuffer periodically.  The new target
implements ggiSetOrigin by creating a parent window, then creating a 
child window inside the parent window.  Thus the child window can be moved 
around inside the parent window, and the parent window will clip the displayed
data to the right size.  This is much more efficient than the old way 
when the server is keeping a backing store (which it sometimes does 
"in secret" even when the backing store functionality in the server is 
turned off.)

Unfortunately many window managers seem to be buggy, and do not install the
colormap of a child window when a mouse enters it.  This causes palette
and gammamap to be messed up.  Since so many windowmanagers fail to implement
the behavior described in the Xlib manpages, a workaround needs to be added 
which will not use the child window (this part is easy enough since the 
-inwin=root option already implements a child-less rendering) and either 
disables ggiSetOrigin support, or uses a better version of the old display-x 
target's creative blitting to emulate setorigin support.

LibGGIMISC's splitline support for the original X display was broken by
the new child-window stuff as well.  In order to implement splitline support,
libggimisc must implement a new set of primitives for the new display X
that uses two child windows to produce the splitline effect.  This complicates
a lot of the primitives, so the code is best isolated in LibGGIMISC so any
bugs or performance issues in it do not affect vanilla LibGGI users who have
no need for splitline.  It would probably be best if the special renderers 
were only loaded on the first call to ggiSetSplitline, so that when LibGGIMISC
implements support for the XSync extension, users who are not using splitline
do not pay a performance penalty for using XSync.

The child window may also be to blame for the fact that a window which
is focused, but not moused over, stops receiving keyboard events.  Reworking
the X input target to take it's keyboard events from the parent window instead
of the child window (mouse and expose/graphicsexpose events must still
come from the child window) would be the needed fix.

The new target tries to remove dl dependencies by creating a separate 
module file for any X extensions used.  Because of some deficiencies in the
X module system (there is no way to cleanly unload a module) some kludges
have had to be made when a module is loaded but gleaned to be nonpresent,
then unloaded.  This won't effect most people.

However, a more common problem will be seen because X does not give
us any way to determine if the XSHM extension will work -- it tells us
whether the server has XSHM, but it does not tell us whether the client
and server can share memory segments.  Thus, when running a remote client,
it may be necessary to manually disable XSHM support with the -noshm target
option.

Anyway, I hope this is helpful to any intrepid soul which decides
to fondle this code :-)

--
Brian

