  
Mini GLX Specification
Tungsten Graphics, Inc.January 20, 2003
 Copyright © 2002-2003 by Tungsten Graphics, Inc., Cedar Park,
Texas. All Rights Reserved. 
Permission is granted to make and distribute verbatim copies of this
document provided the copyright notice and this permission notice are
preserved on all copies.
1. Introduction
The Mini GLX interface facilitates OpenGL rendering on embedded
devices. The interface is a subset of the GLX interface, plus a minimal
set of Xlib-like functions.
Programs written to the Mini GLX specification should run unchanged
on systems with the X Window System and the GLX extension. The intention
is to allow flexibility for prototyping and testing.
This document serves as both the reference guide and programming
guide for Mini GLX.
2. Mini GLX Concepts
The OpenGL specification does not describe how OpenGL rendering
contexts and drawing surfaces (i.e. the frame buffer) are created and
managed. Rather, this is handled by an OpenGL window system interface,
such as Mini GLX.
There are three main datatypes or resources managed by Mini GLX. The
resources and their corresponding GLX or Xlib data types are:
  
    
      
Resource       
Data type     
    
      
pixel formats       
X Visual and XVisualInfo     
    
      
drawing surfaces       
X Window or GLXDrawable     
    
      
rendering contexts       
GLXContext     
  
Pixel formats or X Visuals describe the per-pixel attributes of the
frame buffer.  For example, bits per color component, Z buffer size,
stencil size, TrueColor vs PseudoColor, etc.
Drawing surfaces or X Windows typically describe a spatial
allocation of the frame buffer (i.e. the position and size of a
rectangular region of pixels).  Since MiniGLX doesn't really support a
window system, the window is effectively the entire frame buffer.
A rendering context represents the current OpenGL state such as
current drawing color, line width, blending mode, texture parameters,
etc. Several rendering contexts can be created but only one can be in
use at any given time.
The Mini GLX interface provides all the functions needed for
choosing pixel formats, create drawing surfaces, creating rendering
contexts and binding rendering contexts to drawing surfaces.
3. Using Mini GLX
To use the Mini GLX interface in your application, include the
GL/miniglx.h header file at compile time:
	#include <GL/miniglx.h>  
Applications should link with libGL.so (i.e. gcc
myprogram.o -lGL -o myprogram
).  libGL.so implements the
MiniGLX API functions and, in turn, loads a hardware-specific device
driver (such as 
radeon_dri.so) at runtime.  The
environment variable 
LIBGL_DRIVERS_PATH should name the
directory where these modules are located.
Prior to running a MiniGXL application, the following kernel modules
must be installed:
 agpgart.oradeonfb.o  (assuming Radeon hardware)
radeon.o  (assuming Radeon hardware)
 Finally, MiniGLX reads a configuration file (by default,
/etc/miniglx.conf
) to determine basic configuration information.
 The configuration file may also be located in the directory
specified by the 
MINIGLX_CONF environment variable).The remainder of this section describes the MiniGLX API functions.
3.1 Initialization
The XOpenDisplay function is used to initialize the graphics system:
  
Display *XOpenDisplay(const char *displayname)The displayName parameter is currently ignored in Mini
GLX. It is recommended that 
NULL be passed as thedisplayNameparameter.
If XOpenDisplay is able to initialize the graphics system a pointer
to a Display will be returned.  Otherwise, NULL will be returned.
3.2 Choosing a Visual
A visual (i.e. pixel format) must be chosen before a drawing surface
or rendering context can be created.  This is done with the
glXChooseVisual function:
  
XVisualInfo *glXChooseVisual(Display *dpy, int screen, const int *attribList)dpy is a pointer to the display returned by
XOpenDisplay. 
screen is currently ignored by Mini GLX and should be
zero. 
attribList is a list of GLX attributes which describe
the desired pixel format.  It is terminated by the token 
None.
The attributes are as follows:
  
    
GLX_USE_GL    
This attribute should always be present in order to maintain
compatibility with GLX.
    
GLX_RGBA    
If present, only RGBA pixel formats will be considered.
Otherwise, only color index formats are considered.
    
GLX_DOUBLEBUFFER    
if present, only double-buffered pixel formats will	be chosen.    
GLX_RED_SIZE n    
Must be followed by a non-negative integer indicating the
minimum number of bits per red pixel component that is acceptable.
    
GLX_GREEN_SIZE n    
Must be followed by a non-negative integer indicating the
minimum number of bits per green pixel component that is acceptable.
    
GLX_BLUE_SIZE n    
Must be followed by a non-negative integer indicating the
minimum number of bits per blue pixel component that is acceptable.
    
GLX_ALPHA_SIZE n    
Must be followed by a non-negative integer indicating the
minimum number of bits per alpha pixel component that is acceptable.
    
GLX_STENCIL_SIZE n    
Must be followed by a non-negative integer indicating the
minimum number of bits per stencil value that is acceptable.
    
None    
This token is used to terminate the attribute list.  
glXChooseVisual will return a pointer to an XVisualInfo object which
most closely matches the requirements of the attribute list.  If there
is no visual which matches the request, NULL will be returned.
Note that visuals with accumulation buffers and depth buffers are
not available.
3.3 Creating a Drawing Surface
Drawing surfaces are created as X windows.  For Mini GLX,
windows are 
full-screen; they cover the entire frame buffer.
 Also, Mini GLX imposes a limit of one window.  A second window
cannot be created until the first one is destroyed.
3.3.1 Window Creation
The XCreateWindow function is used to create a drawing surface:
  
Window XCreateWindow( Display *display,                      Window parent,                      int x, int y,                      unsigned int width, unsigned int height,                      unsigned int borderWidth,                      int depth,                      unsigned int class,                      Visual *visual,                      unsigned long valuemask,                      XSetWindowAttributes *attributes )The parameters are as follows:
  
    
display    
A Display pointer, as returned by XOpenDisplay.    
parent    
The parent window for the new window.  For Mini GLX, this
should be
RootWindow(dpy, 0).    
x, y    
The position of the window.  For Mini GLX, both values should
be zero.
    
width, height    
The size of the window.  For Mini GLX, this specifies the
desired screen size such as 1024, 768 or 1280, 1024.
    
borderWidth    
This parameter should be zero.    
depth    
The pixel depth for the window.  For Mini GLX this should be
the depth found in the XVisualInfo object returned by 
glxChooseVisual.    
class    
The window class.  For Mini GLX this value should be InputOutput.    
visual    
This parameter should be the visual field of the XVisualInfoobject returned by 
glxChooseVisual.    
valuemask    
This parameter indicates which fields of the XSetWindowAttributesare to be used. For Mini GLX this is typically the bitmask
CWBackPixel
| CWBorderPixel | CWColormap
.    
attributes    
Initial window attributes. Of the fields in the XSetWindowAttributesstructure, the
background_pixel, border_pixeland 
colormap fields should be set.  See the discussion
below regarding colormaps.
  
XCreateWindow will return a window handle if it succeeds
or zero if it fails.
3.3.2 Window Mapping
To display the window the XMapWindow function must be called:
  
void XMapWindow(Display *dpy, Window w)This function does nothing in Mini GLX but is required for Xlib/GLX
compatibility
3.3.3 Colormaps
Xlib requires specification of a colormap when creating a window.
 For purposes of interoperability, Mini GLX requires this as well,
though the colormap is not actually used.  The XCreateColormap
function is used to create a colormap:
Colormap XCreateColormap(Display *dpy, Window window,
Visual *visual, int alloc)
  
The parameters are as follows:
  
    
dpy    
The display handle as returned by XOpenDisplay.    
window    
 This parameter is ignored by Mini GLX but should be the value
returned by the 
RootWindow(dpy, 0) macro.    
    
visual    
This parameter is ignored by Mini GLX but should be the visual
field of the XVisualInfo object returned by glXChooseVisual. 
    
alloc    
This parameter is ignored by Mini GLX but should be set to AllocNone.  
3.4 Creating a Rendering Context
An OpenGL rendering context is created with the glXCreateContextfunction:
  
GLXContext glXCreateContext(Display *dpy, XVisualInfo *visInfo, GLXContext shareList, Bool direct)The parameters are as follows:
  
    
dpy    
The display handle as returned by XOpenDisplay.    
visInfo    
The visual as returned by glXChooseVisual.    
shareList    
If non-zero, texture objects and display lists are shared with
the named rendering context. If zero, texture objects and display lists
will (initially) be private to this context. They may be shared when a
subsequent context is created.
    
direct    
Specifies whether direct or indirect rendering is desired. For
Mini GLX this value is ignored but it should be set to 
True.  
glXCreateContext will return a GLXContext handle if it
succeeds or zero if it fails due to invalid parameter or insufficient
resources.
3.5 Binding a Rendering Context
The final step before beginning OpenGL rendering is to bind (i.e.
activate) a rendering context and drawing surface with the
glXMakeCurrent function:
  
Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx)The parameters are as follows:
  
    
dpy    
The display handle, as returned by XOpenDisplay.    
drawable    
The window or drawable to bind to the rendering context. This
should be the value returned by XCreateWindow.
    
ctx    
The rendering context to bind, as returned by glXCreateContext.  
If glXMakeCurrent succeeds True is returned.  Otherwise False is
returned to indicate an invalid display, window or context parameter.
After the rendering context has been bound to the drawing surface
OpenGL rendering can begin.
The current rendering context may be unbound by calling
glXMakeCurrent with the window and context parameters set to zero.
An application may create any number of rendering contexts and bind
them as needed. Note that binding a rendering context is generally not a
light-weight operation.  Most simple OpenGL applications create
only one rendering context.
3.6 Color Buffer Swapping
A double buffered window has two color buffers: a front buffer and a
back buffer.  Normally, rendering is directed to the back buffer while
the front buffer is displayed.  When rendering of a frame is finished
the front and back buffers are swapped to provide the illusion of
instanteous screen updates.
The color buffers for a particular window (i.e. drawable) may be
swapped with the glXSwapBuffers command:
  
void glXSwapBuffers(Display *dpy, GLXDrawable drawable)Any pending rendering commands will be completed before the buffer swap
takes place.
Calling glXSwapBuffers on a window which is single-buffered has no
effect.
3.7 Releasing Resources
3.7.1 Releasing Rendering Contexts
A rendering context may be destroyed by calling glXDestroyContext:
  
void glXDestroyContext(Display *dpy, GLXContext ctx)3.7.2 Releasing Windows
A window may be destroyed by calling XDestroyWindow:
  
void XDestroyWindow(Display *dpy, Window window)3.7.3 Releasing Visuals
An XVisualInfo object may be freed by calling XFree:
  
void XFree(void *data)3.7.4 Releasing Colormaps
A colormap may be freed by calling XFreeColormap:
  
void XFreeColormap(Display *dpy, Colormap colormap)3.7.4 Releasing Display Resources
When the application is about to exit, the resources associated with
the graphics system can be released by calling XCloseDisplay:
  
void XCloseDisplay(Display *dpy)The display handle becomes invalid at this point.
3.8 Query Functions
3.8.1 Querying Available Visuals
A list of all available visuals can be obtained with the XGetVisualInfo
function:
XVisualInfo
*XGetVisualInfo(Display *dpy, long vinfo_mask, XVisualInfo
*vinfo_template, int *nitems_return)
The parameters are as follows:
  
    
dpy    
The display handle, as returned by XOpenDisplay.    
vinfo_mask    
A bitmask indicating which fields of the vinfo_template are to
be matched.  The value must be VisualScreenMask.
    
vinfo_template    
A template whose fields indicate which visual attributes must
be matched by the results.  The screen field of this structure must
be zero.
    
nitems_return    
Returns the number of visuals returned.   
The return value is the address of an array of all available visuals.
An example of using XGetVisualInfo to get all available visuals follows:
XVisualInfo visTemplate, *results;int numVisuals;Display *dpy = XOpenDisplay(NULL);visTemplate.screen = 0;results = XGetVisualInfo(dpy, VisualScreenMask, &visTemplate,
&numVisuals);
3.8.2 Querying Visual Attributes
The GLX attributes of an X visual may be queried with the
glXGetConfig function:
  
int glXGetConfig(Display *dpy, XVisualInfo *vis, int attribute, int *value)The parameters are as follows:
  
    
dpy    
The display handle, as returned by XOpenDisplay.    
vis    
The visual, as returned by glXChooseVisual.    
attribute    
The attribute to query.  The attributes are listed below.    
value    
Pointer to an integer in which the result of the query will be
stored. 
  
The return value will be zero if no error occurs. GLX_INVALID_ATTRIBUTE
 will be returned if the attribute
parameter is invalid.
  GLX_BAD_VISUAL will be returned
if the XVisualInfo parameter is invalid.
The following attributes may be queried:
  
    
GLX_USE_GL    
The result will be True or False to
indicate if OpenGL rendering is supported with the visual.  Mini GLX
always return 
True.    
GLX_RGBA    
The result will be True for RGBA visuals or Falsefor color index visuals.
    
GLX_DOUBLEBUFFER    
The result will be True if the visual has two
color buffers or 
False if the visual has one color buffer.    
GLX_RED_SIZE    
The result will be the number of red bits per pixel.    
GLX_GREEN_SIZE    
The result will be the number of green bits per pixel.    
GLX_BLUE_SIZE    
The result will be the number of blue bits per pixel.    
GLX_ALPHA_SIZE    
The result will be the number of alpha bits per pixel.    
GLX_DEPTH_SIZE    
The result will be the number of bits per Z value.    
GLX_STENCIL_SIZE    
The result will be the number of bits per stencil value.      
    
  
3.8.3 Querying the Current Rendering Context
The current rendering context can be queried with
glXGetCurrentContext: 
  
GLXContext glXGetCurrentContext(void)Zero will be returned if no context is currently bound.
3.8.4 Querying the Current Drawable
The current drawable (i.e. window or drawing surface) can be queried
with glXGetCurrentDrawable:
  
GLXDrawable glXGetCurrentDrawable(void)Zero will be returned if no drawable is currently bound.
3.8.5 Function Address Queries
The glXGetProcAddress function will return the address of any
available OpenGL or Mini GLX function:
  
void *glXGetProcAddress(const GLubyte *procName)If procName is a valid function name, a pointer to that
function will be returned.  Otherwise, NULL will be returned.
The purpose of glXGetProcAddress is to facilitate using future
extensions to OpenGL or Mini GLX.  If a future version of the library
adds new extension functions they'll be accessible via
glXGetProcAddress. The alternative is to hard-code calls to the new
functions in the application but doing so will prevent linking the
application with older versions of the library.
3.9 Versioning
The Mini GLX version can be queried at run time with glXQueryVersion:
  
Bool glXQueryVersion(Display *dpy, int *major, int *minor)major will be set to the major version number andminorwill be set to the minor version number.
True will be
returned if the function succeeds. 
False will be returned
if the function fails due to invalid parameters. The 
dpyargument is currently ignored, but should be the value returned by
XOpenDisplay.
At compile time, the Mini GLX interface version can be tested with
the MINI_GLX_VERSION_1_
x preprocessor tokens. For example, if
version 1.0 of Mini GLX is supported, then
 MINI_GLX_VERSION_1_0will be defined. If version 1.1 of Mini GLX is supported, then
MINI_GLX_VERSION_1_1
 will be defined.
At the time of writing the current Mini GLX version is 1.0.
4.0 Interoperability with GLX and Xlib
While Mini GLX strives to be compatible with GLX and Xlib there are
some unavoidable differences which must be taken into consideration.
4.1 Public vs Private Structures
The structure of many X data types is public.  For example, the 
Displaydata type is defined as a structure in /usr/include/X11/Xlib.h and
programmers may access any fields of that structure at will.  Mini
GLX also defines a Display data type but its fields are hidden and not
visiblein 
miniglx.h.  Duplicating the Xlib
declaration for the 
Display data type in minigl.h would
require defining a large number of other superfluous Xlib datatypes.
Mini GLX users are discouraged from directly accessing the fields of
Xlib data types to maximize portability - though this is unavoidable to
some extent.  For example, the 
XVisualInfo and XSetWindowAtttributesdata types must be completely public.
4.2 Macros
In some cases, Xlib defines macros which are meant to be used instead
of direct structure accesses.  For example, the 
RootWindow(dpy,
screen)
 macro returns the root window for a given screen on a
given display.  Unfortunately, macros do nothing to aid in ABI
compatibility since they are resolved at compile time instead of at
link/run time.
Mini GLX also defines a 
RootWindow macro since it's
essential for creating windows.  But the implementation of this
macro by Xlib and Mini GLX is completely different.
4.3 Summary
Because Xlib and Mini GLX define data types and macros differently,
Mini GLX applications must be recompiled when retargeting Mini GLX or
native Xlib/GLX.  That is, applications can't simply be re-linked
because of ABI incompatibilities.
Nevertheless, the fact that Mini GLX programs can be recompiled for
Xlib and GLX increases portability and flexibility for testing and
prototyping.
5.0 Example Program
This section shows an example program which uses the Mini GLX
interface. The program simply draws several frames of a rotating square.
The program may be compiled for use with Xlib/GLX or Mini GLX by
setting the 
USE_MINIGLX token to 0 or 1, respectively.
 Note that the only difference is the header files which are
included.
 
#define USE_MINIGLX 1  /* 1 = use Mini GLX, 0 = use Xlib/GLX */#include <stdio.h>#include <stdlib.h>#include <GL/gl.h>#if USE_MINIGLX#include <GL/miniglx.h>#else#include <GL/glx.h>#include <X11/Xlib.h>#endif/* * Create a simple double-buffered RGBA window. */static WindowMakeWindow(Display * dpy, unsigned int width, unsigned int height){   int visAttributes[] = {      GLX_RGBA,      GLX_RED_SIZE, 1,      GLX_GREEN_SIZE, 1,      GLX_BLUE_SIZE, 1,      GLX_DOUBLEBUFFER,      None   };   XSetWindowAttributes attr;   unsigned long attrMask;   Window root;   Window win;   GLXContext ctx;   XVisualInfo *visinfo;   root = RootWindow(dpy, 0);   /* Choose GLX visual / pixel format */   visinfo = glXChooseVisual(dpy, 0, visAttributes);   if (!visinfo) {      printf("Error: couldn't get an RGB, Double-buffered visual\n");      exit(1);   }   /* Create the window */   attr.background_pixel = 0;   attr.border_pixel = 0;   attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);   attrMask = CWBackPixel | CWBorderPixel | CWColormap;   win = XCreateWindow(dpy, root, 0, 0, width, height,		       0, visinfo->depth, InputOutput,		       visinfo->visual, attrMask, &attr);   if (!win) {      printf("Error: XCreateWindow failed\n");      exit(1);   }   /* Display the window */   XMapWindow(dpy, win);   /* Create GLX rendering context */   ctx = glXCreateContext(dpy, visinfo, NULL, True);   if (!ctx) {      printf("Error: glXCreateContext failed\n");      exit(1);   }   /* Bind the rendering context and window */   glXMakeCurrent(dpy, win, ctx);   return win;}/* * Draw a few frames of a rotating square. */static voidDrawFrames(Display * dpy, Window win){   int angle;   glShadeModel(GL_FLAT);   glClearColor(0.5, 0.5, 0.5, 1.0);   for (angle = 0; angle < 360; angle += 10) {      glClear(GL_COLOR_BUFFER_BIT);      glColor3f(1.0, 1.0, 0.0);      glPushMatrix();      glRotatef(angle, 0, 0, 1);      glRectf(-0.8, -0.8, 0.8, 0.8);      glPopMatrix();      glXSwapBuffers(dpy, win);   }}intmain(int argc, char *argv[]){   Display *dpy;   Window win;   dpy = XOpenDisplay(NULL);   if (!dpy) {      printf("Error: XOpenDisplay failed\n");      return 1;   }   win = MakeWindow(dpy, 300, 300);   DrawFrames(dpy, win);   return 0;}