Mesa Implementation Notes

This document is an overview of the internal structure of Mesa and is meant for those who are interested in modifying or enhancing Mesa, or just curious.

NOTE: As of version 2.0 of Mesa, some of this information is out of date.

Library State and Contexts

OpenGL uses the notion of a state machine. Mesa encapsulates the state in one large struct: gl_context, as seen in context.h. The global variable CC is is the current state, or "Current Context." Contexts are allocated dynamically with malloc. When a context is made current its struct is copied to CC. When a context is made non-current the CC is copied back to the context pointer. CC is not a pointer because I believe it's faster to address a global variable's field rather than dereference a pointer. This is important because CC is referenced a lot.

The gl_context struct actually contains a number of sub structs which exactly correspond to OpenGL's attribute groups. This organization made glPushAttrib and glPopAttrib trivial to implement and proved to be a good way of organizing the state variables.

Vertex buffer

The vertex buffer (see vb.[ch]) is used to accumulate glVertex and associated data (normals, colors, etc) between glBegin/glEnd pairs. When the buffer is filled or glEnd is called the buffer is flushed (see draw.c). Flushing consists of transforming vertices and normals by the current matrices, computing lighting, clip testing, fogging, etc.

Originally, Mesa didn't accumulate vertices in this way. Instead, glVertex transformed and lit then buffered each vertex as it was received. When enough vertices to draw the primitive (1 for points, 2 for lines, >2 for polygons) were accumulated the primitive was drawn and the buffer cleared.

The new approach of buffering many vertices and then transforming, lighting and clip testing is faster because it's done in a "vectorized" manner. See gl_transform_points() in xform.c for an example. Also, vertices shared between primitives (i.e. GL_LINE_STRIP) are only transformed once.

The only complication is clipping. If no vertices in the vertex buffer have their clip flag set, the rasterization functions can be applied directly to the vertex buffer. Otherwise, a clipping function is called before rasterizing each primitive. If clipping introduces new vertices they will be stored at the end of the vertex buffer.

For best performance Mesa clients should try to maximize the number of vertices between glBegin/End pairs and used connected primitives when possible.

Rasterization

The point, line and polygon rasterizers are called via the CC.PointFunc, CC.LineFunc, and CC.PolygonFunc function pointers. Whenever the library state is changed in a significant way, the CC.NewState flag is raised. When glBegin is called CC.NewState is checked. If the flag is set we re-evaluate the state to determine what rasterizers to use. Special purpose rasterizers are selected according to the status of certain state variables such as flat vs smooth shading, depth-buffered vs. non-depth- buffered, etc. The gl_set_point|line|polygon_function() functions do this analysis. They in turn query the device driver for "accelerated" rasterizers. More on that later.

In general, typical states (depth-buffered & smooth-shading) result in optimized rasterizers being selected. Non-typical states (stenciling, blending, stippling) result in slower, general purpose rasterizers being selected.

For best performance, Mesa clients should group state changes (glEnable, glDisable, glShadeModel, glLight*, glMaterial) together to minimize the number of times the rasterizer selectors are called.

Pixel (fragment) buffer

The general purpose point, line and bitmap rasterizers accumulate fragments (pixels plus color, depth, texture coords) in the PB (Pixel Buffer) struct seen in pb.[ch]. When the pixel buffer is full or glEnd is called the pixel buffer is flushed. This includes clipping the frag- ments against the window, depth testing, stenciling, blending, stippling, etc. Finally, the pixel buffer's pixels are drawn by calling one of device driver functions.

Pixel spans

The polygon, glDrawPixels, and glCopyPixels functions generate horizontal runs of pixels called spans. Spans are processed in span.c. Processing includes window clipping, depth testing, stenciling, texturing, etc.) After processing the span is written to the frame buffer by calling a device driver function.

Device Driver

The struct dd_function_table seen in dd.h, defines the device driver functions. By using a table of pointers, the device driver can be changed dynamically at runtime. For example, the X/Mesa and OS/Mesa (Off-Screen rendering) device drivers can co-exist in one library and be selected at runtime. The DD variable instantiates the struct dd_function_table.

In addition to the device driver table functions, each Mesa driver has its own set of unique interface functions. For example, the X/Mesa driver has the XMesaCreateContext, XMesaBindWindow, and XMesaSwapBuffers functions while the Windows/Mesa interface has WMesaCreateContext, WMesaPaletteChange and WMesaSwapBuffers. New Mesa drivers need to both implement the dd_function_table functions and define a set of unique window system or operating system-specific interface functions.

The device driver functions can roughly be divided into four groups:

  1. pixel span functions which read or write horizontal runs of RGB or color-index pixels. Each function takes an array of mask flags which indicate whether or not to plot each pixel in the span.

  2. pixel array functions which are very similar to the pixel span functions except that they're used to read or write arrays of pixels at random locations rather than horizontal runs.

  3. miscellaneous functions for window clearing, setting the current drawing color, enabling/disabling dithering, returning the current frame buffer size, specifying the window clear color, synchroniz- ation, etc. Most of these functions directly correspond to higher level OpenGL functions.

  4. if your graphics hardware or operating system provides accelerated point, line and polygon rendering operations, they can be utilized through the get_points_func, get_line_func, and get_polygon_func functions. Mesa will call these functions to "ask" the device driver for accelerated functions. If the device driver can provide an appropriate renderer, given the current Mesa state, then a pointer to that function can be returned. Otherwise the get_points_func, get_line_func, and get_polygon_func functions can just return NULL.

    Even if hardware accelerated renderers aren't available, the device driver may implement tuned, special purpose code for common kinds of points, lines or polygons. The X/Mesa device driver does this for a number of lines and polygons. See the xmesa3.c file.

    Overall Organization

    The overall relation of the core Mesa library, X device driver/interface, toolkits and application programs is shown in this diagram:

        +-----------------------------------------------------------+
        |                                                           |
        |                   Application Programs                    |
        |                                                           |
        |          +- glu.h -+- aux.h tk.h glut.h -+                |
        |          |         |                     |                |
        |          |   GLU   |   aux, tk or GLUT   |                |
        |          |         |      toolkits       |                |
        |          |         |                     |                |
        +---------- gl.h ------------+-------- glx.h ----+          |
        |                            |                   |          |
        |         Mesa core          |   GLX functions   |          |
        |                            |                   |          |
        +---------- dd.h ------------+------------- xmesa.h --------+
        |                                                           |
        |              XMesa* and device driver functions           |
        |                                                           |
        +-----------------------------------------------------------+
        |                 Hardware/OS/Window System                 |
        +-----------------------------------------------------------+
    
    

    Last updated on Jan 18, 1996 by brianp@ssec.wisc.edu.