The Mesa 3-D Graphics Library

Brian Paul
University of Wisconsin - Space Science and Engineering Center
1225 W. Dayton St.
Madison, WI 53706, USA
May 1996

Abstract

Mesa is a free 3-D graphics library which uses the OpenGL API and semantics. It works on most modern computers allowing people without OpenGL to write and use OpenGL-style applications. This paper describes the implementation of Mesa and the differences between it and OpenGL.


Contents


1. Introduction

Mesa began as an experiment in writing a 3-D graphics library. After about a year of "spare time" development it was released on the Internet. It has since evolved with the help of many contributors to the point where it is a viable and popular alternative to OpenGL.

While Mesa uses the OpenGL API and follows the OpenGL specification very closely, it is important to understand that Mesa is not a true implementation of OpenGL. Official OpenGL products are licensed and must completely implement the OpenGL specification and pass a suite of conformance tests. Mesa meets none of these requirements.

At first, Mesa may seem to be a competitor to official OpenGL products. Actually, Mesa has helped to promote the OpenGL API by expanding the range of computers which may execute OpenGL programs. There are many systems which are not supported by OpenGL vendors but can run Mesa instead. People who are curious about OpenGL may try Mesa at no cost and later purchase a commercial OpenGL implementation which utilizes graphics hardware. Students may learn 3-D programming using Mesa and later develop OpenGL applications on the job.

In the spirit of free software, Mesa is distributed under the terms of the GNU library copyright.


2. Using the Library

The Mesa distribution includes implementations of the core OpenGL library functions, the GLU utility functions, the aux and tk toolkits, Xt/Motif widgets, drivers for X11, Microsoft Windows '95/NT, NeXTStep, AmigaDOS, and many demonstration programs. A Macintosh driver is distributed separately.

Mesa compiles easily, requiring only an ANSI C compiler and the development resources (header files and libraries) for the target platform.

From the application programmer's point of view, Mesa is a nearly seemless replacement for OpenGL. The Mesa header files are named the same as OpenGL's (GL/gl.h, GL/glu.h, GL/glx.h, etc) and contain compatible datatypes, constants and function prototypes. The Mesa library files may be renamed to match the typical OpenGL library names and locations. On some operating systems Mesa may be built as a shared library.

After Mesa has been installed most OpenGL applications should compile and execute without modification.

Because of its strong similarity to OpenGL it's more appropriate to discuss the ways in which Mesa is different from OpenGL rather than the ways in which it's similar. The following sections elaborate on this subject.


2.1 Mesa and OpenGL Differences

Mesa does not implement the full OpenGL specification. Antialiasing, for example, is not available and texture mapping is only partially implemented. Trimmed NURBS are not available and the GLX interface is only emulated. It is expected that these features will eventually be implemented.

Mesa doesn't typically perform as well as commercial OpenGL implementations for several reasons. First, portability to a wide range of computers is considered more important than optimizing for a particular architecture. Second, the features of the underlying hardware can't be directly accessed since Mesa exists as a software library above the operating system and window system programming interfaces. And finally, Mesa's development is not supported by any sort of development team. Only so much can be accomplished by people working in their spare time.

In other respects Mesa has some advantages over OpenGL.


2.2 GLX Emulation

Mesa's interface to the X Window System is defined by the X/Mesa interface. There are X/Mesa functions for creating rendering contexts, destroying contexts, binding contexts to windows and pixmaps, swapping color buffers and querying the current context.

The OpenGL GLX extension is implemented in terms of the X/Mesa interface and Xlib. Implementing a true GLX extension requires modifying the X server and is therefore not feasible with commercial servers.

Because of the way in which Mesa and its GLX exist between an OpenGL application and Xlib, Mesa can be thought of a translator which converts OpenGL API functions to Xlib commands.

Mesa's GLX is not 100% compatible with OpenGL's GLX. In several ways is actually superior. For example, while OpenGL only supports RGB rendering into TrueColor or DirectColor X visuals, Mesa allows RGB rendering into virtually any type and depth of X visual. This is an important feature since many X servers don't offer TrueColor or DirectColor visuals. Other visuals are supported by dithering or converting RGB values to gray levels.

This introduces two potential incompatibilities with OpenGL's GLX.

The first problem is solved with a special Mesa extension to GLX, explained later. The second problem can usually be fixed by modifying the application's GLX code.

There is another nice benefit to implementing Mesa on top of Xlib. Operating systems which support shared libraries can substitute Mesa for OpenGL at runtime, allowing OpenGL applications to be displayed on non-GLX capable X servers without recompiling. By using Mesa's GLX instead of OpenGL's GLX, OpenGL API calls are translated into ordinary X protocol which any X server understands.

An effort to implement a true GLX interface for Mesa is underway. This involves writing an X server extension which can decode and execute GLX protocol and writing a GLX client library which can encode GLX messages.


2.3 Extensions

Mesa implements several popular OpenGL extensions and adds a few of its own.

2.3.1 OpenGL Extensions

Mesa has the following OpenGL extensions:

2.3.2 Mesa Extensions

Mesa offers two extensions.

GLX_MESA_pixmap_colormap

This extension adds the GLX function:

GLXPixmap glXCreateGLXPixmapMESA( Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap )

It is an alternative to the standard glXCreateGLXPixmap function. Since Mesa supports RGB rendering into any X visual, not just TrueColor or DirectColor, Mesa needs colormap information to convert RGB values into pixel values. An X window carries this information but a pixmap does not. This function associates a colormap to a GLX pixmap.

An application using GLX pixmaps should use the following code to associate a colormap with the GLX pixmap when using Mesa.

#ifdef GLX_MESA_pixmap_colormap
   glxpixmap = glXCreateGLXPixmapMESA( display, xvisualinfo,
                                       xpixmap, colormap );
#else
   glxpixmap = glXCreateGLXPixmap( display, xvisualinfo, xpixmap );
#endif


GL_MESA_window_pos

This extension adds the glWindowPos*MESA functions. These functions are convenient alternatives to glRasterPos* because they set the current raster position to a specific window coordinate, bypassing the usual modelview, projection and viewport transformations. This is especially useful for setting the position for glDrawPixels or glBitmap to a desired window coordinate.

For glWindowPosMESA4f( x, y, z, w ) the x, y, z, and w parameters directly set the current raster position except that z is clamped to the range [0,1]. The current raster position valid flag is always set to true. The current raster distance is set to zero. The current raster color and texture coordinate are updated in the same manner as for glRasterPos. In selection mode a hit record is always generated.

Programs using OpenGL, not Mesa, may also use the glWindowPos*MESA functions since an implementation of it in terms of standard OpenGL functions is included with Mesa.

Perhaps the GL_MESA_window_pos extension may be incorporated into a future version of OpenGL since it is so convenient.


3. Implementation

Mesa is written in ANSI C. The core library contains no operating system or window system dependent code making it extremely portable. A special device driver interface insulates the core Mesa library from the underlying window system. Each Mesa window system interface implements both public the OpenGL/window system API functions and the private device driver funtions.


3.1 Library State

OpenGL is designed around the concept of a state machine. In Mesa this state is stored in a large C struct. Much of the state is stored in substructures which directly correspond to the attribute groups such as the polygon group, lighting group and texture group. Pushing and popping of attribute groups is just a matter of copying C structs to and from a stack.

Many API functions simply modify state values and produce no output. When rendering functions are invoked it is often necessary to evaluate the current state to compute derived state values and setup pointers to specific instances of rendering functions. Lazy evaluation is used to updated the state.

For example, Mesa has many instances of specialized polygon drawing functions. Which function to use depends on the state of smooth vs flat shading, dithering, depth testing, etc. When any of these state values are changed the new state flag is set. When glBegin is called the new state flag is tested and if set, the state is evaluated to select the specialized polygon function and the flag is cleared.


3.2 Point, Line and Polygon Rendering

Arguably the most important feature of Mesa is efficient point, line and polygon rendering. The two major components of this are vertex transformation and rasterization.

Vertices specified between glBegin and glEnd are accumulated in a vertex buffer. When the buffer is full or glEnd is called the buffer is processed. Processing the vertex buffer includes transforming vertices from object coordinates to eye coordinates, lighting, transforming eye coordinates to clip coordinates, clip testing, and mapping clip coordinates to window coordinates.

Each transformation and clip test stage is implemented in a tight loop which compilers can unroll for efficient executution. The size of the vertex buffer was chosen so that all vertex data touched in the transformation loops will fit in a 16KB CPU data cache.

Several optimization are used during transformation. The modelview and projection matrices often have particular elements with values of zero or one. These elements are tested to determine if simplified vector/matrix multiplications can be used. Depending on the current lighting parameters, either a full-featured or specialized, optimized lighting function is used. Lookup tables are used to compute the exponential spotlight and material shininess functions.

After a vertex buffer has been processed it is rendered as a set of points, lines or polygons as specified by glBegin.

Arrays of points are rendered by either calling a specialized device driver function or by falling back to a core Mesa drawing function. Points whose clip flag is set are discarded.

Line segments are clipped if either endpoint's clip flag is set. Then, the line is rasterized by calling either a specialized device driver function or a core Mesa line drawing function. Different line drawing functions are called for flat or smooth shading, RGB or color index mode, texturing, etc.

Polygons are clipped with the Sutherland-Hodgman algorithm if any of the vertex clip flags are set. Next, the equation of the plane containing the polygon is computed. The coefficients of the plane equation ax+by+cz=d are useful for a number of things. The c term indicates the front/back orientation of the polygon and is used in culling, two-sided lighting and rasterization. The remaining terms are used for implementing the polygon offset extension and for computing Z values inside the polygon. As with line segments, either a specialized device driver function or core Mesa function is called to rasterize the polygon.

Currently, polygons are not decomposed into triangles. The polygon rasterizer directly renders n-sided, convex polygons. There are advantages to using triangle decomposition and that approach will probably be implemented in the future.

The specialized device driver functions for point, line and polygon rendering take vertices as input and directly modify the frame buffer. Alternatively, the fallback rendering functions in Mesa handle rendering of primitives with arbitrary raster operations. Point and line rasterizers generate fragments which are stored in a pixel buffer. Polygons rasterizers generate horizontal runs of pixels called spans. The pixel buffer and spans are subjected to fragment processing before being written to the frame buffer.


3.3 Fragment processing

Fragments are the pixels generated by rasterization augmented with auxiliary information such as color, depth (Z) and texture coordinates. OpenGL defines an extremely flexible fragment processing pipeline which includes texturing, fogging, clipping, scissoring, alpha testing, stenciling, depth testing, blending, dithering, bitwise logic operations, and masking.

Pixel buffer and span-based fragment processing are very similar, the only difference is that the pixel buffer stores fragments with arbitrary window coordinates while spans are continuous horizontal runs of fragments. It should also be noted that glBitmap stores fragments in the pixel buffer while glDrawPixels generates spans.

Since fragments may be culled during processing, each fragment has a write flag associated with it. Initially, all fragments have their flags set to true. Clipping, scissoring, alpha testing, stenciling, and depth testing may set a flag to false to indicate that it should not be considered in further stages. In the end, only those fragments with their flags set are written to the color buffer.

Each stage of fragment processing is implemented in succession with code similar to:

if (stage is enabled) {
    for (each fragment in the buffer or span) {
        apply the fragment operation,
            possibly setting some write flags to false
    }
}
Finally, fragments are written to the color buffer by device driver functions similar to:

for (each fragment) {
    if (fragment flag is true) {
        write fragment color to color buffer
    }
}
The special cases of all write flags set to true or false are handled appropriately. Also, the case in which all fragment colors are the same is a special case.

The only fragment operation which must be handled below the device driver level is dithering. Depth testing, bitwise logic operators and masking may optionally be implemented by the device driver.


3.4 Device Driver Functions

The device driver interface is a set of function pointers which point to implementations specific to the window system. It includes function for: The device driver must update these pointers whenever the make current function is called or whenever the new state flag is found to be true before rendering.

Some device driver functions are optional and if not implemented by the device driver fall back to core Mesa code. Examples are pixel logic operators, point, line, polygon drawing and the depth buffer implementation.

The device driver interface is rather simple but still allows accelerated rendering funtions to be utilized.


3.5 The X Device Driver

The X device driver is quite large because it supports rendering into a wide variety of X visuals and has many specialized line and polygon rendering functions.

The code for writing RGB pixels to the color buffer could be expressed as:

for (each pixel i) {
    pixel_value = convert_rgb_to_pixel( red[i], green[i], blue[i] );
    put_pixel( x[i], y[i], pixel_value );
}
However, this would be very inefficient in most cases. The best method to convert RGB values to pixel values depends on the X visual. The best method to write pixels to the color buffer depends on whether the buffer is implemented as an X Pixmap or XImage. For these reasons, and the fact that this loop is critical to good performance, there are many instances of device driver functions such as write_color_span. The device driver selects the appropriate function and sets a device driver pointer to that function.

When operating in single buffered mode, rendering is directed into an X window. When operating in double buffered mode, rendering is directed into either a Pixmap or XImage. A Pixmap can be accessed in the same way as a window (both are considered to be drawables). Whether a Pixmap or XImage gives best performance depends on a number of factors.

Using a Pixmap can be quite efficient for rendering plain, flat-shaded points, lines and polygons since the X point, line and polygon drawing functions can be used. Performance is relatively good whether displaying locally or remotely. However, when using smooth shading or per-pixel fragment operations pixels must be drawn individually with XSetForeground and XDrawPoint calls. The amount of data transferred from the client to X server is directly proportional to the number of X calls made. For XSetForeground/XDrawPoint rendering this is usually unacceptably slow.

In most cases using an XImage yields best performance in double buffer mode. The reason is individual pixels can be directly "poked" into the image since it resides in the client's address space. Front/back buffer swapping is implemented by copying the XImage to the X window. The X Shared Memory extension is used when displaying on the local host to accelerate this operation. In the case of remote display, the amount of data transferred from the client to the X server is directly proportional to the window size and not the number of pixels generated during rendering.

Programmers should note that double buffering using an XImage can be faster than single buffering.

Mesa's X driver includes optimized functions for drawing flat shaded lines with or without depth buffering and functions for drawing flat or smooth shaded polygons with or without depth buffering. These are the most common cases for rendering 3-D models and perform much better than using the fallback drawing functions since the pixel buffer and span-based fragment processing is completely bypassed. The line and polygon functions write directly into the color buffer.

The device driver interface to point, line and polygon drawing can also be exploited for specialized 3-D graphics hardware. At least two hardware acceleration projects are underway which use this approach. In this situation, Mesa maintains the library state and performs geometric transformation but leaves rasterization to the hardware.


4. Closing Remarks

Mesa has turned out to be a very useful and popular 3-D library. Its success can be attributed to the facts that the library is free, full featured, reliable, portable and compatible with OpenGL. Many volunteers have contributed to this success.

In the future Mesa will continue to be enhanced, optimized and ported to new systems. No doubt, much of this work will be done by additional volunteers who share an enthusiasm for computer graphics and free software.


5. Obtaining Mesa

Mesa can be downloaded by anonymous ftp from iris.ssec.wisc.edu in the pub/Mesa directory or through the Mesa home page at http://www.ssec.wisc.edu/~brianp/Mesa.html.




Last edited on May 14, 1996 by Brian Paul.