LibGGI: Yet Another Graphics API
At the core of LibGGI is a trick that helps LibGGI be portable and smart regarding acceleration—a creative usage of dynamically loaded libraries. LibGGI functions can be overridden by loading a suitable library. LibGGI is aware of two different types of such libraries:
Display-Modules describe a way to connect to a given kind of back end like X, KGI, SVGAlib etc. They are loaded at ggiOpen time.
Driver modules are normally loaded at mode-setup time and each describes a given API used to draw on the current target. These APIs are normally selected by the back end that is queried for a set of “suggest-strings” that map to these APIs. See Figure 1.
generic stubs (fallback emulation)
You might be surprised by the term “set of”. Normally, there are multiple APIs which can be used to draw on a given target. Let me explain this point a bit further for the KGI target, which makes the most extensive use of this feature. Table 2 is the set of suggest-strings for a fictional ABC graphics card being accessed via KGI. The KGI module managing the card will tell LibGGI to first load a “stubs” library that is used for emulation when a function is not natively supported. This stubs library contains fall-back functionality, such as making up a filled box from multiple horizontal lines. Then LibGGI loads a library that accesses the linear, 8-bit wide frame buffer exported by KGI. This library will hold primitives such as DrawPixel and override the stubs library. LibGGI will then load KGI's generic ioctl method to access acceleration features. This library will handle functions which are commonly accelerated. The next suggest-string adds a few commands that are rather uncommon, but present in the ABC, which are accessed by the private area of the ioctls. The last library loaded accesses the ABC registers in an exported MMIO region. All the libraries are loaded in increasing order of precedence. The later ones override functions of earlier ones if they can do better. Please note this is not a static process—it can still change at runtime, if necessary.
When it comes to graphics performance, many people are afraid LibGGI will be slow because of the relatively high level of abstraction its extension libraries provide. Actually, this high level is necessary if we want to use all graphics cards at their maximum capability. Some high-end cards do have a truly high-level internal API. Having applications that use a low-level API would leave that part of the card unused.
On the other hand, in some cases it is difficult to decide which level of API to use. Consider a 3-D game. You can often do some clever optimizations based on your knowledge of the scene. For a low-end graphics card, you might be able to calculate things faster yourself up to the rasterization level. With high-end cards you might be better off using OpenGL directly, because all calculations go to the card which does them faster than the host CPU.
This is a difficult problem, and actually the only good solution is to implement both and select one method at runtime.
Another ever-present problem is calling overhead. It is faster to use inline code than any kind of library. However, the biggest relative gains/losses are achieved with the very fast small operations such as DrawPixel. This is the primary reason we chose to implement DirectBuffer functionality. If the application knows the DirectBuffer format used by the graphics card, it can use its own inline code to bypass the calling overhead.
LibGGI should perform well over the whole range of possible applications and graphics cards, though specialized solutions might perform slightly better.
If you're considering using LibGGI either as a consumer or for programming your own applications, you might be interested in which programs are already available.
LibGGI has been designed for high speed graphics, so game designers are our primary customers. A lot of popular games have been ported to use LibGGI. Descent and DOOM are two of the more well-known ones. Using LibGGI, we managed to run Descent on a Linux-Alpha machine a few weeks after the source was released.
A common misconception about the GGI project is that we are trying to replace X. This is wrong. We are at a much lower layer than a windowing system, and have implemented some popular window systems on top of LibGGI. We have our own X server (Xggi), a viewer application for the VNC networked desktop, and the Berlin consortium is building its server on top of LibGGI. The existence of these servers together with the ability of LibGGI to display on them brings us to the next generation of interoperability.
Another broad group of applications deals with viewing files. LibGGI has the nice ability to view a JPG file on the console or in an X window, without the spawning application (such as mc) being aware that it is running on X or the console.
Most of the above-mentioned programs have been ported from other graphics APIs. All porters have told me that learning LibGGI was easy, and that after porting, the look of the program was improved.
If you are interested in LibGGI, you will want to know where to get it (see Resources). Our project home page provides many pointers and quite a few sources. LibGGI is available as releases from several major software archives like Sunsite and tsx, as daily CVS snapshots from our web page and its mirrors, as well as via CVS from our public CVS mirrors.
Several precompiled binaries are also available, which should be useful for the “pure user” who doesn't want to bother compiling LibGGI. Give LibGGI a try the next time you write a graphics application.
- Bruce Nikkel's Practical Forensic Imaging (No Starch Press)
- Transitioning to Python 3
- Progress on Privacy
- Linux Journal December 2016
- Stepping into Science
- Radio Free Linux
- FutureVault Inc.'s FutureVault
- CORSAIR's Carbide Air 740
- The Tiny Internet Project, Part II
- A Better Raspberry Pi Streaming Solution