GGI DL System Rewrite rational and TODO list

Author : Brian S. Julin
Date : 2003-04-18
Revision : 1.1
Revision date : 2005-04-17

Section I

Whatchanged traversal

A list of changed() functions gets called when the visual's GC is changed. When you load an extension, it has the option of being notified so it can make adjustments when the GC changes. It does so by hooking a callback function into a list.

The following changes to this system would be useful:

1) Allow sublibs to optionally first try to set new modes via changed() rather than rebuilding the whole API stack from scratch. It would allow simple tweaks in resolution to be done more gracefully. This is just a wishlist item (unless someone can point to a reason why this would be incredibly useful or improve existing code.)

2) changed() traversal must happen not only for extension sublibs, but also for renderer sublibs. Other than modesets, which rebuild the entire rendering chain, there are other less drastic changes that renderers need to be notified of. These are listed in the next item.

3) Add the following items to changed() traversals. The list is not exhaustive and suggestions are welcome:

  1. All changes to GGI flags
  2. Acquire/release of directbuffer
  3. mansync events
  4. read/write/display frame changes

4) Make the changed() traversal system useful/reusable for other extension-private purposes, if not already. For example, a system similar to the changed() traversal could be used by future APIs to perform actions during vsync like flipping the frame in a sprite, on systems where this cannot be done by the hardware. It could serve as a wayto make some extensions cooperate with each other without relying on each other. The new system could be very similar to DirectFB's "reactor" system and perhaps we should look at that for some ideas.

Section II

Function overloading order

Currently there exists a problem which is being worked around by a bit of hackery.

The desired behavior is that we can layer sublibs upon each other, such that accelerated functions can be provided for some operations, and if no accelerated function is available, we fallback to a function provided by a generic renderer (a.k.a. "software renderer") sublib, and if that renderer sublib has no such function, or if it is more efficient to do so, we load a stubs sublib that builds the function from other available functions.

In the GGI core this issue has been mostly ignored because the generic renderers and accelerators tend to provide the full set of primitives. Also, fixing it as described below would cause generic implementations to be preferred over stubs constructs of accelerated functions, which are in most cases faster than software rendering despite the stubs overhead.

In extensions, in order to do this we work a bit backwards. When a target or extension target first loads, it sets all it's function pointers to unimplemented "dummyfunc" pointers. Then the accelerated renderers are loaded, then generic renderers are loaded, then stubs renderers are loaded. Each sublib takes care not to override any function hooks unless they are still set to "dummyfunc". This way we get the desired behavior, but we sacrifice the ability to:

1) Allow stubs to intelligently construct emulated primitives from the best combination of accelerated/generic functions. For example, on some PDAs it would be better to choose to build DrawBox from DrawVline rather than DrawHline because the screen is rotated.

2) Allow generic renderers to better choose between idling and non-idling implementations.

3) Allow more flexibility about which operators or groups of operators are overloaded by a given sublib (right now it is expected that renderers overload opdraw while targets overload all pointers.)

4) Perhaps avoid entirely the loading of dl's that are not actually going to be used, in order to reduce application footprint.

Most of the above is currently impossible simply because we do not keep a stack of the old overloaded values for function hooks. A system to do so would be 60% of the work needed for this section; The rest simply a system to define a pecking order between sets of function implentations.

Section III

LibGG and config-file issues

LibGG was forked out of LibGGI a while back, still contains a couple minor things that are GGI-specific which need to be vanillafied so that LibGG is a more viable stand-alone library for use building other projects. In addition it can be argued that a lot of stuff from GII and GGI should have been vanillafied and moved into LibGG but remains as code duplicated between the two libs differing only by a few project-specific tweaks.

1) Environment variable handling is an obvious candidate for LibGG to include. In addition to portably providing an environment variable API in the off-case we run into a system with a tricky getenv, such an abstraction could allow us to implement configurable default values for environment variables specific to certain targets. For example a user's private ggi rc file could specify that the X target will, by default, be run with GGI_DEFMODE set to 640x480. We can allow both default-if-none-supplied values and override-user-environmant values.

2) Some option string handling can similarly be moved to a more reusable LibGG codebase, and we could allow default option values in config files as well, for example, a user's GGI rc file could specify that display-x is to be started, by default, with the -noinput option. Like environment variables, options could also be allowed to be either defaults or overrides. In addition this might provide some flexibility to allow root to determine local system policies.

3) Multiple-role sublibs are needed to avoid explosion in the number of sublibs. These sublibs would satisfy more than one "suggest string." For example, lines could appear in a config file as such:

fb-accel-10-linear-* default/fbdev/mga/m2164w.so

Thus indicating that any suggest string matching the pattern should be routed to the listed dl. More importantly the listed dl could alter its behavior based on the suggest string used to access it. So the above would first try to fing the symbol GGdl_fb_accel_10_linear_8, then if that failed, it would try to find the symbol GGdl_m2164w. The library could provide both symbols and create different types of instances depending on which one is called.

Using more than one string to get to the same .so works for core renderers, but IIRC does not work at all for extension sublibs due to some internal cruft. Or if not there's some issue lurking in there which I ran up against when trying to do something fancy with LibBuf renderers.

This item is essential to address the large number of new default renderers needed as new extensions start providing alpha-capable generic renderers, where we want to be able to use simple code to generate a few suggest strings systematically based on the pixelformat/layout of a visual, and then have those strings map to a heirarchy of generic rendering sublibs. The "getapi" function of a display/extension can only be so aware of what libraries are availeble before it becomes tedious to keep updating it every time the sublibs in the codebase change over time.

Above this purpose however, allowing sublibs to satisfy more than one suggest string will in general allow us to stop requiring one sublib per suggest string, so if, for example, a target's 16bpp library is only a few lines of additional code in addition to the 32-bpp library, we don't have a full .so for the purpose of adding one trivial function.

4) Static linking of libs is a long-sought goal for some of the embedded market. This has to start on the LibGG level and emulate the dl loading system through a system of string->fn_table mappings.

5) Above in 3) we neglect the fact that some filesystems are not going to want to cooperate with us and so we should allow the base name used when all else fails to be set. Below is an example of a config line sytax that could resolve this. The immediate side-benefit to developers is easy testing of muliple versions of individual sublib binaries:

fb-accel-10-linear-*      m2164w=default/fbdev/mga/2164TEST.DLL

This causes the first string to be used rather than the base filename of the binary object to find the default GGdl_m2164w.

6) Nesting of options and environment variables via aliases, e.g.:

alias display-defaultx  display-x:-noinput:myhost.my.net:0

7) Security. Lest we be remiss, a reminder that all of the above has to take into account a secure system, when the libraries are used by root or especially an SUID executable. Often SUID privilages will not be able to be dropped until after the config file related code has been run, so that code has to be reviewed, and rules developed for what will and will not be overridable in a user's GGI rc file.

Section IV

Auto targets

GGI needs an auto-target that works a lot like the way linux-mouse works. A display-linux that aliases to display-auto on Linux systems, a display-bsd that aliases to display-auto on BSD systems, etc. Our autodetection routines and sensible defaults should be much more well developed IMO such that we are not asking novice users to apply environment variable settings just to get the obvious "do what I want, not what I tell you" behavior.

Currently what auto-detection we do do is hardcoded into a section of the ggiOpen implementation in the core .so. This would move that code outside of the core and split it up into easier-to-maintain per-os codesets to avoid the heavy #ifdef directives that would eventually converge as better default behavior was developed.