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.

Table 2. Multiple APIs

generic stubs (fallback emulation)

linear-8-framebuffer

generic-KGI-ioctl

vendor-ABC-KGI-PrivateIoctl

vendor-ABC-MMIO-DirectAccess

Figure 1. How Transparent Acceleration and Multi-API Work

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.

Performance Considerations

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.

Available Applications

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.

Andreas Beck
studies physics in Düsseldorf.
In his free time he enjoys adding new features to his favourite
programs and operating systems. He can be reached at
andreas.beck@ggi-project.org.